diff --git a/CHANGELOG.md b/CHANGELOG.md index def4e305d..6c4e6590e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ Only write entries that are worth mentioning to users. ## Unreleased +- Shell: Fix slash command completion menu not appearing on exact match — typing a full command name like `/editor` now still shows the command entry (with its description) in the completion menu, while still suppressing unrelated prefix noise such as `/mcp` expanding to `/mcp-server` (fixes #1752) - Shell: Add `/btw` side question command — ask a quick question during streaming without interrupting the main conversation; uses the same system prompt and tool definitions for prompt cache alignment; responses display in a scrollable modal panel with streaming support - Shell: Redesign bottom dynamic area — split the monolithic `visualize.py` (1865 lines) into a modular package (`visualize/`) with dedicated modules for input routing, interactive prompts, approval/question panels, and btw modal; unify input semantics with `classify_input()` for consistent command routing - Shell: Add queue and steer dual-channel input during streaming — Enter queues messages for delivery after the current turn; Ctrl+S injects messages immediately into the running turn's context; queued messages display in the prompt area with count indicator and can be recalled with ↑ diff --git a/docs/en/release-notes/changelog.md b/docs/en/release-notes/changelog.md index 7ab68c6c6..c55a84eaf 100644 --- a/docs/en/release-notes/changelog.md +++ b/docs/en/release-notes/changelog.md @@ -4,6 +4,7 @@ This page documents the changes in each Kimi Code CLI release. ## Unreleased +- Shell: Fix slash command completion menu not appearing on exact match — typing a full command name like `/editor` now still shows the command entry (with its description) in the completion menu, while still suppressing unrelated prefix noise such as `/mcp` expanding to `/mcp-server` (fixes #1752) - Shell: Add `/btw` side question command — ask a quick question during streaming without interrupting the main conversation; uses the same system prompt and tool definitions for prompt cache alignment; responses display in a scrollable modal panel with streaming support - Shell: Redesign bottom dynamic area — split the monolithic `visualize.py` (1865 lines) into a modular package (`visualize/`) with dedicated modules for input routing, interactive prompts, approval/question panels, and btw modal; unify input semantics with `classify_input()` for consistent command routing - Shell: Add queue and steer dual-channel input during streaming — Enter queues messages for delivery after the current turn; Ctrl+S injects messages immediately into the running turn's context; queued messages display in the prompt area with count indicator and can be recalled with ↑ diff --git a/docs/zh/release-notes/changelog.md b/docs/zh/release-notes/changelog.md index 34d66cbd9..0a21a4a3a 100644 --- a/docs/zh/release-notes/changelog.md +++ b/docs/zh/release-notes/changelog.md @@ -4,6 +4,7 @@ ## 未发布 +- Shell:修复 Slash 命令完全匹配时补全菜单不再弹出的问题——输入 `/editor` 等完整命令名时,补全菜单会继续显示该命令条目(含描述),同时仍然抑制诸如 `/mcp` → `/mcp-server` 这类无关前缀噪音(修复 #1752) - Shell:新增 `/btw` 侧问命令——在 streaming 期间提出快速问题,不打断主对话;使用相同的系统提示词和工具定义以对齐 Prompt 缓存;响应在可滚动的模态面板中显示,支持流式输出 - Shell:重新设计底部动态区——将单体 `visualize.py`(1865 行)拆分为模块化包(`visualize/`),包含输入路由、交互式提示、审批/提问面板和 btw 模态面板等独立模块;通过 `classify_input()` 统一输入语义,实现一致的命令路由 - Shell:新增 streaming 期间的排队和 steer 双通道输入——Enter 将消息排队,在当前轮次结束后发送;Ctrl+S 将消息立即注入到正在运行的轮次上下文中;排队消息在提示区域显示计数指示器,可通过 ↑ 键召回编辑 diff --git a/src/kimi_cli/ui/shell/prompt.py b/src/kimi_cli/ui/shell/prompt.py index 57d344cc7..65c4e90fd 100644 --- a/src/kimi_cli/ui/shell/prompt.py +++ b/src/kimi_cli/ui/shell/prompt.py @@ -138,6 +138,22 @@ def get_completions( typed = token[1:] if typed and typed in self._command_lookup: + # Exact match: only show the matching command itself (with its + # description), skipping fuzzy fallbacks like `/mcp` → `/mcp-server`. + # This preserves the intent of #666 (hide unrelated prefix noise) + # while still letting the user confirm the command and read its + # description (#1752). + seen_exact: set[str] = set() + for cmd in self._command_lookup[typed]: + if cmd.name in seen_exact: + continue + seen_exact.add(cmd.name) + yield Completion( + text=f"/{cmd.name}", + start_position=-len(token), + display=f"/{cmd.name}", + display_meta=cmd.description, + ) return mention_doc = Document(text=typed, cursor_position=len(typed)) candidates = list(self._fuzzy.get_completions(mention_doc, complete_event)) diff --git a/tests/ui_and_conv/test_slash_completer.py b/tests/ui_and_conv/test_slash_completer.py index 3897557fe..b9f2609b3 100644 --- a/tests/ui_and_conv/test_slash_completer.py +++ b/tests/ui_and_conv/test_slash_completer.py @@ -47,8 +47,13 @@ def _completions(completer: SlashCommandCompleter, text: str): return list(completer.get_completions(document, event)) -def test_exact_command_match_hides_completions(): - """Exact matches should not show completions.""" +def test_exact_command_match_shows_only_that_command(): + """Exact command name match should show only that command, not prefix fuzzy hits. + + Regression for #1752 (exact match should still reveal the completion entry so + the user can read its description) while preserving the #666 intent of hiding + unrelated noise like `/mcp` → `/mcp-server`. + """ completer = SlashCommandCompleter( [ _make_command("mcp"), @@ -59,11 +64,11 @@ def test_exact_command_match_hides_completions(): texts = _completion_texts(completer, "/mcp") - assert not texts + assert texts == ["/mcp"] -def test_exact_alias_match_hides_completions(): - """Exact alias matches should not show completions.""" +def test_exact_alias_match_shows_only_canonical_command(): + """Exact alias match should show only the canonical command, not other fuzzy hits.""" completer = SlashCommandCompleter( [ _make_command("help", aliases=["h"]), @@ -73,7 +78,24 @@ def test_exact_alias_match_hides_completions(): texts = _completion_texts(completer, "/h") - assert not texts + assert texts == ["/help"] + + +def test_exact_command_match_completion_has_description(): + """Exact matches must carry the command's description so users can read it (#1752).""" + completer = SlashCommandCompleter( + [ + _make_command("editor"), + _make_command("exit"), + ] + ) + + completions = _completions(completer, "/editor") + + assert len(completions) == 1 + assert completions[0].text == "/editor" + assert completions[0].display_text == "/editor" + assert completions[0].display_meta_text == "editor command" def test_should_complete_only_for_root_slash_token():