模块十:扩展与 UI | 前置依赖:全部前置课程 | 预计学习时间:90 分钟
学习目标
完成本课后,你将能够:
- 概述 Claude Code 的 7 大特殊功能子系统(Bridge、Buddy、Voice、KAIROS、ULTRAPLAN、Remote、Computer Use)
- 理解每个子系统的 Feature Gate、核心架构和设计取舍
- 从 6 层视角完整描述 Claude Code 的整体架构
- 总结贯穿全代码库的设计哲学
- 将所学知识综合运用于架构分析和系统设计
Part A:特殊功能全景
30.1 Bridge 模式 — 远程控制
概述
Bridge 模式(代号"Remote Control")允许通过 claude.ai 网页界面远程控制本地或云端的 Claude Code 会话。bridge/ 目录包含 31 个文件。
┌─────────────────────────────────────────────────────────────────┐
│ Bridge 模式架构 │
│ │
│ claude.ai (浏览器) │
│ │ │
│ │ WebSocket / HTTP │
│ ▼ │
│ CCR (Cloud Container Runtime) │
│ │ │
│ │ JWT 认证 │
│ ▼ │
│ ┌──────────────────────────────────────────┐ │
│ │ Bridge Client (本地 Claude Code) │ │
│ │ │ │
│ │ bridgeMain.ts ← 主循环 │ │
│ │ jwtUtils.ts ← JWT 解码/刷新 │ │
│ │ replBridge.ts ← REPL 桥接 │ │
│ │ bridgeEnabled.ts ← 启用条件检测 │ │
│ │ bridgeConfig.ts ← OAuth 认证配置 │ │
│ │ workSecret.ts ← 工作密钥管理 │ │
│ │ sessionRunner.ts ← 会话运行器 │ │
│ └──────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
启用条件
bridgeEnabled.ts 实现了三重门控:
export function isBridgeEnabled(): boolean {
return feature('BRIDGE_MODE')
? isClaudeAISubscriber() && // 1. 必须是 claude.ai 订阅者
getFeatureValue_CACHED_MAY_BE_STALE('tengu_ccr_bridge', false) // 2. GrowthBook 门控
: false // 3. 编译时 Feature 必须开启
}
getBridgeDisabledReason() 提供了精确的诊断信息:无订阅、无 profile scope、无组织 UUID、未启用 — 每种情况给出不同的修复建议。
JWT 认证
// 解码 JWT payload(不验证签名)
export function decodeJwtPayload(token: string): unknown | null {
// 剥离 sk-ant-si- 前缀
const jwt = token.startsWith('sk-ant-si-')
? token.slice('sk-ant-si-'.length) : token
const parts = jwt.split('.')
if (parts.length !== 3 || !parts[1]) return null
return jsonParse(Buffer.from(parts[1], 'base64url').toString('utf8'))
}
// 提前 5 分钟刷新 token
const TOKEN_REFRESH_BUFFER_MS = 5 * 60 * 1000
// 刷新失败后回退到 30 分钟
const FALLBACK_REFRESH_INTERVAL_MS = 30 * 60 * 1000
// 最多连续失败 3 次
const MAX_REFRESH_FAILURES = 3
三种工作模式
| 模式 | 说明 | 关键文件 |
|---|---|---|
| 环境变量 (v1) | 通过 env var 传递认证 | bridgeMain.ts |
| 无环境变量 (v2) | OAuth 认证,无 env 依赖 | envLessBridgeConfig.ts |
| CCR 镜像 | 本地会话转发事件到远程 | isCcrMirrorEnabled() |
v2 模式由 tengu_bridge_repl_v2 GrowthBook 门控,包含一个 session ID 兼容层(cse_* 到 session_* 的重新标记)。
30.2 Buddy 宠物系统
概述
Buddy 系统是一个纯粹的乐趣功能 — 每个用户拥有一个独特的 ASCII 宠物伴侣。buddy/ 目录包含 6 个文件。
buddy/
├── types.ts ← 类型定义(18 种物种、6 种眼睛、8 种帽子、5 种稀有度)
├── companion.ts ← 确定性生成逻辑(Mulberry32 PRNG)
├── sprites.ts ← ASCII 精灵图(每物种 3 帧动画)
├── prompt.ts ← 伴侣系统提示词
├── CompanionSprite.tsx ← React 渲染组件
└── useBuddyNotification.tsx ← 通知 Hook
Mulberry32 PRNG
宠物的所有属性由用户 ID 确定性生成,使用 Mulberry32 伪随机数发生器:
function mulberry32(seed: number): () => number {
let a = seed >>> 0
return function () {
a |= 0
a = (a + 0x6d2b79f5) | 0
let t = Math.imul(a ^ (a >>> 15), 1 | a)
t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t
return ((t ^ (t >>> 14)) >>> 0) / 4294967296
}
}
种子来源:hash(userId + "friend-2026-401"),使用 FNV-1a 哈希(或 Bun.hash)。
18 种物种
duck, goose, blob, cat, dragon, octopus, owl, penguin,
turtle, snail, ghost, axolotl, capybara, cactus, robot,
rabbit, mushroom, chonk
物种名使用 String.fromCharCode() 编码而非字面量,原因是某个物种名与模型代号冲突,编译检查会在构建输出中 grep 这些字符串。
稀有度系统
common: 60% 权重 ★ ← 基础属性 floor = 5
uncommon: 25% 权重 ★★ ← floor = 15
rare: 10% 权重 ★★★ ← floor = 25
epic: 4% 权重 ★★★★ ← floor = 35
legendary: 1% 权重 ★★★★★ ← floor = 50, 帽子必有
Bones vs Soul
CompanionBones (确定性 — 每次从 hash(userId) 重新生成)
├── rarity, species, eye, hat, shiny
└── stats: { DEBUGGING, PATIENCE, CHAOS, WISDOM, SNARK }
CompanionSoul (存储在 config — 模型生成一次)
├── name
└── personality
Companion = Bones + Soul + hatchedAt
安全设计:Bones 从不持久化,每次从 hash(userId) 重新计算。这意味着用户无法通过编辑配置文件伪造稀有度。
ASCII 精灵
每个物种有 3 帧动画,每帧 5 行 x 12 列。{E} 占位符在渲染时替换为实际眼睛字符:
duck 帧 0: duck 帧 1:
__ __
<(· )___ <(· )___
( ._> ( ._>
`--´ `--´~ ← 尾巴摇动
30.3 Voice 模式
Voice 模式通过 claude.ai 的 voice_stream 端点实现语音输入。
启用条件
export function isVoiceModeEnabled(): boolean {
return hasVoiceAuth() && isVoiceGrowthBookEnabled()
}
// Auth: 必须有 Anthropic OAuth token(不支持 API key/Bedrock/Vertex)
// Kill-switch: tengu_amber_quartz_disabled(默认 false = 可用)
kill-switch 设计特殊:默认值为 false(未禁用),这意味着磁盘缓存缺失时视为"未被 kill",新安装立即可用。
键绑定:空格键为 voice:pushToTalk(按住说话),仅在 VOICE_MODE Feature 启用时注册。
30.4 KAIROS — 后台常驻 Agent
KAIROS(代号,Feature Gate: KAIROS / KAIROS_BRIEF)是一个"始终在线"的后台 Agent,在 assistant/ 目录下只有一个文件 sessionHistory.ts。
核心特性
- 15 秒阻塞预算 — KAIROS 不能长时间阻塞用户交互
- Brief 模式 —
isBriefOnly状态,仅输出简短响应 - 独占工具 — 某些工具只对 KAIROS 可用
- 会话历史 — 通过
sessionHistory.ts查看远程会话事件
// sessionHistory.ts — 分页获取会话事件
export async function fetchLatestEvents(
ctx: HistoryAuthCtx,
limit = HISTORY_PAGE_SIZE, // 100
): Promise<HistoryPage | null> {
return fetchPage(ctx, { limit, anchor_to_latest: true }, 'fetchLatestEvents')
}
30.5 ULTRAPLAN — 远程 Opus 规划
ULTRAPLAN 允许用户将复杂规划任务委托给远程 Opus 模型(最长 30 分钟执行时间)。
关键字触发
// keyword.ts — 在用户输入中检测 "ultraplan"
export function findUltraplanTriggerPositions(text: string): TriggerPosition[] {
return findKeywordTriggerPositions(text, 'ultraplan')
}
触发检测有严格的排除规则:
- 引号内 — 反引号、双引号、角括号、花括号、方括号内的不触发
- 路径/标识符 —
src/ultraplan/foo.ts、ultraplan.tsx、--ultraplan-mode不触发 - 问号结尾 —
what is ultraplan?不触发(提问不应触发功能) - 斜杠命令 —
/rename ultraplan foo不触发(这是 /rename 命令)
触发后,replaceUltraplanKeyword 将 "ultraplan" 替换为 "plan"(保留大小写),使转发的 prompt 语法通顺。
30.6 Remote Agents
remote/ 目录(4 个文件)管理远程会话连接:
remote/
├── RemoteSessionManager.ts ← 远程会话管理器
├── SessionsWebSocket.ts ← WebSocket 连接
├── sdkMessageAdapter.ts ← SDK 消息适配
└── remotePermissionBridge.ts ← 权限桥接
RemoteSessionManager 通过 WebSocket 连接到 CCR,转发本地和远程事件。支持观察者模式(只读查看远程会话,不发送中断)。
30.7 Upstream Proxy — 反 ptrace 安全
upstreamproxy/ 目录(2 个文件)用于 CCR 容器内的安全代理。
安全流程
1. 读取 /run/ccr/session_token ← 会话令牌
2. prctl(PR_SET_DUMPABLE, 0) ← 阻止同 UID ptrace 读堆
3. 下载 CA 证书 + 拼接系统 CA bundle ← 信任 MITM 代理
4. 启动 CONNECT→WebSocket relay ← 本地 TCP → WS 隧道
5. 删除 token 文件 ← token 仅留在堆内存
6. 设置 HTTPS_PROXY / SSL_CERT_FILE ← 子进程使用代理
关键安全设计:token 文件在 relay 确认启动后才删除(但在 Agent 循环开始前),确保 Agent 代码无法读取 token 文件。PR_SET_DUMPABLE(0) 阻止同 UID 进程通过 ptrace 读取堆内存中的 token。
relay 使用 protobuf 封装:message UpstreamProxyChunk { bytes data = 1; },通过 WebSocket 与 CCR 上游代理通信。
30.8 Computer Use "Chicago"
Computer Use(内部代号 "chicago")通过 MCP 协议提供屏幕截图和鼠标/键盘控制:
// common.ts
export const COMPUTER_USE_MCP_SERVER_NAME = 'computer-use'
export const CLI_HOST_BUNDLE_ID = 'com.anthropic.claude-code.cli-no-window'
作为 CLI 应用,Claude Code 没有窗口 — CLI_HOST_BUNDLE_ID 永远不会匹配真实的 frontmost application,相关的窗口豁免逻辑实际上是无操作的。
终端 bundle ID 检测使用 __CFBundleIdentifier 环境变量(macOS LaunchServices 注入),回退到已知终端映射表。
Part B:架构总复习
30.9 六层架构视图
┌─────────────────────────────────────────────────────────────────┐
│ 第 6 层: 特殊功能 │
│ Bridge, Buddy, Voice, KAIROS, ULTRAPLAN, Computer Use │
│ Feature Gate 门控,各自独立 │
├─────────────────────────────────────────────────────────────────┤
│ 第 5 层: 多 Agent 编排 │
│ Coordinator 模式 | Swarm/Teams | 子 Agent │
│ 任务分发、并行执行、结果综合 │
├─────────────────────────────────────────────────────────────────┤
│ 第 4 层: 扩展体系 │
│ Plugin 系统 | Skill 系统 | Hook 系统 │
│ 安装/加载/注册/热重载 │
├─────────────────────────────────────────────────────────────────┤
│ 第 3 层: 查询执行 │
│ QueryEngine | 权限系统 | 工具执行 | MCP │
│ 流式响应、推测执行、上下文管理 │
├─────────────────────────────────────────────────────────────────┤
│ 第 2 层: 终端 UI │
│ Ink 渲染引擎 | 组件库 | 键绑定 | Vim 模式 │
│ REPL 循环、输入处理、输出渲染 │
├─────────────────────────────────────────────────────────────────┤
│ 第 1 层: 基础设施 │
│ Feature Gate | 状态管理 | 启动流程 | 配置系统 │
│ 分析/遥测 | 错误处理 | 文件系统操作 │
└─────────────────────────────────────────────────────────────────┘
30.10 完整数据流
一次完整的用户交互数据流:
用户按键
│
▼
parse-keypress.ts ← 原始字节 → 按键事件
│
▼
keybindings/resolver.ts ← 按键 → Action(含 Chord 状态机)
│
▼
useInput / useKeybinding ← Action → 组件响应
│
▼
PromptInput.tsx ← 收集输入文本
│ (enter 键)
▼
processUserInput.ts ← 路由:斜杠命令 / ULTRAPLAN / 普通查询
│
▼
QueryEngine.ts ← 构建系统提示 + 用户消息
│
├── CLAUDE.md 加载 ← 项目指令
├── Skill 上下文注入 ← 可用 Skill 列表
├── Tool 定义注入 ← 可用工具列表
└── MCP 资源注入 ← MCP 工具和上下文
│
▼
API 调用(流式)
│
├── 文本块 → 流式渲染到终端
├── 工具调用 → 权限检查 → Hook(PreToolUse) → 执行 → Hook(PostToolUse)
│ │
│ ├── Bash → 子进程执行
│ ├── Edit → 文件修改 + 快照
│ ├── AgentTool → 子 Agent / Worker 派生
│ └── MCP 工具 → MCP 客户端转发
│
└── 思考块 → 可选显示
│
▼
结果渲染
│
├── reconciler.ts ← React → DOM
├── Yoga 布局 ← Flexbox 计算
├── renderer.ts ← Screen Buffer diff
└── stdout.write() ← ANSI 序列输出
30.11 设计哲学总结
贯穿 Claude Code 整个代码库的核心设计原则:
1. Fail-Closed(安全默认)
所有安全决策默认拒绝,需要显式允许。
- 权限系统:不在白名单中的操作需要用户确认
- Feature Gate:外部构建默认关闭所有内部功能
- Buddy:Bones 从不持久化,防止伪造稀有度
- Upstream Proxy:token 文件在 Agent 循环前删除
2. 编译时 DCE(Dead Code Elimination)
feature('XXX') 的"正面三元模式"确保外部构建中,
内部功能的所有代码(包括字符串字面量)被完全消除。
// 正确模式
return feature('X') ? doStuff() : false
// 错误模式(字符串不会被 DCE)
if (!feature('X')) return false
return doStuff() // 'tengu_...' 字符串泄露到外部构建
3. 不可变状态
DeepImmutable<AppState> + setState(prev => newState) 模式。
34 行 Store 实现,Object.is 跳过无变化更新。
TypeScript 编译器在编译时捕获所有直接修改尝试。
4. 子 Agent 隔离
Worker 看不到 Coordinator 的对话上下文。
INTERNAL_WORKER_TOOLS 防止 Worker 越级操作。
Teammate 运行在独立进程/窗格中,通过 TeamFile 协调。
5. 渐进式加载
- Feature-gated skills 使用 require() 动态加载
- Bundled skill 文件按需提取(首次调用时)
- 插件后台安装,不阻塞启动
- MCP 连接异步建立
6. 缓存优先
- charCache 跨帧复用(避免每帧重新 tokenize)
- pluginLoader memoize(缓存插件加载结果)
- StylePool 会话级持久(styleId 安全缓存)
- rollCache 缓存 Buddy 生成结果
- GrowthBook 磁盘缓存(离线可用)
7. 纯函数优先
- Vim 操作:motions/operators/textObjects 全是纯函数
- 键绑定 resolver:无状态,无副作用
- State selectors:给定相同输入总返回相同输出
- Coordinator prompts:函数式生成
30.12 关键数字回顾
| 维度 | 数字 |
|---|---|
| 总文件数(估计) | 1000+ 个 TypeScript 文件 |
| 组件数量 | 144 个 |
| Hook 事件类型 | 26 种 |
| Feature Gate 层数 | 2 层(编译时 + 运行时) |
| Vim 状态类型 | 11 种 CommandState |
| 键绑定上下文 | 17 个 |
| Buddy 物种 | 18 种 |
| 稀有度等级 | 5 级 |
| Store 核心行数 | ~34 行 |
| Bridge 文件数 | 31 个 |
| Swarm 后端类型 | 3 种(tmux/iTerm2/in-process) |
| Coordinator 阶段 | 4 个(Research/Synthesis/Implementation/Verification) |
课后练习
练习 1:架构图绘制
绘制一张完整的 Claude Code 架构图,包含 6 个层次、所有主要子系统之间的数据流。使用不同颜色标注:Feature Gate 边界、安全边界、进程边界。
练习 2:设计哲学论文
选择 Claude Code 的三个设计原则(如 Fail-Closed、编译时 DCE、不可变状态),写一篇 800-1200 字的分析文章,讨论这些原则如何在具体代码中体现,以及它们之间的协同效应。
练习 3:系统设计实战
假设你要为 Claude Code 添加一个新的特殊功能 — "Pair Programming 模式"(两个用户可以同时连接到同一个会话)。设计其架构:Feature Gate 策略、认证方案、状态同步机制、UI 设计。参考 Bridge 模式和 Swarm 模式的设计。
练习 4:安全审计
对 Claude Code 的安全设计进行一次模拟审计。检查以下攻击面:(a) 恶意 CLAUDE.md 注入, (b) MCP 服务器中间人攻击, (c) 插件供应链攻击, (d) Bridge 模式 token 泄露。分析现有防御措施的有效性,并提出改进建议。
本课小结
| 要点 | 内容 |
|---|---|
| Bridge | 远程控制,JWT 认证,三种工作模式,三重门控 |
| Buddy | 18 种物种,Mulberry32 PRNG,Bones 从不持久化 |
| Voice | OAuth 认证,kill-switch 默认可用,空格键按住说话 |
| KAIROS | 后台常驻,15s 阻塞预算,独占工具 |
| ULTRAPLAN | 关键字触发,严格排除规则,远程 Opus 执行 |
| Upstream Proxy | anti-ptrace,token 堆内存化,CONNECT→WS relay |
| 设计哲学 | Fail-Closed, DCE, 不可变, 隔离, 渐进加载, 缓存优先, 纯函数 |
课程总结
恭喜你完成了 Claude Code 源码分析的全部 30 课内容。
在这门课程中,我们从第 1 课的全局架构鸟瞰开始,逐步深入到启动流程、状态管理、REPL 循环、查询引擎、权限系统、工具执行、MCP 集成、上下文管理、多 Agent 编排、扩展体系、终端 UI,最终在本课中覆盖了所有特殊功能并进行了架构总复习。
课程回顾
| 模块 | 课程 | 核心主题 |
|---|---|---|
| 模块一 | 1-3 | 全局架构、技术栈、Feature Gate |
| 模块二 | 4-5 | 入口启动、状态管理 |
| 模块三 | 6-8 | REPL 循环、查询引擎、流式处理 |
| 模块四 | 9-11 | 权限系统、工具架构、Bash/Edit 工具 |
| 模块五 | 12-14 | 子 Agent、MCP 集成、上下文管理 |
| 模块六 | 15-18 | 系统提示词、CLAUDE.md、压缩策略 |
| 模块七 | 19-22 | 推测执行、缓存、性能优化 |
| 模块八 | 23-26 | 分析遥测、错误处理、配置系统 |
| 模块九 | 27 | Coordinator 多 Worker 编排 |
| 模块十 | 28-30 | 插件/技能/钩子、终端 UI、特殊功能 |
三个带走的核心洞察
1. 层次化的安全设计:从编译时 DCE 到运行时 Feature Gate,从 DeepImmutable 到权限白名单,从 anti-ptrace 到 token 堆内存化 — 安全不是一个功能,而是贯穿所有层次的架构约束。
2. 极简与复杂的平衡:34 行的 Store 实现管理着 50+ 字段的全局状态。5 个文件的 Vim 模式实现了完整的文本编辑。简单的抽象支撑复杂的功能 — 这是优秀架构的标志。
3. 可扩展性的三条路径:Plugin(容器级扩展)、Skill(能力级扩展)、Hook(事件级扩展)— 三个粒度的扩展机制,既互相独立又能协同工作,为生态系统奠定了基础。
希望这门课程能帮助你深入理解大型 TypeScript CLI 应用的架构设计,以及 AI 辅助编程工具在工程实践上的取舍和创新。