
简介这份资源是 Anthropic 官方 Claude Code CLI 工具的源码逆向还原项目面向希望深入理解该 CLI 工作原理、并需要可运行可调试工程环境的开发者。项目以 TypeScript 为主类型问题已全面修复具备企业级可靠性依赖 lock 文件保真可直接执行 bun i 安装、bun run dev 启动便于本地调试与二次开发。压缩包共约 2000 个文件其中 1617 个 ts 与 245 个 tsx 构成核心源码与组件另有 83 个 md 文档、26 个 js、18 个 json 及少量配置与脚本文件整体约 50.86MB目录结构完整覆盖工具链、运行时类型与各类功能模块。目前已有 132 人学习。读者可借此研究 Claude Code 的工程化实现、类型组织与模块划分并基于主干代码扩展自己的 CLI 应用。1. 原汁原味 Claude Code 可运行版为什么值得自己搭一遍很多人第一次接触 Claude Code是在别人的终端录屏里看它自动改文件、跑测试、提交 commit感觉像个黑匣子。但真到自己机器上往往卡在第一步装不上、跑不起来、改不动。市面上流传的所谓「可运行版」大多是打包好的二进制出了问题只能等更新连日志都看不全。而这份 TypeScript 源码版的价值恰恰在于——它把整个 Agent 循环、工具调用协议、上下文管理逻辑摊开给你看你可以断点调试、可以改 prompt 模板、可以加自己的工具。对于想搞清楚「AI 编程助手到底怎么调度工具」的工程师来说这比看一百篇原理文章都管用。这篇文章面向的是愿意动手的开发者你需要有 Node.js 基础、用过 TypeScript、能看懂 npm 脚本。我会从环境准备讲到构建调试再到实际改造每一步都给出可复现的命令和参数说明。搭完这一遍你手里就有个能改、能断点、能扩展的 Claude Code 工作副本。2. 把源码跑起来环境、依赖与首次构建2.1 为什么选源码构建而不是直接装二进制直接下载安装包确实快但你会失去三样东西第一看不到工具调用的完整请求体排查「为什么它没读那个文件」时只能猜第二改不了系统提示词想让它遵守团队编码规范只能靠外部配置绕第三版本升级不可控某天自动更新后行为变了你连回滚的余地都没有。源码构建的代价是首次配置大概二十分钟换来的是完全可控。常见做法是 fork 一份到自己的仓库锁定依赖版本后续按需合并上游改动。我一般会在项目根目录加一个.nvmrc固定 Node 版本避免团队里有人用 18 有人用 22 导致构建产物不一致。2.2 环境准备Node、包管理器与 TypeScript 版本先确认基础环境。Claude Code 这类 Agent 工具对 Node 版本有要求低于 18 会在 ESM 加载和 fetch 上翻车。执行下面命令检查node -v # 期望 v18.17.0 或更高推荐 v20 LTS npm -v # 期望 9.x 以上 corepack enable # 启用 pnpm/yarn 的 shim很多源码包用 pnpm如果node -v低于 18用 nvm 切换nvm install 20 nvm use 20 nvm alias default 20包管理器优先看源码根目录有没有pnpm-lock.yaml。有就用 pnpm没有再用 npm。混用包管理器是依赖树错乱的常见原因血泪经验node_modules里出现两份不同版本的同一依赖构建时报的类型错误能让你查半天。TypeScript 版本要留意。热搜里提到的moduleResolutionnode10已弃用、baseUrl将在 TS 7.0 停止支持这些不是危言耸听。如果你的源码tsconfig.json里还在用node10构建会打警告未来直接报错。建议改成{ compilerOptions: { module: NodeNext, moduleResolution: NodeNext, target: ES2022, strict: true, skipLibCheck: true } }moduleResolution设为NodeNext后相对导入需要带.js后缀即使源文件是.ts这是 ESM 的硬性要求改的时候别漏。skipLibCheck打开能跳过第三方库的类型检查省大量构建时间代价是库自身的类型错误你看不到权衡后一般建议开。2.3 拉取依赖与首次构建的完整命令环境就绪后进入源码目录按顺序执行git clone 你的仓库地址 claude-code-src cd claude-code-src pnpm install --frozen-lockfile # 严格按 lock 文件装避免版本漂移 pnpm run build # 多数项目对应 tsc 或 tsup--frozen-lockfile的作用是如果package.json和 lock 文件不一致就直接失败而不是偷偷升级依赖。CI 环境必加本地首次也可以加确认依赖干净。构建脚本因项目而异常见几种脚本命令实际动作产物位置tsc -p tsconfig.build.json纯类型编译dist/tsup src/index.ts打包 压缩dist/index.jsesbuild --bundle极速打包自定义构建失败时先看第一个错误不要被后面几十条连锁报错带偏。九成情况是类型不匹配或缺少.js后缀。如果报Cannot find module ./xxx.js检查源文件是不是xxx.ts且导入写成了./xxx——NodeNext 下必须写./xxx.js。2.4 配置 API 接入与首次运行验证构建成功后需要配置模型接入。Claude Code 走的是 Anthropic 的 API 协议你需要准备 API Key 和可访问的端点。配置一般通过环境变量注入export ANTHROPIC_API_KEY你的key export ANTHROPIC_BASE_URL你的端点地址 # 若使用兼容网关注意环境变量写进 shell 配置文件前确认该文件权限是 600别让 key 泄露给同机器其他用户。然后运行入口node dist/index.js --help能打印帮助信息说明构建产物可执行。接着做一次最小对话验证node dist/index.js -p 列出当前目录的文件-p是单次执行模式跑完即退适合脚本化验证。如果卡住不动先看网络能否到达端点再看 key 是否有效。首次跑通后建议把这条命令写进package.json的 scripts命名为smoke每次改完代码先跑一遍比手动敲省事。3. 调试与改造让源码真正为你所用3.1 用 VS Code 断点调试 Agent 主循环跑起来只是第一步能断点才是源码版的核心价值。在项目根目录建.vscode/launch.json{ version: 0.2.0, configurations: [ { name: Debug Claude Code, type: node, request: launch, program: ${workspaceFolder}/dist/index.js, args: [-p, 读取 package.json 并总结依赖], env: { ANTHROPIC_API_KEY: ${env:ANTHROPIC_API_KEY} }, sourceMaps: true, outFiles: [${workspaceFolder}/dist/**/*.js] } ] }关键参数是sourceMaps和outFiles。前者让你在.ts源文件上打断点后者告诉调试器去哪里找编译产物。前提是构建时开了sourceMap: true。如果断点变成灰色空心圆说明 sourcemap 没生成或路径不对检查tsconfig里的sourceMap和outDir。我一般会在工具调用的分发函数上下断点比如处理read_file、write_file的地方。这样能清楚看到模型返回的 tool_use 块长什么样、参数怎么解析、结果怎么回填。这是理解 Agent 循环最快的方式比读文档直观得多。3.2 修改系统提示词与工具注册表系统提示词通常单独放在一个文件里比如src/prompts/system.ts或prompts/system.md。改这里能直接影响模型行为。比如团队要求所有代码注释用中文可以在提示词里加一条约束。改完重新构建即可生效不需要动其他逻辑。工具注册表一般在src/tools/index.ts结构类似export const tools [ readFileTool, writeFileTool, bashTool, // 新增工具在这里注册 ];每个工具是一个对象包含name、description、inputSchema和execute方法。description会被塞进请求发给模型写得越清楚模型调用越准。想加一个自定义工具照着现有工具复制一份改就行。注意inputSchema用 JSON Schema 描述参数模型靠它理解怎么传参。schema 写错会导致模型传参格式不对execute 里直接抛错。3.3 构建产物瘦身与启动速度优化源码构建的产物往往偏大启动慢。几个可调的优化点第一tsup或esbuild配置里开minify和treeshake去掉未引用代码第二把不常用的工具做成动态导入用到才加载第三检查有没有把整个node_modules打进去正常应该只打自己的源码依赖走外部 require。# 用 esbuild 分析产物构成 npx esbuild-visualizer --metadata metafile.json启动速度还受 Node 冷启动影响。如果每次调用都要等一两秒可以考虑用--enable-source-maps之外的方式比如把常用路径预热。不过对交互式使用来说这点延迟通常可接受别过度优化。3.4 用环境变量切换多套配置开发时经常要在不同端点、不同 key 之间切换。硬编码或反复改 shell 很烦。做法是建几个 env 文件# .env.dev ANTHROPIC_API_KEYdev_key ANTHROPIC_BASE_URLhttps://dev-endpoint # .env.prod ANTHROPIC_API_KEYprod_key ANTHROPIC_BASE_URLhttps://prod-endpoint运行时用dotenv-cli加载npx dotenv-cli -e .env.dev -- node dist/index.js -p 测试这样切换环境只改一个参数不用动代码。记得把.env.*加进.gitignorekey 进仓库是重大事故。4. 避坑与排查源码构建最容易翻车的五个地方4.1 现象构建报一堆「Cannot find module」原因ESM 后缀缺失NodeNext 模式下所有相对导入必须带.js后缀。从 CommonJS 迁过来的代码几乎必踩。现象是tsc报几十条找不到模块但文件明明存在。解决全局搜索from ./和from ../把没有后缀的补上.js。注意只补相对路径包名不用。批量改可以用正则替换但改完务必跑一次构建确认。4.2 现象运行时报「ERR_REQUIRE_ESM」原因CJS 与 ESM 混用某个依赖是纯 ESM 包你的代码却用require引入。现象是启动直接崩堆栈指向require()。解决把该处改成import或者用动态await import()。如果整个项目是 CJS考虑在package.json里加type: module切到 ESM但要评估所有依赖是否兼容。混用是长期维护的噩梦尽早统一。4.3 现象断点不生效原因sourcemap 路径错位VS Code 里断点是灰色或者断在编译后的 JS 上。原因通常是outDir和launch.json里的outFiles对不上或者构建时没开 sourcemap。解决确认tsconfig里sourceMap: true、outDir: ./distlaunch.json里outFiles指向dist/**/*.js。如果用了 tsup检查它的 sourcemap 选项是否开启。4.4 现象工具调用参数解析失败原因JSON Schema 写得不严谨模型返回的 tool_use 参数偶尔缺字段或类型不对execute 里直接抛错。根因是inputSchema没写required或类型约束太松。解决给每个必填参数加进required数组类型用string、number明确标注枚举值用enum限定。schema 越严格模型传参越规范。另外 execute 里要做防御性校验别假设模型一定传对。4.5 现象改了提示词没生效原因构建缓存或产物未更新改完system.ts重新运行行为没变。先确认构建真的跑了dist里的文件时间戳是不是新的。tsup 有缓存必要时加--no-cache。还有一种情况是提示词被硬编码在多个地方你只改了一处。全局搜索提示词里的特征句确认没有遗漏。改完跑一次smoke脚本验证。5. 进阶技巧把 Claude Code 源码改造成团队专属助手走到这一步你已经能构建、调试、改工具了。接下来最有价值的改造方向是「团队适配」。我一般会做三件事。第一把团队的编码规范、目录约定、提交信息格式写进系统提示词让模型生成的代码天然符合规范省掉 review 时的反复拉扯。第二加一个「项目上下文工具」让它启动时自动读取README、CONTRIBUTING和最近的 git log这样它对新人的问题回答得更准。第三做一个「危险操作二次确认」的包装层在bashTool执行rm、git push --force这类命令前拦截要求显式确认。验证改造是否成功别只看它能不能跑要看三个指标任务完成率、工具调用次数、人工干预频率。我习惯用一个简单的对照实验同一批任务改造前后各跑十次记录成功次数和平均轮次。改造有效的标志是成功次数上升、轮次下降。如果轮次反而涨了说明提示词写得太啰嗦模型在反复确认。最后一个具体技巧把常用的调试命令固化成一个Makefile比如make build、make smoke、make debug。团队里每个人敲的命令一致环境差异导致的问题会少很多。我自己踩过的最大坑是早期没固定 Node 版本同事用 16 我用 20同一个 commit 他构建失败我成功查了一下午才发现是版本问题。从那以后.nvmrc和engines字段成了我每个项目的标配。希望帮到你。本文还有配套的精品资源点击获取