# 核心模块详解 本文件说明:详细分析 Claude Code 的核心源文件,理解其实现原理。 ## 1. main.tsx - CLI 入口点 ### 1.1 功能概述 `main.tsx` 是 Claude Code 应用程序的入口点,负责: - CLI 参数解析 - 应用程序初始化 - REPL(Read-Eval-Print Loop)启动 - 各种启动前检查和配置 ### 1.2 启动流程 ```typescript // 1. 启动性能分析 profileCheckpoint('main_tsx_entry') // 2. MDM 设置预读取(并行) startMdmRawRead() // 3. Keychain 凭据预读取(并行) startKeychainPrefetch() // 4. 初始化遥测 initializeTelemetryAfterTrust() // 5. 获取引导数据 const bootstrapData = await fetchBootstrapData() // 6. 启动 REPL launchRepl() ``` ### 1.3 关键导入 ```typescript import { Command as CommanderCommand } from '@commander-js/extra-typings' import React from 'react' import chalk from 'chalk' import { getTools } from './tools.js' import { getCommands, filterCommandsForRemoteMode } from './commands.js' import { getSystemContext, getUserContext } from './context.js' ``` ### 1.4 核心配置初始化 ```typescript // 权限模式设置 const initialPermissionMode = await initialPermissionModeFromCLI() // 工具权限上下文初始化 initializeToolPermissionContext({ mode: initialPermissionMode, additionalWorkingDirectories: new Map(), alwaysAllowRules: {}, alwaysDenyRules: {}, alwaysAskRules: {}, isBypassPermissionsModeAvailable: false, }) // 获取工具列表 const tools = getTools(appState.toolPermissionContext) // 获取命令列表 const commands = await getCommands(cwd) ``` ## 2. QueryEngine.ts - LLM 查询引擎核心 ### 2.1 功能概述 `QueryEngine` 是 Claude Code 的核心查询处理类,负责: - 管理对话生命周期(每个对话一个 QueryEngine 实例) - 处理用户消息提交 - 执行 API 调用循环 - 处理流式响应 - 编排工具执行 - 管理会话状态(消息、Token 使用等) ### 2.2 类结构 ```typescript export class QueryEngine { private config: QueryEngineConfig private mutableMessages: Message[] // 对话消息列表 private abortController: AbortController // 中断控制器 private permissionDenials: SDKPermissionDenial[] // 权限拒绝记录 private totalUsage: NonNullableUsage // 累计 Token 使用 private hasHandledOrphanedPermission = false private readFileState: FileStateCache // 文件读取缓存 private discoveredSkillNames = new Set() private loadedNestedMemoryPaths = new Set() } ``` ### 2.3 核心方法:submitMessage() 这是处理用户输入的主要方法: ```typescript async *submitMessage( prompt: string | ContentBlockParam[], options?: { uuid?: string; isMeta?: boolean }, ): AsyncGenerator ``` **执行流程**: 1. **初始化阶段** ```typescript this.discoveredSkillNames.clear() setCwd(cwd) // 获取系统提示词 const { defaultSystemPrompt, userContext, systemContext } = await fetchSystemPromptParts({ tools, mainLoopModel, ... }) ``` 2. **处理用户输入** ```typescript const { messages, shouldQuery, allowedTools, model, resultText } = await processUserInput({ input: prompt, mode: 'prompt', context: processUserInputContext, }) // 更新权限规则 setAppState(prev => ({ ...prev, toolPermissionContext: { ...prev.toolPermissionContext, alwaysAllowRules: { command: allowedTools } } })) ``` 3. **构建系统提示** ```typescript const systemPrompt = asSystemPrompt([ ...(customPrompt ?? defaultSystemPrompt), ...(memoryMechanicsPrompt ?? []), // 记忆机制提示 ...(appendSystemPrompt ?? []) ]) ``` 4. **查询循环** ```typescript for await (const message of query({ messages, systemPrompt, userContext, systemContext, canUseTool: wrappedCanUseTool, })) { // 处理各种消息类型 switch (message.type) { case 'assistant': /* 记录助手消息 */ break case 'progress': /* 进度更新 */ break case 'user': /* 用户消息 */ break case 'stream_event': /* 流式事件 */ break case 'attachment': /* 附件处理 */ break } } ``` ### 2.4 流式响应处理 QueryEngine 处理多种流式事件: ```typescript if (message.type === 'stream_event') { // message_start: 新消息开始 if (message.event.type === 'message_start') { currentMessageUsage = EMPTY_USAGE currentMessageUsage = updateUsage(currentMessageUsage, message.event.message.usage) } // message_delta: 消息增量更新 if (message.event.type === 'message_delta') { currentMessageUsage = updateUsage(currentMessageUsage, message.event.usage) if (message.event.delta.stop_reason != null) { lastStopReason = message.event.delta.stop_reason } } // message_stop: 消息结束 if (message.event.type === 'message_stop') { this.totalUsage = accumulateUsage(this.totalUsage, currentMessageUsage) } } ``` ### 2.5 思考模式 (Thinking Mode) Claude Code 支持 Claude 的思考模式: ```typescript const initialThinkingConfig: ThinkingConfig = thinkingConfig ? thinkingConfig : shouldEnableThinkingByDefault() !== false ? { type: 'adaptive' } // 自适应思考 : { type: 'disabled' } // 禁用 ``` 思考规则(注释中的说明): 1. 包含思考或编辑块的消息必须在 `max_thinking_length > 0` 的查询中 2. 思考块不能是消息块中的最后一个 3. 思考块必须在整个助手轨迹中保留 ### 2.6 错误恢复机制 ```typescript // USD 预算超限检查 if (maxBudgetUsd !== undefined && getTotalCost() >= maxBudgetUsd) { yield { type: 'result', subtype: 'error_max_budget_usd', ... } return } // 最大轮次检查 if (maxTurns && nextTurnCount > maxTurns) { yield { type: 'result', subtype: 'error_max_turns', ... } return } // 结构化输出重试限制 if (callsThisQuery >= maxRetries) { yield { type: 'result', subtype: 'error_max_structured_output_retries', ... } return } ``` ## 3. Tool.ts - 工具基类和接口定义 ### 3.1 工具接口定义 ```typescript export type Tool< Input extends AnyObject = AnyObject, Output = unknown, P extends ToolProgressData = ToolProgressData, > = { // 工具名称 readonly name: string // 可选别名(用于工具重命名后的向后兼容) aliases?: string[] // 工具搜索提示词 searchHint?: string // 核心执行方法 call( args: z.infer, context: ToolUseContext, canUseTool: CanUseToolFn, parentMessage: AssistantMessage, onProgress?: ToolCallProgress

