从泄露源码到可本地运行:我把 Claude Code 补成了一个完整的 Bun 工程

这次最核心的变化,不是多了几个功能点,而是把原本”不能直接运行的泄露源码”,补成了一套”可以本地启动、可以切模型、可以交互、可以降级、可以扩展”的完整工程。
从工程结果看,项目已经具备以下基本条件:
-
• 有明确的 Bun 运行时和包结构 -
• 有统一的 CLI 启动入口 -
• 有完整 CLI 与 Recovery CLI 两条执行链路 -
• 有环境变量模板和多模型接入方式 -
• 有本地预加载与运行时注入逻辑 -
• 有可落地的 Computer Use 桥接方案
换句话说,补上的不是零散功能,而是一条可闭环的本地运行链路。
补齐了哪些关键部分
Bun 工程骨架
新增或补齐的基础文件包括:
-
• package.json -
• bunfig.toml -
• tsconfig.json -
• .env.example -
• preload.ts -
• bin/claude-qian
这一层解决的是工程最基础的问题:依赖安装、命令入口、环境变量注入、运行时信息补全,以及本地启动时的工作目录切换。
原始源码没有这些文件。没有 package.json 意味着不能 bun install,没有 preload.ts 意味着运行时缺失 MACRO.VERSION 等全局变量(cli.tsx 的第一行就依赖它),没有 bin/ 意味着没有统一入口。这一层虽然技术含量不高,但它是所有后续步骤的前提。
CLI 启动链路
项目现在有两条可执行入口:
-
• 完整 CLI: src/entrypoints/cli.tsx -
• Recovery CLI: src/localRecoveryCli.ts
统一由 bin/claude-qian 分发:
-
• 默认进入完整 Ink TUI -
• 设置 CLAUDE_CODE_FORCE_RECOVERY_CLI=1时进入 Recovery CLI
bin/claude-qian 的逻辑非常简洁:
#!/usr/bin/env bashset -euo pipefailROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"export CALLER_DIR="$(pwd -W 2>/dev/null || pwd)"cd "$ROOT_DIR"if [[ "${CLAUDE_CODE_FORCE_RECOVERY_CLI:-0}" == "1" ]]; then exec bun --env-file=.env ./src/localRecoveryCli.ts "$@"fiexec bun --env-file=.env ./src/entrypoints/cli.tsx "$@"
这里有一个细节值得注意:CALLER_DIR 会在 preload.ts 中被读取,用来把工作目录切回用户的调用位置。否则 Bun 进程的 cwd 会停留在项目根目录,导致文件操作全部指向错误路径。
这意味着项目不再依赖单一路径启动,而是具备了故障降级能力。当完整 Ink TUI 链路出现依赖问题或初始化异常时,Recovery CLI 可以绕过所有 UI 和插件系统,直接用 readline 提供最基本的对话能力。
多平台运行方式
从当前启动脚本和入口文件来看,这次已经明确整理了多平台运行方式:
-
• macOS / Linux:通过 ./bin/claude-qian启动 -
• Windows:通过 bun --env-file=.env ./src/entrypoints/cli.tsx直接调用入口文件 -
• 全局命令使用:把 bin/加入PATH后,在任意目录调用
多模型接入
.env.example 这次非常关键,因为它把模型接入方式明确模板化了。
当前已经补出了几种典型运行环境:
-
• MiniMax 直连 Anthropic 兼容接口 -
• OpenRouter 直连 Anthropic 兼容接口 -
• OpenAI 通过 LiteLLM 代理接入 -
• DeepSeek 通过 LiteLLM 代理接入
也就是说,这个项目已经不是只能绑定单一服务商,而是可以作为一个”Anthropic 兼容协议入口”的本地 Agent 外壳来运行。
这一层的价值非常实际:
-
• 模型可以替换——不想用 Claude 可以切 DeepSeek -
• 接口可以迁移——从直连切到代理只改环境变量 -
• 成本可以按需调整——开发用便宜模型,生产用强模型 -
• 本地试验和二次开发会更灵活——不需要为了调试一个 prompt 去消耗昂贵的 API 额度
Computer Use 执行链路
src/utils/computerUse/ 相关逻辑已经从原生 Swift / Rust 依赖重构为 Python Bridge 方案:
-
• Bun 负责主运行时 -
• Python 负责桌面控制桥接 -
• 本地自动创建虚拟环境 -
• 依赖按哈希自动安装或更新 -
• 通过子进程桥接截图、鼠标、键盘和前台应用能力
原始源码中 Computer Use 依赖 Swift 和 Rust 编写的原生模块来完成屏幕截图和输入控制。这意味着你需要特定版本的 Xcode、Cargo 工具链,以及和 Anthropic 内部构建系统对齐的编译参数。对于绝大多数本地开发者来说,这条路径几乎不可能复现。
改造后的 Python Bridge 方案用 pyautogui + Pillow 替代了原生截图和输入能力,通过 Bun 子进程调用 Python 脚本来完成桥接。虽然性能上不如原生方案,但胜在依赖简单、跨平台、容易调试。
本地运行时预加载
preload.ts 补齐了本地工程运行时需要的元信息:
-
• 版本号注入( MACRO.VERSION) -
• 包信息注入( MACRO.PACKAGE_URL) -
• 构建时间注入( MACRO.BUILD_TIME) -
• 默认跳过远程预取 -
• 启动时切回调用目录
这部分不直接提供新功能,但决定了项目能否以”本地工程”而不是”临时拼接源码”的方式稳定运行。原始源码在 Anthropic 的内部构建流水线中,这些 MACRO.* 变量是在编译时由打包工具注入的。泄露版本丢失了这个构建环节,所以运行时这些变量全部是 undefined,会导致版本检查、远程配置拉取等多处逻辑崩溃。
从变更看
如果只看文件数量变化,这次修改像是在”补文件”。但从变更结构看,实际完成的是一次工程化修复:
-
• README.md从事件说明转为可运行项目说明 -
• 新增 package.json、bunfig.toml、.env.example、preload.ts、bin/claude-qian -
• 新增 src/localRecoveryCli.ts,补齐降级入口 -
• Computer Use 从原生依赖切换为 Python Bridge -
• 主入口、命令系统、MCP、Skills 和启动流程完成适配
因此,这次工作的目标不是保存源码,而是恢复一套可以本地运行、继续调试和持续扩展的 Agent CLI 工程。
架构概览
从当前结构看,这个项目可以理解为四层:
-
• 入口层:Bun 运行时、预加载、CLI 启动分发 -
• 交互层:Ink TUI、REPL、 --print无头模式、Recovery CLI -
• 编排层:Commands、Tools、Skills、MCP、Multi-Agent、Memory、Workflow -
• 执行层:模型接口、文件系统、Shell、Git、MCP Server、Computer Use
更简洁地说,Bun 负责运行时和启动,Commander 负责命令入口,Ink 负责终端交互,主循环负责请求编排,Commands / Tools / Skills / MCP / Multi-Agent 负责能力扩展,Computer Use 负责桌面执行能力。
整体架构

