开发者指南
本指南为想要理解、修改或贡献 Claude Code 源码的开发者提供参考。
环境准备
必需工具
| 工具 | 版本 | 用途 |
|---|---|---|
| Bun | 最新版 | 运行时、构建工具、包管理器 |
| Node.js | 18+ | 部分原生模块编译需要 |
| Git | 2.x | 源码管理 |
项目结构指引
claude-code-2.1.88/
├── src/ # TypeScript 源码
│ ├── entrypoints/ # 入口文件(CLI、MCP、SDK)
│ ├── main.tsx # 主启动文件
│ ├── Tool.ts # 工具基础接口
│ ├── tools.ts # 工具注册表
│ ├── commands.ts # 命令路由
│ ├── QueryEngine.ts # 查询引擎
│ ├── query.ts # 查询循环
│ ├── context.ts # 上下文构建
│ ├── history.ts # 历史记录
│ ├── tools/ # 40+ 工具实现
│ ├── commands/ # 70+ 斜杠命令
│ ├── services/ # 后台服务
│ ├── components/ # React/Ink 组件
│ ├── hooks/ # React Hook
│ ├── state/ # 状态管理
│ ├── bridge/ # 远程通信
│ ├── ink/ # 自定义 Ink 渲染器
│ ├── utils/ # 工具函数
│ └── constants/ # 常量定义
├── vendor/ # 原生模块源码
└── docs/ # 本文档代码模式与约定
1. React Compiler Runtime
项目使用 React Compiler Runtime 进行自动记忆化,无需 手写 useMemo / useCallback:
typescript
// 构建产物中自动注入
import { c as _c } from "react/compiler-runtime"
// 开发者只需写普通代码
function MyComponent({ data }) {
const processed = expensiveCompute(data) // 自动被 memo 化
return <Box>{processed}</Box>
}2. Feature Gate 模式
条件功能使用 feature() 编译时门控:
typescript
import { feature } from '../constants/common'
if (feature('VOICE_MODE')) {
// 此分支在非 VOICE_MODE 构建中被完全消除
}3. 延迟 Import 模式
大型模块使用动态 import 减少启动时间:
typescript
// ✅ 正确 — 延迟加载
const { QueryEngine } = await import('./QueryEngine')
// ❌ 避免 — 静态导入大模块
import { QueryEngine } from './QueryEngine'4. useSyncExternalStore 模式
绕过 React Context 延迟的高性能状态订阅:
typescript
// 创建 Store
const store = createStore<AppState>(initialState)
// 组件订阅(自动选择性重渲染)
function MyComponent() {
const model = useAppState(s => s.mainLoopModel)
// 仅在 s.currentModel 变化时重渲染
}5. Ref 缓存模式
避免回调重建导致的不必要渲染:
typescript
function StatusLine() {
const settingsRef = useRef(settings)
settingsRef.current = settings
// 稳定回调,不因 settings 变化而重建
const handleClick = useCallback(() => {
doSomething(settingsRef.current)
}, [])
}6. 工具调用模式
工具的 call() 方法返回 Promise<ToolResult<Output>>(不是 AsyncGenerator):
typescript
// src/Tool.ts 中的实际签名
async call(
args: Input,
context: ToolUseContext,
canUseTool: CanUseToolFn,
parentMessage: Message
): Promise<ToolResult<Output>>关键类型
Tool 接口
typescript
interface Tool<Input = unknown, Output = unknown> {
name: string
description(input: Input, options?: ToolDescriptionOptions): Promise<string>
inputSchema: Input // Zod schema 对象
call(args: Input, context: ToolUseContext, canUseTool: CanUseToolFn, parentMessage: Message): Promise<ToolResult<Output>>
checkPermissions(input: Input, context: ToolPermissionContext): Promise<PermissionResult>
isReadOnly(input: Input): boolean
isDestructive?(input?: Input): boolean
isConcurrencySafe(input: Input): boolean
renderToolUseMessage(input: Partial<Input>, options: { theme: ThemeName; verbose: boolean; commands?: Command[] }): React.ReactNode
renderToolResultMessage?(output: Output, { verbose }: { verbose: boolean }): ReactElement
// ...约55个成员(含 prompt, userFacingName, hasMultiTurnCapability 等)
}AppState
typescript
interface AppState {
settings: Settings
mainLoopModel: string
mainLoopModelForSession: string | undefined
toolPermissionContext: DeepImmutable<ToolPermissionContext>
tasks: Tasks
agentNameRegistry: AgentNameRegistration[]
fileHistory: FileHistory
attribution: Attribution
mcp: McpState
plugins: PluginsState
todos: TodosState
notifications: NotificationsState
elicitation: ElicitationState
speculation: SpeculationState
promptSuggestion: PromptSuggestionState
// ...80+ 字段(含 replBridge* 等 12 个桥接字段)
}ToolUseContext
typescript
interface ToolUseContext {
toolUseId: string
abortController: AbortController // 注意: 不是 abortSignal
getAppState: () => DeepImmutable<AppState>
setAppState: SetAppState
readFileState: ReadFileState
options: {
forkNumber: number | undefined
maxThinkingTokens: number | undefined
tools: Tool[]
slowAndCapableModel: string
user_type: string
}
// ...大量运行时上下文
}调试技巧
环境变量
| 变量 | 用途 |
|---|---|
CLAUDE_CODE_DEBUG=1 | 启用调试日志 |
CLAUDE_CODE_DEBUG_REPAINTS=1 | Ink 重绘归因调试 |
CLAUDE_CODE_SHELL | 覆盖默认 Shell |
CLAUDE_CODE_REMOTE_MEMORY_DIR | 自定义记忆目录 |
CLAUDE_CODE_COORDINATOR_MODE=1 | 协调器模式 |
日志查看
bash
# 会话日志位置
~/.claude/logs/
# 实时查看日志
tail -f ~/.claude/logs/current.log添加新工具
- 在
src/tools/创建工具目录:
src/tools/MyNewTool/
├── index.ts # 工具定义
├── prompt.ts # 工具描述/示例
├── UI.tsx # 渲染组件
└── helpers.ts # 辅助函数- 在
tools.ts中注册:
typescript
import { MyNewTool } from './tools/MyNewTool'
// tools.ts 中注册(直接导入或 lazy 导入)
import { MyNewTool } from './tools/MyNewTool'
// 添加到 allBaseTools 数组中添加新命令
- 在
src/commands/创建命令目录:
src/commands/my-command/
└── index.ts- 实现命令接口:
typescript
export default {
type: 'local',
name: 'my-command',
description: '我的命令',
isEnabled: true,
isHidden: false,
async call(args, context) {
// 命令逻辑
},
} satisfies LocalCommand- 在
commands.ts中导入。