Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

第8章:命令系统

本章深入分析 Claude Code 的命令系统实现,包括命令目录结构、注册机制、主要命令详解和命令类型分类。

8.1 commands/ 目录结构

目录概览

src/commands/
├── add-dir/                     # 添加工作目录
├── agents/                      # Agent 管理
├── branch/                      # 分支切换
├── clear/                       # 清屏
├── compact/                     # 上下文压缩
├── config/                      # 配置管理
├── context/                     # 上下文查看
├── cost/                        # 费用统计
├── doctor/                      # 系统诊断
├── exit/                        # 退出 REPL
├── fast/                        # Fast Mode 切换
├── files/                       # 文件列表
├── help/                        # 帮助信息
├── hooks/                       # Hook 管理
├── init.js                      # 项目初始化
├── keybindings/                 # 键绑定配置
├── login/                       # 登录认证
├── logout/                      # 注销
├── mcp/                         # MCP 服务器管理
├── memory/                      # 记忆管理
├── model/                       # 模型选择
├── permissions/                 # 权限管理
├── plan/                        # Plan Mode
├── plugin/                      # 插件管理
├── resume/                      # 恢复会话
├── review.js                    # PR 审查
├── security-review.js           # 安全审查
├── session/                     # 会话管理
├── skills/                      # Skill 管理
├── status/                      # 状态查看
├── terminalSetup/               # 终端配置
├── theme/                       # 主题设置
├── vim/                         # Vim Mode
├── ...
├── commit.js                    # Git 提交
├── commit-push-pr.js            # 提交推送 PR
├── init.ts                      # 初始化入口
└── commands.ts                  # 命令注册表

命令类型分类

graph TD
    subgraph "命令类型"
        PROMPT[prompt<br/>发送到模型]
        LOCAL[local<br/>本地执行]
        LOCAL_JSX[local-jsx<br/>渲染 UI]
    end
    
    subgraph "Prompt 命令"
        P1[init<br/>初始化]
        P2[review<br/>审查]
        P3[security-review<br/>安全审查]
        P4[compact<br/>压缩]
    end
    
    subgraph "Local 命令"
        L1[clear<br/>清屏]
        L2[cost<br/>费用]
        L3[status<br/>状态]
        L4[model<br/>模型]
    end
    
    subgraph "Local-JSX 命令"
        J1[config<br/>配置]
        J2[mcp<br/>MCP]
        J3[login<br/>登录]
        J4[permissions<br/>权限]
    end
    
    PROMPT --> P1
    PROMPT --> P2
    PROMPT --> P3
    PROMPT --> P4
    LOCAL --> L1
    LOCAL --> L2
    LOCAL --> L3
    LOCAL --> L4
    LOCAL_JSX --> J1
    LOCAL_JSX --> J2
    LOCAL_JSX --> J3
    LOCAL_JSX --> J4

Command 类型定义

export type Command = 
  | PromptCommand
  | LocalCommand
  | LocalJSXCommand

export type PromptCommand = {
  type: 'prompt'
  name: string
  description: string
  aliases?: string[]
  
  // Skill 相关属性
  whenToUse?: string
  argumentHint?: string
  allowedTools?: string[]
  model?: string
  disableModelInvocation?: boolean
  userInvocable?: boolean
  contentLength: number
  
  // 来源信息
  source: 'builtin' | 'bundled' | 'skills' | 'plugin' | 'mcp'
  loadedFrom?: LoadedFrom
  
  // Hook 配置
  hooks?: HooksSettings
  
  // 执行方法
  getPromptForCommand: (args: string, context: ToolUseContext) => Promise<ContentBlockParam[]>
}

export type LocalCommand = {
  type: 'local'
  name: string
  description: string
  aliases?: string[]
  
  // 非交互模式处理
  nonInteractive?: LocalCommandNonInteractive
  
  // 执行方法
  handler: (args: string, context: LocalCommandContext) => Promise<LocalCommandResult>
}

export type LocalJSXCommand = {
  type: 'local-jsx'
  name: string
  description: string
  aliases?: string[]
  
  // JSX 渲染
  component: React.ComponentType<{ args: string; context: LocalJSXCommandContext }>
  
  // 可用性检查
  availability?: ('claude-ai' | 'console')[]
  isEnabled?: () => boolean
}

8.2 命令注册机制

commands.ts 注册逻辑

// 命令导入
import addDir from './commands/add-dir/index.js'
import commit from './commands/commit.js'
import config from './commands/config/index.js'
import init from './commands/init.js'
import review from './commands/review.js'
import securityReview from './commands/security-review.js'
// ... 更多命令导入

// 命令数组
const COMMANDS = memoize((): Command[] => [
  addDir,
  advisor,
  agents,
  branch,
  clear,
  config,
  cost,
  doctor,
  exit,
  fast,
  files,
  help,
  init,
  keybindings,
  mcp,
  model,
  permissions,
  plan,
  review,
  securityReview,
  session,
  skills,
  status,
  theme,
  vim,
  // ... 更多命令
])

// 构建命令名称集合
export const builtInCommandNames = memoize(
  (): Set<string> =>
    new Set(COMMANDS().flatMap(_ => [_.name, ...(_.aliases ?? [])])),
)

