Claude Code 源码架构深度解析:从 main.tsx 入口到对话闭环
本文基于 2026 年 3 月通过 npm sourcemap 泄露的 Claude Code 完整源码进行分析,旨在帮助开发者理解这一标杆级 AI 编程助手的内部架构。
目录
1. 项目概览
Claude Code 不是简单的 CLI 包装器。它是一个基于 React + Ink 的终端 TUI 应用,拥有:
- 785KB 的
main.tsx入口文件 - 40+ 个内置工具(文件操作、Shell、搜索、LSP、MCP 等)
- 多智能体协调系统(Swarm/Coordinator)
- 自定义 React 终端渲染引擎(基于 Ink)
- 企业级功能:远程管理设置、策略限制、SSO、审计日志
源码泄露事件背景:Anthropic 在发布 npm 包时未排除
.mapsourcemap 文件,导致完整 TypeScript 源码随包发布。
2. 整体架构
Claude Code 采用分层架构,从上到下依次是:
┌─────────────────────────────────────────────────────────────┐
│ ① 用户交互层 (TUI) │
│ Ink 渲染引擎 ← REPL.tsx ← App.tsx ← 各 UI 组件 │
├─────────────────────────────────────────────────────────────┤
│ ② 核心引擎层 │
│ QueryEngine.ts / query.ts --- LLM 对话编排 │
│ 消息历史 | API 调用 | 流式响应 | Token 管理 │
├─────────────────────────────────────────────────────────────┤
│ ③ 工具执行层 │
│ BashTool | FileRead/Write/Edit | GlobTool | GrepTool │
│ AgentTool | MCPTool | LSP* | REPLTool | SkillTool ... │
├─────────────────────────────────────────────────────────────┤
│ ④ 服务支持层 │
│ API 层 | MCP 客户端 | OAuth | Analytics | autoDream │
│ LSP 管理 | 策略限制 | 远程设置 | 上下文压缩 │
├─────────────────────────────────────────────────────────────┤
│ ⑤ 集成与桥接层 │
│ bridge/ (IDE 集成) | coordinator/ (Swarm) │
├─────────────────────────────────────────────────────────────┤
│ ⑥ 状态管理层 │
│ AppState → AppStateStore → store.ts │
├─────────────────────────────────────────────────────────────┤
│ ⑦ 启动与配置层 │
│ main.tsx → init.ts → setup.ts → config/ │
└─────────────────────────────────────────────────────────────┘
目录结构速览
src/
├── main.tsx # CLI 入口 (Commander.js + ~50 个 CLI flag)
├── QueryEngine.ts # 核心 LLM 对话引擎
├── query.ts # query() 函数:API 调用与流式处理
├── Tool.ts # 工具抽象基类与类型定义
├── setup.ts # 会话初始化设置
├── commands.ts # Slash 命令注册
│
├── tools/ # 40+ 工具实现
│ ├── BashTool/
│ ├── FileReadTool/
│ ├── FileWriteTool/
│ ├── FileEditTool/
│ ├── AgentTool/ # 多智能体调度
│ ├── MCPTool/
│ ├── GlobTool/
│ ├── GrepTool/
│ └── ...
│
├── state/ # 全局状态管理
│ ├── AppState.tsx
│ ├── AppStateStore.ts
│ └── store.ts
│
├── services/ # 后端服务
│ ├── api/ # Claude API 调用层
│ ├── mcp/ # MCP 协议客户端
│ ├── analytics/ # GrowthBook / 事件日志
│ ├── autoDream/ # "梦境"记忆整理系统
│ ├── compact/ # 上下文压缩
│ ├── lsp/ # LSP 服务器管理
│ └── oauth/ # OAuth 认证
│
├── bridge/ # IDE 集成层 (25+ 文件)
│ ├── bridgeMain.ts
│ ├── replBridge.ts
│ └── ...
│
├── coordinator/ # 多智能体协调
│ └── coordinatorMode.ts
│
├── buddy/ # Tamagotchi 彩蛋系统 😄
│ ├── companion.ts
│ └── CompanionSprite.tsx
│
└── utils/ # 工具函数 (100+ 文件)
├── permissions/ # 权限系统
├── hooks/ # 生命周期钩子
└── ...
3. 核心模块速览
3.1 main.tsx --- CLI 入口
- 4683 行 ,使用 Commander.js 解析约 50 个 CLI flag
- 注册
preActionhook 作为真正的初始化触发器 - 根据参数分支到:交互式 REPL / 非交互式 headless / 子命令
3.2 QueryEngine.ts --- 对话引擎
typescript
export class QueryEngine {
private config: QueryEngineConfig
private mutableMessages: Message[]
private abortController: AbortController
private totalUsage: NonNullableUsage
// ...
async *submitMessage(
prompt: string | ContentBlockParam[],
options?: { uuid?: string; isMeta?: boolean }
): AsyncGenerator<SDKMessage, void, unknown> {
// 构建系统提示 → 调用 API → 流式处理 → 工具执行 → 循环
}
}
关键职责:
- 管理单会话的消息历史
- 构建系统提示(System Prompt),整合工具描述、MCP、记忆
- 调用 Claude API 并处理流式 SSE 响应
- 检测工具调用(Tool Use),路由到对应工具
- 上下文压缩(Compact/Snip)决策
- Token 用量和预算追踪
3.3 Tool.ts --- 工具抽象层
所有工具的契约定义:
typescript
export type Tool = {
name: string
description: string
inputJSONSchema: ToolInputJSONSchema
isEnabled: (context: ToolUseContext) => boolean
isReadOnly: boolean
// ...
}
权限模型 (CanUseToolFn):
allow--- 直接执行ask--- 询问用户确认deny--- 拒绝执行
3.4 state/ --- 状态管理
不使用 Redux,而是自定义 Store + React Context:
typescript
// state/store.ts
export function createStore<T>(initialState: T) {
let state = initialState
const listeners = new Set<(state: T, prevState: T) => void>()
return {
getState: () => state,
setState: (updater: (prev: T) => T) => { /* ... */ },
subscribe: (listener) => { /* ... */ }
}
}
4. main.tsx 启动全流程
main.tsx 的启动分为 6 大阶段,我们逐层拆解。
阶段 0:模块级副作用(导入时即执行)
typescript
// main.tsx 第 1-20 行
import { profileCheckpoint } from './utils/startupProfiler.js'
profileCheckpoint('main_tsx_entry') // 1. 启动性能计时
import { startMdmRawRead } from './utils/settings/mdm/rawRead.js'
startMdmRawRead() // 2. 并行启动 MDM 子进程
import { startKeychainPrefetch } from './utils/secureStorage/keychainPrefetch.js'
startKeychainPrefetch() // 3. 并行预取 macOS Keychain
这三行位于所有 import 之前 ,让操作系统在加载剩余 ~135ms 的模块时,并行执行这些慢操作。
阶段 1:main() --- 安全与参数预处理
| 步骤 | 做什么 | 源码位置 |
|---|---|---|
| 1.1 | 设置 NoDefaultCurrentDirectoryInExePath=1,防止 Windows PATH 劫持 |
~L591 |
| 1.2 | 初始化警告处理器 | ~L594 |
| 1.3 | 注册 SIGINT / exit 信号处理 |
~L595-606 |
| 1.4 | 处理 cc:// URL(直接连接远程服务器) |
~L612-641 |
| 1.5 | 处理 Deep Link URI | ~L647-677 |
| 1.6 | 处理 claude assistant [sessionId](KAIROS 模式) |
~L685-699 |
| 1.7 | 处理 claude ssh <host>(SSH 远程会话) |
~L706-795 |
| 1.8 | 检测 -p/--print → 判断非交互模式 |
~L798-803 |
| 1.9 | 判断 Client Type:cli / sdk-ts / sdk-py / remote / vscode ... | ~L817-834 |
| 1.10 | 提前加载 --settings 和 --setting-sources |
~L851-854 |
阶段 2:run() --- CLI 框架初始化
typescript
async function run(): Promise<CommanderCommand> {
const program = new CommanderCommand()
.configureHelp(createSortedHelpConfig())
.enablePositionalOptions()
// ⭐ 核心:preAction hook 是真正的初始化触发器
program.hook('preAction', async (thisCommand) => {
await ensureMdmSettingsLoaded()
await ensureKeychainPrefetchCompleted()
await init() // ← 核心初始化
await initSinks() // 日志 sink
runMigrations() // 配置迁移 v1→v11
void loadRemoteManagedSettings() // 企业远程设置(非阻塞)
void loadPolicyLimits() // 策略限制(非阻塞)
})
// 定义 ~50 个 CLI 选项
program
.option('-p, --print', 'Print response and exit')
.option('--bare', 'Minimal mode')
.option('--model <model>', 'Model for the session')
.option('--permission-mode <mode>', 'Permission mode')
// ... 更多选项
.action(async (prompt, options) => {
// 阶段 4:action 处理
})
}
阶段 3:init() --- 核心初始化
init() 位于 entrypoints/init.ts,使用 memoize 保证只执行一次:
init_function_start
│
├──► enableConfigs() // 启用配置系统
├──► applySafeConfigEnvironmentVariables() // 应用安全的环境变量
├──► applyExtraCACertsFromConfig() // 应用自定义 CA 证书
├──► setupGracefulShutdown() // 注册优雅退出
│
├──► 初始化 1P 事件日志 + GrowthBook(动态导入)
├──► populateOAuthAccountInfoIfNeeded() // OAuth 账户信息
├──► initJetBrainsDetection() // JetBrains IDE 检测
├──► detectCurrentRepository() // GitHub 仓库检测
│
├──► initializeRemoteManagedSettingsLoadingPromise() // 企业远程设置
├──► initializePolicyLimitsLoadingPromise() // 策略限制
│
├──► configureGlobalMTLS() // mTLS 配置
├──► configureGlobalAgents() // HTTP 代理配置
├──► preconnectAnthropicApi() // 预连接 Anthropic API
│
├──► initUpstreamProxy() // CCR 上游代理
└──► setShellIfWindows() // Windows Git Bash
阶段 4:action() --- 会话配置(最复杂的阶段)
这是默认命令的处理逻辑,约 3000 行代码:
action_handler_start
│
├──► 处理 --bare 模式(极简模式,跳过大量初始化)
├──► 忽略 "code" 作为 prompt 的误用
│
├──► 处理 KAIROS (Assistant) 模式
│ └──► 如果启用: assistantModule.initializeAssistantTeam()
│
├──► 解析所有 CLI 选项到变量
│ ├──► outputFormat: text / json / stream-json
│ ├──► permissionMode: auto / accept-all / ...
│ ├──► tools: allow/deny 列表
│ ├──► model: --model 指定的模型
│ ├──► mcpConfig: MCP 服务器配置
│ ├──► continue/resume: 会话恢复
│ ├──► worktree/tmux: git worktree 模式
│ └──► teammate 选项: --agent-id --agent-name --team-name
│
├──► 加载 MCP 配置(本地文件 + claude.ai 远程配置)
│
├──► ⭐ setup() --- 会话核心设置
│ ├──► 并行: getCommands() --- 加载 Slash 命令
│ └──► 并行: getAgentDefinitionsWithOverrides() --- 加载 Agent
│
├──► 模型解析与验证
├──► applyConfigEnvironmentVariables() // 应用完整环境变量
├──► initializeLspServerManager() // LSP 初始化
├──► initializeToolPermissionContext() // 权限上下文
├──► 处理文件下载 (--file)
├──► 处理 teleport / remote 会话
│
└──► 根据参数分支到具体启动路径
setup() 内部详解(setup.ts)
typescript
export async function setup(
cwd: string,
permissionMode: PermissionMode,
allowDangerouslySkipPermissions: boolean,
worktreeEnabled: boolean,
worktreeName?: string,
tmuxEnabled?: boolean,
customSessionId?: string,
// ...
): Promise<void> {
执行流程:
setup_started
│
├──► Node.js 版本检查 (>=18)
├──► 设置自定义 Session ID
├──► startUdsMessaging() // Unix Domain Socket 消息服务器
├──► captureTeammateModeSnapshot() // 多智能体模式快照
├──► 终端备份恢复 (iTerm2 / Apple Terminal)
├──► findCanonicalGitRoot() // 查找 Git 根目录
├──► setProjectRoot() // 设置项目根
│
├──► ⭐ checkHasTrustDialogAccepted() // 信任对话框
│ // "Do you trust the authors of the files in this folder?"
│ // 首次运行必须确认后才加载 .claude/ 目录下的配置
│
├──► 如果 worktree 模式:
│ ├──► createWorktreeForSession() // 创建 git worktree
│ └──► createTmuxSessionForWorktree() // 创建 tmux 会话
│
├──► switchSession() // 切换/创建会话
├──► initializeFileChangedWatcher() // 文件变更监听(触发 hooks)
├──► initSessionMemory() // 初始化会话记忆系统
├──► prefetchApiKeyFromApiKeyHelperIfSafe() // 预取 API Key
├──► captureHooksConfigSnapshot() // Hook 配置快照
├──► checkForReleaseNotes() // 版本更新检查
└──► initSinks() // 初始化遥测日志 sinks
阶段 5:分支到启动路径
┌─────────────────┐
│ action() 结束 │
│ 进入分支逻辑 │
└────────┬────────┘
│
┌────────────────────┼────────────────────┐
▼ ▼ ▼
┌───────────────┐ ┌───────────────┐ ┌───────────────────┐
│ --print (-p) │ │ --continue │ │ 默认路径(新会话) │
│ 非交互模式 │ │ 或 --resume │ │ │
└───────┬───────┘ └───────┬───────┘ └─────────┬─────────┘
│ │ │
▼ ▼ ▼
┌───────────────┐ ┌───────────────┐ ┌───────────────────┐
│ runHeadless() │ │ 加载历史对话 │ │ 初始化空会话 │
│ (print.ts) │ │ processResumed│ │ │
│ │ │ Conversation │ │ │
│ 创建 QueryEngine│ │ │ │ │
│ 单次调用 API │ │ 恢复消息历史 │ │ │
│ 输出结果退出 │ │ │ │ │
└───────────────┘ └─────────┬─────┘ └─────────┬─────────┘
│ │
└─────────┬─────────┘
▼
┌───────────────────┐
│ launchRepl() │
│ │
│ <App> │
│ <REPL /> │
│ </App> │
└───────────────────┘
阶段 6:REPL 启动 --- 进入交互循环
typescript
// replLauncher.tsx
export async function launchRepl(
root: Root,
appProps: AppWrapperProps,
replProps: REPLProps,
renderAndRun: (root: Root, element: React.ReactNode) => Promise<void>
): Promise<void> {
const { App } = await import('./components/App.js')
const { REPL } = await import('./screens/REPL.js')
await renderAndRun(root,
<App {...appProps}>
<REPL {...replProps} />
</App>
)
}
REPL.tsx 启动后:
- Ink 渲染终端 UI(输入框、消息列表、状态栏、权限对话框)
- 监听键盘输入
- 用户按 Enter → 调用
QueryEngine.submitMessage(prompt) - 进入对话循环(见第 6 节)
后台预取 (startDeferredPrefetches()):
typescript
export function startDeferredPrefetches(): void {
void initUser() // 用户信息
void getUserContext() // 用户上下文(CLAUDE.md 等)
void getSystemContext() // 系统上下文(git status)
void getRelevantTips() // 相关提示
void countFilesRoundedRg() // 文件计数
void initializeAnalyticsGates() // 分析 gates
void prefetchOfficialMcpUrls() // MCP URL 预取
void refreshModelCapabilities() // 模型能力刷新
}
这些操作在首屏渲染后异步执行,不阻塞用户输入。
5. QueryEngine:对话引擎心脏
QueryEngine 是 Claude Code 最核心的类,一个实例对应一个会话,状态在多次用户输入间保持。
5.1 核心数据结构
typescript
export class QueryEngine {
private config: QueryEngineConfig // 工具、命令、MCP 等配置
private mutableMessages: Message[] // 消息历史
private abortController: AbortController // 取消控制
private permissionDenials: SDKPermissionDenial[] // 权限拒绝记录
private totalUsage: NonNullableUsage // Token 用量累计
private readFileState: FileStateCache // 文件读取缓存
// ...
}
5.2 submitMessage 执行流程
typescript
async *submitMessage(
prompt: string | ContentBlockParam[],
options?: { uuid?: string; isMeta?: boolean }
): AsyncGenerator<SDKMessage, void, unknown> {
步骤详解:
submitMessage 开始
│
├──► 1. 构建系统提示 (System Prompt)
│ ├──► fetchSystemPromptParts()
│ │ ├──► 默认系统提示(角色定义、安全约束)
│ │ ├──► 工具描述(所有启用工具的 schema)
│ │ ├──► MCP 服务器描述
│ │ ├──► 用户上下文(CLAUDE.md、记忆)
│ │ └──► Coordinator 上下文(多智能体)
│ ├──► 自定义系统提示 (--system-prompt)
│ ├──► 记忆机制提示 (memory mechanics)
│ └──► 追加系统提示 (--append-system-prompt)
│
├──► 2. 处理用户输入
│ └──► processUserInput()
│ ├──► Slash 命令解析 (/clear, /compact, /exit...)
│ ├──► 附件处理(图片、文件)
│ └──► 消息队列优先级管理
│
├──► 3. 构建 API 请求
│ ├──► normalizeMessagesForAPI() // 消息格式转换
│ ├──► prependUserContext() // 附加用户上下文
│ └──► appendSystemContext() // 附加系统上下文
│
├──► 4. 调用 Claude API
│ └──► streamMessage() 或 query()
│ ├──► 建立 SSE 连接
│ ├──► 发送请求(含 tools 定义)
│ └──► 流式接收响应 chunks
│
├──► 5. 流式处理响应
│ ├──► 文本内容 → 直接 yield 给 UI
│ ├──► thinking 块 → yield thinking 内容
│ └──► tool_use 块 → 进入工具执行分支
│
├──► 6. 工具执行分支(如果检测到 Tool Use)
│ ├──► findToolByName() // 匹配工具
│ ├──► wrappedCanUseTool() // 权限检查
│ │ ├──► allow → 执行工具
│ │ ├──► ask → 弹出权限对话框
│ │ └──► deny → 记录拒绝
│ ├──► runTools() / StreamingToolExecutor // 执行工具
│ └──► 工具结果 → 追加到消息历史 → 回到步骤 3(循环)
│
├──► 7. 一轮结束后的处理
│ ├──► 检查 Token 用量(预算限制)
│ ├──► 检查上下文长度(是否需要 compact)
│ ├──► 生成工具使用摘要(toolUseSummary)
│ └──► 持久化会话记录
│
└──► 8. yield 最终消息,generator 结束
5.3 工具执行详解
typescript
// query.ts 中的核心循环
const toolExecutions = extractToolUseBlocks(assistantMessage)
for (const toolUse of toolExecutions) {
const tool = findToolByName(tools, toolUse.name)
// 权限检查
const permission = await canUseTool(tool, toolUse.input, toolUseContext, ...)
if (permission.behavior === 'allow') {
// 执行工具
const result = await tool.call(toolUse.input, toolUseContext)
// 结果追加到消息历史
messages.push(createToolResultMessage(toolUse.id, result))
} else if (permission.behavior === 'ask') {
// 暂停,等待用户确认(通过 REPL UI)
yield createPermissionRequestMessage(toolUse)
// 用户确认后再次进入循环
}
}
6. 主对话循环数据流
┌─────────┐ ┌─────────────┐ ┌─────────────────┐
│ 用户 │────►│ 键盘输入 │────►│ REPL.tsx │
│ │ │ (Ink TUI) │ │ (UI 渲染层) │
└────▲────┘ └─────────────┘ └────────┬────────┘
│ │
│ ① 用户输入 prompt │
│ ▼
│ ┌─────────────────┐
│ │ QueryEngine. │
│ │ submitMessage() │
│ └────────┬────────┘
│ │
│ ② 构建完整上下文 │
│ (System Prompt + History) ▼
│ ┌─────────────────┐
│ │ Claude API │
│ │ (streamMessage)│
│ └────────┬────────┘
│ │
│ ③ 流式 SSE 响应 │
│ ┌────────┴────────┐
│ ▼ ▼
│ ┌─────────────┐ ┌─────────────────┐
│ │ 文本内容 │ │ tool_use 块 │
│ │ → 直接展示 │ │ → 进入工具分支 │
│ └──────┬──────┘ └────────┬────────┘
│ │ │
│ │ ┌─────────┴─────────┐
│ │ ▼ ▼
│ │ ┌────────────┐ ┌──────────────┐
│ │ │ 权限检查 │ │ 执行工具 │
│ │ │ CanUseTool │───►│ Tool.call() │
│ │ └────────────┘ └──────┬───────┘
│ │ │
│ │ ┌────────────┘
│ │ │
│ │ ▼
│ │ ┌─────────────────┐
│ │ │ 工具执行结果 │
│ │ │ ToolResult │
│ │ └────────┬────────┘
│ │ │
│ └──────────────┘
│ │
│ ④ 更新消息历史 │
│ (追加 assistant + tool_result) ▼
│ ┌─────────────────┐
│ │ 上下文检查 │
│ │ - Token 超限? │──是──► Compact
│ │ - 预算耗尽? │──是──► 停止
│ │ - 达到 max-turns│──是──► 退出
│ └────────┬────────┘
│ │ 否
│ ⑤ 如果还有 tool_use │
│ 回到步骤 ② 循环 │
│ ▼
│ ┌─────────────────┐
└──────────────────────────────┤ 渲染最终结果 │
│ 给用户 │
└─────────────────┘
关键循环特性
- 多轮工具调用:一次用户输入可能触发 Claude 多次调用工具(每轮是一个 API 请求)
- 流式渲染 :API 响应通过
AsyncGenerator流式 yield,UI 实时更新 - 权限中断:工具执行前可能暂停等待用户确认,确认后继续
- 上下文压缩:当消息历史过长时,自动触发 Compact/Snip 减少 Token
7. 阅读路线图
如果你想深入阅读这份源码,建议按以下顺序:
第一层:骨架(1-2 小时)
README.md--- 项目概览src/main.tsx(前 100 行 +main()+run())--- 入口流程src/entrypoints/init.ts--- 初始化逻辑src/setup.ts--- 会话设置
第二层:核心(2-3 小时)
src/QueryEngine.ts--- 对话引擎核心(重点读submitMessage)src/query.ts--- API 调用与流式处理src/Tool.ts--- 工具抽象与权限模型src/state/AppState.tsx+store.ts--- 状态管理
第三层:工具(2-3 小时)
src/tools/BashTool.ts--- Shell 执行与沙箱src/tools/FileReadTool.ts/FileWriteTool.ts/FileEditTool.ts--- 文件操作src/tools/AgentTool.ts--- 多智能体调度src/tools/MCPTool.ts--- MCP 协议集成
第四层:子系统(按需)
src/services/api/--- Claude API 调用层mcp/--- MCP 客户端autoDream/--- 记忆整理compact/--- 上下文压缩
src/bridge/--- IDE 集成src/coordinator/--- Swarm 多智能体协调src/buddy/--- Tamagotchi 彩蛋 😄
结语
Claude Code 的源码展现了构建生产级 AI 编程助手所需的全套工程实践:
- 分层清晰的架构:UI → 引擎 → 工具 → 服务,每层职责单一
- 完善的权限模型:从文件系统到 Shell 执行,层层把关
- 企业级功能:远程管理、策略限制、审计、SSO 一应俱全
- 性能优化:预连接、预取、并行初始化、懒加载无处不在
- 扩展性设计:MCP 协议、Plugin 系统、Hook 机制、Slash 命令
这份源码是理解「AI Agent 工程化」的绝佳教材。
本文基于研究目的对公开源码进行分析,所有原始代码版权归 Anthropic PBC 所有。