第一节:斜杠命令
命令解析与触发

作者:小学子 📚 | 日期:2026年4月2日 | 第三阶段 · 模块三


# 第三阶段 · 模块三 · 第一节:斜杠命令与命令解析

核心问题

斜杠命令(/help, /compact)是如何解析的?命令处理流程是什么?内置命令有哪些?


◇ 本节位置


        Claude Code 全局架构
        
        ┌─────────────────────────────────────────────────────────────────────┐
        │  查询引擎层 → 工具/服务层 → 命令系统 ← 本节                      │
        │                                                                      │
        │  用户输入                                                           │
        │  ├── 普通文本 ──> query() ──> 模型处理                             │
        │  └── 斜杠命令(/help) ──> 命令解析器 ──> 命令处理器              │
        └─────────────────────────────────────────────────────────────────────┘
        


一、命令系统概览

1.1 源码位置

源码位置:`src/commands.ts`(754行)

1.2 内置命令列表


        // 命令导入
        import help from './commands/help/index.js'
        import clear from './commands/clear/index.js'
        import compact from './commands/compact/index.js'
        import config from './commands/config/index.js'
        import diff from './commands/diff/index.js'
        import cost from './commands/cost/index.js'
        import session from './commands/session/index.js'
        import status from './commands/status/index.js'
        import resume from './commands/resume/index.js'
        // ... 更多命令
        

1.3 常用命令

命令作用示例
`/help`显示帮助`/help`
`/compact`压缩上下文`/compact`
`/clear`清空会话`/clear`
`/model`切换模型`/model claude-opus-4`
`/context`查看上下文`/context`
`/cost`查看消耗`/cost`
`/session`会话管理`/session list`
`/resume`恢复会话`/resume `


二、命令接口

2.1 Command 接口

源码位置:`src/commands.ts`


        interface Command {
          // 命令名称
          name: string;
        
          // 命令描述
          description: string;
        
          // 处理命令
          async getPromptForCommand(
            args: string,           // 命令参数
            context: CommandContext, // 执行上下文
          ): Promise<CommandResult>;
        }
        

2.2 CommandContext


        interface CommandContext {
          messages: Message[];      // 对话历史
          env: Record<string, string>;  // 环境变量
          cwd: string;            // 当前目录
          // ...
        }
        

2.3 五问分析

问 1:命令和工具有什么区别?

方面工具命令
调用方式模型决定用户主动触发
执行位置query() 循环内命令解析器
返回结果tool_resultCommandResult
示例Read, Write/help, /compact

问 2:命令的执行流程是什么?


        // 用户输入
        const input = "/help compact";
        
        // Step 1: 解析命令
        const { command, args } = parseSlashCommand(input);
        // command = "help", args = "compact"
        
        // Step 2: 查找命令处理器
        const handler = getCommandHandler("help");
        // handler = helpCommand
        
        // Step 3: 执行命令
        const result = await handler.getPromptForCommand(args, context);
        // result = { content: "Available commands: ..." }
        
        // Step 4: 返回结果给用户
        displayResult(result);
        

问 3:命令是如何注册的?


        // 命令注册表
        const commands: Map<string, Command> = new Map();
        
        // 注册内置命令
        commands.set('help', helpCommand);
        commands.set('compact', compactCommand);
        commands.set('clear', clearCommand);
        // ...
        
        // 支持动态注册
        function registerCommand(command: Command) {
          commands.set(command.name, command);
        }
        

问 4:如何处理未知命令?


        function handleCommand(input: string): CommandResult | null {
          const { command, args } = parseSlashCommand(input);
        
          const handler = commands.get(command);
          if (!handler) {
            return {
              type: 'error',
              content: `Unknown command: /${command}. Type /help for available commands.`,
            };
          }
        
          return handler.getPromptForCommand(args, context);
        }
        

问 5:命令可以组合吗?


        // 支持管道(类似 shell)
        "/help | grep compact"
        
        // 解析
        const parts = input.split('|');
        // parts = ["/help", "grep compact"]
        
        // 执行第一个命令
        const result1 = await executeCommand("/help");
        // result1 = "Available commands: /help, /compact, ..."
        
        // 将结果传给下一个命令
        const result2 = await executeCommand("grep compact", result1);
        // result2 = "/compact - Compact the conversation context"
        


三、斜杠命令解析

3.1 解析规则


        // 斜杠命令格式
        /command [args]
        
        // 示例
        /help
        /compact
        /model claude-opus-4
        /context 50
        

3.2 parseSlashCommand 实现


        function parseSlashCommand(input: string): { command: string; args: string } | null {
          // 必须以 / 开头
          if (!input.startsWith('/')) {
            return null;
          }
        
          // 分割命令和参数
          const parts = input.slice(1).split(/\s+/);
          // "/help compact" -> ["help", "compact"]
        
          const command = parts[0] || '';
          const args = parts.slice(1).join(' ');
        
          return { command, args };
        }
        

3.3 五问分析

问 1:为什么用 / 作为命令前缀?


        // 1. 不会和普通文本冲突
        //    用户输入 "/help" 不太可能是要模型处理 "/help" 这个词
        
        // 2. 键盘容易输入
        //    / 键在键盘上方的右手边
        
        // 3. 和 shell/bash 的习惯一致
        //    ls, cd, grep 等命令和 /help 不同
        

问 2:参数如何解析?


        // 简单空格分隔
        "/model claude-opus-4" -> command="model", args="claude-opus-4"
        
        // 带引号的参数
        "/context "50 lines"" -> args='"50 lines"'
        
        // 选项风格
        "/compact --aggressive" -> args="--aggressive"
        

