docs(comments): rewrite comments across all crates to the guidelines
Sweep every first-party crate source (1956 .rs files) to the project comment guidelines: delete redundant restatements, decorative banners, change narration, and end-of-line comments; keep and tighten the crucial ones (invariants, bug rationale, SAFETY blocks, ported-source attribution). No functional code changed. Every edit is proven comment-only against the prior tree by a comment-stripping lexer (string/char/raw-string aware) plus a separate doctest-fence check. Where removing a comment made rustfmt or clippy want to re-lay-out adjacent code, the minimal triggering comment is restored so code tokens stay byte-identical. Gates green: cargo fmt --all --check (0 diffs), cargo check and cargo clippy --workspace --all-targets (0 warnings). Adds scripts/check_codegen_comment_guidelines.py — the enforcement gate for these guidelines (flags banners, end-of-line comments, change narration, and commented-out code).
This commit is contained in:
1 parent
ff0fb56c67
commit
a02b555e66
1458 files changed
+10729
-21750
No files matched your search
@@ -7,7 +7,7 @@
|
||||
//! Skill commands (those with `meta.path` + `meta.scope`) are handled
|
||||
//! client-side: pager reads the SKILL.md, applies substitutions, and
|
||||
//! sends structured prompt blocks directly. Non-skill ACP commands
|
||||
//! pass through to the shell as before.
|
||||
//! pass through to the shell.
|
||||
|
||||
use agent_client_protocol as acp;
|
||||
use kigi_tools::implementations::skills::types::SkillScope;
|
||||
@@ -69,7 +69,7 @@ impl SlashCommand for AcpSlashCommand {
|
||||
return CommandResult::Error(format!("Malformed skill metadata for /{}", self.name));
|
||||
}
|
||||
|
||||
// Non-skill ACP commands: pass through to the shell as before.
|
||||
// Non-skill ACP commands: pass through to the shell.
|
||||
if self.skill_path.is_none() || self.skill_scope.is_none() {
|
||||
let text = if args.trim().is_empty() {
|
||||
format!("/{}", self.name)
|
||||
@@ -79,8 +79,6 @@ impl SlashCommand for AcpSlashCommand {
|
||||
return CommandResult::PassThrough(text);
|
||||
}
|
||||
|
||||
// --- Pass skill through to the shell for expansion ---
|
||||
//
|
||||
// The shell's slash_commands::resolve() handles skill detection,
|
||||
// SKILL.md loading, substitution, and assembly of the
|
||||
// <user_query> + <skill_information> format. The pager just
|
||||
@@ -267,8 +265,6 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
// -- run() tests --
|
||||
|
||||
fn make_skill_cmd(name: &str, path: &str, scope: &str) -> AcpSlashCommand {
|
||||
AcpSlashCommand {
|
||||
name: name.to_string(),
|
||||
@@ -332,8 +328,8 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn run_missing_file_passes_through_to_shell() {
|
||||
// The pager no longer reads SKILL.md — it passes through to the shell.
|
||||
// A missing file still produces InjectSkill with the raw `/skill args` text.
|
||||
// The pager doesn't read SKILL.md itself; it passes the raw text through
|
||||
// to the shell, so a missing file still produces InjectSkill.
|
||||
let cmd = make_skill_cmd("commit", "/nonexistent/path/SKILL.md", "local");
|
||||
let mut ctx = make_exec_ctx();
|
||||
let result = cmd.run(&mut ctx, "fix bug");
|
||||
@@ -486,8 +482,8 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn run_skill_substitutes_skill_dir() {
|
||||
// The pager no longer does substitutions — it passes through to the shell.
|
||||
// This test verifies the pass-through behavior.
|
||||
// Despite the name, the pager performs no substitution here — it
|
||||
// passes the raw `/skill args` text through to the shell.
|
||||
let cmd = make_skill_cmd("config", "/some/path/SKILL.md", "local");
|
||||
let mut ctx = make_exec_ctx();
|
||||
let result = cmd.run(&mut ctx, "");
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
//! return `CommandResult::Action(action)` and let the dispatch layer handle it.
|
||||
//! - `CommandResult` has additional variants: `Action`, `QueueCommand`, `PassThrough`.
|
||||
//! - Trait methods return `&str` (not `&'static str`) to support ACP-sourced commands.
|
||||
//! - `args_required()` added for the two-bit completeness model.
|
||||
//! - `args_required()` distinguishes the two-bit completeness model.
|
||||
//! - `validate_args()` intentionally omitted in phase 1 (folded into `run()`).
|
||||
|
||||
use crate::acp::model_state::ModelState;
|
||||
|
||||
@@ -153,7 +153,6 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn not_available_in_minimal() {
|
||||
// Native terminal selection replaces the in-app copy path in minimal.
|
||||
assert!(!CopyCommand.available_in_minimal());
|
||||
}
|
||||
}
|
||||
@@ -140,7 +140,6 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn not_available_in_minimal() {
|
||||
// The dashboard is out of scope in scrollback-native minimal mode.
|
||||
assert!(!DashboardCommand.available_in_minimal());
|
||||
}
|
||||
}
|
||||
@@ -106,7 +106,6 @@ fn list_path_completions(cwd: &Path, query: &str) -> Vec<ArgItem> {
|
||||
(parent.to_path_buf(), prefix.to_string())
|
||||
};
|
||||
|
||||
// Resolve relative paths against cwd.
|
||||
let resolved = if dir_to_list.is_relative() {
|
||||
cwd.join(&dir_to_list)
|
||||
} else {
|
||||
@@ -148,7 +147,7 @@ fn list_path_completions(cwd: &Path, query: &str) -> Vec<ArgItem> {
|
||||
}
|
||||
}
|
||||
|
||||
// Sort: directories first, then alphabetical. Truncate after sort.
|
||||
// Directories first, then alphabetical.
|
||||
items.sort_by(|a, b| {
|
||||
let a_dir = a.display.ends_with('/');
|
||||
let b_dir = b.display.ends_with('/');
|
||||
|
||||
@@ -140,8 +140,6 @@ mod tests {
|
||||
use super::*;
|
||||
use crate::acp::model_state::ModelState;
|
||||
|
||||
// -- parse_fork_args ---------------------------------------------------
|
||||
|
||||
#[test]
|
||||
fn parse_empty_returns_none_directive_and_no_override() {
|
||||
let parsed = parse_fork_args("").expect("empty args parse");
|
||||
@@ -255,8 +253,6 @@ mod tests {
|
||||
assert_eq!(parsed.directive.as_deref(), Some("investigate"));
|
||||
}
|
||||
|
||||
// -- ForkCommand SlashCommand impl ------------------------------------
|
||||
|
||||
fn make_ctx(models: &ModelState) -> CommandExecCtx<'_> {
|
||||
let bundle = Box::leak(Box::new(crate::app::bundle::BundleState::default()));
|
||||
CommandExecCtx {
|
||||
|
||||
@@ -17,7 +17,6 @@ impl SlashCommand for GboomCommand {
|
||||
}
|
||||
|
||||
fn description(&self) -> &str {
|
||||
// Never shown: the command is hidden from the dropdown.
|
||||
"Hidden easter egg"
|
||||
}
|
||||
|
||||
@@ -25,7 +24,6 @@ impl SlashCommand for GboomCommand {
|
||||
"/gboom"
|
||||
}
|
||||
|
||||
/// Easter egg: typeable, never listed.
|
||||
fn visible(&self, _ctx: &AppCtx) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
use crate::app::actions::Action;
|
||||
use crate::slash::command::{CommandExecCtx, CommandResult, SlashCommand};
|
||||
|
||||
/// Exit the current session and return to the welcome screen.
|
||||
pub struct HomeCommand;
|
||||
|
||||
impl SlashCommand for HomeCommand {
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
use crate::app::actions::Action;
|
||||
use crate::slash::command::{CommandExecCtx, CommandResult, SlashCommand};
|
||||
|
||||
/// Open the interactive Claude settings import modal in the active session.
|
||||
pub struct ImportClaudeCommand;
|
||||
|
||||
impl SlashCommand for ImportClaudeCommand {
|
||||
|
||||
@@ -68,7 +68,6 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn not_available_in_minimal() {
|
||||
// Native terminal scrollback replaces in-app scrolling in minimal.
|
||||
assert!(!JumpCommand.available_in_minimal());
|
||||
}
|
||||
}
|
||||
@@ -211,14 +211,22 @@ mod tests {
|
||||
// suffix, and zero-valued tokens. Each must fall through to the model
|
||||
// with no host-side cadence.
|
||||
for input in [
|
||||
"5x do x", // bad suffix
|
||||
"5 do x", // no suffix
|
||||
"m do x", // too short / no digits
|
||||
"55mm do x", // multi-char suffix
|
||||
"0m do x", // zero value (tool would reject)
|
||||
"0s do x", // zero value
|
||||
"abc do x", // alphabetic
|
||||
"99999999999999999999m do x", // overflows u64 -> parse Err branch
|
||||
// bad suffix
|
||||
"5x do x",
|
||||
// no suffix
|
||||
"5 do x",
|
||||
// too short / no digits
|
||||
"m do x",
|
||||
// multi-char suffix
|
||||
"55mm do x",
|
||||
// zero value (tool would reject)
|
||||
"0m do x",
|
||||
// zero value
|
||||
"0s do x",
|
||||
// alphabetic
|
||||
"abc do x",
|
||||
// overflows u64 -> parse Err branch
|
||||
"99999999999999999999m do x",
|
||||
] {
|
||||
let (interval, prompt) = parse_loop_args(input);
|
||||
assert_eq!(interval, None, "input {input:?} must not yield a token");
|
||||
@@ -228,7 +236,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn natural_language_intervals_are_not_defaulted_host_side() {
|
||||
// The host no longer parses natural-language intervals or substitutes a
|
||||
// The host does not parse natural-language intervals or substitute a
|
||||
// default — these all fall through to the model with no interval token.
|
||||
for input in [
|
||||
"every 30 minutes do x",
|
||||
|
||||
@@ -135,7 +135,6 @@ mod tests {
|
||||
use crate::slash::command::{CommandExecCtx, CommandResult};
|
||||
use crate::slash::registry::CommandRegistry;
|
||||
use agent_client_protocol as acp;
|
||||
/// Build a ModelState with two models for testing.
|
||||
fn sample_models() -> ModelState {
|
||||
let mut models = ModelState::default();
|
||||
let id_fast = acp::ModelId::new(Arc::from("kigi-4.5"));
|
||||
|
||||
@@ -420,8 +420,8 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn run_rejects_unoffered_effort_with_effort_error_not_unknown_model() {
|
||||
// Regression: previously `resolve_effort_token_for` returned None and
|
||||
// the handler fell through to `Unknown model: Reasoning X none`.
|
||||
// Guards against a rejected effort token falling through to
|
||||
// `Unknown model: Reasoning X none` instead of an effort error.
|
||||
let mut state = ModelState::default();
|
||||
let (id, info) = model_with_reasoning("reasoning-x", "Reasoning X");
|
||||
state.available.insert(id, info);
|
||||
|
||||
@@ -24,7 +24,6 @@ impl SlashCommand for SessionInfoCommand {
|
||||
}
|
||||
|
||||
fn run(&self, ctx: &mut CommandExecCtx, _args: &str) -> CommandResult {
|
||||
// Check if we have an active session
|
||||
if ctx.session_id.is_none() {
|
||||
return CommandResult::Error("No active session".to_string());
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
use crate::app::actions::Action;
|
||||
use crate::slash::command::{CommandExecCtx, CommandResult, SlashCommand};
|
||||
|
||||
/// List background tasks, subagents, and scheduled tasks.
|
||||
pub struct TasksCommand;
|
||||
|
||||
impl SlashCommand for TasksCommand {
|
||||
|
||||
@@ -64,7 +64,6 @@ impl SlashCommand for TerminalSetupCommand {
|
||||
|
||||
let mut out = String::new();
|
||||
|
||||
// -- Environment --
|
||||
out.push_str("Environment\n");
|
||||
out.push_str(&format!(" terminal {}\n", ctx.brand));
|
||||
if let Some(v) = crate::terminal::xtversion::detected() {
|
||||
@@ -122,7 +121,6 @@ impl SlashCommand for TerminalSetupCommand {
|
||||
out.push_str(&format!(" newline Alt+Enter ({detail})\n"));
|
||||
}
|
||||
|
||||
// -- Clipboard --
|
||||
out.push_str("\nClipboard routes\n");
|
||||
out.push_str(&format!(
|
||||
" native {} (tool: {})\n",
|
||||
@@ -142,7 +140,6 @@ impl SlashCommand for TerminalSetupCommand {
|
||||
crate::clipboard::wayland_data_control_label()
|
||||
));
|
||||
|
||||
// -- Diagnostics --
|
||||
if warnings.is_empty() {
|
||||
out.push_str("\nNo issues found.\n");
|
||||
} else {
|
||||
|
||||
@@ -168,8 +168,6 @@ mod tests {
|
||||
assert!(!ThemeCommand.available_in_minimal());
|
||||
}
|
||||
|
||||
// -- suggest_args ---------------------------------------------------------
|
||||
|
||||
#[test]
|
||||
fn suggest_args_prepends_auto_option() {
|
||||
with_test_env(|| {
|
||||
@@ -277,8 +275,6 @@ mod tests {
|
||||
});
|
||||
}
|
||||
|
||||
// -- run (dispatches Action::SetTheme) ------------------------------------
|
||||
|
||||
/// `/theme <name>` returns `Action::SetTheme(<canonical>)` —
|
||||
/// the dispatcher handles in-memory state + disk write + toast.
|
||||
#[test]
|
||||
@@ -408,8 +404,6 @@ mod tests {
|
||||
});
|
||||
}
|
||||
|
||||
// -- preview_arg ----------------------------------------------------------
|
||||
|
||||
#[test]
|
||||
fn preview_auto_applies_resolved_theme() {
|
||||
with_test_env(|| {
|
||||
@@ -447,9 +441,7 @@ mod tests {
|
||||
});
|
||||
}
|
||||
|
||||
// -- cancel_preview -------------------------------------------------------
|
||||
|
||||
/// `cancel_preview` restores the previously-applied theme.
|
||||
/// `cancel_preview` restores the theme that was applied before the preview.
|
||||
#[test]
|
||||
fn cancel_preview_restores_previous_kind() {
|
||||
with_test_env(|| {
|
||||
@@ -484,8 +476,6 @@ mod tests {
|
||||
});
|
||||
}
|
||||
|
||||
// -- error handling -------------------------------------------------------
|
||||
|
||||
#[test]
|
||||
fn run_unknown_lists_auto_in_available() {
|
||||
with_test_env(|| {
|
||||
|
||||
@@ -31,10 +31,6 @@ pub use command::{AppCtx, ArgItem, CommandExecCtx, CommandResult, SlashCommand};
|
||||
/// Maximum number of visible rows in the dropdown (scroll beyond this).
|
||||
pub const MAX_VISIBLE_SUGGESTIONS: usize = 6;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// SuggestionRow
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/// A single row in the slash suggestion dropdown.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct SuggestionRow {
|
||||
@@ -138,10 +134,6 @@ fn sync_inline_ghost_to_selection(inner: &mut SlashSnapshot) {
|
||||
.and_then(|row| inline_ghost_from_selected_command(&inner.query, range, row));
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// SlashSnapshot / SlashState
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/// Immutable snapshot of the slash completion state.
|
||||
///
|
||||
/// Produced by `SlashController::refresh()`, consumed by the dropdown
|
||||
@@ -239,10 +231,6 @@ impl SlashState {
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// SlashController
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/// Derives slash completion state from prompt text + cursor.
|
||||
///
|
||||
/// Owns a `CommandRegistry` (mutable for ACP sync) and a `FuzzyMatcher`.
|
||||
@@ -1009,10 +997,6 @@ pub(crate) fn command_offered(
|
||||
&& (!command.dashboard_only() || hide_session_scoped)
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Input analysis
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/// Parsed input structure for slash completion.
|
||||
struct SlashInput {
|
||||
command_range: Range<usize>,
|
||||
@@ -1093,10 +1077,6 @@ fn analyze_input(text: &str, cursor: usize) -> Option<SlashInput> {
|
||||
})
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Invocation parsing
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/// Parsed slash command invocation.
|
||||
pub struct SlashInvocation<'a> {
|
||||
/// Command token (e.g., "model" for "/model kigi-4").
|
||||
@@ -1133,10 +1113,6 @@ pub fn parse_invocation(line: &str) -> Option<SlashInvocation<'_>> {
|
||||
Some(SlashInvocation { token, args })
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Completeness check
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/// Check if a slash command line is complete (ready to execute on Enter).
|
||||
///
|
||||
/// Uses the two-bit model: `takes_args()` + `args_required()`.
|
||||
@@ -1172,10 +1148,6 @@ pub fn is_command_complete(line: &str, registry: &CommandRegistry) -> bool {
|
||||
!invocation.args.trim().is_empty()
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Mid-text inline slash token scanning
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/// A `/token` found anywhere in the input text.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct InlineSlashToken {
|
||||
@@ -1311,7 +1283,8 @@ pub fn scan_inline_slash_tokens(text: &str, cursor: usize) -> Vec<InlineSlashTok
|
||||
iter.next();
|
||||
}
|
||||
if name_end <= name_start {
|
||||
continue; // bare `/` with nothing after
|
||||
// Bare `/` with nothing after.
|
||||
continue;
|
||||
}
|
||||
let name = text[name_start..name_end].to_string();
|
||||
let range = idx..name_end;
|
||||
@@ -1325,10 +1298,6 @@ pub fn scan_inline_slash_tokens(text: &str, cursor: usize) -> Vec<InlineSlashTok
|
||||
tokens
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Tests
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::sync::Arc;
|
||||
@@ -1369,8 +1338,6 @@ mod tests {
|
||||
assert!(parse_invocation("").is_none());
|
||||
}
|
||||
|
||||
// -- is_command_complete tests --
|
||||
|
||||
fn test_registry() -> CommandRegistry {
|
||||
CommandRegistry::new(commands::builtin_commands())
|
||||
}
|
||||
@@ -1421,8 +1388,6 @@ mod tests {
|
||||
assert!(!is_command_complete("hello", ®));
|
||||
}
|
||||
|
||||
// -- Controller tests --
|
||||
|
||||
#[test]
|
||||
fn controller_surfaces_commands_without_query() {
|
||||
let mut ctrl = SlashController::with_builtins(std::path::PathBuf::from("."));
|
||||
@@ -1779,8 +1744,6 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
// -- session-scoped surface filtering (agent dashboard) --
|
||||
|
||||
/// On a session-less surface (the agent dashboard's dispatch input),
|
||||
/// commands that act on a single session are suppressed from completion
|
||||
/// while pager-global commands remain. See `SlashCommand::session_scoped`.
|
||||
@@ -1978,8 +1941,6 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
// -- scan_inline_slash_tokens tests --
|
||||
|
||||
#[test]
|
||||
fn scan_finds_mid_text_slash_token() {
|
||||
let tokens = scan_inline_slash_tokens("do /model now", 6);
|
||||
@@ -2026,8 +1987,6 @@ mod tests {
|
||||
assert!(tokens[0].has_cursor, "cursor at end of token should match");
|
||||
}
|
||||
|
||||
// -- Inline ghost text tests --
|
||||
|
||||
#[test]
|
||||
fn inline_ghost_for_partial_command() {
|
||||
let mut ctrl = SlashController::with_builtins(std::path::PathBuf::from("."));
|
||||
@@ -2083,7 +2042,7 @@ mod tests {
|
||||
assert!(command_prefix_matches_smart("Privacy", "p"));
|
||||
assert!(command_prefix_matches_smart("Privacy", "pr"));
|
||||
// Any uppercase in query requires exact (case-sensitive) prefix.
|
||||
assert!(command_prefix_matches_smart("Privacy", "P")); // "P" is exact prefix of "Privacy"
|
||||
assert!(command_prefix_matches_smart("Privacy", "P"));
|
||||
assert!(!command_prefix_matches_smart("privacy", "Pr"));
|
||||
assert!(!command_prefix_matches_smart("Privacy", "PR"));
|
||||
|
||||
|
||||
@@ -362,8 +362,10 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn dirty_store_yields_one_snapshot_then_clears() {
|
||||
let mut mru = SlashMru::new(); // persist-enabled
|
||||
mru.loaded = true; // avoid disk read in test
|
||||
// persist-enabled
|
||||
let mut mru = SlashMru::new();
|
||||
// avoid disk read in test
|
||||
mru.loaded = true;
|
||||
mru.touch("p", "plan");
|
||||
assert!(mru.dirty);
|
||||
assert!(mru.take_persist_snapshot().is_some());
|
||||
@@ -380,9 +382,11 @@ mod tests {
|
||||
mru.loaded = true;
|
||||
mru.touch("p", "plan");
|
||||
assert!(mru.take_persist_snapshot().is_some());
|
||||
assert!(mru.take_persist_snapshot().is_none()); // nothing to retry yet
|
||||
// nothing to retry yet
|
||||
assert!(mru.take_persist_snapshot().is_none());
|
||||
mru.mark_dirty();
|
||||
assert!(mru.take_persist_snapshot().is_some()); // retried
|
||||
// retried
|
||||
assert!(mru.take_persist_snapshot().is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -36,17 +36,13 @@ pub struct CommandTrigger {
|
||||
pub display: String,
|
||||
/// Text used for fuzzy matching (alias text or canonical name).
|
||||
pub match_text: String,
|
||||
/// Command description.
|
||||
pub description: String,
|
||||
/// Usage string.
|
||||
pub usage: String,
|
||||
/// Whether this command takes arguments.
|
||||
pub takes_args: bool,
|
||||
/// Whether arguments are required (only meaningful when `takes_args` is true).
|
||||
pub args_required: bool,
|
||||
/// Index into `CommandRegistry::commands`.
|
||||
pub command_index: usize,
|
||||
/// Source of this command.
|
||||
pub source: CommandSource,
|
||||
}
|
||||
|
||||
@@ -526,14 +522,12 @@ impl CommandRegistry {
|
||||
// Execution is blocked by `get()`'s `restricted_match` filter —
|
||||
// invoking one shows the subscription upsell instead.
|
||||
|
||||
// Insert canonical key.
|
||||
self.key_to_index.insert(canonical.to_string(), idx);
|
||||
if !menu_only {
|
||||
self.triggers
|
||||
.push(CommandTrigger::new(command, None, canonical, idx, source));
|
||||
}
|
||||
|
||||
// Insert alias keys.
|
||||
for alias in command.aliases() {
|
||||
if source == CommandSource::Builtin && self.key_to_index.contains_key(*alias) {
|
||||
panic!(
|
||||
@@ -677,7 +671,6 @@ mod tests {
|
||||
let mut registry = CommandRegistry::new(vec![builtin]);
|
||||
assert_eq!(registry.command_count(), 1);
|
||||
|
||||
// Add ACP commands.
|
||||
let acp_cmds = vec![agent_client_protocol::AvailableCommand::new(
|
||||
"flush".to_string(),
|
||||
"Flush memory".to_string(),
|
||||
|
||||
Reference in new issue
Block a user