1. 先把场景说清楚:为什么要折腾 Claude Code 可运行版源码
Claude Code 是 Anthropic 官方推出的终端 AI 编程工具,能在命令行里直接读写文件、跑命令、调工具,很多人把它当成“住在终端里的结对程序员”。但官方 CLI 是打包后的产物,想研究它内部怎么组织 REPL、怎么做工具调用循环、怎么做权限校验,光看黑盒行为是不够的。于是社区里出现了把 Claude Code 工程化能力复现出来的可运行版源码项目,目标是把大部分功能还原成能读、能改、能自己构建的 TypeScript 工程。
这个场景真正卡人的地方不在“有没有源码”,而在“源码拿到手之后怎么在本地跑起来”。这类项目通常用 Bun 做包管理和构建,产物又要能同时被 Bun 和 Node 启动,中间还牵扯 feature flag polyfill、monorepo workspace、code splitting 多文件打包。你如果只按普通 Node 项目的习惯去npm install && node index.js,大概率会撞上一堆莫名其妙的报错。
这篇就聚焦一件事:把可运行版源码在 Bun 与 Node 双环境下跑通 CLI,并且接上统一的 API 通道做连通性验证。适合已经在本地做开发调试、想读源码或二次改造的人。下面给的settings.json、config.toml骨架和启动命令都可以直接复制,我会把每一步的预期结果和常见坑一起写清楚。
2. 前置准备:TaoToken 统一 Key 与 API 通道
源码跑起来只是第一步,CLI 要真正能对话、能调工具,得有一个稳定的模型 API 入口。我这边习惯用 TaoToken 做统一通道,原因是它把 Key 管理和 API 地址收敛成一套,Bun 和 Node 两种运行时读同一份配置就行,不用为每个环境单独改 base URL。
你需要先拿到一个 API Key。进入控制台创建即可:
- 控制台入口:https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_content=console&utm_campaign=rewrite
- API Key 管理:https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api-keys&utm_campaign=rewrite
创建完 Key 之后,API 的基础地址是https://taotoken.net/api,注意这个地址后面不要带 UTM 参数,直接作为 base URL 写进配置。模型名按你实际要用的填,比如做代码任务常用的 Claude 系列模型标识。
提示:Key 只存在本地配置文件或环境变量里,不要提交到 git。源码项目里如果有
.env.example,照着复制成.env再填。
如果你后面要长期跑编码任务或者接 Agent 流程,可以顺带了解下 Coding Plan,额度模型更适合持续调用:
- Coding Plan:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding-plan&utm_campaign=rewrite
3. 可复制配置:settings.json 与 config.toml 骨架
Claude Code 系工具一般会读两类配置:一类是 JSON 格式的 settings,管权限、hook、模型;一类是 TOML 格式的 config,管 provider 和认证。下面给的是最小可跑骨架,你按自己路径改。
先看settings.json,放在项目根目录或用户配置目录下:
{ "model": "claude-sonnet-4-5", "apiProvider": "anthropic", "permissions": { "mode": "manual", "allow": [ "Read", "Glob", "Grep" ], "deny": [ "Bash(rm -rf:*)" ] }, "hooks": { "preToolUse": [], "postToolUse": [] }, "env": { "ANTHROPIC_BASE_URL": "https://taotoken.net/api", "ANTHROPIC_API_KEY": "sk-your-key-here" } }这里几个字段值得说明。permissions.mode用manual最稳,工具调用前会问你;想省事可以改auto,但本地调试阶段不建议一上来就放开。deny里挡掉危险命令是基本操作,Bash(rm -rf:*)这种模式匹配能拦住大部分误删。
再看config.toml,管 provider 通道:
[provider] name = "taotoken" base_url = "https://taotoken.net/api" api_key_env = "ANTHROPIC_API_KEY" timeout_seconds = 120 [provider.models] default = "claude-sonnet-4-5" fast = "claude-haiku-4-5" [runtime] prefer = "bun" node_fallback = trueapi_key_env指向环境变量名,这样 Key 不落盘在 TOML 里,更干净。runtime.prefer设成bun,但保留node_fallback,正好对应我们要验证的双环境。
环境变量在 shell 里导出:
export ANTHROPIC_BASE_URL="https://taotoken.net/api" export ANTHROPIC_API_KEY="sk-your-key-here"Windows PowerShell 用$env:ANTHROPIC_API_KEY="sk-..."。这一步做完,Bun 和 Node 启动时都能读到同一份通道配置。
4. 双环境启动:Bun 与 Node 分别怎么跑
源码项目一般用 Bun workspaces 管理 monorepo,构建脚本是build.ts,产物输出到dist/,入口是dist/cli.js加一堆 chunk 文件。先确认 Bun 版本,这个项目对 Bun 版本很敏感,版本低了会出一堆奇怪 BUG:
bun --version # 期望 >= 1.3.11 bun upgrade升级完装依赖:
bun install开发模式启动,看到版本号打印出来就说明入口通了:
bun run dev构建产物:
bun run build构建采用 code splitting 多文件打包,产物在dist/下,入口dist/cli.js加约 450 个 chunk。构建完成后,Bun 和 Node 都能启动这个产物,这是这个项目比较关键的一点。
用 Bun 跑构建产物:
bun dist/cli.js --version用 Node 跑同一个产物:
node dist/cli.js --version两个命令都应该打印出版本号。如果 Bun 能跑、Node 报模块解析错误,多半是构建后处理没把 Node 兼容层打进去,检查build.ts里 Node.js 兼容后处理那段是否执行。
注意:开发模式
bun run dev和构建产物dist/cli.js是两条路径。调试源码逻辑用前者,验证发布形态用后者,别混着排查问题。
5. 连通性验证:发一次真实请求确认通道打通
版本号能打印只说明 CLI 起来了,不代表 API 通道通。做一次最小请求验证。先确认环境变量在当前 shell 生效:
echo $ANTHROPIC_BASE_URL echo $ANTHROPIC_API_KEY | head -c 8第一个应输出https://taotoken.net/api,第二个输出 Key 前 8 位。然后跑一个 print 模式的单次请求:
bun dist/cli.js -p "用一句话说明当前目录下有哪些文件类型"预期结果是模型返回一段描述,并且 CLI 内部会触发 Glob 或 Read 工具去读目录。如果你在settings.json里设了manual权限,会先弹出工具确认,输入允许后继续。
Node 环境同样验证一遍:
node dist/cli.js -p "输出当前工作目录路径"两次都返回正常内容,说明 Bun/Node 双环境加统一 API 通道全部打通。想更直观地看模型对话效果,也可以直接在网页端模型对话里试同一个 Key:
- 模型对话:https://taotoken.net/model-chat?utm_source=taotoken_aicg_blog_end&utm_content=model-chat&utm_campaign=rewrite
如果请求返回 401,是 Key 或环境变量问题;返回 404,多半是 base URL 写成了带路径的形式,确认是https://taotoken.net/api而不是别的拼接。
6. 本篇常见错排查
Bun 版本过低导致构建失败。现象是bun run build中途报feature()未定义或 chunk 生成异常。这个项目入口cli.tsx顶部注入了feature()polyfill,让所有 feature flag 返回 false,跳过未实现分支。Bun 版本低时 polyfill 注入时机可能不对。先bun upgrade到 1.3.11 以上再试。
Node 启动产物报Cannot find module。构建产物是 code splitting 多文件,chunk 之间用相对路径引用。如果你把dist/cli.js单独拷出来跑,chunk 找不到就报这个。要么整个dist/目录一起移动,要么在dist/目录内执行。
API 请求超时。先看config.toml里timeout_seconds,默认 120 秒对长上下文可能不够,调到 300 试试。再确认网络能访问https://taotoken.net/api,用 curl 快速探一下:
curl -s -o /dev/null -w "%{http_code}" https://taotoken.net/api返回非 5xx 说明通道可达,问题在认证或请求体。
工具调用被权限拦住不执行。manual模式下每次工具调用都要确认,调试时容易以为是卡死。要么在交互里按提示允许,要么临时把permissions.mode改成auto,但记得改回来。
feature flag 相关功能全部不可用。这是预期行为。原版通过构建时注入 flag 控制灰度,这个项目里feature()恒返回 false,所以 KAIROS、BRIDGE_MODE、VOICE_MODE 这类功能都是关闭的。你看到某些斜杠命令或工具不生效,先查它是不是挂在某个 flag 下,别当成 bug 提。
接入和排障过程中如果遇到认证配置问题,可以对照接入文档再核一遍参数:
- 接入文档:https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite
7. 继续往下走:从跑通到改造
跑通之后,比较自然的下一步是读src/entrypoints/cli.tsx和src/main.tsx,看 Commander 怎么定义子命令、REPL 怎么用 Ink 渲染。工具调用循环在query.ts,会话状态在QueryEngine.ts,权限系统单独一块,代码量不小但结构清晰。想改行为,优先从settings.json的 hook 和权限规则入手,比直接改源码风险低。
如果你打算把这个 CLI 接进长期编码流程或者 Agent 编排,单次 Key 调用会很快碰到额度管理问题,Coding Plan 那套更适合持续跑:
- Coding Plan:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding-plan&utm_campaign=rewrite
最后提醒一句,这类复现项目更新很快,构建脚本和目录结构可能隔几天就变。遇到和本文不一致的地方,以仓库当前build.ts和package.json为准,先跑bun install再bun run build,大部分问题都能定位到具体那一步。