Claude Code 源码泄露:拆解核心原理
Claude Code 源码泄露:拆解核心原理
第一部分:事件回顾
先快速说说发生了什么。
Anthropic 在 npm 上发布 Claude Code 包的时候,不知道是故意的还是手滑,把 Source Map 文件一起发了上去。
Source Map 是什么?简单说就是”调试用的地图”。线上产品应该用压缩混淆后的代码,Source Map 是给开发者调试用的,不应该发布到生产环境。
但 Anthropic 发了。结果就是任何人下载这个包,解开一看 .map 文件,就能把压缩后的代码还原成完整的 TypeScript 源码——变量名、注释、目录结构,全在那儿。
这个消息最早是 Twitter 用户 @Fried_rice 发现的,然后就是你们看到的那个 GitHub 仓库。
第二部分:技术栈概览
在开始喷代码质量之前,先看看 Claude Code 用的是什么技术栈。
运行时:Bun语言:TypeScript 严格模式CLI UI:React + Ink(给 CLI 用的 React)CLI 参数解析:Commander.js模式验证:Zod v4代码搜索:ripgrep协议:MCP SDK,LSP认证:OAuth 2.0,JWT,macOS Keychain特性开关:GrowthBook遥测:OpenTelemetry + gRPC
有意思的几个点:
Bun 而不是 Node.js——Bun 号称比 Node.js 快几倍,Anthropic 选它可能就是为了 CLI 的启动速度。
React + Ink——用 React 写 CLI 界面,对前端开发者非常友好,降低了门槛。
Zod v4——运行时类型验证,用在工具输入输出上,确保 LLM 调用的工具参数是正确的。
第三部分:好用的核心原因
先说说 Claude Code 为什么好用。这个问题不吹不黑,它确实解决了实际问题。
原因一:工具调用 Loop
传统 AI 助手的玩法是:AI 生成命令 → 你复制粘贴 → 你执行 → 你把结果贴回去。
Claude Code 不是这样。它内置了一个工具调用循环。当你输入一个任务,Claude 会:
-
分析任务 -
决定调用哪个工具 -
自动执行 -
拿到结果 -
继续分析 -
重复直到完成
整个过程你不需要复制粘贴,Claude 直接替你干活。你只需要在危险操作(比如删除文件)时确认一下。
原因二:上下文感知
Claude Code 不是在你输入时才了解你的项目。它在启动时就开始收集上下文:
-
用 ripgrep 扫描代码库结构 -
读取 CLAUDE.md 了解项目规范 -
通过 LSP 获取类型信息 -
记忆对话历史
所以它的回复不是泛泛而谈,是真的贴合你的代码库。
原因三:并行 Agent
Claude Code 可以生成子 Agent。什么意思?
比如你说”帮我把这个项目拆成三个微服务”,它会:
-
创建一个协调者 Agent -
协调者生成3个子 Agent -
3个子 Agent 并行分析不同模块 -
汇总结果,生成统一的拆解方案
这种并行能力在处理大型任务时,时间节省是指数级的。
原因四:MCP 生态
Claude Code 支持 Model Context Protocol。这意味着它可以连接任何实现了 MCP 的服务——数据库、GitHub、Slack、飞书、各种内部系统。
你可以用自然语言操作一切,不需要记住命令。
第四部分:代码质量——问题远多于亮点
好,夸完了。现在开始说实话。
问题一:460 个 eslint-disable
我 grep 了一下,整个代码库有 460 个 eslint-disable 注释,分布在 242 个文件里。
这是什么概念?
eslint-disable 是用来禁用 ESLint 检查的。偶尔用一下是合理的,比如临时绕过某个误报。但460个——这说明代码里有大量违反代码规范的地方,开发者懒得修或者来不及修,就直接禁用了。
更离谱的是,有些文件的 eslint-disable 是成堆出现的。比如 REPL.tsx 有20个,bridgeMain.ts 有15个,main.tsx 有16个。
这意味着什么?代码质量管控基本靠”我不管了”。
问题二:142 个 TODO/FIXME/HACK
代码里有 142 个 TODO、FIXME、HACK、XXX 标记,分布在 93 个文件里。
TODO 还好——正常开发节奏。但 FIXME 和 HACK 不是好兆头。
FIXME 意味着”这里有已知问题但还没修”。HACK 意味着”这里用了一种不优雅的临时方案”。
93个文件里都有未解决的技术债务。
问题三:84 处循环依赖
这是最严重的问题。
循环依赖就是 A 文件引用 B,B 文件又引用 A。在软件工程里,这会导致”先有鸡还是先有蛋”的问题——模块加载顺序不确定,容易引发奇怪的 bug。
Claude Code 代码库里,有 84 处循环依赖相关内容,分布在 64 个文件中。
最常见的应对方法是:用 require() 动态导入。
比如在 main.tsx 里:
// Lazy require to avoid circular dependencyconstgetTeammateUtils=()=>require('./utils/teammate.js')
这是把动态加载当成了遮羞布。真正的解决办法应该是重新设计模块边界,但他们没时间或者没精力做这件事。
问题四:main.tsx 的 import 灾难
main.tsx 这个文件有 300 多行,几乎全是 import。
import{ profileCheckpoint, profileReport }from'./utils/startupProfiler.js';import{ startMdmRawRead }from'./utils/settings/mdm/rawRead.js';import{ ensureKeychainPrefetchCompleted, startKeychainPrefetch }from'./utils/secureStorage/keychainPrefetch.js';import{ feature }from'bun:bundle';import{ Command as CommanderCommand, InvalidArgumentError, Option }from'@commander-js/extra-typings';import chalk from'chalk';// ... 继续100多行
这种写法不是正常的代码结构。这是”先把所有东西引进来再说”的典型代表。
问题五:代码风格不一致
有的文件用 .ts,有的用 .tsx。有的工具在 tools/ 目录,有的在 commands/ 目录。有的用箭头函数,有的用普通函数。命名有时候用 camelCase,有时候用 PascalCase。
没有一致的代码规范,或者有规范但没人执行。
第五部分:架构亮点
虽然代码质量堪忧,但 Claude Code 的架构设计还是有不少亮点的。
亮点一:特性开关的巧妙实现
他们用 Bun 的 bun:bundle 实现了一个很聪明的特性开关:
import{ feature }from'bun:bundle'const voiceCommand =feature('VOICE_MODE')?require('./commands/voice/index.js').default:null
这意味着在构建时,不用的特性会被完全剔除,不会增加包体积。同时也允许同一个代码库有多个版本——比如付费版有这个功能,免费版没有。
亮点二:并行预取
main.tsx 的开头做了并行预取:
// 这些操作并行执行startMdmRawRead();// MDM 设置startKeychainPrefetch();// 钥匙串读取
三个 I/O 操作同时启动,减少启动时间。
亮点三:懒加载大模块
OpenTelemetry 和 gRPC 是很重的模块。他们用动态 import 延迟加载:
const heavyModule =awaitimport('./heavyModule.js')
只有在需要的时候才加载,不影响启动速度。
亮点四:工具系统的模块化
每个工具都是独立的模块,有标准的接口:
// 工具定义const tool =buildTool({ name:'BashTool', inputSchema: z.object({ command: z.string()}), permissionMode:'dangerous',execute:async(input)=>{...}})
这种设计让新增工具变得简单,不需要动核心代码。
第六部分:一些有趣的发现
说几个花边新闻。
彩蛋:Buddy Sprite
代码里有个 buddy/ 目录,实现了 Companion Sprite(陪伴精灵)。可能以后 Claude Code 会有一只电子宠物?
远程会话
remote/ 目录实现了远程会话分享功能。类似 VS Code 的 Live Share,可以把当前会话分享给其他人。
Vim 模式
对 Vim 用户是好消息——有专门的 vim/ 目录原生支持 Vim 操作。
未完成的 KAIROS
代码里有很多 feature('KAIROS') 的判断——这是一个还没发布的功能,内部叫 KAIROS,可能是一种新的 AI 模式。
总结
Claude Code 源码泄露这件事,给了我们一个难得的机会去审视一个顶级 AI 公司的工程实践。
它好用的原因:
-
工具调用循环让 AI 真正能干活而不是只说话 -
上下文感知让它理解你的项目 -
并行 Agent 提升大型任务效率 -
MCP 生态让它能连接一切
但代码质量确实堪忧:
-
460 个 eslint-disable -
142 个 TODO/FIXME/HACK -
84 处循环依赖 -
代码结构混乱,规范执行不力
这说明什么?
产品做得好,不代表代码写得好。
Claude Code 是一个面向用户的产品,它的价值在于解决了用户的痛点。至于代码里面的技术债务,那是内部的——只要产品能跑,只要用户满意,技术债务可以以后再还。
这是很多商业软件的常见选择:用技术债换速度。
作为工程师,我们应该从中学到两件事:
第一,好的产品设计可以弥补代码质量的不足。Claude Code 证明了这一点。
第二,代码质量终究是会还的债。当你想加新功能、当你想重构、当你想让多人协作——技术债就会来收利息。
至于这次泄露是故意还是手滑——那就见仁见智了。
好了,这期就到这里。如果你觉得有用,点个赞。我们下期见。
本文基于 2026年3月31日泄露的 Claude Code 源码分析写成。
视频讲稿
开场
大家好,今天我们聊一个最近在技术圈炸锅的话题——Claude Code 的源码泄露。
2026年3月31日,有人在 GitHub 上传了一个仓库,据说是从 Anthropic 官方 npm 包的 .map 文件里扒出来的完整 TypeScript 源码。1900个文件,51万行代码,一夜之间全暴露了。
这事儿有意思的地方在于:这是我们第一次有机会真正看清 Claude Code 内部是怎么运作的。
但我今天不想只吹它有多牛——网上已经太多这种文章了。我想做一件更客观的事:拆开它的胸腔,看看里面的零件到底是精工制造还是粗制滥造。
第一部分:事件回顾
先快速说说发生了什么。
Anthropic 在 npm 上发布 Claude Code 包的时候,不知道是故意的还是手滑,把 Source Map 文件一起发了上去。
Source Map 是什么?简单说就是”调试用的地图”。线上产品应该用压缩混淆后的代码,Source Map 是给开发者调试用的,不应该发布到生产环境。
但 Anthropic 发了。结果就是任何人下载这个包,解开一看 .map 文件,就能把压缩后的代码还原成完整的 TypeScript 源码——变量名、注释、目录结构,全在那儿。
这个消息最早是 Twitter 用户 @Fried_rice 发现的,然后就是你们看到的那个 GitHub 仓库。
第二部分:技术栈概览
在开始喷代码质量之前,先看看 Claude Code 用的是什么技术栈。
运行时:Bun语言:TypeScript 严格模式CLI UI:React + Ink(给 CLI 用的 React)CLI 参数解析:Commander.js模式验证:Zod v4代码搜索:ripgrep协议:MCP SDK,LSP认证:OAuth 2.0,JWT,macOS Keychain特性开关:GrowthBook遥测:OpenTelemetry + gRPC
有意思的几个点:
Bun 而不是 Node.js——Bun 号称比 Node.js 快几倍,Anthropic 选它可能就是为了 CLI 的启动速度。
React + Ink——用 React 写 CLI 界面,对前端开发者非常友好,降低了门槛。
Zod v4——运行时类型验证,用在工具输入输出上,确保 LLM 调用的工具参数是正确的。
第三部分:好用的核心原因
先说说 Claude Code 为什么好用。这个问题不吹不黑,它确实解决了实际问题。
原因一:工具调用 Loop
传统 AI 助手的玩法是:AI 生成命令 → 你复制粘贴 → 你执行 → 你把结果贴回去。
Claude Code 不是这样。它内置了一个工具调用循环。当你输入一个任务,Claude 会:
-
分析任务 -
决定调用哪个工具 -
自动执行 -
拿到结果 -
继续分析 -
重复直到完成
整个过程你不需要复制粘贴,Claude 直接替你干活。你只需要在危险操作(比如删除文件)时确认一下。
原因二:上下文感知
Claude Code 不是在你输入时才了解你的项目。它在启动时就开始收集上下文:
-
用 ripgrep 扫描代码库结构 -
读取 CLAUDE.md 了解项目规范 -
通过 LSP 获取类型信息 -
记忆对话历史
所以它的回复不是泛泛而谈,是真的贴合你的代码库。
原因三:并行 Agent
Claude Code 可以生成子 Agent。什么意思?
比如你说”帮我把这个项目拆成三个微服务”,它会:
-
创建一个协调者 Agent -
协调者生成3个子 Agent -
3个子 Agent 并行分析不同模块 -
汇总结果,生成统一的拆解方案
这种并行能力在处理大型任务时,时间节省是指数级的。
原因四:MCP 生态
Claude Code 支持 Model Context Protocol。这意味着它可以连接任何实现了 MCP 的服务——数据库、GitHub、Slack、飞书、各种内部系统。
你可以用自然语言操作一切,不需要记住命令。
第四部分:代码质量——问题远多于亮点
好,夸完了。现在开始说实话。
问题一:460 个 eslint-disable
我 grep 了一下,整个代码库有 460 个 eslint-disable 注释,分布在 242 个文件里。
这是什么概念?
eslint-disable 是用来禁用 ESLint 检查的。偶尔用一下是合理的,比如临时绕过某个误报。但460个——这说明代码里有大量违反代码规范的地方,开发者懒得修或者来不及修,就直接禁用了。
更离谱的是,有些文件的 eslint-disable 是成堆出现的。比如 REPL.tsx 有20个,bridgeMain.ts 有15个,main.tsx 有16个。
这意味着什么?代码质量管控基本靠”我不管了”。
问题二:142 个 TODO/FIXME/HACK
代码里有 142 个 TODO、FIXME、HACK、XXX 标记,分布在 93 个文件里。
TODO 还好——正常开发节奏。但 FIXME 和 HACK 不是好兆头。
FIXME 意味着”这里有已知问题但还没修”。HACK 意味着”这里用了一种不优雅的临时方案”。
93个文件里都有未解决的技术债务。
问题三:84 处循环依赖
这是最严重的问题。
循环依赖就是 A 文件引用 B,B 文件又引用 A。在软件工程里,这会导致”先有鸡还是先有蛋”的问题——模块加载顺序不确定,容易引发奇怪的 bug。
Claude Code 代码库里,有 84 处循环依赖相关内容,分布在 64 个文件中。
最常见的应对方法是:用 require() 动态导入。
比如在 main.tsx 里:
// Lazy require to avoid circular dependencyconstgetTeammateUtils=()=>require('./utils/teammate.js')
这是把动态加载当成了遮羞布。真正的解决办法应该是重新设计模块边界,但他们没时间或者没精力做这件事。
问题四:main.tsx 的 import 灾难
main.tsx 这个文件有 300 多行,几乎全是 import。
import{ profileCheckpoint, profileReport }from'./utils/startupProfiler.js';import{ startMdmRawRead }from'./utils/settings/mdm/rawRead.js';import{ ensureKeychainPrefetchCompleted, startKeychainPrefetch }from'./utils/secureStorage/keychainPrefetch.js';import{ feature }from'bun:bundle';import{ Command as CommanderCommand, InvalidArgumentError, Option }from'@commander-js/extra-typings';import chalk from'chalk';// ... 继续100多行
这种写法不是正常的代码结构。这是”先把所有东西引进来再说”的典型代表。
问题五:代码风格不一致
有的文件用 .ts,有的用 .tsx。有的工具在 tools/ 目录,有的在 commands/ 目录。有的用箭头函数,有的用普通函数。命名有时候用 camelCase,有时候用 PascalCase。
没有一致的代码规范,或者有规范但没人执行。
第五部分:架构亮点
虽然代码质量堪忧,但 Claude Code 的架构设计还是有不少亮点的。
亮点一:特性开关的巧妙实现
他们用 Bun 的 bun:bundle 实现了一个很聪明的特性开关:
import{ feature }from'bun:bundle'const voiceCommand =feature('VOICE_MODE')?require('./commands/voice/index.js').default:null
这意味着在构建时,不用的特性会被完全剔除,不会增加包体积。同时也允许同一个代码库有多个版本——比如付费版有这个功能,免费版没有。
亮点二:并行预取
main.tsx 的开头做了并行预取:
// 这些操作并行执行startMdmRawRead();// MDM 设置startKeychainPrefetch();// 钥匙串读取
三个 I/O 操作同时启动,减少启动时间。
亮点三:懒加载大模块
OpenTelemetry 和 gRPC 是很重的模块。他们用动态 import 延迟加载:
const heavyModule =awaitimport('./heavyModule.js')
只有在需要的时候才加载,不影响启动速度。
亮点四:工具系统的模块化
每个工具都是独立的模块,有标准的接口:
// 工具定义const tool =buildTool({ name:'BashTool', inputSchema: z.object({ command: z.string()}), permissionMode:'dangerous',execute:async(input)=>{...}})
这种设计让新增工具变得简单,不需要动核心代码。
第六部分:一些有趣的发现
说几个花边新闻。
彩蛋:Buddy Sprite
代码里有个 buddy/ 目录,实现了 Companion Sprite(陪伴精灵)。可能以后 Claude Code 会有一只电子宠物?
远程会话
remote/ 目录实现了远程会话分享功能。类似 VS Code 的 Live Share,可以把当前会话分享给其他人。
Vim 模式
对 Vim 用户是好消息——有专门的 vim/ 目录原生支持 Vim 操作。
未完成的 KAIROS
代码里有很多 feature('KAIROS') 的判断——这是一个还没发布的功能,内部叫 KAIROS,可能是一种新的 AI 模式。
总结
Claude Code 源码泄露这件事,给了我们一个难得的机会去审视一个顶级 AI 公司的工程实践。
它好用的原因:
-
工具调用循环让 AI 真正能干活而不是只说话 -
上下文感知让它理解你的项目 -
并行 Agent 提升大型任务效率 -
MCP 生态让它能连接一切
但代码质量确实堪忧:
-
460 个 eslint-disable -
142 个 TODO/FIXME/HACK -
84 处循环依赖 -
代码结构混乱,规范执行不力
这说明什么?
产品做得好,不代表代码写得好。
Claude Code 是一个面向用户的产品,它的价值在于解决了用户的痛点。至于代码里面的技术债务,那是内部的——只要产品能跑,只要用户满意,技术债务可以以后再还。
这是很多商业软件的常见选择:用技术债换速度。
作为工程师,我们应该从中学到两件事:
第一,好的产品设计可以弥补代码质量的不足。Claude Code 证明了这一点。
第二,代码质量终究是会还的债。当你想加新功能、当你想重构、当你想让多人协作——技术债就会来收利息。
至于这次泄露是故意还是手滑——那就见仁见智了。
好了,这期就到这里。如果你觉得有用,点个赞。我们下期见。
本文基于 2026年3月31日泄露的 Claude Code 源码分析写成。
夜雨聆风