对照 cli.tsx 的 bootstrap 快速路径,把 Claude Code 的 Base URL 改到 TaoToken

📅 发布时间:2026/9/19 8:17:06
对照 cli.tsx 的 bootstrap 快速路径,把 Claude Code 的 Base URL 改到 TaoToken
1. 对照 cli.tsx bootstrap 的快速路径问题与适用场景要在本机运行 Claude Code并对照 src/entrypoints/cli.tsx 观察 --version 的零模块加载通道必须先就位TaoToken 官网 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 注册后创建 KeyBase URL 用 https://taotoken.net/api。否则你只能读到源码里的return却没法进入完整 CLI 验证请求是否真的发得出去。Claude Code 的入口文件src/entrypoints/cli.tsx只有 302 行但里面塞了 10 多个快速路径、20 多个动态导入。它的核心任务不是处理业务而是在任何业务模块被 eval 之前先把--version、--daemon、--bg、remote-control等特殊入口拦截掉。真正复杂的主程序被推迟到await import(../main.js)才加载。这篇要解决两个问题第一把 cli.tsx 的 bootstrap 机制拆开看理解快速路径、动态导入、feature()DCE、--bare与CLAUDE_CODE_SIMPLE的设计第二给本机 Claude Code 配一条能用的模型通道让源码观察不停留在静态阅读。TaoToken 在这里只提供 Key 和 Base URL不参与也不改 cli.tsx 的任何加载逻辑。2. TaoToken 接入前置Key、模型广场与环境变量时机打开 TaoToken 官网注册账号后进入控制台创建 API Key。模型 ID 不要凭记忆写以官网模型广场当前展示的可用模型为准下面的配置里用MODEL_ID占位你替换成实际模型名即可。cli.tsx 反复强调一件事环境变量必须早于模块加载。--bare路径要在任何模块 eval 之前把process.env.CLAUDE_CODE_SIMPLE设成 1否则 Commander 的 option building 就错过了。模型通道的配置同理ANTHROPIC_BASE_URL和ANTHROPIC_AUTH_TOKEN必须在 Claude Code 进程启动前就存在不能等进了交互模式再临时设置。有两种放法。第一种是 shell profile适合你经常在终端里直接敲claude# ~/.zshrc 或 ~/.bashrc export ANTHROPIC_BASE_URLhttps://taotoken.net/api export ANTHROPIC_AUTH_TOKENYOUR_API_KEY export ANTHROPIC_MODELMODEL_ID改完后执行source ~/.zshrc或者重开终端。第二种是 Claude Code 的~/.claude/settings.json适合把配置固定在工具侧{ env: { ANTHROPIC_BASE_URL: https://taotoken.net/api, ANTHROPIC_AUTH_TOKEN: YOUR_API_KEY, ANTHROPIC_MODEL: MODEL_ID } }注意 Base URL 后面不要再拼/v1。Claude Code 会按自己的路径规则拼接请求写成https://taotoken.net/api/v1反而可能让完整 CLI 路径请求到错误地址。Key 用刚创建的那串模型 ID 从模型广场复制。3. --version 为什么能零模块加载MACRO.VERSION 与动态导入分界先看 cli.tsx 里最短的快速路径。它的判断条件非常窄参数长度为 1且参数是--version、-v或-V。命中后只做一件事——打印版本号然后立即返回。if ( args.length 1 (args[0] --version || args[0] -v || args[0] -V) ) { console.log(${MACRO.VERSION} (Claude Code)); return; }MACRO.VERSION是 Bun 的编译时内建变量构建阶段就从 package.json 和 git describe 注入。运行时它不是函数调用也不是远程查询而是一个已经被内联的字符串。因此这条路径不需要加载 config、不需要初始化 Commander、不需要建立网络通道真正做到零模块加载。对比静态导入和动态导入// 静态导入编译时确定模块图里立即存在 import { main } from ../main.js; // 动态导入执行到这一句才触发加载 const { main: cliMain } await import(../main.js); await cliMain();cli.tsx 顶部只有一个静态导入import { feature } from bun:bundle;因为feature()需要在模块加载时就可被 Bun 识别并且它的 flag 是编译期常量。除此之外主程序、daemon、后台会话、MCP 服务全部走动态导入。这样--version才能避开整张模块图而其他命令接受稍长的加载时间。4. 快速路径地图从 --dump-system-prompt 到 daemon、--bg、remote-control把 cli.tsx 的 302 行按 argv 分支展开可以得到一张责任链地图。每个特殊标志对应一个处理器命中后 return不继续往下走。--version/-v/-V直接打印MACRO.VERSION零模块加载。--dump-system-prompt加载 config.js 和 prompts.js渲染系统提示词它依赖模型选择、工具列表等配置所以不能零加载。--claude-in-chrome-mcp、--chrome-native-host、--computer-use-mcp分别加载对应的 MCP server 模块其中部分被feature(CHICAGO_MCP)包裹。--daemon-workerkind加载 workerRegistry.js按 kind 启动 worker。remote-control/rc/remote/sync/bridge加载 bridgeMain.js但前面有认证、版本、策略三层检查。daemon加载 daemon/main.js面向长运行守护进程。ps/logs/attach/kill/--bg/--background加载 cli/bg.js面向后台会话管理。new/list/reply加载 templateJobs.js。environment-runner、self-hosted-runner分别加载对应 runner 的 main。其他命令最后才await import(../main.js)进入完整 CLI。profileCheckpoint会在进入快速路径时打点例如cli_version_path、cli_daemon_path、cli_bg_path。它本身不改变行为但能记录启动性能方便分析哪条路径被高频使用、哪条路径耗时异常。--bg和daemon容易混淆--bg是用户控制的后台会话管理加载cli/bg.jsdaemon更像系统级服务加载daemon/main.js。remote-control之所以检查多是因为它涉及远程控制能力必须确认登录态、最低版本和策略允许任何一项不满足都要提前退出。5. feature() 与 bun:bundle构建期 DCE 如何删掉内部功能feature()来自bun:bundle是编译时条件编译函数。它必须写在if条件里而且最好保持 inlineif (feature(CHICAGO_MCP) process.argv[2] --computer-use-mcp) { const { runComputerUseMcpServer } await import( ../utils/computerUse/mcpServer.js ); await runComputerUseMcpServer(); return; }如果构建时CHICAGO_MCP为 false整个if块会被 Dead Code Elimination 删除。产物里不再存在这段分支也不需要运行时判断。DUMP_SYSTEM_PROMPT同样如此它用于内部构建外部构建时 flag 为 false整个 block 被消除。这里有个容易踩的坑不要把feature()提取到变量再判断。// 不推荐可能破坏 DCE const isDaemon feature(DAEMON); if (isDaemon args[0] daemon) { }feature()和动态导入解决的不是同一个问题。动态导入是运行时按需加载代码仍然在产物里feature()是构建时消除代码根本不会进入外部构建产物。也正因如此--version不能用feature()包裹。如果VERSIONflag 在构建时为 false整个版本判断会被删掉用户执行claude --version时会跳过快速路径转而加载完整 main.js体验完全相反。6. --bare 与 CLAUDE_CODE_SIMPLE环境变量必须早于模块 eval--bare的处理很短但位置极其关键。它要在任何模块 eval 之前设置环境变量if (args.includes(--bare)) { process.env.CLAUDE_CODE_SIMPLE 1; }为什么不能放到 main.tsx 的 action handler 里因为 Commander 的 option building 发生在 action 执行之前。某些模块在 import 阶段就会检查CLAUDE_CODE_SIMPLE如果等到 action 里才设置模块级 gate 已经错过Commander 的选项也已经构建完了。这和第 2 节的 TaoToken 配置是同一个原则通道变量必须早于 Claude Code 进程加载。你把ANTHROPIC_BASE_URL和ANTHROPIC_AUTH_TOKEN写进 shell profile 或~/.claude/settings.json的 env 段就是在模拟 cli.tsx 对--bare的处理方式。区别只是 cli.tsx 控制的是内部简单模式你控制的是模型请求出口。7. 验证先走 --version 快速路径再进交互模式确认通道配置完成后不要直接开交互模式。按原文的验证顺序来先验证零模块加载的快速路径再验证完整 CLI 路径。第一步claude --version期望看到类似x.y.z (Claude Code)的输出并且几乎立即返回。这一步不触发网络请求只证明 cli.tsx 的--version快速路径正常。第二步claude进入交互模式后发一条短请求例如“用一句话确认当前通道可用”。如果模型正常返回说明完整 CLI 路径已经加载并且ANTHROPIC_BASE_URL与ANTHROPIC_AUTH_TOKEN在模块 eval 之前就生效了。若你更想脚本化验证也可以用claude -p 用一句话确认当前通道可用它同样会走完整 CLI 加载路径。这两步分别对应 cli.tsx 的两条路径--version证明快速路径没有被破坏交互请求证明await import(../main.js)之后的模型通道可用。8. 常见错误与排查快速路径正常但完整路径报错第一种现象claude --version正常但一进交互模式就认证失败。这通常说明ANTHROPIC_AUTH_TOKEN没有进入 Claude Code 进程。先检查echo $ANTHROPIC_AUTH_TOKEN是否有值如果为空把配置写进 shell profile 后重开终端或者确认~/.claude/settings.json的env段拼写正确。第二种现象Base URL 末尾多写了/v1。cli.tsx 不会替你纠正这个路径完整 CLI 会按配置拼接请求。把ANTHROPIC_BASE_URL改回https://taotoken.net/api不要带/v1。第三种现象settings.json格式错误。env必须是对象冒号和引号遵循 JSON 规则。一个多余逗号就可能让 Claude Code 读不到配置表现却像 Key 失效。第四种现象你为了观察--bare手动设置了CLAUDE_CODE_SIMPLE1但模型通道没配。CLAUDE_CODE_SIMPLE只影响简单模式和模块级 gate不提供模型出口。通道仍要靠ANTHROPIC_BASE_URL和ANTHROPIC_AUTH_TOKEN。第五种现象新加命令用了feature()包裹外部构建里命令消失。这时不是运行时错误而是 DCE 在构建期删掉了整个 block。像--version这种必须始终存在的功能不要用 feature flag 包裹。9. CTA把通道配置固化再回源码看 preAction你已经完成两件事把 TaoToken 的 Key 和 Base URL 写进 shell profile 或~/.claude/settings.json并用claude --version加交互请求验证了快速路径与完整路径。接下来如果要把 Key 管理得更清晰或者要把 Claude Code 接入配置完整过一遍可以继续看这两个入口管理 API Keyhttps://taotoken.net/console/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentapi-keysClaude Code 接入文档https://taotoken.net/doc/ClaudeCodeAnthropic?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentclaude-code-doc通道稳定后回到 cli.tsx 的下一层main.tsx 的 preAction 钩子。为什么claude --help不触发初始化init()在什么时机执行这些问题的答案会直接解释快速路径与完整路径之间的空白地带。