第一章:项目全景——目录结构与模块划分

本章从宏观视角俯瞰 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 消息

工具定义:Tool.ts

1
2
3
4
5
6
职责:定义 Tool 接口(所有工具的"契约")
大小:793 行
关键类型:
- Tool<Input, Output, Progress> — 工具核心接口
- ToolUseContext — 工具执行上下文
- ToolPermissionContext — 权限上下文

工具注册:tools.ts

1
2
3
4
5
6
职责:工具注册表,决定哪些工具可用
大小:390 行
关键函数:
- getAllBaseTools() — 所有内置工具的"全家福"
- getTools(permissionContext) — 过滤后的可用工具
- assembleToolPool() — 合并内置 + MCP 外部工具

1.4 功能模块划分

工具目录 tools/(40+ 工具)

每个工具是独立目录,内部按职责拆分文件:

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 // API 调用
microcompact: typeof microcompactMessages // 微压缩
autocompact: typeof autoCompactIfNeeded // 自动压缩
uuid: () => string // UUID 生成
}

生产环境使用 productionDeps(),测试环境注入 mock 实现。


1.9 重点预览:斜杠命令系统

详细实现将在后续章节展开。

命令类型体系

1
2
3
4
5
6
7
8
9
10
11
// 三种命令变体(判别联合类型)
type Command = CommandBase & (PromptCommand | LocalCommand | LocalJSXCommand)

// PromptCommand: 返回内容注入为 LLM prompt
type PromptCommand = { type: 'prompt'; getPromptForCommand(args, context): ContentBlockParam[] }

// LocalCommand: 本地执行,返回文本/压缩结果
type LocalCommand = { type: 'local'; load(): Promise<{ call: LocalCommandCall }> }

// LocalJSXCommand: 渲染 React 组件到终端
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,别名:resetnew

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'), // 用时才 import
}

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/