, ): Promise> // 获取工具描述 description( input: z.infer, options: {...} ): Promise // 输入 Schema readonly inputSchema: Input // 输入 JSON Schema(用于 MCP 工具) readonly inputJSONSchema?: ToolInputJSONSchema // 输出 Schema outputSchema?: z.ZodType } ``` ### 3.2 工具权限方法 ```typescript // 验证输入是否有效 validateInput?( input: z.infer, context: ToolUseContext, ): Promise // 检查权限 checkPermissions( input: z.infer, context: ToolUseContext, ): Promise // 准备权限匹配器 preparePermissionMatcher?( input: z.infer, ): Promise<(pattern: string) => boolean> ``` ### 3.3 工具渲染方法 ```typescript // 渲染工具使用消息 renderToolUseMessage( input: Partial>, options: { theme: ThemeName; verbose: boolean; commands?: Command[] } ): React.ReactNode // 渲染工具结果消息 renderToolResultMessage?( content: Output, progressMessagesForMessage: ProgressMessage

[], options: {...} ): React.ReactNode // 渲染工具使用标签 renderToolUseTag?(input: Partial>): React.ReactNode // 渲染进度消息 renderToolUseProgressMessage?( progressMessagesForMessage: ProgressMessage

[], options: {...} ): React.ReactNode ``` ### 3.4 buildTool 工厂函数 ```typescript const TOOL_DEFAULTS = { isEnabled: () => true, isConcurrencySafe: (_input?: unknown) => false, isReadOnly: (_input?: unknown) => false, isDestructive: (_input?: unknown) => false, checkPermissions: async () => ({ behavior: 'allow', updatedInput: input }), toAutoClassifierInput: (_input?: unknown) => '', userFacingName: (_input?: unknown) => '', } export function buildTool(def: D): BuiltTool { return { ...TOOL_DEFAULTS, userFacingName: () => def.name, ...def, } as BuiltTool } ``` ### 3.5 工具权限上下文 ```typescript export type ToolPermissionContext = { mode: PermissionMode // 'default' | 'auto' | 'bypass' | 'plan' additionalWorkingDirectories: Map alwaysAllowRules: ToolPermissionRulesBySource alwaysDenyRules: ToolPermissionRulesBySource alwaysAskRules: ToolPermissionRulesBySource isBypassPermissionsModeAvailable: boolean isAutoModeAvailable?: boolean strippedDangerousRules?: ToolPermissionRulesBySource shouldAvoidPermissionPrompts?: boolean awaitAutomatedChecksBeforeDialog?: boolean prePlanMode?: PermissionMode } ``` ## 4. commands.ts - 命令注册中心 ### 4.1 功能概述 `commands.ts` 是 Claude Code 的命令注册中心,管理所有 slash commands(以 `/` 开头的命令)。 ### 4.2 命令类型 ```typescript type CommandType = | 'prompt' // 展开为提示发送给模型 | 'local' // 本地执行,返回文本 | 'local-jsx' // 本地执行,渲染 Ink UI ``` ### 4.3 命令定义结构 ```typescript interface Command { type: CommandType name: string aliases?: string[] description: string contentLength: number source: 'builtin' | 'plugin' | 'bundled' | 'mcp' | ... availability?: ('claude-ai' | 'console')[] // ... } ``` ### 4.4 命令加载流程 ```typescript // 1. 获取技能目录命令 const skillDirCommands = await getSkillDirCommands(cwd) // 2. 获取插件命令 const pluginCommands = await getPluginCommands() // 3. 获取内置命令 const builtinCommands = COMMANDS() // 4. 合并并过滤 const allCommands = [ ...bundledSkills, ...builtinPluginSkills, ...skillDirCommands, ...workflowCommands, ...pluginCommands, ...pluginSkills, ...COMMANDS(), ] // 5. 检查可用性要求 const filteredCommands = allCommands.filter(cmd => meetsAvailabilityRequirement(cmd) ) // 6. 检查是否启用 .filter(cmd => isCommandEnabled(cmd)) ``` ### 4.5 远程安全命令 ```typescript export const REMOTE_SAFE_COMMANDS: Set = new Set([ session, exit, clear, help, theme, color, vim, cost, usage, copy, btw, feedback, plan, keybindings, statusline, stickers, mobile, ]) ``` ### 4.6 命令查找 ```typescript export function findCommand( commandName: string, commands: Command[], ): Command | undefined { return commands.find( _ => _.name === commandName || getCommandName(_) === commandName || _.aliases?.includes(commandName) ) } ``` ## 5. context.ts - 系统/用户上下文收集 ### 5.1 功能概述 `context.ts` 负责收集系统上下文和用户上下文,这些上下文会被预置到每个对话的开头。 ### 5.2 Git 状态收集 ```typescript export const getGitStatus = memoize(async (): Promise => { // 检查是否是 Git 仓库 const isGit = await getIsGit() if (!isGit) return null // 并行获取多个 Git 信息 const [branch, mainBranch, status, log, userName] = await Promise.all([ getBranch(), getDefaultBranch(), execFileNoThrow(gitExe(), ['status', '--short'], ...), execFileNoThrow(gitExe(), ['log', '--oneline', '-n', '5'], ...), execFileNoThrow(gitExe(), ['config', 'user.name'], ...), ]) return [ `Current branch: ${branch}`, `Main branch: ${mainBranch}`, `Git user: ${userName}`, `Status:\n${truncatedStatus}`, `Recent commits:\n${log}`, ].join('\n\n') }) ``` ### 5.3 系统上下文 ```typescript export const getSystemContext = memoize(async () => { const gitStatus = await getGitStatus() // 缓存破坏注入(仅用于调试) const injection = feature('BREAK_CACHE_COMMAND') ? getSystemPromptInjection() : null return { ...(gitStatus && { gitStatus }), ...(injection && { cacheBreaker: `[CACHE_BREAKER: ${injection}]` }), } }) ``` ### 5.4 用户上下文 ```typescript export const getUserContext = memoize(async () => { // 获取 CLAUDE.md 文件内容 const shouldDisableClaudeMd = isEnvTruthy(process.env.CLAUDE_CODE_DISABLE_CLAUDE_MDS) || (isBareMode() && getAdditionalDirectoriesForClaudeMd().length === 0) const claudeMd = shouldDisableClaudeMd ? null : getClaudeMds(filterInjectedMemoryFiles(await getMemoryFiles())) // 缓存 CLAUDE.md 内容供自动模式分类器使用 setCachedClaudeMdContent(claudeMd || null) return { ...(claudeMd && { claudeMd }), currentDate: `Today's date is ${getLocalISODate()}.`, } }) ``` ### 5.5 上下文缓存 所有上下文函数都使用 `memoize` 进行缓存,确保在一次对话中只计算一次: ```typescript export const getSystemContext = memoize(async () => {...}) export const getUserContext = memoize(async () => {...}) export const getGitStatus = memoize(async () => {...}) ``` ## 6. cost-tracker.ts - Token 成本追踪 ### 6.1 功能概述 `cost-tracker.ts` 负责追踪和计算 API 调用的 Token 使用量和成本。 ### 6.2 核心数据结构 ```typescript type StoredCostState = { totalCostUSD: number totalAPIDuration: number totalAPIDurationWithoutRetries: number totalToolDuration: number totalLinesAdded: number totalLinesRemoved: number lastDuration: number | undefined modelUsage: { [modelName: string]: ModelUsage } } type ModelUsage = { inputTokens: number outputTokens: number cacheReadInputTokens: number cacheCreationInputTokens: number webSearchRequests: number costUSD: number contextWindow: number maxOutputTokens: number } ``` ### 6.3 成本计算 ```typescript export function addToTotalSessionCost( cost: number, usage: Usage, model: string, ): number { const modelUsage = addToTotalModelUsage(cost, usage, model) addToTotalCostState(cost, modelUsage, model) // 发送到 Statsig 计数器 getCostCounter()?.add(cost, { model }) getTokenCounter()?.add(usage.input_tokens, { ...attrs, type: 'input' }) getTokenCounter()?.add(usage.output_tokens, { ...attrs, type: 'output' }) // 处理 Advisor 使用量 for (const advisorUsage of getAdvisorUsage(usage)) { const advisorCost = calculateUSDCost(advisorUsage.model, advisorUsage) totalCost += addToTotalSessionCost(advisorCost, advisorUsage, advisorUsage.model) } return totalCost } ``` ### 6.4 成本格式化 ```typescript export function formatTotalCost(): string { const costDisplay = formatCost(getTotalCostUSD()) return chalk.dim(` Total cost: ${costDisplay} Total duration (API): ${formatDuration(getTotalAPIDuration())} Total duration (wall): ${formatDuration(getTotalDuration())} Total code changes: ${linesAdded} lines added, ${linesRemoved} lines removed ${formatModelUsage()} `) } ``` ### 6.5 会话成本保存/恢复 ```typescript // 保存当前会话成本到项目配置 export function saveCurrentSessionCosts(fpsMetrics?: FpsMetrics): void { saveCurrentProjectConfig(current => ({ ...current, lastCost: getTotalCostUSD(), lastAPIDuration: getTotalAPIDuration(), lastLinesAdded: getTotalLinesAdded(), lastLinesRemoved: getTotalLinesRemoved(), lastModelUsage: Object.fromEntries(...), lastSessionId: getSessionId(), })) } // 恢复会话成本 export function restoreCostStateForSession(sessionId: string): boolean { const data = getStoredSessionCosts(sessionId) if (!data) return false setCostStateForRestore(data) return true } ``` ## 7. query.ts - 查询管道 ### 7.1 功能概述 `query.ts` 是核心的查询处理管道,负责: - 消息流式 API 调用 - 工具调用编排 - 自动压缩 - 错误恢复 ### 7.2 主查询循环 ```typescript export async function* query( params: QueryParams, ): AsyncGenerator<...> { const consumedCommandUuids: string[] = [] const terminal = yield* queryLoop(params, consumedCommandUuids) return terminal } async function* queryLoop( params: QueryParams, consumedCommandUuids: string[], ): AsyncGenerator<...> { let state: State = { messages: params.messages, toolUseContext: params.toolUseContext, autoCompactTracking: undefined, maxOutputTokensRecoveryCount: 0, // ... } while (true) { // 1. 上下文压缩 const { compactionResult } = await deps.autocompact(...) // 2. API 调用循环 for await (const message of deps.callModel({...})) { if (message.type === 'assistant') { assistantMessages.push(message) // 处理工具调用块 } } // 3. 工具执行 if (needsFollowUp) { const toolUpdates = runTools(toolUseBlocks, ...) for await (const update of toolUpdates) { // 处理工具结果 } } // 4. 递归继续 state = { ...state, messages: [...messages, ...assistantMessages, ...toolResults] } } } ``` ### 7.3 工具执行编排 ```typescript // 两种工具执行模式 if (streamingToolExecutor) { // 流式工具执行:在模型流式输出的同时执行工具 logEvent('tengu_streaming_tool_execution_used', {...}) } else { // 批量工具执行:等待模型完全响应后执行 logEvent('tengu_streaming_tool_execution_not_used', {...}) } const toolUpdates = streamingToolExecutor ? streamingToolExecutor.getRemainingResults() : runTools(toolUseBlocks, assistantMessages, canUseTool, toolUseContext) ``` ### 7.4 错误恢复机制 ```typescript // 1. 模型回退 if (innerError instanceof FallbackTriggeredError && fallbackModel) { currentModel = fallbackModel attemptWithFallback = true continue } // 2. Prompt Too Long 恢复 if (isWithheld413) { // 尝试排空上下文折叠 const drained = contextCollapse.recoverFromOverflow(...) if (drained.committed > 0) { state = { ...state, messages: drained.messages } continue } // 尝试响应式压缩 const compacted = await reactiveCompact.tryReactiveCompact(...) if (compacted) { // ... } } // 3. Max Output Tokens 恢复 if (maxOutputTokensRecoveryCount < MAX_OUTPUT_TOKENS_RECOVERY_LIMIT) { const recoveryMessage = createUserMessage({ content: `Output token limit hit. Resume directly...` }) state = { ...state, messages: [...messages, recoveryMessage] } continue } ``` ### 7.5 上下文压缩 ```typescript // Snip(去除)压缩 if (feature('HISTORY_SNIP')) { const snipResult = snipModule!.snipCompactIfNeeded(messagesForQuery) messagesForQuery = snipResult.messages snipTokensFreed = snipResult.tokensFreed } // 微压缩 const microcompactResult = await deps.microcompact(messagesForQuery, ...) messagesForQuery = microcompactResult.messages // 自动压缩 const { compactionResult } = await deps.autocompact( messagesForQuery, toolUseContext, { systemPrompt, userContext, systemContext, toolUseContext }, querySource, tracking, snipTokensFreed, ) ``` ### 7.6 工具使用摘要 ```typescript // 为耗时的 Haiku 调用生成工具使用摘要 if (config.gates.emitToolUseSummaries && toolUseBlocks.length > 0) { const summary = await generateToolUseSummary({ tools: toolInfoForSummary, signal: toolUseContext.abortController.signal, lastAssistantText, }) // 异步生成,不阻塞下一个 API 调用 nextPendingToolUseSummary = summary.then(s => s ? createToolUseSummaryMessage(summary, toolUseIds) : null ) } ``` ## 8. 总结 这七个核心文件共同构成了 Claude Code 的核心架构: | 文件 | 职责 | |------|------| | `main.tsx` | CLI 入口,应用程序初始化 | | `QueryEngine.ts` | 对话生命周期管理,消息处理 | | `Tool.ts` | 工具基类和接口定义 | | `commands.ts` | Slash 命令注册和管理 | | `context.ts` | 系统/用户上下文收集 | | `cost-tracker.ts` | Token 成本追踪 | | `query.ts` | API 调用管道,工具编排 | 理解这些核心模块是深入研究 Claude Code 源码的基础。