Claude Code 源码分析 - 项目总览
项目概述
Claude Code 是 Anthropic 官方推出的 CLI 工具,允许用户通过终端与 Claude AI 进行交互式对话,执行软件工程任务。项目使用 TypeScript 编写,基于 React Ink 构建终端 UI,采用 Bun 作为运行时和打包工具。
技术栈
| 技术 | 用途 |
|---|---|
| TypeScript | 主要开发语言 |
| React + Ink | 终端 UI 框架(深度定制 Fork) |
| Bun | 运行时 & 打包工具 |
| Zod | 运行时类型校验 |
| Yoga Layout | Flexbox 布局引擎(纯 TS 简化移植) |
| OpenTelemetry | 可观测性/遥测 |
| OAuth 2.0 | 认证体系 |
| WebSocket / SSE | 实时通信 |
| MCP (Model Context Protocol) | 工具扩展协议 |
源码统计
- 总文件数: 1884 个 TypeScript/TSX 文件
- 模块目录数: 35 个顶层模块
- 根级文件数: 18 个核心入口文件
整体架构拓扑
以下所有连线均基于源码 import 语句验证。实线 = 直接 import,虚线 = 间接依赖(通过 hooks 或 type-only import)。
graph TB
subgraph Entry["🚀 入口层"]
CLI["CLI 入口<br/><small>entrypoints/cli</small>"]
SDK["SDK 入口<br/><small>entrypoints/sdk</small>"]
MCP_E["MCP Server<br/><small>entrypoints/mcp</small>"]
end
subgraph Orchestrator["🎯 编排层"]
Main["main.tsx<br/><small>4683 行 · 应用主入口<br/>初始化 · 工具注册 · 路由</small>"]
end
subgraph Bootstrap["⚡ 启动层"]
BS["bootstrap/state<br/><small>全局状态 · 配置加载 · 认证</small>"]
end
subgraph UI["🖥️ 终端 UI 层"]
REPL["REPL.tsx<br/><small>5005 行 · 主交互屏幕</small>"]
Resume["ResumeConversation<br/><small>会话恢复</small>"]
Doctor["Doctor<br/><small>系统诊断</small>"]
Components["components/<br/><small>389 React 组件文件</small>"]
INK["ink/<br/><small>定制 Ink 引擎<br/>Yoga 布局 · 事件系统<br/>终端协议栈</small>"]
end
subgraph Core["🧠 AI 交互核心"]
QueryTS["query.ts<br/><small>1729 行 · 查询主循环</small>"]
QueryDir["query/<br/><small>config · deps · tokenBudget<br/>stopHooks · transitions</small>"]
Services["services/<br/><small>API 调用 · 流式处理<br/>消息压缩 · 分析</small>"]
end
subgraph ToolChain["🔧 工具链"]
Tools["tools/<br/><small>40 个 AI 工具<br/>buildTool 工厂</small>"]
Skills["skills/<br/><small>技能系统</small>"]
Plugins["plugins/<br/><small>插件系统</small>"]
end
subgraph HookSys["🪝 钩子层"]
ReactHooks["hooks/<br/><small>104 React Hooks</small>"]
ExecHooks["utils/hooks/<br/><small>钩子执行引擎<br/>28 种生命周期事件</small>"]
end
subgraph Infra["🏗️ 基础设施"]
State["state/<br/><small>AppState 状态管理</small>"]
Context["context/<br/><small>上下文构建</small>"]
Schemas["schemas/<br/><small>Zod 验证</small>"]
Utils["utils/<br/><small>564 工具文件<br/>31 子目录</small>"]
NativeTS["native-ts/<br/><small>yoga-layout<br/>file-index · 色差</small>"]
end
subgraph Connect["🌐 连接层"]
Bridge["bridge/<br/><small>IDE 桥接</small>"]
Remote["remote/<br/><small>远程会话</small>"]
Server["server/<br/><small>HTTP/WS</small>"]
Coord["coordinator/<br/><small>多实例协调</small>"]
end
subgraph Extra["✨ 增强功能"]
KB["keybindings/<br/><small>17 上下文</small>"]
Vim["vim/<br/><small>Vim 模式</small>"]
Voice["voice/<br/><small>语音交互</small>"]
Memdir["memdir/<br/><small>自动记忆</small>"]
Tasks["tasks/<br/><small>后台任务</small>"]
end
%% 入口 → 编排
CLI --> Main
SDK --> Main
MCP_E --> Main
%% 编排层依赖(main.tsx 直接 import)
Main --> BS
Main --> Services
Main --> Tools
Main --> Skills
Main --> Plugins
Main --> Bridge
Main --> Server
Main --> Coord
Main --> Remote
%% 启动层 → 屏幕(screens 均 import bootstrap/state)
BS --> REPL
BS --> Resume
BS --> Doctor
%% REPL 直接 import(源码验证)
REPL --> QueryTS
REPL --> Components
REPL --> ReactHooks
REPL --> State
REPL --> KB
REPL --> Tasks
REPL -.->|type only| Remote
REPL -.->|type only| Server
%% 组件 → 渲染引擎
Components --> INK
%% 查询核心(query.ts 直接 import)
QueryTS --> QueryDir
QueryTS --> Services
QueryTS --> Tools
QueryTS --> ExecHooks
%% 查询子模块(query/stopHooks.ts 直接 import)
QueryDir --> Services
QueryDir --> Memdir
QueryDir --> KB
%% 钩子层
ReactHooks --> ExecHooks
ReactHooks -.->|间接访问| Bridge
ReactHooks -.->|间接访问| Vim
ReactHooks -.->|间接访问| Voice
%% 基础设施
INK --> NativeTS
Services --> Utils
Tools --> Utils
ExecHooks --> Utils
style Entry fill:#4a9eff,stroke:#2d7cd6,color:#fff
style Orchestrator fill:#e056fd,stroke:#be2edd,color:#fff
style Bootstrap fill:#ff9f43,stroke:#d68536,color:#fff
style UI fill:#a55eea,stroke:#8344c4,color:#fff
style Core fill:#ee5a24,stroke:#c44a1e,color:#fff
style ToolChain fill:#6ab04c,stroke:#58964a,color:#fff
style HookSys fill:#22a6b3,stroke:#1b8a94,color:#fff
style Infra fill:#778ca3,stroke:#5f7186,color:#fff
style Connect fill:#0fb9b1,stroke:#0c9690,color:#fff
style Extra fill:#f7b731,stroke:#c99528,color:#fff
架构图连线依据
| 连线 | 源码依据 |
|---|---|
| CLI/SDK/MCP → main.tsx | 三个入口点均通过 main.tsx 启动应用 |
| main.tsx → bootstrap/ | main.tsx:87 — from './bootstrap/state.js' |
| main.tsx → services/ | main.tsx — 多处 import analytics, api, mcp, policyLimits |
| main.tsx → tools/ | main.tsx:45-46 — SyntheticOutputTool, AgentTool |
| main.tsx → skills/ | main.tsx — 直接 import skills/ |
| main.tsx → plugins/ | main.tsx — 直接 import plugins/ |
| main.tsx → bridge/ | main.tsx — 直接 import bridge/ |
| main.tsx → server/ | main.tsx — 直接 import server/ |
| main.tsx → coordinator/ | main.tsx — 直接 import coordinator/ |
| matsx → remote/ | main.tsx — 直接 import remote/ |
| bootstrap → screens | REPL.tsx:32, Resume.tsx:6, Doctor.tsx:10 — 均 import bootstrap/state |
| REPL → query.ts | screens/REPL.tsx:146 — import { query } from '../query.js' |
| REPL → components/ | screens/REPL.tsx — 14 处 import(VirtualMessageList, PromptInput 等) |
| REPL → hooks/ | screens/REPL.tsx — 21 处 import(useSearchInput, useTerminalSize 等) |
| REPL → state/ | screens/REPL.tsx:170 — import { useAppState } from '../state/AppState.js' |
| REPL → keybindings/ | screens/REPL.tsx — KeybindingProviderSetup, useShortcutDisplay |
| REPL → tasks/ | screens/REPL.tsx:44-45 — InProcessTeammateTask, LocalAgentTask |
| REPL -.- remote/ | screens/REPL.tsx:279 — import type { RemoteSessionConfig } (type-only) |
| REPL -.- server/ | screens/REPL.tsx:62 — import type { DirectConnectConfig } (type-only) |
| components → ink/ | 组件使用 ink/ 提供的 Box, Text 等基础组件渲染 |
| query.ts → query/ | query.ts — import stopHooks, config, deps, transitions, tokenBudget |
| query.ts → services/ | query.ts:7-95 — api/withRetry, compact, toolUseSummary, analytics, tools |
| query.ts → tools/ | query.ts:91 — import { SLEEP_TOOL_NAME } from './tools/SleepTool/prompt.js' |
| query.ts → utils/hooks/ | query.ts:92-93 — postSamplingHooks, executeStopFailureHooks |
| query/ → services/ | query/deps.ts — api/claude, compact/autoCompact, compact/microCompact |
| query/ → memdir/ | query/stopHooks.ts — import { isExtractModeActive } from '../memdir/paths.js' |
| query/ → keybindings/ | query/stopHooks.ts — import { getShortcutDisplay } |
| hooks/ → utils/hooks/ | hooks/useSkillImprovementSurvey.ts, hooks/toolPermission/PermissionContext.ts |
| hooks/ -.- bridge/ | hooks/useReplBridge.tsx import bridge/ |
| hooks/ -.- vim/ | hooks/useVimInput.ts import vim/ |
| hooks/ -.- voice/ | hooks/useVoiceIntegration.tsx import voice/ |
| ink/ → native-ts/ | ink/reconciler.ts, ink/ink.tsx — import yoga-layout |
| services/tools/utils → utils/ | 多处 import utils/ 下的工具函数 |
REPL 不直接 import 的模块:bridge/、vim/、voice/、memdir/、skills/、coordinator/。这些模块通过 hooks/ 间接访问,或由 main.tsx 在启动时编排。
核心数据流
sequenceDiagram
participant U as 用户终端
participant R as REPL.tsx
participant Q as query.ts
participant S as services/api
participant A as Claude API
participant T as tools/
participant H as utils/hooks/
U->>R: 输入文本/命令
R->>R: 解析命令 (/ 开头?)
R->>Q: import { query } 直接调用
loop 查询主循环
Q->>Q: microcompact 消息压缩
Q->>Q: autocompact 检查
Q->>S: callModel() 流式请求
S->>A: HTTP Stream
A-->>S: 流式响应 (文本/工具调用)
S-->>Q: yield 响应块
alt 文本响应
Q-->>R: yield 文本块
R-->>U: 渲染到终端 (ink/)
else 工具调用
Q->>H: executePostSamplingHooks()
Q->>T: runTools() 执行工具
T-->>Q: 工具结果
Q->>Q: 追加结果到消息
end
Q->>Q: checkTokenBudget()
Note over Q: 连续2次 delta < 500 且续传≥3 → 停止
end
Q->>H: 执行停止钩子 (stopHooks.ts)
Note over H: 记忆提取 · 自动推理 · 提示建议
Q-->>R: 查询完成
R->>R: 会话持久化 (utils/sessionStorage)
工具执行流程
flowchart LR
A["AI 请求<br/>工具调用"] --> B{"权限检查<br/><small>hooks/useCanUseTool</small>"}
B -->|自动允许| D["执行工具<br/><small>services/tools/<br/>toolOrchestration</small>"]
B -->|需确认| C["显示权限对话框<br/><small>components/permissions/</small>"]
C -->|允许| D
C -->|拒绝| E["返回拒绝结果"]
D --> F["收集结果"]
F --> G["更新文件状态缓存<br/><small>utils/fileStateCache</small>"]
G --> H["追加到消息"]
H --> I["继续查询循环"]
style A fill:#4a9eff,color:#fff
style B fill:#f7b731,color:#fff
style D fill:#20bf6b,color:#fff
style E fill:#ee5a24,color:#fff
模块依赖关系(基于 import 验证)
graph LR
subgraph 编排
M[main.tsx]
end
subgraph 核心
B[bootstrap]
SC[screens/REPL]
Q[query.ts]
SV[services]
end
subgraph 工具链
TL[tools]
SK[skills]
PL[plugins]
end
subgraph 钩子
RH[hooks]
EH[utils/hooks]
end
subgraph 渲染
CP[components]
IK[ink]
NT[native-ts]
end
subgraph 基础
ST[state]
UT[utils]
end
subgraph 连接
BR[bridge]
RM[remote]
SRV[server]
CO[coordinator]
end
M --> B
M --> SV
M --> TL
M --> SK
M --> PL
M --> BR
M --> SRV
M --> CO
M --> RM
B --> SC
SC --> Q
SC --> CP
SC --> RH
SC --> ST
Q --> SV
Q --> TL
Q --> EH
CP --> IK
IK --> NT
RH --> EH
RH -.-> BR
RH -.-> RM
SV --> UT
TL --> UT
EH --> UT
style M fill:#e056fd,color:#fff
style Q fill:#ee5a24,color:#fff
style SC fill:#a55eea,color:#fff
style UT fill:#778ca3,color:#fff
启动流程
flowchart TB
A["bun run cli.tsx"] --> B["解析 CLI 参数"]
B --> C["main.tsx 初始化"]
C --> D["bootstrap/state<br/><small>加载 settings.json · CLAUDE.md</small>"]
D --> E["认证检查<br/><small>OAuth / API Key</small>"]
E --> F["注册工具 & 加载插件<br/><small>tools/ · skills/ · plugins/</small>"]
F --> G["初始化连接层<br/><small>bridge/ · server/ · coordinator/</small>"]
G --> H{"入口模式?"}
H -->|交互式| I["启动 REPL"]
H -->|--print / -p| J["单次查询"]
H -->|SDK| K["返回 Agent 实例"]
H -->|MCP| L["启动 MCP Server"]
I --> M["渲染终端 UI<br/><small>components/ → ink/ 引擎</small>"]
M --> N["等待用户输入"]
style A fill:#4a9eff,color:#fff
style C fill:#e056fd,color:#fff
style H fill:#f7b731,color:#fff
style I fill:#a55eea,color:#fff
style M fill:#20bf6b,color:#fff
模块目录树
src/
├── main.tsx # 应用主入口 · 编排器 (4683 行)
├── Tool.ts # 工具工厂 buildTool() (792 行)
├── Task.ts # 任务类型定义 (125 行)
├── query.ts # 查询主循环 (1729 行)
├── QueryEngine.ts # 查询引擎封装 (1295 行)
│
├── entrypoints/ # 入口点(CLI/SDK/MCP)
├── bootstrap/ # 应用启动 & 全局状态
├── cli/ # CLI 传输层 & 处理器
├── commands/ # 86 个斜杠命令子目录 + 15 个根级命令文件
├── screens/ # 主要 UI 屏幕(REPL/Doctor/Resume)
├── components/ # 389 个 React UI 组件文件(31 子目录)
├── ink/ # Ink 终端渲染引擎(深度定制 Fork)
│
├── query/ # 查询配置/依赖注入/Token预算/停止钩子
├── services/ # 服务层(20 子目录 + 16 根级文件 · API/分析/压缩)
├── tools/ # 40 个 AI 工具实现
├── skills/ # 技能系统(bundled + custom)
├── plugins/ # 插件系统
├── hooks/ # 104 React UI Hooks
│
├── state/ # 应用状态管理
├── context/ # 上下文收集(git/系统/用户)
├── constants/ # 常量定义
├── types/ # 全局类型定义
├── schemas/ # Zod Schema 定义
│
├── bridge/ # Web/IDE 桥接通信
├── coordinator/ # 多实例协调器
├── remote/ # 远程会话管理
├── server/ # HTTP/WebSocket 服务器
│
├── keybindings/ # 快捷键系统(17 上下文)
├── vim/ # Vim 模式支持
├── voice/ # 语音uddy/ # Buddy 彩蛋(6 文件)
│
├── utils/ # 工具函数库(564 文件 · 31 子目录)
├── native-ts/ # 纯 TS 原生实现(yoga/file-index/色差)
├── memdir/ # 自动记忆系统(8 文件)
├── migrations/ # 配置迁移(11 迁移文件)
├── tasks/ # 后台任务管理(5 种任务类型 + 根级辅助文件)
├── outputStyles/ # 输出样式加载
├── upstreamproxy/ # 上游代理
└── assistant/ # 会话历史管理
01 - 根级文件源码分析
路径:
src/*.ts/src/*.tsx文件数: 18 个
这些文件是整个 Claude Code 应用的核心入口和基础抽象层,定义了应用的启动流程、核心类型和顶层模块导出。
1. main.tsx — 应用主入口
行数: 4683 行
功能概述
应用的最顶层入口文件,负责解析 CLI 参数、初始化环境、选择运行模式并启动对应的屏幕。
核心逻辑
CLI 参数解析 → 环境初始化 → 模式选择 → 渲染对应屏幕
- 解析命令行参数(
--resume,--continue,--print等) - 调用
setup.ts进行环境初始化 - 根据参数选择运行模式:
- 交互式 REPL 模式 → 渲染
REPL屏幕 - 恢复会话模式 → 渲染
ResumeConversation屏幕 - 诊断模式 → 渲染
Doctor屏幕 - 非交互式打印模式 → 直接输出
- 交互式 REPL 模式 → 渲染
- 使用 Ink 渲染 React 组件到终端
关键依赖
screens/REPL.tsx— 主交互屏幕screens/ResumeConversation.tsx— 会话恢复屏幕screens/Doctor.tsx— 诊断屏幕setup.ts— 环境初始化ink/ink.tsx— Ink 渲染器
2. Tool.ts — 工具抽象基类
行数: 792 行
功能概述
定义了 AI 工具的核心抽象。所有工具通过 buildTool(def) 工厂函数构建(不是链式 Builder),接收 ToolDef 对象,返回展开后的 BuiltTool。
导出
buildTool(def)— 工厂函数,将ToolDef转为BuiltToolToolDef类型 — 工具定义接口BuiltTool类型 — 构建后的工具对象TOOL_DEFAULTS— 安全默认值
工厂模式
// 源码 src/Tool.ts:783-792
export function buildTool<D extends AnyToolDef>(def: D): BuiltTool<D> {
return {
...TOOL_DEFAULTS,
userFacingName: () => def.name,
...def,
} as BuiltTool<D>
}
设计亮点
- 工厂函数 + 对象展开: 不是类继承,而是
TOOL_DEFAULTS与def展开合并 - 安全默认值:
TOOL_DEFAULTS提供默认权限检查、默认非并发安全等 - MCP 集成: 支持 Model Context Protocol 工具协议
- 60+ 工具: 类型系统通过 0-error typecheck 验证所有工具定义
3. Task.ts — 任务类型定义
行数: 125 行
功能概述
定义后台任务的类型系统,支持 7 种任务类型和 5 种状态。任务 ID 使用 randomBytes(8) 生成,带单字符类型前缀。
导出
TaskType— 任务类型联合类型TaskStatus— 任务状态联合类型Task— 任务接口generateTaskId()— 任务 ID 生成函数
任务类型
| 类型 | 说明 |
|---|---|
local_bash | 本地 Shell 命令 |
local_agent | 本地子 Agent |
remote_agent | 远程 Agent |
in_process_teammate | 进程内队友 |
local_workflow | 本地工作流 |
monitor_mcp | MCP 监控 |
dream | 后台推理任务 |
任务状态
pending → running → completed
→ failed
→ killed
ID 生成
- 使用
randomBytes(8)生成(不是crypto.randomUUID()) - 36 字符字母表(a-z + 0-9)
- 单字符类型前缀:
b=local_bash,a=local_agent,r=remote_agent,t=in_process_teammate,w=local_workflow,m=monitor_mcp,d=dream - 36^8 ≈ 2.8 万亿种组合,足以抵抗暴力符号链接攻击
4. QueryEngine.ts — 查询引擎
行数: 1295 行
功能概述
查询引擎的顶层抽象,封装了与 Claude API 的交互逻辑。
核心职责
- 管理查询生命周期
- 协调模型调用和工具执行
- 处理流式响应
- 管理 token 预算
5. commands.ts — 命令注册中心
行数: 754 行
功能概述
中央命令注册表,聚合来自多个来源的斜杠命令(/help, /commit, /review 等)。
导出
getCommands()— 获取所有可用命令(带缓存)REMOTE_SAFE_COMMANDS— 远程安全命令集合BRIDGE_SAFE_COMMANDS— 桥接安全命令集合INTERNAL_ONLY_COMMANDS— 仅内部使用的命令
命令来源
bundled skills (内置技能)
+ plugin skills (插件技能)
+ skill directories (.skills/ 目录)
+ workflows (工作流)
+ built-in commands (内置命令)
= 完整命令列表
安全过滤
REMOTE_SAFE: 远程会话中允许执行的命令白名单BRIDGE_SAFE_COMMANDS: 桥接模式中允许的命令白名单INTERNAL_ONLY_COMMANDS: 对 AI 隐藏的内部命令
缓存机制
使用 memoization 确保命令只发现一次,后续调用直接返回缓存结果。
6. context.ts — 上下文收集
行数: 189 行
功能概述
收集对话所需的上下文信息,包括 git 仓库状态和系统/用户上下文。
导出
getGitStatus()— 收集 git 状态(memoized)getSystemContext()— 收集系统上下文(memoized)getUserContext()— 收集用户上下文(memoized)setSystemPromptInjection()— 设置缓存破坏注入(调试用)
收集内容
- Git 状态: 分支名、工作区状态(截断到 2000 字符)、最近提交、用户信息
- CLAUDE.md 文件: 从项目目录树中发现并加载所有 CLAUDE.md 文件
- 缓存破坏注入: 用于调试的缓存破坏机制
特性
- Memoized 缓存,避免重复收集
- 支持 bare mode(最小上下文)
- 支持显式添加额外目录
- 诊断日志带 PII 过滤
7. cost-tracker.ts — 费用追踪器
行数: 323 行
功能概述
全面的 API 使用费用监控系统,支持按模型粒度追踪。
追踪指标
| 指标 | 说明 |
|---|---|
| 输入 tokens | 发送给模型的 token 数 |
| 输出 tokens | 模型生成的 token 数 |
| 缓存读取 tokens | 从缓存读取的 token 数 |
| 缓存创建 tokens | 写入缓存的 token 数 |
| Web 搜索请求 | 网页搜索调用次数 |
| USD 费用 | 计算的美元费用 |
持久化
- 会话数据持久化到项目配置
- 支持通过 session ID 跨会话恢复
- 进程退出时自动保存
8. costHook.ts — 费用摘要 Hook
行数: 22 行
功能概述
React Hook,在进程退出时显示格式化的费用摘要。
导出
useCostSummary()— React Hook
逻辑
- 使用
useEffect监听进程退出事件 - 格式化显示总费用、token 使用量
- 与计费访问控制系统集成
9. dialogLaunchers.tsx — 对话框启动器
行数: 132 行
功能概述
提供各种对话框的启动函数,用于在 REPL 中弹出模态对话框。
典型对话框
- 权限确认对话框
- 设置对话框
- 模型选择对话框
- 帮助对话框
10. history.ts — 历史记录管理
行数: ~150 行
功能概述
管理对话历史记录的加载、保存和查询。
核心功能
- 加载历史会话列表
- 按项目/仓库过滤会话
- 渐进式加载(分页)
- 会话元数据管理(标题、时间戳、消息数)
11. ink.ts — Ink 模块导出
行数: ~30 行
功能概述
Ink 终端 UI 框架的顶层导出文件,重新导出 ink/ 目录中的核心组件和 hooks。
导出内容
- React 组件:
Box,Text,Spacer等 - Hooks:
useInput,useApp,useStdin等 - 渲染函数:
render
12. interactiveHelpers.tsx 行数**: ~80 行
功能概述
提供交互式 UI 的辅助组件和函数。
典型功能
- 确认提示
- 选择列表
- 进度指示器
- 错误显示
13. projectOnboardingState.ts — 项目引导状态
行数: ~50 行
功能概述
管理项目首次使用时的引导流程状态。
功能
- 检测是否为新项目
- 追踪引导步骤完成状态
- 持久化引导进度
14. query.ts — 查询入口
行数: 1729 行
功能概述
查询主循环的完整实现(不是简单导出),包含与 Claude API 交互、工具调用处理、流式响应、token 预算管理等核心逻辑。
核心流程
query(messages, tools, config)
→ 构建请求
→ 调用模型(流式)
→ 处理工具调用
→ 返回响应
15. replLauncher.tsx — REPL 启动器
行数: 22 行
16. setup.ts — 环境初始化
行数: ~200 行
功能概述
应用启动时的环境初始化,在 main.tsx 中最先调用。
初始化步骤
- 设置进程信号处理
- 初始化日志系统
- 加载用户配置
- 初始化 OpenTelemetry
- 设置错误处理
- 检查更新
- 运行配置迁移
17. tasks.ts — 任务模块导出
行数: ~30 行
功能概述
tasks/ 目录的顶层导出文件。
18. tools.ts — 工具模块导出
行数: ~100 行
功能概述
tools/ 目录的顶层导出,注册并导出所有可用的 AI 工具。
注册的工具
Bash— 执行 Shell 命令Read— 读取文件Write— 写入文件Edit— 编辑文件Glob— 文件模式匹配Grep— 内容搜索Agent— 子 Agent 启动WebFetch— 网页获取WebSearch— 网页搜索Notebook— Jupyter Notebook 编辑TodoWrite— 任务列表管理- 更多 MCP 工具…
文件间依赖关系
main.tsx
├── setup.ts (初始化)
├── context.ts (上下文)
├── commands.ts (命令)
├── tools.ts (工具)
│ └── Tool.ts (基类)
├── tasks.ts (任务)
│ └── Task.ts (类型)
├── query.ts (查询)
│ └── QueryEngine.ts (引擎)
├── cost-tracker.ts (费用)
│ └── costHook.ts (Hook)
└── replLauncher.tsx (启动器)
└── screens/REPL.tsx (主屏幕)
02 - entrypoints 模块源码分析
路径:
src/entrypoints/功能: 多入口点系统,支持 CLI、SDK、MCP 三种运行模式
模块概述
entrypoints/ 定义了 Claude Code 的多种启动方式。不同的入口点决定了应用以何种模式运行——交互式 CLI、程序化 SDK、还是 MCP 服务器。
文件清单
| 文件 | 行数 | 说明 |
|---|---|---|
cli.tsx | 302 | CLI 主入口 |
init.ts | 340 | 初始化入口(文档之前遗漏) |
mcp.ts | 196 | MCP 服务器入口 |
sandboxTypes.ts | 156 | 沙箱类型定义 |
agentSdkTypes.ts | 443 | Agent SDK 类型定义(re-export hub + stub 函数) |
sdk/coreTypes.ts | 62 | SDK 核心类型(HOOK_EVENTS, EXIT_REASONS 常量) |
sdk/coreSchemas.ts | 1889 | SDK 核心 Schema(文档之前遗漏,最大文件) |
sdk/controlSchemas.ts | 663 | SDK 控制协议 Schema |
1. cli.tsx — CLI 主入口
行数: 302 行(比预期小得多,大量逻辑已拆分到其他模块)
功能概述
这是用户在终端执行 claude 命令时的入口点。负责完整的 CLI 生命周期管理。
核心流程
命令行解析 → 认证检查 → 模式路由 → 屏幕渲染 → 退出处理
详细步骤
-
命令行参数解析
- 使用自定义解析器处理参数
- 支持子命令:
auth,config,doctor,mcp,plugin等 - 支持标志:
--print,--resume,--continue,--model等
-
认证流程
- 检查 OAuth token 有效性
- 支持 API Key 和 OAuth 两种认证方式
- 处理 token 刷新
-
模式路由
claude → 交互式 REPL claude -p "prompt" → 非交互式打印模式 claude --resume → 恢复会话 claude doctor → 诊断模式 claude auth login → 认证登录 claude config → 配置管理 claude mcp → MCP 服务器管理 -
屏幕渲染
- 使用 Ink 渲染 React 组件到终端
- 管理终端原始模式
- 处理窗口大小变化
-
退出处理
- 保存会话状态
- 清理临时资源
- 发送遥测数据
2. mcp.ts — MCP 服务器入口
行数: 197 行
功能概述
将 Claude Code 作为 MCP (Model Context Protocol) 服务器运行,允许其他 AI 应用通过标准协议调用 Claude Code 的工具。
导出
- MCP 服务器启动函数
核心逻辑
// 伪代码
async function startMCPServer() {
// 1. 初始化 MCP 传输层(stdio)
const transport = new StdioTransport()
// 2. 注册可用工具
const tools = loadTools()
// 3. 处理 MCP 请求
transport.onRequest(async (request) => {
switch (request.method) {
case 'tools/list':
return { tools: tools.map(t => t.toMCPSchema()) }
case 'tools/call':
return await executeTool(request.params)
}
})
// 4. 启动服务器
await transport.start()
}
MCP 协议支持
ListToolsRequest— 列出可用工具(含 Zod→JSON Schema 转换)CallToolRequest— 调用工具(含输入验证和权限检查)- 注意:当前不支持 resources 相关处理(无
resources/list或resources/read)
3. sandboxTypes.ts — 沙箱类型定义
行数: 156 行
功能概述
使用 Zod Schema 定义沙箱环境的配置和权限,不是简单的 interface。
核心 Schema
// 实际是 Zod schema,包含细粒度配置
const SandboxConfigSchema = z.object({
network: z.object({ ... }), // 网络访问控制
filesystem: z.object({
allowRead: z.array(z.string()), // 允许读取的路径
denyRead: z.array(z.string()), // 禁止读取的路径
allowManagedDomainsOnly: z.boolean(), // 仅允许托管域名
}),
// ... 更多细粒度配置
})
4. agentSdkTypes.ts — Agent SDK 类型定义
行数: ~500+ 行
功能概述
定义 Agent SDK 的完整类型系统,包括消息格式、事件类型和钩子事件。
核心类型
// SDK 消息类型
type SDKMessage = {
type: 'usesistant' | 'system' | 'tool_use' | 'tool_result'
content: ContentBlock[]
// ...
}
// 钩子事件类型
type HookEvent =
| 'PreToolUse' // 工具执行前
| 'PostToolUse' // 工具执行后
| 'Stop' // 回合结束
| 'TeammateIdle' // 队友空闲
| 'TaskCompleted' // 任务完成
| 'Notification' // 通知
| 'SubagentStop' // 子Agent停止
// 导出的常量
const HOOK_EVENTS: HookEvent[] = [...]
设计特点
- 使用 discriminated union 实现类型安全的消息路由
- 钩子事件覆盖完整的工具生命周期
- 支持子 Agent 和队友模式的事件
5. sdk/coreTypes.ts — SDK 核心类型
行数: 63 行
功能概述
SDK 的最基础类型定义,被其他 SDK 文件广泛引用。
导出
// 内容块类型
type ContentBlockParam =
| TextBlock
| ImageBlock
| ToolUseBlock
| ToolResultBlock
// 消息角色
type Role = 'user' | 'assistant'
// 停止原因
type StopReason =
| 'end_turn' // 正常结束
| 'max_tokens' // 达到 token 上限
| 'stop_sequence' // 遇到停止序列
| 'tool_use' // 需要执行工具
6. sdk/controlSchemas.ts — SDK 控制协议 Schema
行数: 664 行
功能概述
使用 Zod 定义 SDK 控制协议的完整 Schema,用于 CLI 和 Web/IDE 之间的双向通信。
控制请求类型
// 服务器 → 客户端的控制请求
type ServerControlRequest =
| { type: 'initialize', payload: InitializePayload }
type: 'set_model', payload: SetModelPayload }
| { type: 'interrupt', payload: InterruptPayload }
| { type: 'set_permission_mode', payload: SetPermissionModePayload }
| { type: 'set_max_thinking_tokens', payload: SetMaxThinkingTokensPayload }
控制响应类型
// 客户端 → 服务器的控制响应
type ClientControlResponse = {
requestId: string
success: boolean
error?: string
data?: unknown
}
Schema 验证
- 所有控制消息都经过 Zod Schema 验证
- 支持版本协商
- 类型安全的序列化/反序列化
模块间关系
entrypoints/
├── cli.tsx ──────────→ screens/REPL.tsx (交互模式)
│ → screens/Doctor.tsx (诊断模式)
│ → screens/ResumeConversation.tsx (恢复模式)
│
├── mcp.ts ──────────→ tools/ (注册工具为 MCP 资源)
│
├── agentSdkTypes.ts → 被 bridge/, hooks/, query/ 广泛引用
│
└── sdk/
├── coreTypes.ts → 基础类型,被所有 SDK 相关代码引用
└── controlSchemas.ts → 被 bridge/ 用于消息验证
设计亮点
- 多入口架构: 同一套核心代码支持 CLI、SDK、MCP 三种运行模式
- 协议分层: 控制协议与业务逻辑分离,Schema 独立定义
- 类型驱动: 使用 Zod Schema 同时提供运行时验证和编译时类型
- 渐进式复杂度: 从简单的 MCP 服务器到完整的交互式 CLI,复杂度逐层递增
03 - bootstrap 模块源码分析
路径:
src/bootstrap/文件数: 1 个(但极其庞大) 功能: 全局应用状态管理 — 整个应用的“神经系统“
模块概述
bootstrap/ 模块只有一个文件 state.ts,但它是整个 Claude Code 应用最核心的状态容器。它维护了一个全局单例 STATE 对象,通过 150+ 个 getter/setter 函数提供类型安全的状态访问。
state.ts — 全局状态容器
行数: 1758 行 导出数量: 215 个(函数、类型、常量等)
架构设计
┌─────────────────────────────────────────┐
│ STATE (单例对象) │
├─────────────────────────────────────────┤
│ 会话管理 │ 费用追踪 │ Token 统计 │
│ 路径管理 │ 模型配置 │ 遥测指标 │
│ Agent 状态 │ API 缓存 │ 错误日志 │
│ 插件系统 │ 权限管理 │ Cron 任务 │
│ Hook 系统 │ 技能追踪 │ 提示缓存 │
│ 模式标志 │ 团队创建 │ 调试状态 │
└─────────────────────────────────────────┘
↕ (通过 getter/setter 访问)
整个应用的所有模块
状态分类详解
1. 会话管理 (Session Management)
// 核心函数
getSessionId(): SessionId // 获取当前会话 ID
regenerateSessionId(): void // 重新生成会话 ID
switchSession(id: SessionId): void // 切换到指定会话
getParentSessionId(): SessionId | undefined // 获取父会话 ID(子Agent场景)
设计说明: 会话 ID 使用 randomUUID() 生成(通过 src/utils/crypto.js 封装),支持父子会话关系(用于子 Agent 场景)。switchSession 在恢复历史会话时使用。注意:parentSessionId 只有 getter,没有独立的 setter。
2. 路径管理 (Path Management)
getOriginalCwd(): string // 获取原始工作目录
setOriginalCwd(path: string): void
getProjectRoot(): string // 获取项目根目录
setProjectRoot(path: string): void
getCwdState(): string // 获取当前工作目录状态
setCwdState(state: string): void
设计说明: 区分“原始工作目录“(用户启动 CLI 的位置)和“项目根目录“(git 仓库根目录),这对于正确解析相对路径至关重要。
3. 费用与性能追踪 (Cost & Performance Tracking)
// 费用
addToTotalCostState(cost: number, modelUsage: ModelUsage, model: string): void
getTotalCostUSD(): number
// API 耗时
getTotalAPIDuration(): number
getTotalAPIDurationWithoutRetries(): number
// 工具耗时(按回合)
addToTurnHookDuration(ms: number): void
addToTurnToolDuration(ms: number): void
addToTurnClassifierDuration(ms: number): void
getTurnHookDurationMs(): number
getTurnToolDurationMs(): number
getTurnClassifierDurationMs(): number
设计说明: 性能追踪分为“总计“和“按回合“两个维度。回合级别的追踪用于识别单次交互中的性能瓶颈。
4. Token 统计 (Token Tracking)
// 全局 Token 统计
getTotalInputTokens(): number
getTotalOutputTokens(): number
getTotalCacheReadInputTokens(): number
getTotalCacheCreationInputTokens(): number
// 按模型统计
getModelUsage(): { [modelName: string]: ModelUsage }
注意:不存在独立的
recordModelUsage()和getTotalTokensAcrossModels()函数。模型使用数据通过addToTotalCostState()的第二、三个参数间接记录。
**ModelUsage 结构**:
```typescript
interface ModelUsage {
inputTokens: number
outputTokens: number
cacheReadInputTokens: number
cacheCreationInputTokens: number
apiCalls: number
totalDurationMs: number
}
设计说明: 使用 lodash-es/sumBy 聚合跨模型的 token 统计。支持多模型场景(主模型 + 分类器模型)。
5. 模型配置 (Model Configuration)
getMainLoopModelOverride(): ModelSetting | undefined
setMainLoopModelOverride(model: ModelSetting | undefined): void
getInitialMainLoopModel(): ModelSetting
setInitialMainLoopModel(model: ModelSetting): void
getModelStrings(): ModelStrings | null
setModelStrings(settings: ModelStrings): void
设计说明: 支持运行时模型切换(通过 /model 命令),同时保留初始模型配置用于回退。
6. OpenTelemetry 遥测 (Telemetry)
// Meter(指标)
setMeter(meter: Meter): void
getMeter(): Meter | undefined
// 各种计数器
getSessionCounter(): Counter
getLocCounter(): Counter // 代码行数计数器
getPrCounter(): Counter // PR 计数器
getCommitCounter(): Counter // 提交计数器
getCostCounter(): Counter // 费用计数器
getTokenCounter(): Counter // Token 计数器
getCodeEditToolDecisionCounter(): Counter // 代码编辑决策计数器
getActiveTimeCounter(): Counter // 活跃时间计数器
// Logger & Tracer
setLoggerProvider(provider: LoggerProvider): void
getEventLogger(): Logger | undefined
setMeterProvider(provider: MeterProvider): void
setTracerProvider(provider: BasicTracerProvider): void
设计说明: 完整集成 OpenTelemetry 标准,支持 Metrics、Logs、Traces 三大支柱。计数器覆盖了从会话到代码编辑的各个维度。
7. Agent 与 UI (Agent & UI)
getAgentColorMap(): Map<string, AgentColorName> // Agent ID → 颜色映射
设计说明: 多 Agent 场景下,每个 Agent 分配不同颜色用于 UI 区分。颜色从预定义调色板中循环分配。
8. API 请求缓存 (API Request Caching)
getLastAPIRequest(): unknown
setLastAPIRequest(request: unknown): void
getLastAPIRequestMessages(): Message[]
setLastAPIRequestMessages(messages: Message[]): void
getLastClassifierRequests(): unknown[]
setLastClassifierRequests(requests: unknown[]): void
设计说明: 缓存最近的 API 请求用于调试和重试。分别缓存主模型请求和分类器请求。
9. 错误日志 (Error Logging)
addToInMemoryErrorLog(errorInfo: { error: string; timestamp: string }): void
设计说明: 内存中的错误日志,用于 doctor 诊断命令和调试。不持久化到磁盘。注意:只有写入函数,没有独立的 getInMemoryErrorLog() getter。
10. 插件系统 (Plugin System)
getInlinePlugins(): Array<string>
setInlinePlugins(plugins: Array<string>): void
getUseCoworkPlugins(): boolean
setUseCoworkPlugins(enabled: boolean): void
11. 权限与信任 (Permissions & Trust)
getSessionBypassPermissionsMode(): boolean
setSessionBypassPermissionsMode(bypass: boolean): void
getSessionTrustAccepted(): boolean
setSessionTrustAccepted(accepted: boolean): void
设计说明: bypassPermissions 用于自动化场景(如 CI/CD),trustAccepted 记录用户是否已接受项目信任提示。
12. Cron 任务 (Cron Tasks)
getSessionCronTasks(): SessionCronTask[]
addSessionCronTask(task: SessionCronTask): void
removeSessionCronTasks(ids: string[]): void
getScheduledTasksEnabled(): boolean
setScheduledTasksEnabled(enabled: boolean): void
设计说明: 支持会话内的定时任务(如定期检查部署状态),任务随会话结束而销毁。
13. Hook 系统 (Hook System)
registerHookCallbacks(hooks: Partial<Record<HookEvent, RegisteredHookMatcher[]>>): void
getRegisteredHooks(): Partial<Record<HookEvent, RegisteredHookMatcher[]>> | null
clearRegisteredHooks(): void
14. 技能追踪 (Skills Tracking)
addInvokedSkill(skillName: string, skillPath: string, content: string, agentId: string | null = null): void
getInvokedSkills(): Map<string, InvokedSkillInfo>
clearInvokedSkills(): void
设计说明: 追踪已调用的技能,在消息压缩(compaction)事件后保持持久化。
15. 提示缓存 (Prompt Caching)
getPromptCache1hAllowlist(): string[] | null
setPromptCache1hAllowlist(allowlist: string[] | null): void
getPromptCache1hEligible(): boolean | null
setPromptCache1hEligible(eligible: boolean): void
getCachedClaudeMdContent(): string | null
setCachedClaudeMdContent(content: string): void
设计说明: 1 小时提示缓存白名单机制,减少重复的系统提示发送。CLAUDE.md 内容也被缓存以避免重复读取。
16. 模式标志 (Mode Flags)
getAfkModeHeaderLatched(): boolean | null // AFK 模式(离开键盘)
setAfkModeHeaderLatched(v: boolean): void
getFastModeHeaderLatched(): boolean // 快速模式
setFastModeHeaderLatched(v: boolean): void
getCacheEditingHeaderLatched(): boolean // 缓存编辑模式
setCacheEditingHeaderLatched(v: boolean): void
设计说明: 使用“锁存“(latched)模式,一旦设置在整个会话中不再改变。这些标志通过 HTTP 头传递给 API。
设计模式分析
1. 单例模式
整个模块维护一个 STATE 对象,所有状态集中管理。
2. 函数式访问器
不直接暴露 STATE 对象,而是通过 getter/setter 函数访问,确保类型安全和封装性。
3. 不可变性倾向
虽然 STATE 本身是可变的,但通过函数式接口鼓励单向数据流。
4. 关注点分离
150+ 个函数按功能域组织,每个域独立管理自己的状态切片。
为什么这个文件这么大?
state.ts 的 1758 行看起来很多,但考虑到:
- 它是整个应用唯一的全局状态容器
- 215 个导出大多是简单的 getter/setter(平均每个 ~8 行)
- 集中管理避免了状态分散导致的一致性问题
- 类型安全的访问器比直接操作全局对象更可靠
这是一个经过深思熟虑的架构决策,而非代码膨胀。
04 - cli 模块源码分析
路径:
src/cli/功能: CLI 传输层、IO 处理、子命令处理器
模块概述
cli/ 模块负责 CLI 的底层通信基础设施,包括传输协议(WebSocket/SSE/HTTP)、结构化 IO、子命令处理器和输出格式化。
文件清单
| 文件 | 行数 | 说明 |
|---|---|---|
structuredIO.ts | 859 | SDK 消息协议核心实现 |
remoteIO.ts | 255 | 远程双向流式 IO |
print.ts | 5594 | 输出打印/格式化(最大文件) |
ndjsonSafeStringify.ts | 33 | NDJSON 安全序列化 |
exit.ts | 32 | 退出辅助函数 |
update.ts | 422 | 版本更新检查 |
handlers/auth.ts | 331 | OAuth 认证处理 |
handlers/plugins.ts | 879 | 插件管理处理 |
handlers/autoMode.ts | 171 | 自动模式配置 |
handlers/agents.ts | 71 | Agent 列表显示 |
handlers/util.tsx | 110 | 杂项子命令 |
handlers/mcp.tsx | 361 | MCP 服务器管理 |
transports/HybridTransport.ts | 283 | 混合传输(WS读+HTTP写) |
transports/WebSocketTransport.ts | ~200 | WebSocket 传输 |
transports/SSETransport.ts | ~200 | SSE 传输 |
transports/SerialBatchEventUploader.ts | ~150 | 批量事件上传 |
transports/WorkerStateUploader.ts | ~100 | Worker 状态上传 |
transports/ccrClient.ts | ~200 | CCR v2 客户端 |
transports/transportUtils.ts | ~100 | 传输工具函数 |
核心文件详解
1. structuredIO.ts — SDK 消息协议核心
行数: 859 行
功能概述
实现 SDK 模式下的完整消息协议,处理控制请求/响应、权限管理、Hook 回调和 MCP 消息转发。
导出
StructuredIO类SANDBOX_NETWORK_ACCESS_TOOL_NAME常量
核心架构
外部客户端 (Web/IDE/SDK)
↕ JSON 消息
StructuredIO
├── 控制请求处理 (control_request)
│ ├── initialize
│ ├── set_model
│ ├── interrupt
│ ├── set_permission_mode
│ └── set_max_thinking_tokens
│
├── 控制响应处理 (control_response)
│ └── 权限请求的响应
│
├── 权限管理
│ ├── sendPermissionRequest()
│ ├── handlePermissionResponse()
│ └── cancelPermissionRequest()
│
├── Hook 回调
│ └── 转发 hook 执行结果
│
└── MCP 消息转发
└── 透传 MCP 协议消息
关键实现细节
class StructuredIO {
// 防重复:追踪已处理的 tool_use ID
private readonly resolvedToolUseIds = new Set<string>()
// 消息发送(带 NDJSON 安全序列化)
send(message: SDKMessage): void {
const json = ndjsonSafeStringify(message)
this.transport.write(json + '\n')
}
// 控制请求处理
async handleControlRequest(request: ServerControlRequest): Promise<void> {
switch (request.type) {
case 'initialize':
// 版本协商、能力交换
break
case 'set_model':
// 运行时模型切换
setMainLoopModelOverride(request.payload.model)
break
case 'interrupt':
// 中断当前执行
this.abortController.abort()
break
}
}
}
2. remoteIO.ts — 远程双向流式 IO
行数: 255 行
功能概述
扩展 StructuredIO,添加远程会话支持(WebSocket/SSE 传输、会话令牌刷新和 keep-alive 机制)。
导出
RemoteIO类(继承StructuredIO)
核心特性
class RemoteIO extends StructuredIO {
// CCR v2 客户端集成
private ccrClient: CCRClient
// 120 秒 keep-alive 帧
private keepAliveInterval = setInterval(() => {
this.send({ type: 'keep_alive' })
}, 120_000)
// 动态会话令牌刷新
async refreshSessionToken(): Promise<void> {
const newToken = await this.ccrClient.refreshToken()
this.transport.updateAuth(newToken)
}
}
3. ndjsonSafeStringify.ts — NDJSON 安全序列化
行数: 33 行
功能概述
解决 NDJSON(Newline DeliON)传输中的 Unicode 行终止符问题。
核心逻辑
export function ndjsonSafeStringify(value: unknown): string {
const json = JSON.stringify(value)
// 转义 U+2028 (行分隔符) 和 U+2029 (段落分隔符)
// 这两个 Unicode 字符在 JSON 中合法,但会破坏 NDJSON 的行分割
return json.replace(/[\u2028\u2029]/g, (char) =>
char === '\u2028' ? '\\u2028' : '\\u2029'
)
}
4. handlers/auth.ts — OAuth 认证处理
行数: 331 行
功能概述
完整的 OAuth 2.0 认证流程实现,支持 claude.ai 和 Console 两种认证源。
导出
installOAuthTokens()— 安装 OAuth 令牌authLogin()— 登录流程authStatus()— 认证状态查询authLogout()— 登出
authLogin() ├── 检查环境变量 CLAUDE_CODE_OAUTH_REFRESH_TOKEN(快速路径) │ └── 直接使用,跳过浏览器流程 │ └── 标准 OAuth 流程 ├── 启动本地 HTTP 服务器(回调接收) ├── 打开浏览器到授权页面 ├── 等待用户授权 ├── 接收授权码 ├── 交换 access_token + refresh_token ├── 获取用户 profile ├── 创建 API Key(如需要) └── 存储令牌到本地
#### 令牌存储
- 令牌存储在 `~/.claude/` 目录下
- 支持多账户切换
- 自动刷新过期令牌
---
### 5. handlers/plugins.ts — 插件管理处理
**行数**: 879 行
#### 功能概述
完整的插件生命周期管理,包括安装、卸载、启用、禁用、更新和市场操作。
#### 导出
- 多个插件操作处理函数
#### 支持的操作
| 操作 | 说明 |
|------|------|
| install | 安装插件(从市场或本地路径) |
| uninstall | 卸载插件 |
| enable | 启用已安装的插件 |
| disable | 禁用插件(保留安装) |
| update | 更新插件到最新版本 |
| list | 列出已安装插件 |
| search | 搜索市场插件 |
#### 作用域
```typescript
type PluginScope = 'user' | 'project' | 'local'
// user: ~/.claude/plugins/ — 全局插件
// project: .claude/plugins/ — 项目级插件
// local: 本地路径引用
–cowork 标志
支持 --cowork 标志,启用协作插件模式。
6. handlers/autoMode.ts — 自动模式配置
行数: 171 行
功能概述
管理自动模式的分类器规则,控制哪些操作自动允许、软拒绝或受环境限制。
导出
autoModeDefaultsHandler()— 默认规则管理autoModeConfigHandler()— 规则配置autoModeCritiqueHandler()— 规则审查(使用 LLM)
规则类别
type RuleCategory = 'allow' | 'soft_deny' | 'environment'
// allow: 自动允许的操作(如读取文件)
// soft_deny: 软拒绝(提示用户确认)
// environment: 环境限制(如网络访问)
LLM 审查
autoModeCritiqueHandler 使用 LLM 来审查用户编写的规则,确保规则的合理性和安全性。
传输层架构
HybridTransport — 混合传输
行数: 283 行
┌─────────────────────────────────────┐
│ HybridTransport │
├─────────────────────────────────────┤
│ 读取: WebSocket (实时推送) │
│ 写入: HTTP POST (批量上传) │
├─────────────────────────────────────┤
│ SerialBatchEventUploader │
│ ├── 100ms 缓冲窗口 │
│ ├── 合并 stream_event │
│ └── 指数退避重试 │
├─────────────────────────────────────┤
│ 超时配置: │
│ ├── POST 超时: 15 秒 │
│ └── 关闭优雅期: 3 秒 │
└─────────────────────────────────────┘
设计原因
- WebSocket 适合实时读取(低延迟推送)
- HTTP POST 适合可靠写入(自动重试、批量合并)
- 混合模式兼顾了实时性和可靠性
模块依赖关系
cli/
├── structuredIO.ts ← entrypoints/sdk/ (类型定义)
│ └── remoteIO.ts (继承扩展)
│
├── handlers/
│ ├── auth.ts ← constants/oauth (OAuth 配置)
│ ├── plugins.ts ← services/ (插件服务)
│ ├── autoMode.ts ← services/api/ (LLM 调用)
│ └── mcp.tsx ← tools/ (MCP 工具注册)
│
└── transports/
├── HybridTransport.ts
│ ├── WebSocketTransport.ts (基类)
│ └── SerialBatchEventUploader.ts (批量上传)
├── SSETransport.ts
└── ccrClient.ts (CCR v2 协议)
cli 模块 — handlers 子目录
路径:
src/cli/handlers/功能: CLI 子命令处理器
文件清单
| 文件 | 行数 | 说明 |
|---|---|---|
auth.ts | 331 | OAuth 2.0 认证流程(登录/登出/状态) |
plugins.ts | 879 | 插件完整生命周期(安装/卸载/启用/禁用/更新/市场) |
autoMode.ts | 171 | 自动模式分类器规则管理(allow/soft_deny/environment) |
agents.ts | 71 | Agent 列表显示(按来源分组) |
util.tsx | 110 | 杂项子命令(setupToken/doctor/install) |
mcp.tsx | ~1500+ | MCP 服务器管理(最大的 handler) |
auth.ts 详解
导出
installOAuthTokens()— 安装 OAuth 令牌authLogin()— 登录流程authStatus()— 认证状态查询authLogout()— 登出
登录流程
authLogin()
├── 快速路径: CLAUDE_CODE_OAUTH_REFRESH_TOKEN 环境变量
└── 标准 OAuth 流程
├── 启动本地 HTTP 服务器(回调接收)
├── 打开浏览器到授权页面
├── 等待用户授权 → 接收授权码
├── 交换 access_token + refresh_token
├── 获取用户 profile
└── 存储令牌到 ~/.claude/
plugins.ts 详解
支持的操作
| 操作 | 说明 |
|---|---|
| install | 从市场或本地路径安装 |
| uninstall | 卸载插件 |
| enable | 启用已安装的插件 |
| disable | 禁用(保留安装) |
| update | 更新到最新版本 |
| list | 列出已安装插件 |
| search | 搜索市场 |
三种作用域
user:~/.claude/plugins/— 全局project:.claude/plugins/— 项目级local: 本地路径引用
autoMode.ts 详解
三种规则类别
allow— 自动允许(如读取文件)soft_deny— 软拒绝(提示用户确认)environment— 环境限制(如网络访问)
LLM 审查
autoModeCritiqueHandler 使用 LLM 审查用户编写的规则,确保合理性和安全性。
cli 模块 — transports 子目录
路径:
src/cli/transports/功能: 网络传输层 — WebSocket/SSE/HTTP 传输协议实现
文件清单
| 文件 | 行数 | 说明 |
|---|---|---|
HybridTransport.ts | 283 | 混合传输(WS 读 + HTTP POST 写) |
WebSocketTransport.ts | ~200 | WebSocket 传输基类 |
SSETransport.ts | ~200 | Server-Sent Events 传输 |
SerialBatchEventUploader.ts | ~150 | 批量事件上传器 |
WorkerStateUploader.ts | ~100 | Worker 状态上传 |
ccrClient.ts | ~200 | CCR v2 客户端 |
transportUtils.ts | ~100 | 传输工具函数 |
HybridTransport — 核心传输
┌─────────────────────────────────────┐
│ HybridTransport │
├─────────────────────────────────────┤
│ 读取: WebSocket (实时推送,低延迟) │
│ 写入: HTTP POST (批量上传,可靠) │
├─────────────────────────────────────┤
│ SerialBatchEventUploader │
│ ├── 100ms 缓冲窗口 │
│ ├── 合并 stream_event │
│ └── 指数退避重试 │
├─────────────────────────────────────┤
│ 超时: POST 15s / 关闭优雅期 3s │
└─────────────────────────────────────┘
设计原因
- WebSocket 适合实时读取(低延迟推送)
- HTTP POST 适合可靠写入(自动重试、批量合并)
- 混合模式兼顾实时性和可靠性
ccrClient.ts — CCR v2 协议
CCR(Claude Code Remote)v2 客户端,处理远程会话的创建、令牌刷新和消息传输。
05 - commands 模块源码分析
路径:
src/commands/功能: 斜杠命令实现 — 内置命令的具体逻辑
模块概述
commands/ 包含所有内置斜杠命令的具体实现。这些命令通过 /命令名 在 REPL 中调用,涵盖会话管理、配置、调试、模型切换等功能。
典型命令列表
| 命令 | 功能 |
|---|---|
/help | 显示帮助信息 |
/clear | 清空对话 |
/compact | 压缩对话历史 |
/model | 切换模型 |
/config | 配置管理 |
/cost | 显示费用 |
/doctor | 运行诊断 |
/login | 登录认证 |
/logout | 登出 |
/permissions | 权限管理 |
/mcp | MCP 服务器管理 |
/vim | 切换 Vim 模式 |
/theme | 切换主题 |
/fast | 切换快速模式 |
/bug | 报告 Bug |
/init | 初始化项目配置 |
/memory | 记忆管理 |
/tasks | 任务管理 |
/hooks | 钩子管理 |
/listen | 语音模式 |
命令注册模式
每个命令文件导出一个 Command 对象:
// 典型命令结构
export const helpCommand: Command = {
name: 'help',
description: '显示帮助信息',
isEnabled: () => true,
isHidden: false,
userFacing: true,
execute: async (args, context) => {
// 命令逻辑
},
render: (props) => {
// React 组件渲染
return <HelpScreen />
}
}
命令分类
会话管理命令
/clear— 清空当前对话,重新开始/compact— 压缩对话历史,减少 token 使用/resume— 恢复之前的会话
配置命令
/config— 查看/修改配置/permissions— 管理权限规则/model— 切换 AI 模型/theme— 切换 UI 主题/vim— 切换 Vim 编辑模式/fast— 切换快速模式
诊断命令
/doctor— 运行系统诊断/cost— 显示当前会话费用/bug— 生成 Bug 报告
认证命令
/login— OAuth 登录/logout— 登出
扩展命令
/mcp— MCP 服务器管理/hooks— 钩子配置/tasks— 后台任务管理/memory— 自动记忆管理
命令安全分类
// 注意:这两个集合存放的是 Command 对象,不是字符串
const REMOTE_SAFE_COMMANDS: Set<Command> = new Set([...])
const BRIDGE_SAFE_COMMANDS: Set<Command> = new Set([...])
// 内部命令 — 对 AI 隐藏
const INTERNAL_ONLY_COMMANDS = new Set([...])
commands 模块 — 86 个斜杠命令完整清单
路径:
src/commands/子目录数: 86 个 每个命令一个独立目录,通过load: () => import()懒加载
会话管理(11 个)
| 命令 | 别名 | 行数 | 说明 |
|---|---|---|---|
/clear | reset, new | 19 | 清空对话历史,重新开始 |
/compact | — | 15 | 清空历史但保留摘要,支持非交互模式 |
/branch | fork | 14 | 创建对话分支 |
/resume | continue | 12 | 恢复之前的对话 |
/rewind | checkpoint | 13 | 回退代码/对话到之前的点 |
/rename | — | 12 | 重命名当前对话(立即执行) |
/export | — | 11 | 导出对话到文件或剪贴板 |
/tag | — | 12 | 给会话打标签(仅内部用户) |
/exit | quit | 12 | 退出 REPL(立即执行) |
/btw | — | 11 | 快速旁白问题,不打断主对话 |
/thinkback | — | 13 | 2025 年度回顾(特性门控) |
配置与设置(13 个)
| 命令 | 行数 | 说明 |
|---|---|---|
/config | 11 | 打开配置面板(别名 settings) |
/theme | 10 | 切换主题 |
/color | 16 | 设置提示栏颜色(立即执行) |
/model | 16 | 切换 AI 模型 |
/effort | 13 | 设置推理努力级别(low/medium/high/max/auto) |
/fast | 26 | 切换快速模式(受限可用性) |
/vim | 11 | 切换 Vim/Normal 编辑模式 |
/keybindings | 13 | 打开/创建快捷键配置文件 |
/privacy-settings | 14 | 查看/更新隐私设置(订阅用户) |
/remote-env | 15 | 配置默认远程环境 |
/sandbox-toggle | 50 | 配置沙箱设置(动态状态显示) |
/voice | 20 | 切换语音模式(claude.ai,特性门控) |
/output-style | 11 | 已弃用,隐藏 |
诊断与监控(7 个)
| 命令 | 行数 | 说明 |
|---|---|---|
/doctor | 12 | 诊断安装和设置问题 |
/status | 12 | 显示综合状态(立即执行) |
/stats | 10 | 显示使用统计和活动 |
/cost | 23 | 显示会话费用和时长(订阅用户隐藏,内部用户除外) |
/usage | 9 | 显示计划使用限制(claude.ai 用户) |
/diff | 8 | 查看未提交变更和每轮 diff |
/heapdump | 12 | 转储 JS 堆(隐藏,内部用) |
认证与账户(4 个)
| 命令 | 行数 | 说明 |
|---|---|---|
/login | 14 | 登录或切换账户 |
/logout | 10 | 登出 |
/upgrade | 16 | 升级到 Max 计划(claude.ai 用户) |
/passes | 22 | 分享免费周给朋友(推荐系统) |
远程与桥接(4 个)
| 命令 | 行数 | 说明 |
|---|---|---|
/bridge | 26 | 远程控制会话(特性门控,禁用时隐藏) |
/session | 16 | 显示远程会话 URL 和 QR 码(别名 remote) |
/remote-setup | 20 | 在 Web 上设置 Claude Code(命名 web-setup) |
/desktop | 26 | 在 Claude Desktop 中继续会话(平台特定) |
IDE 与集成(6 个)
| 命令 | 行数 | 说明 |
|---|---|---|
/ide | 11 | 管理 IDE 集成 |
/chrome | 13 | Chrome 中的 Claude 设置(claude.ai 用户) |
/mobile | 11 | 显示移动端 QR 码(别名 ios, android) |
/terminalSetup | 23 | 安装终端快捷键绑定(终端特定) |
/plugin | 11 | 管理插件(别名 plugins, marketplace,立即执行) |
/reload-plugins | 18 | 激活待处理的插件变更 |
上下文与文件(5 个)
| 命令 | 行数 | 说明 |
|---|---|---|
/context | 24 | 查看上下文(交互式彩色网格 / 非交互式) |
/files | 12 | 列出上下文中的文件(仅内部用户) |
/add-dir | 11 | 添加新的工作目录 |
/memory | 10 | 编辑 Claude 记忆文件 |
/copy | 15 | 复制 Claude 最后回复到剪贴板 |
规划与任务(3 个)
| 命令 | 行数 | 说明 |
|---|---|---|
/plan | 11 | 启用计划模式或查看会话计划 |
/tasks | 11 | 列出和管理后台任务(别名 bashes) |
/agents | 10 | 管理 Agent 配置 |
MCP 与工具(3 个)
| 命令 | 行数 | 说明 |
|---|---|---|
/mcp | 12 | 管理 MCP 服务器(立即执行) |
/permissions | 11 | 管理 allowed-tools) |
/hooks | 11 | 查看钩子配置 |
帮助与反馈(5 个)
| 命令 | 行数 | 说明 |
|---|---|---|
/help | 10 | 显示帮助和可用命令 |
/feedback | 26 | 提交反馈(别名 bug,多重限制) |
/release-notes | 11 | 查看发布说明 |
/stickers | 11 | 订购 Claude Code 贴纸 |
/skills | 10 | 列出可用技能 |
内部/禁用存根(5 个)
| 命令 | 说明 |
|---|---|
autofix-pr | 禁用存根(1 行) |
ant-trace | 禁用存根(1 行) |
bughunter | 禁用存根(1 行) |
backfill-sessions | 禁用存根(1 行) |
break-cache | 禁用存根(1 行) |
其他特殊命令
| 命令 | 行数 | 说明 |
|---|---|---|
/share | — | 分享对话 |
/summary | — | 生成对话摘要 /review |
/issue | — | GitHub Issue 操作 |
/install-github-app | — | 安装 GitHub App |
/install-slack-app | — | 安装 Slack App |
/good-claude | — | 正向反馈 |
/thinkback-play | 17 | 播放 thinkback 动画(隐藏) |
命令注册模式
// 每个命令目录的 index.ts(典型 10-26 行)
export default {
type: 'local', // 'local' | 'local-jsx'
name: 'help',
description: 'Show help',
isEnabled: () => true, // 动态启用检查
isHidden: false, // 是否在帮助中隐藏
userFacing: true,
aliases: [],
immediateExecution: false, // 是否立即执行(不进入对话)
load: () => import('./HelpCommand.js'), // 懒加载
}
可用性限制类型
claude-ai only — 仅 claude.ai 用户
ant-only — 仅 Anthropic 内部用户
subscriber-only — 仅付费订阅用户
feature-gated — 受特性标志控制
policy-based — 受组织策略控制
platform-specific — 特定平台
06 - screens 模块源码分析
路径:
src/screens/文件数: 3 个 功能: 主要 UI 屏幕 — REPL、会话恢复、诊断
模块概述
screens/ 包含 Claude Code 的三个主要用户界面屏幕。其中 REPL.tsx 是整个应用最核心、最庞大的组件。
1. REPL.tsx — 主交互屏幕(应用心脏)
行数: 5005 行(整个项目最大的单文件)
功能概述
REPL(Read-Eval-Print Loop)是 Claude Code 的核心交互界面,管理整个对话流程、工具执行、权限处理和用户交互。
架构分层
┌─────────────────────────────────────────────────┐
│ REPL 组件 │
├─────────────────────────────────────────────────┤
│ 输入层: PromptInput 组件 │
│ ├── 用户文本输入 │
│ ├── 命令解析 (/help, /commit 等) │
│ └── 附件处理(图片、文件) │
├─────────────────────────────────────────────────┤
│ 处理层: 消息处理 & 查询执行 │
│ ├── 消息队列管理 │
│ ├── query() 调用 → Claude API │
│ ├── 流式响应处理 │
│ ├── 工具调用分发 │
│ └── 权限请求处理 │
├─────────────────────────────────────────────────┤
│ 状态层: 会话 & 文件状态 │
│ ├── 对话消息数组 │
│ ├── 文件状态缓存 │
│ ├── 归因状态(用于 commit) │
│ ├── 后台任务状态 │
│ └── Swarm/团队成员状态 │
├─────────────────────────────────────────────────┤
│ 渲染层: UI 输出 │
│ ├── 消息列表(虚拟滚动) │
│ ├── 任务列表 (TaskListV2) │
│ ├── 权限对话框 │
│ ├── 费用摘要 │
│ ├── 处理中 Spinner │
│ └── 全屏布局模式 │
└─────────────────────────────────────────────────┘
核心状态
// 主要 useState 状态
const [messages, setMessages] = useState<Message[]>([]) // 对话消息
const [isProcessing, setIsProcessing] = useState(false) // 是否处理中
const [permissionRequest, setPermissionRequest] = useState() // 权限请求
const [fileStateCache, setFileStateCache] = useState() // 文件状态
const [attribution, setAttribution] = useState() // 归因信息
const [backgroundTasks, setBackgroundTasks] = useState() // 后台任务
消息处理流程
用户输入
↓
解析命令 (/ 开头?)
├── 是 → 执行命令处理器
└── 否 → 构建用户消息
↓
添加到消息数组
↓
调用 query(messages, tools, config)
↓
流式接收响应
├── 文本块 → 追加到助手消息
├── 工具调用 → 检查权限 → 执行工具 → 返回结果
└── 停止信号 → 执行停止钩子 → 完成回合
工具执行流程
AI 请求工具调用
↓
权限检查
├── 自动允许 → 直接执行
├── 需要确认 → 显示权限对话框
│ ├── 用户允许 → 执行
│ └── 用户拒绝 → 返回拒绝结果
└── 沙箱权限 → 沙箱权限管理
↓
执行工具
↓
收集结果
↓
更新文件状态缓存
↓
追踪执行指标
高级功能
| 功能 | 说明 |
|---|---|
| 语音集成 | 条件加载的语音输入/输出 |
| IDE Diff 同步 | 与 IDE 的文件差异同步 |
| 远程会话 | 支持远程 SSH 会话 |
| 主动建议 | 条件启用的主动提示建议 |
| 定时任务/触发器 | 条件启用的计划任务 |
| Web 浏览器工具 | 条件启用的浏览器自动化 |
| 消息编辑 | 支持编辑和重新提交消息 |
| 压缩操作 | 手动/自动消息压缩 |
| 会话分叉 | 从任意点分叉会话 |
会话管理
// 自动保存
useEffect(() => {
const interval = setInterval(() => {
saveSessionState(messages, metadata)
}, AUTO_SAVE_INTERVAL)
return () => clearInterval(interval)
}, [messages])
// 会话标题生成
useEffect(() => {
if (messages.length > 2 && !sessionTitle) {
generateSessionTitle(messages).then(setSessionTitle)
}
}, [messages.length])
2. ResumeConversation.tsx — 会话恢复屏幕
行数: 398 行
功能概述
允许用户浏览和恢复之前的对话会话,支持同仓库和跨项目的会话查找。
核心流程
加载会话列表(渐进式)
↓
显示会话选择器
├── 按仓库过滤
├── 按 PR 编号过滤
└── 跨项目搜索
↓
用户选择会话
↓
检查跨项目情况
├── 同项目 → 直接恢复
└── 跨项目 → 显示切换命令
↓
恢复会话数据
├── restoreSessionMetadata() — 恢复会话元数据
├── restoreWorktreeForResume() — 恢复 Worktree 状态
├── adoptResumedSessionFile() — 接管会话文件指针
├── restoreAgentFromSession() — 恢复 Agent 上下文
└── recordContentReplacement() — 记录内容替换
↓
渲染 REPL 组件(带恢复的消息)
关键函数
// 渐进式加载会话日志
loadSameRepoMessageLogsProgressive() // 同仓库会话
loadAllProjectsMessageLogsProgressive() // 所有项目会话
// PR 过滤
parsePrIdentifier(input: string) // 解析 PR 标识符
// 跨项目检测
checkCrossProjectResume(session, currentProject)
// 会话分叉
forkSession(originalSession) // 创建会话副本
会话恢复(真实函数)
// 源码 src/screens/ResumeConversation.tsx:254-261
restoreSessionMetadata(...) // 恢复会话元数据
restoreWorktreeForResume(...) // 恢复 Worktree 状态
adoptResumedSessionFile() // 接管会话文件指针
注意:之前文档中写的 adoptSession() 抽象函数不存在。
3. Doctor.tsx — 诊断屏幕
行数: 574 行
功能概述
系统诊断和健康检查屏幕,显示系统信息、配置状态、验证错误和版本信息。
诊断内容
Doctor 诊断报告
├── 系统信息
│ ├── Claude Code 版本
│ ├── 操作系统版本
│ ├── Node/Bun 运行时版本
│ └── Shell 类型
│
├── Agent 信息
│ ├── 活跃 Agent 列表(按来源分组)
│ │ ├── built-in (内置)
│ │ ├── user (用户级)
│ │ ├── project (项目级)
│ │ └── plugin (插件)
│ ├── Agent 目录路径
│ └── 加载失败的 Agent 文件
│
├── 配置验证
│ ├── settings.json 验证错误
│ ├── MCP 解析警告
│ ├── 环境变量验证
│ │ ├── BASH_MAX_OUTPUT_LENGTH
│ │ ├── TASK_MAX_OUTPUT_LENGTH
│ │ └── CLAUDE_CODE_MAX_OUTPUT_TOKENS
│ └── 快捷键冲突
│
├── 版本信息
│ ├── 当前版本
│ ├── 可用版本(stable/latest)
│ ├── 自动更新渠道
│ └── npm/GCS dist tags
│
├── 锁管理
│ ├── PID 版本锁状态
│ ├── 活跃锁列表
│ └── 已清理的过期锁
│
└── 沙箱诊断
└── 沙箱环境状态
导出
Doctor— 主组件DistTagsDisplay— 版本标签显示辅助组件
UI 结构
<Pane title="Claude Code Doctor">
<SystemInfo />
<AgentInfo />
<ValidationErrors />
<VersionInfo />
<LockStatus />
<SandboxDiagnostic />
<Text>"Press Enter to continue"</Text>
</Pane>
模块间关系
screens/
├── REPL.tsx
│ ├── ← components/ (UI 组件)
│ ├── ← query/ (查询执行)
│ ├── ← tools/ (工具注册)
│ ├── ← hooks/ (钩子系统)
│ ├── ← services/ (API/分析)
│ ├── ← state/ (状态管理)
│ └── ← keybindings/ (快捷键)
│
├── ResumeConversation.tsx
│ ├── ← utils/sessionStorage (会话存储)
│ ├── ← utils/fileHistory (文件历史)
│ └── → REPL.tsx (恢复后渲染)
│r.tsx
├── ← services/analytics (诊断数据)
├── ← schemas/ (配置验证)
└── ← cli/update (版本检查)
07 - components 模块源码分析
路径:
src/components/根级文件数: 110+ 个.tsx/.ts文件 子目录数: 31 个 功能: React UI 组件库 — 终端界面的所有可视化组件
模块概述
components/ 是 Claude Code 中文件数量最多的模块。基于 Ink 框架,这些组件在终端中渲染富文本界面。
根级核心组件(精选)
消息显示
| 文件 | 说明 |
|---|---|
Messages.tsx | 消息列表容器 |
Message.tsx | 单条消息渲染 |
MessageRow.tsx | 消息行布局 |
VirtualMessageList.tsx | 虚拟滚动消息列表(性能优化) |
MessageResponse.tsx | 助手响应渲染 |
MessageSelector.tsx | 消息选择器 |
MessageTimestamp.tsx | 消息时间戳 |
MessageModel.tsx | 消息模型标识 |
Markdown.tsx | Markdown 渲染器 |
MarkdownTable.tsx | Markdown 表格 |
代码与 Diff
| 文件 | 说明 |
|---|---|
StructuredDiff.tsx | 结构化代码差异显示 |
StructuredDiffList.tsx | 差异列表 |
FileEditToolDiff.tsx | 文件编辑工具的 diff 显示 |
HighlightedCode.tsx | 代码语法高亮 |
对话框与交互
| 文件 | 说明 |
|---|---|
AutoModeOptInDialog.tsx | 自动模式选择对话框 |
BridgeDialog.tsx | 桥接对话框 |
BypassPermissionsModeDialog.tsx | 权限绕过对话框 |
CostThresholdDialog.tsx | 费用阈值对话框 |
ExportDialog.tsx | 导出对话框 |
GlobalSearchDialog.tsx | 全局搜索对话框 |
HistorySearchDialog.tsx | 历史搜索对话框 |
ModelPicker.tsx | 模型选择器 |
ThemePicker.tsx | 主题选择器 |
OutputStylePicker.tsx | 输出样式选择器 |
状态与信息
| 文件 | 说明 |
|---|---|
StatusLine.tsx | 状态行 |
StatusNotices.tsx | 状态通知 |
Spinner.tsx | 加载动画 |
TaskListV2.tsx | 任务列表 |
Stats.tsx | 使用统计 |
TokenWarning.tsx | Token 警告 |
MemoryUsageIndicator.tsx | 内存使用指示器 |
布局与导航
| 文件 | 说明 |
|---|---|
App.tsx | 应用根组件 |
FullscreenLayout.tsx | 全屏布局 |
ScrollKeybindingHandler.tsx | 滚动快捷键处理 |
TagTabs.tsx | 标签页 |
SearchBox.tsx | 搜索框 |
工具相关
| 文件 | 说明 |
|---|---|
ToolUseLoader.tsx | 工具调用加载器 |
FallbackToolUseErrorMessage.tsx | 工具错误回退消息 |
FallbackToolUseRejectedMessage.tsx | 工具拒绝回退消息 |
FileEditToolUpdatedMessage.tsx | 文件编辑更新消息 |
远程与桥接
| 文件 | 说明 |
|---|---|
TeleportProgress.tsx | Teleport 进度 |
TeleportError.tsx | Teleport 错误 |
RemoteCallout.tsx | 远程提示 |
RemoteEnvironmentDialog.tsx | 远程环境对话框 |
其他
| 文件 | 说明 |
|---|---|
TextInput.tsx | 基础文本输入 |
VimTextInput.tsx | Vim 模式文本输入 |
BaseTextInput.tsx | 文本输入基类 |
Onboarding.tsx | 新手引导 |
Feedback.tsx | 反馈组件 |
DevBar.tsx | 开发者工具栏 |
子目录(31 个)
PromptInput/ — 用户输入(21 文件)
最核心的交互组件目录:
| 文件 | 说明 |
|---|---|
PromptInput.tsx | 主输入组件 |
ShimmeredInput.tsx | 带闪烁效果的输入 |
PromptInputFooter.tsx | 底部快捷键和状态 |
PromptInputFooterLeftSide.tsx | 底部左侧 |
PromptInputFooterSuggestions.tsx | 底部建议 |
PromptInputHelpMenu.tsx | 帮助菜单 |
PromptInputModeIndicator.tsx | 模式指示器 |
PromptInputQueuedCommands.tsx | 排队命令 |
PromptInputStashNotice.tsx | Stash 通知 |
VoiceIndicator.tsx | 语音指示器 |
HistorySearchInput.tsx | 历史搜索输入 |
IssueFlagBanner.tsx | Issue 标记横幅 |
Notifications.tsx | 通知 |
SandboxPromptFooterHint.tsx | 沙箱提示 |
inputModes.ts | 输入模式定义 |
inputPaste.ts | 粘贴处理 |
useMaybeTruncateInput.ts | 输入截断 Hook |
usePromptInputPlaceholder.ts | 占位符 Hook |
useShowFastIconHint.ts | 快速模式提示 Hook |
useSwarmBanner.ts | Swarm 横幅 Hook |
utils.ts | 工具函数 |
permissions/ — 权限请求(30+ 文件)
| 子目录/文件 | 说明 |
|---|---|
PermissionDialog.tsx | 基础权限对话框 |
PermissionRequest.tsx | 权限请求组件 |
PermissionPrompt.tsx | 权限提示 |
PermissionRequestTitle.tsx | 请求标题 |
PermissionExplanation.tsx | 权限解释 |
PermissionRuleExplanation.tsx | 规则解释 |
WorkerBadge.tsx | Worker 标记 |
BashPermissionRequest/ | Shell 命令审批 |
FileEditPermissionRequest/ | 文件编辑审批 |
FileWritePermissionRequest/ | 文件写入审批 |
FilePermissionDialog/ | 文件权限对话框 |
WebFetchPermissionRequest/ | HTTP 请求审批 |
AskUserQuestionPermissionRequest/ | 用户提问审批 |
EnterPlanModePermissionRequest/ | 计划模式审批 |
ExitPlanModePermissionRequest/ | 退出计划审批 |
ComputerUseApproval/ | 计算机使用审批 |
SandboxPermissionRequest.tsx | 沙箱权限 |
SkillPermissionRequest/ | 技能权限 |
| ellPermissionRequest/` | PowerShell 权限 |
NotebookEditPermissionRequest/ | Notebook 编辑权限 |
SedEditPermissionRequest/ | Sed 编辑权限 |
FilesystemPermissionRequest/ | 文件系统权限 |
rules/ | 权限规则子目录 |
messages/ — 消息组件(33 文件)
| 文件 | 说明 |
|---|---|
UserPromptMessage.tsx | 用户输入消息 |
UserTextMessage.tsx | 用户文本消息 |
UserImageMessage.tsx | 用户图片消息 |
UserBashInputMessage.tsx | 用户 Bash 输入 |
UserBashOutputMessage.tsx | 用户 Bash 输出 |
UserCommandMessage.tsx | 用户命令消息 |
UserTeammateMessage.tsx | 用户队友消息 |
UserChannelMessage.tsx | 用户频道消息 |
AssistantTextMessage.tsx | 助手文本回复 |
AssistantToolUseMessage.tsx | 助手工具调用 |
AssistantThinkingMessage.tsx | 助手思考过程 |
AssistantRedactedThinkingMessage.tsx | 助手编辑后思考 |
AttachmentMessage.tsx | 附件消息 |
SystemTextMessage.tsx | 系统文本消息 |
SystemAPIErrorMessage.tsx | API 错误消息 |
RateLimitMessage.tsx | 速率限制消息 |
CompactBoundaryMessage.tsx | 压缩边界消息 |
HookProgressMessage.tsx | 钩子进度消息 |
PlanApprovalMessage.tsx | 计划审批消息 |
TaskAssignmentMessage.tsx | 任务分配消息 |
ShutdownMessage.tsx | 关闭消息 |
HighlightedThinkingText.tsx | 高亮思考文本 |
GroupedToolUseContent.tsx | 分组工具调用内容 |
CollapsedReadSeant.tsx | 折叠的读取/搜索内容 |
AdvisorMessage.tsx | 顾问消息 |
UserToolResultMessage/ | 用户工具结果(子目录) |
diff/ — 代码差异(3 文件)
| 文件 | 说明 |
|---|---|
DiffDetailView.tsx | 详细 diff 视图 |
DiffDialog.tsx | Diff 对话框 |
DiffFileList.tsx | 变更文件列表 |
其他子目录
| 目录 | 说明 |
|---|---|
agents/ | Agent 管理和创建向导 |
teams/ | 团队协作组件 |
tasks/ | 后台任务 UI |
mcp/ | MCP 服务器管理界面 |
skills/ | 技能相关组件 |
memory/ | 记忆管理组件 |
sandbox/ | 沙箱管理组件 |
shell/ | Shell 相关组件 |
hooks/ | 组件级自定义 Hooks |
ui/ | 通用 UI 工具组件 |
design-system/ | 设计系统(ThemedText、Dialog、Pane 等) |
w/ | 向导流程组件 |
grove/ | Grove 相关组件 |
CustomSelect/ | 自定义选择列表 |
Settings/ | 设置面板 |
HelpV2/ | 帮助界面 v2 |
LogoV2/ | Logo 显示 v2 |
Spinner/ | 加载动画(子目录) |
StructuredDiff/ | 结构化 diff(子目录) |
TrustDialog/ | 项目信任对话框 |
FeedbackSurvey/ | 反馈调查 |
Passes/ | 通行证/推荐 |
DesktopUpsell/ | 桌面版推广 |
ClaudeCodeHint/ | 使用提示 |
LspRecommendation/ | LSP 推荐 |
HighlightedCode/ | 代码高亮(子目录) |
ManagedSettingsSecurityDialog/ | 托管设置安全对话框 |
components 模块 — 31 个组件子目录分类
路径:
src/components/子目录数: 31 个 总文件数: 150+
设计系统(design-system/)
基础 UI 原语,被其他所有组件使用:
ThemedText— 主题感知文本(从主题键或原始颜色解析)Dialog— 基础对话框(取消/确认,可配置快捷键)Pane— 带边框的面板容器FuzzyPicker— 模糊搜索选择界面Tabs— 标签页导航ProgressBar— 进度条Tooltip— 悬停信息Badge— 状态标记Divider— 分隔线ErrorBoundary— 错误边界
核心交互组件
PromptInput/(20+ 文件)
用户输入的主入口,最复杂的组件目录:
PromptInput— 主输入组件ShimmeredInput— 带闪烁效果的输入InputFooter— 底部快捷键和状态InputHeader— 顶部上下文信息AttachmentList— 附件管理InputHistory— 命令历史导航InputSuggestions— 自动补全建议MultilineInput— 多行输入CodeInput— 代码输入(语法高亮)
CustomSelect/
自定义选择列表(键盘导航、搜索过滤、多选、分组)
Spinner/
加载动画指示器
权限组件(permissions/,30+ 文件)
| 组件 | 说明 |
|---|---|
PermissionDialog | 基础权限对话框包装器(圆角边框、标题) |
BashPermissionRequest | Shell 命令审批 |
FileEditPermissionRequest | 文件修改审批 |
FileReadPermissionRequest | 文件读取审批 |
FileWritePermissionRequest | 文件写入审批 |
WebFetchPermissionRequest | HTTP 请求审批 |
MCPToolPermissionRequest | MCP 工具执行审批 |
AgentPermissionRequest | Agent 操作审批 |
NetworkPermissionRequest | 网络访问审批 |
WorkerBadge | 显示请求权限的 worker/agent |
消息组件(messages/,30+ 文件)
| 组件 | 说明 |
|---|---|
UserPromptMessage | 用户输入显示(10k 字符截断:头 2.5k + 尾 2.5k) |
AssistantTextMessage | 助手文本回复 |
AssistantToolUseMessage | 工具调用显示 |
ThinkingMessage | 思考过程显示 |
ToolResultMessage | 工具执行结果 |
ErrorMessage | 错误显示 |
SystemMessage | 系统通知 |
CodeBlockMessage | 代码块(语法高亮) |
DiffMessage | 代码变更可视化 |
ImageMessage | 图片内容 |
任务组件(tasks/,12 文件)
后台任务的 UI 展示:
BackgroundTasksDialog— 后台任务管理对话框RemoteSessionProgress— 远程会话进度ShellProgress— Shell 命令执行进度TaskList/TaskItem/TaskStatus/TaskProgress
MCP 组件(mcp/,13 文件)
MCP 服务器管理界面:
MCPSettings— 配置界面MCPReconnect— 重连处理MCPToolListView— 可用工具列表MCPServerStatus— 连接状态MCPServerList— 服务器列表
Agent 组件(agents/,20+ 文件)
Agent 管理和创建向导:
AgentsMenu— Agent 选择和管理CreateAgentWizard— 多步骤创建向导AgentNameStep→AgentDescriptionStep→AgentInstructionsStep→AgentToolsStep→AgentReviewStep
AgentList/AgentCard/AgentStatus
Diff 组件(diff/,3 文件)
代码差异显示:
DiffFileList— 变更文件列表DiffDialog— 代码比较界面DiffDetailView— 详细 diff(语法高亮)
其他组件目录
| 目录 | 说明 |
|---|---|
hooks/ | 组件级自定义 Hooks |
ui/ | 通用 UI 工具组件 |
shell/ | Shell 相关组件 |
sandbox/ | 沙箱管理组件 |
memory/ | 记忆管理组件 |
skills/ | 技能相关组件 |
teams/ | 团队协作组件 |
wizard/ | 向导流程组件 |
grove/ | Grove 相关组件 |
TrustDialog/ | 项目信任对话框 |
Settings/ | 设置面板 |
HelpV2/ | 帮助界面 v2 |
LogoV2/ | Logo 显示 v2 |
HighlightedCode/ | 代码高亮显示 |
StructuredDiff/ | 结构化 diff |
FeedbackSurvey/ | 反馈调查 |
Passes/ | 通行证/推荐 |
DesktopUpsell/ | 桌面版推广 |
ClaudeCodeHint/ | 使用提示 |
LspRecommendation/ | LSP 推荐 |
ManagedSettingsSecurityDialog/ | 托管设置安全对话框 |
关键设计模式
- 主题系统:
resolveColor()处理主题键和原始颜色(rgb/hex/ansi256) - React Compiler: 所有组件使用
_c函数优化 - 截断策略: 大内容 >10k 字符截断,防止按键延迟
- Feature Flags: KAIROS/KAIROS_BRIEF 控制布局模式
08 - ink 模块源码分析
路径:
src/ink/文件数: 96 个 功能: 深度定制的 Ink 终端渲染引擎
模块概述
ink/ 是对 Ink(React 终端 UI 框架)的深度定制版本。Claude Code 没有直接使用 npm 上的 ink 包,而是将其 fork 并大幅扩展,添加了自定义布局引擎、事件系统、终端查询、搜索高亮等功能。
架构总览
ink/
├── 核心渲染
│ ├── ink.tsx # Ink 主入口 & render()
│ ├── reconciler.ts # React Reconciler(自定义)
│ ├── renderer.ts # 渲染管线
│ ├── root.ts # 根节点管理
│ ├── dom.ts # 虚拟 DOM 节点
│ └── instances.ts # 实例管理
│
├── 布局系统
│ ├── layout/
│ │ ├── engine.ts # 薄包装:createLayoutNode() → createYogaLayoutNode()
│ │ ├── node.ts # 布局节点
│ │ ├── geometry.ts # 几何计算
│ │ └── yoga.ts # Yoga 集成(真正的布局核心,308 行)
│ ├── styles.ts # 样式处理
│ └── get-max-width.ts # 最大宽度计算
│
├── 输出管线
│ ├── output.ts # 输出缓冲
│ ├── render-node-to-output.ts # 节点→输出
│ ├── render-border.ts # 边框渲染
│ ├── render-to-screen.ts # 输出→屏幕
│ ├── frame.ts # 帧管理
│ └── log-update.ts # 增量屏幕更新
│
├── 文本处理
│ ├── stringWidth.ts # 字符串宽度计算
│ ├── wrapAnsi.ts # ANSI 文本换行
│ ├── widest-line.ts # 最宽行计算
│ ├── squash-text-nodes.ts # 文本节点合并
│ ├── bidi.ts # 双向文本支持
│ ├── colorize.ts # 颜色化
│ └── tabstops.ts # Tab 停止位
│
├── 事件系统
│ ├── events/
│ │ ├── emitter.ts # 事件发射器
│ │ ├── dispatcher.ts # 事件分发器
│ │ ├── event.ts # 基础事件
│ │ ├── input-event.ts # 输入事件
│ │ ├── keyboard-event.ts # 键盘事件
│ │ ├── click-event.ts # 点击事件
│ │ ├── focus-event.ts # 焦点事件
│ │ └── terminal-event.ts # 终端事件
│ ├── parse-keypress.ts # 按键解析
│ └── hit-test.ts # 点击测试
│
├── 终端交互
│ ├── terminal.ts # 终端抽象
│ ├── terminal-querier.ts # 终端能力查询
│ ├── terminal-focus-state.ts # 终端焦点状态
│ ├── supports-hyperlinks.ts # 超链接支持检测
│ └── termio/ # 终端 IO 协议
│ ├── tokenize.ts # 令牌化
│ ├── parser.ts # 解析器
│ ├── ansi.ts # ANSI 序列
│ ├── csi.ts # CSI 序列
│ ├── sgr.ts # SGR(颜色/样式)
│ ├── osc.ts # OSC 序列
│ ├── esc.ts # ESC 序列
│ ├── dec.ts # DEC 私有序列
│ └── types.ts # 类型定义
│
├── 基础组件
│ ├── components/
│ │ ├── Box.tsx # 盒模型容器
│ │ ├── Text.tsx # 文本组件
│ │ ├── Spacer.tsx # 间距组件
│ │ ├── Newline.tsx # 换行组件
│ │ ├── Link.tsx # 超链接组件
│ │ ├── Button.tsx # 按钮组件
│ │ ├── ScrollBox.tsx # 滚动容器
│ │ ├── NoSelect.tsx # 不可选择区域
│ │ ├── RawAnsi.tsx # 原始 ANSI 输出
│ │ ├── AlternateScreen.tsx # 备用屏幕
│ │ ├── ErrorOverview.tsx # 错误概览
│ │ ├── App.tsx # 应用根组件
│ │ └── 上下文提供者...
│ └── Ansi.tsx # ANSI 渲染组件
│
├── Hooks
│ ├── hooks/
│ │ ├── use-input.ts # 输入处理
│ │ ├── use-stdin.ts # stdin 访问
│ │ ├── use-app.ts # 应用上下文
│ │ ├── use-selection.ts # 选择状态
│ │ ├── use-interval.ts # 定时器
│ │ ├── use-animation-frame.ts # 动画帧
│ │ ├── use-terminal-viewport.ts # 终端视口
│ │ ├── use-terminal-title.ts # 终端标题
│ │ ├── use-terminal-focus.ts # 终端焦点
│ │ ├── use-declared-cursor.ts # 光标声明
│ │ ├── use-tab-status.ts # Tab 状态
│ │ └── use-search-highlight.ts # 搜索高亮
│
├── 优化
│ ├── optimizer.ts # 渲染优化器
│ ├── node-cache.ts # 节点缓存
│ └── line-width-cache.ts # 行宽缓存
│
├── 焦点管理
│ ├── focus.ts # 焦点系统
│ └── selection.ts # 选择管理
│
├── 搜索
│ └── searchHighlight.ts # 搜索高亮
│
└── 常量
├── constants.ts # 常量定义
└── warn.ts # 警告工具
核心渲染管线
` React 组件树 ↓ (reconciler.ts — 自定义 React Reconciler) 虚拟 DOM 树 (dom.ts) ↓ (layout/engine.ts — Yoga Flexbox 布局) 布局树(带位置和尺寸) ↓ (render-node-to-output.ts) 输出缓冲 (output.ts) ↓ (render-border.ts — 边框渲染) ↓ (colorize.ts — 颜色化) ↓ (render-to-screen.ts) ANSI 字符串 ↓ (log-update.ts — 增量更新) 终端屏幕
---
## 关键子系统
### 1. 自定义 React Reconciler
```typescript
// reconciler.ts
// 使用 react-reconciler 创建自定义渲染器
// 将 React 组件映射到终端虚拟 DOM 节点
const reconciler = createReconciler({
createInstance(type, props) {
return new DOMNode(type, props)
},
aToContainer(container, child) {
container.appendChild(child)
},
// ... 完整的 reconciler 接口实现
})
2. 终端 IO 协议栈 (termio/)
原始字节流
↓ tokenize.ts (令牌化)
令牌流 (ANSI/CSI/SGR/OSC/ESC/DEC)
↓ parser.ts (解析)
结构化事件
↓ 分发到对应处理器
支持的终端协议
- ANSI: 基础控制序列
- CSI: 控制序列引入(光标移动、清屏等)
- SGR: 选择图形再现(颜色、粗体等)
- OSC: 操作系统命令(超链接、标题等)
- ESC: 转义序列
- DEC: DEC 私有序列(光标样式等)
3. 事件系统
终端原始输入
↓ parse-keypress.ts
键盘事件 (KeyboardEvent)
↓ hit-test.ts
点击事件 (ClickEvent) — 如果是鼠标输入
↓ dispatcher.ts
事件分发到组件树
↓ emitter.ts
组件事件处理器
4. 焦点管理
// focus.ts
// 管理组件焦点状态
// 支持 Tab 导航和程序化焦点切换
class FocusManager {
focusNext(): void
focusPrevious(): void
focus(id: string): void
blur(): void
}
与标准 Ink 的差异
| 特性 | 标准 Ink | Claude Code Ink |
|---|---|---|
| 布局引擎 | yoga-wasm | 纯 TS Yoga 移植 |
| 事件系统 | 基础键盘 | 完整事件系统(键盘/鼠标/焦点) |
| 终端协议 | 基础 ANSI | 完整协议栈(CSI/SGR/OSC/DEC) |
| 搜索高亮 | 无 | 内置搜索高亮 |
| 点击测试 | 无 | 支持鼠标点击 |
| 超链接 | 无 | OSC 8 终端超链接 |
| 双向文本 | 无 | BiDi 支持 |
| 渲染优化 | 基础 | 节点缓存 + 行宽缓存 + 优化器 |
| 光标管理 | 基础 | 声明式光标系统 |
设计亮点
- 零 WASM 依赖: 用纯 TS Yoga 替代 yoga-wasm,避免 WASM 加载问题
- 完整终端协议: 部能力(超链接、鼠标、焦点追踪)
- 声明式光标: 组件声明光标位置,框架自动管理
- 增量渲染: log-update 只更新变化的行,减少闪烁
- 多层缓存: 节点缓存 + 行宽缓存 + 布局缓存,确保渲染性能
ink 模块 — 5 个子目录详解
路径:
src/ink/子目录: layout/, events/, hooks/, components/, termio/
1. layout/ — Flexbox 布局引擎(4 文件)
| 文件 | 行数 | 说明 |
|---|---|---|
yoga.ts | 309 | Yoga 布局引擎 TS 移植,createYogaNode 工厂 |
node.ts | 153 | LayoutNode 接口定义(几何 + 样式属性) |
geometry.ts | 98 | 几何原语(Rect, Point, Size, Edges) |
engine.ts | 6 | 布局节点工厂函数 |
2. events/ — DOM 风格事件系统(10 文件)
| 文件 | 行数 | 说明 |
|---|---|---|
event.ts | 12 | 基础 Event 类 |
terminal-event.ts | 108 | TerminalEvent 基类,DOM 风格传播 API(capture/bubble) |
dispatcher.ts | 234 | 事件分发系统,capture/bubble 两阶段 |
keyboard-event.ts | 52 | KeyboardEvent 实现 |
focus-event.ts | 22 | FocusEvent(带 relatedTarget) |
click-event.ts | 39 | ClickEvent(带本地坐标) |
input-event.ts | 206 | 输入解析,支持 Kitty 键盘协议 |
emitter.ts | 40 | 自定义 EventEmitter(stopImmediatePropagation) |
event-handlers.ts | 74 | 事件处理器类型定义 |
terminal-focus-event.ts | — | 终端焦点事件 |
3. termio/ — 终端 IO 协议栈(9 文件)
原始字节流 → tokenize.ts → parser.ts → 结构化事件
| 文件 | 行数 | 说明 |
|---|---|---|
ansi.ts | 76 | C0 控制字符和 ESC_TYPE 常量 |
types.ts | 237 | 语义类型(Color, TextStyle, Action) |
tokenize.ts | 320 | 流式令牌化器,X10 鼠标支持 |
parser.ts | 395 | 语义动作生成器,grapheme 分割 |
sgr.ts | 309 | SGR 参数解析(颜色/样式),扩展色支持 |
csi.ts | 320 | CSI 序列类型和生成器 |
osc.ts | 494 | OSC 序列解析(剪贴板、超链接、标题) |
esc.ts | 68 | ESC 序列解析 |
dec.ts | 61 | DEC 私有模式序列 |
4. components/ — 基础 UI 组件(18 文件)
| 文件 | 行数 | 说明 |
|---|---|---|
App.tsx | 657 | 应用根组件(React Compiler 优化) |
Text.tsx | 254 | 核心文本渲染(样式、颜色、粗体等) |
Box.tsx | 213 | 盒模型布局容器(Flexbox 属性) |
ScrollBox.tsx | 237 | 滚动容器(命令式 API,视口裁剪) |
Button.tsx | 192 | 交互按钮(focus/hover/active 状态) |
AlternateScreen.tsx | 80 | 备用屏幕缓冲管理 |
Link.tsx | 42 | 超链接(OSC 8 终端超链接) |
Newline.tsx | 39 | 换行插入 |
Spacer.tsx | 20 | 弹性间距 |
RawAnsi.tsx | ~50 | 原始 ANSI 输出 |
NoSelect.tsx | ~30 | 不可选择区域 |
ErrorOverview.tsx | ~100 | 错误概览 |
AppContext.ts | ~20 | 应用上下文 |
StdinContext.ts | ~20 | stdin 上下文 |
ClockContext.tsx | — | 时钟上下文(定时刷新) |
CursorDeclarationContext.ts | — | 光标声明上下文 |
TerminalFocusContext.tsx | — | 终端焦点上下文 |
TerminalSizeContext.tsx | — | 终端尺寸上下文 |
5. hooks/ — React Hooks(12 文件)
| 文件 | 行数 | 说明 |
|---|---|---|
use-input.ts | 93 | 键盘输入处理 |
use-app.ts | 8 | 应用上下文访问 |
use-stdin.ts | ~30 | stdin 访问 |
use-selection.ts | ~50 | 选择状态管理 |
use-interval.ts | ~30 | 定时器 Hook |
use-animation-frame.ts | ~40 | 动画帧 Hook |
use-terminal-viewport.ts | ~50 | 终端视口尺寸 |
use-terminal-title.ts | ~30 | 终端标题设置 |
use-terminal-focus.ts | ~30 | 终端焦点追踪 |
use-declared-cursor.ts | ~40 | 声明式光标位置 |
use-tab-status.ts | ~30 | Tab 状态 |
use-search-highlight.ts | ~50 | 搜索高亮 |
09 - query 模块源码分析
路径:
src/query/文件数: 5 个 功能: 查询执行核心 — 与 Claude API 交互的主循环
模块概述
query/ 是 Claude Code 与 AI 模型交互的核心引擎。它管理查询生命周期、token 预算、依赖注入和停止钩子执行。设计上追求纯函数化,便于测试和未来的 step() 提取。
1. config.ts — 查询配置快照
行数: 46 行
功能概述
在 query() 入口点创建不可变的配置快照,将运行时配置与可变状态分离。
导出
QueryConfig类型 — 配置快照结构buildQueryConfig()— 工厂函数
配置结构
type QueryConfig = {
sessionId: SessionId
gates: {
streamingToolExecution: boolean // gate: tengu_streaming_tool_execution2
emitToolUseSummaries: boolean
isAnt: boolean
fastModeEnabled: boolean // 字段名是 fastModeEnabled,不是 fastMode
}
}
构建逻辑
function buildQueryConfig(): QueryConfig {
return {
sessionId: getSessionId(),
gates: {
// Statsig 特性门控(使用缓存值,可能过期)
streamingToolExecution: checkStatsigFeatureGate_CACHED_MAY_BE_STALE('streaming_tool_exec'),
// 环境变量控制
emitToolUseSummaries: isEnvTruthy('EMIT_TOOL_USE_SUMMARIES'),
// 内部用户检测
isAnt: detectIsAnt(),
// 快速模式(内联检测,避免引入重模块图)
fastMode: isFastModeEnabled(),
}
}
}
设计亮点
- 不可变快照: 配置在 query() 入口创建后不再变化,避免中途配置变更导致的不一致
- 刻意排除 feature() 门控: 为了 tree-shaking 优化,不引入
bun:bundle的 feature() 函数 - 内联检测: fastMode 检测内联实现,避免引入 heavy module graph
2. deps.ts — 依赖注入容器
行数: 40 行
功能概述
为 query() 函数提供依赖注入,允许测试时注入 fake 实现而无需 spyOn。
导出
QueryDeps类型 — 依赖接口productionDeps()— 生产环境依赖工厂
依赖接口
type QueryDeps = {
callModel: typeof queryModelWithStreaming // 模型 API 调用
microcompact: typeof microcompactMessages // 消息微压缩
autocompact: typeof autoCompactIfNeeded // 自动压缩
uuid: typeof randomUUID // UUID 生成
}
生产实现
function productionDeps(): QueryDeps {
return {
callModel: queryModelWithStreaming,
microcompact: microcompactMessages,
autocompact: autoCompactIfNeeded,
uuid: randomUUID,
}
}
设计亮点
- typeof 同步: 使用
typeof fn保持签名与真实实现自动同步 - 窄范围: 刻意只注入 4 个依赖,作为模式验证(proof of pattern)
- 无 mock 测试: 测试直接注入 fake 对象,比
jest.spyOn更可靠
3. tokenBudget.ts — Token 预算管理
行数: 93 行
功能概述
追踪 token 使用量,在预算耗尽或收益递减时决定停止查询继续。
导出
BudgetTracker类型 — 预算追踪状态createBudgetTracker()— 创建追踪器TokenBudgetDecision类型 — 决策联合类型checkTokenBudget()— 主决策函数
常量
const COMPLETION_THRESHOLD = 0.9 // 90% 预算使用率阈值
const DIMINISHING_THRESHOLD = 500 // 收益递减阈值(tokens)
决策流程
checkTokenBudget(tracker, currentTokens, budget, agentId)
│
├── agentId 存在? → STOP(子Agent不续传)
├── budget 为 null/0? → STOP
│
├── 计算当前使用百分比
├── 计算自上次检查的 delta
│
├── 检测收益递减:
│ └── 连续 2 次 delta < 500 tokens 且续传次数 ≥ 3
│ → STOP(附带 completion_event)
│
├── 未递减 且 < 90% 预算
│ → CONTINUE(附带 nudge 消息)
│
└── 超过 90% 或递减
→ STOP(附带 completion_event + 指标)
决策类型
type ContinueDecision = {
action: 'continue'
nudgeMessage: string
continuationCount: number
pct: number // 字段名是 pct,不是 percentage
turnTokens: number
budget: number
}
type StopDecision = {
action: 'stop'
completionEvent?: {
totalTokens: number
budget: number
continuations: number
pct: number // 同上
diminishingReturns: boolean
}
}
4. stopHooks.ts — 停止钩子编排器
行数: 474 行
功能概述
在每个查询回合结束时编排停止钩子的执行,管理后台任务(记忆提取、自动推理、提示建议),协调钩子结果。
导出
handleStopHooks()— 异步生成器函数
执行流程
handleStopHooks(context)
│
├── 1. 设置阶段
│ ├── 创建钩子上下文(消息、系统提示、工具上下文)
│ ├── 保存缓存安全参数(仅主会话)
│ └── 运行模板任务分类(如果在 job 模式)
│
├── 2. 后台任务(fire-and-forget,bare 模式跳过)
│ ├── 提示建议执行
│ ├── 记忆提取(如果 extract 模式激活)
│ └── 自动推理(非子Agent)
│
├── 3. Chicago MCP 清理
│ └── 自动取消隐藏 & 释放计算机使用锁
│
├── 4. Stop 钩子执行
│ ├── 通过生成器执行钩子
│ ├── 追踪进度消息、钩子计数、错误
│ ├── 收集阻塞错误
│ ├── 检查续传阻止标志
│ └── 处理中止信号
│
├── 5. 队友特定钩子(如果队友模式)
│ ├── TaskCompleted 钩子(每个进行中的任务)
│ └── TeammateIdle 钩子
│
└── 6. 结果聚合
├── 返回 StopHookResult
│ ├── blockingErrors: Error[]
│ └── preventContinuation: boolean
└── yield件、摘要
钩子类型
| 钩子事件 | 触发时机 | 说明 |
|---|---|---|
Stop | 每个回合结束 | 通用停止钩子 |
TaskCompleted | 任务完成时 | 队友模式专用 |
TeammateIdle | 队友空闲时 | 队友模式专用 |
后台任务
// 提示建议(fire-and-forget)
executePromptSuggestion(context).catch(logError)
// 记忆提取(条件执行)
if (isExtractModeActive()) {
extractMemories(context).catch(logError)
}
// 自动推理(非子Agent)
if (!isSubagent) {
autoDream(context).catch(logError)
}
5. 查询主循环(推断)
虽然 src/query/ 目录包含配置、依赖注入、token 预算和停止钩子,但真正的查询主循环在根级 src/query.ts(1729 行),不需要“推断“。
query(messages, tools, config, deps)
│
├── 构建配置快照 (c
├── 注入依赖 (deps.ts)
├── 创建预算追踪器 (tokenBudget.ts)
│
├── 主循环:
│ ├── 微压缩消息 (deps.microcompact)
│ ├── 自动压缩检查 (deps.autocompact)
│ ├── 调用模型 (deps.callModel) — 流式
│ ├── 处理响应:
│ │ ├── 文本块 → yield 给 UI
│ │ ├── 工具调用 → 执行工具 → 追加结果
│ │ └── 停止信号 → 退出循环
│ ├── 检查 token 预算 (tokenBudget.ts)
│ │ ├── CONTINUE → 继续循环
│ │ └── STOP → 退出循环
│ └── 循环继续...
│
└── 执行停止钩子 (stopHooks.ts)
模块设计哲学
- 纯函数化追求: config 和 deps 的分离是为了将 query() 逐步重构为纯 reducer
- 可测试性优先: 依赖注入而非模块 mock
- 渐进式停止: token 预算不是硬切断,而是通过收益递减检测智能停止
- **生opHooks 使用 async generator,允许调用方逐步消费结果
- 关注点分离: 配置、依赖、预算、钩子各自独立,互不耦合
10 - services 模块源码分析
路径:
src/services/子目录数: 20 个 根级文件数: 15 个 功能: 服务层 — API 调用、分析、压缩、MCP、OAuth 等核心服务
模块概述
services/ 是 Claude Code 的服务层,封装了与外部系统交互的核心逻辑。
重要纠正: 之前文档中列出的 services/permissions/、services/sandbox/ 目录不存在。权限相关实现在 src/utils/permissions/,沙箱相关在 src/utils/sandbox/。
真实目录结构
子目录(20 个)
| 目录 | 说明 |
|---|---|
api/ | Claude API 交互(流式调用、重试、错误处理、用量、会话入口等) |
analytics/ | 分析与遥测(GrowthBook、事件日志、DataDog、指标) |
compact/ | 消息压缩(自动压缩、微压缩、分组、时间策略等) |
mcp/ | MCP 客户端(连接管理、传输层、配置、认证、权限等) |
oauth/ | OAuth 服务 |
tools/ | 工具执行服务(流式工具执行器、工具编排、工具钩子) |
plugins/ | 插件服务 |
lsp/ | LSP 集成(Language Server Protocol) |
policyLimits/ | 策略限制(组织级使用限制) |
remoteManagedSettings/ | 远程托管设置 |
settingsSync/ | 设置同步 |
teamMemorySync/ | 团队记忆同步 |
tips/ | 使用提示系统 |
toolUseSummary/ | 工具使用摘要 |
AgentSummary/ | Agent 执行结果摘要 |
MagicDocs/ | 魔法文档(自动文档生成) |
PromptSuggestion/ | 提示建议(主动建议下一步) |
SessionMemory/ | 会话记忆(跨回合上下文保持) |
autoDream/ | 自动推理(后台记忆整合) |
extractMemories/ | 记忆提取(从对话中提取值得记忆的信息) |
根级文件(15 个)
| 文件 | 说明 |
|---|---|
awaySummary.ts | 离开摘要 |
claudeAiLimits.ts | claude.ai 使用限制 |
claudeAiLimitsHook.ts | 限制 Hook |
diagnosticTracking.ts | 诊断追踪 |
internalLogging.ts | 内部日志 |
mockRateLimits.ts | 模拟速率限制 |
notifier.ts | 通知器 |
preventSleep.ts | 防止休眠 |
rateLimitMessages.ts | 速率限制消息 |
rateLimitMocking.ts | 速率限制模拟 |
tokenEstimation.ts | Token 估算 |
vcr.ts | VCR 录制/回放 |
voice.ts | 语音服务 |
voiceKeyterms.ts | 语音关键词 |
voiceStreamSTT.ts | 语音流式 STT |
核心服务详解
1. api/ — Claude API 交互
文件数: 20 个
| 文件 | 说明 |
|---|---|
claude.ts | 主 API 调用(流式) |
client.ts | API 客户端 |
bootstrap.ts | API 启动初始化 |
withRetry.ts | 重试策略 |
errors.ts | 错误类型定义 |
errorUtils.ts | 错误处理工具 |
usage.ts | 用量追踪 |
logging.ts | API 日志 |
sessionIngress.ts | 会话入口 |
filesApi.ts | 文件 API |
grove.ts | Grove 集成 |
adminRequests.ts | 管理请求 |
dumpPrompts.ts | 提示转储(调试) |
emptyUsage.ts | 空用量对象 |
firstTokenDate.ts | 首 token 时间 |
metricsOptOut.ts | 指标退出 |
overageCreditGrant.ts | 超额信用 |
promptCacheBreakDetection.ts | 提示缓存破坏检测 |
referral.ts | 推荐系统 |
ultrareviewQuota.ts | Ultrareview 配额 |
注意:之前文档中写的 models.ts、rateLimit.ts、headers.ts 在此目录中不存在。
2. analytics/ — 分析与遥测
文件数: 9 个
| 文件 | 说明 |
|---|---|
index.ts | 事件日志主入口 |
growthbook.ts | GrowthBook 特性门控 |
config.ts | 分析配置 |
datadog.ts | DataDog 集成 |
metadata.ts | 事件元数据 |
sink.ts | 事件接收器 |
sinkKillswitch.ts | 接收器 kill-switch |
firstPartyEventLogger.ts | 第一方事件日志 |
firstPartyEventLoggingExporter.ts | 第一方事件导出 |
注意:之前文档中写的 statsig.ts、otel.ts、events.ts 在此目录中不存在。
3. compact/ — 消息压缩
文件数: 11 个
| 文件 | 说明 |
|---|---|
autoCompact.ts | 自动压缩(上下文窗口管理) |
microCompact.ts | 微压缩(截断过长工具结果) |
apiMicrocompact.ts | API 级微压缩 |
compact.ts | 压缩核心逻辑 |
prompt.ts | 压缩提示词 |
grouping.ts | 消息分组 |
sessionMemoryCompact.ts | 会话记忆压缩 |
timeBasedMCConfig.ts | 基于时间的微压缩配置 |
compactWarningHook.ts | 压缩警告钩子 |
compactWarningState.ts | 压缩警告状态 |
postCompactCleanup.ts | 压缩后清理 |
4. mcp/ — MCP 客户端
文件数: 22 个
| 文件 | 说明 |
|---|---|
client.ts | MCP 客户端实现 |
config.ts | MCP 配置 |
types.ts | MCP 类型定义 |
auth.ts | MCP 认证 |
MCPConnectionManager.tsx | 连接管理器(React 组件) |
InProcessTransport.ts | 进程内传输 |
SdkControlTransport.ts | SDK 控制传输 |
channelAllowlist.ts | 频道白名单 |
channelPermissions.ts | 频道权限 |
channelNotification.ts | 频道通知 |
elicitationHandler.ts | 引出处理器 |
envExpansion.ts | 环境变量展开 |
normalization.ts | 规范化 |
officialRegistry.ts | 官方注册表 |
utils.ts | MCP 工具函数 |
xaa.ts / xaaIdpLogin.ts | XAA 认证 |
claudeai.ts | claude.ai 集成 |
oauthPort.ts | OAuth 端口 |
headersHelper.ts | 请求头辅助 |
mcpStringUtils.ts | 字符串工具 |
vscodeSdkMcp.ts | VS Code SDK MCP |
useManageMCPConnections.ts | 连接管理 Hook |
注意:之前文档中写的 discovery.ts、transport.ts 在此目录中不存在。
5. tools/ — 工具执行服务
文件数: 4 个
| 文件 | 说明 |
|---|---|
StreamingToolExecutor.ts | 流式工具执行器 |
toolExecution.ts | 工具执行核心 |
toolOrchestration.ts | 工具编排 |
toolHooks.ts | 工具钩子集成 |
不存在的目录(之前文档错误)
以下目录在 src/sces/ 中不存在:
→ 实际在services/permissions/src/utils/permissions/→ 实际在services/sandbox/src/utils/sandbox/
设计亮点
- 流式优先: API 调用使用 AsyncGenerator 实现流式处理
- 多层压缩: 自动压缩(LLM 摘要)+ 微压缩(截断)+ 基于时间的策略
- GrowthBook 门控: 特性标志控制渐进式发布
- MCP 标准: 完整实现 MCP 协议,22 个文件覆盖连接、认证、权限、传输
- 工具编排: 独立的工具执行服务层,支持流式执行和钩子集成
services 模块 — 20 个服务子目录
路径:
src/services/子目录数: 20 个
服务清单
核心服务
| 目录 | 说明 |
|---|---|
api/ | Claude API 交互(流式调用、模型选择、重试、速率限制、请求头) |
analytics/ | 分析与遥测(GrowthBook + Statsig 双门控、OpenTelemetry、事件日志) |
compact/ | 消息压缩(自动压缩 LLM 摘要 + 微压缩截断) |
oauth/ | OAuth 服务(令牌管理、刷新、存储) |
mcp/ | MCP 客户端(服务器发现、连接、工具调用、资源读取) |
AI 增强服务
| 目录 | 说明 |
|---|---|
autoDream/ | 自动推理(后台记忆整合) |
extractMemories/ | 记忆提取(从对话中提取值得记忆的信息) |
SessionMemory/ | 会话记忆(跨回合的上下文保持) |
AgentSummary/ | Agent 摘要(子 Agent 执行结果摘要) |
PromptSuggestion/ | 提示建议(主动建议下一步操作) |
MagicDocs/ | 魔法文档(自动生成文档) |
工具与权限服务
| 目录 | 说明 |
|---|---|
tools/ | 工具服务(工具注册、发现、执行协调) |
toolUseSummary/ | 工具使用摘要(生成工具调用的摘要) |
plugins/ | 插件服务(插件加载、验证、生命周期) |
配置与策略服务
| 目录 | 说明 |
|---|---|
policyLimits/ | 策略限制(组织级别的使用限制) |
remoteManagedSettings/ | 远程托管设置(从服务器同步配置) |
settingsSync/ | 设置同步(跨设备设置同步) |
teamMemorySync/ | 团队记忆同步(团队共享记忆的同步) |
其他服务
| 目录 | 说明 |
|---|---|
lsp/ | LSP 集成(Language Server Protocol,代码智能) |
tips/ | 提示系统(使用技巧和建议) |
11 - tools 模块源码分析
路径:
src/tools/功能: AI 工具实现 — Claude 可调用的所有工具
模块概述
tools/ 包含 Claude Code 中 AI 可以调用的所有工具实现。每个工具通过 buildTool(def) 工厂函数构建(不是类继承),接收 ToolDef 对象定义,返回 BuiltTool。
工具清单
文件操作工具
| 工具 | 功能 | 只读 | 破坏性 |
|---|---|---|---|
Read | 读取文件内容 | ✅ | ❌ |
Write | 创建/覆写文件 | ❌ | ✅ |
Edit | 精确字符串替换编辑 | ❌ | ❌ |
NotebookEdit | Jupyter Notebook 编辑 | ❌ | ❌ |
Glob | 文件模式匹配搜索 | ✅ | ❌ |
Grep | 文件内容正则搜索 | ✅ | ❌ |
系统操作工具
| 工具 | 功能 | 只读 | 破坏性 |
|---|---|---|---|
Bash | 执行 Shell 命令 | ❌ | ✅ |
Agent | 启动子 Agent | ❌ | ❌ |
网络工具
| 工具 | 功能 | 只读 | 破坏性 |
|---|---|---|---|
WebFetch | 获取网页内容 | ✅ | ❌ |
WebSearch | 网页搜索 | ✅ | ❌ |
任务管理工具
| 工具 | 功能 | 只读 | 破坏性 |
|---|---|---|---|
TodoWrite | 写入任务列表 | ❌ | ❌ |
注意:TodoReadTool 目录不存在,只有 TodoWriteTool。
特殊工具
| 工具 | 功能 |
|---|---|
AskUser | 向用户提问 |
EnterPlanMode | 进入计划模式 |
ExitPlanMode | 退出计划模式 |
Skill | 调用技能 |
CronCreate | 创建定时任务 |
CronDelete | 删除定时任务 |
CronList | 列出定时任务 |
EnterWorktree | 进入 Git Worktree |
ExitWorktree | 退出 Git Worktree |
RemoteTrigger | 远程触发器 |
核心工具详解
1. Bash — Shell 命令执行
权限检查
needsPermission: (input) => {
const { command } = input
// 检查是否匹配自动允许规则
if (matchesAllowRule(command)) return false
// 检查是否是只读命令
if (isReadOnlyCommand(command)) return false
// 默认需要权限
return true
}
执行逻辑
execute: async (input, context) => {
const { command, timeout } = input
// 1. 创建子进程
const proc = spawn('sh', ['-c', command], {
cwd: context.cwd,
timeout: timeout || 120000, // 默认 2 分钟超时
env: { ...process.env, ...context.env },
})
// 2. 收集输出
let stdout = '', stderr = ''
proc.stdout.on('data', (d) => stdout += d)
proc.stderr.on('data', (d) => stderr += d)
// 3. 等待完成
const exitCode = await waitForExit(proc)
// 4. 截断过长输出
return { stdout: truncate(stdout), stderr: truncate(stderr), exitCode }
}
安全特性
- 命令白名单/黑名单
- 超时控制(默认 120 秒)
- 输出长度限制
- 沙箱环境支持
- 网络访问控制
2. Read — 文件读取
功能特性
- 支持文本文件、图片、PDF、Jupyter Notebook
- 行号显示(cat -n 格式)
- 支持 offset/limit 分页读取
- 支持 PDF 页码范围
- 图片以多模态内容返回
execute: async (input) => {
const { file_path, offset, limit, pages } = input
// 检测文件类型
if (isImage(file_path)) {
return { type: 'image',ait readFileAsBase64(file_path) }
}
if (isPDF(file_path)) {
return { type: 'text', content: await extractPDFText(file_path, pages) }
}
if (isNotebook(file_path)) {
return { type: 'text', content: await renderNotebook(file_path) }
}
// 文本文件
const content = await readFileWithLineNumbers(file_path, offset, limit)
return { type: 'text', content }
}
3. Edit — 精确编辑
核心逻辑
execute: async (input) => {
const { file_path, old_string, new_string, replace_all } = input
// 1. 读取文件
const content = await readFile(file_path, 'utf-8')
// 2. 查找 old_string
if (!content.includes(old_string)) {
throw new Error('old_string not found in file')
}
// 3. 检查唯一性(除非 replace_all)
if (!replace_all) {
const count = countOccurrences(content, old_string)
if (count > 1) {
throw new Error('old_string is not unique, provide more context')
}
}
// 4. 执行替换
const newContent = replace_all
? content.replaceAll(old_string, new_string)
: content.replace(old_string, new_string)
// 5. 写入文件
await writeFile(file_path, newContent)
return { success: true }
}
安全特性
- 要求先 Read 再 Edit(防止盲改)
- old_string 唯一性检查
- 保留原始缩进
4. Agent — 子 Agent 启动
execute: async (input, context) => {
const { prompt, subagent_type, model, isolation } = input
// 1. 选择 Agent 类型
const agentConfig = resolveAgentType(subagent_type)
// 2. 创建隔离环境(可选)
let workDir = context.cwd
if (isolation === 'worktree') {
workDir = await createGitWorktree()
}
// 3. 启动子 Agent
const agent = await spawnAgent({
prompt,
model: model || agentConfig.model,
tools: agentConfig.tools,
cwd: workDir,
parentSessionId: context.sessionId,
})
// 4. 等待完成
const result = await agent.waitForCompletion()
sult
}
Agent 类型
general-purpose— 通用 AgentExplore— 代码探索 Agent(只读)Plan— 计划 Agent(只读)claude-code-guide— 使用指南 Agent
5. Glob — 文件模式匹配
execute: async (input) => {
const { pattern, path } = input
// 使用 fast-glob 进行文件搜索
const files = await glob(pattern, {
cwd: path || process.cwd(),
ignore: ['node_modules/**', '.git/**'],
onlyFiles: true,
})
// 按修改时间排序
return files.sort((a, b) => b.mtime - a.mtime)
}
6. Grep — 内容搜索
exee: async (input) => {
const { pattern, path, glob: fileGlob, output_mode } = input
// 使用 ripgrep 进行搜索
const results = await ripgrep(pattern, {
path: path || process.cwd(),
glob: fileGlob,
maxResults: input.head_limit || 250,
})
switch (output_mode) {
case 'content': return formatContentResults(results)
case 'files_with_matches': return formatFileResults(results)
case 'count': return formatCountResults(results)
}
}
工具注册流程
// tools.ts — 工具注册入口
function registerAllTools(): Tool[] {
return [
buildBashTool(),
buildReadTool(),
buildWriteTool(),
buiol(),
buildGlobTool(),
buildGrepTool(),
buildAgentTool(),
buildWebFetchTool(),
buildWebSearchTool(),
buildTodoReadTool(),
buildTodoWriteTool(),
buildAskUserTool(),
// ... 更多工具
// MCP 工具动态注册
...await discoverMCPTools(),
]
}
设计亮点
- Builder 模式: 统一的工具构建接口,安全默认值
- 权限分层: 只读/非破坏性/破坏性三级权限
- MCP 扩展: 通过 MCP 协议动态发现和注册第三方工具
- 输出控制: 所有工具输出都有长度限制,防止上下文溢出
- 沙箱支持: 工具可在沙箱环境中受限执行
tools 模块 — 42 个工具子目录完整清单
路径:
src/tools/每个工具一个独立目录
文件操作工具
| 工具目录 | 行数 | 功能 | 权限 |
|---|---|---|---|
FileReadTool/ | 1184 | 读取文件(文本/图片/PDF/Notebook),支持分页、去重、图片压缩 | 只读 |
FileWriteTool/ | 435 | 创建/覆写文件,强制 LF 换行,过期检查,LSP 通知 | 破坏性 |
FileEditTool/ | 626 | 精确字符串替换编辑,唯一性检查,1GiB 上限,技能发现 | 破坏性 |
NotebookEditTool/ | ~200 | Jupyter Notebook 单元格编辑 | 破坏性 |
GlobTool/ | 199 | 文件模式匹配搜索,100 结果上限,路径相对化 | 只读 |
GrepTool/ | 578 | ripgrep 内容搜索,250 默认上限,分页支持 | 只读 |
系统操作工具
| 工具目录 | 行数 | 功能 | 权限 |
|---|---|---|---|
BashTool/ | ~800 | Shell 命令执行,120s 超时,输出截断,沙箱支持 | 破坏性 |
PowerShellTool/ | ~300 | PowerShell 命令执行(Windows) | 破坏性 |
AgentTool/ | ~500 | 启动子 Agent(general/Explore/Plan/guide),worktree 隔离 | 非破坏性 |
REPLTool/ | ~200 | 交互式 REPL 工具 | 非破坏性 |
SleepTool/ | ~50 | 等待指定时间 | 只读 |
网络工具
| 工具目录 | 行数 | 功能 | 权限 |
|---|---|---|---|
WebFetchTool/ | ~400 | 获取网页内容,HTML→Markdown 转换,15 分钟缓存 | 只读 |
WebSearchTool/ | ~300 | 网页搜索 | 只读 |
任务管理工具
| 工具目录 | 行数 | 功能 | 权限 |
|---|---|---|---|
TaskCreateTool/ | ~150 | 创建任务 | 非破坏性 |
TaskGetTool/ | ~80 | 获取任务详情 | 只读 |
TaskListTool/ | ~80 | 列出所有任务 | 只读 |
TaskUpdateTool/ | ~150 | 更新任务状态/内容 | 非破坏性 |
TaskOutputTool/ | ~100 | 获取任务输出 | 只读 |
TaskStopTool/ | ~80 | 停止运行中的任务 | 非破坏性 |
TodoWriteTool/ | ~150 | 写入待办列表 | 非破坏性 |
计划模式工具
| 工具目录 | 行数 | 功能 | 权限 |
|---|---|---|---|
EnterPlanModeTool/ | 127 | 进入计划模式,激活分类器 | 只读 |
ExitPlanModeTool/ | 494 | 退出计划模式,呈现计划供审批,队友邮箱审批 | 破坏性 |
Worktree 工具
| 工具目录 | 行数 | 功能 | 权限 |
|---|---|---|---|
EnterWorktreeTool/ | 128 | 创建隔离 git worktree,验证 slug 格式 | 破坏性 |
ExitWorktreeTool/ | 330 | 退出 worktree(keep/remove),统计未提交变更 | 破坏性 |
MCP 工具
| 工具目录 | 行数 | 功能 | 权限 |
|---|---|---|---|
MCPTool/ | ~300 | 调用 MCP 服务器工具 | 动态 |
ListMcpResourcesTool/ | 124 | 列出 MCP 资源,LRU 缓存 | 只读 |
ReadMcpResourceTool/ | ~100 | 读取 MCP 资源 | 只读 |
McpAuthTool/ | ~150 | MCP 认证处理 | 非破坏性 |
通信工具
| 工具目录 | 行数 | 功能 | 权限 |
|---|---|---|---|
AskUserQuestionTool/ | ~200 | 向用户提问(多选/单选/预览) | 只读 |
SendMessageTool/ | ~150 | 发送消息给其他 Agent | 非破坏性 |
BriefTool/ | 205 | 发送消息给用户(助手模式主输出通道) | 只读 |
配置工具
| 工具目录 | 行数 | 功能 | 权限 |
|---|---|---|---|
ConfigTool/ | 468 | 获取/设置 Claude Code 配置,支持点号嵌套 | 动态 |
SkillTool/ | ~200 | 调用技能 | 非破坏性 |
定时任务工具
| 工具目录 | 行数 | 功能 | 权限 |
|---|---|---|---|
ScheduleCronTool/ | ~200 | 创建/删除/列出定时任务 | 非破坏性 |
RemoteTriggerTool/ | ~150 | 远程触发器管理 | 非破坏性 |
团队工具
| 工具目录 | 功能 | 权限 |
|–––––|——|——|——|
| TeamCreateTool/ | ~200 | 创建团队(Swarm 模式) | 非破坏性 |
| TeamDeleteTool/ | ~100 | 删除团队 | 破坏性 |
代码智能工具
| 工具目录 | 行数 | 功能 | 权限 |
|---|---|---|---|
LSPTool/ | 861 | 代码智能(定义跳转/引用/符号/悬停),10MB 上限 | 只读 |
ToolSearchTool/ | ~100 | 搜索可用工具 | 只读 |
其他
| 工具目录 | 行数 | 功能 | 权限 |
|---|---|---|---|
SyntheticOutputTool/ | ~100 | 合成输出(内部用) | 只读 |
shared/ | — | 工具间共享代码 | |
testing/ | — | 测试工具 |
12 - skills 模块源码分析
路径:
src/skills/文件数: 20 个 功能: 技能系统 — 可扩展的斜杠命令(/batch, /simplify, /debug 等)
注意:/commit 和 /review 不是 bundled skill,而是 src/commands/ 中的独立命令。
模块概述
skills/ 实现了 Claude Code 的技能系统,即用户通过 /命令名 调用的预定义工作流。技能可以来自内置捆绑、用户自定义目录、插件或 MCP 提供者。
核心基础设施
1. bundledSkills.ts — 内置技能注册表
行数: 221 行
功能概述
内置技能的核心注册表,管理随 CLI 一起发布的技能。
导出
registerBundledSkill(def)— 注册内置技能getBundledSkills()— 获取所有内置技能clearBundledSkills()— 清空(测试用)getBundledSkillExtractDir()— 获取技能文件提取目录BundledSkillDefinition类型
注册流程
// 源码 src/skills/bundledSkills.ts:15-40
export type BundledSkillDefinition = {
name: string
description: string
aliases?: string[]
whenToUse?: string
argumentHint?: string
allowedTools?: string[]
model?: string
disableModelInvocation?: boolean
userInvocable?: boolean
isEnabled?: () => boolean
hooks?: HooksSettings
context?: 'inline' | 'fork'
agent?: string
files?: Record<string, string> // 参考文件(懒提取到磁盘)
getPromptForCommand: (args: string, context: ToolUseContext) => Promise<ContentBlockParam[]>
}
安全文件提取
// 懒提取技能文件到临时目录
// 使用 O_NOFOLLOW | O_EXCL 防止符号链接攻击
// Memoize 提取 Promise 避免重复提取
async function extractSkillFile(relativePath: string): Promise<string> {
const targetPath = join(extractDir, relativePath)
// 验证相对路径防止目录遍历
if (relativePath.includes('..')) throw new Error('Path traversal detected')
const fd = await open(targetPath, O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW)
// ...
}
2. loadSkillsDir.ts — 技能目录发现与加载
行数: 1087 行(最大的技能文件)
功能概述
从 .skills/ 目录发现和加载用户自定义技能,解析 SKILL.md frontmatter,创建 Command 对象。
导出
getSkillDirCommands()— 获取目录技能命令loadSkillsFromSkillsDir()— 从目录加载技能createSkillCommand()— 创建技能命令parseSkillFrontmatterFields()— 解析 frontmatterdiscoverSkillDirsForPaths()— 发现技能目录addSkillDirectories()— 添加技能目录activateConditionalSkillsForPaths()— 激活条件技能getDynamicSkills()— 获取动态技能clearSkillCaches()— 清空缓存
SKILL.md 格式
---
name: my-skill
description: 我的自定义技能
model: claude-sonnet-4-6
allowed-tools: [Bash, Read, Write]
user-invocable: true
condition: "src/**/*.ts"
---
这里是技能的提示词内容...
发现流程
项目根目录
├── .skills/ ← 项目级技能
│ ├── commit/
│ │ └── SKILL.md
│ └── review/
│ └── SKILL.md
│
├── ~/.claude/skills/ ← 用户级技能
│ └── my-skill/
│ └── SKILL.md
│
└── 插件提供的技能目录
条件技能
// 条件技能只在匹配的文件路径下激活
// 使用 minimatch 进行 glob 匹配
activateConditionalSkillsForPaths(paths: string[]) {
for (const skill of conditionalSkills) {
if (paths.some(p => minimatch(p, skill.condition))) {
activateSkill(skill)
}
}
}
去重机制
- 使用
realpath()解析符号链接后去重 - 缓存已发现的技能目录
- 遵守
.gitignore规则过滤
3. mcpSkillBuilders.ts — MCP 技能构建器注入
行数: 45 行
功能概述
依赖注入注册表,打破 MCP 技能发现与技能加载之间的循环依赖。
type MCPSkillBuilders = {
createSkillCommand: typeof createSkillCommand
parseSkillFrontmatterFields: typeof parseSkillFrontmatterFields
}
// 写入一次,之后只读
let builders: MCPSkillBuilders | undefined
function registerMCPSkillBuilders(b: MillBuilders): void {
builders = b
}
function getMCPSkillBuilders(): MCPSkillBuilders {
if (!builders) throw new Error('MCP skill builders not registered')
return builders
}
内置技能详解
4. bundled/index.ts — 初始化入口
行数: 80 行
调用所有内置技能的注册函数:
function initBundledSkills(): void {
registerClaudeApiSkill()
registerBatchSkill()
registerDebugSkill()
registerSimplifySkill()
registerKeybindingsSkill()
registerRememberSkill()
registerUpdateConfigSkill()
registerSkillifySkill()
registerVerifySkill()
registerStuckSkill()
registerLoremIpsumSkill()
registerClaudeInChromeSkill()
// ... 受 feature flag 控制的技能
}
5. bundled/batch.ts — 批量并行执行
行数: 125 行
功能
编排大规模并行代码变更,在隔离的 git worktree 中生成 5-30 个 Agent。
工作流
/batch "将所有 console.log 替换为 logger.info"
↓
分析变更范围
↓
创建 5-30 个 git worktree
↓
每个 worktree 中启动独立 Agent
↓
Agent 并行执行变更
↓
收集结果,合并到主分支
6. bundled/claudeApi.ts — Claude API 开发辅助
行数: 197 行
功能
帮助用户构建使用 Claude API 的应用,自动检测项目语言并提供对应示例。
function registerClaudeApiSkill(): void {
// 检测项目语言
const language = detectProjectLanguage() // TypeScript | Python | other
// 懒加载 247KB 文档包
const docs = await loadDocBundle(language)
registerBundledSkill({
name: 'claude-api',
description: 'Build apps with the Claude API',
prompt: SKILL_PROMPT,
referenceFiles: SKILL_FILES[language],
})
}
7. bundled/simplify.ts — 代码审查与简化
行数: 70 行
功能
三阶段代码审查工作流,启动三个并行审查 Agent。
/simplify
↓
Phase 1: git diff 识别变更
↓
Phase 2: 启动 3 个并行 Agent
├── Agent 1: 代码复用审查
├── Agent 2: 代码质量审查
└── Agent 3: 效率审查
↓
Phase 3: 聚合发现,修复问题
8. bundled/updateConfig.ts — 配置管理
行数: 476 行
功能
settings.json 配置管理技能,动态生成 JSON Schema 文档。
特性
- 从 Zod SettingsSchema 动态生成 JSON Schema
- 文档化三层配置系统(user/project/local)
- 完整的 hooks 文档(所有事件类型和钩子类型)
- 强调“先读后写“模式
9. bundled/keybindings.ts — 快捷键自定义
行数: 340 行
功能
生成快捷键系统的完整文档,包括默认绑定、保留键和自定义格式。
10. bundled/remember.ts — 记忆管理
行数: 83 行(仅内部用户可用)
工作流
/remember
↓
Step 1: 收集记忆层
├── CLAUDE.md
├── CLAUDE.local.md
├── 自动记忆
└── 团队记忆
↓
Step 2: 按目标分类条目
↓
Step 3: 识别清理机会(重复/过期/冲突)
↓
Step 4: 呈现结构化报告,等待用户批准
11. bundleskillify.ts — 工作流捕获
行数: 197 行(仅内部用户可用)
功能
将当前会话的工作流捕获为可复用的技能文件。
/skillify
↓
提取会话中的用户消息
↓
四轮访谈:
1. 高层确认
2. 细节补充
3. 步骤分解
4. 最终问题
↓
生成 SKILL.md(含 frontmatter)
↓
预览 → 用户确认 → 保存
12. bundled/debug.ts — 调试日志
行数: 104 行
// 启用调试日志
enableDebugLogging()
// 读取最后 100 行日志
const logs = await readLastLines(getDebugLogPath(), 100)
// 提供日志路径
console.log(`Debug log: ${getDebugLogPath()}`)
13. bundled/loremIpsum.ts — 长文本生成
行数: 283 行(仅内部用户可用)
功能
生成填充文本用于长上下文测试。
- 使用 200 个经过验证的单 token 词汇
- 句子长度 10-20 词
- 随机段落分隔
- 上限 500k n- 输入验证
14. bundled/stuck.ts — 卡住诊断
行数: 80 行(仅内部用户可用)
功能
诊断冻结/缓慢的 Claude Code 会话。
- 调查机器上的其他 Claude Code 进程
- 识别卡住迹象(高 CPU、D/T/Z 进程状态、高 RSS)
- 收集诊断上下文
- 仅诊断,不杀进程
15. bundled/verify.ts — 变更验证
行数: 31 行(仅内部用户可用)
通过运行应用来验证代码变更。
内容包文件
claudeApiContent.ts (76 行)
在构建时内联 markdown 文档,提供模型变量、技能提示和参考文件。
verifyContent.ts (14 行)
在构建时内联 SKILL.md 和示例文件。
架构总结
skills/
├── 基础设施
│ ├── bundledSkills.ts ← 内置技能注册表
│ ├── loadSkillsDir.ts ← 目录技能发现
│ └── mcpSkillBuilders.ts ← DI 打破循环依赖
│
├── 初始化
│ └── bundled/inde ← 统一初始化入口
│
├── 开发工具技能
│ ├── claudeApi.ts ← API 开发辅助
│ ├── claudeInChrome.ts ← Chrome 自动化
│ ├── batch.ts ← 批量并行执行
│ ├── debug.ts ← 调试日志
│ └── simplify.ts ← 代码审查
│
├── 配置技能
│ ├── updateConfig.ts ← settings.json 管理
│ └── keybindings.ts ← 快捷键自定义
│
├── 记忆/工作流技能
│ ├── remember.ts ← 记忆管理
│ └── skillify.ts ← 工作流捕获
│
├── 诊断技能
│ ├── stuck.ts ← 卡住诊断
│ ├── verify.ts ← 变更验证
│ └── loremIp ← 长文本测试
│
└── 内容包
├── claudeApiContent.ts ← API 文档包
└── verifyContent.ts ← 验证文档包
13 - plugins 模块源码分析
路径:
src/plugins/文件数: 2 个 功能: 插件系统 — 内置插件注册与管理
模块概述
plugins/ 是一个相对精简的模块,提供内置插件的注册表和初始化入口。插件的安装/卸载等生命周期管理在 cli/handlers/plugins.ts 中实现。
1. builtinPlugins.ts — 内置插件注册表
行数: 160 行
导出
registerBuiltinPlugin(def)— 注册内置插件getBuiltinPlugins()— 获取所有内置插件(按用户设置过滤)getBuiltinPluginSkillCommands()— 获取插件提供的技能命令isBuiltinPluginId(id)— 检查是否为内置插件 IDclearBuiltinPlugins()— 清空注册表(测试用)BuiltinPluginDefinition类型
核心逻辑
// 返回 enabled/disabled 两个数组,不是单个过滤后的数组
export function getBuiltinPlugins(): {
enabled: LoadedPlugin[]
disabled: LoadedPlugin[]
}
内置插件可以携带 skills、hooks、mcpServers,ID 采用 {name}@builtin 格式。
2. bundled/index.ts — 初始化入口
行数: 24 行
功能
空的初始化函数,作为未来插件系统扩展的占位符。
export function initBuiltinPlugins(): void {
// 未来在此注册内置插件
// 当前为空实现
}
插件系统全景
虽然 plugins/ 模块本身很小,但插件系统涉及多个模块的协作:
插件系统全景
├── plugins/ ← 插件注册表(本模块)
│ ├── builtinPlugins.ts ← 内置插件定义
│ └── bundled/index.ts ← 初始化入口
│
├── cli/handlers/plugins.ts ← 插件生命周期管理
│ ├── install / uninstall
│ ├── enable / disable
│ ├── update
│ └── marketplace 操作
│
├── schemas/ ← 插件配置 Schema
│ └── plugins.ts ← Zod 验证
│
├── skills/ ← 插件提供的技能
│ └── loadSkillsDir.ts ← 从插件目录加载技能
│
└── settings.json ← 插件启用/禁用配置
└── disabledPlugins: []
插件作用域
~/.claude/plugins/ ← 用户级插件(全局)
.claude/plugins/ ← 项目级插件
本地路径引用 ← 本地插件
14 - hooks 模块源码分析
路径:
src/hooks/(React UI hooks)+src/utils/hooks/(钩子执行引擎) 功能: 钩子系统 — 工具生命周期事件的拦截与扩展
重要说明:两个目录的区别
| 目录 | 内容 | 文件数 |
|---|---|---|
src/hooks/ | React UI hooks(useArrowKeyHistory、useCanUseTool、useGlobalKeybindings 等) | 85+ |
src/utils/hooks/ | 钩子执行引擎(execPromptHook、execHttpHook、execAgentHook 等) | 17 |
文档以下内容描述的是 src/utils/hooks/ 中的钩子执行系统,不是 src/hooks/ 中的 React hooks。
src/hooks/ — React UI Hooks(85+ 文件)
这些是标准的 React hooks,用于 UI 状态管理,与钩子执行系统无关:
src/hooks/
├── useArrowKeyHistory.tsx # 箭头键历史导航
├── useCanUseTool.tsx # 工具可用性检查
├── useGlobalKeybindings.tsx # 全局快捷键
├── useReplBridge.tsx # REPL 桥接
├── useVoice.ts # 语音模式
├── useCommandQueue.ts # 命令队列
├── useDiffData.ts # Diff 数据
├── useExitOnCtrlCD.ts # Ctrl+C/D 退出
├── useDynamicConfig.ts # 动态配置
├── notifs/ # 通知相关 hooks
├── toolPermission/ # 工具权限相关 hooks
└── ... 80+ 其他 React hooks
src/utils/hooks/ — 钩子执行引擎(17 文件)
这才是真正的钩子配置与执行系统:
src/utils/hooks/
├── AsyncHookRegistry.ts # 异步钩子注册表与生命周期管理
├── sessionHooks.ts # 会话级钩子注册
├── hookEvents.ts # 钩子事件发射系统
├── hookHelpers.ts # 钩子辅助函数
├── hooksConfigManager.ts # 钩子配置管理
├── hooksConfigSnapshot.ts # 钩子配置快照
├── hooksSettings.ts # 钩子设置验证
├── execAgentHook.ts # Agent 钩子执行器
├── execHttpHook.ts # HTTP Webhook 执行器
├── execPromptHook.ts # LLM 提示钩子执行器
├── apiQueryHookHelper.ts # API 查询钩子辅助
├── postSamplingHooks.ts # 采样后钩子
├── registerFrontmatterHooks.ts # Frontmatter 钩子注册
├── registerSkillHooks.ts # 技能钩子注册
├── skillImprovement.ts # 技能改进
├── fileChangedWatcher.ts # 文件变更监听
└── ssrfGuard.ts # SSRF 防护(HTTP 钩子安全)
钩子事件类型(28 个)
源码 src/entrypoints/sdk/coreTypes.ts:25-53:
| 事件 | 说明 |
|---|---|
PreToolUse | 工具执行前,可阻止执行 |
PostToolUse | 工具执行后,可检查结果 |
PostToolUseFailure | 工具执行失败后 |
Notification | 通知发送时 |
UserPromptSubmit | 用户提交提示时 |
SessionStart | 会话开始 |
SessionEnd | 会话结束 |
Stop | 回合结束时,可阻止结束 |
StopFailure | 停止失败时 |
SubagentStart | 子 Agent 启动时 |
SubagentStop | 子 Agent 停止时 |
PreCompact | 消息压缩前 |
PostCompact | 消息压缩后 |
PermissionRequest | 权限请求时 |
PermissionDenied | 权限被拒绝时 |
Setup | 初始化设置时 |
TeammateIdle | 队友空闲时 |
TaskCreated | TaskCompleted |
Elicitation | 引出(向用户提问)时 |
ElicitationResult | 引出结果返回时 |
ConfigChange | 配置变更时 |
WorktreeCreate | Worktree 创建时 |
WorktreeRemove | Worktree 移除时 |
InstructionsLoaded | 指令加载完成时 |
CwdChanged | 工作目录变更时 |
FileChanged | 文件变更时 |
钩子类型(4 种)
1. Shell 命令钩子 (command)
{
"type": "command",
"command": "npm test",
"shell": "bash",
"timeout": 30000,
"if": "Bash(npm *)"
}
执行器: src/utils/hooks/ 中通过 shell 子进程执行
2. LLM 提示钩子 (prompt)
{
"type": "prompt",
"prompt": "检查这个代码变更是否安全",
"model": "claude-haiku-4-5",
"timeout": 60000
}
执行器: src/utils/hooks/execPromptHook.ts
3. HTTP Webhook 钩子 (http)
{
"type": "http",
"url": "https://api.example.com/hook",
"headers": { "Authorization": "Bearer $TOKEN" },
"timeout": 10000
}
执行器: src/utils/hooks/execHttpHook.ts(含 ssrfGuard.ts SSRF 防护)
4. Agent 验证器钩子 (agent)
{
"type": "agent",
"prompt": "验证代码变更符合团队规范",
"model": "claude-sonnet-4-6",
"timeout": 120000
}
执行器: src/utils/hooks/execAgentHook.ts
钩子配置格式
// settings.json
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash(*)",
"hooks": [
{
"type": "command",
"command": "echo '即将执行: $TOOL_INPUT'",
"timeout": 5000
}
]
}
],
"PostToolUse": [
{
"matcher": "Write(*)",
"hooks": [
{
"type": "command",
"command": "eslint --fix $FILE_PATH",
"timeout": 30000
}
]
}
],
"Stop": [
{
"hooks": [
{
: "prompt",
"prompt": "总结本次对话的关键变更"
}
]
}
]
}
}
钩子执行流程
工具调用请求
↓
PreToolUse 钩子 (src/utils/hooks/)
├── matcher 匹配检查
├── if 条件检查
├── 执行钩子(并行)
├── 收集结果
│ ├── 阻塞错误 → 阻止工具执行
│ └── 非阻塞 → 继续
↓
工具执行
↓
PostToolUse 钩子
├── 同样的匹配和执行流程
├── 可以检查工具结果
└── 可以触发后续操作
↓
回合结束
↓
Stop 钩子
├── 执行停止钩子
├── 后台任务(记忆提取等)
└── 可以阻止回合结束
设计亮点
- 双目录分离: React UI hooks (
src/hooks/) 与钩子执行引擎 (src/utils/hooks/) 完全分离 - 28 种事件: 覆生命周期的完整事件链
- **: HTTP 钩子内置 SSRF 安全守卫
- Matcher 模式: 使用 glob 模式匹配工具名和参数
- 条件执行:
if字段支持权限规则语法过滤 - 并行执行: 同一事件的多个钩子并行执行
- 超时控制: 每个钩子独立超时
15 - state 模块源码分析
路径:
src/state/文件数: 6 个 总行数: 1190 行 功能: React 感知的应用状态管理 — 组件级订阅与重渲染
模块概述
state/ 与 bootstrap/state.ts 的全局单例不同,这里的状态是 React 感知的,支持组件级别的订阅和选择性重渲染。类似 Zustand 的设计模式。
文件详解
1. store.ts — 状态存储核心(34 行)
核心 API
type Store<T> = {
getState: () => T
setState: (updater: (prev: T) => T) => void // 接受 updater 函数,不是部分状态
subscribe: (listener: () => void) => () => void // listener 无参数,返回 unsubscribe
}
function createStore<T>(
initialState: T,
onChange?: (args: { newState: T; oldState: T }) => void
): Store<T>
注意:
setState接受 updater 函数(prev) => next,不是直接传入部分状态对象。subscribe的 listener 不接收参数。onChange回调(接收新旧状态)是createStore的第二个参数。
2. AppStateStore.ts — 应用状态定义(569 行)
功能
定义完整的应用状态结构和初始值。
实际 AppState 关键字段
interface AppState {
// 设置与配置
settings: SettingsJson
verbose: boolean
mainLoopModel: ModelSetting
expandedView: boolean
// 权限
toolPermissionContext: ToolPermissionContext
// 任务(对象映射,非数组)
tasks: { [taskId: string]: TaskState }
// MCP
mcp: MCPState
// 插件
plugins: PluginState
// 推测执行
speculation: SpeculationState
// 团队视图
viewingAgentTaskId?: string
// 消息与对话
messages: Message[]
// 文件历史
fileHistory: FileHistoryState
// 归因追踪
attribution: AttributionState
// 通知
notifications: Notification[]
// 待办列表
todoList: TodoList | null
// ... 更多字段
}
注意:
tasks是{ [taskId: string]: TaskState }对象映射,不是数组。
3. selectors.ts — 状态选择器(76 行)
功能
派生状态选择器,用于从 AppState 中提取计算状态。
实际导出
// 获取当前查看的队友任务
function getViewedTeammateTask(
appState: Pick<AppState, 'viewingAgentTaskId' | 'tasks'>
): InProcessTeammateTaskState | undefined
// 确定用户输入应路由到哪个 Agent
type ActiveAgentForInput =
| { type: 'leader' }
| { type: 'viewed'; task: InProcessTeammateTaskState }
| { type: 'named_agent'; task: LocalAgentTaskState }
function getActiveAgentForInput(appState: AppState): ActiveAgentForInput
4. AppState.tsx — React Provider(199 行)
功能
React Context Provider,将状态存储注入组件树。
// Context 名称
const AppStoreContext = createContext<Store<AppState>>(...)
const HasAppStateContext = createContext<boolean>(false) // 防嵌套
// 消费 Hook
function useAppState<T>(selector: (state: AppState) => T): T {
const store = useContext(AppStoreContext)
return useSyncExternalStore(
store.subscribe,
() => selector(store.getState())
)
}
5. onChangeAppState.ts — 状态变更监听(171 行)
功能
硬编码的状态变更副作用处理器,响应特定字段的变化。
// 接收新旧状态,内部硬编码了对以下字段变化的响应:
function onChangeAppState({ newState, oldState }: {
newState: AppState
oldState: AppState
}): void {
// toolPermissionContext.mode 变化 → 通知权限模式变更
// mainLoopModel 变化 → 设置模型覆盖
// expandedView 变化 → 保存配置
// verbose 变化 → 保存配置
// settings 变化 → 应用环境变量、清除凭证缓存
}
注意:这不是一个通用的注册机制,而是一个具体的函数,内部硬编码了对特定字段变化的响应逻辑。
6. teammateViewHelpers.ts — 队友视图辅助(141 行)
实际导出
function enterTeammateView(appState: AppState, taskId: string): void
function exitTeammateView(appState: AppState): void
function stopOrDismissAgent(appState: AppState, taskId: string): void
与 bootstrap/state.ts 的区别
| 特性 | bootstrap/state.ts | state/ 模块 |
|---|---|---|
| 类型 | 全局单例对象 | React 感知的 Store |
| 访问方式 | getter/setter 函数 | useAppState Hook |
| 重渲染 | 不触发 | 自动触发组件重渲染 |
| 用途 | 非 UI 状态(API、遥测) | UI 相关状态(消息、任务) |
| 生命周期 | 进程级 | 组件树级 |
16 - context 模块源码分析
路径:
src/context/功能: 上下文收集 — git 状态、CLAUDE.md、环境信息注入系统提示
模块概述
context/ 负责收集对话所需的各种上下文信息并注入到系统提示中,帮助 AI 理解当前项目环境。所有收集操作都带 memoization 缓存。
收集的上下文类型
1. Git 上下文
interface GitContext {
branch: string // 当前分支名
status: string // 工作区状态(截断到 2000 字符)
recentCommits: string[] // 最近 N 条提交
user: string // git 用户名
isRepo: boolean // 是否在 git 仓库中
mainBranch: string // 主分支名(main/master)
}
git status输出截断到 2000 字符,防止大仓库状态溢出- 最近提交用于 AI 理解项目活跃度和变更方向
2. CLAUDE.md 上下文
发现路径优先级(从高到低):
1. 项目根目录/CLAUDE.md ← 项目级指令
2. 项目根目录/CLAUDE.local.md ← 本地个人指令(gitignore)
3. 当前目录/CLAUDE.md ← 子目录级指令
4. 父目录链中的 CLAUDE.md ← 继承链
5. ~/.claude/CLAUDE.md ← 全局指令
3. 环境上下文
interface EnvironmentContext {
platform: string // darwin / linux / win32
shell: string // bash / zsh / fish
osVersion: string // Darwin 24.6.0
cwd: string // 当前工作目录
projectRoot: string // 项目根目录
}
核心函数
// 主入口 — 带 memoization 缓存
const gatherContext = memoize(async (): Promise<ConversationContext> => {
const [git, claudeMd, env] = await Promise.all([
gatherGitContext(),
gatherClaudeMdContext(),
gatherEnvironmentContext(),
])
return { git, claudeMd, env }
})
特性
- Memoized: 避免重复收集,同一会话内只收集一次
- Bare 模式: 最小上下文,用于轻量级场景
- 显式目录添加: 支持手动添加额外目录的 CLAUDE.md
- 诊断日志: 带 PII 过滤的调试日志
- 缓存破坏: 调试用的缓存破坏注入机制
17 - constants 模块源码分析
路径:
src/constants/功能: 常量定义 — 产品信息、OAuth 配置、模型列表、UI 常量
核心常量文件
product.ts — 产品信息
export const PRODUCT_NAME = 'Claude Code'
export const PRODUCT_COMMAND = 'claude'
export const CLI_VERSION = '...' // 从 package.json 读取
export const USER_AGENT = `claude-code/${CLI_VERSION}`
oauth.ts — OAuth 配置
export function getOauthConfig() {
return {
clientId: '...',
authorizationEndpoint: 'https://claude.ai/oauth/authorize',
tokenEndpoint: 'https://claude.ai/oauth/token',
scopes: ['openid', 'profile', 'email'],
redirectUri: 'http://localhost:{port}/callback',
}
}
models.ts — 模型配置
export const MODEL_ALIASES = {
'opus': 'claude-opus-4-6',
'sonnet': 'claude-sonnet-4-6',
'haiku': 'claude-haiku-4-5',
'opus[1m]': 'claude-opus-4-6[1m]',
'sonnet[1m]': 'claude-sonnet-4-6[1m]',
}
outputStyles.ts — 输出样式类型
interface OutputStyleConfig {
name: string
description: string
prompt: string
source: 'user' | 'project' | 'plugin'
keepCodingInstructions: boolean
}
18 - types 模块源码分析
路径:
src/types/文件数: ~11 个 功能: 全局类型定义 — 消息、工具、权限、设置等核心类型
核心类型
message.ts — 消息类型
type Message = {
role: 'user' | 'assistant'
content: ContentBlock[]
id?: string
timestamp?: number
}
type ContentBlock =
| { type: 'text'; text: string }
| { type: 'image'; source: ImageSource }
| { type: 'tool_use'; id: string; name: string; input: unknown }
| { type: 'tool_result'; tool_use_id: string; content: unknown }
| { type: 'thinking'; thinking: string }
ids.ts — ID 类型(品牌类型)
// 使用品牌类型防止 ID 混用
type SessionId = string & { __brand: 'SessionId' }
type TaskId = string & { __brand: 'TaskId' }
type AgentId = string & { __brand: 'AgentId' }
permissions.ts — 权限类型
type PermissionMode = 'default' | 'auto' | 'bypassAll'
type PermissionRequest = {
toolName: string
toolInput: unknown
requestId: string
}
type PermissionUpdate = {
behavior: 'allow' | 'deny'
rule?: string // 持久化规则
}
settings.ts — 设置类型
interface Settings {
model?: string
theme?: string
vimMode?: boolean
autoMemory?: boolean
permissions?: PermissionRule[]
hooks?: HooksSettings
env?: Record<string, string>
mcpServers?: Record<string, MCPServerConfig>
// ...
}
tool.ts — 工具相关类型
interface ToolUseContext {
sessionId: SessionId
agentId?: AgentId
cwd: string
abortSignal: AbortSignal
}
hooks.ts — 钩子系统类型
interface HookContext {
messages: Message[]
systemPrompt: string
toolName?: string
toolInput?: unknown
toolResult?: unknown
}
type HookCallback = (context: HookContext) => Promise<HookResult>
mcp.ts — MCP 协议类型
interface MCPServerConfig {
command: string
args?: string[]
env?: Record<string, string>
}
interface MCPTool {
name: string
description: string
inputSchema: JSONSchema
}
theme.ts — 主题类型
type Theme = 'dark' | 'light' | 'light-daltonized' | 'dark-daltonized'
model.ts — 模型配置类型
interface ModelSetting {
model: string
contextWindow: number
maxOutputTokens: number
}
agent.ts — Agent 类型
interface AgentDefinition {
name: string
description: string
model?: string
tools?: string[]
systemPrompt?: string
source: 'built-in' | 'user' | 'project' | 'plugin'
}
plugin.ts — 插件类型
interface Plugin {
id: string
name: string
version: string
enabled: boolean
scope: 'user' | 'project' | 'local'
}
19 - schemas 模块源码分析
路径:
src/schemas/功能: Zod Schema 定义 — 运行时类型验证
hooks.ts — 钩子 Schema
行数: 223 行
核心设计
使用 lazySchema 打破循环依赖(settings/types.ts ↔ plugins/schemas.ts)。
四种钩子类型的 discriminated union
const HookCommandSchema = z.discriminatedUnion('type', [
// Shell 命令钩子
z.object({
type: z.literal('command'),
command: z.string(),
shell: z.enum(SHELL_TYPES).optional(),
timeout: z.number().optional(),
if: IfConditionSchema.optional(),
statusMessage: z.string().optional(),
once: z.boolean().optional(),
asyncRewake: z.boolean().optional(),
}),
// LLM 提示钩子
z.object({
type: z.literal('prompt'),
prompt: z.string(),
model: z.string().optional(),
timeout: z.number().optional(),
if: IfConditionSchema.optional(),
}),
// HTTP Webhook 钩子
z.object({
type: z.literal('http'),
url: z.string().url(),
headers: z.record(z.string()).optional(),
allowedEnvVars: z.array(z.string()).optional(),
timeout: z.number().optional(),
}),
// Agent 验证器钩子
z.object({
type: z.literal('agent'),
prompt: z.string(),
model: z.string().optional(),
timeout: z.number().optional(),
}),
])
匹配器 Schema
const HookMatcherSchema = z.object({
matcher: z.string().optional(), // glob 模式,如 "Bash(git *)"
hooks: z.array(HookCommandSchema),
})
完整钩子配置
const HooksSchema = z.record(
z.enum(HOOK_EVENTS), // PreToolUse, PostToolUse, Stop, ...
z.array(HookMatcherSchema)
).partial()
IfConditionSchema — 条件过滤
// 可选的权限规则语法,控制钩子何时运行
// 例如: "Bash(git *)" 只在 Bash 工具执行 git 命令时触发
const IfConditionSchema = z.string()
设计亮点
- lazySchema: 使用懒加载打破 settings/types.ts 和 plugins/schemas.ts 之间的循环依赖
- discriminated union: 通过
type字段实现类型安全的钩子路由 - 独立提取: 从 settings/types.ts 中提取出来,避免循环引用
20 - bridge 模块源码分析
路径:
src/bridge/文件数: 31 个 功能: Web/IDE 桥接通信 — 连接 CLI 与 Web UI/IDE 扩展
模块概述
bridge/ 是 Claude Code 最复杂的通信模块之一,负责在 CLI 进程与 Web 界面(claude.ai/code)或 IDE 扩展(VS Code/JetBrains)之间建立双向通信桥梁。支持多会话管理、断线重连、权限代理和状态同步。
架构总览
┌──────────────┐ WebSocket/SSE ┌──────────────────┐
│ Web UI │ ◄──────────────────────► │ │
│ (claude.ai) │ │ Bridge Layer │
└──────────────┘ │ │
│ ├── 消息路由 │
┌──────────────┐ WebSocket/SSE │ ├── 权限代理 │
│ IDE 扩展 │ ◄──────────────────────► │ ├── 状态同步 │
│ (VS Code) │ │ ├── 断线重连 │
└──────────────┘ │ └── 多会话管理 │
│ │
└────────┬─────────┘
│
┌────────▼─────────┐
│ CLI 核心 │
│ (REPL/Query) │
└──────────────────┘
核心文件详解
1. bridgeMessaging.ts — 消息处理核心
行数: 462 行
功能概述
传输层消息处理,提供纯函数用于解析 WebSocket 消息、路由控制请求和去重回声。
导出
isSDKMessage()— SDK 消息类型守卫isSDKControlResponse()— 控制响应类型守卫isSDKControlRequest()— 控制请求类型守卫isEligibleBridgeMessage()— 桥接消息资格检查extractTitleText()— 提取标题文本handleIngressMessage()— 入站消息处理handleServerControlRequest()— 服务器控制请求处理makeResultMessage()— 构造结果消息BoundedUUIDSet类 — 有界 UUID 集合
BoundedUUIDSet — FIFO 环形缓冲去重
class BoundedUUIDSet {
private set = new Set<string>()
private queue: string[] = []
private maxSize: number
add(uuid: string): boolean {
if (this.set.has(uuid)) return false // 重复
this.set.add(uuid)
this.queue.push(uuid)
if (this.queue.length > this.maxSize) {
const oldest = this.queue.shift()!
this.set.delete(oldest)
}
return true // 新消息
}
// O(1) 操作,防止回声消息重复处理
}
控制请求处理
async function handleServerControlRequesServerControlRequest) {
switch (request.type) {
case 'initialize': // 初始化连接
case 'set_model': // 切换模型
case 'interrupt': // 中断执行
case 'set_permission_mode': // 设置权限模式
case 'set_max_thinking_tokens': // 设置思考 token 上限
}
}
2. bridgePointer.ts — 崩溃恢复指针
行数: 211 行
功能概述
会话启动时写入指针文件,用于崩溃恢复和 --continue 功能。
导出
BRIDGE_POINTER_TTL_MS— 指针 TTL(4 小时)BridgePointer类型writeBridgePointer()— 写入指针readBridgePointer()— 读取指针readBridgePointerAcrossWorktrees()— 跨 worktree 读earBridgePointer()` — 清除指针
指针结构
type BridgePointer = {
sessionId: string
environmentId: string
source: 'standalone' | 'repl'
}
过期检测
// 通过文件 mtime 检测过期(4 小时 TTL)
const stats = await stat(pointerPath)
const age = Date.now() - stats.mtimeMs
if (age > BRIDGE_POINTER_TTL_MS) return null // 过期
Worktree 扇出
// 跨 git worktree 查找最新指针
// MAX_WORKTREE_FANOUT = 50,限制并行 stat() 调用
async function readBridgePointerAcrossWorktrees() {
const worktrees = await getGitWorktrees()
const pointers = await Promise.all(
worktrees.slice(0, 50).map(wt => readBridgePointer(wt.path))
)
return pointers
.filter(Boolean)
.sort((a, b) => b.mtime - a.mtime)[0] // 取最新
}
3. bridgeUI.ts — 终端 UI 实现
行数: 531 行
功能概述
桥接状态的终端 UI 显示,包括 QR 码、Spinner、会话列表和工具活动。
导出
createBridgeLogger()— 创建桥接日志器
状态机
idle → attached → titled
↓ ↓ ↓
└── reconnecting ──┘
↓
failed
UI 功能
| 功能 | 说明 |
|---|---|
| QR 码 | 连接/会话 URL 的 QR 码显示 |
| Spinner | 等待连接时的动画 |
| 会话列表 | 多会话模式下的项目符号列表 |
| 工具活动 | 显示当前执行的工具(30 秒过期) |
| 容量指示 | Spawn 模式下的容量显示 |
ANSI 光标操作
// 追踪 statusLineCount 用于 ANSI 光标操作
function updateDisplay() {
// 上移 N 行
process.stdout.write(`\x1b[${statusLineCount}A`)
// 清除到末尾
process.stdout.write('\x1b[J')
// 写入新内容
process.stdout.write(newContent)
// 更新行数(考虑终端换行)
statusLineCount = countVisualLines(newContent, terminalWidth)
}
4. bridgePermissionCallbacks.ts — 权限代理
行数: 44 行
功能概述
定义 CLI 和 Web 应用之间权限请求/响应的回调接口。
type BridgePermissionCallbacks = {
sendRequest(request: PermissionRequest): void
sendResponse(response: BridgePermissionResponse): void
cancelRequest(requestId: string): void
onResponse(handler: (response: BrPermissionResponse) => void): void
}
type BridgePermissionResponse = {
behavior: 'allow' | 'deny'
updatedInput?: unknown
updatedPermissions?: PermissionUpdate
message?: string
}
5. bridgeStatusUtil.ts — 状态工具函数
行数: 164 行
导出
StatusState类型 — idle | attached | titled | reconnecting | failedTOOL_DISPLAY_EXPIRY_MS— 工具显示过期时间(30 秒)SHIMMER_INTERVAL_MS— 闪烁动画间隔buildBridgeConnectUrl()— 构建连接 URLbuildBridgeSessionUrl()— 构建会话 URLcomputeShimmerSegments()— 计算闪烁动画段getBridgeStatus()— 获取桥接WithOsc8Link()` — OSC 8 终端超链接
闪烁动画
// 使用 grapheme segmentation 支持多字节字符
function computeShimmerSegments(text: string, index: number) {
const graphemes = [...new Intl.Segmenter('en', { granularity: 'grapheme' })
.segment(text)]
// 计算闪烁位置...
}
OSC 8 超链接
// 终端可点击链接
function wrapWithOsc8Link(text: string, url: string): string {
return `\x1b]8;;${url}\x07${text}\x1b]8;;\x07`
}
6. bridgeConfig.ts — 桥接配置
管理桥接连接的配置参数,包括 WebSocket URL、认证令牌和重连策略。
7. bridgeMain.ts — 桥接主逻辑
桥接模式的主入口,协调连接建立、消息路由和生命周期管理。
8. remoteBridgeCore.ts — 远程桥接核心
远程桥接的核心实现,处理与远程服务器的持久连接。
9. replBridge.ts — REPL 桥接
将桥接功能集成到 REPL 屏幕中。
10. initReplBridge.ts — REPL 桥接初始化
REPL 模式下桥接的初始化逻辑。
11. sessionRunner.ts — 会话运行器
管理桥接会话的执行生命周期。
12. createSession.ts — 会话创建
创建新的桥接会话。
13. codeSessionApi.ts — 代码会话 API
与后端代码会话 API 的交互。
14. jwtUtils.ts — JWT 工具
JWT 令牌的解析和验证。
15. flushGate.ts — 刷新门控
控制消息刷新的门控机制。
16. capacityWake.ts — 容量唤醒
管理桥接容量和唤醒逻辑。
17. pollConfig.ts / pollConfigDefaults.ts — 轮询配置
桥接轮询的配置和默认值。
18. inboundMessages.ts / inboundAttachments.ts — 入站处理
处理入站消息和附件。
19. types.ts — 类型定义
桥接模块的内部类型定义。
设计亮点
- 多传输支持: WebSocket 和 SSE 双传输,自动降级
- 崩溃恢复: 指针文件 + TTL 机制确保会话可恢复
- 回声去重: BoundedUUIDSet 用 O(1) 操作过滤重复消息
- Worktree 感知: 跨 git worktree 查找会话,支持并行开发
- 渐进式 UI: 状态机驱动的终端 UI,支持 QR 码和闪烁动画
- 权限代理: CLI 和 Web 之间透明的权限请求转发
21 - coordinator 模块源码分析
路径:
src/coordinator/文件数: 1 个 行数: 369 行 功能: 协调器模式 — 功能标志检测、会话模式匹配和 Worker 上下文构建
模块概述
coordinator/ 模块实现的是协调器模式的功能标志和上下文构建,不是多会话管理或容量控制系统。核心功能是检测当前是否处于协调器模式,匹配会话模式,以及为 Worker 构建工具上下文和系统提示。
coordinatorMode.ts — 唯一文件
核心导出
// 检测是否处于协调器模式
function isCoordinatorMode(): boolean {
if (feature('COORDINATOR_MODE')) {
return isEnvTruthy(process.env.CLAUDE_CODE_COORDINATOR_MODE)
}
return false
}
// 匹配会话模式(恢复会话时检查模式是否一致)
function matchSessionMode(
sessionMode: 'coordinator' | 'normal' | undefined
): string | undefined
// 构建 Worker 的用户上下文(工具列表、系统提示等)
function getCoordinatorUserContext(options: {
scratchpadDir?: string
}): CoordinatorUserContext
// 返回协调器系统提示词
function getCoordinatorSystemPrompt(): string
设计说明
- 通过
feature('COORDINATOR_MODE')编译时门控 +CLAUDE_CODE_COORDINATOR_MODE环境变量双重控制 matchSessionMode()在恢复会话时检查当前模式与会话存储的模式是否一致,不一致时翻转环境变量- Worker 工具上下文定义了 Worker 可用的工具集(排除 TeamCreate/TeamDelete/SendMessage/SyntheticOutput 等内部工具)
- 支持 scratchpad 功能(通过
tengu_scratchStatsig 门控)
内部常量
// Worker 不可用的内部工具
const INTERNAL_WORKER_TOOLS = new Set([
TEAM_CREATE_TOOL_NAME,
TEAM_DELETE_TOOL_NAME,
SEND_MESSAGE_TOOL_NAME,
SYNTHETIC_OUTPUT_TOOL_NAME,
])
与其他模块的关系
coordinator/
├── ← bootstrap/state.ts (isCoordinatorMode 被全局使用)
├── → tools/ (引用工具名常量)
├── → services/analytics/ (Statsig 门控)
└── → constants/tools.ts (ASYNC_AGENT_ALLOWED_TOOLS)
注意:多会话的 Spawn 模式逻辑在
bridge/bridgeUI.ts中,不在 coordinator 模块。
22 - remote 模块源码分析
路径:
src/remote/文件数: 4 个 功能: 远程会话管理 — 云端 Agent 会话的连接、消息收发和状态同步
文件详解
1. RemoteSessionManager.ts — 远程会话管理器
管理远程会话的连接、消息收发和权限处理。
class RemoteSessionManager {
// 连接管理
connect(): Promise<void>
disconnect(): void
reconnect(): Promise<void>
isConnected(): boolean
getSessionId(): string
// 消息发送
sendMessage(content: RemoteMessageContent): Promise<void>
// 权限处理
respondToPermissionRequest(requestId: string, response: PermissionUpdate): void
// 会话控制
cancelSession(): void
}
注意:不存在
createSession、disconnectSession、resumeSession、getActiveSession方法。
2. SessionsWebSocket.ts — 会话 WebSocket
维护与远程服务器的 WebSocket 持久连接。URL 和认证信息在构造函数中传入。
class SessionsWebSocket {
// 连接管理(无参数,配置在构造函数中)
connect(): void
close(): void
reconnect(): void
isConnected(): boolean
// 消息发送
sendControlResponse(response: SDKControlResponse): void
sendControlRequest(request: SDKControlRequest): void
// 重连(私有方法)
private scheduleReconnect(delay: number, label: string): void
}
注意:
connect()无参数;不存在onMessage和send方法;重连方法是scheduleReconnect(私有),不是reconnectWithBackoff。消息回调通过构造函数的SessionsWebSocketCallbacks参数传入。
3. sdkMessageAdapter.ts — SDK 消息适配器
将远程 SDK 消息转换为本地 REPL 可用的格式。只有单向转换(SDK→REPL),不存在反向转换。
// SDK 消息 → 本地消息
function convertSDKMessage(message: SDKMessage): ConvertedMessage
// 辅助函数
function isSessionEndMessage(message: SDKMessage): boolean
function isSuccessResult(message: SDKMessage): boolean
function getResultText(message: SDKMessage): string
type ConvertedMessage = { ... }
注意:不存在
adaptRemoteToLocal和adaptLocalToRemote函数。
4. remotePermissionBridge.ts — 远程权限工具
提供为远程权限请求创建合成消息和工具存根的工具函数,不是一个代理转发模块。
// 为远程权限请求创建合成的 assistant 消息
function createSyntheticAssistantMessage(
toolName: string,
toolInput: Record<string, unknown>,
toolUseId: string
): Message
// 创建工具存根(用于权限检查)
function createToolStub(toolName: string): Tool
23 - server 模块源码分析
路径:
src/server/功能: HTTP/WebSocket 服务器 — IDE 扩展和 Web UI 的通信后端
功能概述
提供 HTTP 和 WebSocket 服务器,用于:
- IDE 扩展通信(VS Code / JetBrains)
- Web UI 桥接(claude.ai/code)
- MCP 服务器托管
- 健康检查端点 (
/health) - 会话状态查询 (
/status)
端点
| 端点 | 方法 | 说明 |
|---|---|---|
/health | GET | 健康检查,返回 200 |
/status | GET | 会话状态(消息数、费用、模型等) |
/ws | WebSocket | 双向消息通道 |
/mcp | WebSocket/stdio | MCP 协议端点 |
WebSocket 通信
IDE 扩展 / Web UI
↕ WebSocket (/ws)
Server
↕ 内部事件
REPL / Query Engine
消息类型
// 服务器 → 客户端
type ServerMessage =
| { type: 'message'; message: SDKMessage }
| { type: 'status'; status: SessionStatus }
| { type: 'permission_request'; request: PermissionRequest }
// 客户端 → 服务器
type ClientMessage =
| { type: 'user_message'; content: string }
| { type: 'permission_response'; response: PermissionUpdate }
| { type: 'control_request'; request: ServerControlRequest }
与其他模块的关系
server/
├── ← bridge/ (桥接通信使用 server 的 WebSocket)
├── ← cli/transports/ (传输层连接到 server)
├── → screens/REPL.tsx (转发用户消息)
└── → services/mcp/ (托管 MCP 服务器)
24 - keybindings 模块源码分析
路径:
src/keybindings/文件数: 14 个 功能: 快捷键系统 — 上下文感知的键盘绑定管理
模块概述
keybindings/ 实现了一套完整的键盘快捷键系统,支持 17 种上下文、72+ 种动作、和弦序列(chord)、平台特定处理和用户自定义。
架构总览
┌─────────────────────────────────────────────┐
│ 快捷键系统架构 │
├─────────────────────────────────────────────┤
│ │
│ 用户输入 (按键事件) │
│ ↓ │
│ KeybindingProviderSetup.tsx (React 组件) │
│ ↓ │
│ resolver.ts (纯函数解析器) │
│ ├── 和弦状态管理 │
│ ├── Escape 取消 │
│ └── 上下文匹配 │
│ ↓ │
│ match.ts (匹配逻辑) │
│ ├── Alt/Meta 等价处理 │
│ └── Escape 键特殊处理 │
│ ↓ │
│ defaultBindings.ts + loadUserBindings.ts │
│ ├── 默认绑定 │
│ ├── 用户自定义 (~/.claude/keybindings.json) │
│ └── 合并策略 │
│ ↓ │
│ useKeybinding.ts (React Hook) │
│ └── 注册到处理器 Map │
│ │
└─────────────────────────────────────────────┘
核心文件详解
1. schema.ts — Schema 定义
行数: 237 行
导出
KEYBINDING_CONTEXTS— 19 种上下文KEYBINDING_ACTIONS— 72+ 种动作- Zod Schema 定义
上下文列表(17 个)
| 上下文 | 说明 |
|---|---|
| Global | 全局 |
| Chat | 聊天输入 |
| Autocomplete | 自动补全 |
| Confirmation | 确认对话框 |
| Help | 帮助页面 |
| Transcript | 对话记录 |
| HistorySearch | 历史搜索 |
| Task | 任务管理 |
| ThemePicker | 主题选择器 |
| Settings | 设置页面 |
| Tabs | 标签页 |
| Attachments | 附件管理 |
| Footer | 底部栏 |
| MessageSelector | 消息选择器 |
| DiffDialog | Diff 对话框 |
| ModelPicker | 模型选择器 |
| Select | 选择列表 |
| Plugin | 插件管理 |
注意:源码中没有 Permission 和 Voice 这两个 context(语音按键绑定通过 voice:pushToTalk action 在其他 context 中处理)。
动作分类
// 应用级动作
'app:quit', 'app:help', 'app:settings', 'app:theme'
// 聊天动作
'chat:submit', 'chat:newline', 'chat:clear', 'chat:interrupt'
'chat:paste-image', 'chat:history-prev', 'chat:history-next'
// 自动补全动作
'autocomplete:accept', 'autocomplete:dismiss'
// 确认动作
'confirmation:yes', 'confirmation:no', 'confirmation:always'
// 标签页动作
'tabs:next', 'tabs:prev', 'tabs:close'
// 对话记录动作
'transcript:scroll-up', 'transcript:scroll-down'
'transcript:page-up', 'transcript:page-down'
'transcript:top', 'transcript:bottom'
// 更多...
2. parser.ts — 按键解析器
行数: 204 行
功能
解析按键字符串(如 `ctrl+shif化对象,处理修饰键别名和平台特定显示。
修饰键别名
const MODIFIER_ALIASES = {
'ctrl': 'ctrl',
'control': 'ctrl',
'cmd': 'meta',
'command': 'meta',
'win': 'meta',
'super': 'meta',
'alt': 'alt',
'option': 'alt',
'shift': 'shift',
}
平台显示
// macOS: ⌘⇧K
// Windows/Linux: Ctrl+Shift+K
function formatKeystroke(keystroke: Keystroke, platform: Platform): string
3. defaultBindings.ts — 默认绑定
行数: 341 行
功能
定义所有默认快捷键绑定,包含平台特定处理。
平台特定绑定
// 图片粘贴键
const IMAGE_PASTE_KEY = process.platform === 'darwin'
? 'cmd+v' // macOS
: 'ctrl+shift+v' // Windows/Linux
// Windows Terminal VT 模式检测
if (isWindowsTerminalVTMode()) {
// 调整某些绑定以适应 VT 模式
}
Feature Flag 集成
某些绑定受 feature flag 控制,仅在特定条件下启用。
4. reservedShortcuts.ts — 保留快捷键
行数: 128 行
不可重绑定的快捷键
const NON_REBINDABLE = new Set([
'ctrl+c', // 中断/复制
'ctrl+d', // EOF
'ctrl+m', // 回车等价
])
终端保留
const TERMINAL_RESERVED = new Set([
'ctrl+z', // 挂起
'ctrl+\\', // SIGQUIT
])
macOS 保留
const MACOS_RESERVED = new Set([
'cmd+c', // 复制
'cmd+v', // 粘贴
'cmd+x', // 剪切
'cmd+q', // 退出
'cmd+w', // 关闭窗口
'cmd+tab', // 切换应用
'cmd+space', // Spotlight
])
5. match.ts — 匹配逻辑
行数: 121 行
功能
将 Ink 输入事件与快捷键定义进行匹配。
特殊处理
// Alt 和 Meta 等价处理
// 在某些终端中 Alt 和 Meta 是同一个键
if (binding.alt && event.meta) return true
if (binding.meta && event.alt) return true
// Escape 键特殊处理
// Escape 可能是 Alt 前缀的一部分
if (event.key === 'escape' && !binding.escape) {
// 等待下一个按键判断是否是 Alt 组合
}
6. resolver.ts — 纯函数解析器
行数: 245 行
功能
纯函数实现的快捷键解析,管理和弦状态和 Escape 取消。
和弦序列
// 和弦示例: ctrl+k ctrl+s
// 第一次按 ctrl+k → 进入和弦等待状态
// 第二次按 ctrl+s → 匹配完成,执行动作
// 按 Escape → 取消和弦
type ChordState = {
firstKeystroke: Keystroke
timestamp: number
timeout: number // 1000ms 超时
}
7. loadUserBindings.ts — 用户自定义加载
行数: 473 行
功能
从 ~/.claude/keybindings.json 加载用户自定义绑定,支持热重载。
文件监听
// 使用 chokidar 监听文件变化
const watcher = chokidar.watch(keybindingsPath, {
persistent: true,
ignoreInitial: true,
})
watcher.on('change', () => {
// 重新加载并合并绑定
reloadBindings()
})
合并策略
// 用户绑定覆盖默认绑定
// 如果用户绑定作,替换默认绑定
// 如果用户绑定了一个新的动作,追加
function mergeBindings(defaults, userBindings) {
const merged = new Map(defaults)
for (const [action, binding] of userBindings) {
merged.set(action, binding) // 覆盖或追加
}
return merged
}
8. validate.ts — 验证系统
行数: 499 行
功能
全面验证用户自定义绑定的合法性。
验证项目
| 验证 | 说明 |
|---|---|
| 上下文名称 | 必须是 19 种合法上下文之一 |
| 动作格式 | 必须匹配 context:action 格式 |
| 按键语法 | 修饰键 + 键名的合法组合 |
| 命令绑定 | 正则验证命令绑定格式 |
| 重复检测 | 同一上下文中的重复绑定警告 |
| 保留键检测 | 不可重绑定的快捷键警告 |
| voice:pushToTalk | 特殊处理语音按键绑定 |
9. useKeybinding.ts — React Hook
行数: 197 行
功能
React Hook,支持和弦序列和 stopImmediatePropagation 事件控制。
function useKeybinding(
context: KeybindingContext,
action: KeybindingAction,
handler: () => void,
options?: { enabled?: boolean }
): void {
// 注册到处理器 Map
// 支持和弦序列
// stopImmediatePropagation 防止事件冒泡
}
10. KeybindingProviderSetup.tsx — React 组件
行数: 307 行
功能
React 组件,提供快捷键上下文、热重载和和弦拦截。
核心结构
function KeybindingProviderSetup({ children }) {
// 处理器注册表 Map
const handlers = useRef(new Map())
// 活跃上下文 refs
const activeContexts = useRef(new Set())
// 和弦超时: 1000ms
const CHORD_TIMEOUT = 1000
return (
<KeybindingContext.Provider value={{ handlers, activeContexts }}>
<ChordInterceptor>
{children}
</ChordInterceptor>
</KeybindingContext.Provider>
)
}
ChordInterceptor 组件
拦截按键事件,管理和弦状态,在超时后自动取消。
11. shortcutFormat.ts / useShortcutDisplay.ts
shortcutFormat.ts (64 行)
非 React 工具函数,格式化快捷键显示字符串,带回退追踪。
useShortcutDisplay.ts (60 行)
React Hook 版本,附带分析日志记录。
12. template.ts — 模板生成
行数: 53 行
生成 keybindings.json 模板文件,包含 JSON Schema URL。
function generateTemplate(): string {
return JSringify({
"$schema": "https://...",
// 空的绑定模板
}, null, 2)
}
设计亮点
- 上下文感知: 19 种上下文确保快捷键不会在错误的场景触发
- 和弦支持: 类似 VS Code 的多键序列(ctrl+k ctrl+s)
- 平台适配: macOS/Windows/Linux 各有适当的默认绑定
- 热重载: 修改 keybindings.json 后立即生效,无需重启
- 安全验证: 全面的验证系统防止无效或危险的绑定
- 纯函数解析: resolver 是纯函数,易于测试
25 - vim 模块源码分析
路径:
src/vim/文件数: 5 个 总行数: 1513 行 功能: Vim 模式 — 终端输入框的 Vim 键绑定支持
文件详解
1. types.ts — Vim 状态类型(199 行)
// VimState 是联合类型,只有 INSERT 和 NORMAL 两种模式(大写)
// 不存在 Visual 和 Command 模式
type VimState =
| { mode: 'INSERT'; insertedText: string }
| { mode: 'NORMAL'; command: CommandState }
// NORMAL 模式下的命令状态机(11 种状态)
type CommandState =
| { type: 'idle' }
| { type: 'count'; digits: string }
| { type: 'operator'; op: Operator; count: number }
| { type: 'operatorCount'; op: Operator; count: number; digits: string }
| { type: 'operatorFind'; op: Operator; count: number; find: FindType }
| { type: 'operatorTextObj'; op: Operator; count: number; scope: TextObjScope }
| { type: 'find'; find: FindType; count: number }
| { type: 'g'; count: number }
| { type: 'operatorG'; op: Operator; count: number }
| { type: 'replace'; count: number }
| { type: 'indent'; dir: '>' | '<'; count: number }
// 持久状态(跨命令保持)
type PersistentState = {
lastChange: RecordedChange | null // dot-repeat 记录
lastFind: { type: FindType; char: string } | null
register: string // 寄存器内容
registerIsLinewise: boolean
}
function createInitialVimState(): VimState {
return { mode: 'INSERT', insertedText: '' }
}
2. motions.ts — 光标移动(82 行)
| 键 | 动作 | 说明 |
|---|---|---|
h | 左移 | 字符级 |
l | 右移 | 字符级 |
w | 下一个词首 | 词级 |
b | 上一个词首 | 词级 |
e | 当前词尾 | 词级 |
0 | 行首 | 行级 |
$ | 行尾 | 行级 |
^ | 首个非空字符 | 行级 |
gg | 文档开头 | 文档级 |
G | 文档末尾 | 文档级 |
3. operators.ts — 操作符(556 行)
| 键 | 操作 | 说明 |
|---|---|---|
d | 删除 | dw 删除一个词 |
c | 修改 | cw 修改一个词(进入 INSERT) |
y | 复制 | yw 复制一个词 |
p | 粘贴 | 粘贴寄存器内容 |
x | 删除字符 | 删除光标下字符 |
4. textObjects.ts — 文本对象(186 行)
| 键 | 对象 | 说明 |
|---|---|---|
iw | 内部词 | 不含周围空格 |
aw | 一个词 | 含周围空格 |
i" | 引号内 | 双引号内容 |
a" | 含引号 | 含双引号本身 |
i( | 括号内 | 圆括号内容 |
a( | 含括号 | 含圆括号本身 |
5. transitions.ts — 状态转换(490 行)
这是一个完整的状态机实现,处理 NORMAL 模式下 11 种 CommandState 之间的转换。
INSERT 模式
└── Escape → NORMAL (idle)
NORMAL 模式 (CommandState 状态机)
idle
├── i/a/o/A/I/O/s/S/C → INSERT
├── 数字 → count
├── d/c/y → operator
├── f/F/t/T → find
├── g → g
├── r → replace
├── >/< → indent
└── h/l/w/b/e/0/$... → 执行 motion
count
├── 数字 → count (追加)
└── 操作符/motion → 带 count 执行
operator
├── 数字 → operatorCount
├── f/F/t/T → operatorFind
├── i/a → operatorTextObj
├── g → operatorG
└── motion → 执行 operator+motion
注意:不存在 Visual 模式和 Command 模式。Vim 实现仅覆盖 INSERT 和 NORMAL 两种模式。
设计说明
- Vim 模式仅作用于 PromptInput 输入框,不影响对话记录的浏览
- 使用 discriminated union 实现类型安全的状态机
- CommandState 的 11 种状态确保了 TypeScript 的穷举检查
- PersistentState 支持 dot-repeat(
.重复上次操作)和寄存器 - 初始状态为 INSERT 模式(与传统 Vim 不同,因为终端输入框默认需要输入)
26 - voice 模块源码分析
路径:
src/voice/文件数: 1 个 功能: 语音模式 — 语音输入/输出支持
voiceModeEnabled.ts
行数: 55 行
导出
isVoiceGrowthBookEnabled()— GrowthBook kill-switch 检查hasVoiceAuth()— OAuth 认证检查(需要 claude.ai 账户)isVoiceModeEnabled()— 综合启用检查
启用条件
function isVoiceModeEnabled(): boolean {
// 两个条件都必须满足
return isVoiceGrowthBookEnabled() // 1. GrowthBook 特性标志开启
&& hasVoiceAuth() // 2. 有 claude.ai OAuth 认证
}
语音流连接
- 端点: claude.ai 的
voice_stream - 认证: OAuth Bearer Token
- 协议: WebSocket 双向流
- Kill-switch: GrowthBook 可随时关闭
与 REPL 的集成
语音模式在 screens/REPL.tsx 中条件加载:
// REPL.tsx 中
if (isVoiceModeEnabled()) {
const { VoiceInput } = await import('../voice/VoiceInput')
// 渲染语音输入组件
}
语音输入转换为文本后,走和键盘输入相同的消息处理流程。
27 - buddy 模块源码分析
路径:
src/buddy/文件数: 6 个(含 CompanionSprite.tsx) 功能: 伴侣系统 — 虚拟宠物彩蛋(teaser 窗口 2026 年 4 月 1-7 日,命令在之后持续可用)
模块概述
buddy/ 是一个有趣的彩蛋模块,实现了一个虚拟伴侣(宠物)系统。使用种子随机数生成器确保确定性,基于稀有度的抽卡机制,以及 ASCII 艺术精灵动画。仅在 2026 年 4 月 1-7 日期间激活。
文件详解
1. types.ts — 类型定义
行数: 149 行
稀有度权重
const RARITY_WEIGHTS = {
common: 0.60, // 60% — 普通
uncommon: 0.25, // 25% — 不常见
rare: 0.10, // 10% — 稀有
epic: 0.04, // 4% — 史诗
legendary: 0.01, // 1% — 传说
}
物种列表
// 使用 String.fromCharCode 编码物种名称
// 避免模型代号碰撞(AI 模型可能以动物命名)
const SPECIES = [
String.fromCharCode(99, 97, 116), // "cat"
String.fromCharCode(100, 111, 103), // "dog"
String.fromCharCode(102, 111, 120), // "fox"
// ... 共 18 种物种
]
设计亮点: 使用 String.fromCharCode 而非字符串字面量,防止代码中出现的动物名称被误认为是 AI 模型代号。
2. companion.ts — 伴侣生成核心
行数: 134 行
Mulberry32 伪随机数生成器
// 种子确定性 PRNG — 相同种子总是生成相同伴侣
function mulberry32(seed: number): () => number {
return function() {
seed |= 0
seed = seed + 0x6D2B79F5 | 0
let t = Math.imul(seed ^ seed >>> 15, 1 | seed)
t = t + Math.imul(t ^ t >>> 7, 61 | t) ^ t
return ((t ^ t >>> 14) >>> 0) / 4294967296
}
}
稀有度抽卡
// 累积分布函数抽卡
function rollRarity(rng: () => number): Rarity {
const roll = rng()
let cumulative = 0
for (const [rarity, weight] of Object.entries(RARITY_WEIGHTS)) {
cumulative += weight
if (roll <= cumulative) return rarity as Rarity
}
return 'common' // 兜底
}
伴侣生成
function generateCompanion(sessionId: string): Companion {
// 用 sessionId 作为种子 → 同一会话总是同一伴侣
const seed = hashString(sessionId)
const rng = mulberry32(seed)
const rarity = rollRarity(rng)
const species = SPECIES[Math.floor(rng() * SPECIES.length)]
const name = generateName(rng)
return { species, rarity, name, seed }
}
3. sprites.ts — ASCII 艺术精灵
行数: 515 行
功能
为 18 种物种提供 ASCII 艺术,每种有 3 帧动画。
精灵格式
// 每个精灵: 5 行 × 12 字符宽 × 3 动画帧
type Sprite = {
frames: [string[], string[], string[]] // 3 帧
// 每帧 5 行
}
// 示例 (cat):
const catSprite = {
frames: [
// 帧 1
[
' /\\_/\\ ',
' ( o.o ) ',
' > ^ < ',
' /| |\\ ',
'(_| |_) ',
],
// 帧 2 (微动)
[
' /\\_/\\ ',
' ( o.o ) ',
' > ^ < ',
' /| |\\ ',
'(_| |_) ',
],
// 帧 3
// ...
]
}
4. prompt.ts — 介绍文本
行数: 37 行
function companionIntroText(companion: Companion): string {
return `
## 🎉 你获得了一个伴侣!
**${companion.name}** (${companion.species})
稀有度: ${formatRarity(companion.rarity)}
${renderSprite(companion.species, 0)}
`.trim()
}
5. useBuddyNotification.tsx — React Hook
行数: 97 行
功能
React Hook,区分 teaser 窗口和 live 状态:
isBuddyTeaserWindow()— 仅 2026 年 4 月 1-7 日为 true(本地时间,非 UTC)isBuddyLive()— 2026 年 4 月之后持续为 true
useBuddyNotification() 只负责显示 /buddy 彩虹文字 teaser 通知(15 秒超时),不负责直接生成 companion 卡片。Companion 的空闲展示和反应由 CompanionSprite.tsx 处理。
// teaser 窗口: 2026-04-01 到 2026-04-07(本地时间)
export function isBuddyTeaserWindow(): boolean {
const d = new Date()
return d.getFullYear() === 2026 && d.getMonth() === 3 && d.getDate() <= 7
}
// live: 2026 年 4 月之后永久生效
export function isBuddyLive(): boolean {
const d = new Date()
return d.getFullYear() > 2026 || (d.getFullYear() === 2026 && d.getMonth() >= 3)
}
6. CompanionSprite.tsx — 伴侣精灵组件
React 组件,负责伴侣的空闲展示和动画反应。在 isBuddyLive() 为 true 时渲染。
设计亮点
- 确定性随机: Mulberry32 PRNG 确保相同会话总是生成相同伴侣
- 反碰撞编码:
String.fromCharCode避免动物名称与 AI 模型代号冲突 - 限时彩蛋: 仅在愚人节期间激活,不影响正常使用
- 抽卡机制: 累积分布函数实现的稀有度系统,1% 传说概率
28 - utils 模块源码分析
路径:
src/utils/根级文件数: 280+ 个.ts/.tsx文件 子目录数: 31 个 功能: 工具函数库 — 覆盖项目所有基础设施需求
模块概述
utils/ 是 Claude Code 中文件数量最多的模块,包含 280+ 个根级工具文件和 31 个子目录。
根级核心文件(按功能分类,仅列出已验证存在的文件)
Shell 与进程
| 文件 | 说明 |
|---|---|
Shell.ts | Shell 抽象层(exec/execStream/which) |
ShellCommand.ts | Shell 命令封装 |
execFileNoThrow.ts | 不抛异常的 execFile |
process.ts | 进程工具 |
genericProcessUtils.ts | 通用进程工具 |
gracefulShutdown.ts | 优雅关闭 |
cleanupRegistry.ts | 清理注册表(进程退出时资源释放) |
Git 操作
| 文件 | 说明 |
|---|---|
git.ts | Git 核心操作(status/branch/commit 等) |
gitDiff.ts | Git Diff 处理 |
gitSettings.ts | Git 配置 |
worktree.ts | Git Worktree 管理 |
getWorktreePaths.ts | Worktree 路径获取 |
detectRepository.ts | 仓库检测 |
ghPrStatus.ts | GitHub PR 状态 |
commitAttribution.ts | 提交归因 |
认证与安全
| 文件 | 说明 |
|---|---|
auth.ts | 认证核心 |
authFileDescriptor.ts | 认证文件描述符 |
authPortable.ts | 可移植认证 |
aws.ts | AWS 集成 |
awsAuthStatusManager.ts | AWS 认证状态 |
crypto.ts | 加密工具 |
mtls.ts | mTLS 配置 |
文件操作
| 文件 | 说明 |
|---|---|
file.ts | 文件基础操作 |
fileRead.ts | 文件读取(多格式支持) |
fileReadCache.ts | 文件读取缓存 |
fileHistory.ts | 文件历史追踪 |
fileStateCache.ts | 文件状态缓存 |
fileOperationAnalytics.ts | 文件操作分析 |
readFileInRange.ts | 范围读取 |
diff.ts | 差异计算 |
pdf.ts / pdfUtils.ts | PDF 处理 |
notebook.ts | Jupyter Notebook 处理 |
会话管理
| 文件 | 说明 |
|---|---|
sessionStorage.ts | 会话持久化 |
sessionRestore.ts | 会话恢复 |
sessionState.ts | 会话状态 |
sessionTitle.ts | 会话标题生成 |
sessionStart.ts | 会话启动 |
sessionActivity.ts | 会话活动追踪 |
sessionUrl.ts | 会话 URL |
listSessionsImpl.ts | 会话列表实现 |
crossProjectResume.ts | 跨项目恢复 |
Agent 与 AI
| 文件 | 说明 |
|---|---|
agentContext.ts | Agent 上下文 |
agentId.ts | Agent ID 管理 |
agenticSessionSearch.ts | Agent 会话搜索 |
teammate.ts | 队友管理 |
teammateContext.ts | 队友上下文 |
teammateMailbox.ts | 队友邮箱 |
sideQuery.ts | 侧查询(轻量级 LLM 调用) |
sideQuestion.ts | 侧问题 |
advisor.ts | 顾问 |
effort.ts | 推理努力级别 |
fastMode.ts | 快速模式 |
消息处理
| 文件 | 说明 |
|---|---|
messages.ts | 消息构建工具 |
messagePredicates.ts | 消息谓词(类型判断) |
messageQueueManager.ts | 消息队列管理 |
contentArray.ts | 内容数组工具 |
配置与设置
| 文件 | 说明 |
|---|---|
config.ts | 配置管理 |
configConstants.ts | 配置常量 |
envUtils.ts | 环境变量工具 |
claudemd.ts | CLAUDE.md 处理 |
cliArgs.ts | CLI 参数解析 |
钩子系统
| 文件 | 说明 |
|---|---|
hooks.ts | 钩子顶层工具(注意:执行引擎在 utils/hooks/ 子目录) |
格式化与显示
| 文件 | 说明 |
|---|---|
format.ts | 通用格式化 |
intl.ts | 国际化 |
markdown.ts | Markdown 处理 |
truncate.ts | 文本截断 |
sliceAnsi.ts | ANSI 切片 |
stringUtils.ts | 字符串工具 |
hyperlink.ts | 终端超链接 |
调试与日志
| 文件 | 说明 |
|---|---|
debug.ts | 调试日志 |
debugFilter.ts | 调试过滤 |
diagLogs.ts | 诊断日志 |
log.ts | 日志 |
errors.ts | 错误处理 |
errorLogSink.ts | 错误日志接收器 |
Token 与预算
| 文件 | 说明 |
|---|---|
tokenBudget.ts | Token 预算管理 |
tokens.ts | Token 工具 |
modelCost.ts | 模型费用计算 |
网络
| 文件 | 说明 |
|---|---|
http.ts | HTTP 请求 |
proxy.ts | 代理配置 |
caCerts.ts | CA 证书 |
peerAddress.ts | 对端地址 |
其他重要文件
| 文件 | 说明 |
|---|---|
lazySchema.ts | 懒加载 Schema(打破循环依赖) |
memoize.ts | 缓存/记忆化 |
frontmatterParser.ts | Frontmatter 解析 |
uuid.ts | UUID 生成 |
hash.ts | 哈希计算 |
json.ts | JSON 工具 |
sleep.ts | 延时 |
cron.ts / cronScheduler.ts / cronTasks.ts | 定时任务 |
glob.ts | Glob 匹配 |
ripgrep.ts | Ripgrep 搜索 |
platform.ts | 平台检测 |
terminal.ts | 终端工具 |
theme.ts | 主题 |
zodToJsonSchema.ts | Zod→JSON Schema 转换 |
xml.ts / yaml.ts | XML/YAML 工具 |
子目录(31 个)
| 目录 | 说明 |
|---|---|
hooks/ | 钩子执行引擎(17 文件:execPromptHook、execHttpHook、execAgentHook 等) |
permissions/ | 权限规则引擎 |
settings/ | 设置读写(三层合并:user/project/local) |
shell/ | Shell 提供者(bash/zsh/fish/powershell) |
bash/ | Bash 特定工具 |
powershell/ | PowerShell 特定工具 |
git/ | Git 扩展操作 |
github/ | GitHub API 集成 |
model/ | 模型工具(别名解析、能力查询) |
mcp/ | MCP 工具 |
memory/ | 记忆工具 |
messages/ | 消息工具 |
skills/ | 技能工具 |
plugins/ | 插件工具 |
todo/ | 待办列表工具 |
task/ | 任务管理工具 |
swarm/ | Swarm 模式(多 Agent 协作) |
suggestions/ | 提示建议 |
ultraplan/ | Ultraplan 工具 |
sandbox/ | 沙箱工具 |
computerUse/ | 计算机使用工具 |
claudeInChrome/ | Chrome 中的 Claude |
teleport/ | Teleport API 集成 |
secureStorage/ | 安全存储 |
filePersistence/ | 文件持久化 |
background/ | 后台任务(含 remote/ 子目录) |
deepLink/ | 深度链接 |
telemetry/ | 遥测工具 |
nativeInstaller/ | 原生安装器 |
dxt/ | 桌面扩展工具 |
processUserInput/ | 用户输入处理 |
之前文档中不存在的文件(已删除)
以下文件在 src/utils/ 中不存在,之前文档错误列出:
processManager.ts、killProcess.ts- ~~gitWorktreeworktree.ts`)、
gitBlame.ts、gitLog.ts fileWrite.ts、fileDiff.ts(实际是diff.ts)messageFormat.ts、messageSearch.tspermissionRules.ts、permissionMode.ts(在utils/permissions/子目录中)hookRunner.ts、hookContext.ts(在utils/hooks/子目录中)logForDebugging.ts(实际是debug.ts)、profiling.tstokenCount.ts、tokenEstimate.ts(实际是tokens.ts)websocket.ts、retry.ts(API 重试在services/api/withRetry.ts)
utils 模块 — 31 个工具子目录分类
路径:
src/utils/子目录数: 31 个 根级文件数: 280+ 总文件数: 500+
子目录清单(按功能分类)
Shell 与进程
| 目录 | 说明 |
|---|---|
shell/ | Shell 提供者(bash/zsh/fish/powershell 多 Shell 支持) |
bash/ | Bash 特定工具(命令解析、安全检查) |
powershell/ | PowerShell 特定工具 |
Git 与版本控制
| 目录 | 说明 |
|---|---|
git/ | Git 核心操作(status/branch/commit/diff/worktree/blame) |
github/ | GitHub API 集成(PR/Issue/App 安装) |
认证与安全
| 目录 | 说明 |
|---|---|
teleport/ | Teleport API 集成(OAuth API 调用) |
secureStorage/ | 安全存储(令牌加密存储) |
permissions/ | 权限规则引擎 |
文件与持久化
| 目录 | 说明 |
|---|---|
filePersistence/ | 文件持久化(原子写入、锁文件) |
消息与对话
| 目录 | 说明 |
|---|---|
messages/ | 消息构建、格式化、搜索、压缩辅助 |
processUserInput/ | 用户输入处理(解析、验证) |
AI 与 Agent
| 目录 | 说明 |
|---|---|
swarm/ | Swarm 模式(多 Agent 协作) |
memory/ | 记忆工具(记忆文件读写) |
suggestions/ | 提示建议生成 |
ultraplan/ | Ultraplan 工具(超级计划模式) |
配置与设置
| 目录 | 说明 |
|---|---|
settings/ | 设置读写(三层合并:user/project/local) |
hooks/ | 钩子执行引擎和运行器 |
skills/ | 技能工具(加载、解析) |
plugins/ | 插件工具(加载、验证) |
MCP 与工具
| 目录 | 说明 |
|---|---|
mcp/ | MCP 工具(客户端辅助、消息转换) |
todo/ | 待办列表工具 |
task/ | 任务管理工具 |
网络与通信
| 目录 | 说明 |
|---|---|
background/ | 后台任务(含 remote/ 子目录) |
deepLink/ | 深度链接处理 |
遥测与分析
| 目录 | 说明 |
|---|---|
telemetry/ | 遥测工具(OpenTelemetry 辅助) |
模型与 AI
| 目录 | 说明 |
|---|---|
model/ | 模型工具(别名解析、能力查询) |
安装与更新
| 目录 | 说明 |
|---|---|
nativeInstaller/ | 原生安装器(桌面应用安装) |
dxt/ | DXT 工具(桌面扩展) |
特殊功能
| 目录 | 说明 |
|---|---|
sandbox/ | 沙箱工具(环境隔离) |
computerUse/ | 计算机使用工具(屏幕操作) |
claudeInChrome/ | Chrome 中的 Claude 工具 |
根级核心文件(精选)
| 文件 | 说明 |
|---|---|
Shell.ts | Shell 抽象层(exec/execStream/which) |
ShellCommand.ts | Shell 命令封装 |
auth.ts | 认证核心 |
config.ts | 配置管理 |
envUtils.ts | 环境变量工具(isEnvTruthy 等) |
debug.ts | 调试日志 |
format.ts | 通用格式化 |
lazySchema.ts | 懒加载 Schema(打破循环依赖) |
memoize.ts | 缓存/记忆化 |
retry.ts | 重试逻辑 |
frontmatterParser.ts | Frontmatter 解析 |
sessionStorage.ts | 会话持久化 |
sessionRestore.ts | 会话恢复 |
fileRead.ts | 文件读取(多格式) |
fileHistory.ts | 文件历史追踪 |
tokenBudget.ts | Token 预算管理 |
proxy.ts | 代理配置 |
mtls.ts | mTLS 配置 |
cleanupRegistry.ts | 清理注册表(进程退出时资源释放) |
agentContext.ts | Agent 上下文 |
teammate.ts | 队友管理 |
sideQuery.ts | 侧查询(轻量级 LLM 调用) |
29 - native-ts 模块源码分析
路径:
src/native-ts/文件数: ~10 个 功能: 纯 TypeScript 原生实现 — 文件索引、Yoga 布局引擎、颜色 Diff
模块概述
native-ts/ 包含三个高性能的纯 TypeScript 实现,替代了原本需要原生 C/C++ 绑定的功能。这种设计选择优先考虑可移植性和零依赖安装体验。
1. file-index/ — 模糊文件搜索引擎
index.ts (370 行)
功能概述
实现 nucleo 风格的模糊文件搜索,使用位图过滤实现 O(1) 快速拒绝,支持边界/驼峰加分和间隔惩罚。
导出
FileIndex类
核心算法
class FileIndex {
private files: string[]
private bitmaps: Uint32Array[] // 每个文件的字符位图
constructor(files: string[]) {
this.files = files
// 预计算每个文件的字符位图
this.bitmaps = files.map(f => computeBitmap(f))
}
search(query: string, topK: number = 20): SearchResult[] {
const queryBitmap = computeBitmap(query)
const results: SearchResult[] = []
for (let i = 0; i < this.files.length; i++) {
// Phase 1: 位图快速拒绝 — O(1)
// 如果查询中的字符不全在文件名中出现,直接跳过
if ((queryBitmap & ~this.bitmaps[i]) !== 0) continue
// Phase 2: 融合 indexOf 扫描
const score = this.computeScore(query, this.files[i])
if (score > 0) {
results.push({ file: this.files[i], score })
}
}
// Top-K 堆维护
return topKHeap(results, topK)
}
}
评分规则
评分语义:分数越低越好(lower = better)。分数是 position-in-results / result-count,最佳匹配为 0.0。包含 “test” 的路径有 1.05× 惩罚(上限 1.0),使非测试文件排名略高。
内部使用 nucleo 风格的评分常量:
| 常量 | 值 | 说明 |
|---|---|---|
SCORE_MATCH | 16 | 基础匹配分 |
BONUS_BOUNDARY | +8 | 单词边界匹配 |
BONUS_CAMEL | +6 | 驼峰位置匹配 |
BONUS_CONSECUTIVE | +4 | 连续字符匹配 |
BONUS_FIRST_CHAR | +8 | 首字符匹配 |
PENALTY_GAP_START | -3 | 间隔惩罚 |
智能大小写
// 全小写查询 → 大小写不敏感
// 包含大写 → 大小写敏感
const caseSensitive = query !== query.toLowerCase()
2. color-diff/ — 语法高亮差异
index.ts (999 行)
功能概述
实现带语法高亮的代码差异显示,使用懒加载的 highlight.js 避免 50MB+ 的包体积。
导出
ColorDiff类
核心架构
ColorDiff
├── 懒加载 highlight.js(避免 50MB 包体积)
├── 词级别差异(word-level diffing)
├── ANSI 颜色渲染
│ ├── truecolor 模式(24-bit)
│ ├── color256 模式(8-bit)
│ └── ansi 模式(16 色)
└── 行级别 + 词级别混合差异
懒加载策略
class ColorDiff {
private hljs: HighlightJS | null = null
private async getHighlighter(): Promise<HighlightJS> {
if (!this.hljs) {
// 动态导入,避免启动时加载 50MB+
const { default: hljs } = await import('highlight.js')
this.hljs = hljs
}
return this.hljs
}
}
词级别差异
// 不是简单的行级别 diff,而是在行内进一步做词级别 diff
// 这样可以精确高亮行内的具体变更
function wordDiff(oldLine: string, newLine: string): DiffSegment[] {
const oldWords = tokenize(oldLine)
const newWords = tokenize(newLine)
return computeLCS(oldWords, newWords) // 最长公共子序列
}
3. yoga-layout/ — Flexbox 布局引擎
enums.ts (134 行)
功能概述
定义 Yoga 布局引擎的枚举常量,使用 const 对象而非 TypeScript enum 以支持 tree-shaking。
// 使用 const 对象而非 enum,支持 tree-shaking
export const Align = {
Auto: 0,
FlexStart: 1,
Center: 2,
FlexEnd: 3,
Stretch: 4,
Baseline: 5,
SpaceBetween: 6,
SpaceAround: 7,
SpaceEvenly: 8,
} as const
export const Edge = {
Left: 0,
Top: 1,
Right: 2,
Bottom: 3,
Start: 4,
End: 5,
Horizontal: 6,
Vertical: 7,
All: 8,
} as const
export const FlexDirection = {
Column: 0,
ColumnReverse: 1,
Row: 2,
RowReverse: 3,
} as const
// Display, Justify, Overflow, Position, Wrap 等...
index.ts (2578 行)
功能概述
Yoga Flexbox 布局引擎的简化 TypeScript 移植,覆盖 Ink 实际使用的子集,不是完整的 Meta Yoga 全量移植。源码注释明确说明:“simplified single-pass flexbox implementation that covers the subset of features Ink actually uses”。
核心特性
class Node {
// 脏标志系统 — 只重新计算变更的节点
private isDirty: boolean = true
// 4 条目布局缓存 — 避免重复计算
private layoutCache: LayoutCache = new Array(4)
// 9 边模型折叠为 4 物理边
// Edge: Left, Top, Right, Bottom, Start, End, Horizontal, Vertical, All
// → 物理: left, top, right, bottom
private resolveEdge(edge: Edge): PhysicalEdge
// Flexbox 布局计算
calculateLayout(
availableWidth: number,
availableHeight: number,
direction: Direction
void
}
Value 类型
type Value = {
value: number
unit: 'point' | 'percent' | 'auto' | 'undefined'
}
function resolveValue(value: Value, parentSize: number): number {
switch (value.unit) {
case 'point': return value.value
case 'percent': return value.value / 100 * parentSize
case 'auto': return NaN // 由布局算法决定
case 'undefined': return NaN
}
}
布局算法核心
calculateLayout(node, availableWidth, availableHeight)
│
├── 检查缓存(4 条目)
│ └── 命中 → 直接返回
│
├── 解析 margin, padding, border
│
├── 确定主轴和交叉轴
│ ├── row → 主轴=水平, 交叉轴=垂直
│ └── column → 主轴=垂直, 交叉轴=水平
│
├── 测量子节点
│ ├── 固定尺寸子节点 → 直接使用
│ ├── flex 子节点 → 按 flex-grow/shrink 分配
│ └── auto 子节点 → 递归计算
│
├── 主轴布局
│ ├── justify-content 对齐
│ └── 分配剩余空间
│
├── 交叉轴布局
│ ├── align-items 对齐
│ └── align-self 覆盖
│
├── 写入布局结果
│ ├── left, top, width, height
│ └── 递归写入子节点
│
└── 更新缓存
设计哲学
- 零原生依赖: 纯 TypeScript 实现避免了 node-gyp 编译问题和平台兼容性问题
- 懒加载: highlight.js 等重依赖按需加载,不影响启动速度
- const 对象 vs enum: 使用
as const对象替代 TypeScript enum,支持 tree-shaking 减小包体积 - 位图优化: 文件索引使用位图实现 O(1) 快速拒绝,大幅减少不必要的字符串比较
- 缓存策略: Yoga 布局使用 4 条目缓存 + 脏标志,避免重复计算
30 - memdir 模块源码分析
路径:
src/memdir/文件数: 8 个 功能: 自动记忆系统 — 跨会话的持久化记忆,支持私有记忆和团队记忆
模块概述
memdir/ 实现了 Claude Code 的自动记忆系统,允许 AI 在会话间保持对用户偏好、项目上下文和反馈的记忆。记忆存储在 ~/.claude/projects/<project>/memory/ 目录中。支持双作用域架构(私有 + 团队),AI 驱动的相关记忆检索,以及多层安全防护。
文件详解
1. paths.ts — 路径管理与特性开关
行数: 279 行
导出
isAutoMemoryEnabled()— 检查自动记忆是否启用isExtractModeActive()— 检查后台提取 Agent 是否激活getMemoryBaseDir()— 获取记忆基础目录getAutoMemPath()— 获取自动记忆目录路径(memoized)getAutoMemDailyLogPath(date?)— 获取 KAIROS 模式的每日日志路径getAutoMemEntrypoint()— 获取 MEMORY.md 路径isAutoMemPath(absolutePath)— 检查路径是否在记忆目录内hasAutoMemPathOverride()— 检查 Cowork 覆盖是否设置
启用优先级链(5 级)
1. 环境变量 CLAUDE_CODE_DISABLE_AUTO_MEMORY
2. SIMPLE 模式检查
3. CCR 远程环境检查
4. settings.json 中的 autoMemory 设置
5. 默认值: true
路径解析优先级
1. CLAUDE_COWORK_MEMORY_PATH_OVERRIDE 环境变量
2. settings.json 中的 autoMemoryDirectory 设置(支持 ~/ 展开)
3. 计算路径: baseDir + sanitized(git root)
安全验证
function validateMemoryPath(path: string): void {
// 拒绝: 相对路径、根路径、UNC 路径、null 字节
if (path.includes('\0')) throw new Error('Null byte in path')
if (!isAbsolute(path)) throw new Error('Relative path')
if (path === '/') throw new Error('Root path')
// ...
}
设计亮点
- Worktree 共享: 使用 canonical git root,所以 worktree 共享同一份记忆
- 安全边界: projectSettings 不允许设置路径覆盖(防止恶意项目配置)
2. memoryTypes.ts — 记忆类型分类学
行数: 272 行
四种记忆类型
| 类型 | 作用域 | 说明 | 示例 |
|---|---|---|---|
user | 始终私有 | 用户角色、偏好、知识 | “用户是高级 Go 开发者,React 新手” |
feedback | 默认私有 | 用户对工作方式的反馈 | “不要在回复末尾总结” |
project | 偏向团队 | 项目进展、目标、截止日期 | “3月5日起冻结非关键合并” |
reference | 通常团队 | 外部系统资源指针 | “Bug 追踪在 Linear INGEST 项目” |
不应保存的内容
- 代码模式/架构(可从代码推导)
- Git 历史(git log 可查)
- 调试解决方案(修复在代码中)
- CLAUDE.md 中已有的内容
- 临时任务详情
导出的提示词模板
TYPES_SECTION_COMBINED— 带<scope>标签的双目录版本TYPES_SECTION_INDIVIDUAL— 单目录版本WHAT_NOT_TO_SAVE_SECTION— 排除指导MEMORY_DRIFT_CAVEAT— 过期警告文本WHEN_TO_ACCESS_SECTION— 访问时机指导TRUSTING_RECALL_SECTION— 召回信任指导MEMORY_FRONTMATTER_EXAMPLE— frontmatter 格式示例
3. memdir.ts — 记忆系统主编排器
行数: 508 行
导出
ENTRYPOINT_NAME = 'MEMORY.md'MAX_ENTRYPOINT_LINES = 200MAX_ENTRYPOINT_BYTES = 25600(25KB)truncateEntrypointContent()— 强制大小限制ensureMemoryDirExists()— 创建目录结构buildMemoryLines()— 构建提示词行buildMemoryPrompt()— 构建完整提示词loadMemoryPrompt()— 主入口,按特性分发
特性分发逻辑
loadMemoryPrompt()
├── KAIROS 模式? → 每日追加日志模式
├── TEAMMEM 启用? → 双目录联合提示词
└── 默认 → 单目录个人提示词
MEMORY.md 截断
function truncateEntrypointContent(content: string, filePath: string) {
// 强制 200 行 AND 25KB 上限
// 超出时添加警告横幅
ifth > MAX_ENTRYPOINT_LINES) {
return {
content: lines.slice(0, MAX_ENTRYPOINT_LINES).join('\n'),
truncation: { originalLines: lines.length, keptLines: MAX_ENTRYPOINT_LINES }
}
}
}
遥测日志
memory_directory_used— 记忆目录被使用memory_directory_created— 记忆目录被创建memory_entrypoint_truncated— MEMORY.md 被截断
4. memoryScan.ts — 记忆目录扫描
行数: 95 行
导出
MemoryHeader类型 —{ filename, filePath, mtimeMs, description, type }scanMemoryFiles(memoryDir, signal)— 扫描记忆文件头formatMemoryManifest(memories)— 格式化为文本清单
扫描优化
async function scanMemoryFiles(memoryDir: string): Promise<MemoryHeader[]> {
// 递归读取目录
const entries = await readdir(memoryDir, { recursive: true })
// 过滤 .md 文件,排除 MEMORY.md
const mdFiles = entries.filter(e => e.endsWith('.md') && e !== 'MEMORY.md')
// 只读取每个文件的前 30 行(frontmatter)
// readFileInRange 内部 stat 返回 mtimeMs,避免二次 stat
const headers = await Promise.allSettled(
mdFiles.map(f => readFirstLines(f, 30))
)
// 按修改时间降序排序,取前 200 个
return headers
.filter(h => h.status === 'fulfilled')
.sort((a, b) => b.mtimeMs - a.mtimeMs)
.slice(0, 200)
}
清单格式
- [user] user_role.md (2026-03-15): 数据科学家,关注可观测性
- [feedback] feedback_testing.md (2026-03-10): 集成测试必须用真实数据库
5. findRelevantMemories.ts — AI 驱动的记忆检索
行数: 142 行
导出
RelevantMemory类型 —{ filePath, mtimeMs }findRelevantMemories(memoryDir, conversationText, alreadySurfaced, signal)— 检索相关记忆
核心流程
扫描记忆目录 (scanMemoryFiles)
↓
过滤已展示的记忆 + 活跃工具的参考文档
↓
格式化为文本清单
↓
调用 Sonnet 模型 (sideQuery)
├── 系统提示: SELECT_MEMORIES_SYSTEM_PROMPT
├── 用户消息: 对话文本 + 记忆清单
└── 输出格式: JSON Schema (最多 5 个文件名)
↓
映射文件名回完整路径 + mtime
↓
返回 Rey[]
错误处理
- 失败时返回空数组(不抛异常)
- 优雅降级,不影响主对话流程
6. memoryAge.ts — 记忆时效性
行数: 54 行
导出
memoryAgeDays(mtimeMs)— 计算天数memoryAge(mtimeMs)— 人类可读的年龄(“today”/“yesterday”/“N days ago”)memoryFreshnessText(mtimeMs)— 过期警告文本memoryFreshnessNote(mtimeMs)— 格式化的过期注释
逻辑
// ≤1 天: 无警告
// >1 天: "This memory is from [age] and may be outdated"
// 防止模型将过期的代码引用当作当前事实
7. teamMemPaths.ts — 团队记忆路径(安全加固)
行数: 293 行
导出
PathTraversalError— 自定义错误类isTeamMemoryEnabled()— 团队记忆是否启用getTeamMemPath()— 团队记忆目录路径validateTeamMemWritePath(filePath)— 写入路径验证validateTeamMemKey(relativeKey)— 服务器提供的 key 验证isTeamMemFile(filePath)— 综合检查
多层安全防护(PSR M22186)
第 1 层: 字符串级别
├── 拒绝 null 字节
├── 拒绝 URL 编码遍历 (%2e%2e%2f)
├── 拒绝 Unicode 规范化攻击(全角字符)
├── 拒绝反斜杠
└── 拒绝绝对路径
第 2 层: 符号链接解析
├── realpathDeepestExisting() 向上遍历解析
├── 检测悬空符号链接 (lstat)
└── 真实路径包含性检查
启用条件
function isTeamMemoryEnabled(): boolean {
return isAutoMemoryEnabled() // 自动记忆已启用
&& checkFeatureFlag('tengu_herring_clock') // 特性标志
}
8. teamMemPrompts.ts — 团队记忆提示词构建
行数: 101 行
导出
buildCombinedMemoryPrompt()— 构建双目录联合提示词
提示词结构
1. 双目录说明(私有 vs 团队)
2. 作用域指导(私有: 用户特定, 团队: 共享)
3. 类型分类(带 <scope> 标签)
4. 排除指导 + 团队记忆安全警告
5. 保存方法(两步: 写文件 + 更新 MEMORY.md 索引)
6. 访问时机
7. 记忆 vs 其他持久化(计划、任务)
8. 搜索过往上下文(grep 指导)
架构总结
memdir/
├── 配置层
│ ├── paths.ts ← 路径解析 + 特性开关(5 级优先级)
│ └── memoryTypes.ts ← 类型分类学 + 提示词模板
│
├── 核心层
│ ├── memdir.ts ← 主编排器(特性分发 + 提示词构建)
│ ├── memoryScan.ts ← 目录扫描(前 30 行 frontmatter)
│ └── findRelevantMemories.ts ← AI 驱动的相关性检索(Sonnet)
│
├── 安全层
│ ├── teamMemPaths.ts ← 多层路径遍历防护(PSR M22│ └── memoryAge.ts ← 时效性警告(防止过期引用)
│
└── 团队层
└── teamMemPrompts.ts ← 双目录联合提示词构建
关键设计决策
- 双作用域: 私有记忆(用户偏好)和团队记忆(项目知识)分离
- AI 检索: 使用 Sonnet 模型智能选择相关记忆,而非全量加载
- 安全加固: 多层路径遍历防护,防止恶意项目配置攻击
- Worktree 共享: 使用 canonical git root,worktree 共享记忆
- 优雅降级: 所有错误返回空结果,不影响主流程
- 大小限制: MEMORY.md 强制 200 行 / 25KB 上限
31 - migrations 模块源码分析
路径:
src/migrations/文件数: 11 个 功能: 配置迁移 — 跨版本的配置格式升级,确保向后兼容
模块概述
migrations/ 处理 Claude Code 跨版本升级时的配置格式迁移。每个迁移文件是一个幂等函数,在应用启动时按需执行。迁移覆盖了从权限配置、模型别名到 MCP 服务器审批等多个领域。
迁移文件详解
1. migrateAutoUpdatesToSettings.ts
行数: 62 行
功能
将自动更新偏好从全局配置迁移到 settings.json 环境变量。
迁移逻辑
旧: globalConfig.autoUpdates = false
新: settings.json → env.DISABLE_AUTOUPDATER = '1'
步骤
- 检查
autoUpdates是否显式为 false - 读取用户设置,添加
DISABLE_AUTOUPDATER: '1'到 env - 立即设置
process.env使其即时生效 - 从全局配置中删除
autoUpdates和autoUpdatesProtectedForNative - 记录分析事件
2. migrateBypassPermissionsAcceptedToSettings.ts
行数: 41 行
功能
将权限绕过接受标志从全局配置迁移到 settings.json。
旧: globalConfig.bypassPermissionsModeAccepted = true
新: settings.json → skipDangerousModePermissionPrompt: true
3. migrateEnableAllProjectMcpServersToSettings.ts
行数: 119 行
功能
将 MCP 服务器审批字段从项目配置迁移到本地设置。
迁移字段
| 旧字段 | 新位置 |
|---|---|
enableAllProjectMcpServers | local settings |
enabledMcpjsonServers | local settings(数组合并去重) |
disabledMcpjsonServers | local settings(数组合并去重) |
特殊处理
- 数组字段使用合并去重策略,避免覆盖已有配置
- 记录迁移数量到分析事件
4. migrateFennecToOpus.ts
行数: 46 行
功能
将已移除的 fennec 模型别名迁移到 Opus 4.6 别名(仅内部用户)。
映射规则
fennec-latest[1m] → opus[1m]
fennec-latest → opus
fennec-fast-latest → opus[1m] + fastMode: true
opus-4-5-fast → opus[1m] + fastMode: true
条件
- 仅
USER_TYPE === 'ant'(Anthropic 内部用户)
5. migrateLegacyOpusToCurrent.ts
行数: 58 行
功能
将第一方用户从显式 Opus 4.0/4.1 版本字符串迁移到 ‘opus’ 别名(解析为 4.6)。
匹配的旧值
claude-opus-4-20250514
claude-opus-4-1-20250805
claude-opus-4-0
claude-opus-4-1
迁移结果
所有上述值 → model: 'opus'
条件
- 仅 firstParty API 提供者
- 仅启用了 legacy remap 的用户
6. migrateOpusToOpus1m.ts
行数: 44 行
功能
将符合条件的用户(Max/Team Premium)从 ‘opus’ 迁移到 ‘opus[1m]’,用于合并的 Opus 1M 体验。
条件
- Opus 1M 合并已启用
- 用户设置的模型恰好是 ‘opus’
- Pro 订阅者和第三方用户跳过
7. migrateReplBridgeEnabledToRemoteControlAtStartup.ts
行数: 23 行(最小的迁移)
功能
重命名配置键。
旧: globalConfig.replBridgeEnabled
新: globalConfig.remoteControlAtStartup
特殊处理
- 使用 untyped cast 访问旧键(已从类型定义中移除)
- 仅在旧键存在且新键不存在时迁移
8. migrateSonnet1mToSonnet45.ts
行数: 49 行
功能
将 ‘sonnet[1m]’ 用户固定到显式版本 ‘sonnet-4-5-20250929[1m]’(因为 ‘sonnet’ 现在解析为 4.6)。
迁移逻辑
sonnet[1m] → sonnet-4-5-20250929[1m]
特殊处理
- 同时迁移内存中的模型覆盖(
getMainLoopModelOverride) - 使用完成标志
sonnet1m45MigrationComplete防止重复执行
9. migrateSonnet45ToSonnet46.ts
行数: 68 行
功能
将 Pro/Max/Team Premium 用户从显式 Sonnet 4.5 字符串迁移到 ‘sonnet’ 别名(现在是 4.6)。
匹配的旧值
claude-sonnet-4-5-20250929 → sonnet
claude-sonnet-4-5-20250929[1m] → sonnet[1m]
sonnet-4-5-20250929 → sonnet
sonnet-4-5-20250929[1m] → sonnet[1m]
条件
- 仅 firstParty Pro/Max/Team Premium 订阅者
- 新用户(numStartups ≤ 1)跳过通知
10. resetAutoModeOptInForDefaultOffer.ts
行数: 52 行
功能
一次性迁移:为接受了旧对话框但默认模式不是 ‘auto’ 的用户清除 skipAutoPermissionPrompt。
条件
TRANSCRIPT_CLASSIFIER特性已启用- 自动模式状态为 ‘enabled’
- 用户有
skipAutoPermissionPrompt但默认模式不是 ‘auto’
11. resetProToOpusDefault.ts
行数: 52 行
功能
自动将 Pro 用户迁移到 Opus 4.5 默认模型。
逻辑
- 无自定义模型设置 → 保存
opusProMigrationTimestamp(用于通知) - 有自定义模型设置 → 仅标记迁移完成
通用模式
1. 幂等性保证
// 大多数迁移使用完成标志
const config = getGlobalConfig()
if (config.migrationXComplete) return // 已执行过,跳过
// ... 执行迁移 ...
saveGlobalConfig({ ...config, migrationXComplete: true })
2. 条件执行
// 按用户类型、订阅、API 提供者过滤
if (getAPIProvider() !== 'firstParty') return
if (!isProSubscriber()) return
3. 分析追踪
// 所有迁移记录分析事件
logEvent('migration_x_completed', { originalModel, newModel })
logEvent('migration_x_error', { error: e.message })
4. 错误处理
try {
// 迁移逻辑
} catch (e) {
logError('Migration failed', e)
// 不抛出 — 迁移失败不应阻止应用启动
}
迁移执行时机
应用启动 (setup.ts)
↓
按顺序检查每个迁移
├── 检查完成标志
├── 检查前置条件(用户类型、订阅等)
└── 执行迁移(如需要)
↓
所有迁移完成
↓
继续正常启动流程
32 - tasks 模块源码分析
路径:
src/tasks/文件数: 12 个 功能: 后台任务管理 — 7 种任务类型的完整生命周期管理
模块概述
tasks/ 实现了 Claude Code 的后台任务系统,使用 discriminated union 架构统一管理 7 种任务类型。每种任务类型有独立的状态接口、类型守卫、React 组件和生命周期函数。
架构总览
TaskState (discriminated union)
├── LocalShellTask — 本地 Shell 命令 (type: 'local_bash')
├── LocalAgentTask — 本地子 Agent (type: 'local_agent')
├── RemoteAgentTask — 远程 Agent (type: 'remote_agent')
├── InProcessTeammate — 进程内队友 (type: 'in_process_teammate')
├── LocalMainSession — 本地主会话后台化 (type: 'local_main_session')
├── DreamTask — 后台推理/记忆整合 (type: 'dream')
└── MonitorMcpTask — MCP 监控 (type: 'monitor_mcp')
核心文件
1. types.ts — 类型统一
行数: 47 行
// 所有任务类型的 discriminated union
type TaskState =
| LocalShellTaskState
| LocalAgentTaskState
| RemoteAgentTaskState
| InProcessTeammateTaskState
| LocalMainSessionTaskState
| DreamTaskState
| MonitorMcpTaskState
// 后台任务(运行中或待处理 + 已后台化)
type BackgroundTaskState = TaskState
function isBackgroundTask(task: TaskState): boolean {
return (task.status === 'running' || task.status === 'pending')
&& task.isBackgrounded
}
2. stopTask.ts — 任务终止
行数: 101 行
导出
StopTaskError— 自定义错误类stopTask(appState, taskId)— 通用任务终止函数
逻辑
async function stopTask(appState: AppState, taskId: string): Promise<void> {
// 1. 验证任务存在且正在运行
const task = findTask(appState, taskId)
if (!task) throw new StopTaskError('Task not found')
if (task.status !== 'running') throw new StopTaskError('Task not running')
// 2. 调用任务特定的 kill 实现
await task.kill()
// 3. Shell 任务: 抑制 exit code 137 的噪音通知
if (isLocalShellTask(task) && task.exitCode === 137) {
suppressNotification(task)
}
// 4. 发送 SDK 事件
emitTaskTerminatedSdk(task)
}
3. pillLabel.ts — 任务标签 UI
行数: 83 行
功能
为底部状态栏的后台任务药丸标签生成紧凑文本。
// 类型特定标签
"1 shell" // 1 个 Shell 任务
"2 teams" // 2 个队友任务
"◇ ultraplan" // ultraplan 阶段(空心钻石 = 等待输入)
"◆ ultraplan" // ultraplan 阶段(实心钻石 = 计划就绪)
任务类型详解
4. DreamTask — 后台推理/记忆整合
行数: 158 行
功能
在用户不活跃时,AI 在后台进行记忆整合和推理。
状态
interface DreamTaskState extends TaskStateBase {
type: 'dream'
phase: DreamPhase // 'starting' | 'updating'
turns: DreamTurn[] // 最近 30 轮(用于实时显示)
touchedFiles: string[] // 通过 Edit/Write 触及的文件
}
生命周期
registerDreamTask()
↓
phase: 'starting'
↓ (首次工具调用)
phase: 'updating'
↓ (追踪 EdWrite 的文件)
addDreamTurn(turn) // 保留最近 30 轮
↓
completeDreamTask() 或 failDreamTask()
清理
注册到 cleanup 系统,通过 AbortController 处理中止。
5. LocalMainSessionTask — 主会话后台化
行数: 480 行
功能
支持用户按 Ctrl+B 两次将当前主会话查询后台化,继续在前台进行新对话。
关键设计
// 任务 ID 使用 's' 前缀(vs Agent 的 'a' 前缀)
const taskId = 's' + generateId()
// 隔离的 transcript 文件,防止 /clear 后损坏
const transcriptFile = createIsolatedTranscript()
生命周期
用户按 Ctrl+B 两次
↓
registerMainSessionTask()
├── 创建隔离 transcript
├── 保存当前消息上下文
└── 启动后台查询
↓
后台运行中...
↓
foregroundMainSessionTask() // 用户选择前台化
├── 恢复消息到主对话
└── 继续交互
6. InProcessTeammateTask — 进程内队友
行数: 122 行 (types) + 126 行 (component)
功能
支持多个 AI Agent 在同一进程内协作(Swarm 模式)。
身份系统
interface TeammateIdentity {
agentId: AgentId
agentName: string
teamName: string
color: string // UI 区分颜色
planModeRequired: boolean // 是否需要计划模式审批
parentSessionId: string
}
消息上限
const TEAMMATE_MESSAGES_UI_CAP = 50
// 防止 36.8GB 内存膨胀
function appendCappedMessage(messages: Message[], msg: Message): Message[] {
if (messages.length >= TEAMMATE_MESSAGES_UI_CAP) {
return [...messages.slice(1), msg] // FIFO
}
return [...messages, msg]
}
隔离机制
- 使用
AsyncLocalStorage实现并发 Agent 隔离 - 邮箱消息系统用于 Agent 间通信
- 优雅关闭:处理待处理消息后再停止
7. LocalShellTask — Shell 命令执行
行数: 42 行 (guards) + 77 行 (kill) + 522 行 (component)
卡住检测
const STALL_THRESHOLD = 45_000 // 45 秒
const STALL_CHECK_INTERVAL = 5_000 // 每 5 秒检查
function isShellTaskStalled(task: LocalShellTaskState): boolean {
// 检测交互式提示模式
const interactivePatterns = [
/\(y\/n\)/,
/\[y\/n\]/,
/Press any key|Enter password/,
]
return task.lastOutputAge > STALL_THRESHOLD
|| interactivePatterns.some(p => p.test(task.lastOutput))
}
任务种类
type BashTaskKind = 'bash' | 'monitor'
// bash: 标准命令,有完成通知
// monitor: 流式输出,无完成通知(如 tail -f)
僵尸进程清理
// 防止 10 天僵尸进程
function killShellTasksForAgent(agentId: AgentId): void {
// 终止该 Agent 的所有 Shell 任务
// 清除排队的通知
// 驱逐任务输出缓存
}
8. LocalAgentTask — 本地子 Agent
行数: 682 行
功能
管理本地子 Agent 执行,包括进度追踪、消息队列和磁盘输出。
进度追踪
interface ProgressTracker {
inputTokens: number
outputTokens: number
cacheReadTokens: number
toolActivities: ToolActivity[] // 工具活动列表
startTime: number
lastActivityTime: number
}
interface ToolActivity {
toolName: string
description: string
timestamp: number
}
消息队列
// 后台 Agent 的消息队列
function appendMessageToLocalAgent(taskId: string, message: Message): void
function drainPendingMessages(taskId: string): Message[]
磁盘输出
// 输出写入磁盘文件,带驱逐策略
// 防止内存膨胀
const outputFile = createTempFile(`agent-${taskId}.jsonl`)
9. RemoteAgentTask — 远程 Agent
行数: 855 行(最大的任务文件)
远程任务类型
type RemoteTaskType =
| 'remote-agent' // 通用远程 Agent
| 'ultraplan' // 超级计划
| 'ultrareview' // 超级审查
| 'autofix-pr' // 自动修复 PR
| 'background-pr' // 后台 PR
前置条件检查
registerRemoteAgentTask()
↓
前置条件验证:
├── 用户已登录?
├── 远程环境可用?
├── 在 Git 仓库中?
├── 有 GitHub 远程?
└── GitHub App 已安装?
↓
全部通过 → 创建远程会话
任一失败 → 显示错误 + 修复指导
Ultraplan 阶段追踪
// Ultraplan 有特殊的阶段状态
type UltraplanPhase =
| 'needs_input' // 等待用户输入(◇ 空心钻石)
| 'plan_ready' // 计划就绪(◆ 实心钻石)
| 'executing' // 执行中
元数据持久化
// 元数据保存到会话 sidecar 文件
// 支持跨会话恢复远程任务状态
persistMetadata(taskId, { remoteSessionId, status, phase })
通用设计模式
1. TaskStateBase 基础接口
interface TaskStateBase {
id: string
type: string
status: 'pending' | 'running' | 'completed' | 'failed' | 'killed'
isBackgrounded: boolean
startTime: number
endTime?: number
error?: string
}
2. 每种任务类型的标准导出
// 类型守卫
export function isXxxTask(task: TaskState): task is XxxTaskState
// 生命周期函数
export function registerXxxTask(params): void
export function backgroundXxxTask(taskId): void
export function foregroundXxxTask(taskId): void
// React 组件
export function XxxTask(props): JSX.Element
3. AbortController 取消机制
所有长时间运行的任务都使用 AbortController,支持优雅取消。
4. 清理注册
所有任务注册到 cleanup 系统,确保进程退出时资源被正确释放。
模块依赖关系
tasks/
├── types.ts ← 所有任务状态类型
├── stopTask.ts ← 通用终止逻辑
├── pillLabel.ts ← UI 标签
│
├── DreamTask/ ← 后台推理
├── LocalMainSessionTask/ ← 主会话后台化
├── InProcessTeammateTask/ ← 队友协作
│ ├── types.ts
│ └── InProcessTeammateTask.tsx
├── LocalShellTask/ ← Shell 命令
│ ├── guards.ts
│ ├── killShellTasks.ts
│ LocalShellTask.tsx
├── LocalAgentTask/ ← 本地 Agent
│ └── LocalAgentTask.tsx
└── RemoteAgentTask/ ← 远程 Agent
└── RemoteAgentTask.tsx
tasks 模块 — 5 个任务类型子目录
路径:
src/tasks/子目录: DreamTask/, InProcessTeammateTask/, LocalAgentTask/, LocalShellTask/, RemoteAgentTask/
1. DreamTask/ — 后台推理/记忆整合
文件: DreamTask.ts (158 行)
interface DreamTaskState extends TaskStateBase {
type: 'dream'
phase: 'starting' | 'updating'
turns: DreamTurn[] // 最近 30 轮
touchedFiles: string[] // Edit/Write 触及的文件
}
生命周期: registerDreamTask() → phase:starting → 首次工具调用 → phase:updating → completeDreamTask()
2. InProcessTeammateTask/ — 进程内队友协作
文件: types.ts (122 行) + InProcessTeammateTask.tsx (126 行)
interface TeammateIdentity {
agentId: AgentId
agentName: string // 如 "reviewer"
teamName: string // 如 "code-review-team"
color: string // UI 区分颜色
planModeRequired: boolean
parentSessionId: string
}
- 消息上限 50 条(FIFO,防 36.8GB 内存膨胀)
AsyncLocalStorage实现并发 Agent 隔离- 邮箱消息系统用于 Agent 间通信
3. LocalShellTask/ — Shell 命令执行
文件: guards.ts (42 行) + killShellTasks.ts (77 行) + LocalShellTask.tsx (522 行)
type BashTaskKind = 'bash' | 'monitor'
// bash: 标准命令,有完成通知
// monitor: 流式输出,无完成通知(如 tail -f)
- 卡住检测: 45 秒阈值,每 5 秒检查
- 交互式提示模式检测:
(y/n),[y/n],Press any key,Enter password - 僵尸进程清理:
killShellTasksForAgent()防止 10 天僵尸
4. LocalAgentTask/ — 本地子 Agent
文件: LocalAgentTask.tsx (682 行)
interface ProgressTracker {
inputTokens: number
outputTokens: number
toolActivities: ToolActivity[]
startTime: number
lastActivityTime: number
}
- Token 计数(input + output,缓存感知)
- 消息队列(后台 Agent 的 pending messages)
- 磁盘输出(JSONL 文件,带驱逐策略)
- AbortController 取消
5. RemoteAgentTask/ — 远程 Agent(最大,855 行)
文件: RemoteAgentTask.tsx (855 行)
type RemoteTaskType =
| 'remote-agent' // 通用远程
| 'ultraplan' // 超级计划
| 'ultrareview' // 超级审查
| 'autofix-pr' // 自动修复 PR
| 'background-pr' // 后台 PR
前置条件检查链:
登录? → 远程环境? → Git 仓库? → GitHub 远程? → GitHub App?
Ultraplan 阶段: needs_input(◇) → plan_ready(◆) → executing
元数据持久化到会话 sidecar 文件,支持跨会话恢复。
33 - upstreamproxy 模块源码分析
路径:
src/upstreamproxy/文件数: 2 个 功能: 上游代理 — CCR 环境中的 CONNECT-over-WebSocket 代理隧道
模块概述
upstreamproxy/ 实现了 CCR(Claude Code Remote)环境中的上游代理系统。当 Claude Code 在远程容器中运行时,工具(如 curl、gh、kubectl)的 HTTPS 请求需要通过代理隧道转发,由服务端注入组织配置的凭证(如 DD-API-KEY)。
1. relay.ts — CONNECT-over-WebSocket 中继
行数: 456 行
导出
encodeChunk(data)— 编码 protobuf UpstreamProxyChunk 消息decodeChunk(buf)— 解码 protobuf 块UpstreamProxyRelay类型 —{ port: number, stop: () => void }startUpstreamProxyRelay(opts)— 启动中继服务器startNodeRelay(wsUrl, authHeader, wsAuthHeader)— Node.js 特定实现
架构
工具 (curl/gh/kubectl)
↓ HTTP CONNECT
本地 TCP 服务器 (localhost:ephemeral)
↓ WebSocket 隧道
CCR upstreamproxy 端点
↓ MITM TLS + 凭证注入
真实上游服务器
连接状态机
Phase 1: 累积 CONNECT 请求
↓ (直到 CRLF CRLF 终止符)
Phase 2: 打开 WebSocket 隧道(带认证头)
↓
Phase 3: 双向字节转发
├── 客户端 → 服务器: encodeChunk() → WebSocket
└── 服务器 → 客户端: WebSocket → decodeChunk() → TCP
Protobuf 编码(手写)
// 手写 protobuf wire format,避免引入 protobuf 库
// UpstreamProxyChunk: field 1, wire type 2 (length-delimited)
function encodeChunk(data: Uint8Array): Uint8Array {
const tag = 0x0a // field 1, wire type 2
const len = encodeVarint(data.length)
return concat([tag], len, data)
}
双运行时支持
if (typeof Bun !== 'undefined') {
// Bun: 需要显式写缓冲管理(背压处理)
return startBunRelay(wsUrl, auth)
} else {
// Node.js: 内部缓冲
return startNodeRelay(wsUrl, auth)
}
关键参数
- 最大块大小: 512KB
- Keepalive: 每 30 秒发送空块
- 错误处理: 隧道建立前返回 502 Bad Gateway;建立后静默关闭
2. upstreamproxy.ts — 代理系统初始化
行数: 286 行
导出
SESSION_TOKEN_PATH = '/run/ccr/session_token'initUpstreamProxy(opts?)— 初始化代理系统getUpstreamProxyEnv()— 获取子进程环境变量resetUpstreamProxyForTests()— 测试重置
初始化流程
initUpstreamProxy()
├── 1. 守卫: 仅在 CLAUDE_CODE_REMOTE && CCR_UPSTREAM_PROXY_ENABLED 时执行
├── 2. 令牌: 读取 /run/ccr/session_token → 读后即删
├── 3. 安全: prctl(PR_SET_DUMPABLE, 0) 阻止 ptrace
├── 4. CA 证书: 下载 + 合并到 ~/.ccr/ca-bundle.crt
├── 5. 中继: startUpstreamProxyRelay() → 获取本地端口
└── 6. 环境变量: HTTPS_PROXY, SSL_CERT_FILE, NODE_EXTRA_CA_CERTS 等
NO_PROXY 排除列表
localhost, 127.0.0.1, RFC1918, IMDS, api.anthropic.com, github.com, registry.npmjs.org 等
Fail-Open 设计
任何错误只记录警告,不中断会话。
设计亮点
- 零依赖 Protobuf: 手写 wire format,避免引入 protobuf 库
- 双运行时: Bun 和 Node.js 各自的背压处理
- 安全加固: prctl 防 ptrace、令牌读后即删、CA 证书管理
- Fail-Open: 代理失败不阻断会话
- 凭证注入: 服务端 MITM 注入组织凭证,客户端无需感知
34 - outputStyles 模块源码分析
路径:
src/outputStyles/文件数: 1 个 功能: 输出样式加载 — 自定义 AI 响应的格式和风格
loadOutputStylesDir.ts
行数: 99 行
导出
getOutputStyleDirStyles(cwd)— 获取输出样式配置(memoized)clearOutputStyleCaches()— 清空缓存
样式文件格式
---
name: concise
description: 简洁直接的回复风格
keep-coding-instructions: true
---
回复时请保持简洁。不要使用 emoji。
避免冗长的解释,直接给出答案。
加载流程
.claude/output-styles/ ← 项目级样式
~/.claude/output-styles/ ← 用户级样式
↓
loadMarkdownFilesForSubdir('output-styles', cwd)
↓
对每个 .md 文件:
├── 提取文件名作为默认样式名
├── 解析 frontmatter (name, description, keep-coding-instructions)
├── 使用 frontmatter name 或回退到文件名
├── 提取描述(frontmatter 或 markdown 内容)
├── 解析 keep-coding-instructions 标志
└── 警告 force-for-plugin(仅插件样式有效)
↓
返回 OutputStyleConfig[]
Memoization
结果按 cwd 缓存,避免重复文件系统访问。
OutputStyleConfig 结构
interface OutputStyleConfig {
name: string // 样式名称
description: string // 样式描述
prompt: string // 注入到系统提示的内容
source: 'user' | 'project' // 来源
keepCodingInstructions: boolean // 是否保留默认编码指令
}
35 - assistant 模块源码分析
路径:
src/assistant/文件数: 1 个 功能: 会话历史 API — 从远程 API 分页获取会话事件
sessionHistory.ts
行数: 88 行
导出
HISTORY_PAGE_SIZE = 100— 分页大小HistoryPage类型 —{ events: SDKMessage[], firstId: string, hasMore: boolean }HistoryAuthCtx类型 —{ baseUrl: string, headers: Record<string, string> }createHistoryAuthCtx(sessionId)— 创建认证上下文fetchLatestEvents(ctx, limit?)— 获取最新事件页fetchOlderEvents(ctx, beforeId, limit?)— 获取更早事件页
关键依赖
axios— HTTP 客户端getOauthConfig— OAuth 配置SDKMessage— 事件消息类型getOAuthHeaders,prepareApiRequest— API 认证
认证上下文创建
async function createHistoryAuthCtx(sessionId: string): Promise<HistoryAuthCtx> {
const headers = await getOAuthHeaders()
const { baseUrl } = await prepareApiRequest()
return {
baseUrl: `${baseUrl}/v1/sessions/${sessionId}/events`,
headers: {
...headers,
'anthropic-beta': 'ccr-byoc-2025-07-29',
'x-organization-uuid': orgUuid,
}
}
}
分页策略
获取最新页:
GET /v1/sessions/{id}/events?anchor_to_latest=true&limit=100
→ { events: [...], firstId: "cursor_abc", hasMore: true }
获取更早页(游标分页):
GET /v1/sessions/{id}/events?before_id=cursor_abc&limit=100
→ { events: [...], firstId: "cursor_xyz", hasMore: false }
错误处理
// HTTP 错误或网络故障返回 null(不抛异常)
// 用 logForDebugging 记录状态码
// 15 秒请求超时
try {
const response = await axios.get(url, { headers, timeout: 15000 })
return mapToHistoryPage(response.data)
} catch (error) {
logForDebugging('Failed to fetch events', error.response?.status)
return null
}
使用场景
主要被 screens/ResumeConversation.tsx 使用,在恢复远程会话时获取历史事件。
用户选择恢复远程会话
↓
createHistoryAuthCtx(sessionId)
↓
fetchLatestEvents(ctx, 100)
↓
显示会话内容
↓
用户滚动加载更多 → fetchOlderEvents(ctx, cursor, 100)
从源码角度看:如何避免封号
本文基于 Claude Code 源码中的认证、遥测、指纹、归因等机制,分析 Anthropic 后端可能用于检测异常账号的信号,以及中国用户被封号的常见原因。
封号的本质
Anthropic 封号不是随机的,而是基于多维度信号交叉验证。从源码来看,每次 API 请求都会携带大量元数据,后端可以据此判断你是否是“正常用户“。
一、Claude Code 上报了哪些信息
1. 每次 API 请求必带的 HTTP 头
// services/api/client.ts:106-115
headers = {
'x-app': 'cli',
'User-Agent': 'claude-cli/2.1.87 (consumer, cli)',
'x-claude-remote-container-id': '...', // 远程容器 ID(如有)
'x-claude-remote-session-id': '...', // 远程会话 ID(如有)
'x-client-app': '...', // SDK 客户端标识
'x-client-request-id': 'uuid', // 每次请求唯一 ID
}
2. 归因头(Attribution Header)— 最关键的追踪机制
// constants/system.ts:73-91
// 每次请求都带,格式:
// x-anthropic-billing-header: cc_version=2.1.87.a3f; cc_entrypoint=cli; cch=00000;
function getAttributionHeader(fingerprint: string): string {
const version = `${MACRO.VERSION}.${fingerprint}` // 版本号 + 指纹
const entrypoint = process.env.CLAUDE_CODE_ENTRYPOINT ?? 'unknown'
const cch = feature('NATIVE_CLIENT_ATTESTATION') ? ' cch=00000;' : ''
// cch=00000 会被 Bun 原生 HTTP 层替换为真实的客户端证明 token
return `x-anthropic-billing-header: cc_version=${version}; cc_entrypoint=${entrypoint};${cch}`
}
这个头包含三个关键信息:
- cc_version — 版本号 + 3 字符指纹(证明你用的是真正的 Claude Code)
- cc_entrypoint — 入口类型(cli/sdk/mcp)
- cch — 客户端证明 token(Bun 原生层计算,防伪造)
3. 指纹算法
// utils/fingerprint.ts
const FINGERPRINT_SALT = '59cf53e54c78' // 硬编码盐值,必须和后端匹配
function computeFingerprint(messageText: string, version: string): string {
// 取用户第一条消息的第 4、7、20 个字符
const indices = [4, 7, 20]
const chars = indices.map(i => messageText[i] || '0').join('')
const input = `${FINGERPRINT_SALT}${chars}${version}`
return createHash('sha256').update(input).digest('hex').slice(0, 3)
}
后端会验证这个指纹。如果你用第三方客户端伪造请求,指纹对不上就会被标记。
4. 客户端证明(Native Client Attestation)
// constants/system.ts:81-82
// cch=00000 是占位符,Bun 的原生 HTTP 层会在发送前替换为真实 hash
// 实现在 bun-anthropic/src/http/Attestation.zig
const cch = feature('NATIVE_CLIENT_ATTESTATION') ? ' cch=00000;' : ''
这是最难绕过的机制 — 证明 token 由 Bun 运行时的 Zig 原生代码计算,不在 JS 层暴露,第三方客户端几乎无法复现。
5. User-Agent 格式
// utils/http.ts:36
// 格式:claude-cli/{版本} ({用户类型}, {入口点})
return `claude-cli/${MACRO.VERSION} (${process.env.USER_TYPE}, ${process.env.CLAUDE_CODE_ENTRYPOINT ?? 'cli'})`
// 示例:claude-cli/2.1.87 (consumer, cli)
6. 设备 ID(持久化)
// utils/config.ts:1757-1764
function getOrCreateUserID(): string {
const config = getGlobalConfig()
if (config.userID) return config.userID
// 首次运行生成,存储在 ~/.claude/config.json,永久关联
const userID = randomBytes(32).toString('hex')
saveGlobalConfig(current => ({ ...current, userID }))
return userID
}
这个 ID 存在 ~/.claude/config.json 里,一旦生成就永久绑定。如果你的账号被封,换账号但不清理这个文件,新账号也可能被关联。
7. GrowthBook 用户画像
// services/analytics/growthbook.ts — 上报给特性门控系统的属性
attributes = {
deviceID, // 设备 ID
sessionId, // 会话 ID
organizationUUID, // 组织 ID
accountUUID, // 账号 ID
rateLimitTier, // 限流等级
subscriptionType, // 订阅类型(free/pro/team/enterprise)
platform, // 操作系统
email, // 邮箱
}
8. 遥测事件
// services/analytics/ — 双通道上报
// 1. Datadog — 实时指标
// 2. 第一方事件日志 — 发送到 /api/event_logging/batch
// 批处理:10 秒间隔,200 条批量,8192 队列
二、后端可能的封号判据
基于源码中上报的信息,后端大概率会检测以下异常:
IP 地址相关
| 信号 | 风险 | 说明 |
|---|---|---|
| 中国大陆 IP 直连 | 🔴 极高 | Anthropic 不对中国提供服务,直连 = 违反 ToS |
| IP 频繁切换 | 🟡 中等 | 短时间内 IP 跳跃,像是共享代理 |
| 数据中心 IP | 🟡 中等 | 机房 IP 而非住宅 IP,可能是批量使用 |
| IP 与注册地不符 | 🟡 中等 | 注册时美国 IP,使用时亚洲 IP |
客户端指纹相关
| 信号 | 风险 | 说明 |
|---|---|---|
| 指纹验证失败 | 🔴 极高 | 第三方客户端伪造请求,指纹对不上 |
| cch 证明缺失/无效 | 🔴 极高 | 非官方 Bun 运行时,无法生成证明 token |
| User-Agent 异常 | 🟡 中等 | 格式不对或版本号不存在 |
| 版本号过旧 | 🟢 低 | 长期不更新,可能是破解版 |
使用模式相关
| 信号 | 风险 | 说明 |
|---|---|---|
| 同一设备 ID 多账号 | 🔴 极高 | 一台机器切换多个账号 |
| 请求频率异常 | 🟡 中等 | 超出正常人类使用频率 |
| 7×24 无间断使用 | 🟡 中等 | 没有人类作息规律 |
| 只用 API 不用 UI | 🟢 低 | 纯 SDK 调用法用途 |
三、实用建议
1. 网络层面
- 使用稳定的住宅代理,不要用数据中心 IP
- 保持 IP 一致性 — 不要频繁切换节点,选一个地区固定用
- Claude Code 原生支持代理:
// utils/proxy.ts — 支持的环境变量
// HTTPS_PROXY / https_proxy / HTTP_PROXY / http_proxy
// NO_PROXY — 支持通配符、域名后缀、端口、IP
设置方式:export HTTPS_PROXY=http://your-proxy:port
2. 客户端层面
- 用官方客户端,不要用第三方封装或破解版
- 官方客户端的 cch 证明 token 是 Zig 原生代码生成的,第三方无法复现
- 及时更新版本 — 旧版本的指纹算法可能和后端不匹配
3. 账号层面
- 一机一号 —
~/.claude/config.json里的userID是持久化的设备指纹 - 如果要换账号,需要清理
~/.claude/目录 - 不要共享账号 — GrowthBook 会追踪 deviceID + accountUUID 的关联
4. 使用模式
- 保持正常使用节奏 — 不要写脚本批量调用
- 不要关闭遥测 — 虽然可以通过
CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1关闭非必要遥测,但完全没有遥测数据本身就是异常信号
5. 关于 API Key vs OAuth
源码中两种认证方式的追踪力度不同:
// OAuth 用户 — 追踪更多
attributes = { subscriptionType, rateLimitTier, billingType, organizationUUID, accountUUID }
// API Key 用户 — 追踪相对少
// 但 policyLimits 仍然会检查
使用 API Key(Console)比 OAuth(claude.ai 订阅)的追踪维度少一些,但核心的 IP + 指纹 + 设备 ID 检测是一样的。
四、源码中的“后门“和可控开关
可以关闭的
| 开关 | 环境变量 | 效果 |
|---|---|---|
| 归因头 | CLAUDE_CODE_ATTRIBUTION_HEADER=0 | 不发送 billing header |
| 非必要遥测 | CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1 | 关闭分析/遥测 |
| GrowthBook | 无直接开关 | 6 小时刷新,有磁盘缓存 |
无法关闭的
| 机制 | 原因 |
|---|---|
| User-Agent | 硬编码在请求头中 |
| 指纹 (fingerprint) | 后端验证,不发 = 请求被拒 |
| cch 证明 | Bun 原生层注入,JS 层无法控制 |
| OAuth token 属性 | 服务端下发,客户端无法修改 |
策略限制的 Fail-Open 设计
// services/policyLimits/index.ts
// 大多数策略检查在获取失败时默认放行(fail-open)
// 唯一例外:HIPAA 组织的 allow_product_feedback 策略(fail-closed)
这意味着即使策略服务器不可达,Claude Code 仍然可以正常使用 — 但这不代表后端不记录。
五、总结
从源码来看,Anthropic 的检测体系是多层纵深防御:
第 1 层:IP 地址(最容易被检测,也最容易解决)
第 2 层:客户端指纹 + cch 证明(确认是官方客户端)
第 3 层:设备 ID + 账号关联(跨会话追踪)
第 4 层:使用模式分析(频率、时间、行为)
第 5 层:GrowthBook 特性门控(服务端动态控制)
中国用户被封号最常见的原因是第 1 层(IP 暴露)和第 3 层(一机多号)。用好代理 + 一机一号 + 官方客户端,基本可以避免大部分风险。
声明:本分析仅基于公开源码的技术解读,不构成任何规避服务条款的建议。使用 Claude Code 请遵守 Anthropic 的使用政策。
快问快答 (FAQ)
基础概念
Q: Claude Code 到底是什么?和 Claude 网页版有什么区别?
Claude Code 是 Anthropic 官方的 CLI 工具,直接在终端里和 Claude 交互,核心区别是它能直接操作你的文件系统 — 读写文件、执行 Shell 命令、搜索代码,本质上是一个 AI 驱动的编程 Agent,不只是聊天。
Q: 用什么语言写的?为什么选 TypeScript + Bun?
全部 TypeScript,1884 个文件。选 Bun 而不是 Node 主要是为了:
- 更快的启动速度(CLI 工具对冷启动敏感)
- 内置打包器,不需要额外的 webpack/esbuild
- 原生支持 TypeScript,不需要编译步骤
Q: 为什么 Fork 了 Ink 而不是直接用 npm 包?
标准 Ink 不够用。Claude Code 需要:
- 鼠标点击支持(hit-test)
- 完整终端协议栈(CSI/SGR/OSC/DEC)
- 声明式光标管理
- 搜索高亮
- 纯 TS 的 Yoga 布局(避免 WASM 加载问题)
这些都不是简单的插件能解决的,所以直接 Fork 了整个框架,改了约 80 个文件。
架构设计
Q: main.tsx 4683 行、REPL.tsx 5005 行,为什么不拆分?
这是个好问题。从源码来看:
- main.tsx 是编排器,负责初始化所有模块(bootstrap、tools、skills、plugins、bridge、server、coordinator),拆开会导致初始化顺序难以管理
- REPL.tsx 是整个交互的状态中心,消息数组、权限请求、文件状态缓存、后台任务全在这里,拆开会导致状态同步问题
本质上是“God Component“反模式,但在 CLI 场景下,状态集中管理比分散管理更实际。
Q: query.ts 和 query/ 目录是什么关系?
query.ts(根级,1729 行)是查询主循环,直接被 REPL.tsx import,负责调用 Claude API、处理流式响应、执行工具query/(目录)是主循环的支撑模块:配置快照(config.ts)、依赖注入(deps.ts)、Token 预算(tokenBudget.ts)、停止钩子(stopHooks.ts)
Q: hooks/ 和 utils/hooks/ 为什么分成两个?
完全不同的东西:
src/hooks/(104 个文件)— React Hooks,给 UI 组件用的(useSearchInput、useTerminalSize 等)src/utils/hooks/(17 个文件)— 钩子执行引擎,处理 28 种生命周期事件(Stop、PreToolUse、PostToolUse 等)
前者是 React 的 useState/useEffect 那套,后者是 Claude Code 自己的事件系统。
Q: 工具是怎么注册的?类继承还是工厂模式?
工厂模式。所有 40 个工具都通过 buildTool(def) 构建:
// src/Tool.ts:783-792
export function buildTool<D>(def: D): BuiltTool<D>
传入一个 ToolDef 对象(包含 name、description、inputSchema、execute 等),返回 BuiltTool。没有基类继承。
Q: MCP 工具是怎么集成的?
Claude Code 同时是 MCP Client 和 MCP Server:
- 作为 Client:启动时动态发现并注册第三方 MCP 工具,和内置工具统一管理
- 作为 Server:通过
entrypoints/mcp.ts入口暴露自己的能力给其他 MCP Client
核心流程
Q: 用户输入到 AI 回复的完整链路是什么?
用户输入 → REPL.tsx 解析
→ import { query } from '../query.js' 直接调用
→ microcompact 消息压缩
→ autocompact 检查(上下文太长时自动压缩)
→ callModel() → services/api → Claude API(流式)
- 文本 → yield 给 REPL → ink/ 渲染到终端
- 工具调用 → 权限检查 → 执行 → 结果追加到消息 → 继续循环
→ checkTokenBudget()(连续2次 delta<500 且续传≥3 → 停止)
→ 停止钩子(记忆提取、自动推理、提示建议)
→ 会话持久化
Q: 权限系统怎么工作的?
三级权限:
- 自动允许 — 只读工具(Read、Glob、Grep)和匹配白名单的命令
- 需要确认 — 写文件、执行未知命令,弹出权限对话框
- 沙箱执行 — 在受限环境中运行,网络和文件系统访问受控
权限规则在 utils/permissions/ 中定义,检查逻辑在 hooks/useCanUseTool.ts。
Q: Token 预算是怎么控制的?
不是硬切断,而是收益递减检测:
const COMPLETION_THRESHOLD = 0.9 // 90% 预算使用率
const DIMINISHING_THRESHOLD = 500 // 收益递减阈值
// 连续 2 次 delta < 500 tokens 且续传次数 ≥ 3 → 停止
也就是说,如果 AI 连续两轮只产出很少的新内容,系统会判断它在“原地打转“,主动停止。
连接与扩展
Q: bridge/ 是干什么的?VS Code 扩展怎么和 CLI 通信?
bridge/ 实现了 IDE 桥接协议。VS Code/JetBrains 扩展通过这个桥接层和 Claude Code CLI 进程通信,实现:
- 文件 diff 同步
- 编辑器内显示 AI 修改
- 共享终端上下文
REPL 不直接 import bridge/,而是通过 hooks/useReplBridge.tsx 间接访问。
Q: 多个 Claude Code 实例怎么协调?
coordinator/ 模块负责多实例协调,被 main.tsx 在启动时初始化。主要解决:
- 同一项目多个终端窗口的会话隔离
- 文件锁冲突
- 共享状态同步
Q: 子 Agent 是怎么工作的?
通过 tools/AgentTool/ 实现。用户或 AI 可以启动子 Agent:
- general-purpose — 通用 Agent,拥有所有工具
- Explore — 只读代码探索,不能修改文件
- Plan — 计划模式,只读分析后输出方案
子 Agent 可以选择在 Git Worktree 中隔离运行,避免影响主工作区。
有趣的细节
Q: Task ID 是怎么生成的?
不是 UUID,而是 randomBytes(8) + 单字符类型前缀 + 36 字符字母表编码。比 UUID 短很多,在终端显示更友好。
Q: Buddy 彩蛋是什么?
src/buddy/ 目录(6 个文件)实现了一个隐藏的伴侣系统:
isBuddyTeaserWindow:2026 年 4 月 1-7 日显示预告isBuddyLive:2026 年 4 月之后正式上线- 包含
CompanionSprite.tsx精灵动画组件
看起来是个愚人节彩蛋,但代码写得很认真。
Q: 为什么用纯 TS 重写 Yoga 布局而不是用 WASM?
native-ts/yoga-layout/ 是 Meta Yoga 的简化子集移植,不是完整移植。原因:
- 避免 WASM 加载的兼容性问题(不同平台、不同 Node/Bun 版本)
- CLI 场景只需要基础 Flexbox(行/列布局、对齐、padding),不需要完整 CSS 规范
- 纯 TS 更容易调试和定制
Q: 会话数据存在哪里?
utils/sessionStorage.ts 负责持久化,存储在 ~/.claude/ 目录下:
- 会话消息历史
- 会话元数据(标题、时间戳、项目路径)
- 支持跨项目恢复(
crossProjectResume.ts) - 自动定时保存
Q: 快速模式 (Fast Mode) 是什么?
不是切换到更小的模型,而是同一个模型用更快的输出配置。通过 bootstrap/state 中的 fastModeEnabled 标志控制,影响 query/config.ts 中的查询参数。