// 主命令加载函数
const loadAllCommands = memoize(async (cwd: string): Promise<Command[]> => {
  const [
    { skillDirCommands, pluginSkills, bundledSkills, builtinPluginSkills },
    pluginCommands,
    workflowCommands,
  ] = await Promise.all([
    getSkills(cwd),
    getPluginCommands(),
    getWorkflowCommands ? getWorkflowCommands(cwd) : Promise.resolve([]),
  ])

  return [
    ...bundledSkills,
    ...builtinPluginSkills,
    ...skillDirCommands,
    ...workflowCommands,
    ...pluginCommands,
    ...pluginSkills,
    ...COMMANDS(),
  ]
})

// 获取可用命令
export async function getCommands(cwd: string): Promise<Command[]> {
  const allCommands = await loadAllCommands(cwd)
  
  // 获取动态 Skills
  const dynamicSkills = getDynamicSkills()
  
  // 过滤可用命令
  const baseCommands = allCommands.filter(
    _ => meetsAvailabilityRequirement(_) && isCommandEnabled(_),
  )
  
  // 合并动态 Skills
  return [...baseCommands, ...uniqueDynamicSkills]
}

命令加载流程图

sequenceDiagram
    participant Main as main.tsx
    participant Commands as commands.ts
    participant Skills as skills/
    participant Plugins as plugins/
    participant Registry as Command Registry
    
    Main->>Commands: getCommands(cwd)
    Commands->>Commands: loadAllCommands(cwd)
    
    Commands->>Skills: getSkills(cwd)
    Skills-->>Commands: skillDirCommands, bundledSkills
    
    Commands->>Plugins: getPluginCommands()
    Plugins-->>Commands: pluginCommands, pluginSkills
    
    Commands->>Commands: COMMANDS()
    Commands-->>Commands: 内置命令列表
    
    Commands->>Commands: 合并所有命令
    Commands->>Commands: meetsAvailabilityRequirement()
    Commands->>Commands: isCommandEnabled()
    
    Commands-->>Main: 可用命令列表

可用性检查

export function meetsAvailabilityRequirement(cmd: Command): boolean {
  if (!cmd.availability) return true
  
  for (const a of cmd.availability) {
    switch (a) {
      case 'claude-ai':
        if (isClaudeAISubscriber()) return true
        break
      case 'console':
        if (
          !isClaudeAISubscriber() &&
          !isUsing3PServices() &&
          isFirstPartyAnthropicBaseUrl()
        ) return true
        break
    }
  }
  return false
}

命令查找函数

export function findCommand(
  commandName: string,
  commands: Command[],
): Command | undefined {
  return commands.find(
    _ =>
      _.name === commandName ||
      getCommandName(_) === commandName ||
      _.aliases?.includes(commandName),
  )
}

export function getCommand(commandName: string, commands: Command[]): Command {
  const command = findCommand(commandName, commands)
  if (!command) {
    throw ReferenceError(
      `Command ${commandName} not found. Available commands: ${commands
        .map(_ => getCommandName(_))
        .sort()
        .join(', ')}`,
    )
  }
  return command
}

8.3 主要命令详解

/init 命令

// init 命令定义
export default {
  type: 'prompt',
  name: 'init',
  description: 'Initialize a new CLAUDE.md file with codebase documentation',
  aliases: ['initialize'],
  contentLength: 0,
  progressMessage: 'initializing',
  source: 'builtin',
  async getPromptForCommand(args, context) {
    const cwd = args || getCwd()
    
    return [
      { type: 'text', text: `
# Project Initialization

Analyze the codebase at ${cwd} and create:

## CLAUDE.md Structure
1. Project overview
2. Key directories and their purposes
3. Important files
4. Build/test/lint commands
5. Architecture summary
6. Development guidelines

## Instructions
1. Use Glob to discover project structure
2. Use Read to analyze key configuration files
3. Use Grep to find patterns and conventions
4. Use Write to create CLAUDE.md

Focus on practical, actionable information for future sessions.
      ` }
    ]
  },
}

/commit 命令

// commit 命令定义(Internal Only)
export default {
  type: 'prompt',
  name: 'commit',
  description: 'Create a git commit',
  contentLength: 0,
  progressMessage: 'creating commit',
  source: 'builtin',
  async getPromptForCommand(args, context) {
    return [
      { type: 'text', text: `
# Create Git Commit

Create a git commit with the staged changes.

## Requirements
1. Run \`git status\` to see staged changes
2. Run \`git diff --cached\` to see diff
3. Analyze changes and draft commit message
4. Run \`git commit\` with the message

## Commit Message Guidelines
- Focus on the "why" rather than the "what"
- Be concise (under 72 chars for title)
- Use imperative mood
- Include Co-Authored-By attribution

## Important
- Never use --no-verify
- Never skip hooks
- If pre-commit hook fails, fix the issue and retry

Co-Authored-By: Claude <noreply@anthropic.com>
      ` }
    ]
  },
}

Internal Only Commands