问 3:命令别名如何处理?


        // 别名映射
        const aliases: Record<string, string> = {
          'h': 'help',
          '?': 'help',
          'c': 'compact',
          'cl': 'clear',
        };
        
        // 解析后转换
        function resolveCommand(name: string): string {
          return aliases[name] || name;
        }
        
        // 使用
        const { command, args } = parseSlashCommand(input);
        const resolved = resolveCommand(command);
        

问 4:如何防止命令注入?


        // 问题:用户可能输入
        // "/help; rm -rf /"
        
        // 解决方案:只允许特定的命令
        const allowedCommands = new Set(['help', 'compact', 'clear', ...]);
        
        function handleCommand(input: string): CommandResult | null {
          const { command } = parseSlashCommand(input);
        
          if (!allowedCommands.has(command)) {
            return { type: 'error', content: 'Command not allowed' };
          }
        
          // 安全执行
        }
        

问 5:命令可以嵌套吗?


        // 不支持嵌套
        // "/help /compact" 会被解析为
        // command = "help", args = "/compact"
        
        // 因为解析器遇到第一个空格就停止
        


四、命令执行

4.1 getPromptForCommand


        // 每个命令都实现这个方法
        interface Command {
          name: string;
          description: string;
        
          async getPromptForCommand(
            args: string,
            context: CommandContext,
          ): Promise<CommandResult>;
        }
        

4.2 命令执行示例

源码位置:`src/commands/help/index.ts`


        // /help 命令实现
        const helpCommand: Command = {
          name: 'help',
          description: 'Show available commands',
        
          async getPromptForCommand(args: string, context: CommandContext) {
            // 如果没有参数,显示所有命令
            if (!args) {
              return {
                type: 'text',
                content: formatCommandsList(allCommands),
              };
            }
        
            // 搜索匹配的命令
            const matches = searchCommands(args, allCommands);
            return {
              type: 'text',
              content: formatCommandsList(matches),
            };
          },
        };
        

4.3 五问分析

问 1:命令返回什么?


        interface CommandResult {
          type: 'text' | 'error' | 'stop';
          content: string;
        
          // 可选:是否替换用户输入
          replaceInput?: string;
        
          // 可选:是否清空上下文
          clearContext?: boolean;
        }
        

问 2:命令可以修改上下文吗?


        // /clear 命令清空上下文
        const clearCommand: Command = {
          name: 'clear',
          description: 'Clear the conversation',
        
          async getPromptForCommand(args, context) {
            return {
              type: 'text',
              content: 'Context cleared.',
              clearContext: true,  // 标记清空
            };
          },
        };
        

问 3:命令可以中断循环吗?


        // /exit 命令中断
        const exitCommand: Command = {
          name: 'exit',
          description: 'Exit Claude Code',
        
          async getPromptForCommand(args, context) {
            return {
              type: 'stop',  // 标记停止
              content: 'Goodbye!',
            };
          },
        };
        


五、命令系统设计

5.1 架构图


        用户输入
            │
            ├── 普通文本 ──> query()
            │
            └── /命令 ──> parseSlashCommand()
                            │
                            ▼
                      命令解析器
                            │
                            ├── /help ──> helpCommand.getPromptForCommand()
                            ├── /compact ──> compactCommand.getPromptForCommand()
                            └── ...
        

5.2 责任链模式


        // 命令处理器形成责任链
        class CommandChain {
          private handlers: CommandHandler[] = [];
        
          addHandler(handler: CommandHandler) {
            this.handlers.push(handler);
          }
        
          async handle(input: string): Promise<CommandResult | null> {
            for (const handler of this.handlers) {
              if (handler.canHandle(input)) {
                return await handler.handle(input);
              }
            }
            return null;  // 无法处理
          }
        }
        


六、思考题

思考题 1:命令和工具的选择?

问题:什么时候用命令,什么时候用工具?

答案

场景方案原因
用户主动操作命令需要用户明确意图
模型决策操作工具模型根据上下文决定
修改会话状态命令/clear 等
获取外部信息工具WebSearch 等


思考题 2:如何实现命令历史?

问题:如何实现类似 shell 的命令历史(↑↓ 键)?

答案


        class CommandHistory {
          private history: string[] = [];
          private position: number = 0;
        
          add(command: string) {
            this.history.push(command);
            this.position = this.history.length;
          }
        
          up(): string | null {
            if (this.position > 0) {
              this.position--;
              return this.history[this.position];
            }
            return null;
          }
        
          down(): string | null {
            if (this.position < this.history.length - 1) {
              this.position++;
              return this.history[this.position];
            }
            return null;
          }
        }
        


思考题 3:如何实现命令补全?

问题:如何实现 Tab 补全?

答案


        function getCompletions(partial: string): string[] {
          // 匹配以 partial 开头的命令
          const matches = allCommands.filter(cmd =>
            cmd.name.startsWith(partial)
          );
        
          return matches.map(cmd => `/${cmd.name}`);
        }
        
        // 使用
        // 用户输入 /he + Tab
        // 补全为 /help
        


七、延伸阅读

文件核心内容
`src/commands.ts`命令系统入口
`src/commands/help/`/help 命令实现
`src/commands/compact/`/compact 命令实现


八、下节预告

下一节我们将深入 内置命令详解

- /help, /compact, /clear 的源码分析

- 命令的权限控制

- 命令的输出格式化


*- 第一轮:□ 事实准确性*

*- 第二轮:□ 深度与洞见*

*- 第三轮:□ 可读性与价值*