“
Claude Code意外泄漏51.2万行TS核心代码
Harness 工程:设计、实现与可借鉴点
本文描述仓库中 rust/ 兼容 harness 的目标、结构与实现方式,并归纳对 大型代码库迁移、双语言共存、渐进替换 类项目的借鉴意义。主程序真源仍在 ../src/(TypeScript) ;Rust 侧当前里程碑是 「可证明的抽取 + 与上游接缝对齐的骨架」,而非完整 CLI 运行时。
1. Harness-first 在讲什么?
rust/README.md 引用的 PRD 思路可概括为四步:
- 先抽「可观测事实」:从现有上游源码中稳定读出 命令表、工具表、启动阶段 等,而不是先写一大套自以为对齐的运行时。
- 边界与上游同名同构:crate 划分贴在
commands/tools/ runtime(bootstrap) 等 主仓库已有的接缝 上,方便两边对照与后续填充。 - 证明先于扩张:用 测试 + 小 CLI 子命令 把抽取结果 钉在 CI 里;新功能先在 harness 层 reak proof,再谈行为兼容。
- 公开承认缺口:里程碑描述明确 不做 drop-in 全量 parity,避免对外过度承诺。
这是一种 「兼容性优先的脚手架」 策略:价值在于 降低迁移不确定性与回归成本,而不是第一天换掉主程序。
2. 工作空间与依赖图
rust/
├── Cargo.toml # workspace,members = crates/*,unsafe forbid 等统一 lint
├── README.md
└── crates/
├── rusty-claude-cli/ # 二进制入口(薄)
├── compat-harness/ # 读 TS 源、做抽取的唯一实现 crate
├── runtime/ # BootstrapPhase / BootstrapPlan(无 I/O)
├── commands/ # CommandRegistry 等纯数据类型
└── tools/ # ToolRegistry 等纯数据类型
依赖关系(有向无环):
commands与tools互不依赖:清单 形态 独立,避免类型互相拖拽。compat-harness聚合 解析逻辑 + IO(读文件) ;其它 crate 保持可单测、可复用的小库。
3. 上游路径契约:UpstreamPaths
compat-harness 假定仓库布局固定(与当前 monorepo 一致):
| 方法 | 指向 |
|---|---|
commands_path() | repo_root/src/commands.ts |
tools_path() | repo_root/src/tools.ts |
cli_path() | repo_root/src/entrypoints/cli.tsx |
from_workspace_dir 通过 canonicalize + parent() 从 rust/crates/compat-harness/../../ 推出 repo_root。
借鉴:把 「真源文件位置」 收束成一个类型,后续改路径只改一处;测试用 CARGO_MANIFEST_DIR 定位 fixture。
4. 抽取如何实现?(启发式逐行,非 TypeScript AST)
4.1 设计取舍
未引入 swc/typescript parser:对 registry 型文件(大量 import、export const … = [、feature() ? require)采用 逐行扫描 + 简单字符串规则。
| 优点 | 缺点 |
|---|---|
| 零第三方解析依赖、实现短、编译快 | 上游 大改格式 时可能误报/漏报 |
| 与「manifest 级」目标匹配,不做语义分析 | 不能替代类型检查或真实 import 图 |
适合 harness 的第一阶段;若后期需要精确到 导出图 / 循环依赖,可再 增量 接 AST 或 ts-morph,而不必推翻 crate 划分。
4.2 命令清单(extract_commands)
- 内置:
import … from './commands/...'→ 符号记入CommandSource::Builtin。 - 内部列表:在
INTERNAL_ONLY_COMMANDS = [与 closing]之间,按行提取标识符 →InternalOnly。 - 特性门控:行内同时含
feature('与./commands/,取赋值左侧名 →FeatureGated。 - 去重:
(name, source)二元组去重 →CommandRegistry。
4.3 工具清单(extract_tools)
./tools/的 import 且符号以Tool/Tools结尾 →ToolSource::Base。feature('...')且与Tool相关的赋值 →Conditional。
4.4 启动阶段(extract_bootstrap_plan)
对 cli.tsx 全文做子串探测(如 --version、startupProfiler、--daemon-worker),按固定顺序 追加BootstrapPhase 枚举项,最后 MainRuntime。
这与真实运行时 「有则启用某快路径」 的语义大致同构,但是 粗粒度 的静态近似。
5. 二进制入口:rusty-claude-cli
当前只做三件事(见 main.rs):
| 子命令 | 行为 |
|---|---|
| (无参数) | 提示此为 foundation,引导 --help |
dump-manifests | 对 当前工作区 调用 extract_manifest,打印 命令/工具/phases 数量 |
bootstrap-plan | 打印 BootstrapPlan::claude_code_default()(runtime 内 完整阶段骨架) |
--help | 使用说明 |
注意:bootstrap-plan 当前打印的是 runtime 中写死的「全阶段列表」,而 dump-manifests 里报告 bootstrap phases 数量 时用的是 extract_bootstrap_plan(cli.tsx) 的 启发式子集。二者 源码未完全统一,符合「脚手架阶段」常见情况:一个命令展示「目标模型」,另一个展示「从上游扫出来的近似」。后续可改为 bootstrap-plan 也走 extract_manifest 或并列输出,便于对齐。
6. 测试作为「活文档」与回归护栏
compat-harness 内集成测试(见 lib.rs``#[cfg(test)]):
- 从 本仓库
fixture_paths()读真实commands.ts/tools.ts。 - 断言 非空 manifest。
- 断言 已知符号(如
addDir、review、AgentTool、BashTool)存在,且 不会像字面量那样误提INTERNAL_ONLY_COMMANDS。
借鉴:不 snapshot 整个列表(避免上游小改导致海量 diff),而用 最小护栏(非空 + 锚点符号)平衡 稳定性与维护成本。
7. 工作空间工程质量
resolver = "2"、统一 edition / license / publish。- workspace lint:
unsafe_code = forbid(rust/Cargo.toml):与安全文化一致,harness 也不偷偷unsafe。
8. 可借鉴点(针对类似「从 TS/JS 大单体迁 Rust/Go」的项目)
- 接缝优先的 crate 切分
先对齐 产品已存在的模块名(commands / tools / bootstrap),而不是按 Rust 书上的分层 重命名,减少团队沟通成本。 - 「抽取器」与「领域类型」分离
commands、tools只放 registry 数据结构;文件 IO + 启发式解析 放在compat-harness。将来换解析实现, 下游类型稳定。 - 证明工件跑在 CI
小测试 + 一个dump-manifests式命令,让 「还能读懂上游 registry」 成为 合并门禁,早于重写运行时。 - 显式来源标签
Builtin/InternalOnly/FeatureGated与Base/Conditional让 同一符号在不同构建下的可见性 有地方表达,便于以后生成文档或与新运行时对齐。 - 接受「廉价启发式」的第一版
在 AST 投入 之前,用行级规则快速 覆盖 80% manifest;文档里写清 脆弱点(格式重写、feature()行文变化)。 - DAG 依赖、零环
commands⊥tools避免 类型泥球;大项目上这种依赖纪律 后期收益大。 - 里程碑话术
README 明确 harness-first ≠ feature parity,管理 干系人预期,避免 harness 被误当成「已可替换」。
9. 局限与后续方向(客观描述)
- 无 Anthropic API、无 QueryEngine、无 Ink/UI:Rust 层 不参与 主产品运行路径。
- 抽取 不验证:TS 能否编译、import 是否解析成功、
feature()是否 DCE。 bootstrap-plan与extract_bootstrap_plan输出 未统一(见 §5),属于可改进的工程细节。- 上游若 重命名 registry 文件 或 改成动态注册表,需同步更新
UpstreamPaths与解析规则。
10. 与仓库内其它文档的关系
rust/README.md:里程碑与命令行用法(权威简短版)。ARCHITECTURE.md:全仓库 TS + Rust 关系总览。- 若扩展 harness,宜在
rust/README.md更新里程碑,而非仅改本文。
基于 rust/README.md、rust/crates/*/src/lib.rs、rusty-claude-cli/src/main.rs、rust/Cargo.toml 整理。