本文档深入解析 Claude Code CLI 中三个核心命令的实现机制,通过分析其架构模式、执行流程和设计决策,帮助开发者理解命令系统的工作原理和扩展方式。
命令架构基础:统一的类型系统
Claude Code 的命令系统建立在 三种核心命令类型 之上,每种类型对应不同的执行模式和复杂度等级。这种设计既保证了简单命令的轻量级实现,又为复杂交互提供了完整的生命周期管理。
Command 类型联合
type Command = CommandBase & (PromptCommand | LocalCommand | LocalJSXCommand)
所有命令共享 CommandBase 基础属性(名称、描述、启用状态等),但在执行机制上通过 类型鉴别器(type discriminator) 实现多态:
| 命令类型 | type 字段 | 执行模式 | 适用场景 | 示例 |
|---|---|---|---|---|
| PromptCommand | 'prompt' | 生成提示词 → 模型执行 | 简单任务自动化 | /commit, /review |
| LocalCommand | 'local' | 本地函数调用 | 纯逻辑操作 | /compact |
| LocalJSXCommand | 'local-jsx' | React 组件渲染 | 需要用户交互的复杂操作 | /ultrareview |
Sources: types/command.ts
架构对比:三种命令类型的设计哲学
graph TB
subgraph "PromptCommand 流程"
P1[用户输入 /commit] --> P2[getPromptForCommand]
P2 --> P3[生成动态提示词]
P3 --> P4[注入 Shell 命令输出]
P4 --> P5[发送给 Claude 模型]
P5 --> P6[模型执行 git 操作]
end
subgraph "LocalCommand 流程"
L1[用户输入 /compact] --> L2[懒加载命令模块]
L2 --> L3[调用本地 call 函数]
L3 --> L4[执行压缩逻辑]
L4 --> L5[更新消息列表]
end
subgraph "LocalJSXCommand 流程"
J1[用户输入 /ultrareview] --> J2[渲染 React 对话框]
J2 --> J3[用户确认配额/付费]
J3 --> J4[创建远程会话]
J4 --> J5[轮询结果回传]
end
style P1 fill:#e1f5ff
style L1 fill:#f3e5f5
style J1 fill:#fff3e0
设计决策解析:
-
PromptCommand 采用 声明式编程 模式,命令只需定义”做什么”(通过提示词),模型负责”如何做”。这降低了实现复杂度,但牺牲了精确控制。
-
LocalCommand 提供 命令式编程 能力,适合需要精确控制执行流程、访问本地状态或执行敏感操作的场景。
-
LocalJSXCommand 结合了 React 的 组件化 UI 和命令执行,用于需要复杂用户交互(如确认对话框、表单输入)的场景。
Sources: types/command.ts, commands.ts
/commit:智能 Git 提交生成器
核心机制:动态提示词构建
/commit 命令通过 模板字符串 + Shell 命令插值 的方式构建上下文丰富的提示词。其核心创新在于使用 executeShellCommandsInPrompt 函数,在提示词发送给模型前动态注入实时 Git 状态。
const command = {
type: 'prompt',
name: 'commit',
allowedTools: ['Bash(git add:*)', 'Bash(git status:*)', 'Bash(git commit:*)'],
async getPromptForCommand(_args, context) {
const promptContent = getPromptContent() // 包含 !`git status` 等插值
const finalContent = await executeShellCommandsInPrompt(
promptContent,
context,
'/commit'
)
return [{ type: 'text', text: finalContent }]
},
}
关键设计点:
-
工具白名单机制:
allowedTools限制模型只能执行 Git 相关操作,防止越权。这体现了 最小权限原则(Principle of Least Privilege)。 -
Shell 命令插值语法:提示词中的
!`git status`会被替换为实际命令输出,使得模型能获取实时上下文而无需用户手动粘贴。 -
Git 安全协议:提示词中内置了防护规则,如禁止修改配置、禁止跳过钩子、禁止
--amend(除非用户明确要求)。
Sources: commands/commit.ts
执行流程与上下文注入
sequenceDiagram
participant U as 用户
participant C as /commit 命令
participant S as Shell 执行器
participant M as Claude 模型
participant G as Git 仓库
U->>C: 输入 /commit
C->>C: getPromptContent()
Note over C: 生成包含插值的提示词模板
C->>S: executeShellCommandsInPrompt
S->>G: git status
G-->>S: 工作树状态
S->>G: git diff HEAD
G-->>S: 变更差异
S->>G: git log --oneline -10
G-->>S: 提交历史
S-->>C: 替换后的完整提示词
C->>M: 发送提示词 + 工具白名单
M->>M: 分析变更并起草提交消息
M->>G: git add <files>
M->>G: git commit -m "..."
G-->>M: 提交成功
M-->>U: 显示提交结果
上下文信息层次:
| 上下文类型 | Shell 命令 | 用途 |
|---|---|---|
| 工作树状态 | git status | 识别未跟踪文件和修改 |
| 变更差异 | git diff HEAD | 理解具体改动内容 |
| 当前分支 | git branch --show-current | 上下文感知 |
| 提交历史 | git log --oneline -10 | 学习项目提交风格 |
这种 渐进式上下文披露(Progressive Context Disclosure)确保模型既能获得足够信息生成高质量提交消息,又不会因过多无关信息而分心。
Sources: commands/commit.ts
HEREDOC 语法与提交消息格式
命令强制使用 HEREDOC 语法创建提交,确保多行消息的正确处理:
git commit -m "$(cat <<'EOF'
Commit message here.
[Optional attribution footer]
EOF
)"
这种设计解决了两个问题:
-
Shell 转义安全:HEREDOC 避免了消息中的特殊字符(如引号、美元符号)被 Shell 错误解析。
-
归属信息注入:通过
getAttributionTexts()动态添加可选的 Co-authored-by 信息,支持多人协作场景。
Sources: commands/commit.ts
/review:多层次代码审查系统
双路径架构:本地与远程审查
/review 命令展现了 功能分层 的设计模式,提供两种审查路径以适应不同需求:
| 特性 | /review (本地) | /ultrareview (远程) |
|---|---|---|
| 执行位置 | 本地 Claude 模型 | Claude Code on the Web |
| 审查深度 | 标准代码审查 | 深度 Bug 检测(10-20分钟) |
| 计费模式 | 消耗本地配额 | 独立配额/按需付费 |
| 实现类型 | PromptCommand | LocalJSXCommand |
| 用户交互 | 无 | 需确认配额/付费 |
Sources: commands/review.ts
本地审查实现:简洁的提示词工程
本地 /review 使用 结构化提示词 引导模型执行标准审查流程:
const LOCAL_REVIEW_PROMPT = (args: string) => `
You are an expert code reviewer. Follow these steps:
1. If no PR number is provided, run \`gh pr list\` to show open PRs
2. If a PR number is provided, run \`gh pr view <number>\` to get PR details
3. Run \`gh pr diff <number>\` to get the diff
4. Analyze the changes and provide a thorough code review that includes:
- Overview of what the PR does
- Analysis of code quality and style
- Specific suggestions for improvements
- Any potential issues or risks
Keep your review concise but thorough. Focus on:
- Code correctness
- Following project conventions
- Performance implications
- Test coverage
- Security considerations
PR number: ${args}
`
提示词设计模式:
-
步骤化指令:将复杂任务分解为明确的步骤(1-4),降低模型遗漏关键环节的概率。
-
结构化输出要求:通过列表形式规定审查维度,确保输出的全面性和一致性。
-
约束与平衡:既要求”concise”(简洁)又要求”thorough”(全面),引导模型在深度和广度间取得平衡。
Sources: commands/review.ts
远程审查实现:配额管理与用户确认
/ultrareview 采用 LocalJSXCommand 类型,需要处理复杂的用户交互和配额逻辑:
const ultrareview: Command = {
type: 'local-jsx',
name: 'ultrareview',
description: `~10–20 min · Finds and verifies bugs in your branch.
Runs in Claude Code on the web. See ${CCR_TERMS_URL}`,
isEnabled: () => isUltrareviewEnabled(),
load: () => import('./review/ultrareviewCommand.js'),
}
配额管理机制:
graph TD
A[用户调用 /ultrareview] --> B{检查订阅类型}
B -->|Team/Enterprise| C[直接通过]
B -->|Pro/Max| D[查询配额]
D --> E{剩余审查次数}
E -->|> 0| F[显示: 这是免费审查 X/Y]
E -->|= 0| G{余额检查}
G -->|充足| H[显示: 将使用额外用量]
G -->|不足| I[显示: 余额不足]
F --> J[用户确认对话框]
H --> J
J -->|确认| K[启动远程审查]
J -->|取消| L[取消操作]
Sources: commands/review.ts, commands/review/reviewRemote.ts
远程任务执行流程:
// 1. 检查资格和配额
const eligibility = await checkRemoteAgentEligibility()
if (!eligibility.ok) {
throw new Error(formatPreconditionError(eligibility))
}
// 2. 创建远程会话
const sessionUrl = await teleportToRemote({
repoPath: detectCurrentRepositoryWithHost(),
branch: getCurrentBranch(),
})
// 3. 注册任务以便轮询结果
registerRemoteAgentTask({
sessionId: remoteSessionId,
onResult: (result) => {
// 通过 task-notification 机制将结果注入本地会话
}
})
这种 异步任务 + 轮询 模式解耦了远程长时间运行任务和本地 UI,用户可以在审查进行时继续其他工作。
Sources: commands/review/reviewRemote.ts
/compact:智能上下文压缩引擎
多级压缩策略:性能与质量的平衡
/compact 命令是 Claude Code 中最复杂的本地命令,实现了 三层层叠压缩策略 以优化 token 使用:
graph TB
A[用户调用 /compact] --> B{有自定义指令?}
B -->|否| C[尝试 Session Memory 压缩]
B -->|是| D[跳过 Session Memory]
C --> E{成功?}
E -->|是| F[快速返回<br/>低成本压缩]
E -->|否| G{Reactive-Only 模式?}
D --> G
G -->|是| H[Reactive Compact 路径]
G -->|否| I[传统压缩路径]
I --> J[Microcompact 预处理]
J --> K[compactConversation 主压缩]
H --> L[执行 Hooks]
K --> L
F --> M[清理与缓存重置]
L --> M
style C fill:#c8e6c9
style F fill:#a5d6a7
style H fill:#fff9c4
style I fill:#ffccbc
三层层叠详解:
| 层级 | 策略 | Token 成本 | 适用场景 | 实现位置 |
|---|---|---|---|---|
| 1. Session Memory | 提取结构化记忆 | ~1K tokens | 无自定义指令的常规压缩 | sessionMemoryCompact.ts |
| 2. Reactive Compact | 增量式分组压缩 | ~5K tokens | Reactive-Only 模式 | reactiveCompact.ts |
| 3. Legacy Compact | 全量对话摘要 | ~10K+ tokens | 需要自定义摘要指令 | compact.ts |
Sources: commands/compact/compact.ts
Session Memory 压缩:低成本优先路径
Session Memory 压缩通过 结构化记忆提取 替代对话摘要,大幅降低 API 调用成本:
const sessionMemoryResult = await trySessionMemoryCompaction(
messages,
context.agentId,
)
if (sessionMemoryResult) {
getUserContext.cache.clear?.()
runPostCompactCleanup()
return {
type: 'compact',
compactionResult: sessionMemoryResult,
displayText: buildDisplayText(context),
}
}
核心优势:
-
零 API 调用:不需要调用 Claude API 生成摘要,直接从对话中提取结构化信息。
-
保留关键信息:通过启发式算法识别并保留决策点、错误解决方案等高价值内容。
-
快速执行:通常在 1-2 秒内完成,用户几乎无感知。
Sources: commands/compact/compact.ts
Legacy 压缩流程:完整实现剖析
当需要自定义摘要指令或 Session Memory 不适用时,系统回退到 Legacy 压缩路径:
1. Microcompact 预处理
const microcompactResult = await microcompactMessages(messages, context)
const messagesForCompact = microcompactResult.messages
作用:在主压缩前通过启发式规则快速移除冗余内容(如重复的文件读取结果),减少后续 API 调用的 token 消耗。
Sources: commands/compact/compact.ts
2. compactConversation 核心逻辑
const result = await compactConversation(
messagesForCompact, // 待压缩消息
context, // 执行上下文
await getCacheSharingParams(context, messagesForCompact), // 缓存参数
false, // 是否部分压缩
customInstructions, // 用户自定义指令
false, // 是否静默模式
)
关键步骤:
sequenceDiagram
participant C as compactConversation
participant H as Pre-Compact Hooks
participant A as Claude API
participant P as Post-Compact Hooks
C->>H: 执行前置钩子
H-->>C: 返回自定义指令
C->>C: stripImagesFromMessages
Note over C: 移除图片以避免 PTL 错误
C->>C: groupMessagesByApiRound
Note over C: 按 API 调用轮次分组
C->>A: 发送摘要请求
A-->>C: 返回摘要文本
C->>C: createCompactBoundaryMessage
Note over C: 创建压缩边界标记
C->>P: 执行后置钩子
P-->>C: 返回用户显示消息
C->>C: 恢复关键文件内容
C->>C: 恢复技能指令
Sources: services/compact/compact.ts
3. 图片移除策略
为防止压缩 API 调用本身触发 prompt-too-long 错误,系统会移除图片并用文本标记替换:
export function stripImagesFromMessages(messages: Message[]): Message[] {
return messages.map(message => {
if (message.type !== 'user') return message
const newContent = content.flatMap(block => {
if (block.type === 'image') {
return [{ type: 'text', text: '[image]' }]
}
if (block.type === 'document') {
return [{ type: 'text', text: '[document]' }]
}
// 处理 tool_result 中嵌套的图片
return [block]
})
return { ...message, message: { ...message.message, content: newContent } }
})
}
设计权衡:牺牲图片信息以换取压缩成功率,但保留 [image] 标记让摘要提及”用户分享了图片”。
Sources: services/compact/compact.ts
4. Post-Compact 恢复机制
压缩后会智能恢复 关键文件内容 和 技能指令,确保后续对话的连贯性:
export const POST_COMPACT_MAX_FILES_TO_RESTORE = 5
export const POST_COMPACT_TOKEN_BUDGET = 50_000
export const POST_COMPACT_MAX_TOKENS_PER_FILE = 5_000
export const POST_COMPACT_SKILLS_TOKEN_BUDGET = 25_000
export const POST_COMPACT_MAX_TOKENS_PER_SKILL = 5_000
Token 预算分配:
- 文件恢复:50K 总预算,单个文件最多 5K,最多恢复 5 个最近访问的文件
- 技能恢复:25K 总预算,单个技能最多 5K(技能文件通常较大,如 verify=18.7KB)
Sources: services/compact/compact.ts
Hook 系统:扩展压缩生命周期
压缩命令提供了 两个扩展点 允许自定义逻辑注入:
| Hook 类型 | 执行时机 | 用途 | 参数 |
|---|---|---|---|
| Pre-Compact | 压缩开始前 | 添加自定义摘要指令、记录状态 | { trigger, customInstructions } |
| Post-Compact | 压缩完成后 | 清理、通知、状态同步 | { trigger, customInstructions, compactionResult } |
// Pre-Compact Hook 示例
const hookResult = await executePreCompactHooks(
{ trigger: 'manual', customInstructions: customInstructions || null },
context.abortController.signal,
)
// 合并 Hook 返回的自定义指令
const mergedInstructions = mergeHookInstructions(
customInstructions,
hookResult.newCustomInstructions,
)
实际应用场景:
- 团队规范注入:Pre-Compact Hook 自动添加”优先保留架构决策”的指令。
- 外部系统集成:Post-Compact Hook 将压缩事件同步到监控平台。
- 自定义摘要格式:通过 customInstructions 要求摘要遵循特定模板。
Sources: commands/compact/compact.ts, services/compact/compact.ts
设计模式总结与最佳实践
三种命令类型的选型指南
| 需求特征 | 推荐类型 | 理由 |
|---|---|---|
| 简单自动化任务,可由模型完成 | PromptCommand | 实现简单,声明式定义 |
| 需要访问本地状态或执行敏感操作 | LocalCommand | 完全控制执行流程 |
| 需要复杂用户交互(对话框、表单) | LocalJSXCommand | React 组件化 UI |
| 需要长时间运行或远程执行 | LocalJSXCommand | 异步任务管理 |
命令实现的关键原则
-
最小权限原则:通过
allowedTools限制模型能力范围,防止越权操作(见/commit)。 -
渐进式上下文披露:只提供任务所需的最小上下文,避免信息过载(见
/commit的 Git 状态注入)。 -
优雅降级:为复杂操作提供多层回退策略,确保基本功能可用(见
/compact的三层层叠)。 -
用户确认机制:对不可逆或高成本操作,通过 LocalJSXCommand 提供交互式确认(见
/ultrareview)。 -
扩展性设计:通过 Hook 系统允许第三方注入自定义逻辑,保持核心简洁。
性能优化技巧
- 懒加载模块:LocalCommand 和 LocalJSXCommand 使用
load()函数延迟加载重型依赖。
const compact = {
type: 'local',
load: () => import('./compact.js'), // 只在调用时加载
}
-
缓存清理:压缩后主动清理
getUserContext.cache防止内存泄漏。 -
并发执行:独立操作(如 Pre-Compact Hooks 和缓存参数构建)并行执行以减少延迟。
const [hookResult, cacheSafeParams] = await Promise.all([
executePreCompactHooks(...),
getCacheSharingParams(...),
])
Sources: commands/compact/index.ts, commands/compact/compact.ts
延伸阅读
要深入理解命令系统的完整架构,建议按以下顺序阅读相关文档:
- 命令架构基础:命令架构:Command 接口与注册机制 — 了解命令注册、发现和调用的完整流程
- 压缩服务深度解析:压缩服务:上下文压缩与内存优化策略 — 探索压缩算法、Token 预算管理等高级主题
- Hook 系统原理:配置管理:settings、环境变量与迁移系统 — 学习如何配置和使用各类 Hook