Skip to content

02 — 入口与启动流程

概述

Claude Code 有三种运行模式,对应三个入口点。理解启动流程是阅读后续代码的基础——因为启动阶段决定了哪些模块被初始化、哪些被跳过,以及运行时状态的初始值。

模式入口场景
交互式 REPLmain.tsxreplLauncher.tsx终端中直接运行 claude
非交互式 (pipe/print)main.tsxcli/print.tsclaude --print "..." 或 管道输入
MCP Serverentrypoints/mcp.ts其他工具通过 MCP 协议调用 Claude Code
SDK 嵌入entrypoints/sdk/第三方代码通过 SDK 直接调用

三种模式最终都收敛到同一个 query 循环query.ts),只是 UI 层和 IO 层不同。

启动时序

阶段 1: 并行预取 — 为什么在 import 之前?

main.tsx 的前 20 行是精心设计的启动优化。在 Bun 解析后续 ~135ms 的 import 时,已经有三个异步操作在并行执行:

typescript
// 这些副作用必须在所有其他 import 之前执行:
profileCheckpoint('main_tsx_entry');  // 标记入口时间

startMdmRawRead();     // 启动 plutil 子进程读取 MDM 受管配置
startKeychainPrefetch(); // 启动 macOS Keychain 读取 (OAuth + 旧版 API Key)

这种"在 import 期间做 IO"的模式看起来不寻常,但在 CLI 工具中是有效的——用户感知到的启动时间 = max(import 时间, IO 时间),而不是两者之和。

阶段 3: setup.ts — 做了什么?

setup() 是一次性的会话环境准备。它和 init() 的区别是:init() 是全局的(不依赖具体目录),setup() 是会话级的(依赖 cwd)。

步骤具体操作为什么重要
Node 版本检查要求 >= 18兼容性保证
Git Root 查找findCanonicalGitRoot()确定项目边界,CLAUDE.md 搜索范围
CWD 设置setCwd() + setProjectRoot()所有 Tool 的路径解析基准
Session 初始化switchSession()创建唯一 Session ID,关联日志/遥测
Worktree (可选)createWorktreeForSession()Git worktree 隔离工作区
Hooks 快照captureHooksConfigSnapshot()运行时检测 hooks 配置变化
File WatcherinitializeFileChangedWatcher()监听配置文件变更
Session MemoryinitSessionMemory()加载上一次会话的记忆上下文
Release NotescheckForReleaseNotes()升级后首次运行提示新功能

阶段 4: 运行时组装 — Tool、Command、Prompt 是如何装配的?

这是启动中最关键的步骤。在 REPL 启动前,main.tsx 会把所有 "零件" 装配到一起:

  1. Tool 加载 (getTools()): 从 tools/ 目录加载所有内置 Tool 实例,加上 MCP 提供的远程工具
  2. Command 加载 (getCommands()): 从 commands/ 目录加载所有斜杠命令定义
  3. System Prompt 构建 (getSystemPrompt()): 组装完整的系统提示(见 07-服务层
  4. MCP 连接: 发现并连接所有配置的 MCP 服务器
  5. Agent 定义: 加载内置 Agent + 用户自定义 Agent(从 ~/.claude/agents/

所有这些最终汇聚成 AppState 的初始值,传给 REPL 组件。

replLauncher.tsx — 为什么单独一个文件?

tsx
export async function launchRepl(root, appProps, replProps, renderAndRun) {
  const { App } = await import('./components/App.js')
  const { REPL } = await import('./screens/REPL.js')
  await renderAndRun(root, <App {...appProps}><REPL {...replProps} /></App>)
}

这个文件虽然只有几行,但它存在的原因是 代码分割:通过 dynamic importAppREPL 的代码(及其依赖的 100+ 组件)只在交互模式下才加载。非交互模式(--print)不会执行这段代码,从而加快冷启动。

entrypoints/ — 其他入口

文件运行模式说明
cli.tsx非交互--print 模式:只输出文本,不启动 TUI
init.ts所有模式全局初始化(配置、认证、遥测),所有入口都会调用
mcp.tsMCP ServerClaude Code 自身作为 MCP 服务端暴露工具能力
sdk/coreSchemas.tsSDKSDK 的输入/输出 JSON Schema
sdk/coreTypes.tsSDKSDK 的 TypeScript 类型定义
sdk/controlSchemas.tsSDKSDK 控制命令的 Schema
agentSdkTypes.tsSDKAgent SDK 类型定义
sandboxTypes.ts所有模式沙箱类型定义

入口收敛图

无论哪种入口,最终都通过 query.tsquery() 生成器与 Claude API 通信。这个生成器是整个系统的核心,详见 04-REPL 与 Query 循环

Feature Flags — 编译期代码分割

项目使用 bun:bundlefeature()构建时 决定代码分支。这不是运行时 if/else,而是在 bundle 时直接删除不需要的代码路径:

typescript
import { feature } from 'bun:bundle'

// 构建时如果 COORDINATOR_MODE=false,整个 require 和 coordinatorModule 会被删除
const coordinatorModule = feature('COORDINATOR_MODE')
  ? require('./coordinator/coordinatorMode.js') : null
Feature Flag功能说明
COORDINATOR_MODE协调者模式多 Agent 编排的高级模式
KAIROSAssistant 模式Kairos 助手(含 Dream、Brief 等)
BRIDGE_MODEIDE BridgeVS Code / JetBrains 集成
DAEMON后台守护进程远程控制服务端
VOICE_MODE语音输入语音转文字
HISTORY_SNIP历史截断对话历史管理优化
WORKFLOW_SCRIPTS工作流脚本可编排的自动化脚本
PROACTIVE主动建议模型主动提出操作建议
CCR_REMOTE_SETUP远程设置claude.ai Web 端远程控制
EXPERIMENTAL_SKILL_SEARCH实验性 Skill 搜索基于语义的 Skill 查找

这意味着不同的构建配置会产生功能不同的二进制文件。公开发行版通常只启用稳定的 feature flags。