# Claude Code 数据流与生命周期 ## 1. 启动流程 ### 1.1 完整启动序列 ``` 终端执行: bun run dev (→ bun run src/entrypoints/cli.tsx) │ ├── Phase 0: 预加载 │ ├── globalThis.MACRO 注入 (版本号、构建信息) │ ├── process.env 初始化 (COREPACK_ENABLE_AUTO_PIN, NODE_OPTIONS) │ └── Ablation baseline 环境变量设置 │ ├── Phase 1: 快速路径路由 │ ├── --version → console.log(MACRO.VERSION) → 退出 │ ├── --dump-system-prompt → 渲染系统提示词 → 退出 │ ├── --claude-in-chrome-mcp → 启动 Chrome MCP Server │ ├── --chrome-native-host → 启动 Chrome Native Host │ └── --computer-use-mcp → 启动 Computer Use MCP │ ├── Phase 2: CLI 初始化 (cli.tsx main()) │ ├── import startupProfiler → profileCheckpoint('cli_entry') │ ├── import commander → 解析命令行参数 │ ├── import enableConfigs() → 加载用户配置 │ ├── 注册所有 Command (commands.ts, 60+) │ ├── 挂载 hook 系统 │ └── commander.parse() → 路由到对应命令 │ ├── Phase 3: REPL 启动 (默认模式) │ ├── import main.tsx → 启动 Ink 渲染器 │ │ ├── 注册 bun:bundle polyfill (entry.ts) │ │ └── import App.tsx │ │ │ ├── 组件挂载 │ │ ├── 检查环境 (Bun版本/终端能力) │ │ ├── 加载认证状态 (auth.ts) │ │ ├── 初始化 AppStore (createStore) │ │ ├── 运行 preflightChecks (网络可达性) │ │ └── 加载 MCP 服务端配置 │ │ │ └── 进入 REPL 主循环 │ ├── 加载历史会话 (sessionRestore.ts) │ ├── 显示欢迎信息和系统提示 │ └── 等待用户输入 │ └── Phase 4: UI 就绪 ├── VirtualMessageList 渲染历史消息 ├── StatusLine 显示模型/成本/快捷键 └── TextInput 获得焦点,等待输入 ``` ### 1.2 启动优化策略 - **延迟加载**: `cli.tsx` 中的 `await import()` 确保快速路径不加载不必要模块 - **Feature Flag DCE**: `feature('PROACTIVE')` 在构建时消除死代码 - **Profile Checkpoint**: `startupProfiler.ts` 记录各阶段耗时 - **预连接**: `apiPreconnect.ts` 在启动时预建立 HTTPS 连接 --- ## 2. 对话循环(核心数据流) ### 2.1 主循环 ``` 用户输入 "帮我重构这个函数" │ ├── Step 1: 输入处理 (handlePromptSubmit.ts) │ ├── 解析 @file / @agent 等提及 │ ├── 处理剪贴板图片粘贴 │ ├── 处理引用消息 (↑ 历史选取) │ └── 构建 UserMessage { role: 'user', content: [...] } │ ├── Step 2: 预处理 Hooks (hooks.ts, 164KB) │ ├── UserPromptSubmit hook: 修改/拦截用户输入 │ ├── 注入 CLAUDE.md 系统上下文 │ ├── 加载 MEMORY.md 记忆内容 │ └── 加载 Skills 和 MCP 指令 │ ├── Step 3: 构建 Query (QueryEngine.ts) │ ├── 构建 System Prompt: │ │ ├── 基础系统提示词 (constants/prompts.ts, 55KB) │ │ ├── 环境信息 (OS/Shell/Git/日期) │ │ ├── 工具清单 (所有可用工具的 name + description + schema) │ │ ├── CLAUDE.md 内容 (项目级 + 用户级) │ │ ├── MEMORY.md 内容 (自动记忆) │ │ └── MCP 服务端提供的上下文 │ │ │ ├── 构建 Messages: │ │ ├── 历史消息 (截断至 Token 预算) │ │ ├── 当前 UserMessage │ │ └── Tool Results (若有待回传) │ │ │ └── 选择模型: getMainLoopModel() → Claude Opus/Sonnet/Haiku │ ├── Step 4: API 调用 │ ├── POST https://api.anthropic.com/v1/messages │ ├── Headers: x-api-key, anthropic-version, ... │ ├── Body: { model, system, messages, tools, max_tokens, ... } │ ├── Stream: true (SSE 流式响应) │ │ │ └── 处理响应流 (server-sent events) │ ├── message_start → 新消息开始 │ ├── content_block_start → 文本块/工具调用块开始 │ ├── content_block_delta → 增量内容 (text_delta / input_json_delta) │ ├── content_block_stop → 块结束 │ ├── message_delta → 用量/结束原因 │ └── message_stop → 消息完成 │ ├── Step 5: 响应处理 │ ├── 解析 content_block 类型: │ │ ├── text → 实时渲染 Markdown (打字机效果) │ │ ├── tool_use → 进入工具调用流程 (见 Step 6) │ │ └── thinking → 渲染扩展思考 (可选展示) │ │ │ └── 更新会话状态: │ ├── 追加 AssistantMessage 到消息列表 │ ├── 更新 Token 使用量 / 成本 │ └── 持久化到 sessionStorage │ ├── Step 6: 工具调用循环 (Tool Use Loop) │ ├── 解析 tool_use 参数 (JSON → Zod 校验) │ ├── 权限检查 (useCanUseTool) │ │ ├── 需要用户确认 → 弹出权限 UI → 等待用户决策 │ │ │ ├── 批准 → 继续 │ │ │ └── 拒绝 → 返回拒绝消息 │ │ └── 自动批准 → 继续 │ │ │ ├── 执行工具: │ │ ├── 触发 PreToolUse hooks │ │ ├── tool.toolUseOutput(params) │ │ │ ├── BashTool: spawn 子进程 + 流式输出 │ │ │ ├── FileEditTool: 读取文件 + 字符串替换 + 写回 │ │ │ ├── AgentTool: fork 子 Agent + 等待完成 │ │ │ └── WebFetchTool: HTTP GET + HTML→Markdown + AI 提取 │ │ └── 触发 PostToolUse hooks │ │ │ ├── 构建 ToolResult: │ │ { role: 'user', content: [{ type: 'tool_result', tool_use_id, content }] } │ │ │ ├── 回传模型 (回到 Step 4) │ │ 模型收到工具结果后继续生成回复或调用更多工具 │ │ │ └── 循环终止条件: │ ├── 模型仅返回 text (不再调用工具) │ ├── 达到最大工具轮次 │ ├── 用户手动中断 (Ctrl+C) │ └── Token 预算用尽 (触发自动压缩) │ ├── Step 7: 响应完成 │ ├── 触发 Stop hooks │ ├── 自动内存提取 (extractMemories) │ ├── 文件历史快照 (fileHistoryMakeSnapshot) │ ├── 更新会话标题 (sessionTitle.ts) │ └── 统计记录 (成本/时间/工具调用次数) │ └── 回到 Step 1: 等待下一条用户输入 ``` ### 2.2 流式渲染管道 ``` API SSE Stream │ ▼ Stream Processor (query.ts) │ 解析 SSE events, 拼接 JSON fragments ▼ Message Builder (messages.ts) │ 构建 Message 对象树 ▼ React State Update (useReplBridge.tsx) │ setState(newMessage) → React re-render ▼ Ink Reconciler (ink/reconciler.ts) │ Virtual DOM diff ▼ Node → ANSI Renderer (ink/render-node-to-output.ts) │ React 元素 → ANSI 字符串 ▼ Screen Buffer (ink/screen.ts) │ 计算 diff, 仅输出变化部分 ▼ Terminal Output (ink/output.ts) │ process.stdout.write(ansiString) ▼ 用户终端 ``` --- ## 3. Task 生命周期 ### 3.1 主会话任务 ``` 用户连接 REPL │ ├── 创建 LocalMainSessionTask │ ├── status: 'pending' │ ├── 开始首次对话 → status: 'running' │ │ ├── 每次对话循环 (QueryEngine) │ │ └── 工具执行 (Bash/Agent/...) │ │ │ └── 结束条件: │ ├── 用户退出 (Ctrl+C / /exit) → status: 'completed' │ ├── 崩溃/异常 → status: 'failed' │ └── 用户中断 (Ctrl+C during run) → status: 'cancelled' │ └── 会话持久化 (sessionStorage.ts) └── ~/.claude/projects//.jsonl ``` ### 3.2 子 Agent 任务 ``` AgentTool.toolUseOutput() │ ├── 创建 LocalAgentTask 或 RemoteAgentTask │ ├── status: 'pending' │ ├── 分配工具子集 (根据 subagent_type) │ │ ├── general-purpose → 全部工具 │ │ ├── explore → Glob + Grep + Read (只读) │ │ └── plan → 仅计划工具 │ │ │ ├── 构建独立系统提示词 (Agent 角色描述) │ │ │ └── 开始执行: │ ├── status: 'running' │ ├── 独立对话循环 (独立的 QueryEngine) │ │ ├── 上下文隔离 (不共享主会话消息) │ │ └── 消耗独立 Token 预算 │ │ │ ├── run_in_background: true │ │ ├── 后台执行,不阻塞 │ │ └── 完成时通过 notification 通知 │ │ │ └── run_in_background: false (默认) │ ├── 前台阻塞等待 │ └── 完成时返回结果给调用者 │ └── 结果归并: ├── 成功 → 提取关键产出 + 清理临时上下文 └── 失败 → 错误信息 + 部分产出 ``` ### 3.3 Shell 后台任务 ``` BashTool 长时间命令 │ ├── 创建 LocalShellTask │ ├── 后台执行: spawn(command, { detached: true }) │ ├── 实时输出: stdout/stderr → stream │ │ └── UI 实时显示在 TaskListV2 面板 │ │ │ └── 完成: exitCode + 完整输出 │ └── 生命周期管理: ├── 用户可随时取消: task.kill() ├── 超时自动终止: setTimeout(kill, timeout) └── 退出清理: gracefulShutdown 等待所有任务完成 ``` --- ## 4. 会话持久化与恢复 ### 4.1 会话存储结构 ``` ~/.claude/ ├── projects/ │ └── / │ ├── .jsonl # 完整对话记录 (JSONL) │ ├── .meta.json # 会话元数据 │ └── memory/ │ └── MEMORY.md # 自动记忆索引 │ ├── settings.json # 用户全局设置 ├── credentials.json # API Key 等凭证 (加密) └── stats/ └── usage.json # 用量统计 ``` ### 4.2 会话恢复流程 ``` claude --resume (或 /resume 命令) │ ├── listSessionsImpl() 列出所有历史会话 │ └── 解析 .meta.json → 标题/时间/模型 │ ├── ResumeConversation 界面 │ └── 用户选择要恢复的会话 │ ├── sessionRestore.ts 加载会话 │ ├── 读取 .jsonl 文件 │ ├── 解析所有 Message 对象 │ ├── 重建 AppState (消息列表/任务状态) │ └── 恢复上下文 (模型/配置/权限模式) │ └── 继续对话 (从上次中断处) ``` ### 4.3 会话导出 ``` ExportDialog ├── Markdown: 渲染对话为 .md 文件 ├── JSON: 原始 JSON 格式 ├── HTML: 静态 HTML 页面 (含样式) └── PNG: 终端截图 (通过 ansiToPng, 215KB) ``` --- ## 5. Bridge 模式数据流 ### 5.1 Bridge 连接流程 ``` 本地 Claude Code (Client) 远程环境 (Server) │ │ ├── claude remote-control │ │ (启动 Bridge 监听) │ │ │ ├── WebSocket/TCP 连接 ────────────────►│ │ ├── 鉴权 (JWT/TrustedDevice) │ ├── 环境信息交换 │ ◄── Handshake OK ────────────────│ ├── 创建工作目录 │ │ ├── 会话同步 (replBridge.ts, 102KB) │ │ ├── 发送 AppState 快照 ───────────►│ ├── 应用状态到远程 │ ├── 发送用户消息 ──────────────────►│ ├── 执行查询 │ │ │ ├── 工具调用在远程执行 │ │ ◄── 流式响应 ────────────────│ ├── 文件操作在远程执行 │ │ │ │ ◄── 状态同步 ────────────────────│ ├── 远程文件变化回传 │ ◄── 进度通知 ────────────────────│ │ │ │ └── 双向同步维持 │ ├── 心跳 (keep-alive) │ ├── 断线重连 (replBridgeTransport) │ └── 会话恢复 (sessionRunner) │ ``` ### 5.2 Bridge 状态机 ``` DISCONNECTED │ (用户触发连接) ▼ CONNECTING │ (WebSocket 连接建立) ├── 成功 → HANDSHAKE └── 失败 → DISCONNECTED (显示错误, 可重试) HANDSHAKE │ (JWT 验证 + 设备信任) ├── 成功 → CONNECTED └── 失败 → DISCONNECTED (认证错误) CONNECTED │ (会话同步初始化) ▼ SYNCED │ (正常双向通信) ├── 断线 → RECONNECTING └── 用户断开 → DISCONNECTED RECONNECTING ├── 重连成功 → SYNCED └── 超时 → DISCONNECTED ``` --- ## 6. Memory 系统数据流 ### 6.1 记忆生命周期 ``` 会话启动 │ ├── memdir.loadMemoryPrompt() │ ├── 扫描 ~/.claude/projects//memory/ │ ├── 读取 MEMORY.md 索引 │ ├── 读取每个 .md 记忆文件 │ │ ├── 解析 frontmatter (name/description/type) │ │ └── 提取正文内容 │ │ │ └── findRelevantMemories() │ ├── 基于当前会话上下文匹配相关记忆 │ └── 按新鲜度排序 (memoryAge) │ ├── 拼入 System Prompt │ └── "# Memory\n... (相关记忆内容) ..." │ └── 会话中 ├── 模型使用 Write 工具 → 写入新的 .md 文件 │ └── 更新 MEMORY.md 索引 │ ├── extractMemories 服务 → 自动从对话中提取 │ └── 后台异步写入 │ └── 会话结束 └── 记忆文件保持不变 (跨会话持久化) ``` ### 6.2 四种记忆类型 ```markdown --- name: <名称> description: <一行描述> type: user | feedback | project | reference --- <内容> ``` | 类型 | 用途 | 示例 | |---|---|---| | **user** | 用户角色/偏好/知识 | "用户是资深 Go 开发者" | | **feedback** | 用户反馈的行为规范 | "不要 mock 数据库测试" | | **project** | 项目上下文/目标 | "下周四冻结合并" | | **reference** | 外部系统指针 | "Bug 在 Linear INGEST 项目里" | --- ## 7. Hook 系统 ### 7.1 可用 Hook 事件 ```typescript interface Hooks { // 事件触发型 UserPromptSubmit: (messages) => messages // 用户提交前 PreToolUse: (toolName, params) => params // 工具执行前 PostToolUse: (toolName, result) => void // 工具执行后 Stop: (session) => void // 对话完成 // 通知型 Notification: (event) => void // 各类事件通知 SessionStart: (info) => void // 会话启动 // 配置型 (settings.json) // "hooks": { "PreToolUse": [{ "matcher": "Bash", "command": "..." }] } } ``` ### 7.2 Hook 执行流程 ``` 事件触发 │ ├── 加载 hooks 配置 (hooks.ts) │ ├── settings.json 中的 hooks 数组 │ └── 项目级 .claude/settings.json │ ├── 匹配规则 │ ├── matcher: 工具名/正则/通配符 │ └── 仅匹配的 hook 执行 │ └── 执行 ├── shell command hooks: spawn(command, args) ├── 内置 hooks: 调用内部函数 └── 超时控制: 长时间 hook 被终止 ``` --- ## 8. 工具结果存储 `toolResultStorage.ts` (39KB) 负责工具调用结果(特别是大文件)的存储策略: - **小结果** (< 阈值): 直接存在消息对象中 - **大结果**: 写入临时文件,消息中只存文件引用路径 - **图片结果**: 存为 Base64 或文件引用,带缩放缓存 - **清理**: 会话关闭时自动清理临时文件 --- ## 9. 错误处理与恢复 ### 9.1 API 错误分类 ``` API 错误 ├── 可重试错误 (retryable) │ ├── 429 Rate Limit → 指数退避重试 │ ├── 5xx Server Error → 线性退避重试 │ └── 网络超时 → 立即重试 (最多3次) │ ├── 不可重试错误 │ ├── 401 Unauthorized → 提示检查 API Key │ ├── 403 Forbidden → 提示检查权限 │ ├── 400 Bad Request → 显示错误详情 │ └── Token 超限 → 触发自动压缩 │ └── 流式中断 ├── SSE 连接断开 → 尝试重连 + 部分结果 └── 解析错误 → 丢弃损坏chunk,继续 ``` ### 9.2 对话崩溃恢复 ``` 异常发生 │ ├── conversationRecovery.ts │ ├── 自动保存当前状态 (crash snapshot) │ ├── 标记会话为 interrupted │ └── 下次启动时提示恢复 │ └── 用户重启 Claude Code ├── 检测到未完成会话 ├── 显示 ResumeConversation 界面 └── 从崩溃点恢复对话 (最多丢失最后一条消息) ``` --- *本文档基于 2026-06-11 源码状态生成*