docs: 添加文档大纲及 superpowers/outline 目录

Co-Authored-By: deepseek-v4-pro <deepseek-ai@claude-code-best.win>
This commit is contained in:
claude-code-best
2026-06-15 16:17:03 +08:00
parent 37dac682b9
commit 178868175e
39 changed files with 9972 additions and 0 deletions

View File

@@ -0,0 +1,155 @@
# 序章:一份被反编译重建的 CLI为什么处处是"约束的印记"
> 这不是原版代码,而是反编译产物在 Bun/JSC 约束下重建出来的东西——每一个奇怪的设计都有具体的根因。
## 反编译的语义stub、feature gate、_c() 都是正常的
打开 `src/types/global.d.ts:1`,你会看到这份代码开宗明义的声明:
```ts
/**
* Global declarations for compile-time macros and internal-only identifiers
* that are eliminated via Bun's MACRO/bundle feature system.
*/
```
这不是普通的 TypeScript 项目。这份代码的源头是编译后的产物,而不是人类手写的源码。类型声明文件里塞满了"只在编译期存在、运行时会被消除"的标识符:`MACRO.VERSION``MACRO.BUILD_TIME``resolveAntModel()``Gates``TungstenPill()`。这些东西在原版 Anthropic 内部构建链里是真实的函数和对象,但在反编译产物里,它们只剩下一个类型签名——一个空壳。
再往下看 `global.d.ts:59`
```ts
// T — Generic type parameter leaked from React compiler output
// (react/compiler-runtime emits compiled JSX that loses generic type params)
declare type T = unknown
```
`T = unknown`。这不是谁偷懒写了无意义的类型别名。React Compilerreact-compiler-runtime在编译 JSX 时会把泛型参数丢掉,反编译产物于是到处出现裸露的 `T`。为了让 TypeScript 编译器不报错,只能声明 `type T = unknown`。这是一个典型的"反编译痕迹"——它不是设计决策,而是信息丢失后的补救。
打开 `src/types/react-compiler-runtime.d.ts:1`,类型声明更简洁:
```ts
declare module 'react/compiler-runtime' {
export function c(size: number): unknown[]
}
```
一个函数 `c`,接受一个数字参数,返回 `unknown[]`。这个函数在原版 Anthropic 代码库里是 React Compiler 的运行时 memoization 辅助函数,用于生成 `$` 变量(你在反编译的 React 组件里会看到 `const $ = _c(N)` 这样的模式)。但在反编译产物里,编译器把它内联了,原始模块不复存在。为了不破坏下游 import只能声明一个 `unknown[]` 返回值——类型系统在说"我知道这里有东西,但我不知道它是什么"。
## 全书的叙事主线:约束驱动架构
这本书的组织逻辑不是"这个项目有什么功能",而是"哪些约束逼出了哪些设计决策"。这个区别很重要。
你将要读到的每一章,都在追问同一个问题:**如果不这么做会怎样?**
- 第一章讲 Code Splitting——答案是"RSS 暴涨到 1GBCLI 启动就要吃掉你一整 GB 内存"。这不是优化,是生存需求。
- 第三章讲 performanceShim——答案是"JSC 的 Performance 实现有个永不收缩的 C++ Vector长会话累积数百 MB 死容量"。
- 第五章讲 Feature Flag 的三个硬约束——答案是"Bun 编译器 DCE 的 AST 模式匹配限制,`feature()` 只能出现在 `if` 条件位置"。
这本书里几乎每一个看似奇怪的设计——`feature()` 不能赋值给变量、`--version` 必须零模块加载、构建产物要正则替换 `globalThis.Bun`——都指向同一个主题:**你面对的不是一张白纸,而是 JSC 内存模型、Bun 编译器限制、反编译信息丢失这三重约束的交叉压力。**
## 如何阅读本书:打开编辑器,对照锚点
每个章节末尾的"锚点"不是装饰,而是邀请。每一条锚点都是 `文件:行号` 格式,指向代码库中真实存在的代码。
比如本章提到 `src/types/global.d.ts:59``T = unknown`。你可以现在就打开那个文件,跳到第 59 行,亲眼看到那行代码和它上方的注释。再比如本章开头引用了 `CLAUDE.md`(项目根目录下的那份),第一句话就是:
> This is a **reverse-engineered / decompiled** version of Anthropic's official Claude Code CLI tool.
这不是隐喻。这份代码库的每一个角落都带着反编译的指纹。有些指纹很明显——`declare type T = unknown``export function c(size: number): unknown[]`有些指纹很隐蔽——feature flag 系统的硬约束、模块级单例状态、"42 条 lint 规则关闭"(那是第十五章的内容)。
建议你用 VS Code 或任何编辑器打开这个项目的根目录。每次看到锚点引用时,花十秒钟跳过去看一下。你会发现文档描述和实际代码之间的对应关系非常精确——这比任何架构图都直观。
## 两类禁用 feature丢失的 stub vs 原本就 stubbed 的
`scripts/defines.ts:39``DEFAULT_BUILD_FEATURES` 列表里有 65+ 个 feature flag。其中有 8 个被注释掉了:
```ts
// 'HISTORY_SNIP', // 已禁用snip 功能暂时关闭
// 'CONTEXT_COLLAPSE', // 已禁用:实现是空壳 stub启用后会抑制 auto compact 导致上下文管理完全失效
// 'FORK_SUBAGENT', // 已禁用:通过 Agent tool 的特殊方式实现了等效功能,无需再开
// 'UDS_INBOX', // 进程间通信管道inbox/pipe/peers 等命令)构建后 nodejs 环境卡住
// 'LAN_PIPES', // 局域网管道,依赖 UDS_INBOX 构建后 nodejs 环境卡住
// 'REVIEW_ARTIFACT', // 代码审查产物API 请求无响应,待排查 schema 兼容性)
// 'SKILL_LEARNING',
// 'TEAMMEM', // 已禁用:依赖 COORDINATOR_MODE邮箱文件无限增长
```
表面上看它们都是"被禁用的",但禁用的原因截然不同。混淆这两类会导致严重误判。
**第一类:反编译丢失导致的 stub。** `CONTEXT_COLLAPSE``HISTORY_SNIP``FORK_SUBAGENT``UDS_INBOX``LAN_PIPES``REVIEW_ARTIFACT` 属于这一类。
打开 `src/setup.ts:290` 你会看到:
```ts
if (feature('CONTEXT_COLLAPSE')) {
require('./services/contextCollapse/index.js').initContextCollapse()
}
```
`src/services/contextCollapse/` 目录确实存在,里面有 `index.ts``operations.ts``persist.ts` 三个文件。但注释明确说"实现是空壳 stub启用后会抑制 auto compact 导致上下文管理完全失效"。反编译过程保留了文件结构和函数签名,但丢失了核心逻辑。如果你强行启用 `FEATURE_CONTEXT_COLLAPSE=1`init 函数会跑起来,但它做的事情是错误的——它会抑制自动压缩,导致长对话的上下文管理彻底崩溃。
`HISTORY_SNIP` 的情况类似。打开 `src/commands.ts:92`
```ts
const forceSnip = feature('HISTORY_SNIP')
? require('./commands/force-snip.js').default
: null
```
`src/commands/force-snip/` 目录根本不存在。如果你启用这个 feature运行时会直接 `MODULE_NOT_FOUND`。这个 feature 在原版里指向一个完整的消息历史裁剪子系统(`src/utils/messages.ts:2652` 里有它的运行时检查逻辑),但反编译过程丢失了 `force-snip` 命令模块。
**第二类:功能原本就 stubbed 的。** `SKILL_LEARNING``TEAMMEM` 属于这一类。
打开 `src/services/skillLearning/featureCheck.ts:11`
```ts
export function isSkillLearningCompiledIn(): boolean {
if (feature('SKILL_LEARNING')) return true
return false
}
```
这个目录下有 20+ 个文件(`agentGenerator.ts``evolution.ts``instinctParser.ts``skillLifecycle.ts` 等),结构完整。这不是反编译丢失——这是 Anthropic 原版里本身就 stubbed 的功能。feature flag 注释写的也很清楚:`SKILL_LEARNING` 的 slash command 被编译进 build但运行时默认 OFF需要 operator 主动 `/skill-learning start` 开启。这不是"丢了",而是"还没开放"。
`TEAMMEM` 也是类似情况。`src/memdir/memdir.ts:7``src/utils/memoryFileDetection.ts:17` 等多处引用了 `feature('TEAMMEM')` 的分支逻辑,相关代码路径是完整的。禁用的原因是"依赖 COORDINATOR_MODE邮箱文件无限增长"——这是一个产品决策,不是反编译事故。
**区分这两类的实用方法**:看被注释掉的那行注释。如果注释说"实现是空壳 stub"或"构建后环境卡住",那是反编译丢失(第一类)。如果注释说"依赖某 feature"或"待排查",那是功能本身的问题(第二类)。第一类强行启用会破坏核心功能;第二类启用后可能有 bug 但不会让系统崩溃。
## bun:bundle 的幽灵模块
`src/types/internal-modules.d.ts:10` 声明了一个不存在的模块:
```ts
declare module 'bun:bundle' {
export function feature(name: string): boolean
}
```
`bun:bundle` 是 Bun 运行时的内置模块,由 Bun 编译器在构建时解析。你在 Bun 以外的环境里跑 `import { feature } from 'bun:bundle'` 会报错——这个模块只存在于 Bun 的编译管道里。类型声明文件把它写出来,纯粹是为了让 TypeScript 不报 `Cannot find module 'bun:bundle'` 错误。
这个幽灵模块贯穿整个代码库。`scripts/vite-plugin-feature-flags.ts:29` 里有一个 Rollup 插件,专门在 Vite 构建时把 `bun:bundle` 虚拟化为一个始终返回 `false` 的 stub
```ts
load(id) {
if (id === resolvedVirtualModuleId) {
return 'export function feature(name) { return false; }'
}
}
```
同一个 `feature()` 函数,在 Bun 构建里是编译器的 DCEdead code elimination钩子在 Vite 构建里被插件替换为字面量。两种构建管道对同一个函数的理解完全不同,但产出的行为一致。这种"双管道、单语义"的设计是反编译重建工作的典型特征——你不需要理解原版为什么这么做,你只需要在两条路径上复现相同的行为。
## 反编译产物的类型补丁成本
`bun:bundle` 不是唯一的幽灵模块。同一个文件里还声明了 `bun:ffi``internal-modules.d.ts:14`),以及 `bidi-js``asciichart``@napi-rs/keyring` 等没有 `@types` 包的第三方模块。所有导出都被类型化为 `any` 或最小接口。
这意味着什么?意味着你在阅读代码时看到的类型签名,有很多是"人为补丁"而非"原始设计"。`T = unknown` 是最极端的例子,但更常见的模式是 `Record<string, unknown>`——当反编译丢掉了结构信息时,退化为字典类型是唯一安全的选项。
如果你在代码里看到某个函数接收 `Record<string, unknown>` 参数,或者在某个地方有 `as unknown as SomeType` 的双重断言,那大概率是反编译信息丢失的痕迹。这不是代码质量问题,而是信息损失的必然结果——就像你把一栋建筑拆成零件再重建,总有些螺丝的规格对不上,只能用万能件替代。
## 延伸阅读
- 想了解 Feature Flag 系统为什么有"三个硬约束",见 [第五章Feature Flag 系统的三个硬约束](./05-feature-flags.md)
- 想看 Code Splitting 是怎么被 JSC 内存压力逼出来的,见 [第一章Code Splitting 不是优化,是生存需求](./01-code-splitting.md)
- 想了解 biome.json 关掉 42 条规则的反编译指纹,见 [第十五章biome.json 的 42 条规则关闭](./15-biome-42-rules.md)
- 想看 performanceShim 如何修补 JSC 内存泄漏,见 [第三章performanceShim —— JSC 内存泄漏的运行时补丁](./03-performance-shim.md)