docs(article): 添加 Claude Code 源码分析文章及相关架构图
- 新增 008 号文章《51 万行源码意外曝光!我扒完了 Claude Code 的全部家底》 - 添加 8 个 Mermaid 架构图文件,涵盖整体架构、启动流程、查询循环等 - 新增项目配置文件 CLAUDE.md,定义自媒体写作规范 - 创建详细的架构分析文档 claude-arch-by-claude.md - 包含权限系统、工具调度、多智能体等核心技术解析 - 记录反蒸馏机制、KAIROS 守护进程等隐藏功能发现 - 提供完整的工具清单及安全防护措施说明
@ -17,4 +17,5 @@
|
|||||||
- 七牛 CDN 域名:`https://cdn.union.jxyunge.com/self-media/`
|
- 七牛 CDN 域名:`https://cdn.union.jxyunge.com/self-media/`
|
||||||
- 图片存放路径规则:`{编号}/{文件名}`,如 `005/cover.jpg`、`005/rubin-gpu.jpg`
|
- 图片存放路径规则:`{编号}/{文件名}`,如 `005/cover.jpg`、`005/rubin-gpu.jpg`
|
||||||
- 禁止在正式文章中直接引用第三方图片链接(外链不稳定,可能失效)
|
- 禁止在正式文章中直接引用第三方图片链接(外链不稳定,可能失效)
|
||||||
|
- 写文章时不能使用占位符图片链接,所有图片必须先实际生成/下载到本地,再通过 `/upload-qiniu` 上传到七牛,最后用真实的七牛 CDN 链接替换到文章中
|
||||||
- 使用 `/upload-qiniu` 工具上传图片到七牛
|
- 使用 `/upload-qiniu` 工具上传图片到七牛
|
||||||
|
|||||||
405
articles/008-51万行源码意外曝光!我扒完了Claude Code的全部家底.md
Normal file
@ -0,0 +1,405 @@
|
|||||||
|
# 51 万行源码意外曝光!我扒完了 Claude Code 的全部家底
|
||||||
|
|
||||||
|
> 发布日期:2026-04-01
|
||||||
|
> 分类:技术解读 / 深度分析
|
||||||
|
> 作者:老邓唠AI
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## 引子:Anthropic 自己把自己扒光了
|
||||||
|
|
||||||
|
3 月 31 日凌晨,AI 圈炸了一颗核弹。
|
||||||
|
|
||||||
|
不是发新模型,不是融资消息——是 **Anthropic 自己把 Claude Code 的完整源码泄漏了**。
|
||||||
|
|
||||||
|
事情是这样的:Anthropic 在 npm 发布 `@anthropic-ai/claude-code@2.1.88` 时,打包进了一个 59.8MB 的 JavaScript Source Map 文件。这个 `.map` 文件本来是内部调试用的,但它直接指向了 Anthropic 自家 Cloudflare R2 存储桶上的**完整 TypeScript 源码压缩包**。
|
||||||
|
|
||||||
|
安全研究员 Chaofan Shou 第一个发现了这个链接,并在 X 上公开。
|
||||||
|
|
||||||
|
<!-- TODO: Chaofan Shou 推特截图 -->
|
||||||
|
|
||||||
|
几小时内,**1,900 个 TypeScript 文件、512,664 行代码**被完整镜像到 GitHub 上。有人甚至在 2 小时内就用 Python 重写了核心逻辑,仓库星标飙到 5 万。
|
||||||
|
|
||||||
|
更讽刺的是,这已经是 Anthropic **第二次**犯同样的错误——2025 年 2 月就出过一次几乎一模一样的 source map 泄漏。而就在几天前,他们还刚刚意外暴露了内部模型代号 "Mythos"。
|
||||||
|
|
||||||
|
Anthropic 官方的回应是:*"This was a release packaging issue caused by human error, not a security breach."*(这是人为错误导致的发布打包问题,不是安全漏洞。)
|
||||||
|
|
||||||
|
但代码已经在互联网上了。**DMCA 撤回通知能删仓库,删不掉已经下载到本地的 zip 包。**
|
||||||
|
|
||||||
|
我花了一整天时间,把这 51 万行代码从头到尾扒了一遍。下面是我发现的全部内容。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 一、这到底是个多大的工程?
|
||||||
|
|
||||||
|
先看硬核数据:
|
||||||
|
|
||||||
|
| 指标 | 数据 |
|
||||||
|
|------|------|
|
||||||
|
| 总代码量 | **512,664 行** TypeScript |
|
||||||
|
| 文件数 | 1,884 个 `.ts/.tsx` 文件 |
|
||||||
|
| 运行时 | Bun(不是 Node.js) |
|
||||||
|
| 终端 UI | 自研 Ink 分支 + React + Yoga Layout |
|
||||||
|
| Schema 校验 | Zod v4(所有工具输入、API 响应、配置文件) |
|
||||||
|
| 实验平台 | GrowthBook(所有开关都用 `tengu_` 前缀) |
|
||||||
|
| 最大单文件 | `print.ts` — **5,594 行,单个函数 3,167 行,12 层嵌套** |
|
||||||
|
|
||||||
|
51 万行是什么概念?Linux 内核 0.01 版不到 1 万行,整个 VS Code 编辑器大约 30 万行。Claude Code 一个 CLI 工具,代码量比 VS Code 还多。
|
||||||
|
|
||||||
|
**这不是一个"LLM 套壳",这是一个完整的操作系统级智能体。**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 二、整体架构:五层洋葱
|
||||||
|
|
||||||
|
从源码来看,Claude Code 的架构像一颗洋葱,从外到内分五层:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
我们一层一层拆。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 三、启动流程:快到你感觉不到
|
||||||
|
|
||||||
|
你在终端敲下 `claude` 回车,背后发生了什么?
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
关键设计:**入口文件只有 302 行**。通过动态 `import()` 延迟加载 4,683 行的主模块,确保 `claude --version` 这种简单命令毫秒级响应。所有重依赖(MCP、GrowthBook、keychain)都是**并行初始化**,不互相等待。
|
||||||
|
|
||||||
|
这是一个对启动速度有执念的团队写出来的代码。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 四、核心引擎:一个永不停歇的循环
|
||||||
|
|
||||||
|
Claude Code 的心脏是一个**流式查询循环**。你发一条消息,引擎就开始转:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
几个精妙的设计:
|
||||||
|
|
||||||
|
**1. 输出恢复机制**:当模型因 `max_output_tokens` 截断时,自动续写,最多重试 3 次。你以为 Claude 一口气写了 2000 行代码?其实它可能分了 3 次才写完,但你看不出接缝。
|
||||||
|
|
||||||
|
**2. 工具结果预算**:工具返回的结果如果太大(比如 `grep` 搜到了 1 万行),不会直接塞进上下文窗口。而是**存到磁盘**,给模型一个文件路径 + 预览摘要。这就是为什么 Claude Code 处理大项目不容易爆上下文。
|
||||||
|
|
||||||
|
**3. 自动压缩**:当 token 数接近上下文窗口极限时(默认留 20,000 token 缓冲区),自动触发一轮"摘要"调用,把历史对话压缩成精简版。你聊了 100 轮,模型看到的可能只有最近 10 轮 + 前 90 轮的摘要。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 五、工具系统:40+ 个武器库
|
||||||
|
|
||||||
|
Claude Code 注册了超过 40 个工具。但更有意思的是它们的**分类和调度策略**。
|
||||||
|
|
||||||
|
### 完整工具清单
|
||||||
|
|
||||||
|
| 分类 | 工具 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| 文件操作 | FileRead, FileWrite, FileEdit, Glob, Grep, NotebookEdit | 读写搜索编辑 |
|
||||||
|
| 系统执行 | Bash, PowerShell | Shell 命令 |
|
||||||
|
| 网络 | WebFetch, WebSearch | 抓网页、搜索 |
|
||||||
|
| 智能体 | Agent, SendMessage, TeamCreate, TeamDelete | 生成/管理子智能体 |
|
||||||
|
| 任务 | TaskCreate/Get/Update/List/Stop/Output | 后台任务管理 |
|
||||||
|
| 规划 | EnterPlanMode, ExitPlanMode | 只读规划模式 |
|
||||||
|
| Git | EnterWorktree, ExitWorktree | Worktree 隔离 |
|
||||||
|
| MCP | MCPTool, ListMcpResources, ReadMcpResource | MCP 协议 |
|
||||||
|
| 辅助 | ToolSearch, Skill, AskUserQuestion, Config, Brief, LSP, TodoWrite | 杂项 |
|
||||||
|
| **KAIROS 专属** | Sleep, CronCreate/Delete/List, Monitor, PushNotification | 自主守护模式 |
|
||||||
|
|
||||||
|
### 读写分离调度
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
每个工具都声明了自己是否"并发安全"(`isConcurrencySafe`)。读文件、搜索这类只读操作可以 10 个并发跑;改文件、执行命令这类写操作必须排队。
|
||||||
|
|
||||||
|
这就是为什么你让 Claude Code 探索一个大项目时速度特别快——它在后台同时搜 10 个文件。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 六、权限系统:六种模式,层层过滤
|
||||||
|
|
||||||
|
这可能是 Claude Code 最严谨的模块,**24 个文件**专门负责权限控制。
|
||||||
|
|
||||||
|
### 六种安全模式
|
||||||
|
|
||||||
|
| 模式 | 行为 | 典型场景 |
|
||||||
|
|------|------|---------|
|
||||||
|
| `default` | 每次新操作都问你 | 日常使用 |
|
||||||
|
| `plan` | 只能读,不能写 | 审查代码 |
|
||||||
|
| `acceptEdits` | 自动接受文件编辑 | 信任的项目 |
|
||||||
|
| `bypassPermissions` | 跳过所有检查 | YOLO 模式 |
|
||||||
|
| `dontAsk` | 不问就拒绝 | 最严格 |
|
||||||
|
| `auto` | **AI 自动判断安全性** | Anthropic 内部专用 |
|
||||||
|
|
||||||
|
### 权限决策链
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
白名单支持 glob 模式:`Bash(git *)` 表示允许所有 `git` 开头的命令。连续被拒绝太多次后,系统会自动降级到手动确认模式,防止模型"硬闯"。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 七、多智能体:一个包工头带一群工人
|
||||||
|
|
||||||
|
Claude Code 的多智能体系统分两层:**协调器**(包工头)和**工作智能体**(工人)。
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
协调器的系统提示词长达 300 多行,定义了**四阶段工作流**:
|
||||||
|
|
||||||
|
1. **Research** — 先派人探索代码库
|
||||||
|
2. **Synthesis** — 汇总发现,制定方案
|
||||||
|
3. **Implementation** — 派多个工人并行修改
|
||||||
|
4. **Verification** — 跑测试,验收结果
|
||||||
|
|
||||||
|
最有意思的是,这套协调逻辑**不是写在代码里的,而是写在 prompt 里的**。协调器通过系统提示词被"教会"如何当领导:
|
||||||
|
|
||||||
|
> *"Do not rubber-stamp weak work"*(不要草率通过低质量工作)
|
||||||
|
> *"You must understand findings before directing follow-up work"*(必须理解发现后才能指导下一步)
|
||||||
|
|
||||||
|
用 prompt 而非代码来编排多智能体——这可能是目前最优雅的 Agent 编排方式。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 八、记忆系统:文件驱动的长期记忆
|
||||||
|
|
||||||
|
Claude Code 的记忆不是什么花哨的向量数据库,而是**最朴素的文件系统**:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
每条记忆是一个独立的 Markdown 文件,带 frontmatter(标题、描述、类型)。`MEMORY.md` 是索引文件,限制 200 行 / 25KB,直接注入系统提示词。需要回忆时,通过语义搜索找到相关记忆文件再注入。
|
||||||
|
|
||||||
|
还有一个**记忆老化**机制(`memoryAge.ts`),会逐步淘汰过时的记忆。
|
||||||
|
|
||||||
|
简单、可靠、可调试。不需要起一个 Pinecone 实例。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 九、系统提示词:分段缓存的精密工程
|
||||||
|
|
||||||
|
Claude Code 的系统提示词不是一个大字符串,而是分成**静态段**和**动态段**,中间用一个缓存边界分隔:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
静态段通过 Anthropic API 的 `cache_control` 参数跨会话缓存,动态段每次重新构建。这直接影响成本——缓存命中的 token **不计费**。
|
||||||
|
|
||||||
|
源码注释里有一句话让我印象深刻:
|
||||||
|
|
||||||
|
> *"在按 token 付费时,缓存失效不再是计算机科学笑话,而是会计问题。"*
|
||||||
|
|
||||||
|
为此,他们写了一个 `promptCacheBreakDetection.ts`,追踪 **12 个缓存破坏维度**。一旦检测到缓存命中率异常下降,就触发报警。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 十、隐藏彩蛋:源码里的"不能说的秘密"
|
||||||
|
|
||||||
|
这才是本次泄漏最劲爆的部分。源码里藏着大量**从未公开的功能和机制**。
|
||||||
|
|
||||||
|
### 10.1 反蒸馏机制:给竞争对手下毒
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// services/api/claude.ts (301-313)
|
||||||
|
if (feature('ANTI_DISTILLATION_CC')) {
|
||||||
|
if (process.env.CLAUDE_CODE_ENTRYPOINT === 'cli' &&
|
||||||
|
shouldIncludeFirstPartyOnlyBetas()) {
|
||||||
|
result.anti_distillation = ['fake_tools']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
当启用时,向 API 请求注入 `anti_distillation: ['fake_tools']`。效果:**服务端会在工具调用中混入虚假的工具响应**。
|
||||||
|
|
||||||
|
什么意思?如果有竞争对手在录制 Claude Code 的 API 流量来训练自己的模型,这些虚假的工具数据就会**污染他们的训练集**。
|
||||||
|
|
||||||
|
简单说:**你抄我的作业?我给你塞几道错题。**
|
||||||
|
|
||||||
|
不过分析者指出,这个机制其实很容易绕过——MITM 代理在请求到达 API 前就能剥离该字段。*"真正的保护可能是法律而非技术。"*
|
||||||
|
|
||||||
|
### 10.2 伪装模式:Anthropic 员工的"隐身衣"
|
||||||
|
|
||||||
|
`utils/undercover.ts` 大约 90 行,但信息量巨大。
|
||||||
|
|
||||||
|
当 Anthropic 内部员工用 Claude Code 在**外部开源仓库**工作时,这个模式自动启用。它会:
|
||||||
|
|
||||||
|
- 删除所有 "Co-Authored-By: Claude" 标识
|
||||||
|
- 禁止提及内部代码名(Capybara、Tengu 等)
|
||||||
|
- 隐藏内部 Slack 频道和仓库名
|
||||||
|
- 不暴露未发布的模型版本号
|
||||||
|
|
||||||
|
最关键的一行注释:
|
||||||
|
|
||||||
|
> *"There is NO force-OFF. This guards against model codename leaks."*
|
||||||
|
|
||||||
|
**没有强制关闭开关。** 这是一扇单向门——一旦检测到外部仓库就自动启用,谁也关不掉。
|
||||||
|
|
||||||
|
这说明什么?**Anthropic 的员工一直在用 Claude Code 给开源项目提交代码,而且不想让任何人知道。**
|
||||||
|
|
||||||
|
### 10.3 挫折感检测:它知道你在骂人
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// utils/userPromptKeywords.ts
|
||||||
|
const negativePattern =
|
||||||
|
/\b(wtf|wth|ffs|omfg|shit(ty|tiest)?|dumbass|horrible|awful|
|
||||||
|
piss(ed|ing)? off|piece of (shit|crap|junk)|what the (fuck|hell)|
|
||||||
|
fucking? (broken|useless|terrible|awful|horrible)|fuck you|
|
||||||
|
screw (this|you)|so frustrating|this sucks|damn it)\b/
|
||||||
|
```
|
||||||
|
|
||||||
|
这段正则表达式扫描你的每一条输入。一旦检测到你在骂 Claude,就会弹出一个分享对话记录的提示——方便 Anthropic 内部员工快速提交反馈。
|
||||||
|
|
||||||
|
为什么用正则而不是让 LLM 判断?注释写道:**"正则比 LLM 推理更快更便宜"**——用于简单的脏话检测,杀鸡不用牛刀。
|
||||||
|
|
||||||
|
> 放心,这个功能在外部版本中是被编译器完整删除的。你骂了也没人知道。
|
||||||
|
|
||||||
|
### 10.4 KAIROS:一直在线的 AI 守护者
|
||||||
|
|
||||||
|
**KAIROS**——古希腊语"恰当的时机"——是这次泄漏中**最重磅的发现**。
|
||||||
|
|
||||||
|
它在源码中被提及超过 **150 次**,是一个完全已经开发好但尚未发布的功能:**始终在线的后台智能体**。
|
||||||
|
|
||||||
|
当前的 Claude Code 是"你问我答"模式。但 KAIROS 模式下,Claude Code 变成了一个**永不下线的守护进程**:
|
||||||
|
|
||||||
|
- **autoDream**:你不用 Claude Code 的时候,它在后台自动"做梦"——整理记忆、合并发现、消除矛盾
|
||||||
|
- **Cron 任务**:每 5 分钟刷新一次计划任务
|
||||||
|
- **GitHub webhook**:监听你仓库的 PR、Issue、CI 状态
|
||||||
|
- **推送通知**:主动找你汇报发现
|
||||||
|
|
||||||
|
autoDream 的触发条件也在源码里:
|
||||||
|
1. 距离上次整合 ≥ 24 小时
|
||||||
|
2. 至少 5 个新会话
|
||||||
|
3. 同一时间只有一个进程执行整合(进程锁)
|
||||||
|
|
||||||
|
**这不再是一个工具,这是一个 AI 同事。**
|
||||||
|
|
||||||
|
### 10.5 Buddy 伴侣系统:愚人节彩蛋?认真的?
|
||||||
|
|
||||||
|
`buddy/` 目录包含一个完整的 **Tamagotchi 风格虚拟宠物系统**:
|
||||||
|
|
||||||
|
- **18 种物种**:鸭子、龙、章鱼、水豚、幽灵、蘑菇……物种名用十六进制编码,因为其中一个物种名跟内部模型代号撞了
|
||||||
|
- **稀有度**:普通(60%)、非凡(25%)、稀有(10%)、史诗(4%)、**传说(1%)**
|
||||||
|
- **RPG 属性**:DEBUGGING、PATIENCE、CHAOS、WISDOM、SNARK
|
||||||
|
- **防篡改**:宠物数据从 `hash(userId)` 确定性生成,不存在本地配置里。你想改配置文件把自己的宠物变成传说级?不好意思,每次都是现算的
|
||||||
|
|
||||||
|
活跃窗口:**2026 年 4 月 1-7 日**。没错,就是今天开始。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 十一、Bash 安全:23 道防线
|
||||||
|
|
||||||
|
Claude Code 让 AI 在你电脑上执行 Shell 命令。这意味着安全必须做到极致。
|
||||||
|
|
||||||
|
`bashSecurity.ts` 实现了 **23 项编号安全检查**:
|
||||||
|
|
||||||
|
| 防御类别 | 具体内容 |
|
||||||
|
|---------|---------|
|
||||||
|
| 命令注入 | 拦截 `$()`、`${}`、进程替换 `<()`、`>()` |
|
||||||
|
| Zsh 危险命令 | 封禁 `zmodload`、`sysopen`、`ztcp` 等 18 个内置命令 |
|
||||||
|
| 绕过攻击 | 防御 Zsh 的 `=curl` 等号展开(能绕过 curl 权限检查) |
|
||||||
|
| Unicode 攻击 | 检测零宽空格注入、不可见 Unicode 字符 |
|
||||||
|
| 环境变量 | 防御 IFS 空字节注入 |
|
||||||
|
| 混淆手法 | 花括号展开、注释/引号边界错位 |
|
||||||
|
| 审计发现 | HackerOne 报告的格式错误 token 绕过 |
|
||||||
|
|
||||||
|
每次触发都记录事件(`tengu_bash_security_check_triggered` + 检查编号),用于持续监控攻击模式。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 十二、250,000 次 API 调用的浪费——三行代码修好
|
||||||
|
|
||||||
|
源码注释里有一段让人目瞪口呆的记录:
|
||||||
|
|
||||||
|
> **2026-03-10:BQ 分析显示 1,279 个会话在单次会话中有 50+ 连续自动压缩失败(最高达 3,272 次),全球每日浪费约 250,000 次 API 调用。**
|
||||||
|
|
||||||
|
发生了什么?当上下文窗口接近极限时,Claude Code 会自动尝试压缩对话。但如果上下文已经太大,压缩也会失败。原来的代码没有失败上限,就**一直重试、一直失败、一直烧钱**。
|
||||||
|
|
||||||
|
修复方案:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const MAX_CONSECUTIVE_AUTOCOMPACT_FAILURES = 3
|
||||||
|
```
|
||||||
|
|
||||||
|
**三行代码,每天省 25 万次 API 调用。**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 十三、44 个特性开关:产品路线图全曝光
|
||||||
|
|
||||||
|
Claude Code 使用 Bun 的构建时特性开关系统。`feature('FLAG_NAME')` 在编译时被常量折叠——外部版本中,所有内部功能的代码直接**物理删除**,不是注释掉,是根本不存在于二进制中。
|
||||||
|
|
||||||
|
但源码里全都有。一共 **44 个特性开关**,部分列举:
|
||||||
|
|
||||||
|
| 开关 | 功能 | 状态 |
|
||||||
|
|------|------|------|
|
||||||
|
| `KAIROS` | 始终在线守护智能体 | 开发完成,未发布 |
|
||||||
|
| `VOICE_MODE` | 语音输入(Deepgram STT) | 开发完成,未发布 |
|
||||||
|
| `COORDINATOR_MODE` | 多智能体协调 | 已发布 |
|
||||||
|
| `BUDDY` | 虚拟宠物 | 愚人节限定 |
|
||||||
|
| `ANTI_DISTILLATION_CC` | 反蒸馏投毒 | 内部启用 |
|
||||||
|
| `DAEMON` | 后台守护进程 | 开发中 |
|
||||||
|
| `BRIDGE_MODE` | IDE 桥接 | 已发布 |
|
||||||
|
| `AGENT_TRIGGERS` | 智能体触发器 | 开发中 |
|
||||||
|
| `NATIVE_CLIENT_ATTESTATION` | 客户端证明 | 开发中 |
|
||||||
|
| `TORCH` / `ULTRAPLAN` | 未知 | 未知 |
|
||||||
|
|
||||||
|
**这基本上就是 Anthropic 未来半年的产品路线图。** 竞争对手(OpenAI Codex、Google Gemini CLI)现在知道 Anthropic 在做什么了。
|
||||||
|
|
||||||
|
源码可以被重构。但战略意外,无法被 DMCA 撤回。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 十四、社区的反应:2 小时 5 万星
|
||||||
|
|
||||||
|
泄漏发生后,GitHub 上迅速出现了多个镜像仓库。其中最火的是 `claw-code`——一个韩国开发者在凌晨 4 点被手机通知吵醒,**连夜用 Python 重写了 Claude Code 的核心架构**,然后推上了 GitHub。
|
||||||
|
|
||||||
|
> *"My girlfriend in Korea was genuinely worried I might face legal action from Anthropic just for having the code on my machine — so I did what any engineer would do under pressure: I sat down, ported the core features to Python from scratch, and pushed it before the sun came up."*
|
||||||
|
|
||||||
|
2 小时后,仓库星标突破 **5 万**——成为 GitHub 历史上达到 5 万星最快的仓库。
|
||||||
|
|
||||||
|
还有人用 Rust 重写了 `runtime` 层(6 个 crate,31 个 `.rs` 文件),声称性能提升了 3 倍。
|
||||||
|
|
||||||
|
Anthropic 很快发出了 DMCA 撤回通知,删除了原始镜像。但 Python 重写版因为是"clean-room rewrite"(洁净室重写),目前仍然在线。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 十五、这件事意味着什么?
|
||||||
|
|
||||||
|
### 对开发者
|
||||||
|
|
||||||
|
Claude Code 的架构中有大量值得学习的模式:
|
||||||
|
- **流式优先**:整个链路都是 `AsyncGenerator`
|
||||||
|
- **读写分离的工具调度**:简单但高效
|
||||||
|
- **prompt 编排多智能体**:用自然语言而非代码定义工作流
|
||||||
|
- **文件驱动的记忆系统**:简单可靠,不依赖外部服务
|
||||||
|
- **构建时死代码消除**:一套代码,两个版本
|
||||||
|
|
||||||
|
### 对行业
|
||||||
|
|
||||||
|
1. **AI 编程工具的复杂度远超想象**。51 万行代码、44 个特性开关、23 项安全检查——这不是一个周末 hackathon 能搞定的东西
|
||||||
|
2. **KAIROS 代表着方向**。AI 编程助手正在从"你问我答"走向"始终在线的 AI 同事"。Anthropic 已经把它做出来了,只是没发布
|
||||||
|
3. **开源 vs 闭源的边界越来越模糊**。Google 开源了 Gemini CLI,OpenAI 开源了 Codex agent SDK。但那些只是工具包。Claude Code 暴露的是**旗舰产品的完整内部实现**——这不一样
|
||||||
|
|
||||||
|
### 对 Anthropic
|
||||||
|
|
||||||
|
这是一周内的第二次意外泄露。对于一家以"AI 安全"为品牌核心的公司来说,连续的安全事故无疑让人尴尬。不过换个角度看——如果你的代码足够好,被看到也不是世界末日。
|
||||||
|
|
||||||
|
从源码质量来看,Claude Code 的工程水平确实很高。虽然 `print.ts` 有 5,594 行、单个函数 3,167 行、12 层嵌套这种"史诗级屎山",但整体架构思路清晰、安全意识到位、性能优化深入。
|
||||||
|
|
||||||
|
**51 万行代码,一次意外,全世界都看见了。**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
> 如果你觉得这篇文章有价值,欢迎转发给身边的开发者朋友。这可能是我们唯一一次机会,看到一个世界级 AI 编程智能体的完整内部实现。
|
||||||
|
>
|
||||||
|
> 关注"老邓唠AI",下一篇我们聊聊从 Claude Code 的架构中,普通开发者能学到哪些可以直接用的设计模式。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**参考资料:**
|
||||||
|
|
||||||
|
- [The Register: Anthropic accidentally exposes Claude Code source code](https://www.theregister.com/2026/03/31/anthropic_claude_code_source_code/)
|
||||||
|
- [DEV Community: Claude Code's Entire Source Code Was Just Leaked](https://dev.to/gabrielanhaia/claude-codes-entire-source-code-was-just-leaked-via-npm-source-maps-heres-whats-inside-cjo)
|
||||||
|
- [Alex Kim's Blog: The Claude Code Source Leak](https://alex000kim.com/posts/2026-03-31-claude-code-source-leak/)
|
||||||
|
- [Fortune: Anthropic leaks its own AI coding tool's source code](https://fortune.com/2026/03/31/anthropic-source-code-claude-code-data-leak-second-security-lapse-days-after-accidentally-revealing-mythos/)
|
||||||
|
- [VentureBeat: Claude Code's source code appears to have leaked](https://venturebeat.com/technology/claude-codes-source-code-appears-to-have-leaked-heres-what-we-know)
|
||||||
|
- [GitHub: claw-code (Python rewrite)](https://github.com/instructkr/claw-code)
|
||||||
796
articles/008/claude-arch-by-claude.md
Normal file
@ -0,0 +1,796 @@
|
|||||||
|
# Claude Code 源码泄漏深度架构分析
|
||||||
|
|
||||||
|
> 2026年3月31日,Anthropic 在 npm 发布 `@anthropic-ai/claude-code@2.1.88` 时,意外将一个 59.8MB 的 JavaScript Source Map 文件打包在内。这个 `.map` 文件指向了 Anthropic 自家 Cloudflare R2 存储桶上的完整 TypeScript 源码压缩包。安全研究员 Chaofan Shou 率先发现并公开了这个链接,数小时内,1,900 个 TypeScript 文件、512,664 行代码被完整镜像到了 GitHub 上。
|
||||||
|
>
|
||||||
|
> 本文将从架构层面,深入拆解这个"可能是当前最复杂的 AI 编程智能体"的内部实现。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 一、技术栈总览
|
||||||
|
|
||||||
|
| 维度 | 技术选型 |
|
||||||
|
|------|---------|
|
||||||
|
| 语言 | TypeScript(1,884 个 `.ts/.tsx` 文件) |
|
||||||
|
| 运行时 | Bun(非 Node.js) |
|
||||||
|
| 终端 UI | 自研 Ink 分支 + React + Yoga Layout |
|
||||||
|
| Schema 校验 | Zod v4 |
|
||||||
|
| API 通信 | Anthropic SDK + SSE 流式传输 |
|
||||||
|
| 构建系统 | Bun Bundler(`bun:bundle` 特性开关) |
|
||||||
|
| 实验平台 | GrowthBook(`tengu_*` 前缀) |
|
||||||
|
| 可观测性 | OpenTelemetry + Datadog + Perfetto |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 二、整体架构
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph TB
|
||||||
|
subgraph Entry["入口层"]
|
||||||
|
CLI["cli.tsx<br/>CLI 入口"]
|
||||||
|
MCP_ENTRY["mcp.ts<br/>MCP Server 入口"]
|
||||||
|
SDK["agentSdkTypes.ts<br/>SDK 入口"]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph Core["核心引擎"]
|
||||||
|
MAIN["main.tsx<br/>4,683 行<br/>REPL 编排器"]
|
||||||
|
QE["QueryEngine.ts<br/>1,295 行<br/>会话管理器"]
|
||||||
|
QUERY["query.ts<br/>1,729 行<br/>流式查询循环"]
|
||||||
|
API["claude.ts<br/>3,419 行<br/>Anthropic API 客户端"]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph Tools["工具系统"]
|
||||||
|
TOOL_DEF["Tool.ts<br/>792 行<br/>工具接口定义"]
|
||||||
|
TOOL_REG["tools.ts<br/>389 行<br/>工具注册表"]
|
||||||
|
TOOL_ORCH["toolOrchestration.ts<br/>并发调度"]
|
||||||
|
TOOL_EXEC["toolExecution.ts<br/>1,745 行<br/>执行引擎"]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph Agent["多智能体"]
|
||||||
|
COORD["coordinatorMode.ts<br/>协调器"]
|
||||||
|
AGENT_RUN["runAgent.ts<br/>973 行<br/>子智能体启动器"]
|
||||||
|
TASKS["tasks/<br/>任务状态机"]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph Infra["基础设施"]
|
||||||
|
PERM["permissions/<br/>24 个文件<br/>权限系统"]
|
||||||
|
MCP_CLIENT["mcp/client.ts<br/>3,348 行<br/>MCP 客户端"]
|
||||||
|
BRIDGE["bridge/<br/>27 个文件<br/>IDE 桥接"]
|
||||||
|
MEMDIR["memdir/<br/>9 个文件<br/>记忆系统"]
|
||||||
|
INK["ink/<br/>终端渲染引擎"]
|
||||||
|
end
|
||||||
|
|
||||||
|
CLI --> MAIN
|
||||||
|
MCP_ENTRY --> MAIN
|
||||||
|
SDK --> QE
|
||||||
|
|
||||||
|
MAIN --> QE
|
||||||
|
QE --> QUERY
|
||||||
|
QUERY --> API
|
||||||
|
QUERY --> TOOL_ORCH
|
||||||
|
|
||||||
|
TOOL_ORCH --> TOOL_EXEC
|
||||||
|
TOOL_EXEC --> TOOL_DEF
|
||||||
|
TOOL_REG --> TOOL_DEF
|
||||||
|
|
||||||
|
TOOL_EXEC --> AGENT_RUN
|
||||||
|
COORD --> AGENT_RUN
|
||||||
|
AGENT_RUN --> TASKS
|
||||||
|
AGENT_RUN --> QUERY
|
||||||
|
|
||||||
|
TOOL_EXEC --> PERM
|
||||||
|
MAIN --> MCP_CLIENT
|
||||||
|
MAIN --> BRIDGE
|
||||||
|
QE --> MEMDIR
|
||||||
|
MAIN --> INK
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 三、启动流程
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
sequenceDiagram
|
||||||
|
participant User as 用户终端
|
||||||
|
participant CLI as cli.tsx
|
||||||
|
participant Main as main.tsx
|
||||||
|
participant GB as GrowthBook
|
||||||
|
participant MCP as MCP Servers
|
||||||
|
participant REPL as REPL 循环
|
||||||
|
|
||||||
|
User->>CLI: claude 命令
|
||||||
|
CLI->>CLI: 快速路径检查<br/>(--version, --dump-system-prompt)
|
||||||
|
CLI->>Main: 动态 import main.tsx
|
||||||
|
|
||||||
|
par 并行初始化
|
||||||
|
Main->>GB: 加载特性开关
|
||||||
|
Main->>Main: 读取 settings / MDM / keychain
|
||||||
|
Main->>MCP: 连接 MCP 服务器
|
||||||
|
Main->>Main: 加载工具 & 命令
|
||||||
|
end
|
||||||
|
|
||||||
|
Main->>Main: 构建系统提示词
|
||||||
|
Main->>REPL: launchRepl()
|
||||||
|
REPL->>User: 就绪,等待输入
|
||||||
|
```
|
||||||
|
|
||||||
|
**关键设计**:`cli.tsx` 仅 302 行,通过动态 `import()` 延迟加载 `main.tsx`(4,683 行),确保 `--version` 等快速路径毫秒级响应。所有重量级依赖(MCP、GrowthBook、keychain)都通过并行初始化加载。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 四、核心查询循环
|
||||||
|
|
||||||
|
### 4.1 QueryEngine — 会话管理器
|
||||||
|
|
||||||
|
`QueryEngine` 是 SDK/headless 模式下的会话管理器,一个实例管理一次完整对话:
|
||||||
|
|
||||||
|
```
|
||||||
|
QueryEngine
|
||||||
|
├── mutableMessages: Message[] // 消息历史(随对话增长)
|
||||||
|
├── abortController: AbortController // 会话级中止控制
|
||||||
|
├── permissionDenials: SDKPermissionDenial[] // 权限拒绝记录
|
||||||
|
├── totalUsage: NonNullableUsage // Token 用量聚合
|
||||||
|
├── discoveredSkillNames: Set<string> // 每轮发现的技能
|
||||||
|
└── loadedNestedMemoryPaths: Set<string> // 已加载的 CLAUDE.md 路径
|
||||||
|
```
|
||||||
|
|
||||||
|
核心方法 `submitMessage()` 是一个 `AsyncGenerator<SDKMessage>`,每次调用经历:
|
||||||
|
|
||||||
|
1. 构建系统提示词(`fetchSystemPromptParts()`)
|
||||||
|
2. 处理斜杠命令(`processUserInput()`)
|
||||||
|
3. 持久化用户消息到 transcript
|
||||||
|
4. 进入流式查询循环(`query()`),yield 出 `SDKMessage`
|
||||||
|
5. 处理上下文压缩、权限、最大轮次限制
|
||||||
|
|
||||||
|
### 4.2 query.ts — 流式查询循环
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart TD
|
||||||
|
START["用户消息"] --> BUILD["构建查询配置"]
|
||||||
|
BUILD --> CALL["queryModelWithStreaming()<br/>调用 Anthropic API"]
|
||||||
|
CALL --> STREAM["流式接收响应"]
|
||||||
|
STREAM --> CHECK{是否有工具调用?}
|
||||||
|
|
||||||
|
CHECK -->|有| RUN_TOOLS["runTools()<br/>执行工具"]
|
||||||
|
RUN_TOOLS --> BUDGET["applyToolResultBudget()<br/>结果预算控制"]
|
||||||
|
BUDGET --> HOOKS["executePostSamplingHooks()"]
|
||||||
|
HOOKS --> COMPACT{"需要压缩?"}
|
||||||
|
COMPACT -->|是| AUTO_COMPACT["autoCompactIfNeeded()"]
|
||||||
|
AUTO_COMPACT --> CALL
|
||||||
|
COMPACT -->|否| CALL
|
||||||
|
|
||||||
|
CHECK -->|无| RECOVERY{max_output_tokens<br/>恢复?}
|
||||||
|
RECOVERY -->|是,≤3次| CALL
|
||||||
|
RECOVERY -->|否| STOP_HOOKS["handleStopHooks()"]
|
||||||
|
STOP_HOOKS --> END["返回结果"]
|
||||||
|
```
|
||||||
|
|
||||||
|
**关键机制**:
|
||||||
|
- **Output Recovery**:当模型因 `max_output_tokens` 截断时,自动重试最多 3 次
|
||||||
|
- **工具结果预算**:大结果持久化到磁盘,用文件路径 + 预览替代,防止上下文窗口膨胀
|
||||||
|
- **自动压缩**:接近上下文窗口限制时触发对话摘要压缩
|
||||||
|
- **依赖注入**:`QueryDeps` 接口注入 `callModel`、`microcompact`、`autocompact`、`uuid`,方便单元测试
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 五、工具系统
|
||||||
|
|
||||||
|
### 5.1 Tool 接口
|
||||||
|
|
||||||
|
`Tool<Input, Output, P>` 是一个功能丰富的接口,定义了工具的完整生命周期:
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
classDiagram
|
||||||
|
class Tool {
|
||||||
|
+name: string
|
||||||
|
+description(input, options): string
|
||||||
|
+inputSchema: ZodSchema
|
||||||
|
+call(args, context, canUseTool, parentMessage, onProgress?)
|
||||||
|
+checkPermissions(input, context): PermissionResult
|
||||||
|
+validateInput(input, context): ValidationResult
|
||||||
|
+isReadOnly(input): boolean
|
||||||
|
+isConcurrencySafe(input): boolean
|
||||||
|
+isDestructive(input): boolean
|
||||||
|
+maxResultSizeChars: number
|
||||||
|
+shouldDefer: boolean
|
||||||
|
+renderToolUseMessage(input, options): ReactNode
|
||||||
|
+renderToolResultMessage(...): ReactNode
|
||||||
|
+toAutoClassifierInput(input): string
|
||||||
|
}
|
||||||
|
|
||||||
|
class ToolUseContext {
|
||||||
|
+options: Options
|
||||||
|
+abortController: AbortController
|
||||||
|
+appState: AppState
|
||||||
|
+permissionContext: PermissionContext
|
||||||
|
+fileStateCache: FileStateCache
|
||||||
|
+sessionMetadata: SessionMetadata
|
||||||
|
}
|
||||||
|
|
||||||
|
Tool --> ToolUseContext : 接收
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5.2 完整工具清单
|
||||||
|
|
||||||
|
源码中注册了 **40+ 个工具**,按功能分类:
|
||||||
|
|
||||||
|
| 分类 | 工具名 | 说明 |
|
||||||
|
|------|--------|------|
|
||||||
|
| **文件操作** | FileReadTool, FileWriteTool, FileEditTool, GlobTool, GrepTool, NotebookEditTool | 文件读写、搜索、编辑 |
|
||||||
|
| **系统执行** | BashTool, PowerShellTool | Shell 命令执行 |
|
||||||
|
| **网络访问** | WebFetchTool, WebSearchTool | 网页抓取、搜索 |
|
||||||
|
| **智能体** | AgentTool, SendMessageTool, TeamCreateTool, TeamDeleteTool | 多智能体生成与协调 |
|
||||||
|
| **任务管理** | TaskCreateTool, TaskGetTool, TaskUpdateTool, TaskListTool, TaskStopTool, TaskOutputTool | 后台任务管理 |
|
||||||
|
| **规划模式** | EnterPlanModeTool, ExitPlanModeTool | 只读规划模式切换 |
|
||||||
|
| **Worktree** | EnterWorktreeTool, ExitWorktreeTool | Git Worktree 隔离 |
|
||||||
|
| **MCP** | MCPTool, ListMcpResourcesTool, ReadMcpResourceTool | MCP 协议交互 |
|
||||||
|
| **其他** | ToolSearchTool, SkillTool, AskUserQuestionTool, ConfigTool, BriefTool, LSPTool, TodoWriteTool | 工具搜索、技能、配置等 |
|
||||||
|
| **KAIROS 专属** | SleepTool, CronCreateTool, CronDeleteTool, CronListTool, MonitorTool, PushNotificationTool | 自主守护模式工具 |
|
||||||
|
|
||||||
|
### 5.3 工具执行调度
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart LR
|
||||||
|
subgraph Parallel["并发批次"]
|
||||||
|
direction TB
|
||||||
|
G1["GlobTool ✓"]
|
||||||
|
G2["GrepTool ✓"]
|
||||||
|
G3["FileReadTool ✓"]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph Serial["串行执行"]
|
||||||
|
direction TB
|
||||||
|
S1["FileEditTool"]
|
||||||
|
S2["BashTool"]
|
||||||
|
end
|
||||||
|
|
||||||
|
INPUT["工具调用列表"] --> PARTITION{"isConcurrencySafe?"}
|
||||||
|
PARTITION -->|true| Parallel
|
||||||
|
PARTITION -->|false| Serial
|
||||||
|
Parallel --> MERGE["合并结果"]
|
||||||
|
Serial --> MERGE
|
||||||
|
```
|
||||||
|
|
||||||
|
`toolOrchestration.ts` 将工具调用分为两类:
|
||||||
|
- **只读工具**(`isConcurrencySafe=true`):`GlobTool`、`GrepTool`、`FileReadTool` 等,最多 10 个并发执行
|
||||||
|
- **写入工具**(`isConcurrencySafe=false`):`FileEditTool`、`BashTool` 等,严格串行执行
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 六、权限系统
|
||||||
|
|
||||||
|
权限系统由 24 个文件组成,是 Claude Code 安全模型的核心。
|
||||||
|
|
||||||
|
### 6.1 权限模式
|
||||||
|
|
||||||
|
| 模式 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| `default` | 每次新操作提示用户确认 |
|
||||||
|
| `plan` | 只读规划模式,禁止写操作 |
|
||||||
|
| `acceptEdits` | 自动接受文件编辑 |
|
||||||
|
| `bypassPermissions` | 绕过所有权限检查 |
|
||||||
|
| `dontAsk` | 从不询问(自动拒绝未允许的操作) |
|
||||||
|
| `auto` | AI 驱动的自动审批(Anthropic 内部专用) |
|
||||||
|
|
||||||
|
### 6.2 权限决策流程
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart TD
|
||||||
|
REQ["工具调用请求"] --> DENY{"在 alwaysDeny 规则中?"}
|
||||||
|
DENY -->|是| BLOCKED["❌ 拒绝"]
|
||||||
|
DENY -->|否| ALLOW{"在 alwaysAllow 规则中?"}
|
||||||
|
ALLOW -->|是| PASS["✅ 允许"]
|
||||||
|
ALLOW -->|否| TOOL_CHECK{"工具自身<br/>checkPermissions()"}
|
||||||
|
TOOL_CHECK -->|拒绝| BLOCKED
|
||||||
|
TOOL_CHECK -->|允许| CLASSIFIER{"AI 分类器<br/>(auto 模式)"}
|
||||||
|
CLASSIFIER -->|安全| PASS
|
||||||
|
CLASSIFIER -->|危险| DIALOG{"shouldAvoidPermissionPrompts?"}
|
||||||
|
DIALOG -->|是| BLOCKED
|
||||||
|
DIALOG -->|否| USER["🔔 提示用户确认"]
|
||||||
|
USER -->|允许| PASS
|
||||||
|
USER -->|拒绝| BLOCKED
|
||||||
|
```
|
||||||
|
|
||||||
|
权限规则支持 glob 模式匹配,例如 `Bash(git *)` 允许所有 `git` 开头的 bash 命令。`denialTracking.ts` 追踪连续拒绝次数,超过阈值后触发降级到手动确认模式。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 七、多智能体架构
|
||||||
|
|
||||||
|
### 7.1 协调器模式
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph TB
|
||||||
|
subgraph Coordinator["协调器 (Coordinator)"]
|
||||||
|
C["协调器智能体<br/>全局视角 + 任务分配"]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph Workers["工作智能体 (Workers)"]
|
||||||
|
W1["Worker 1<br/>文件探索"]
|
||||||
|
W2["Worker 2<br/>代码修改"]
|
||||||
|
W3["Worker 3<br/>测试验证"]
|
||||||
|
end
|
||||||
|
|
||||||
|
C -->|"AgentTool<br/>生成"| W1
|
||||||
|
C -->|"AgentTool<br/>生成"| W2
|
||||||
|
C -->|"SendMessageTool<br/>追加指令"| W1
|
||||||
|
W1 -->|"task-notification<br/>XML 回报"| C
|
||||||
|
W2 -->|"task-notification<br/>XML 回报"| C
|
||||||
|
C -->|"AgentTool<br/>生成"| W3
|
||||||
|
W3 -->|"task-notification<br/>XML 回报"| C
|
||||||
|
C -->|"TaskStopTool<br/>终止"| W1
|
||||||
|
```
|
||||||
|
|
||||||
|
协调器系统提示词(300+ 行)定义了 **四阶段工作流**:
|
||||||
|
|
||||||
|
1. **Research** — 探索代码库,理解上下文
|
||||||
|
2. **Synthesis** — 综合发现,制定方案
|
||||||
|
3. **Implementation** — 并行执行代码修改
|
||||||
|
4. **Verification** — 验证结果,运行测试
|
||||||
|
|
||||||
|
关键原则写在 prompt 里而非代码里:
|
||||||
|
- *"Do not rubber-stamp weak work"*(不要草率通过低质量工作)
|
||||||
|
- *"You must understand findings before directing follow-up work"*(在指导后续工作前必须理解发现)
|
||||||
|
|
||||||
|
### 7.2 子智能体启动流程
|
||||||
|
|
||||||
|
`runAgent.ts`(973 行)是子智能体的核心启动器:
|
||||||
|
|
||||||
|
1. 生成唯一 `AgentId`
|
||||||
|
2. 创建独立的 `FileStateCache`
|
||||||
|
3. 通过 `createSubagentContext()` fork 父级的 `ToolUseContext`
|
||||||
|
4. 初始化智能体专属 MCP 服务器(来自 frontmatter)
|
||||||
|
5. 运行独立的 `query()` 流式循环
|
||||||
|
6. 注册 Perfetto tracing(性能追踪)
|
||||||
|
7. 写入智能体元数据和 sidechain transcript
|
||||||
|
|
||||||
|
### 7.3 任务类型
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
classDiagram
|
||||||
|
class TaskType {
|
||||||
|
<<enumeration>>
|
||||||
|
local_bash
|
||||||
|
local_agent
|
||||||
|
remote_agent
|
||||||
|
in_process_teammate
|
||||||
|
local_workflow
|
||||||
|
monitor_mcp
|
||||||
|
dream
|
||||||
|
}
|
||||||
|
|
||||||
|
class TaskStatus {
|
||||||
|
<<enumeration>>
|
||||||
|
pending
|
||||||
|
running
|
||||||
|
completed
|
||||||
|
failed
|
||||||
|
killed
|
||||||
|
}
|
||||||
|
|
||||||
|
class LocalAgentTask
|
||||||
|
class InProcessTeammateTask
|
||||||
|
class RemoteAgentTask
|
||||||
|
class LocalShellTask
|
||||||
|
class DreamTask
|
||||||
|
|
||||||
|
TaskType <-- LocalAgentTask
|
||||||
|
TaskType <-- InProcessTeammateTask
|
||||||
|
TaskType <-- RemoteAgentTask
|
||||||
|
TaskType <-- LocalShellTask
|
||||||
|
TaskType <-- DreamTask
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 八、MCP(Model Context Protocol)集成
|
||||||
|
|
||||||
|
Claude Code 既是 MCP **客户端**(连接外部 MCP 服务器),也可以作为 MCP **服务器**运行。
|
||||||
|
|
||||||
|
### 8.1 支持的传输类型
|
||||||
|
|
||||||
|
| 传输方式 | 配置类型 | 说明 |
|
||||||
|
|----------|---------|------|
|
||||||
|
| `stdio` | `McpStdioServerConfig` | 标准进程通信 |
|
||||||
|
| `sse` | `McpSSEServerConfig` | Server-Sent Events |
|
||||||
|
| `sse-ide` | — | IDE 专用 SSE |
|
||||||
|
| `http` | `McpHTTPServerConfig` | HTTP 直连 |
|
||||||
|
| `ws` | `McpWebSocketServerConfig` | WebSocket |
|
||||||
|
| `sdk` | `McpSdkServerConfig` | SDK 内嵌 |
|
||||||
|
|
||||||
|
### 8.2 MCP 连接状态机
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
stateDiagram-v2
|
||||||
|
[*] --> Pending: 初始化
|
||||||
|
Pending --> Connected: 连接成功
|
||||||
|
Pending --> Failed: 连接失败
|
||||||
|
Pending --> NeedsAuth: 需要认证
|
||||||
|
NeedsAuth --> Connected: OAuth 完成
|
||||||
|
Connected --> Failed: 断开连接
|
||||||
|
Connected --> Disabled: 用户禁用
|
||||||
|
Failed --> Pending: 重连
|
||||||
|
```
|
||||||
|
|
||||||
|
`mcp/client.ts`(3,348 行)是最大的 MCP 相关文件,负责连接管理、工具发现、资源预取和认证流程(支持 OAuth 和 XAA 跨应用访问)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 九、记忆系统
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph LR
|
||||||
|
MEMORY_MD["MEMORY.md<br/>记忆索引<br/>(≤200 行 / 25KB)"] --> NOTE1["user_role.md"]
|
||||||
|
MEMORY_MD --> NOTE2["feedback_testing.md"]
|
||||||
|
MEMORY_MD --> NOTE3["project_auth.md"]
|
||||||
|
|
||||||
|
SYSTEM_PROMPT["系统提示词"] --> MEMORY_MD
|
||||||
|
SYSTEM_PROMPT --> TYPES["记忆类型指令"]
|
||||||
|
SYSTEM_PROMPT --> RULES["存取规则"]
|
||||||
|
|
||||||
|
NOTE1 --> SEMANTIC["语义搜索<br/>findRelevantMemories()"]
|
||||||
|
NOTE2 --> SEMANTIC
|
||||||
|
NOTE3 --> SEMANTIC
|
||||||
|
SEMANTIC --> INJECT["注入上下文"]
|
||||||
|
```
|
||||||
|
|
||||||
|
记忆系统(`memdir/`,9 个文件)采用**文件驱动**的设计:
|
||||||
|
|
||||||
|
- `MEMORY.md` 作为入口索引文件,限制 200 行 / 25KB,注入到系统提示词中
|
||||||
|
- 每条记忆是独立的 Markdown 文件,带有 frontmatter(name、description、type)
|
||||||
|
- 支持语义搜索(`findRelevantMemories()`)
|
||||||
|
- 记忆老化/淘汰机制(`memoryAge.ts`)
|
||||||
|
- 团队共享记忆支持(`teamMemPaths.ts`,TEAMMEM 特性开关后)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 十、终端渲染引擎
|
||||||
|
|
||||||
|
Claude Code 使用**自研的 Ink 分支**(非 npm 上的 Ink 库),基于 React + Yoga Layout 实现终端 UI。
|
||||||
|
|
||||||
|
```
|
||||||
|
ink/
|
||||||
|
├── root.ts — render() / createRoot() 入口
|
||||||
|
├── dom.ts — 虚拟 DOM 实现
|
||||||
|
├── frame.ts — 渲染帧管理,防闪烁
|
||||||
|
├── focus.ts — 键盘焦点管理
|
||||||
|
├── components/
|
||||||
|
│ ├── App.tsx — 根组件
|
||||||
|
│ ├── Box.tsx — 布局容器
|
||||||
|
│ ├── Text.tsx — 文本组件
|
||||||
|
│ ├── ScrollBox.tsx — 滚动区域
|
||||||
|
│ └── AlternateScreen.tsx — 全屏覆盖
|
||||||
|
├── events/ — 自定义事件系统
|
||||||
|
├── hooks/ — use-input, use-app, use-animation-frame 等
|
||||||
|
├── termio/ — 原始终端 I/O
|
||||||
|
└── Ansi.tsx — ANSI 转义码渲染组件
|
||||||
|
```
|
||||||
|
|
||||||
|
据泄漏分析文章指出,其终端渲染使用了 `Int32Array` 支持的 ASCII 字符池和位掩码编码的样式元数据,声称"在 token 流式传输期间将 `stringWidth` 调用减少约 50 倍"。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 十一、系统提示词构建
|
||||||
|
|
||||||
|
系统提示词是分段动态组装的,带有缓存边界标记:
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph TB
|
||||||
|
subgraph Static["静态段(全局可缓存 scope='global')"]
|
||||||
|
INTRO["getSimpleIntroSection()<br/>智能体身份 + 安全指令"]
|
||||||
|
SYSTEM["getSimpleSystemSection()<br/>工具使用 + 权限模式"]
|
||||||
|
TASKS_SEC["getSimpleDoingTasksSection()<br/>软件工程行为规范"]
|
||||||
|
ACTIONS["getActionsSection()<br/>操作可逆性策略"]
|
||||||
|
TOOL_GUIDE["getUsingYourToolsSection()<br/>工具使用指南"]
|
||||||
|
end
|
||||||
|
|
||||||
|
BOUNDARY["═══ SYSTEM_PROMPT_DYNAMIC_BOUNDARY ═══"]
|
||||||
|
|
||||||
|
subgraph Dynamic["动态段(用户/会话级,不跨组织缓存)"]
|
||||||
|
HOOKS_SEC["getHooksSection()<br/>用户钩子指令"]
|
||||||
|
UNDERCOVER["Undercover 指令<br/>(ant-only)"]
|
||||||
|
MEMORY["loadMemoryPrompt()<br/>记忆内容"]
|
||||||
|
LANG["语言偏好"]
|
||||||
|
CONTEXT["getUserContext()<br/>Git 状态 / CLAUDE.md / 平台信息"]
|
||||||
|
MCP_INST["MCP 指令"]
|
||||||
|
end
|
||||||
|
|
||||||
|
Static --> BOUNDARY
|
||||||
|
BOUNDARY --> Dynamic
|
||||||
|
```
|
||||||
|
|
||||||
|
这种设计让静态段可以跨会话缓存(通过 Anthropic API 的 `cache_control` 参数),而动态段每次重新构建。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 十二、隐藏特性与彩蛋
|
||||||
|
|
||||||
|
### 12.1 反蒸馏机制(Anti-Distillation)
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// services/api/claude.ts (301-313)
|
||||||
|
if (
|
||||||
|
feature('ANTI_DISTILLATION_CC')
|
||||||
|
? process.env.CLAUDE_CODE_ENTRYPOINT === 'cli' &&
|
||||||
|
shouldIncludeFirstPartyOnlyBetas() &&
|
||||||
|
getFeatureValue_CACHED_MAY_BE_STALE(
|
||||||
|
'tengu_anti_distill_fake_tool_injection', false)
|
||||||
|
: false
|
||||||
|
) {
|
||||||
|
result.anti_distillation = ['fake_tools']
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
当启用时,向 API 请求注入 `anti_distillation: ['fake_tools']`,服务端会在工具调用中混入虚假工具响应。目的:如果竞争对手录制 Claude Code 的 API 流量来训练模型,虚假工具数据会污染训练集。
|
||||||
|
|
||||||
|
**绕过分析**:MITM 代理可在请求到达 API 前剥离该字段;设置 `CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS` 环境变量可禁用;第三方 SDK 入口完全绕过。正如分析者所言:"真正的保护可能是法律而非技术"。
|
||||||
|
|
||||||
|
### 12.2 伪装模式(Undercover Mode)
|
||||||
|
|
||||||
|
`utils/undercover.ts` — Anthropic 内部员工在外部开源仓库工作时自动启用:
|
||||||
|
|
||||||
|
- 禁止提及内部代码名(Capybara、Tengu 等)
|
||||||
|
- 隐藏内部 Slack 频道和仓库名称
|
||||||
|
- 删除所有 "Co-Authored-By" 标识
|
||||||
|
- 不暴露未发布的模型版本号
|
||||||
|
|
||||||
|
**关键限制**:**没有强制关闭开关**。注释明确写道:*"There is NO force-OFF. This guards against model codename leaks."* 这是一扇单向门。
|
||||||
|
|
||||||
|
### 12.3 挫折感检测
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// utils/userPromptKeywords.ts
|
||||||
|
const negativePattern =
|
||||||
|
/\b(wtf|wth|ffs|omfg|shit(ty|tiest)?|dumbass|horrible|awful|
|
||||||
|
piss(ed|ing)? off|piece of (shit|crap|junk)|what the (fuck|hell)|
|
||||||
|
fucking? (broken|useless|terrible|awful|horrible)|fuck you|
|
||||||
|
screw (this|you)|so frustrating|this sucks|damn it)\b/
|
||||||
|
```
|
||||||
|
|
||||||
|
仅在 Anthropic 内部版本中启用(外部构建通过死代码消除移除)。当检测到用户情绪消极时,弹出 transcript 分享提示,方便内部员工快速提交反馈。选用正则而非 LLM 的原因:比模型推理调用更快更便宜。
|
||||||
|
|
||||||
|
### 12.4 KAIROS — 自主守护智能体
|
||||||
|
|
||||||
|
**KAIROS**(古希腊语"恰当的时机")是一个被提及 150+ 次的特性开关,代表着一个全新的交互范式——**始终在线的后台智能体**。
|
||||||
|
|
||||||
|
核心能力:
|
||||||
|
- `/dream` 技能 — "夜间记忆蒸馏"
|
||||||
|
- `autoDream` 守护进程 — 用户空闲时自动进行记忆整合
|
||||||
|
- GitHub webhook 订阅 — 监听仓库事件
|
||||||
|
- Cron 定时任务 — 每 5 分钟计划刷新
|
||||||
|
- 推送通知 — 主动通知用户
|
||||||
|
|
||||||
|
**autoDream 触发条件**:
|
||||||
|
1. 距离上次整合 ≥ 24 小时
|
||||||
|
2. 至少 5 个新会话
|
||||||
|
3. 进程锁(同一时间只有一个进程执行整合)
|
||||||
|
|
||||||
|
### 12.5 Buddy 伴侣系统(愚人节彩蛋)
|
||||||
|
|
||||||
|
```
|
||||||
|
buddy/
|
||||||
|
├── companion.ts — Mulberry32 PRNG 确定性生成
|
||||||
|
├── types.ts — 物种、稀有度、属性定义
|
||||||
|
├── CompanionSprite.tsx — 500ms 刷新的终端动画精灵
|
||||||
|
├── sprites.ts — ASCII 艺术帧
|
||||||
|
├── prompt.ts — 系统提示词注入
|
||||||
|
└── useBuddyNotification.tsx — 预告逻辑
|
||||||
|
```
|
||||||
|
|
||||||
|
一个 Tamagotchi 风格的虚拟宠物系统:
|
||||||
|
|
||||||
|
- **18 种物种**:鸭子、鹅、blob、猫、龙、章鱼、猫头鹰、企鹅、海龟、蜗牛、幽灵、美西螈、水豚、仙人掌、机器人、兔子、蘑菇、胖墩。物种名用十六进制字符数组编码,避免触发内部代码名扫描器
|
||||||
|
- **稀有度**:普通(60%)、非凡(25%)、稀有(10%)、史诗(4%)、传说(1%)
|
||||||
|
- **RPG 属性**:DEBUGGING、PATIENCE、CHAOS、WISDOM、SNARK
|
||||||
|
- **防篡改**:骨骼数据(物种、稀有度、闪光)从 `hash(userId)` 确定性生成,不存储在配置中,无法伪造传说级
|
||||||
|
- **活跃窗口**:2026 年 4 月 1-7 日(跨时区滚动上线)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 十三、Bash 安全检查
|
||||||
|
|
||||||
|
`tools/BashTool/bashSecurity.ts` 实现了 **23 项编号安全检查**:
|
||||||
|
|
||||||
|
| 检查项 | 防御内容 |
|
||||||
|
|--------|---------|
|
||||||
|
| 命令替换 | `$()`、`${}`、进程替换 `<()`、`>()` |
|
||||||
|
| Zsh 危险内置 | `zmodload`、`emulate`、`sysopen`、`ztcp`、`zsocket`、`zf_rm` 等 18 个 |
|
||||||
|
| Zsh 等号展开 | `=curl` 绕过 curl 权限检查 |
|
||||||
|
| Unicode 攻击 | 零宽空格注入、Unicode 空白字符 |
|
||||||
|
| IFS 注入 | 空字节 IFS 注入 |
|
||||||
|
| Shell 元字符 | 混淆标志、花括号展开、中间单词哈希 |
|
||||||
|
| 控制字符 | 不可见控制字符注入 |
|
||||||
|
| 注释/引号错位 | 注释与引号边界不对齐攻击 |
|
||||||
|
| PowerShell | PowerShell 语法检测 |
|
||||||
|
| HackerOne 发现 | 格式错误 token 绕过(安全审计中发现) |
|
||||||
|
|
||||||
|
每次触发的检查都会记录 `tengu_bash_security_check_triggered` 事件(带数字 ID),用于安全监控和统计。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 十四、Prompt 缓存经济学
|
||||||
|
|
||||||
|
`services/api/promptCacheBreakDetection.ts` 追踪 **12+ 个缓存破坏维度**:
|
||||||
|
|
||||||
|
```
|
||||||
|
系统提示词哈希 | 工具 Schema 哈希 | cache_control 哈希
|
||||||
|
单工具 Schema 变更 | 模型切换 | 快速模式
|
||||||
|
全局缓存策略 | Beta 头部 | effort 值
|
||||||
|
Auto 模式状态 | 超限状态 | 微压缩状态
|
||||||
|
```
|
||||||
|
|
||||||
|
当检测到缓存破坏(>5% 缓存读取 token 下降 且 >2,000 绝对 token 下降)时:
|
||||||
|
- 触发 `tengu_prompt_cache_break` 分析事件
|
||||||
|
- 写入 diff 文件到 `~/.claude/tmp/cache-break-*.diff`
|
||||||
|
- 区分服务端破坏 vs TTL 过期
|
||||||
|
|
||||||
|
正如源码注释所言:*"在按 token 付费时,缓存失效不再是计算机科学笑话,而是会计问题。"*
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 十五、自动压缩与 250K API 调用浪费
|
||||||
|
|
||||||
|
`services/compact/autoCompact.ts` 中有一段引人注目的注释:
|
||||||
|
|
||||||
|
> 2026-03-10:BQ 分析显示 1,279 个会话在单次会话中有 50+ 连续自动压缩失败(最高达 3,272 次),全球每日浪费约 250,000 次 API 调用。
|
||||||
|
|
||||||
|
修复方案:**三行代码**。
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const MAX_CONSECUTIVE_AUTOCOMPACT_FAILURES = 3
|
||||||
|
```
|
||||||
|
|
||||||
|
添加一个断路器,连续失败 3 次后停止重试。
|
||||||
|
|
||||||
|
自动压缩参数:
|
||||||
|
- 缓冲区:13,000 tokens(`AUTOCOMPACT_BUFFER_TOKENS`)
|
||||||
|
- 警告阈值:上下文窗口 - 20,000 tokens
|
||||||
|
- 摘要输出预留:20,000 tokens(基于 p99.99 实际摘要为 17,387 tokens)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 十六、IDE 桥接(Bridge)
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph LR
|
||||||
|
subgraph IDE["IDE 端"]
|
||||||
|
VSCODE["VS Code 扩展"]
|
||||||
|
JETBRAINS["JetBrains 插件"]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph Bridge["桥接层 (27 个文件)"]
|
||||||
|
BRIDGE_MAIN["bridgeMain.ts<br/>2,999 行<br/>CCR WebSocket 服务器"]
|
||||||
|
REPL_BRIDGE["replBridge.ts<br/>2,406 行<br/>REPL 远程模式"]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph Cloud["claude.ai"]
|
||||||
|
CCR["Claude Code Remote"]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph Local["本地 CLI"]
|
||||||
|
CLAUDE["claude 进程"]
|
||||||
|
end
|
||||||
|
|
||||||
|
VSCODE <-->|JWT 认证| BRIDGE_MAIN
|
||||||
|
JETBRAINS <-->|JWT 认证| BRIDGE_MAIN
|
||||||
|
BRIDGE_MAIN <-->|WebSocket| CCR
|
||||||
|
REPL_BRIDGE <-->|WebSocket| CCR
|
||||||
|
BRIDGE_MAIN --> CLAUDE
|
||||||
|
REPL_BRIDGE --> CLAUDE
|
||||||
|
```
|
||||||
|
|
||||||
|
桥接系统支持:
|
||||||
|
- WebSocket 双向通信
|
||||||
|
- JWT 认证 + Token 刷新调度
|
||||||
|
- 指数退避重连
|
||||||
|
- 可信设备 Token 管理
|
||||||
|
- 容量感知唤醒(`capacityWake.ts`)
|
||||||
|
- 消息流控门(`flushGate.ts`)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 十七、构建时特性开关系统
|
||||||
|
|
||||||
|
Claude Code 最精妙的设计之一是其构建时特性开关系统:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// 使用 bun:bundle 的 feature() 函数
|
||||||
|
if (feature('KAIROS')) {
|
||||||
|
// 此代码在外部构建中被完整删除
|
||||||
|
loadKairosModule()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用户类型检查也会被常量折叠
|
||||||
|
if ("external" === 'ant') {
|
||||||
|
// 外部构建:编译为 if (false) → 死代码消除
|
||||||
|
loadInternalOnlyFeature()
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**已知特性开关**(44 个,部分列表):
|
||||||
|
|
||||||
|
| 开关名 | 功能 |
|
||||||
|
|--------|------|
|
||||||
|
| `KAIROS` / `PROACTIVE` | 自主守护智能体 |
|
||||||
|
| `ANTI_DISTILLATION_CC` | 反蒸馏保护 |
|
||||||
|
| `COORDINATOR_MODE` | 多智能体协调 |
|
||||||
|
| `BRIDGE_MODE` | IDE 桥接 |
|
||||||
|
| `DAEMON` | 后台守护进程 |
|
||||||
|
| `VOICE_MODE` | 语音输入 |
|
||||||
|
| `BUDDY` | 伴侣系统 |
|
||||||
|
| `HISTORY_SNIP` | 历史裁剪 |
|
||||||
|
| `WORKFLOW_SCRIPTS` | 工作流脚本 |
|
||||||
|
| `AGENT_TRIGGERS` | 智能体触发器 |
|
||||||
|
| `FORK_SUBAGENT` | 分叉子智能体 |
|
||||||
|
| `REACTIVE_COMPACT` | 响应式压缩 |
|
||||||
|
| `CONTEXT_COLLAPSE` | 上下文折叠 |
|
||||||
|
| `TRANSCRIPT_CLASSIFIER` | 转录分类器 |
|
||||||
|
| `NATIVE_CLIENT_ATTESTATION` | 原生客户端证明 |
|
||||||
|
| `TEMPLATES` | 模板系统 |
|
||||||
|
| `TORCH` / `ULTRAPLAN` / `UDS_INBOX` | 未知内部功能 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 十八、语音输入
|
||||||
|
|
||||||
|
`hooks/useVoice.ts` 实现了**按住说话**的语音输入:
|
||||||
|
|
||||||
|
- 使用 Anthropic 的 `voice_stream` STT 端点(Deepgram 后端)
|
||||||
|
- macOS 原生音频或 SoX 录制
|
||||||
|
- WebSocket 连接到 `conversation_engine` 端点
|
||||||
|
- 支持多语言(BCP-47 编码,从系统 locale 自动检测)
|
||||||
|
- "Keyterms" 注入提升识别准确度
|
||||||
|
- 5 次快速按键激活阈值(防止正常打字误触发)
|
||||||
|
- 通过 `VOICE_MODE` 构建开关完整移除
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 十九、关键架构模式总结
|
||||||
|
|
||||||
|
### 19.1 流式优先(Streaming-First)
|
||||||
|
|
||||||
|
从 `submitMessage()` 到 `query()` 到 `queryModelWithStreaming()`,整个链路都是 `AsyncGenerator<SDKMessage>`。工具执行期间通过 `onProgress` 回调发出进度消息。
|
||||||
|
|
||||||
|
### 19.2 依赖注入测试
|
||||||
|
|
||||||
|
`QueryDeps` 接口注入 `callModel`、`microcompact`、`autocompact`、`uuid`,避免测试中使用 `spyOn`。
|
||||||
|
|
||||||
|
### 19.3 上下文穿透
|
||||||
|
|
||||||
|
`ToolUseContext` 是贯穿整个工具执行链路的"胖上下文"对象。子智能体通过 `createSubagentContext()` 获得 fork 的副本。
|
||||||
|
|
||||||
|
### 19.4 双层特性门控
|
||||||
|
|
||||||
|
- **构建时**:`feature()` 从 `bun:bundle` 常量折叠,死代码消除
|
||||||
|
- **运行时**:GrowthBook 远程开关(`tengu_*`),支持灰度发布和 A/B 测试
|
||||||
|
|
||||||
|
### 19.5 分叉子智能体
|
||||||
|
|
||||||
|
后台任务(autoDream、压缩、会话记忆、推测执行)都通过 `runForkedAgent()` 运行——隔离的子智能体,有自己的查询来源,防止递归并共享父级的缓存安全参数。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 二十、代码质量观察
|
||||||
|
|
||||||
|
| 指标 | 数据 |
|
||||||
|
|------|------|
|
||||||
|
| 总代码量 | 512,664 行 TypeScript |
|
||||||
|
| 文件数 | 1,884 个 `.ts/.tsx` |
|
||||||
|
| 最大文件 | `cli/print.ts`(5,594 行,单函数 3,167 行,12 层嵌套) |
|
||||||
|
| 第二大文件 | `main.tsx`(4,683 行) |
|
||||||
|
| API 客户端 | `claude.ts`(3,419 行) |
|
||||||
|
| MCP 客户端 | `mcp/client.ts`(3,348 行) |
|
||||||
|
| 桥接主模块 | `bridgeMain.ts`(2,999 行) |
|
||||||
|
|
||||||
|
一些值得注意的代码风格:
|
||||||
|
- 偏好单文件大函数而非过度抽象(`print.ts` 是极端案例)
|
||||||
|
- 大量使用 `feature()` 门控保持外部构建精简
|
||||||
|
- 独创的 analytics 安全类型:`AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS`——防止开发者意外将文件路径或代码片段发送到分析系统
|
||||||
|
- `tengu_` 前缀统一所有实验名和事件名(Tengu 是内部代号,讽刺的是在 Undercover Mode 的注释中被列为"不应暴露的代码名"示例)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 结语
|
||||||
|
|
||||||
|
Claude Code 的 512,664 行源码揭示了一个工程复杂度远超预期的系统。它不仅仅是一个"LLM 套壳"——从自研终端渲染引擎到 23 项 Bash 安全检查,从多智能体协调到 prompt 缓存经济学,每一个模块都体现了在真实生产环境中打磨 AI 编程工具的深度工程投入。
|
||||||
|
|
||||||
|
最具战略意义的发现不是源码本身(它可以被重构),而是那 44 个特性开关背后的产品路线图:KAIROS 自主守护智能体、语音输入、团队协作记忆……这些代表着 Anthropic 对 AI 编程工具未来形态的判断。而这种战略意外,无法被 DMCA 撤回。
|
||||||
491
articles/008/cover.html
Normal file
@ -0,0 +1,491 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<style>
|
||||||
|
@import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;700&family=Noto+Sans+SC:wght@900&display=swap');
|
||||||
|
|
||||||
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||||
|
|
||||||
|
body {
|
||||||
|
width: 900px;
|
||||||
|
height: 383px;
|
||||||
|
overflow: hidden;
|
||||||
|
background: #0a0a0f;
|
||||||
|
font-family: 'Noto Sans SC', sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.canvas {
|
||||||
|
position: relative;
|
||||||
|
width: 900px;
|
||||||
|
height: 383px;
|
||||||
|
overflow: hidden;
|
||||||
|
background:
|
||||||
|
radial-gradient(ellipse 80% 60% at 75% 50%, rgba(220, 80, 40, 0.12) 0%, transparent 70%),
|
||||||
|
radial-gradient(ellipse 50% 80% at 20% 80%, rgba(40, 80, 220, 0.08) 0%, transparent 60%),
|
||||||
|
linear-gradient(160deg, #0a0a12 0%, #0d0d18 40%, #0a0f1a 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Scrolling code background */
|
||||||
|
.code-rain {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
opacity: 0.12;
|
||||||
|
font-family: 'JetBrains Mono', monospace;
|
||||||
|
font-size: 11px;
|
||||||
|
line-height: 1.6;
|
||||||
|
color: #7faaff;
|
||||||
|
overflow: hidden;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.code-col {
|
||||||
|
position: absolute;
|
||||||
|
top: -20px;
|
||||||
|
white-space: pre;
|
||||||
|
animation: codeScroll 20s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes codeScroll {
|
||||||
|
from { transform: translateY(-50%); }
|
||||||
|
to { transform: translateY(0); }
|
||||||
|
}
|
||||||
|
|
||||||
|
.code-col:nth-child(1) { left: 2%; animation-duration: 18s; color: #5a7fbb; }
|
||||||
|
.code-col:nth-child(2) { left: 14%; animation-duration: 22s; animation-delay: -3s; color: #6b8fcc; }
|
||||||
|
.code-col:nth-child(3) { left: 26%; animation-duration: 16s; animation-delay: -7s; }
|
||||||
|
.code-col:nth-child(4) { left: 54%; animation-duration: 25s; animation-delay: -2s; color: #5a7fbb; }
|
||||||
|
.code-col:nth-child(5) { left: 66%; animation-duration: 19s; animation-delay: -5s; }
|
||||||
|
.code-col:nth-child(6) { left: 78%; animation-duration: 21s; animation-delay: -9s; color: #6b8fcc; }
|
||||||
|
.code-col:nth-child(7) { left: 88%; animation-duration: 17s; animation-delay: -4s; }
|
||||||
|
|
||||||
|
/* Glitch scan line */
|
||||||
|
.scanline {
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 2px;
|
||||||
|
background: linear-gradient(90deg, transparent, rgba(220, 80, 40, 0.4), rgba(255, 120, 60, 0.6), rgba(220, 80, 40, 0.4), transparent);
|
||||||
|
animation: scan 3s ease-in-out infinite;
|
||||||
|
z-index: 2;
|
||||||
|
box-shadow: 0 0 20px rgba(220, 80, 40, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes scan {
|
||||||
|
0%, 100% { top: -2px; opacity: 0; }
|
||||||
|
10% { opacity: 1; }
|
||||||
|
90% { opacity: 1; }
|
||||||
|
100% { top: 383px; opacity: 0; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Grid overlay */
|
||||||
|
.grid-overlay {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
background-image:
|
||||||
|
linear-gradient(rgba(100, 150, 255, 0.03) 1px, transparent 1px),
|
||||||
|
linear-gradient(90deg, rgba(100, 150, 255, 0.03) 1px, transparent 1px);
|
||||||
|
background-size: 40px 40px;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Main content */
|
||||||
|
.content {
|
||||||
|
position: relative;
|
||||||
|
z-index: 10;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
padding: 36px 48px;
|
||||||
|
gap: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.left {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Leak badge */
|
||||||
|
.badge {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
background: rgba(220, 50, 30, 0.15);
|
||||||
|
border: 1px solid rgba(220, 50, 30, 0.5);
|
||||||
|
color: #ff6b4a;
|
||||||
|
font-family: 'JetBrains Mono', monospace;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 700;
|
||||||
|
padding: 4px 12px;
|
||||||
|
border-radius: 4px;
|
||||||
|
letter-spacing: 2px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
width: fit-content;
|
||||||
|
animation: badgePulse 2s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge::before {
|
||||||
|
content: '';
|
||||||
|
width: 6px;
|
||||||
|
height: 6px;
|
||||||
|
background: #ff4030;
|
||||||
|
border-radius: 50%;
|
||||||
|
animation: dot 1s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes dot {
|
||||||
|
0%, 100% { opacity: 1; }
|
||||||
|
50% { opacity: 0.3; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes badgePulse {
|
||||||
|
0%, 100% { box-shadow: 0 0 10px rgba(220, 50, 30, 0.1); }
|
||||||
|
50% { box-shadow: 0 0 20px rgba(220, 50, 30, 0.25); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Title */
|
||||||
|
.title {
|
||||||
|
font-size: 46px;
|
||||||
|
font-weight: 900;
|
||||||
|
line-height: 1.15;
|
||||||
|
letter-spacing: -1px;
|
||||||
|
color: #f0f0f5;
|
||||||
|
text-shadow: 0 2px 30px rgba(0,0,0,0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.title .num {
|
||||||
|
background: linear-gradient(135deg, #ff6b3d, #ff4019);
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
-webkit-text-fill-color: transparent;
|
||||||
|
background-clip: text;
|
||||||
|
font-size: 52px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title .leak {
|
||||||
|
position: relative;
|
||||||
|
color: #ff6b4a;
|
||||||
|
-webkit-text-fill-color: #ff6b4a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subtitle {
|
||||||
|
font-size: 17px;
|
||||||
|
color: rgba(180, 195, 230, 0.7);
|
||||||
|
font-weight: 400;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subtitle strong {
|
||||||
|
color: rgba(220, 230, 255, 0.9);
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Right side - terminal card */
|
||||||
|
.right {
|
||||||
|
width: 280px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.terminal {
|
||||||
|
width: 100%;
|
||||||
|
background: rgba(12, 14, 24, 0.85);
|
||||||
|
border: 1px solid rgba(100, 150, 255, 0.12);
|
||||||
|
border-radius: 10px;
|
||||||
|
overflow: hidden;
|
||||||
|
box-shadow:
|
||||||
|
0 4px 40px rgba(0, 0, 0, 0.5),
|
||||||
|
0 0 60px rgba(220, 80, 40, 0.06),
|
||||||
|
inset 0 1px 0 rgba(255, 255, 255, 0.04);
|
||||||
|
}
|
||||||
|
|
||||||
|
.terminal-bar {
|
||||||
|
height: 28px;
|
||||||
|
background: rgba(20, 22, 35, 0.9);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0 10px;
|
||||||
|
gap: 6px;
|
||||||
|
border-bottom: 1px solid rgba(100, 150, 255, 0.06);
|
||||||
|
}
|
||||||
|
|
||||||
|
.terminal-dot {
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
.terminal-dot:nth-child(1) { background: #ff5f57; }
|
||||||
|
.terminal-dot:nth-child(2) { background: #ffbd2e; }
|
||||||
|
.terminal-dot:nth-child(3) { background: #28c840; }
|
||||||
|
|
||||||
|
.terminal-body {
|
||||||
|
padding: 14px;
|
||||||
|
font-family: 'JetBrains Mono', monospace;
|
||||||
|
font-size: 10.5px;
|
||||||
|
line-height: 1.7;
|
||||||
|
color: #8899bb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.terminal-body .cmd { color: #28c840; }
|
||||||
|
.terminal-body .path { color: #ffbd2e; }
|
||||||
|
.terminal-body .err { color: #ff5f57; }
|
||||||
|
.terminal-body .str { color: #7faaff; }
|
||||||
|
.terminal-body .comment { color: #4a5568; }
|
||||||
|
.terminal-body .highlight { color: #ff6b4a; font-weight: 700; }
|
||||||
|
.terminal-body .white { color: #c8d4e8; }
|
||||||
|
|
||||||
|
/* Bottom bar */
|
||||||
|
.bottom-bar {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
height: 3px;
|
||||||
|
background: linear-gradient(90deg,
|
||||||
|
transparent,
|
||||||
|
#ff4019 20%,
|
||||||
|
#ff6b3d 50%,
|
||||||
|
#ff4019 80%,
|
||||||
|
transparent
|
||||||
|
);
|
||||||
|
z-index: 10;
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Corner accents */
|
||||||
|
.corner {
|
||||||
|
position: absolute;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
z-index: 10;
|
||||||
|
opacity: 0.3;
|
||||||
|
}
|
||||||
|
.corner--tl { top: 12px; left: 12px; border-top: 2px solid #ff6b4a; border-left: 2px solid #ff6b4a; }
|
||||||
|
.corner--tr { top: 12px; right: 12px; border-top: 2px solid #ff6b4a; border-right: 2px solid #ff6b4a; }
|
||||||
|
.corner--bl { bottom: 12px; left: 12px; border-bottom: 2px solid #ff6b4a; border-left: 2px solid #ff6b4a; }
|
||||||
|
.corner--br { bottom: 12px; right: 12px; border-bottom: 2px solid #ff6b4a; border-right: 2px solid #ff6b4a; }
|
||||||
|
|
||||||
|
/* Noise texture */
|
||||||
|
.noise {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
z-index: 5;
|
||||||
|
opacity: 0.035;
|
||||||
|
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="canvas">
|
||||||
|
<!-- Code rain background -->
|
||||||
|
<div class="code-rain">
|
||||||
|
<div class="code-col">const query = async () => {
|
||||||
|
const stream = api.stream()
|
||||||
|
for await (const chunk of stream) {
|
||||||
|
if (chunk.type === 'tool_use') {
|
||||||
|
await executeTool(chunk)
|
||||||
|
}
|
||||||
|
yield chunk.delta
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export class QueryEngine {
|
||||||
|
private sessions: Map<string>
|
||||||
|
async compact(history) {
|
||||||
|
if (tokens > MAX_CONTEXT) {
|
||||||
|
return summarize(history)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const PERMISSIONS = [
|
||||||
|
'FileRead', 'FileWrite',
|
||||||
|
'Bash', 'Glob', 'Grep',
|
||||||
|
]
|
||||||
|
function checkSecurity(cmd) {
|
||||||
|
for (const rule of RULES) {
|
||||||
|
if (rule.match(cmd)) block()
|
||||||
|
}
|
||||||
|
}</div>
|
||||||
|
<div class="code-col">interface Tool {
|
||||||
|
name: string
|
||||||
|
isConcurrencySafe: boolean
|
||||||
|
execute(input: unknown)
|
||||||
|
}
|
||||||
|
async function dispatch(calls) {
|
||||||
|
const reads = calls.filter(safe)
|
||||||
|
const writes = calls.filter(!safe)
|
||||||
|
await Promise.all(reads)
|
||||||
|
for (const w of writes) {
|
||||||
|
await w.execute()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// KAIROS daemon mode
|
||||||
|
class KairosDaemon {
|
||||||
|
private cron: CronScheduler
|
||||||
|
async autoDream() {
|
||||||
|
await consolidateMemory()
|
||||||
|
await mergeFindingss()
|
||||||
|
}
|
||||||
|
watch(repo: Repository) {
|
||||||
|
repo.on('pr', handle)
|
||||||
|
repo.on('issue', handle)
|
||||||
|
}
|
||||||
|
}</div>
|
||||||
|
<div class="code-col">const FEATURE_FLAGS = {
|
||||||
|
KAIROS: false,
|
||||||
|
VOICE_MODE: false,
|
||||||
|
COORDINATOR: true,
|
||||||
|
BUDDY: true,
|
||||||
|
ANTI_DISTILL: true,
|
||||||
|
DAEMON: false,
|
||||||
|
BRIDGE: true,
|
||||||
|
TORCH: false,
|
||||||
|
}
|
||||||
|
// anti-distillation
|
||||||
|
if (feature('ANTI_DISTILL')) {
|
||||||
|
result.anti_distillation
|
||||||
|
= ['fake_tools']
|
||||||
|
}
|
||||||
|
// undercover mode
|
||||||
|
export function isUndercover() {
|
||||||
|
return isExternalRepo()
|
||||||
|
&& isAnthropicUser()
|
||||||
|
}</div>
|
||||||
|
<div class="code-col">export async function main() {
|
||||||
|
const config = loadConfig()
|
||||||
|
const keys = await keychain()
|
||||||
|
|
||||||
|
await Promise.all([
|
||||||
|
growthbook.init(),
|
||||||
|
mcp.connect(servers),
|
||||||
|
registerTools(TOOLS),
|
||||||
|
])
|
||||||
|
|
||||||
|
const prompt = buildSystem({
|
||||||
|
identity: AGENT_IDENTITY,
|
||||||
|
tools: TOOL_SPECS,
|
||||||
|
memory: loadMemory(),
|
||||||
|
claudeMd: readClaudeMd(),
|
||||||
|
})
|
||||||
|
|
||||||
|
launchRepl(prompt, config)
|
||||||
|
}</div>
|
||||||
|
<div class="code-col">// bashSecurity.ts
|
||||||
|
const CHECKS = 23
|
||||||
|
function validateCommand(cmd) {
|
||||||
|
// Check 1: $(command)
|
||||||
|
// Check 2: process substitution
|
||||||
|
// Check 7: zmodload bypass
|
||||||
|
// Check 12: unicode zero-width
|
||||||
|
// Check 19: IFS null byte
|
||||||
|
// Check 23: HackerOne report
|
||||||
|
if (dangerous(cmd)) {
|
||||||
|
telemetry.track(
|
||||||
|
'bash_security_triggered',
|
||||||
|
{ check: checkId }
|
||||||
|
)
|
||||||
|
return BLOCKED
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 512,664 lines total
|
||||||
|
// 1,884 .ts/.tsx files
|
||||||
|
// Runtime: Bun</div>
|
||||||
|
<div class="code-col">class MemorySystem {
|
||||||
|
private index: MemoryIndex
|
||||||
|
|
||||||
|
async recall(query: string) {
|
||||||
|
const matches = semantic(
|
||||||
|
this.memories, query
|
||||||
|
)
|
||||||
|
return matches.slice(0, 5)
|
||||||
|
}
|
||||||
|
|
||||||
|
async age() {
|
||||||
|
for (const m of this.memories) {
|
||||||
|
if (isStale(m)) {
|
||||||
|
await this.archive(m)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// buddy/species.ts
|
||||||
|
const SPECIES = [
|
||||||
|
'duck', 'dragon', 'octopus',
|
||||||
|
'capybara', 'ghost', 'mushroom',
|
||||||
|
]</div>
|
||||||
|
<div class="code-col">// coordinator prompt (300+ lines)
|
||||||
|
// Phase 1: Research
|
||||||
|
// Phase 2: Synthesis
|
||||||
|
// Phase 3: Implementation
|
||||||
|
// Phase 4: Verification
|
||||||
|
//
|
||||||
|
// "Do not rubber-stamp
|
||||||
|
// weak work"
|
||||||
|
//
|
||||||
|
// prompt cache strategy:
|
||||||
|
// static segments: cached
|
||||||
|
// dynamic segments: rebuilt
|
||||||
|
//
|
||||||
|
// cache_control: {
|
||||||
|
// type: 'ephemeral'
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// MAX_AUTOCOMPACT = 3
|
||||||
|
// saved 250k API calls/day</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="scanline"></div>
|
||||||
|
<div class="grid-overlay"></div>
|
||||||
|
<div class="noise"></div>
|
||||||
|
|
||||||
|
<div class="corner corner--tl"></div>
|
||||||
|
<div class="corner corner--tr"></div>
|
||||||
|
<div class="corner corner--bl"></div>
|
||||||
|
<div class="corner corner--br"></div>
|
||||||
|
|
||||||
|
<!-- Main content -->
|
||||||
|
<div class="content">
|
||||||
|
<div class="left">
|
||||||
|
<div class="badge">source leaked</div>
|
||||||
|
<div class="title">
|
||||||
|
<span class="num">51万行</span>源码<span class="leak">曝光</span><br>
|
||||||
|
我扒完了Claude Code<br>的全部家底
|
||||||
|
</div>
|
||||||
|
<div class="subtitle">
|
||||||
|
<strong>512,664行</strong> TypeScript · <strong>1,884</strong> 文件 · <strong>44</strong> 特性开关
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="right">
|
||||||
|
<div class="terminal">
|
||||||
|
<div class="terminal-bar">
|
||||||
|
<div class="terminal-dot"></div>
|
||||||
|
<div class="terminal-dot"></div>
|
||||||
|
<div class="terminal-dot"></div>
|
||||||
|
</div>
|
||||||
|
<div class="terminal-body">
|
||||||
|
<span class="comment">// npm source map leak</span><br>
|
||||||
|
<span class="cmd">$</span> <span class="white">npm pack @anthropic-ai/claude-code</span><br>
|
||||||
|
<span class="path">→</span> <span class="str">claude-code-2.1.88.tgz</span><br>
|
||||||
|
<span class="path">→</span> <span class="str">index.js.map</span> <span class="highlight">59.8MB</span><br><br>
|
||||||
|
<span class="comment">// found R2 bucket URL...</span><br>
|
||||||
|
<span class="err">⚠ EXPOSED:</span><br>
|
||||||
|
<span class="white"> files: </span><span class="highlight">1,884</span><br>
|
||||||
|
<span class="white"> lines: </span><span class="highlight">512,664</span><br>
|
||||||
|
<span class="white"> flags: </span><span class="highlight">44</span><br>
|
||||||
|
<span class="white"> tools: </span><span class="highlight">40+</span><br><br>
|
||||||
|
<span class="err">█ KAIROS █ ANTI_DISTILL</span><br>
|
||||||
|
<span class="err">█ BUDDY █ UNDERCOVER</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bottom-bar"></div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
BIN
articles/008/cover.png
Normal file
|
After Width: | Height: | Size: 409 KiB |
37
articles/008/diagrams/01-architecture.mmd
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
graph TB
|
||||||
|
subgraph Layer1["第一层:入口"]
|
||||||
|
CLI["cli.tsx — CLI 入口 (302行)"]
|
||||||
|
MCP_E["mcp.ts — MCP Server"]
|
||||||
|
SDK_E["agentSdkTypes.ts — SDK"]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph Layer2["第二层:核心引擎"]
|
||||||
|
MAIN["main.tsx (4,683行)<br/>REPL 编排器"]
|
||||||
|
QE["QueryEngine.ts (1,295行)<br/>会话管理"]
|
||||||
|
QUERY["query.ts (1,729行)<br/>流式查询循环"]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph Layer3["第三层:工具执行"]
|
||||||
|
TOOLS["40+ 工具<br/>文件/Shell/网络/智能体"]
|
||||||
|
ORCH["并发调度器<br/>读写分离"]
|
||||||
|
PERM["权限系统<br/>24 个文件"]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph Layer4["第四层:智能体协调"]
|
||||||
|
COORD["协调器模式"]
|
||||||
|
AGENT["子智能体启动器"]
|
||||||
|
TASK["7 种任务类型"]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph Layer5["第五层:基础设施"]
|
||||||
|
API_C["Anthropic API 客户端"]
|
||||||
|
MCP_C["MCP 客户端 (3,348行)"]
|
||||||
|
BRIDGE["IDE 桥接 (27个文件)"]
|
||||||
|
MEM["记忆系统"]
|
||||||
|
INK["终端渲染引擎"]
|
||||||
|
end
|
||||||
|
|
||||||
|
Layer1 --> Layer2
|
||||||
|
Layer2 --> Layer3
|
||||||
|
Layer3 --> Layer4
|
||||||
|
Layer4 --> Layer5
|
||||||
BIN
articles/008/diagrams/01-architecture.png
Normal file
|
After Width: | Height: | Size: 354 KiB |
22
articles/008/diagrams/02-startup.mmd
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
sequenceDiagram
|
||||||
|
participant U as 你的终端
|
||||||
|
participant CLI as cli.tsx (302行)
|
||||||
|
participant Main as main.tsx (4,683行)
|
||||||
|
participant GB as GrowthBook 特性开关
|
||||||
|
participant MCP as MCP 服务器
|
||||||
|
participant REPL as REPL 交互循环
|
||||||
|
|
||||||
|
U->>CLI: $ claude
|
||||||
|
CLI->>CLI: 快速路径检查<br/>(--version? --help?)
|
||||||
|
CLI->>Main: 动态 import()
|
||||||
|
|
||||||
|
par 并行初始化(不阻塞)
|
||||||
|
Main->>GB: 加载 44 个特性开关
|
||||||
|
Main->>Main: 读取配置 / 密钥链
|
||||||
|
Main->>MCP: 连接所有 MCP 服务器
|
||||||
|
Main->>Main: 注册 40+ 工具
|
||||||
|
end
|
||||||
|
|
||||||
|
Main->>Main: 组装系统提示词
|
||||||
|
Main->>REPL: launchRepl()
|
||||||
|
REPL->>U: 光标闪烁,等你说话
|
||||||
BIN
articles/008/diagrams/02-startup.png
Normal file
|
After Width: | Height: | Size: 221 KiB |
19
articles/008/diagrams/03-query-loop.mmd
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
flowchart TD
|
||||||
|
START["你的消息"] --> BUILD["组装查询配置"]
|
||||||
|
BUILD --> CALL["调用 Anthropic API<br/>(SSE 流式传输)"]
|
||||||
|
CALL --> STREAM["实时接收 token"]
|
||||||
|
STREAM --> CHECK{模型要调用工具?}
|
||||||
|
|
||||||
|
CHECK -->|是| TOOLS["执行工具<br/>(读文件/改代码/跑命令...)"]
|
||||||
|
TOOLS --> BUDGET["结果预算控制<br/>(太大就存磁盘)"]
|
||||||
|
BUDGET --> COMPACT{"快爆上下文窗口了?"}
|
||||||
|
COMPACT -->|是| COMPRESS["自动压缩对话历史"]
|
||||||
|
COMPRESS --> CALL
|
||||||
|
COMPACT -->|否| CALL
|
||||||
|
|
||||||
|
CHECK -->|否| DONE{"输出被截断?"}
|
||||||
|
DONE -->|是,≤3次| CALL
|
||||||
|
DONE -->|否| END["完成"]
|
||||||
|
|
||||||
|
style TOOLS fill:#e1f5fe
|
||||||
|
style COMPRESS fill:#fff3e0
|
||||||
BIN
articles/008/diagrams/03-query-loop.png
Normal file
|
After Width: | Height: | Size: 304 KiB |
8
articles/008/diagrams/04-rw-dispatch.mmd
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
flowchart LR
|
||||||
|
INPUT["模型一次返回 5 个工具调用"] --> SPLIT{"只读?"}
|
||||||
|
|
||||||
|
SPLIT -->|"Glob ✓<br/>Grep ✓<br/>FileRead ✓"| PAR["并发执行<br/>(最多 10 个)"]
|
||||||
|
SPLIT -->|"FileEdit ✗<br/>Bash ✗"| SEQ["串行执行<br/>(一个一个来)"]
|
||||||
|
|
||||||
|
PAR --> MERGE["合并结果,返回模型"]
|
||||||
|
SEQ --> MERGE
|
||||||
BIN
articles/008/diagrams/04-rw-dispatch.png
Normal file
|
After Width: | Height: | Size: 101 KiB |
14
articles/008/diagrams/05-permission.mmd
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
flowchart TD
|
||||||
|
REQ["工具调用请求"] --> DENY{"在黑名单?"}
|
||||||
|
DENY -->|是| NO["拒绝"]
|
||||||
|
DENY -->|否| ALLOW{"在白名单?"}
|
||||||
|
ALLOW -->|是| YES["放行"]
|
||||||
|
ALLOW -->|否| TOOL{"工具自检<br/>checkPermissions()"}
|
||||||
|
TOOL -->|危险| CLASS{"AI 分类器<br/>(仅 auto 模式)"}
|
||||||
|
CLASS -->|安全| YES
|
||||||
|
CLASS -->|危险| ASK{"能弹窗吗?"}
|
||||||
|
ASK -->|能| USER["问用户"]
|
||||||
|
ASK -->|不能| NO
|
||||||
|
|
||||||
|
style NO fill:#ffcdd2
|
||||||
|
style YES fill:#c8e6c9
|
||||||
BIN
articles/008/diagrams/05-permission.png
Normal file
|
After Width: | Height: | Size: 245 KiB |
18
articles/008/diagrams/06-multi-agent.mmd
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
graph TB
|
||||||
|
subgraph Boss["协调器"]
|
||||||
|
C["全局视角<br/>任务分配<br/>质量把关"]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph Team["工作团队"]
|
||||||
|
W1["Worker 1<br/>探索代码结构"]
|
||||||
|
W2["Worker 2<br/>修改文件"]
|
||||||
|
W3["Worker 3<br/>运行测试"]
|
||||||
|
end
|
||||||
|
|
||||||
|
C -->|"生成"| W1
|
||||||
|
C -->|"生成"| W2
|
||||||
|
C -->|"追加指令"| W1
|
||||||
|
W1 -.->|"回报结果"| C
|
||||||
|
W2 -.->|"回报结果"| C
|
||||||
|
C -->|"验收后生成"| W3
|
||||||
|
W3 -.->|"回报结果"| C
|
||||||
BIN
articles/008/diagrams/06-multi-agent.png
Normal file
|
After Width: | Height: | Size: 178 KiB |
10
articles/008/diagrams/07-memory.mmd
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
graph LR
|
||||||
|
INDEX["MEMORY.md<br/>记忆索引<br/>(≤200行)"] --> M1["user_role.md<br/>用户信息"]
|
||||||
|
INDEX --> M2["feedback_testing.md<br/>纠正记录"]
|
||||||
|
INDEX --> M3["project_context.md<br/>项目背景"]
|
||||||
|
|
||||||
|
PROMPT["系统提示词"] -->|注入| INDEX
|
||||||
|
M1 --> SEARCH["语义搜索"]
|
||||||
|
M2 --> SEARCH
|
||||||
|
M3 --> SEARCH
|
||||||
|
SEARCH --> INJECT["注入当前对话"]
|
||||||
BIN
articles/008/diagrams/07-memory.png
Normal file
|
After Width: | Height: | Size: 116 KiB |
18
articles/008/diagrams/08-prompt-cache.mmd
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
graph TB
|
||||||
|
subgraph Cache["可缓存(跨会话复用)"]
|
||||||
|
A["智能体身份 + 安全指令"]
|
||||||
|
B["工具使用规范"]
|
||||||
|
C["软件工程行为准则"]
|
||||||
|
D["操作可逆性策略"]
|
||||||
|
end
|
||||||
|
|
||||||
|
WALL["══ CACHE BOUNDARY ══"]
|
||||||
|
|
||||||
|
subgraph Fresh["每次重建"]
|
||||||
|
E["用户钩子"]
|
||||||
|
F["记忆内容"]
|
||||||
|
G["Git 状态 / CLAUDE.md"]
|
||||||
|
H["MCP 指令"]
|
||||||
|
end
|
||||||
|
|
||||||
|
Cache --> WALL --> Fresh
|
||||||
BIN
articles/008/diagrams/08-prompt-cache.png
Normal file
|
After Width: | Height: | Size: 138 KiB |