跳转到内容

入口与 Bootstrap

理解 Claude Code 的 bootstrap 过程是理解一切的基础。启动序列跨越四个文件,各自承担不同职责:快速路由、核心初始化、CLI 框架以及环境配置。

sequenceDiagram
    participant OS as Operating System
    participant CLI as cli.tsx
    participant INIT as init.ts
    participant MAIN as main.tsx
    participant SETUP as setup.ts
    participant REPL as REPL.tsx

    OS->>CLI: bun run cli.tsx
    CLI->>CLI: Fast-path checks (--version, --bridge, etc.)
    CLI->>INIT: init()
    INIT->>INIT: enableConfigs()
    INIT->>INIT: applySafeConfigEnvironmentVariables()
    INIT->>INIT: setupGracefulShutdown()
    INIT->>INIT: configureGlobalAgents() (proxy/mTLS)
    CLI->>MAIN: Dynamic import main.tsx
    MAIN->>MAIN: Side effects: profiler, MDM, keychain
    MAIN->>MAIN: Commander.js argument parsing
    MAIN->>MAIN: API key validation
    MAIN->>MAIN: MCP server initialization
    MAIN->>SETUP: setup(cwd, permissionMode, ...)
    SETUP->>SETUP: setCwd(), captureHooksConfigSnapshot()
    SETUP->>SETUP: Worktree creation (if --worktree)
    SETUP->>SETUP: Background jobs, telemetry
    MAIN->>REPL: launchRepl() or print mode

