启动流程详解
Claude Code 的启动过程涉及 3 个关键文件和多个初始化步骤,从 CLI 解析到 REPL 界面完全就绪。
启动链概览
用户执行 `claude` 命令
↓
entrypoints/cli.tsx (~303 行)
├── main() — 命令行路由入口
│ ├── args 路由判断 (16+ 个 feature-gated 快速路径)
│ ├── 特殊模式检测: --version, --mcp, -p, server, bridge, daemon 等
│ └── 动态 import 目标模块
↓
main.tsx (~4684 行)
├── Commander.js 选项解析 (~50 个选项)
├── CURRENT_MIGRATION_VERSION = 11 — 运行迁移
├── runMigrations() — 9 个同步 + 2 个条件 + 1 个异步迁移
└── 启动 REPL 或执行一次性查询
↓
entrypoints/init.ts (~309 行)
├── enableConfigs() — 验证并启用配置系统
├── applySafeConfigEnvironmentVariables() + applyExtraCACertsFromConfig()
├── setupGracefulShutdown() — 注册清理钩子
├── 初始化 1P 事件日志 + GrowthBook
├── populateOAuthAccountInfoIfNeeded()
├── initJetBrainsDetection()
├── detectCurrentRepository()
├── initializeRemoteManagedSettingsLoadingPromise()
├── configureGlobalMTLS() + configureGlobalAgents()
├── preconnectAnthropicApi()
└── (延迟) initTelemetryAfterTrust → OTEL 加载 (~400KB)
↓
screens/REPL.tsx — 交互式循环
├── App.tsx → Provider 组合
├── StatusLine → 状态栏
├── PromptInput → 用户输入
└── 等待用户交互...第一站:cli.tsx — 命令行路由
entrypoints/cli.tsx 是整个应用的入口点,main() 函数实现了一个巨型路由器,所有依赖都使用动态 import() 以最小化模块加载。
关键路由表
| 条件 | 目标 | 说明 |
|---|---|---|
--version / -v / -V | 直接输出版本 | 零模块加载快速路径 |
--dump-system-prompt | 导出系统提示词 | feature gate DUMP_SYSTEM_PROMPT |
--claude-in-chrome-mcp | Chrome MCP | Chrome MCP 服务器 |
--computer-use-mcp | Computer Use MCP | feature gate CHICAGO_MCP |
--daemon-worker (DAEMON) | Daemon Worker | 内部 worker 进程 |
remote-control/rc/remote/sync/bridge (BRIDGE_MODE) | Bridge 模块 | claude.ai 桥接 |
daemon (DAEMON) | 守护进程 Supervisor | 后台运行 |
ps/logs/attach/kill/--bg (BG_SESSIONS) | 会话管理 | 后台会话管理 |
new/list/reply (TEMPLATES) | 模板系统 | 模板创建/列表/回复 |
environment-runner (BYOC_ENVIRONMENT_RUNNER) | 环境运行器 | BYOC 环境 |
self-hosted-runner (SELF_HOSTED_RUNNER) | 自托管运行器 | 自托管模式 |
--tmux + --worktree | tmux worktree | tmux worktree 快速路径 |
--update/--upgrade | 更新子命令 | 重定向到 update |
| 默认 | main.tsx → cliMain() | 交互式终端界面 |
第二站:main.tsx — Commander.js 配置
main.tsx (~4684 行) 是最核心的启动文件,使用 Commander.js 定义 ~50 个 CLI 选项:
关键选项
typescript
program
.option('-p, --pipe', '管道模式(一次性查询)')
.option('--model <model>', '模型选择')
.option('--max-turns <n>', 'Agent 最大轮次')
.option('--permission-mode <mode>', '权限模式')
.option('--allowedTools <tools...>', '允许的工具')
.option('--resume <session>', '恢复会话')
.option('--add-dir <dir>', '添加工作目录')
.option('--output-format <fmt>', '输出格式 (text|json|stream-json)')
.option('--verbose', '详细日志')
.option('--dangerously-skip-permissions', '跳过权限(危险)')
// ...更多选项迁移系统
typescript
// src/main.tsx L325
const CURRENT_MIGRATION_VERSION = 11
// runMigrations() 中的实际迁移(按执行顺序):
// 同步迁移:
// migrateAutoUpdatesToSettings()
// migrateBypassPermissionsAcceptedToSettings()
// migrateEnableAllProjectMcpServersToSettings()
// resetProToOpusDefault()
// migrateSonnet1mToSonnet45()
// migrateLegacyOpusToCurrent()
// migrateSonnet45ToSonnet46()
// migrateOpusToOpus1m()
// migrateReplBridgeEnabledToRemoteControlAtStartup()
// 条件迁移:
// resetAutoModeOptInForDefaultOffer() — 仅 feature('TRANSCRIPT_CLASSIFIER') 时
// migrateFennecToOpus() — 仅内部构建 (ant) 时
// 异步迁移 (fire-and-forget):
// migrateChangelogFromConfig()第三站:init.ts — 多步骤初始化
entrypoints/init.ts 导出一个被 memoize 包裹的 init() 异步函数,确保只执行一次。
注意: 与文档旧版不同,init 并非简单的 5 个命名阶段,而是一系列顺序步骤,通过
profileCheckpoint标记进度。
初始化步骤(按实际执行顺序)
typescript
async function init() {
// 1. enableConfigs() — 验证并启用配置系统
// 2. applySafeConfigEnvironmentVariables() + applyExtraCACertsFromConfig()
// 3. setupGracefulShutdown() — 注册 SIGINT/SIGTERM/exit 清理
// 4. 异步初始化 1P 事件日志 + GrowthBook 特性门控
// 5. populateOAuthAccountInfoIfNeeded() — OAuth 账户信息
// 6. initJetBrainsDetection() — JetBrains IDE 检测
// 7. detectCurrentRepository() — 当前仓库检测
// 8. initializeRemoteManagedSettingsLoadingPromise() — 远程托管设置
// + initializePolicyLimitsLoadingPromise() — 策略限制
// 9. recordFirstStartTime() — 记录首次启动时间
// 10. configureGlobalMTLS() — mTLS 客户端证书
// 11. configureGlobalAgents() — 代理配置
// 12. preconnectAnthropicApi() — API 预连接
// 13. initUpstreamProxy() — 仅 CLAUDE_CODE_REMOTE 时
// 14. setShellIfWindows() — Windows Shell 设置
// 15. registerCleanup(shutdownLspServerManager) — LSP 清理
// + registerCleanup(cleanupSessionTeams) — 会话团队清理
// 16. ensureScratchpadDir() — 仅 scratchpad 启用时
}延迟初始化: initTelemetryAfterTrust
typescript
async function initializeTelemetryAfterTrust() {
// 仅在用户接受信任对话框后执行
// 延迟加载 OpenTelemetry (~400KB OTEL SDK)
// 初始化 2 个 sink:
// - Datadog (允许事件白名单)
// - 1P (BatchLogRecordProcessor)
// 配置采样率(按事件名称)
// 配置 GrowthBook killswitch
}第四站:REPL.tsx — 交互式界面
screens/REPL.tsx 是主界面组件,负责将所有系统组合成用户可交互的终端 UI:
组件树
<REPL>
<App>
<FpsMetricsProvider>
<StatsProvider>
<AppStateProvider initialState={...}>
<FullscreenLayout>
<ScrollBox>
<LogoHeader />
<VirtualMessageList messages={...} />
</ScrollBox>
<StatusLine />
<PromptInput />
</FullscreenLayout>
</AppStateProvider>
</StatsProvider>
</FpsMetricsProvider>
</App>
</REPL>REPL Props
typescript
// 实际类型名为 Props(非 REPLProps)
export type Props = {
commands: Command[]
initialTools: Tool[]
mcpClients?: MCPServerConnection[] // 可选,类型为 MCPServerConnection[]
remoteSessionConfig?: RemoteSessionConfig
systemPrompt?: string
initialMessages?: Message[]
debug?: boolean
thinkingConfig: ThinkingConfig // 必选
pendingHookMessages?: Message[]
// ... 还有 initialContentReplacements, dynamicMcpConfig,
// strictMcpConfig, sshSession, directConnectConfig, taskListId 等
}初始化时序图
t=0ms cli.tsx main() 开始
t=5ms ├── args 路由判断
t=10ms ├── dynamic import main.tsx
t=20ms main.tsx 开始
t=25ms ├── Commander.js 解析选项
t=30ms ├── runMigrations() (11 个迁移)
t=50ms ├── init() 开始 (5 阶段)
t=55ms │ ├── enableConfigs()
t=80ms │ ├── applySafeConfigEnvironmentVariables()
t=120ms │ ├── setupGracefulShutdown()
t=150ms │ ├── initializeRemoteManagedSettingsLoadingPromise()
t=200ms │ └── preconnectAnthropicApi()
t=220ms REPL.tsx 挂载
t=250ms ├── AppState 初始化 (80+ 字段)
t=280ms ├── 工具池构建 (assembleToolPool)
t=300ms ├── Ink 渲染引擎启动
t=350ms ├── 首帧渲染
t=400ms └── 等待用户输入
-------- 延迟初始化 --------
t=500ms initTelemetryAfterTrust (如信任已建立)
t=600ms MCP 服务器连接 (并行)
t=800ms GrowthBook 配置刷新启动优化技术
- 延迟 import: 除入口外的模块全部
await import()按需加载 - 记忆化初始化:
init.ts中每个阶段只执行一次(memoize) - 并行加载: MCP 客户端连接并行启动
- 延迟遥测: OTEL ~400KB 在信任建立后才加载
- 渐进渲染: 首帧先显示 Logo + 输入框,数据后续填充