# Slash Command 重构路线图 ## 总体目标 用 Qwen 内部架构风格,交付一个在外部体验上 95% 对齐 Claude Code 的 command 平台,同时修复三模式分裂、命令来源单一、prompt command 无法被模型调用三个核心问题。 --- ## 核心设计原则 1. **每个 Phase 可独立 ship**:完成后行为是自洽的,不依赖未来 Phase 才能运行 2. **Phase 1 是纯基础设施**:除修复 MCP_PROMPT 被错误拦截外,不改变任何现有可用命令集 3. **行为变化与架构变化分开**:Phase 1 做架构,Phase 2 做能力扩展 4. **不照搬 Claude Code 内部架构**:但对齐用户可感知的能力面 --- ## Phase 1:基础设施重建(纯架构,零行为变化) ### 目标 建立统一的命令元数据模型和跨模式管理机制,为后续所有 Phase 提供底层支撑。 ### 功能点 #### 1.1 扩展 `SlashCommand` 元数据模型 在现有 `SlashCommand` 接口上新增以下字段: **来源字段** - `source: CommandSource`:命令来源枚举(`builtin-command` / `bundled-skill` / `skill-dir-command` / `plugin-command` / `mcp-prompt` 等) - `sourceLabel?: string`:展示用的来源标签(如 `"Built-in"` / `"MCP: github-server"`) **模式能力字段** - `supportedModes: ExecutionMode[]`:声明在哪些运行模式下可用(`interactive` / `non_interactive` / `acp`) **执行类型字段** - `commandType: CommandType`:声明执行类型(`prompt` / `local` / `local-jsx`) **可见性字段** - `userInvocable: boolean`:用户是否可通过 slash command 调用(默认 `true`) - `modelInvocable: boolean`:模型是否可通过 tool call 调用(默认 `false`) **辅助元数据字段**(为 Phase 3 预留,Phase 1 仅定义,不使用) - `argumentHint?: string`:参数提示,如 `""` / `"show|list|set"` - `whenToUse?: string`:何时调用该命令的说明(供模型使用) - `examples?: string[]`:使用示例 #### 1.2 Loader 填充 source/commandType 字段 每个 Loader 在构建 `SlashCommand` 时必须填充 `source` 和 `commandType`: | Loader | source | commandType | | -------------------------------- | ------------------- | ------------------------------------- | | `BuiltinCommandLoader` | `builtin-command` | 由各命令声明(`local` / `local-jsx`) | | `BundledSkillLoader` | `bundled-skill` | `prompt` | | `FileCommandLoader`(用户/项目) | `skill-dir-command` | `prompt` | | `FileCommandLoader`(插件) | `plugin-command` | `prompt` | | `McpPromptLoader` | `mcp-prompt` | `prompt` | #### 1.3 内置命令声明 `supportedModes` 和 `commandType` 为所有 built-in 命令显式声明: - `commandType`:`local`(无 UI 依赖)或 `local-jsx`(依赖 dialog/React) - `supportedModes`:`local` 类命令声明 `['interactive', 'non_interactive', 'acp']`;`local-jsx` 类命令声明 `['interactive']` #### 1.4 用 capability-based 过滤替换硬编码白名单 - 删除 `ALLOWED_BUILTIN_COMMANDS_NON_INTERACTIVE` 常量 - 删除 `filterCommandsForNonInteractive` 函数 - 新增 `filterCommandsForMode(commands, mode)` 函数,基于 `supportedModes` 字段过滤 - 新增 `getEffectiveSupportedModes(cmd)` 工具函数(考虑 CommandKind 默认策略) - 修改 `handleSlashCommand` / `getAvailableCommands` 函数签名,移除 `allowedBuiltinCommandNames` 参数 #### 1.5 CommandService 升级为统一 Registry - 新增 `getCommandsForMode(mode: ExecutionMode)` 方法 - 新增 `getModelInvocableCommands()` 方法(Phase 2/3 使用,Phase 1 提供接口) - 现有 `getCommands()` 保持不变(interactive 使用) ### 验收标准 - [ ] `SlashCommand` 接口包含所有新字段,TypeScript 编译通过 - [ ] 所有 Loader 填充 `source` 和 `commandType` 字段 - [ ] 所有 built-in 命令声明 `commandType` 和 `supportedModes` - [ ] `ALLOWED_BUILTIN_COMMANDS_NON_INTERACTIVE` 已删除,被 capability filter 取代 - [ ] **non-interactive 下可用命令集与重构前完全一致**(现有测试不 break) - [ ] MCP prompt commands 在 non-interactive/acp 下可正常执行(修复原有错误限制) - [ ] `CommandService.getCommandsForMode('non_interactive')` 返回正确的命令集 - [ ] 所有现有测试通过 --- ## Phase 2:能力扩展(命令整理与 prompt command 模型调用) ### 目标 基于 Phase 1 的元数据基础,扩展三种模式下的命令可用范围,并打通 prompt command 的模型调用通路。 ### 功能点 #### 2.1 扩展 non-interactive / acp 可用命令集 将以下命令的 `supportedModes` 扩展到包含 `non_interactive` 和 `acp`,并确保其 action 实现可在无 UI 环境运行: **直接可扩展**(action 已无 UI 依赖): - `/export`:文件 I/O,返回 `message` - `/memory`:文件 I/O,返回 `message` - `/plan`:返回 `submit_prompt` - `/tools`:改为返回 `message`(文本列表,替换 UI 渲染) - `/stats`:改为返回 `message`(文本格式,替换 UI 渲染) **需要 local 子命令拆分**(当前只有 `local-jsx` 壳): | 命令 | 新增的 local 子命令 | | -------------- | ----------------------------------------------------------------------------- | | `/model` | `show`(当前模型)、`list`(可选列表)、`set `(切换) | | `/permissions` | `show`(当前权限模式)、`set `(设置) | | `/mcp` | `list`(MCP 服务列表)、`show `(服务详情)、`status`(所有服务状态) | | `/memory` | 已有 `show`/`add`/`refresh`(确认 non-interactive 下可用) | > **注意**:上述 UI 壳命令不会被删除,`/model` 不带子命令时仍然打开 dialog(interactive 模式)。新增子命令是 **在现有命令上追加**,不是替换。 #### 2.2 prompt command 模型调用打通 - 在 `CommandService`(或 `CommandRegistry`)中实现 `getModelInvocableCommands()`,返回所有 `modelInvocable: true` 的命令 - 将 `BundledSkillLoader`、`FileCommandLoader`(用户/项目命令)、`McpPromptLoader` 加载的命令标记为 `modelInvocable: true` - 改造 `SkillTool`:从只消费 `SkillManager.listSkills()` 改为同时消费 `CommandService.getModelInvocableCommands()` - 构建统一的模型可调用命令描述,注入 `SkillTool` 的 description #### 2.3 mid-input slash command 检测(基础版) - 在 `InputPrompt` 中检测光标附近的 slash token(不限于行首) - 检测到 slash token 后触发补全菜单(展示命令名 + description) - 补全菜单弹出位置跟随光标 - **不**包含 argument hints、source badge 等(Phase 3 做) ### 验收标准 - [ ] `/export`、`/memory`、`/plan`、`/tools`、`/stats` 在 non-interactive 模式下可正常执行并返回结构化输出 - [ ] `/model show`、`/model set ` 在 non-interactive / acp 下可执行 - [ ] `/permissions show`、`/permissions set ` 在 non-interactive / acp 下可执行 - [ ] `/mcp list`、`/mcp show ` 在 non-interactive / acp 下可执行 - [ ] 模型在对话中可以通过 `SkillTool` 调用 bundled skill、file command(用户/项目)、MCP prompt - [ ] 模型不可以调用 built-in commands(`userInvocable: true`,`modelInvocable: false`) - [ ] mid-input slash:在正文中输入 `/` 后触发命令补全菜单 - [ ] `SkillTool` 的 description 包含所有 `modelInvocable` 命令的描述 --- ## Phase 3:体验对齐(补全增强 + Claude Code 命令补齐) ### 目标 在 Phase 1/2 的元数据和命令能力基础上,补齐补全体验,并补充 Claude Code 中存在而 Qwen Code 缺失的命令。 ### 功能点 #### 3.1 补全体验增强 **source badge** - 在补全菜单中展示命令来源标签(`[MCP]` 已有,扩展为 `[Skill]`、`[Custom]` 等) - 使用 `source` / `sourceLabel` 字段渲染 **argument hint** - 补全菜单中命令名后展示 `argumentHint`(如 `set `) - `argumentHint` 由 Phase 1 元数据字段提供 **recently used 排序** - 记录用户最近使用的命令(session 级别,无需持久化) - 在补全排序中给近期使用的命令加权 **alias 命中高亮** - 当补全命中 `altNames` 而非主名时,在展示时注明(如 `help (alias: ?)`) **冲突策略对齐** - 明确优先级:built-in > bundled/skill-dir > plugin > mcp - 冲突时将低优先级命令重命名(如 `pluginName.commandName`) #### 3.2 mid-input slash command 完整版 - 在 Phase 2 基础版上增加 argument hints 和 source badge 展示 - ghost text 提示(输入 `/he` 时显示 `/help` 的淡色提示) - 有效命令 token 高亮(已完成匹配的 slash command 显示不同颜色) #### 3.3 Help 目录重构 将 `/help` 从平铺列表改为分组目录: - **Built-in Commands**(local + local-jsx,注明 mode) - **Bundled Skills** - **Custom Commands**(用户/项目 file commands) - **Plugin Commands** - **MCP Commands** 每条命令展示:名称、argumentHint、description、source、supportedModes 标记 #### 3.4 ACP available commands 元数据增强 在 `sendAvailableCommandsUpdate()` 中将更多元数据暴露给 ACP 客户端: - `argumentHint` - `source` - `supportedModes` - `subcommands`(名称列表) - `modelInvocable` #### 3.5 Claude Code 缺失命令补齐 补充 Qwen Code 当前没有、Claude Code 有且常用的命令: | 命令 | 类型 | 说明 | | ---------------- | ------- | ---------------------------------------- | | `/doctor` | `local` | 环境自检,输出配置/连接/工具状态诊断 | | `/release-notes` | `local` | 展示当前版本的更新日志 | | `/cost` | `local` | 展示当前 session 的 token 消耗和费用估算 | > 注:`/review`、`/commit` 等任务类命令以 bundled skill 形式提供,不在此列。 ### 验收标准 - [ ] 补全菜单展示 source badge(`[MCP]`、`[Skill]`、`[Custom]`) - [ ] 补全菜单展示 argumentHint(如 `set `) - [ ] 近期使用的命令在补全列表中优先出现 - [ ] alias 命中时在补全项中注明原名 - [ ] mid-input slash:ghost text 提示正确渲染 - [ ] `/help` 输出按来源分组,每条命令展示支持模式标记 - [ ] ACP available commands 包含 `argumentHint`、`source`、`subcommands` 字段 - [ ] `/doctor`、`/release-notes`、`/cost` 三个命令可用 - [ ] `/doctor` 在 non-interactive 模式下可执行(返回 `message`) --- ## 各 Phase 依赖关系 ``` Phase 1(元数据 + 统一过滤) │ ├──► Phase 2(能力扩展) │ │ │ ├──► slash command 子命令拆分 │ └──► prompt command 模型调用(需要 getModelInvocableCommands()) │ └──► Phase 3(体验对齐) │ ├──► source badge(需要 Phase 1 source 字段) ├──► argument hint(需要 Phase 1 argumentHint 字段) └──► Help 分组(需要 Phase 1 source 字段) ``` Phase 2 和 Phase 3 不互相依赖,可以并行推进(或根据优先级调换部分子项)。