第一阶段:快速路由(src/entrypoints/cli.tsx

Section titled “第一阶段:快速路由(src/entrypoints/cli.tsx)”

bootstrap entrypoint 采用零导入快速路径设计。某些操作应在不加载完整应用程序的情况下完成:

src/entrypoints/cli.tsx
async function main(): Promise<void> {
const args = process.argv.slice(2)
// Fast-path for --version/-v: zero module loading needed
if (args.length === 1 && (args[0] === '--version' || args[0] === '-v' || args[0] === '-V')) {
console.log(`${MACRO.VERSION} (Claude Code)`)
return
}
// For all other paths, load the startup profiler
const { profileCheckpoint } = await import('../utils/startupProfiler.js')
profileCheckpoint('cli_entry')

快速路径模式支持多种专用模式:

Flag/子命令行为导入量
--version打印版本并退出
--dump-system-prompt输出系统 prompt(仅内部)最少——config + 模型
--claude-in-chrome-mcpChrome 扩展的 MCP serverChrome MCP 模块
--daemon-worker守护进程 worker(仅内部)仅 worker 注册表
remote-control远程会话的 bridge 模式Bridge 模块

关键设计:每个 import 都是 await import()(动态导入),按需加载。

在主 CLI 加载之前,cli.tsx 处理两项关键的环境调整:

// src/entrypoints/cli.tsx — Top-level side effects
// Prevent corepack auto-pinning (modifies package.json)
process.env.COREPACK_ENABLE_AUTO_PIN = '0'
// Set max heap size for CCR (Claude Code Remote) containers
if (process.env.CLAUDE_CODE_REMOTE === 'true') {
const existing = process.env.NODE_OPTIONS || ''
process.env.NODE_OPTIONS = existing
? `${existing} --max-old-space-size=8192`
: '--max-old-space-size=8192'
}

第二阶段:核心初始化(src/entrypoints/init.ts

Section titled “第二阶段:核心初始化(src/entrypoints/init.ts)”

init() 函数是**记忆化(memoized)**的——无论被调用多少次,都只执行一次:

src/entrypoints/init.ts
export const init = memoize(async (): Promise<void> => {
const initStartTime = Date.now()
logForDiagnosticsNoPII('info', 'init_started')
profileCheckpoint('init_function_start')
// 1. Enable configuration system
enableConfigs()
// 2. Apply SAFE environment variables (before trust dialog)
applySafeConfigEnvironmentVariables()
// 3. Apply extra CA certificates from settings
applyExtraCACertsFromConfig()
// 4. Register graceful shutdown handlers
setupGracefulShutdown()
// 5. Configure mTLS
configureGlobalMTLS()
// 6. Configure proxy (HTTP agents)
configureGlobalAgents()
// 7. Pre-connect to Anthropic API
preconnectAnthropicApi()
// ...
})

init 序列精心排列操作顺序,在遵守依赖关系的同时最大化并行性:

graph TB
    A["enableConfigs()"] --> B["applySafeConfigEnvironmentVariables()"]
    B --> C["applyExtraCACertsFromConfig()"]
    C --> D["setupGracefulShutdown()"]
    D --> E["configureGlobalMTLS()"]
    E --> F["configureGlobalAgents()"]

    B --> G["populateOAuthAccountInfoIfNeeded() (async, void)"]
    B --> H["initJetBrainsDetection() (async, void)"]
    B --> I["detectCurrentRepository() (async, void)"]
    B --> J["initializeRemoteManagedSettingsLoadingPromise()"]

    F --> K["preconnectAnthropicApi()"]

关键顺序

  • enableConfigs() 必须最先运行——所有内容都从 config 中读取
  • applySafeConfigEnvironmentVariables() 应用信任前安全的环境变量(无危险密钥)
  • applyExtraCACertsFromConfig() 必须在任何 TLS 连接之前执行(Bun 在启动时缓存证书存储)
  • configureGlobalMTLS()configureGlobalAgents() 之前——mTLS 设置会注入到代理 agent 中

用户接受信任对话框后,还会应用额外的敏感 config:

// Called later in the startup sequence, after trust is established
export async function initializeTelemetryAfterTrust(): Promise<void> {
// Now safe to apply ALL environment variables (including sensitive ones)
applyConfigEnvironmentVariables()
// Initialize telemetry, analytics, etc.
}

第三阶段:CLI 框架(src/main.tsx

Section titled “第三阶段:CLI 框架(src/main.tsx)”

主模块是代码库中最大的文件。它注册 commander.js 命令、解析参数并启动相应模式。

main.tsx 在任何 import 完成求值之前触发三个并行操作:

// src/main.tsx — Lines 1-20
import { profileCheckpoint } from './utils/startupProfiler.js'
profileCheckpoint('main_tsx_entry') // Mark entry timestamp
import { startMdmRawRead } from './utils/settings/mdm/rawRead.js'
startMdmRawRead() // Fire MDM subprocesses (plutil/reg query) in parallel
import { startKeychainPrefetch } from './utils/secureStorage/keychainPrefetch.js'
startKeychainPrefetch() // Fire macOS keychain reads in parallel

这种并行预取模式通过将 keychain 读取与剩余约 135ms 的模块导入重叠,在 macOS 上节省约 65ms。

CLI 使用 @commander-js/extra-typings 进行类型安全的参数解析:

// src/main.tsx (conceptual)
import { Command as CommanderCommand, Option } from '@commander-js/extra-typings'
const program = new CommanderCommand()
.name('claude')
.option('-p, --print', 'Print mode (non-interactive)')
.option('--model <model>', 'Model to use')
.option('--permission-mode <mode>', 'Permission mode')
.option('--dangerously-skip-permissions', 'Skip all permission checks')
.option('--resume <session>', 'Resume a previous session')
.option('--worktree', 'Create a git worktree for this session')
// ... 40+ more options

参数解析后,启动流程继续:

  1. Config 验证 — 检查无效 settings,必要时显示对话框
  2. 认证流程 — 验证 API key 或 OAuth token
  3. GrowthBook 初始化 — 来自 Anthropic 实验平台的 feature flag
  4. MCP server 启动 — 并行连接已配置的 MCP server
  5. tool 组装 — 根据权限和 config 构建 tool 池
  6. agent 定义 — 从 .claude/agents/ 加载 agent 定义
  7. 模式分发 — 启动 REPL(交互式)或 print 模式(无头)

第四阶段:环境配置(src/setup.ts

Section titled “第四阶段:环境配置(src/setup.ts)”

setup() 函数处理初始化后的环境配置:

src/setup.ts
export async function setup(
cwd: string,
permissionMode: PermissionMode,
allowDangerouslySkipPermissions: boolean,
worktreeEnabled: boolean,
worktreeName: string | undefined,
tmuxEnabled: boolean,
customSessionId?: string | null,
worktreePRNumber?: number,
messagingSocketPath?: string,
): Promise<void> {
graph TB
    A["setCwd(cwd)"] --> B["captureHooksConfigSnapshot()"]
    B --> C["initializeFileChangedWatcher(cwd)"]
    C --> D{worktreeEnabled?}
    D -->|Yes| E["createWorktreeForSession()"]
    E --> F["process.chdir(worktreePath)"]
    D -->|No| G["Background jobs"]
    F --> G

    G --> H["initSessionMemory()"]
    G --> I["lockCurrentVersion()"]
    G --> J["getCommands() prefetch"]
    G --> K["loadPluginHooks() prefetch"]

    K --> L["checkForReleaseNotes()"]
    L --> M["Permission mode validation"]

Claude Code 为进程终止信号注册处理程序:

// src/utils/gracefulShutdown.ts (called from init.ts)
export function setupGracefulShutdown(): void {
// Register cleanup for SIGINT, SIGTERM, SIGHUP
// Ensures:
// - Terminal state is restored (cursor, alternate screen)
// - Session data is flushed to disk
// - Child processes are killed
// - Telemetry is flushed
}

gracefulShutdownSync() 函数为无法使用异步清理的场景提供同步退出路径:

// Used in signal handlers where async is not available
gracefulShutdownSync()
// Restores terminal, flushes sync-safe writes

传入 --worktree 时,setup.ts 会创建一个隔离的 git worktree:

// src/setup.ts — Worktree handling
if (worktreeEnabled) {
const hasHook = hasWorktreeCreateHook()
const inGit = await getIsGit()
if (!hasHook && !inGit) {
process.stderr.write(chalk.red(
`Error: Can only use --worktree in a git repository`
))
process.exit(1)
}
const slug = worktreePRNumber
? `pr-${worktreePRNumber}`
: (worktreeName ?? getPlanSlug())
worktreeSession = await createWorktreeForSession(getSessionId(), slug, ...)
process.chdir(worktreeSession.worktreePath)
setCwd(worktreeSession.worktreePath)
setOriginalCwd(getCwd())
setProjectRoot(getCwd())
}

对于 --dangerously-skip-permissionssetup.ts 强制执行安全检查:

// src/setup.ts — Security validation
if (permissionMode === 'bypassPermissions' || allowDangerouslySkipPermissions) {
// Block root/sudo on Unix
if (process.platform !== 'win32' && process.getuid?.() === 0
&& process.env.IS_SANDBOX !== '1') {
console.error('--dangerously-skip-permissions cannot be used with root/sudo')
process.exit(1)
}
// External users: require Docker/sandbox + no internet
if (process.env.USER_TYPE === 'ant') {
const [isDocker, hasInternet] = await Promise.all([
envDynamic.getIsDocker(),
env.hasInternetAccess(),
])
if (!isSandboxed || hasInternet) {
console.error('--dangerously-skip-permissions requires sandbox with no internet')
process.exit(1)
}
}
}
stateDiagram-v2
    [*] --> CliEntry: bun run cli.tsx
    CliEntry --> FastPath: --version, --bridge, etc.
    FastPath --> [*]: Exit immediately

    CliEntry --> Init: Normal path
    Init --> MainTsx: Dynamic import
    MainTsx --> ArgParse: Commander.js
    ArgParse --> AuthCheck: Validate API key
    AuthCheck --> McpInit: Start MCP servers
    McpInit --> Setup: setup()
    Setup --> ReplMode: Interactive
    Setup --> PrintMode: --print flag

    ReplMode --> Running: REPL loop
    PrintMode --> Running: Single query

    Running --> Shutdown: SIGINT/SIGTERM/exit
    Shutdown --> Cleanup: Flush sessions, restore terminal
    Cleanup --> [*]

bootstrap 序列包含若干关键性能优化:

  1. 并行预取 — MDM 读取、keychain 读取和 API 预连接与模块导入并行进行
  2. 动态导入 — 快速路径加载零模块;主路径使用 await import()
  3. 记忆化 initinit()memoize() 防止重复初始化
  4. 后台任务 — 非关键工作(attribution hook、session 文件访问)通过 void import().then() 运行
  5. 启动分析器 — 整个启动路径中的 profileCheckpoint() 调用允许测量每个阶段
// Profiling checkpoints in the startup path
profileCheckpoint('cli_entry')
profileCheckpoint('init_function_start')
profileCheckpoint('init_configs_enabled')
profileCheckpoint('init_safe_env_vars_applied')
profileCheckpoint('init_after_graceful_shutdown')
profileCheckpoint('init_after_1p_event_logging')
profileCheckpoint('main_tsx_entry')
profileCheckpoint('setup_before_prefetch')
profileCheckpoint('setup_after_prefetch')