启动链路
否
是
能力分层

请求生命周期

工具系统

多 Agent 架构

权限与安全
已授权
需确认
允许
拒绝
禁止

服务层

状态与数据流
text
tool_use

核心模块分工
|
|
|
|
|---|---|---|
|
|
bin/claude-qian
preload.ts、src/entrypoints/cli.tsx |
|
|
|
--print、Recovery CLI |
|
|
|
|
|
|
|
|
|
如果按模块理解,可以拆成 4 层
入口层:把工程真正拉起来
核心组件包括:
-
• bin/claude-qian:统一入口脚本,负责环境变量加载和链路分发 -
• preload.ts:运行时信息注入,补齐MACRO.*全局变量 -
• src/entrypoints/cli.tsx:快速分流入口,处理--version、--dump-system-prompt等快速路径 -
• src/main.tsx:完整 CLI 主入口 -
• src/setup.ts:初始化配置、权限、会话等核心基础设施
这一层的职责很明确:启动 Bun 运行时,装载 .env,注入本地运行时信息,设置工作目录,根据参数或环境变量分流到完整 CLI 或 Recovery CLI,然后初始化配置、权限、会话。
交互层:把能力呈现给用户
这一层提供了四种交互模式:
-
• Ink TUI:完整的终端界面,支持滚动、输入框、权限弹窗、多窗口渲染 -
• REPL 主循环:驱动用户输入 → 模型调用 → 工具执行 → 响应输出的完整循环 -
• --print无头模式:适合脚本调用,输入 prompt 直接输出结果 -
• Recovery CLI:纯 readline 实现,绕过 Ink 和所有插件,提供最小可用对话
四种模式的共同点是它们最终都调用同一套请求编排逻辑(query.ts),区别只在于输入输出方式和加载的能力范围。
编排层:项目的核心
从当前结构来看,项目最核心的不是 UI,而是中间这层能力编排:
-
• Commands:面向用户的命令,如 /help、/clear、/compact -
• Tools:面向模型的可执行工具,如 Read、Write、Bash、Agent -
• Skills:可复用的工作流能力,如 commit、review-pr -
• MCP:外部能力接入协议,让模型可以调用第三方服务 -
• Multi-Agent:多 Agent 协作,通过 Agent Tool 派生子任务 -
• Memory:跨会话记忆,持久化用户偏好和项目信息 -
• Plugin / Workflow:扩展能力,支持外部插件挂载
也就是说,这个项目本质上不是一个单纯的对话程序,而是一个带有执行能力、状态能力、扩展能力和外部接入能力的终端 Agent。
执行层:真正与外部世界发生关系
最底层负责把能力真正落地:
-
• 连接 Anthropic 兼容模型接口,发送请求并解析流式响应 -
• 调用文件系统和 Shell,执行读写、搜索、命令运行 -
• 接入 MCP Server,桥接外部工具和数据源 -
• 执行桌面控制能力,通过 Python Bridge 完成截图和输入
其中 Computer Use 这次的改造尤为关键,因为它把一条原本依赖强原生模块的执行路径,改造成了一条更容易在本地复现的 Bun + Python 协同方案。
为什么说补齐的是”运行闭环”
许多源码项目并不缺少单点功能,真正缺少的是完整运行闭环。典型缺口通常包括:
-
• 没有统一运行时——不知道该用 Node 还是 Bun,版本要求不明 -
• 没有明确 CLI 入口——源码有几十个 ts 文件,不知道从哪个开始执行 -
• 没有环境变量模板——缺哪些 key、格式是什么、默认值是什么全靠猜 -
• 没有多平台启动方式——只在某一种 OS 上验证过 -
• 没有模型替换方案——硬编码了特定 API 地址 -
• 没有故障降级路径——任何一个依赖出问题整个系统就起不来 -
• 没有可复现的桌面执行方案——依赖了无法获取的私有模块
这次改造补上的,正是这些决定”能否实际使用”的基础设施。因此,项目当前已经具备一个本地 Agent CLI 的基本闭环:
-
• 可以安装 -
• 可以配置 -
• 可以启动 -
• 可以交互 -
• 可以切换模型 -
• 可以扩展能力 -
• 可以在复杂链路异常时降级运行
当前运行方式
安装依赖
bun install
配置环境变量
cp .env.example .env
然后在 .env 中填入模型配置。当前已预留 MiniMax、OpenRouter、OpenAI + LiteLLM、DeepSeek + LiteLLM 等接入方式。
启动完整 CLI
./bin/claude-qian
直接通过 Bun 启动入口
bun --env-file=.env ./src/entrypoints/cli.tsx
启动 Recovery CLI
CLAUDE_CODE_FORCE_RECOVERY_CLI=1 ./bin/claude-qian
如果只看这几条命令,就能很明显感受到工程化之后的变化:它已经不再是”需要你自己猜入口、补变量、改依赖”的源码,而是一套结构清晰、路径统一的 Bun 项目。
小结
这次补的不是几个脚本或说明文件,而是一套能够本地运行、具备降级路径和扩展接口的 Bun 版 Claude Code 工程。
它补齐了这些关键部分:
-
• Bun 运行环境 -
• 本地 CLI 启动链路 -
• macOS / Linux / Windows 的运行方式 -
• 多模型接入环境 -
• Recovery CLI 降级环境 -
• Computer Use 的 Python Bridge 运行环境 -
• 本地预加载和本地版本化运行时
从整体架构上看,现在这个项目已经具备了一个本地 Agent CLI 应有的基本轮廓:有统一入口、有运行时、有终端交互、有工具和命令系统、有 MCP 和 Multi-Agent 扩展能力、有桌面控制链路、有降级方案。
对于想研究本地 Agent、终端智能助手或 Claude Code 类项目结构的人来说,这个版本的价值已经从”可阅读”提升为”可运行、可调试、可扩展”。
源码地址:https://github.com/xuqssq/claude-code-qian
夜雨聆风