/commit/review/security-review 等命令标记为 INTERNAL_ONLY_COMMANDS,仅在 USER_TYPE === 'ant' 且非 Demo 环境下可用。这些命令涉及敏感操作,不暴露给外部用户。

/review 命令

// review 命令定义
export default {
  type: 'prompt',
  name: 'review',
  description: 'Review a pull request',
  aliases: ['pr-review'],
  contentLength: 0,
  progressMessage: 'reviewing',
  source: 'builtin',
  async getPromptForCommand(args, context) {
    // 解析 PR 参数
    const prNumber = parsePRArg(args)
    
    return [
      { type: 'text', text: `
# Pull Request Review

Review PR #${prNumber} comprehensively.

## Steps
1. Fetch PR info: \`gh pr view ${prNumber}\`
2. Get diff: \`gh pr diff ${prNumber}\`
3. Analyze changes for:
   - Code quality
   - Bug risks
   - Security concerns
   - Test coverage
4. Check commit messages
5. Verify CI status

## Output Format
### Summary
Brief overview of changes

### Critical Issues
High-priority problems requiring attention

### Suggestions
Improvement recommendations

### Overall Assessment
Approve / Request Changes / Comment
      ` }
    ]
  },
}

/config 命令(Local-JSX)

// config 命令定义(交互式 UI)
export default {
  type: 'local-jsx',
  name: 'config',
  description: 'Configure Claude Code settings',
  availability: ['claude-ai', 'console'],
  
  component: ({ args, context }) => {
    // 渲染配置 UI
    return (
      <Box flexDirection="column">
        <Text bold>Configuration Settings</Text>
        {/* 配置选项 UI */}
      </Box>
    )
  },
  
  isEnabled: () => true,
}

/mcp 命令(子命令结构)

// mcp 命令定义(带子命令)
export default {
  type: 'local-jsx',
  name: 'mcp',
  description: 'Manage MCP servers',
  
  // 子命令
  subcommands: {
    add: {
      description: 'Add an MCP server',
      handler: async (args) => { /* ... */ },
    },
    remove: {
      description: 'Remove an MCP server',
      handler: async (args) => { /* ... */ },
    },
    list: {
      description: 'List configured MCP servers',
      handler: async () => { /* ... */ },
    },
    restart: {
      description: 'Restart an MCP server',
      handler: async (args) => { /* ... */ },
    },
  },
}

命令类型处理流程

flowchart TB
    subgraph "命令输入"
        INPUT[/command args] --> PARSE[解析命令名和参数]
    end
    
    subgraph "命令查找"
        PARSE --> FIND[findCommand]
        FIND --> CHECK{找到命令?}
        CHECK --> |"否"| ERROR[抛出错误]
        CHECK --> |"是"| TYPE{命令类型?}
    end
    
    subgraph "类型处理"
        TYPE --> |"prompt"| PROMPT[getPromptForCommand]
        TYPE --> |"local"| LOCAL[handler]
        TYPE --> |"local-jsx"| JSX[渲染 Component]
    end
    
    subgraph "执行结果"
        PROMPT --> MODEL[发送到模型]
        LOCAL --> RESULT[返回结果文本]
        JSX --> UI[显示 UI]
        
        MODEL --> TOOLS[工具调用循环]
        TOOLS --> OUTPUT[最终输出]
    end

远程模式命令过滤

// 远程安全命令列表
export const REMOTE_SAFE_COMMANDS: Set<Command> = new Set([
  session,    // 显示远程会话 QR
  exit,       // 退出
  clear,      // 清屏
  help,       // 帮助
  theme,      // 主题
  color,      // Agent 颜色
  vim,        // Vim 模式
  cost,       // 费用
  usage,      // 使用统计
  copy,       // 复制消息
  // ...
])

// Bridge 安全命令
export const BRIDGE_SAFE_COMMANDS: Set<Command> = new Set([
  compact,    // 上下文压缩
  clear,      // 清屏
  cost,       // 费用
  summary,    // 总结
  releaseNotes, // 更新日志
  files,      // 文件列表
])

// 过滤远程模式命令
export function filterCommandsForRemoteMode(commands: Command[]): Command[] {
  return commands.filter(cmd => REMOTE_SAFE_COMMANDS.has(cmd))
}

命令生命周期

stateDiagram-v2
    [*] --> Registered: 导入命令
    Registered --> Loaded: loadAllCommands
    Loaded --> Available: meetsAvailabilityRequirement + isEnabled
    Available --> Invoked: 用户调用
    Invoked --> Executing: 执行命令
    Executing --> Completed: 完成
    Executing --> Failed: 错误
    Completed --> [*]
    Failed --> [*]
    
    Available --> Disabled: isEnabled = false
    Disabled --> [*]

命令设计建议

  1. prompt 命令用于发送到模型处理,适合复杂任务
  2. local 命令用于快速本地操作,无需模型参与
  3. local-jsx 命令用于需要交互 UI 的场景
  4. 使用 availability 限制命令可见性
  5. 使用 aliases 提供便捷别名

至此,核心模块篇已完整分析了 Claude Code 的查询引擎、工具系统、技能系统和命令系统。后续章节将继续分析 UI 组件、Bridge 远程控制和服务层实现。