基于 2026年03月31日 泄露的 Claude Code CLI 源代码分析。 约 1,900 个文件,512,000+ 行 TypeScript 代码。
- 一、项目概览
- 二、技术栈
- 三、目录结构全景
- 四、核心架构:Agent 循环
- 五、工具系统总体设计
- 六、工具执行管线
- 七、所有工具详细设计
- 八、权限系统
- 九、Hook 系统
- 十、上下文管理与压缩策略
- 十一、子 Agent 系统
- 十二、UI 与渲染层
- 十三、状态管理
- 十四、服务层
- 十五、远程与桥接
- 十六、扩展机制
- 十七、性能优化设计
- 十八、设计模式总结
Claude Code 是 Anthropic 官方的 CLI 工具,允许用户在终端中直接与 Claude AI 交互,执行软件工程任务——编辑文件、运行命令、搜索代码库、管理 git 工作流等。
项目为单体结构(非 monorepo),所有源码集中在 src/ 目录下,根目录仅有 README.md 和 src/。
| 类别 | 技术 |
|---|---|
| 运行时 | Bun |
| 语言 | TypeScript (strict) |
| 终端 UI | React + Ink(自定义 fork) |
| CLI 解析 | Commander.js (@commander-js/extra-typings) |
| Schema 验证 | Zod v4 |
| 代码搜索 | ripgrep |
| 协议 | MCP SDK、LSP |
| API | Anthropic SDK(支持直连、Bedrock、Vertex、Foundry) |
| 遥测 | OpenTelemetry + gRPC |
| 特性开关 | GrowthBook + bun:bundle 编译期消除 |
| 认证 | OAuth 2.0、JWT、macOS Keychain |
src/
├── main.tsx # 主入口:Commander.js CLI 解析 + React/Ink 渲染初始化
├── QueryEngine.ts # 核心查询引擎(~46K 行)
├── query.ts # 查询管线(query loop 实现)
├── tools.ts # 工具注册表
├── Tool.ts # 工具类型定义(~29K 行)
├── commands.ts # 命令注册表(~25K 行)
│
├── entrypoints/ # 启动入口(cli.tsx 为最外层)
├── tools/ # 工具实现(~40 个)
│ ├── AgentTool/ # 子 Agent 工具
│ ├── BashTool/ # Shell 命令执行
│ ├── FileReadTool/ # 文件读取
│ ├── FileWriteTool/ # 文件创建/覆盖
│ ├── FileEditTool/ # 文件局部编辑
│ ├── GlobTool/ # 文件模式匹配
│ ├── GrepTool/ # ripgrep 内容搜索
│ ├── WebFetchTool/ # URL 内容获取
│ ├── WebSearchTool/ # 网络搜索
│ ├── MCPTool/ # MCP 工具模板
│ ├── NotebookEditTool/ # Jupyter Notebook 编辑
│ ├── AskUserQuestionTool/ # 用户交互问答
│ ├── TodoWriteTool/ # 待办列表管理
│ ├── SkillTool/ # 技能执行
│ ├── SendMessageTool/ # 多 Agent 消息发送
│ ├── ToolSearchTool/ # 延迟工具发现
│ └── ... # 更多工具
│
├── commands/ # 斜杠命令实现(~50 个)
├── components/ # Ink UI 组件(~140 个)
├── screens/ # 全屏 UI(REPL、Doctor、Resume)
├── hooks/ # React Hooks
├── services/ # 服务层
│ ├── api/ # Anthropic API 客户端
│ ├── mcp/ # MCP 连接管理
│ ├── compact/ # 上下文压缩
│ ├── tools/ # 工具执行编排
│ ├── analytics/ # 特性开关与分析
│ ├── lsp/ # LSP 客户端
│ ├── oauth/ # OAuth 认证
│ └── ...
│
├── state/ # 状态管理(自定义 Store)
├── context/ # React Context Providers
├── query/ # 查询管线辅助模块
├── schemas/ # 配置 Schema(Zod)
├── types/ # TypeScript 类型定义
├── utils/ # 工具函数
│
├── bridge/ # IDE 桥接(VS Code / JetBrains / claude.ai)
├── coordinator/ # 多 Agent 协调器
├── remote/ # 远程会话(CCR Sessions API)
├── server/ # 直连自建 Session 服务端
├── plugins/ # 插件系统
├── skills/ # 技能系统
├── tasks/ # 任务管理
├── ink/ # 自定义 Ink 渲染器
├── keybindings/ # 快捷键配置
├── vim/ # Vim 模式
├── voice/ # 语音输入
├── memdir/ # 持久化记忆目录
├── migrations/ # 配置迁移
├── buddy/ # 伴侣精灵(彩蛋)
├── outputStyles/ # 输出样式
└── upstreamproxy/ # 代理配置
Claude Code 的 Agent 采用经典的 ReAct(Reasoning + Acting)循环,通过一个 while(true) 异步生成器驱动模型调用与工具执行的交替进行。
entrypoints/cli.tsx
│ 最外层入口,处理 --version、MCP、daemon 等快速路径
│ 默认路径动态 import main.tsx
▼
main.tsx (Commander.js)
│ 创建完整 CLI 程序,解析参数
│ 并行预取:MDM 设置、Keychain、GrowthBook
▼
replLauncher.tsx → App.tsx + REPL.tsx
│ 启动 Ink 渲染器,展示交互界面
▼
用户输入
│
▼
handlePromptSubmit.ts
│ 校验空输入、解析引用、expandPastedTextRefs
▼
processUserInput.ts
│ 解析斜杠命令 / 处理文本提示 / UserPromptSubmit hooks
▼
QueryEngine.submitMessage()
│ 维护消息数组、构建系统提示
▼
query() → queryLoop()
│ 核心 Agent 循环
query.ts 中的 queryLoop() 是一个 while(true) 异步生成器,每轮迭代流程:
┌─────────────────────────────────────────────────────────────┐
│ queryLoop 每轮迭代 │
│ │
│ 1. 上下文裁剪 │
│ ├─ getMessagesAfterCompactBoundary() 从最近压缩边界开始 │
│ ├─ applyToolResultBudget() 大工具结果落盘 │
│ ├─ snipCompactIfNeeded() 历史截断 │
│ ├─ microcompactMessages() 微压缩 │
│ └─ autoCompactIfNeeded() 自动全量压缩 │
│ │
│ 2. 系统提示构建 │
│ └─ appendSystemContext(systemPrompt, systemContext) │
│ │
│ 3. 模型调用(流式) │
│ └─ deps.callModel() → queryModelWithStreaming() │
│ └─ anthropic.beta.messages.create({stream: true}) │
│ │
│ 4. 流式处理 │
│ ├─ 累积 assistantMessages │
│ ├─ 提取 toolUseBlocks │
│ └─ StreamingToolExecutor(可选:边收流边执行工具) │
│ │
│ 5. 分支判断 │
│ ├─ 无 tool_use → 处理错误恢复 / Stop hooks → return │
│ └─ 有 tool_use → 进入工具执行 │
│ │
│ 6. 工具执行 │
│ └─ runTools() / StreamingToolExecutor │
│ ├─ 权限检查 (canUseTool) │
│ ├─ Pre/Post Tool Hooks │
│ └─ tool.call(args, context, ...) │
│ │
│ 7. 组装下一轮消息 │
│ └─ messages = [...现有消息, ...助手消息, ...工具结果] │
│ │
│ 8. 继续 while(true) 下一轮 ──→ 回到步骤 1 │
└─────────────────────────────────────────────────────────────┘
query/deps.ts 定义了 QueryDeps 接口,允许测试时 mock 核心依赖:
export type QueryDeps = { callModel: typeof queryModelWithStreaming // 模型调用 microcompact: typeof microcompactMessages // 微压缩 autocompact: typeof autoCompactIfNeeded // 自动压缩 uuid: () => string // UUID 生成 }
流式入口(services/api/claude.ts):
queryModelWithStreaming()→withStreamingVCR包装 →queryModel()queryModel()调用anthropic.beta.messages.create({ ...params, stream: true })+.withResponse()- 直接使用原始
Stream<BetaRawMessageStreamEvent>(而非BetaMessageStream),避免input_json_delta的 O(n2) 解析 - 流空闲看门狗、
releaseStreamResources防资源泄漏 - 失败时可降级到
executeNonStreamingRequest
客户端工厂(services/api/client.ts):
getAnthropicClient()按getAPIProvider()走直连 Anthropic、Bedrock、Vertex、Foundry 等后端- 处理 OAuth / API key 认证
Tool<Input, Output, P> 是所有工具的核心类型(src/Tool.ts),泛型参数:
Input extends AnyObject— Zod schema 描述的输入类型Output— 工具返回数据类型P extends ToolProgressData— 进度事件类型
| 字段 | 类型 | 说明 |
|---|---|---|
name |
readonly string |
工具唯一标识符 |
aliases? |
string[] |
向后兼容别名(重命名工具时使用) |
searchHint? |
string |
ToolSearch 关键词匹配用的短语(3-10 词) |
maxResultSizeChars |
number |
超过此阈值的结果会持久化到磁盘(Infinity 禁用) |
strict? |
readonly boolean |
严格模式,API 更严格遵循参数 schema |
| 字段 | 类型 | 说明 |
|---|---|---|
inputSchema |
readonly Input |
Zod schema 定义输入参数 |
inputJSONSchema? |
ToolInputJSONSchema |
MCP 工具直接使用 JSON Schema |
outputSchema? |
z.ZodType<unknown> |
可选的输出 schema |
| 字段 | 类型 | 说明 |
|---|---|---|
isMcp? |
boolean |
标记为 MCP 工具 |
isLsp? |
boolean |
标记为 LSP 工具 |
mcpInfo? |
{ serverName, toolName } |
MCP 服务器和工具原始名称 |
| 字段 | 类型 | 说明 |
|---|---|---|
shouldDefer? |
readonly boolean |
为 true 时初始以 defer_loading 发送,需 ToolSearch 激活 |
alwaysLoad? |
readonly boolean |
永不延迟,即使启用了 ToolSearch |
isEnabled(): boolean // 工具是否启用 isConcurrencySafe(input): boolean // 是否可并发安全执行 isReadOnly(input): boolean // 是否只读 isDestructive?(input): boolean // 是否不可逆(删除/覆盖/发送) interruptBehavior?(): 'cancel' | 'block' // 用户新消息时:cancel 取消 / block 阻塞 isSearchOrReadCommand?(input): { isSearch; isRead; isList? } // UI 折叠判断 requiresUserInteraction?(): boolean // 需要用户交互 isTransparentWrapper?(): boolean // 委托渲染给内部工具(如 REPL)
call(args, context: ToolUseContext, canUseTool, parentMessage, onProgress?): Promise<ToolResult<Output>> description(input, options): Promise<string> // 面向模型的工具描述 prompt(options): Promise<string> // 面向模型的使用提示 validateInput?(input, context): Promise<ValidationResult> // 自定义输入验证
checkPermissions(input, context): Promise<PermissionResult> preparePermissionMatcher?(input): Promise<(pattern: string) => boolean> // Hook 条件匹配器
userFacingName(input): string renderToolUseMessage(input, options): React.ReactNode renderToolResultMessage?(content, progressMessages, options): React.ReactNode renderToolUseProgressMessage?(progressMessages, options): React.ReactNode renderToolUseTag?(input): React.ReactNode // 标签元数据(超时、模型等) renderGroupedToolUse?(toolUses, options): React.ReactNode | null // 批量渲染 getToolUseSummary?(input): string | null // 简要摘要 getActivityDescription?(input): string | null // 活动描述 renderToolUseQueuedMessage?(): React.ReactNode renderToolUseRejectedMessage?(input, options): React.ReactNode renderToolUseErrorMessage?(result, options): React.ReactNode
inputsEquivalent?(a, b): boolean // 判断两个输入是否等价 toAutoClassifierInput(input): unknown // 安全分类器的紧凑输入表示 mapToolResultToToolResultBlockParam(content, toolUseID): ToolResultBlockParam // 转 API 格式 extractSearchText?(out): string // 转录搜索索引 getPath?(input): string // 文件路径相关工具
// PermissionResult — 工具级权限返回 type PermissionResult<Input> = | { behavior: 'allow'; updatedInput?: Input } | { behavior: 'deny'; message: string; decisionReason: PermissionDecisionReason } | { behavior: 'ask'; message: string; suggestions?: PermissionUpdate[] } | { behavior: 'passthrough'; message: string } // 交给通用权限系统 // PermissionDecisionReason — 10 种决策原因 type PermissionDecisionReason = | 'rule' | 'mode' | 'subcommandResults' | 'permissionPromptTool' | 'hook' | 'asyncAgent' | 'sandboxOverride' | 'classifier' | 'workingDir' | 'safetyCheck' | 'other' // PermissionMode — 7 种权限模式 type PermissionMode = | 'acceptEdits' | 'bypassPermissions' | 'default' | 'dontAsk' | 'plan' | 'auto' | 'bubble'
所有工具通过 buildTool(def: ToolDef) 创建,填充 fail-closed 默认值:
const TOOL_DEFAULTS = { isEnabled: () => true, // 默认启用 isConcurrencySafe: (_input?) => false, // 假设不安全(保守) isReadOnly: (_input?) => false, // 假设会写(保守) isDestructive: (_input?) => false, // 默认非破坏性 checkPermissions: (input) => // 交给通用权限系统 Promise.resolve({ behavior: 'allow', updatedInput: input }), toAutoClassifierInput: (_input?) => '', // 跳过分类器 userFacingName: () => '', // 用 def.name 覆盖 } function buildTool(def: ToolDef): Tool { return { ...TOOL_DEFAULTS, userFacingName: () => def.name, ...def, // 调用方的定义覆盖默认值 } }
传给每个 tool.call() 的上下文对象,包含:
配置选项:
options.commands/options.tools/options.mainLoopModel— 命令、工具列表、模型options.mcpClients/options.mcpResources— MCP 连接和资源options.agentDefinitions— Agent 定义options.maxBudgetUsd?— 预算限制options.customSystemPrompt?/options.appendSystemPrompt?— 自定义系统提示
执行控制:
abortController— 取消控制器readFileState— 文件读取缓存(mtime 追踪,防重复读取)messages— 对话消息列表toolUseId?— 当前工具调用 ID
状态管理:
getAppState()/setAppState()— 全局应用状态读写updateFileHistoryState/updateAttributionState— 文件历史和归属追踪
UI 回调:
setToolJSX?— 设置工具 JSX 渲染addNotification?— 添加通知sendOSNotification?— 系统级通知
Agent 特有:
agentId?/agentType?— 子 Agent 标识queryTracking?— 查询链追踪(chainId + depth)
权限相关:
toolDecisions?— 工具决策缓存(accept/reject + source + timestamp)localDenialTracking?— 异步子 Agent 的本地拒绝追踪
getAllBaseTools() ← 收集所有工具(按 feature flag 条件加载)
│
▼
getTools(permissionContext) ← 过滤:deny 规则 → REPL 隐藏 → isEnabled
│
▼
assembleToolPool(perms, mcp) ← 内置 + MCP 合并,内置优先,按名排序保 prompt cache
assembleToolPool() 是组装最终工具池的唯一真相来源(REPL 和 runAgent 都使用它):
getTools(permissionContext)获取内置工具filterToolsByDenyRules(mcpTools, permissionContext)过滤 MCP 工具- 内置和 MCP 工具分别按名排序(保持内置工具为连续前缀,确保 prompt-cache 稳定性)
uniqBy([...builtIn.sort(), ...mcp.sort()], 'name')— 同名时内置优先
1. 定义阶段
ToolDef (可省略默认方法) → buildTool() → Tool (完整接口)
2. 注册阶段
getAllBaseTools() — 收集所有工具(条件加载)
3. 过滤阶段
getTools(permissionContext)
→ filterToolsByDenyRules() 移除被拒绝的工具
→ REPL 过滤 隐藏 REPL_ONLY_TOOLS
→ isEnabled() 过滤 移除禁用工具
4. 合并阶段
assembleToolPool(permissionContext, mcpTools)
→ 内置 + MCP 工具按名去重合并
5. 延迟加载(可选)
shouldDefer=true 的工具以 defer_loading:true 发送给 API
模型通过 ToolSearchTool 按 searchHint 发现并加载
6. 执行阶段
tool.validateInput(input, context)
tool.checkPermissions(input, context)
通用权限系统 + hooks + 分类器
tool.call(args, context, canUseTool, parentMessage, onProgress)
→ 返回 ToolResult<Output>
7. 结果处理
tool.mapToolResultToToolResultBlockParam() → 转 API 格式
tool.renderToolResultMessage() → UI 渲染
services/tools/toolOrchestration.ts 中的 runTools() 是非流式模式入口:
分区策略 — partitionToolCalls():
- 每个工具通过
tool.isConcurrencySafe(parsedInput)判定是否并发安全 - 连续的并发安全工具合并成一个批次,并行执行
- 非并发安全工具单独成为一个批次,串行执行
isConcurrencySafe抛异常时保守视为非并发安全
并发执行:
- 使用
all()工具函数交错多个 async generator 输出 - 最大并发数
CLAUDE_CODE_MAX_TOOL_USE_CONCURRENCY(默认 10) - context modifiers 被缓存,所有工具执行完毕后按顺序应用
串行执行:
- 每个工具完成后立即应用 context modifier,下一个工具看到更新后的上下文
runToolUse()(services/tools/toolExecution.ts):
┌──────────────────────────────────────────────────────────┐
│ 1. 工具查找 │
│ 在可见工具集查找 → 回退到全量列表(处理废弃别名) │
│ 找不到 → 返回 <tool_use_error> │
│ │
│ 2. 中止检查 │
│ abortController.signal.aborted → 返回取消消息 │
│ │
│ 3. 两阶段输入验证 │
│ Phase 1: Zod schema 验证 │
│ 失败 → formatZodValidationError │
│ 延迟加载工具 schema 未发送 → 提示调 ToolSearch │
│ Phase 2: tool.validateInput() │
│ 自定义逻辑(如"必须先读再写") │
│ │
│ 4. 输入预处理 │
│ 剥离内部注入字段 → backfillObservableInput │
│ │
│ 5. PreToolUse 钩子 │
│ 可能:修改输入 / 做权限决策 / 停止执行 │
│ 类型:message / hookPermissionResult / │
│ hookUpdatedInput / preventContinuation / │
│ additionalContext / stop │
│ │
│ 6. 权限检查 (resolveHookPermissionDecision) │
│ ┌─ hook allow + deny 规则 → deny 覆盖 │
│ ├─ hook allow + ask 规则 → 仍需用户交互 │
│ ├─ hook deny → 直接拒绝 │
│ └─ 无 hook → canUseTool 正常流程 │
│ 安全不变式:hook 的 allow 不能绕过 deny/ask 规则 │
│ │
│ 7. 实际执行 │
│ tool.call(callInput, context, canUseTool, │
│ assistantMessage, onProgress) │
│ │
│ 8. PostToolUse 钩子 │
│ MCP 工具:先跑 hook(可能修改输出),再 addToolResult │
│ 非 MCP:先 addToolResult,再跑 hook │
│ │
│ 9. 结果格式化 │
│ tool.mapToolResultToToolResultBlockParam() │
│ → ToolResultBlockParam → createUserMessage │
│ 附加 acceptFeedback / contentBlocks │
│ │
│ 10. 错误路径 │
│ → PostToolUseFailure 钩子 → formatError │
│ → MCP 认证错误 → 更新客户端状态为 needs-auth │
└──────────────────────────────────────────────────────────┘
StreamingToolExecutor(services/tools/StreamingToolExecutor.ts)实现了边接收模型输出边执行工具:
核心思想: 在模型仍在生成输出的同时开始执行已完成的工具调用。每个工具有状态机:queued → executing → completed → yielded。
并发控制规则:
- 没有正在执行的工具 → 可以执行
- 当前和新工具都是并发安全的 → 可以并行
- 否则必须等待
兄弟错误传播:
- 只有 Bash 工具错误会取消兄弟工具(Bash 命令常有隐含依赖链)
- Read / WebFetch 等独立工具的错误不影响并行伙伴
结果按序输出:
- progress 消息立即输出
- 最终结果按接收顺序输出
- 遇到还在执行的非并发安全工具 → 阻塞后续结果(维护顺序语义)
中断行为:
cancel:用户中断时立即取消(如 Bash、Agent)block(默认):阻塞直到完成
Discard 机制: 流式回退时,所有待执行工具被丢弃,已排队的不启动,正在执行的收到合成错误消息。
外层 try-catch 捕获所有未处理异常,返回 <tool_use_error> 格式的错误消息。
错误分类(遥测):
TelemetrySafeError→ 使用 telemetryMessage- Node.js fs errors → 使用 error code(ENOENT、EACCES)
- 稳定
.name属性(>3 字符,未被 minify)→ 使用 error.name - 兜底 →
"Error"或"UnknownError"
| 属性 | 值 |
|---|---|
| name | Read |
| inputSchema | file_path: string, offset?: number, limit?: number, pages?: string |
| concurrency | true(可并发) |
| readOnly | true |
| maxResultSizeChars | Infinity(永不持久化,避免循环读取) |
| strict | true |
call() 实现:
- 文本文件:行范围读取(offset/limit),添加行号,token 限制验证
- 图片:base64 编码,自动调整大小/压缩以适应 token 预算
- PDF:整页或按页范围提取(poppler-utils),支持 DocumentBlockParam
- Notebook:
.ipynbJSON 解析 - 重复读取消除:通过
readFileStatemtime 检查,如果文件未变则返回file_unchanged存根 - 安全:阻止设备文件(/dev/zero 等),UNC 路径保护,网络安全提醒
- 文件不存在时建议相似文件名
- macOS 截图路径空格字符兼容
- 触发技能发现(
discoverSkillDirsForPaths)
权限:checkReadPermissionForTool — 文件系统读权限检查
| 属性 | 值 |
|---|---|
| name | Write |
| inputSchema | file_path: string, content: string |
| concurrency | false |
| readOnly | false |
| maxResultSizeChars | 100,000 |
| strict | true |
call() 实现:
- 创建新文件或完整覆盖现有文件
- 必须先读取再写入(validateInput 检查
readFileState) - 原子性:读取-修改-写入关键区间内避免 async 操作
- 编码保持(utf8/utf16le)
- LSP 通知(didChange + didSave)
- VSCode diff 视图通知
- 文件历史备份
- 生成 diff patch 用于 UI 展示
validateInput:检查 deny 规则、UNC 路径、必须先读取、mtime 新鲜度、团队内存秘密保护
权限:checkWritePermissionForTool
| 属性 | 值 |
|---|---|
| name | Edit |
| inputSchema | file_path: string, old_string: string, new_string: string, replace_all?: boolean |
| concurrency | false |
| readOnly | false |
| maxResultSizeChars | 100,000 |
| strict | true |
call() 实现:
- 字符串替换编辑,
findActualString引号标准化(curly ↔ straight quotes) preserveQuoteStyle保持文件原有引号风格- 支持
replace_all全部替换 - 空
old_string+ 不存在的文件 = 创建新文件 - 空
old_string+ 空文件 = 替换空内容 - 1 GiB 文件大小上限
- LSP / VSCode 通知同 FileWriteTool
- Settings 文件特殊验证
validateInput(非常严格):
- 文件必须存在
- 必须先读后写
- mtime 新鲜度检查
old_string必须在文件中唯一匹配(多匹配需replace_all).ipynb文件重定向到 NotebookEditTool
权限:checkWritePermissionForTool
| 属性 | 值 |
|---|---|
| name | NotebookEdit |
| inputSchema | notebook_path: string, cell_id?: string, new_source: string, cell_type?: 'code'|'markdown', edit_mode?: 'replace'|'insert'|'delete' |
| concurrency | false |
| readOnly | false |
| shouldDefer | true |
call() 实现:
- replace / insert / delete 三种编辑模式
- 按 cell ID 或索引定位
- 重置执行计数和输出(代码单元格)
- 保持 notebook 格式(nbformat 版本兼容)
- 必须先读取再编辑
权限:checkWritePermissionForTool
| 属性 | 值 |
|---|---|
| name | Glob |
| inputSchema | pattern: string, path?: string |
| concurrency | true |
| readOnly | true |
| isSearchOrReadCommand | {isSearch: true, isRead: false} |
call() 实现:
- 使用
glob()执行文件模式匹配 - 默认限制 100 个结果(可通过
globLimits调整) - 结果按修改时间排序
- 路径相对化以节省 token
权限:checkReadPermissionForTool
| 属性 | 值 |
|---|---|
| name | Grep |
| inputSchema | pattern: string, path?: string, glob?: string, output_mode?: 'content'|'files_with_matches'|'count', -B/-A/-C?: number, -n/-i?: boolean, type?: string, head_limit?: number, offset?: number, multiline?: boolean |
| concurrency | true |
| readOnly | true |
| maxResultSizeChars | 20,000 |
| strict | true |
call() 实现:
- 基于 ripgrep 的内容搜索
- 自动排除 VCS 目录(.git / .svn / .hg)
- 最大列宽 500(防 minified 文件污染)
head_limit默认 250(防上下文膨胀)offset支持分页- 三种输出模式:
content:匹配行(路径相对化)files_with_matches:按 mtime 排序的文件路径count:匹配计数汇总
- 忽略 deny 规则路径和孤立插件目录
权限:checkReadPermissionForTool
| 属性 | 值 |
|---|---|
| name | ToolSearch |
| inputSchema | query: string, max_results?: number (default 5) |
| concurrency | true |
| readOnly | true |
call() 实现:
select:<tool_name>直接选择特定工具- 关键词搜索(匹配名称 + searchHint + 描述)
- 返回匹配工具的完整描述
- 缓存工具描述(工具集变化时失效)
设计意图:减少初始 prompt 中的工具数量,只在需要时通过搜索加载 shouldDefer=true 的工具。
| 属性 | 值 |
|---|---|
| name | Bash |
| inputSchema | command: string, timeout?: number, description?: string |
| concurrency | false(默认) |
| readOnly | 基于命令语义分析动态判断 |
| shouldDefer | false |
| interruptBehavior | cancel |
call() 实现:
- 使用
exec()执行 shell 命令 - 超时机制:默认/最大超时 ms 可配置
- 沙箱执行:
shouldUseSandbox判断是否在沙箱中运行 - 后台任务:assistant 模式下 15s 自动后台化
- 输出截断:
EndTruncatingAccumulator处理大输出 - 大输出持久化:超限结果存到磁盘(
buildLargeToolResultMessage) - 图片输出检测:自动调整大小
- sed 命令检测:重定向到 FileEditTool
- Git 操作追踪
- 文件历史追踪:sed / tee 等修改文件的命令
- CWD 重置:当前目录不在项目内时重置
isSearchOrReadCommand()分析命令链(grep/find/cat 等)- 支持
renderGroupedToolUse批量渲染
权限:bashToolHasPermission — 基于命令内容匹配 allow/deny/ask 规则,支持通配符模式(如 Bash(git *))
| 属性 | 值 |
|---|---|
| name | WebFetch |
| inputSchema | url: string (url format), prompt: string |
| concurrency | true |
| readOnly | true |
| shouldDefer | true |
| maxResultSizeChars | 100,000 |
call() 实现:
getURLMarkdownContent— 抓取 URL 并转为 markdown- 重定向检测(跨域重定向返回建议)
applyPromptToMarkdown— 使用 Haiku 小模型提取/总结内容- 预批准主机直通(不需要 prompt 处理)
- 二进制内容持久化到磁盘
- 认证 URL 警告
权限:基于域名的 allow/deny/ask 规则,预批准主机列表自动允许
| 属性 | 值 |
|---|---|
| name | WebSearch |
| inputSchema | query: string (min 2), allowed_domains?: string[], blocked_domains?: string[] |
| concurrency | true |
| readOnly | true |
| shouldDefer | true |
call() 实现:
- 使用 Anthropic API 的
web_search_20250305服务器工具 - 最多 8 次搜索
- 使用 Haiku 小模型或主模型
- 实时进度更新(搜索查询、结果计数)
- 仅在 firstParty / Vertex / Foundry 提供者下启用
权限:passthrough — 交给通用权限系统
| 属性 | 值 |
|---|---|
| name | Task |
| aliases | ['Agent'] |
| inputSchema | description: string, prompt: string, subagent_type?: string, model?: 'sonnet'|'opus'|'haiku', run_in_background?: boolean, name?: string, team_name?: string, mode?: PermissionMode, isolation?: 'worktree'|'remote', cwd?: string |
| concurrency | false |
| readOnly | false |
| shouldDefer | false |
| interruptBehavior | cancel |
call() 实现 — 最复杂的工具之一:
- 创建和运行子 Agent(通过
runAgent()) - 支持同步/异步(前台/后台)执行
- Fork 子 Agent 模式(
isForkSubagentEnabled) - Worktree 隔离(
createAgentWorktree) - 远程 Agent(
teleportToRemote) - 多 Agent 团队协调(
spawnTeammate) - Agent 类型选择(
subagent_type→ agent definitions) - 进度追踪和摘要
- Agent 颜色管理
- 自动后台化(120s 超时)
权限:通过 agent deny 规则过滤,检查 MCP 服务器要求
| 属性 | 值 |
|---|---|
| name | TaskOutput |
| inputSchema | task_id: string, block?: boolean (default true), timeout?: number (0-600000, default 30000) |
| concurrency | true |
| readOnly | true |
call() 实现:
- 获取后台任务输出
- 支持阻塞等待(轮询直到完成或超时)
- 处理 shell / agent / remote 三种任务类型
| 属性 | 值 |
|---|---|
| name | TaskStop |
| aliases | ['KillShell'] |
| inputSchema | task_id?: string, shell_id?: string |
| concurrency | true |
| shouldDefer | true |
call() 实现: 停止后台任务(shell 或 agent),通过 stopTask() 统一接口。
| 属性 | 值 |
|---|---|
| name | TodoWrite |
| inputSchema | todos: TodoListSchema[] |
| shouldDefer | true |
| strict | true |
| isEnabled | !isTodoV2Enabled()(与 v2 Task 工具互斥) |
call() 实现:
- 更新会话级待办列表(存储在
AppState.todos) - 所有任务完成时自动清空列表
- 可触发验证提醒(3+ 任务全部完成但无验证步骤时)
特殊:renderToolUseMessage() 返回 null — 不在消息流中显示
| 工具 | name | inputSchema | 说明 |
|---|---|---|---|
| TaskCreateTool | TaskCreate |
subject, description, activeForm?, metadata? |
创建任务,执行 TaskCreated 钩子 |
| TaskUpdateTool | TaskUpdate |
taskId, subject?, description?, status?, addBlocks?, owner?, metadata? |
更新任务,支持删除和完成钩子 |
| TaskListTool | TaskList |
{} |
列出所有非内部任务 |
| TaskGetTool | TaskGet |
taskId |
获取单个任务详情 |
所有 Task v2 工具 shouldDefer: true,isConcurrencySafe: true。
| 属性 | 值 |
|---|---|
| name | Skill |
| inputSchema | skill: string, args?: string |
| concurrency | false |
call() 实现:
- inline 模式:技能提示注入为
newMessages+contextModifier - fork 模式:在独立子 Agent 中运行(
executeForkedSkill) - remote 模式:从远程加载 SKILL.md(实验性)
- 支持模型覆盖、effort 覆盖、工具白名单
- 技能使用追踪(
recordSkillUsage)
权限:基于技能名称的 allow/deny/ask 规则;安全属性的技能自动允许
| 属性 | 值 |
|---|---|
| name | SendMessage |
| inputSchema | to: string, summary?: string, message: string | StructuredMessage |
call() 实现:
- 在多 Agent 团队中发送消息
- 支持文本消息和结构化消息(shutdown_request/response, plan_approval_response)
- 广播(
*)或定向发送 - 通过 UDS 或团队邮箱路由
- 支持关机请求/批准/拒绝流程
| 属性 | 值 |
|---|---|
| name | TeamCreate |
| inputSchema | team_name: string, description?: string, agent_type?: string |
call() 实现: 创建团队文件、注册清理、初始化任务目录。
| 属性 | 值 |
|---|---|
| name | TeamDelete |
| inputSchema | {}(无参数) |
call() 实现: 检查活跃成员、清理目录、清除颜色分配。
| 属性 | 值 |
|---|---|
| name | AskUserQuestion |
| inputSchema | questions: [{question, header, options: [{label, description, preview?}], multiSelect?}] (1-4 个问题) |
| shouldDefer | true |
| requiresUserInteraction | true |
call() 实现:
- 向用户展示多选/单选 UI
- 答案通过权限系统的
updatedInput注入 - 支持预览内容(代码片段、mockup)和多选
权限:ask — 始终需要用户交互(答案 = 权限授予)
| 属性 | 值 |
|---|---|
| name | SendUserMessage |
| aliases | ['Brief'] |
| inputSchema | message: string, attachments?: string[], status: 'normal'|'proactive' |
| shouldDefer | true |
call() 实现: 在 Kairos/assistant 模式下发送消息给用户,支持附件(图片/文件),区分主动消息和回复消息。
| 属性 | 值 |
|---|---|
| name | EnterPlanMode |
| inputSchema | {}(无参数) |
| concurrency | true |
| readOnly | true |
| shouldDefer | true |
call() 实现: 切换到计划模式——将权限模式改为 plan,只允许读取操作。不能在子 Agent 中使用。
| 属性 | 值 |
|---|---|
| name | ExitPlanMode |
| inputSchema | allowedPrompts?: [{tool: 'Bash', prompt: string}] |
| readOnly | false |
| shouldDefer | true |
| requiresUserInteraction | 非团队成员时为 true |
call() 实现: 退出计划模式并恢复原始权限。团队成员发送计划审批请求给团队领导,处理 auto-mode 恢复和危险权限还原。
| 属性 | 值 |
|---|---|
| name | EnterWorktree |
| inputSchema | name?: string |
call() 实现: 创建 git worktree,切换 CWD,清除缓存。
| 属性 | 值 |
|---|---|
| name | ExitWorktree |
| inputSchema | action: 'keep'|'remove', discard_changes?: boolean |
call() 实现: keep 保留 worktree;remove 删除。检查未提交更改。
| 属性 | 值 |
|---|---|
| name | mcp(运行时被覆盖为 mcp__<server>__<tool>) |
| isMcp | true |
| inputSchema | z.object({}).passthrough()(接受任意输入) |
| maxResultSizeChars | 100,000 |
设计:这是一个模板工具。name、description、prompt、call、userFacingName 都在 mcpClient.ts 中被覆盖为具体 MCP 工具实现。
权限:passthrough — 交给 MCP 权限系统
未认证的 MCP 服务器生成此占位工具,触发 OAuth 后由重连接换回真实工具集。
| 属性 | 值 |
|---|---|
| name | ListMcpResourcesTool |
| inputSchema | server?: string |
| concurrency | true |
| readOnly | true |
call() 实现: 列出 MCP 服务器提供的资源(LRU 缓存,启动预取)。
| 属性 | 值 |
|---|---|
| name | ReadMcpResourceTool |
| inputSchema | server: string, uri: string |
| concurrency | true |
| readOnly | true |
call() 实现: 读取具体 MCP 资源,二进制 blob 持久化到磁盘。
| 属性 | 值 |
|---|---|
| name | StructuredOutput |
| concurrency | true |
| readOnly | true |
| isEnabled | 仅非交互会话 |
设计:用于 SDK/CLI 模式返回结构化 JSON 输出。通过 createSyntheticOutputTool(jsonSchema) 动态创建带 Ajv 验证的实例。验证失败抛出 TelemetrySafeError。使用 WeakMap 缓存避免重复编译。
| 工具 | inputSchema | 说明 |
|---|---|---|
| CronCreate | cron: string, prompt: string, recurring?: boolean, durable?: boolean |
创建定时任务(5 字段 cron 表达式) |
| CronDelete | id: string |
删除定时任务 |
| CronList | {} |
列出所有活跃定时任务 |
受 feature flag AGENT_TRIGGERS 控制。
| 属性 | 值 |
|---|---|
| name | RemoteTrigger |
| inputSchema | action: 'list'|'get'|'create'|'update'|'run', trigger_id?: string, body?: Record |
| concurrency | true |
| readOnly | action 为 list/get 时 |
call() 实现: 管理远程调度触发器(CRUD + run),通过 OAuth 认证调用 Anthropic API。
| 属性 | 值 |
|---|---|
| name | LSP |
| isLsp | true |
| inputSchema | operation: enum, filePath: string, line: number, character: number |
| concurrency | true |
| readOnly | true |
| shouldDefer | true |
支持的 LSP 操作:
goToDefinition/goToImplementationfindReferenceshoverdocumentSymbol/workspaceSymbolprepareCallHierarchy/incomingCalls/outgoingCalls
call() 实现: 等待 LSP 初始化 → 打开文件 → 发送请求 → 格式化结果。支持动态服务器配置和上下文聚合。
以下工具受特性开关或环境变量控制:
| 工具 | 说明 | 条件 |
|---|---|---|
| SleepTool | 暂停等待(主动模式) | feature('PROACTIVE') | feature('KAIROS') |
| MonitorTool | 监控功能 | feature('MONITOR_TOOL') |
| WorkflowTool | 工作流脚本 | feature('WORKFLOW_SCRIPTS') |
| PowerShellTool | Windows PowerShell | isPowerShellToolEnabled() |
| REPLTool | 沙箱 REPL | USER_TYPE === 'ant'(内部) |
| SnipTool | 历史裁剪 | feature('HISTORY_SNIP') |
| ListPeersTool | 列出 UDS 对等方 | feature('UDS_INBOX') |
| WebBrowserTool | 浏览器自动化 | feature('WEB_BROWSER_TOOL') |
| CtxInspectTool | 上下文检查 | feature('CONTEXT_COLLAPSE') |
| TerminalCaptureTool | 终端捕获 | feature('TERMINAL_PANEL') |
| ConfigTool | 配置管理 | USER_TYPE === 'ant'(内部) |
| TungstenTool | 内部工具 | USER_TYPE === 'ant'(内部) |
| VerifyPlanExecutionTool | 计划验证 | CLAUDE_CODE_VERIFY_PLAN === 'true' |
| OverflowTestTool | 溢出测试 | feature('OVERFLOW_TEST_TOOL') |
| SendUserFileTool | 发送文件 | feature('KAIROS') |
| PushNotificationTool | 推送通知 | feature('KAIROS') | feature('KAIROS_PUSH_NOTIFICATION') |
| SubscribePRTool | PR 订阅 | feature('KAIROS_GITHUB_WEBHOOKS') |
| TestingPermissionTool | 测试权限 | NODE_ENV === 'test' |
控制工具在不同 Agent 模式下的可用性:
| 常量 | 用途 |
|---|---|
ALL_AGENT_DISALLOWED_TOOLS |
所有子 Agent 禁用的工具(TaskOutput、PlanMode、AskUser 等) |
CUSTOM_AGENT_DISALLOWED_TOOLS |
自定义 Agent 额外禁用 |
ASYNC_AGENT_ALLOWED_TOOLS |
异步 Agent 白名单(文件操作、搜索、Shell 等) |
COORDINATOR_MODE_ALLOWED_TOOLS |
协调器模式仅允许(Agent、TaskStop、SendMessage、StructuredOutput) |
IN_PROCESS_TEAMMATE_ALLOWED_TOOLS |
进程内队友额外允许(Task CRUD、SendMessage、Cron) |
工具调用请求
│
▼
hasPermissionsToUseTool() ← utils/permissions/permissions.ts
│
├─ allow → 直接执行
├─ deny → 拒绝并返回错误
└─ ask → 交互式确认
├─ coordinator handler
├─ interactive handler(终端提示)
└─ swarm worker handler
| 模式 | 说明 |
|---|---|
default |
危险操作需用户确认 |
plan |
只读模式,不执行写操作 |
bypassPermissions |
跳过所有权限检查 |
auto |
自动批准所有操作 |
acceptEdits |
接受编辑操作 |
dontAsk |
不询问,自动拒绝不确定的操作 |
bubble |
向上冒泡给父 Agent |
ToolPermissionContext = { mode: PermissionMode alwaysAllowRules: ToolPermissionRulesBySource // 始终允许的规则 alwaysDenyRules: ToolPermissionRulesBySource // 始终拒绝的规则 alwaysAskRules: ToolPermissionRulesBySource // 始终询问的规则 shouldAvoidPermissionPrompts?: boolean // 后台 Agent 自动拒绝 awaitAutomatedChecksBeforeDialog?: boolean // 协调器等待自动检查 prePlanMode?: PermissionMode // 进入 plan 模式前的模式 }
安全不变式:Hook 的 allow 决策不能绕过 settings.json 的 deny/ask 规则。
| 事件 | 触发时机 |
|---|---|
PreToolUse |
工具执行前 |
PostToolUse |
工具执行后 |
PostToolUseFailure |
工具执行失败后 |
UserPromptSubmit |
用户提交输入时 |
SessionStart |
会话开始 |
SessionEnd |
会话结束 |
SubagentStart |
子 Agent 启动 |
SubagentStop |
子 Agent 停止 |
PreCompact |
压缩前 |
PostCompact |
压缩后 |
Stop |
Agent 停止时 |
TaskCompleted |
任务完成时 |
TeammateIdle |
队友空闲时 |
| 类型 | 说明 |
|---|---|
command |
执行 shell 命令 |
prompt |
发送额外提示给模型 |
http |
发送 HTTP 请求 |
agent |
启动 Agent |
HooksSchema = Partial<Record<HookEvent, HookMatcher[]>> HookMatcher = { if?: string // 条件表达式(如工具名匹配) command?: string // shell 命令 prompt?: string // 提示文本 http?: HttpConfig // HTTP 配置 agent?: AgentConfig // Agent 配置 }
实现核心:utils/hooks.ts(~5000+ 行),包含所有 execute*Hooks 系列函数。
Claude Code 采用多级压缩策略处理长对话:
Level 0: Tool Result Budget(工具结果预算)
│ 超大工具结果落盘,替换为预览摘要
│ 由 maxResultSizeChars 和 PERSISTED_OUTPUT_TAG 控制
▼
Level 1: Microcompact(微压缩)
│ 超时的旧 tool_result 内容清空为 [Old tool result content cleared]
│ 保留最近 N 个,重置 microcompact 状态
│ 支持 Cached Microcompact(登记 cache_edits,不本地改消息)
▼
Level 2: History Snip(历史截断)
│ snipCompactIfNeeded — 截断较旧的历史消息
▼
Level 3: Context Collapse(上下文折叠)
│ 细粒度折叠特定区段
│ 在 autocompact 之前投影/提交 collapse
▼
Level 4: Auto Compact(自动全量压缩)
│ trySessionMemoryCompaction → compactConversation
│ 调模型生成摘要,替换全部历史
有效窗口 = 模型上下文窗口 - min(MAX_OUTPUT_TOKENS, MAX_OUTPUT_TOKENS_FOR_SUMMARY=20000)
可被 CLAUDE_CODE_AUTO_COMPACT_WINDOW 进一步限制
触发阈值 = 有效窗口 - AUTOCOMPACT_BUFFER_TOKENS(13000)
可被 CLAUDE_AUTOCOMPACT_PCT_OVERRIDE 百分比覆盖
当 tokenCountWithEstimation(messages) - snipTokensFreed > 触发阈值
→ 先尝试 trySessionMemoryCompaction
→ 失败再走 compactConversation
→ 连续失败 ≥3 次有 circuit breaker
- 执行 PreCompact hooks,合并自定义说明
streamCompactSummary()— 调模型生成对话摘要- 若摘要以
prompt_too_long开头 →truncateHeadForPTLRetry剥掉最老轮次重试 - 压缩前 strip 图片,避免摘要请求过大
- 构建 post-compact 消息:
boundary → summaryMessages → messagesToKeep → attachments → hookResults
- 执行 PostCompact hooks
readFileState.clear()清除文件读取缓存
tokenCountWithEstimation():
- 从最后一条带
usage的 assistant 消息向前 walk - 计算
getTokenCountFromUsage(usage)+ 新增消息的 rough 估计 - 不含 cache token(
finalContextTokensFromLastResponse用于task_budget扣减)
支持多种执行模式:
| 模式 | 说明 |
|---|---|
| 普通子 Agent | 在当前进程内运行 |
| 后台子 Agent | isAsync 异步执行 |
| Worktree 隔离 | 在独立 git worktree 中运行 |
| 远程 Agent | 通过 teleportToRemote 远程执行 |
| Swarm / 多 Agent | 通过 coordinator 协调 |
| Fork 子 Agent | 带独立消息历史 |
tools/AgentTool/runAgent.ts 中的 runAgent() 是异步生成器:
- 解析 Agent 定义(模型、权限模式、MCP、hooks、skills)
initializeAgentMcpServers()— 合并父级与 Agent 自身的 MCP 工具createSubagentContext()— 构造隔离的ToolUseContext(独立消息、abortController、appState 包装等)- 注册 SubagentStart hooks 和 frontmatter hooks
- 调用
query()进入核心循环 — 子 Agent 与主 Agent 共用同一个 query 管线 - 过滤/记录侧链 transcript(
recordSidechainTranscript) - 过滤子 Agent 不需要对外的
stream_event
Coordinator 模式(coordinator/coordinatorMode.ts):
- 由
feature('COORDINATOR_MODE')+CLAUDE_CODE_COORDINATOR_MODE环境变量控制 - 主会话扮演 orchestrator,用 Agent/SendMessage/TaskStop 驱动 worker
- 注入长系统说明(任务通知 XML 格式、并行策略、worker prompt 指导)
Swarm(utils/swarm/):
- 进程内多 Agent 并行运行
inProcessRunner.ts在循环里多次调用runAgent
Team:
TeamCreateTool/TeamDeleteTool管理团队级并行工作SendMessageTool实现 Agent 间通信
Claude Code 没有直接使用 npm 上的 Ink 包,而是在 src/ink/ 下实现了一套自定义的 Ink 风格 API:
ink/ink.tsx— 核心Ink类(stdin/stdout 管理、帧渲染、FocusManager、patchConsole)ink/root.ts—Root实例(render / unmount / waitUntilExit)ink.ts— 对外createRoot/render入口,包裹ThemeProvider
components/Markdown.tsx— 使用marked.lexer解析(无 markdown 语法时 Fast path 优化)components/StreamingMarkdown— 流式 Markdown 渲染(模型输出时实时渲染)- 代码高亮通过
cliHighlight实现 components/MarkdownTable.tsx— 表格渲染
screens/REPL.tsx— 主交互界面(useInput、consumeEarlyInput、handlePromptSubmit)components/PromptInput/— 输入组件(历史、补全、快捷键、Vim 模式)components/Messages.tsx— 消息列表渲染(流式助手文本使用<StreamingMarkdown>)
Claude Code 使用自定义极简 Store(非 Redux/Zustand),结合 React Context 和 useSyncExternalStore:
// state/store.ts — 极简 store createStore(initialState) → { getState, setState, subscribe } // setState 使用 Object.is 短路 // state/AppState.tsx — Provider AppStateProvider → AppStoreContext → useSyncExternalStore(store.subscribe, selector) // useAppState(selector) 按选择器切片更新 // useSetAppState() 只拿 setState // 禁止嵌套 Provider
state/AppStateStore.ts 定义了庞大的 AppState 类型:
- 设置与配置
- 任务与 MCP/插件状态
- 权限模式与规则
- 推测执行(speculation)状态
- 远程会话/桥接 UI 标志
- 团队/teammate 状态
- 通知队列
- 各种 overlay/UI 状态
state/onChangeAppState.ts 是全局副作用中心,setState 后自动触发:
- 权限模式变化 →
notifySessionMetadataChanged/notifyPermissionModeChanged - 模型变更 → 写入设置
- UI 偏好(expandedView、verbose、tmux)→
saveGlobalConfig - 设置变更 → 清 auth 缓存、
applyConfigEnvironmentVariables
| 服务 | 目录 | 职责 |
|---|---|---|
| API 客户端 | services/api/ |
Anthropic SDK 调用、流式/非流式、重试、多后端支持 |
| MCP | services/mcp/ |
MCP 连接管理、OAuth、配置合并、工具注册、elicitation |
| LSP | services/lsp/ |
语言服务器协议客户端、诊断、多语言支持 |
| OAuth | services/oauth/ |
OAuth 2.0 认证流程 |
| 压缩 | services/compact/ |
自动/手动压缩、微压缩、reactive compact |
| 分析 | services/analytics/ |
GrowthBook 特性开关、Datadog、事件追踪 |
| 工具编排 | services/tools/ |
工具执行调度、流式执行、hook 集成 |
| 记忆提取 | services/extractMemories/ |
自动记忆提取 |
| 团队同步 | services/teamMemorySync/ |
团队记忆同步 |
| 策略限制 | services/policyLimits/ |
组织策略限制 |
| 远程设置 | services/remoteManagedSettings/ |
远程托管设置 |
| 插件 | services/plugins/ |
插件安装与管理 |
| Token 估计 | services/tokenEstimation.ts |
Token 计数估算 |
面向 IDE 扩展(VS Code / JetBrains)与 claude.ai 的双向通信:
| 文件 | 职责 |
|---|---|
bridgeMain.ts |
桥接主循环(轮询/多 session spawn、退避、容量唤醒) |
replBridge.ts |
REPL 会话桥接(v1/v2 transport、HybridTransport) |
remoteBridgeCore.ts |
无 Environments API 的直连路径(CCR v2) |
bridgeMessaging.ts |
消息协议、ingress 消息与权限控制 |
bridgePermissionCallbacks.ts |
权限回调 |
jwtUtils.ts |
JWT 认证 |
sessionRunner.ts |
会话执行管理 |
workSecret.ts |
Work secret 管理 |
面向 Anthropic Sessions API (CCR) 的客户端:
| 文件 | 职责 |
|---|---|
SessionsWebSocket.ts |
WebSocket 连接(wss://.../v1/sessions/ws/{id}/subscribe)、鉴权、重连、ping |
RemoteSessionManager.ts |
HTTP 事件发送 + WS 消息接收、SDKControlPermissionRequest、viewerOnly |
sdkMessageAdapter.ts |
SDKMessage ↔ 内部 Message 转换 |
remotePermissionBridge.ts |
远程工具权限的合成消息构造 |
面向自建 Session 服务的客户端:
| 文件 | 职责 |
|---|---|
types.ts |
ServerConfig、SessionInfo、SessionIndex |
createDirectConnectSession.ts |
POST ${serverUrl}/sessions 创建会话 |
directConnectManager.ts |
WebSocket + NDJSON 协议,转发 SDKMessage 与权限请求 |
三者分工:
- Bridge:本地 Claude Code 进程作为 worker 与 claude.ai 环境对接
- Remote:CLI 作为 CCR session 的客户端(观察/控制另一进程中的 Agent)
- Server:连接私有化部署的 Session 服务
- 配置文件:
~/.mcp.json+managed-mcp.json - 传输协议:stdio / SSE / HTTP / WebSocket
- 插件补充:
getPluginMcpServers从插件目录合并.mcp.json - 运行时:
useManageMCPConnections管理连接/重连,appState.mcp.tools实时更新 - 工具名称:
mcp__<server>__<tool>(buildMcpToolName生成) - 资源:
ListMcpResourcesTool/ReadMcpResourceTool枚举与读取
- 目录结构:
plugin.json+commands/+agents/+hooks/hooks.json+.mcp.json - 加载:
pluginLoader.ts处理目录扫描、manifest 校验、依赖解析 - 贡献点:命令、Agent 定义、Hook、MCP 服务器、Skills
- 来源:CLI
--plugin-dir、市场、内置
skills/目录 +SkillTool工具- 可复用的工作流(SKILL.md 格式)
- 用户可添加自定义技能
- 技能可通过斜杠命令或模型自主调用(通过 SkillTool)
- 支持 inline / fork / remote 三种执行模式
- 内置 ~50 个命令(
/commit、/review、/compact、/mcp等) - 注册:
commands.ts中COMMANDS()内置列表 +loadAllCommands(cwd)合并插件/技能/工作流命令 - 执行:
processSlashCommand.tsx解析和执行,支持context:fork在子 Agent 中运行 - 部分命令(
type === 'prompt')可通过 SkillTool 让模型自主调用
// main.tsx — 在其他 import 之前作为副作用并行启动 startMdmRawRead() // MDM 设置预读 startKeychainPrefetch() // Keychain 预取 // API preconnect、GrowthBook 初始化同样并行
- OpenTelemetry (~400KB)、gRPC (~700KB) 等重模块通过
import()按需加载 - 工具通过
shouldDefer/alwaysLoad标志控制延迟加载 - Zod schema 通过
lazySchema()延迟初始化,避免循环依赖
import { feature } from 'bun:bundle' const voiceCommand = feature('VOICE_MODE') ? require('./commands/voice/index.js').default : null // 未启用的代码在构建时完全剥离(dead code elimination)
Notable flags: PROACTIVE, KAIROS, BRIDGE_MODE, DAEMON, VOICE_MODE, AGENT_TRIGGERS, MONITOR_TOOL
StreamingToolExecutor 在模型流式输出过程中就开始执行已完成的工具调用,无需等整条消息接收完毕。
assembleToolPool() 中内置工具和 MCP 工具分别按名排序,保持内置工具为连续前缀。工具集变化时,已缓存的工具描述需失效重建。
所有工具通过 buildTool() 创建,填充 fail-closed 默认值(假设不并发、不只读),确保新工具默认安全。
FileEditTool / FileWriteTool / NotebookEditTool 都要求先 Read 再 Edit/Write,通过 readFileState 的 mtime 比较防止数据丢失和竞争条件。
非核心工具标记为 shouldDefer: true,初始 prompt 中以 defer_loading 方式发送(不含完整 schema),需通过 ToolSearchTool 按 searchHint 发现后才能使用,减少 prompt 开销。
validateInput(输入验证)→ checkPermissions(工具级权限)→ 通用权限系统(规则匹配 + hooks + 分类器)。Hook 的 allow 不能绕过 deny/ask 规则——安全不变式。
每个工具通过 isConcurrencySafe(input) 方法基于具体输入动态判断,而非静态标记。连续并发安全工具自动合并批次并行执行。
超过 maxResultSizeChars 的结果存储到磁盘,仅返回预览摘要。FileReadTool 设 Infinity 永不持久化(避免循环读取自身输出)。
长时间运行的工具通过 onProgress 回调报告中间状态(BashProgress、AgentToolProgress、WebSearchProgress 等),前端实时展示。
StreamingToolExecutor 实现"边收流边执行",只有 Bash 错误级联取消兄弟任务(Shell 命令常有隐含依赖链),其他工具失败不影响并行伙伴。
从 Tool Result Budget → Microcompact → History Snip → Context Collapse → Auto Compact,五级压缩策略确保长对话不超出上下文窗口,同时尽可能保留 prompt cache。
子 Agent 与主 Agent 共用同一个 query() 管线,通过 ToolUseContext 隔离实现复用。从简单的 fork 到复杂的多 Agent swarm,都基于同一核心循环。
用户输入
│
▼
REPL.onSubmit() → handlePromptSubmit() → processUserInput()
│ 解析斜杠命令 / 文本提示 / UserPromptSubmit hooks
▼
QueryEngine.submitMessage()
│ 拼装 systemPrompt、userContext、systemContext
▼
query() → queryLoop() [while(true)]
│
├─ 上下文裁剪(5 级压缩)
├─ appendSystemContext()
│
├─ queryModelWithStreaming()
│ └─ anthropic.beta.messages.create({stream: true})
│
├─ 流式处理 + StreamingToolExecutor
│
├─ 无 tool_use → Stop hooks → return
│
└─ 有 tool_use
│
├─ partitionToolCalls()(并发 / 串行分区)
│
└─ runToolUse() ×ばつ N
├─ validateInput(Zod + 自定义)
├─ PreToolUse hooks
├─ resolveHookPermissionDecision
│ └─ hook allow 不能绕过 deny/ask 规则
├─ tool.call()
├─ PostToolUse hooks(MCP 可修改输出)
└─ createUserMessage(tool_result)
│
└─ 合并到 messages → 继续 while(true) 下一轮
本文档基于 2026年03月31日 泄露的 Claude Code CLI 源代码分析生成。所有原始源代码为 Anthropic 所有。