Skip to content

开发者指南

想改 Claude Code 的源码?先把这篇看完。不然你大概率会被 4684 行的 main.tsx 劝退。

环境准备

必需工具

  • Bun(最新版)— 运行时 + 构建工具 + 包管理器,三合一
  • Node.js 18+ — 部分原生模块还是需要 Node 编译
  • Git 2.x — 不解释
bash
# 确认版本
bun --version   # >= 1.x
node --version  # >= 18
git --version   # >= 2.x

项目结构

claude-code/
├── src/
│   ├── entrypoints/     # CLI、MCP、SDK 入口
│   ├── main.tsx         # 主启动文件(4684 行,是的)
│   ├── tools/           # 40+ 工具实现
│   ├── commands/        # 70+ 斜杠命令
│   ├── services/        # 后台服务
│   ├── components/      # 200+ React/Ink 组件
│   ├── hooks/           # 100+ 自定义 Hook
│   └── utils/           # 300+ 工具函数
├── vendor/              # 原生模块源码
└── docs/                # 文档

代码模式

1. React Compiler 自动 memo

项目用了 React Compiler,不需要手写 useMemo 或 useCallback。编译器会自动分析依赖并插入缓存。

如果你习惯性地加 useMemo,在这个项目里反而是多余的。

2. Feature Gate 模式

条件功能通过编译时门控实现:

typescript
if (feature('SOME_FEATURE')) {
  // 未启用时整个分支在构建产物中不存在
}

3. 延迟 Import

大型模块一律动态加载:

typescript
// 不要这样
import { heavyModule } from './heavy'

// 要这样
const { heavyModule } = await import('./heavy')

这是启动速度快的关键。

4. useSyncExternalStore 模式

绕过 React Context 的延迟问题,实现高性能状态订阅。当状态更新频繁时,Context 的 re-render 成本太高,用 useSyncExternalStore 直接订阅外部 store 更高效。

5. Ref 缓存模式

避免回调重建导致的不必要重渲染:

typescript
const callbackRef = useRef(callback)
callbackRef.current = callback
// 传给子组件的是 ref,不会触发重渲染

6. 工具调用模式

工具的 call() 方法返回 Promise<ToolResult<Output>>,不是 AsyncGenerator。

关键类型

Tool 接口

大约 55 个成员。核心的几个:

typescript
interface Tool {
  name: string
  description: string
  inputSchema: ZodSchema
  call(input, context): Promise<ToolResult>
  isEnabled?(context): boolean
  requiresPermission?(input): boolean
  // ...还有 50 个
}

AppState

80+ 字段的全局状态。从模型选择到权限配置,从任务列表到历史记录,全在这一个对象里。

ToolUseContext

工具执行时的运行时上下文,提供文件系统访问、状态读写、权限检查等能力。

调试技巧

环境变量

变量作用
CLAUDE_CODE_DEBUG=1启用调试日志
CLAUDE_CODE_DEBUG_REPAINTS=1Ink 重绘调试
CLAUDE_CODE_SHELL覆盖默认 Shell
CLAUDE_CODE_COORDINATOR_MODE=1协调器模式

日志

会话日志在 ~/.claude/logs/,实时查看:

bash
tail -f ~/.claude/logs/*.log

添加新工具

  1. src/tools/ 下创建目录
  2. 实现 index.ts(工具逻辑)、prompt.ts(描述)、UI.tsx(渲染)
  3. tools.ts 中注册

添加新命令

  1. src/commands/ 下创建目录
  2. 实现 LocalCommand 接口
  3. commands.ts 中导入

两者的区别记住一句话:工具给 AI 调,命令给人用