第一章:项目全景——目录结构与模块划分
本章从宏观视角俯瞰 Claude Code 项目的整体架构,帮助读者建立对 1900+ 文件、50 万行代码的"心智地图"。
同时预览本系列重点关注的三个方向:Agent 循环、斜杠命令(/resume、/clear、/compact)。
目录
1.1 项目规模概览
| 指标 |
数值 |
| 源码目录 |
claude-code/src/ |
| 文件总数 |
~1,902 |
| 顶层子目录 |
36 个 |
| 顶层独立文件 |
18 个 |
| 内置工具(Tools) |
40+ |
| 斜杠命令(Commands) |
101 个目录 |
| 服务模块(Services) |
20 个子域,130 个文件 |
| UI 组件(Components) |
389 个文件 |
| 工具函数(Utils) |
564 个文件 |
1.2 顶层目录结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| claude-code/src/ ├── entrypoints/ # 入口点(CLI 启动、SDK、MCP Server) ├── main.tsx # 主流程:参数解析、初始化、REPL 启动 ├── query.ts # ★ Agent 循环核心(异步生成器) ├── QueryEngine.ts # Agent 循环的 SDK/Headless 封装类 ├── Tool.ts # ★ 工具类型定义(793 行) ├── tools.ts # 工具注册表(390 行) ├── commands.ts # 斜杠命令注册表与分发 ├── context.ts # 系统提示词组装 ├── replLauncher.tsx # REPL 渲染启动器 ├── Task.ts # 任务定义 ├── tasks.ts # 任务管理 ├── history.ts # 会话历史 ├── cost-tracker.ts # Token 费用追踪 ├── setup.ts # 环境初始化 │ ├── tools/ # 40+ 个内置工具实现 ├── commands/ # 101 个斜杠命令实现 ├── services/ # 20 个服务子域 ├── components/ # 389 个 UI 组件 ├── hooks/ # 104 个 React Hooks ├── screens/ # 全屏页面(REPL 主界面) ├── state/ # 应用状态管理 ├── context/ # React Context Providers ├── utils/ # 564 个工具函数 ├── ink/ # ★ 定制版 Ink(终端 React 渲染器) ├── types/ # TypeScript 类型定义 ├── constants/ # 常量 ├── schemas/ # 数据校验 ├── migrations/ # 配置迁移 │ ├── plugins/ # 插件系统 ├── skills/ # 技能系统 ├── coordinator/ # 多 Agent 协调 ├── bridge/ # IDE 集成(VS Code / JetBrains) ├── remote/ # 远程会话 ├── server/ # 内嵌服务器 ├── vim/ # Vim 模式 ├── voice/ # 语音输入 ├── keybindings/ # 快捷键 ├── tasks/ # 后台任务系统 ├── buddy/ # Buddy 模式 ├── memdir/ # 记忆目录 ├── native-ts/ # 原生 TypeScript 工具 ├── cli/ # CLI 子命令 ├── bootstrap/ # 引导加载 └── outputStyles/ # 输出样式
|
1.3 核心骨架文件
这是理解整个项目必须先读的 6 个文件:
启动入口:entrypoints/cli.tsx
1 2 3 4 5 6
| 职责:CLI 最外层分发器 大小:~500 行 核心逻辑: 1. 检测快速路径(--version, --dump-system-prompt 等)→ 零依赖返回 2. 检测特殊模式(bridge, daemon, mcp-server 等)→ 各自入口 3. 均不匹配 → 加载 main.tsx → 完整 CLI 启动
|
主流程:main.tsx
1 2 3 4 5 6 7 8
| 职责:完整 CLI 初始化与 REPL 启动 大小:~3800 行 核心逻辑: 1. 并行预取(MDM 配置、Keychain 密钥) 2. 命令行参数解析(Commander.js) 3. 认证、配置、分析、插件加载 4. 创建 AppState 和 Store 5. 启动 REPL(launchRepl)
|
Agent 循环:query.ts
1 2 3 4 5 6 7
| 职责:★ 整个项目最核心的文件 —— 实现"思考→行动→观察"的 Agent 循环 大小:~1729 行 核心逻辑: while (true) { 准备上下文 → 调用 LLM → 提取工具调用 → 执行工具 → 循环 } 导出:async function* query() — 异步生成器
|
引擎封装:QueryEngine.ts
1 2 3
| 职责:对 query() 的类封装,提供 SDK/Headless 调用接口 大小:~1186 行 核心方法:async *submitMessage() — 消费 query() 的输出,转换为 SDK 消息
|
1 2 3 4 5 6
| 职责:定义 Tool 接口(所有工具的"契约") 大小:793 行 关键类型: - Tool<Input, Output, Progress> — 工具核心接口 - ToolUseContext — 工具执行上下文 - ToolPermissionContext — 权限上下文
|
1 2 3 4 5 6
| 职责:工具注册表,决定哪些工具可用 大小:390 行 关键函数: - getAllBaseTools() — 所有内置工具的"全家福" - getTools(permissionContext) — 过滤后的可用工具 - assembleToolPool() — 合并内置 + MCP 外部工具
|
1.4 功能模块划分
每个工具是独立目录,内部按职责拆分文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| tools/ ├── AgentTool/ # 启动子 Agent ├── BashTool/ # ★ 最复杂:执行 Shell 命令 │ ├── BashTool.tsx # 工具定义与主逻辑 │ ├── bashPermissions.ts # 权限判断 │ ├── bashSecurity.ts # 安全分析(命令注入检测) │ ├── prompt.ts # 提示词 │ ├── UI.tsx # 终端渲染 │ └── ... ├── FileReadTool/ # 读文件 ├── FileEditTool/ # 编辑文件 ├── FileWriteTool/ # 写文件 ├── GlobTool/ # 文件名搜索 ├── GrepTool/ # 文件内容搜索 ├── WebFetchTool/ # HTTP 请求 ├── WebSearchTool/ # Web 搜索 ├── AskUserQuestionTool/ # 向用户提问 ├── SkillTool/ # 执行技能 ├── MCPTool/ # MCP 协议工具 ├── NotebookEditTool/ # Jupyter 编辑 ├── EnterPlanModeTool/ # 进入规划模式 ├── ExitPlanModeTool/ # 退出规划模式 ├── EnterWorktreeTool/ # 进入工作树 ├── ExitWorktreeTool/ # 退出工作树 ├── TaskCreateTool/ # 创建任务 ├── TaskGetTool/ # 获取任务 ├── TaskUpdateTool/ # 更新任务 ├── TaskListTool/ # 列出任务 ├── TaskOutputTool/ # 任务输出 ├── TaskStopTool/ # 停止任务 ├── SendMessageTool/ # Agent 间消息传递 ├── ScheduleCronTool/ # 定时任务 ├── PowerShellTool/ # PowerShell(Windows) ├── LSPTool/ # 语言服务协议 ├── REPLTool/ # REPL 工具 ├── SleepTool/ # 等待/休眠 ├── RemoteTriggerTool/ # 远程触发 └── shared/ # 工具间共享逻辑
|
命令目录 commands/(101 个)
每个命令是独立目录,延迟加载:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| commands/ ├── clear/ # ★ /clear — 清空对话历史 ├── compact/ # ★ /compact — 压缩上下文 ├── resume/ # ★ /resume — 恢复历史会话 ├── commit.ts # /commit — 提交代码 ├── diff/ # /diff — 查看差异 ├── review/ # /review — 代码审查 ├── model/ # /model — 切换模型 ├── mcp/ # /mcp — MCP 管理 ├── memory/ # /memory — 记忆管理 ├── config/ # /config — 配置 ├── skills/ # /skills — 技能管理 ├── plugin/ # /plugin — 插件管理 ├── hooks/ # /hooks — Hook 管理 ├── session/ # /session — 会话管理 ├── export/ # /export — 导出对话 ├── cost/ # /cost — 费用查看 ├── doctor/ # /doctor — 诊断 ├── help/ # /help — 帮助 ├── vim/ # /vim — Vim 模式 ├── voice/ # /voice — 语音输入 ├── plan/ # /plan — 规划模式 ├── permissions/ # /permissions — 权限管理 ├── fast/ # /fast — 快速模式 ├── effort/ # /effort — 推理深度 ├── tasks/ # /tasks — 任务列表 ├── agents/ # /agents — Agent 管理 ├── branch/ # /branch — 分支管理 ├── context/ # /context — 上下文查看 ├── stats/ # /stats — 统计信息 ├── login/ # /login — 登录 ├── logout/ # /logout — 登出 └── ... # 更多(upgrade, rename, share, teleport 等)
|
服务目录 services/(20 个子域)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| services/ ├── api/ # LLM API 调用(流式响应、重试、限流) ├── mcp/ # MCP 协议客户端(连接、认证、工具发现) ├── compact/ # ★ 上下文压缩(auto-compact, micro-compact) ├── analytics/ # 遥测与特性门控(GrowthBook, Statsig) ├── lsp/ # 语言服务协议(代码诊断) ├── oauth/ # OAuth 认证流程 ├── plugins/ # 插件安装与管理 ├── policyLimits/ # 组织策略限制 ├── remoteManagedSettings/ # 远程托管配置 ├── extractMemories/ # 自动记忆提取 ├── autoDream/ # 空闲时记忆整理 ├── SessionMemory/ # 会话记忆管理 ├── MagicDocs/ # Magic Docs(自动文档) ├── PromptSuggestion/ # 提示词建议 ├── tips/ # 使用提示 ├── tools/ # 工具执行引擎(StreamingToolExecutor, 编排) ├── toolUseSummary/ # 工具使用摘要 ├── settingsSync/ # 配置同步 ├── teamMemorySync/ # 团队记忆同步 └── AgentSummary/ # Agent 摘要生成
|
1.5 基础设施层
状态管理 state/(6 个文件)
采用自定义轻量级 Store,结合 React 18 的 useSyncExternalStore:
1 2 3 4 5 6 7
| state/ ├── store.ts # Store 原语(~34 行,发布-订阅模式) ├── AppStateStore.ts # AppState 类型定义(巨大的状态树) ├── AppState.tsx # React 集成层(Provider + useAppState Hook) ├── onChangeAppState.ts # 状态变化副作用处理 ├── selectors.ts # 计算属性/选择器 └── teammateViewHelpers.ts # 多 Agent 视图辅助
|
AppState 的主要字段分区:
| 分区 |
职责 |
| UI 状态 |
verbose, briefMode, expandedView, statusLine |
| 模型配置 |
mainLoopModel, effort |
| 权限 |
toolPermissionContext, denialTracking |
| MCP |
clients, tools, commands, resources |
| 插件 |
enabled, disabled, commands, errors |
| 任务 |
tasks (Record<id, TaskState>) |
| Agent |
agentDefinitions, standaloneAgentContext |
| 会话 |
fileHistory, attribution, speculation |
React 上下文 context/(9 个文件)
1 2 3 4 5 6 7 8 9 10
| context/ ├── notifications.tsx # 通知队列与展示 ├── stats.tsx # Token/费用/时间统计 ├── overlayContext.tsx # 全屏覆盖层 ├── promptOverlayContext.tsx # 输入覆盖层 ├── voice.tsx # 语音模式 ├── QueuedMessageContext.tsx # 延迟消息队列 ├── modalContext.tsx # 模态对话框 ├── mailbox.tsx # 组件间消息传递 └── fpsMetrics.tsx # 帧率性能监控
|
终端渲染 ink/(96 个文件)
Claude Code fork 了 Ink 框架并深度定制:
- 自定义 React Reconciler(协调器)
- 基于 Yoga 的 Flexbox 布局
- 文本选择、点击事件、差异更新
- 虚拟滚动优化
1.6 扩展能力层
1 2 3 4 5 6 7 8 9 10
| ├── plugins/ # 插件系统(额外工具、命令、Hook) ├── skills/ # 技能系统(可复用工作流模板) ├── coordinator/ # 多 Agent 协调模式 ├── bridge/ # IDE 桥接(VS Code / JetBrains) ├── remote/ # 远程会话 ├── vim/ # Vim 模式 ├── voice/ # 语音输入 ├── keybindings/ # 快捷键系统 ├── tasks/ # 后台任务管理 └── buddy/ # Buddy 协作模式
|
1.7 数据流全景图
flowchart TD
Input[/"用户输入"/]
REPL["REPL.tsx
(UI 层)"]
Commands["commands.ts
(命令分发)"]
QE["QueryEngine
(SDK/Headless 入口)"]
subgraph AgentLoop["query() — Agent 循环(异步生成器)"]
direction TB
Step1["1. 上下文准备(压缩、裁剪)"]
Step2["2. yield* → 调用 LLM API(流式)"]
Step3["3. 提取 tool_use 块"]
Step4{"有工具调用?"}
Step5["5. 执行工具 → yield 结果"]
Step6["6. 构建下一轮状态"]
Return["return Terminal(终止原因)"]
Step1 --> Step2
Step2 --> Step3
Step3 --> Step4
Step4 -- "否" --> Return
Step4 -- "是" --> Step5
Step5 --> Step6
Step6 --> Step1
end
REPL_Render["REPL.tsx
for await 消费生成器输出
渲染到终端"]
API[("Claude API")]
Tools[("tools/")]
Input --> REPL
REPL -- "斜杠命令" --> Commands
REPL -- "普通消息" --> QE
QE --> AgentLoop
API -. "流式响应" .-> Step2
Tools -. "工具结果" .-> Step5
AgentLoop -- "yield 事件流
StreamEvent | Message" --> REPL_Render
生成器输出类型:
yield: StreamEvent | Message | ToolUseSummaryMessage
return: Terminal(终止原因)
1.8 重点预览:Agent 循环
详细实现将在第三章展开,这里先建立宏观认知。
核心文件
| 文件 |
角色 |
query.ts |
Agent 循环主实现(query() + queryLoop()) |
QueryEngine.ts |
类封装,管理会话生命周期 |
query/deps.ts |
依赖注入接口(4 个核心依赖) |
query/config.ts |
不可变配置快照 |
query/tokenBudget.ts |
Token 预算追踪与续写决策 |
query/stopHooks.ts |
停止钩子处理(异步生成器) |
函数签名
1 2 3 4 5 6 7
| export async function* query(params: QueryParams): AsyncGenerator<StreamEvent | Message | ToolUseSummaryMessage, Terminal>
// 内部循环 async function* queryLoop(params: QueryParams, consumedCommandUuids: string[]): AsyncGenerator<StreamEvent | Message | ToolUseSummaryMessage, Terminal>
|
循环的 5 个阶段
flowchart TD
Start(("Turn 开始"))
subgraph Phase1["Phase 1: 上下文准备"]
P1A["Snip 裁剪"]
P1B["Microcompact"]
P1C["Context Collapse"]
P1D["Autocompact(超阈值时触发)"]
P1E["Token 限制检查"]
P1A --> P1B --> P1C --> P1D --> P1E
end
subgraph Phase2["Phase 2: API 调用(流式)"]
P2A["逐 chunk yield StreamEvent"]
P2B["实时提取 tool_use 块"]
P2C["流式工具执行(可选,提前开始)"]
P2A --> P2B --> P2C
end
subgraph Phase3["Phase 3: 后处理"]
P3Check{"有工具调用?"}
P3A["运行 StopHooks"]
P3B["尝试恢复或重试"]
P3Check -- "否" --> P3A
P3Check -- "有恢复性错误" --> P3B
end
subgraph Phase4["Phase 4: 工具执行"]
P4A["只读工具 → 并行(最多 10 个)"]
P4B["写入工具 → 串行"]
P4C["yield 每个工具结果"]
P4A --> P4C
P4B --> P4C
end
subgraph Phase5["Phase 5: 状态推进"]
P5A{"超过 maxTurns?"}
P5B["构建新 State"]
P5A -- "否" --> P5B
end
Terminal(("return Terminal"))
Start --> Phase1 --> Phase2 --> Phase3
P3Check -- "是" --> Phase4 --> Phase5
P3A --> Terminal
P5A -- "是" --> Terminal
P5B --> Start
终止条件(10 种)
| 终止原因 |
触发场景 |
completed |
LLM 不再调用工具,任务完成 |
max_turns |
达到最大轮次限制 |
aborted_streaming |
用户在流式响应中中断 |
aborted_tools |
用户在工具执行中中断 |
prompt_too_long |
上下文超长且恢复失败 |
blocking_limit |
Token 硬限制(auto-compact 关闭时) |
model_error |
API 抛出未捕获异常 |
image_error |
图片大小/格式错误 |
hook_stopped |
用户定义的 Hook 阻止继续 |
stop_hook_prevented |
停止钩子明确阻止续写 |
依赖注入(query/deps.ts)
1 2 3 4 5 6
| export type QueryDeps = { callModel: typeof queryModelWithStreaming microcompact: typeof microcompactMessages autocompact: typeof autoCompactIfNeeded uuid: () => string }
|
生产环境使用 productionDeps(),测试环境注入 mock 实现。
1.9 重点预览:斜杠命令系统
详细实现将在后续章节展开。
命令类型体系
1 2 3 4 5 6 7 8 9 10 11
| type Command = CommandBase & (PromptCommand | LocalCommand | LocalJSXCommand)
type PromptCommand = { type: 'prompt'; getPromptForCommand(args, context): ContentBlockParam[] }
type LocalCommand = { type: 'local'; load(): Promise<{ call: LocalCommandCall }> }
type LocalJSXCommand = { type: 'local-jsx'; load(): Promise<{ call: LocalJSXCommandCall }> }
|
注册与分发
flowchart LR
subgraph Sources["命令来源"]
Builtin["COMMANDS()
内置命令"]
Skills["技能目录"]
Plugins["插件命令"]
Workflow["工作流命令"]
end
Merge["getCommands(cwd)
合并 + 过滤"]
Find["findCommand(name)
按 name / alias 查找"]
Exec["执行命令"]
Builtin --> Merge
Skills --> Merge
Plugins --> Merge
Workflow --> Merge
Merge --> Find --> Exec
三个重点命令预览
/clear(类型:local,别名:reset、new)
flowchart TD
Start["/clear 触发"] --> Hook1["执行 SessionEnd 钩子"]
Hook1 --> Cache["发送缓存驱逐提示"]
Cache --> Clear["清空所有消息
setMessages(() => [])"]
Clear --> NewID["重新生成会话 ID"]
NewID --> ClearCache["清除 ~25+ 种缓存"]
ClearCache --> ResetCWD["重置工作目录为初始目录"]
ResetCWD --> Tasks["杀死前台任务
保留后台任务"]
Tasks --> ResetState["重置 AppState
(MCP、文件历史、归因等)"]
ResetState --> Hook2["执行 SessionStart 钩子"]
Hook2 --> Done(("完成"))
/compact(类型:local,参数:可选的摘要指令)
flowchart TD
Start["/compact 触发"] --> GetMsg["获取压缩边界后的消息"]
GetMsg --> Try1{"尝试 Session Memory
Compaction(轻量路径)"}
Try1 -- "成功" --> Cleanup["清理缓存、更新状态"]
Try1 -- "失败" --> Try2{"尝试 Reactive
Compaction
(feature-gated)"}
Try2 -- "成功" --> Cleanup
Try2 -- "失败/不可用" --> Traditional["传统压缩路径"]
subgraph Traditional["传统压缩路径"]
direction TB
Micro["运行 microcompact 减少 token"]
Compact["调用 compactConversation() 生成摘要"]
Replace["替换历史消息为摘要"]
Micro --> Compact --> Replace
end
Traditional --> Cleanup
Cleanup --> Done(("完成"))
/resume(类型:local-jsx,别名:continue)
flowchart TD
Start["/resume 触发"]
Start --> HasArg{"提供了参数?"}
HasArg -- "无参数" --> Picker["显示交互式会话选择器
(React 组件)"]
HasArg -- "有参数" --> UUID{"尝试 UUID 匹配"}
UUID -- "找到" --> Resume
UUID -- "未找到" --> Title{"尝试自定义标题匹配"}
Title -- "找到" --> Resume
Title -- "未找到" --> Error["显示错误信息"]
Picker -- "用户选择" --> CrossCheck{"跨项目检查"}
CrossCheck -- "同项目" --> Resume["调用 context.resume()
加载历史消息"]
CrossCheck -- "不同项目" --> Clipboard["复制命令到剪贴板
提示用户切换目录"]
Resume --> Done(("完成"))
1.10 关键设计原则
1. 关注点分离
每个目录只负责一件事。工具的定义(Tool.ts)、注册(tools.ts)、执行(services/tools/)、权限(utils/permissions/)分布在不同模块中。
2. 延迟加载(Lazy Loading)
命令和工具都使用 load() 模式,只在实际调用时才加载重依赖:
1 2 3 4 5
| const clear = { type: 'local', name: 'clear', load: () => import('./clear.js'), }
|
3. 异步生成器驱动
核心循环用 async function* 实现,通过 yield 将中间结果推送给消费者,实现了计算与渲染的解耦。
4. 不可变状态 + 函数式更新
AppState 使用 DeepImmutable<T> 类型保护,状态更新通过函数式 setState((prev) => next) 模式。
5. 依赖注入
query/deps.ts 将外部依赖抽象为接口,使核心循环可以独立测试。
6. Feature Flag 驱动开发
通过编译时 feature() 门控和运行时 statsig/GrowthBook 门控,同一份代码可以产出不同功能集的产品。
7. 快速路径优化
cli.tsx 中对简单请求(如 --version)提供零依赖快速返回,避免加载 50 万行代码。
各目录文件规模对比
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| utils/ ████████████████████████████████████████ 564 文件 components/ ██████████████████████████████ 389 文件 commands/ █████████████████ 207 文件(101个目录) tools/ ████████████████ 184 文件 services/ ███████████ 130 文件 hooks/ ████████ 104 文件 ink/ ███████ 96 文件 bridge/ ███ 31 文件 constants/ ██ 21 文件 skills/ ██ 20 文件 cli/ ██ 19 文件 keybindings/ █ 14 文件 tasks/ █ 12 文件 types/ █ 11 文件 migrations/ █ 11 文件 context/ █ 9 文件
|
下一步
- 第二章:启动流程——从
entrypoints/cli.tsx 到 REPL 就绪的完整链路
- 第三章:Agent 循环深度解析——
query.ts 的 1729 行如何驱动整个 Agent
- 第四章:斜杠命令系统——/resume、/clear、/compact 的完整实现剖析
本文档基于 Claude Code 源码分析生成,源码路径:claude-code/src/