get-shit-done v1.39.0-rc.5 技术解读:Codex hooks 配置迁移加固与 --minimal 轻量安装
get-shit-done(下称 GSD)是一套面向 Claude Code / OpenCode / Gemini / Codex 等 AI 编程运行时(runtime)的 meta-prompting、上下文工程与规格驱动开发系统。本文围绕其 v1.39.0-rc.5 预发布版本说明展开,聚焦本版本在 Codex 配置迁移器(hooks migrator)上的正确性加固,并回溯 rc.4 一并带入正式版的 --minimal 轻量安装模式 与 Codex 安装防损坏保护。读完你将能复现预发布安装流程,理解 GSD 如何安全改写 ~/.codex/config.toml 的 hooks 结构,以及如何针对小上下文窗口的本地大模型做裁剪安装。
一、版本背景:next 标签下的预发布节奏
GSD 采用严格的发布流水线:正式版发布前,先在 release 分支上产出 Release Candidate(RC),以 npm 的 next 标签对外发布,供使用者做真实环境验证。v1.39.0-rc.5 即处在这一阶段,其版本说明明确标注:
Pre-release candidate. Published to npm under the
nexttag.
对应的最新安装入口为:
npx get-shit-done-cc@next
需要说明的是,本仓库已演进至更高的版本号(当前 package.json 中的版本为 1.50.0-canary.0),因此这份 rc.5 说明属于历史快照。但其中涉及的安装器实现(bin/install.js)至今仍是 GSD 的核心交付物,后续版本的所有相关能力都建立在本版本打磨出的正确性地基之上。
rc.5 的内容包含两部分:一是 rc.5 本轮新增的 Codex hooks 迁移器加固(#2809);二是随 rc.4 发布、同样属于本次测试范围的 --minimal 安装标志(#2762) 与 Codex 安装防损坏修复(#2760)。
二、rc.5 核心修复:Codex hooks 迁移器的五轮加固(#2809)
2.1 背景:两层嵌套 hooks schema 迁移
Codex 0.124.0 将 hooks 配置从 map 格式迁移到 array-of-tables(AoT)格式,并且 GSD 需要把托管 hook 写成 [[hooks.<Event>]] → [[hooks.<Event>.hooks]] 的两层嵌套结构。安装器在每次安装/重装/卸载时都要把用户既有配置安全迁移到这一新 schema。rc.4 中的修复(#2760)已经覆盖了 [hooks.<Event>] map 格式与 [[hooks]] 扁平 AoT 格式,而 rc.5 的 #2809 则针对迁移路径上的 五个边界情形 做了收尾加固——这些情形是在五轮 code review 中逐一发现的,全部围绕"TOML 语法解析的严谨性"展开:
| 发现的问题 | 修复方式 |
|---|---|
parseHooksBody 使用裸正则 /^([\w.]+)\s*=/,会静默丢弃连字符键(如 status-message)与任何带引号的 TOML 键 |
替换为既有的完整 TOML 键解析器 parseTomlKey() |
buildNestedBlock 无条件发射 [[hooks.TYPE.hooks]],即使没有任何 handler 字段,也会产生"只有 type = "command"、没有 command"的脏条目 |
增加守卫:仅含 matcher / 无 handler 字段的段只发射事件条目块 |
legacyMapSections 的过滤条件是 section.path.startsWith('hooks.'),未检查段数,导致 [hooks.SessionStart.hooks] 这类三段表被误判为事件条目,被当作假的嵌套事件重新发射 |
改为 section.segments.length === 2(与之前应用于 staleNamespacedAotSections 的修复一致) |
缺少对含点号的事件名的回归测试——[[hooks."before.tool"]] 的路径是 2 段,但 split('.') 会得到 3 部分,误判其类型 |
补充回归测试;带引号含点名称被正确视为单个两段命名空间 |
安装测试中的 handler 命令路径断言使用正则(/gsd-check-update\.js/),而非精确绝对路径 |
强化为 assert.strictEqual + path.join(codexHome, 'hooks', 'gsd-check-update.js') |
2.2 源码视角:修复为何关键
上述五项修复的本质,是 用真正的 TOML 词法解析取代字符串近似匹配。在 bin/install.js 中可以看到这一整套解析基础设施:
- parseTomlKeyPath:逐字符解析 TOML 键路径,支持单引号/双引号键、
\转义与点号分隔,返回语义上的段(segment)数组,例如[[hooks."before.tool"]]解析出['hooks', 'before.tool']; - parseTomlKey:在赋值语句(含
=)上提取键名,先排除表头,再走parseTomlKeyPath,因此status-message这类连字符键和"quoted key"都能被正确识别——这正是修复表中第一行"弃裸正则、改用parseTomlKey"的落点; - 解析函数注释中明确写到了第三、四行修复的设计动机(见 parseTomlTableSection 相关注释):保留真实的段计数,避免用
split('.')之类按点号切分的方法误判含点号的带引号键名。
2.3 迁移函数的整体守卫逻辑
迁移主入口是 migrateCodexHooksMapFormat,它一次性处理三类遗留形态:
- map 格式的
[hooks.TYPE]表(legacyMapSections 过滤逻辑):要求!section.array、hooks.前缀、且section.segments.length === 2,并显式排除 Codex 的持久化 hook-trust 命名空间hooks.state(Codex CLI 0.130.0+ 引入,永不使用 AoT 形态); - 扁平的
[[hooks]]AoT 条目(flatAotSections):与[[hooks.<Event>]]命名空间形态在同一个 TOML 文件中互斥(hooks不能同时是数组又是表),因此按event键取出事件名并改写成嵌套形态; - 过时的单块
[[hooks.TYPE]](staleNamespacedAotSections):事件条目级直接携带 handler 字段、却没有[[hooks.TYPE.hooks]]子表——这是 Codex 0.124.0+ 会拒绝的旧形态。
对于处理结果(buildNestedBlock),它先用 tomlBareKey 对事件名做键名合法性判断(凡含非 [A-Za-z0-9_-] 字符的事件名一律转成带引号键),再执行第二项修复的守卫:只有当确实存在 handler 字段时才发射 [[hooks.TYPE.hooks]] 子表,否则只发射事件条目块,从源头杜绝"有 type 没 command"的半成品条目。
最后,迁移块的插入位置也遵循 TOML 语法约束(注释见 bin/install.js):map 格式块插入到首个剩余表之前以保留文件相对顺序,而扁平 AoT 块一律 追加到文件末尾——因为 AoT 不能出现在普通表之前,若插到文件头部会破坏 [features] / [model] 等的相对顺序。
2.4 代码级注意点:#3346 的防呆设计
在迁移逻辑中还有一条值得注意的细节:当遗留 [hooks.<X>] 的正文里显式声明了 event = "..." 时,以该 event 值为事件名叶子键(mapOnlyBlocks 逻辑)。原因在于 Codex pre-AoT 时代会把 <file>:<event>:<line>:<col> 这样的位置标识符写成表键,若原样把路径段当作叶子事件名发射,会产生 Codex 0.124.0+ 拒绝的非法 TOML 键链——这是安装器对"历史配置里藏着非语义键名"的又一次防御。
三、rc.4 新增能力:--minimal 轻量安装标志(#2762)
3.1 作用与适用人群
--minimal(别名 --core-only)只安装支撑主工作流闭环所需的六个核心技能:
new-project、discuss-phase、plan-phase、execute-phase、help、update
且不安装任何 gsd-* 子代理(subagent)。版本说明给出的冷启动系统提示词开销对比如下:
| 模式 | 冷启动系统提示词开销 |
|---|---|
| full(默认) | 约 12k tokens |
| minimal | 约 700 tokens |
这一模式针对的是 上下文窗口 32K–128K 的本地 LLM:在这类模型上,完整技能面(full surface)的固定提示词开销占比过高,裁剪到 minimal 后可以把宝贵的上下文预算让给实际任务内容。而使用 Sonnet 4.6 / Opus 4.7 的云端模型用户通常并不需要它——完整技能面才是云端模型的正确默认。
3.2 安装清单记录与升级路径
安装清单(manifest)会记录本次安装模式:
mode: "minimal" | "full"
该字段在源码中的写入位置是 writeManifest 的 manifest 对象(bin/install.js),mode 由 options.mode === 'minimal' 决定。清单哈希覆盖 get-shit-done/、commands/gsd/ 以及各运行时技能目录,用于后续安装时的差异检测。
由于模式被持久化记录,升级/扩容也很直接:在任意时刻运行不带 --minimal 的 gsd update,即可把 minimal 安装扩容到完整技能面,无需重装。
3.3 实现细节与后续演进
在 bin/install.js 中,参数解析把 --minimal 与 --core-only 视为等价:
const hasMinimal = args.includes('--minimal') || args.includes('--core-only');
安装器帮助文本(bin/install.js)同样声明 --minimal 是 --profile=core 的向后兼容别名,并给出冷启动开销从约 12k 降到约 700 的效果说明;若同时传入 --minimal 与 --profile=<name>,则直接报错退出,二者互斥。
值得注意的是,这套能力在后继版本中已演进为可组合的 profile 体系:在 get-shit-done/bin/lib/install-profiles.cjs 中,PROFILES 定义了 core、standard、full 三档(install-profiles.cjs),支持 --profile=core,audit 取并集的组合安装;MINIMAL_SKILL_ALLOWLIST 直接由 PROFILES.core 派生(install-profiles.cjs)。当前仓库中的 core 档已包含 8 个技能(在 rc.4 的 6 个基础上并入 phase、surface 等),且安装器会记录 profile 并让 gsd update 尊重该选择——这是 rc.4 时代"6 技能严格白名单"向后兼容的自然延伸。
四、rc.4 防御性修复:Codex 安装不再损坏 ~/.codex/config.toml(#2760)
在 --minimal 之外,rc.4 的另一项重头戏是让 Codex 安装具备"要么成功、要么完好回滚"的事务性语义。版本说明列出的安装器行为包括:
- 无条件清除遗留的
[agents](单括号)与[[agents]](sequence)块——无论是否存在 GSD 标记,这两者在当前 Codex TOML schema 中都非法; - 沿用用户既有配置形态发射 GSD 托管 hook:若既有配置使用
[[hooks.<Event>]]命名空间 AoT 形态则沿用之,否则写顶层[[hooks]]; - 迁移过程中把遗留
[hooks.<Event>](map 格式)改写为[[hooks.<Event>]](数组格式); - 原子写入:先写临时文件再
renameSync,杜绝半截写入; - 写后校验:用严格 TOML 解析器验证写后字节,拒绝重复键、重复表头、值后的尾随字节以及不支持的值类型;
- 失败回滚:任何写前或写时失败都会恢复安装前快照并以清晰错误中止,而不是"警告后继续"。
这些行为并非纸面承诺,tests/bug-2760-codex-install-defensive.test.cjs 对其做了成体系的回归验证,覆盖场景包括:全新安装发射两层嵌套 AoT schema、保留用户既有 [[hooks.SessionStart]] 条目同时把 GSD 托管 handler 注册进 hooks.json、重装时把扁平 [[hooks]] + event 与单块 [[hooks.SessionStart]](无 .hooks 子表)统一替换为嵌套 schema、卸载后残留状态校验、以及空配置文件的合法性校验。
针对"破坏文件"这一最坏情形,测试还专门模拟了写入失败路径:
- 当
fs.renameSync对configPath抛错时,断言安装前配置字节原样保留; - 当对
.tmp-目标执行fs.writeFileSync抛错时,同样断言快照恢复且无.tmp-残留文件(见该测试文件中#2760 fix 4 — Write-failure rollback (atomic write + snapshot restore)一节)。
由此,Codex 安装被收敛为一个可证明的原子操作:破坏性写入之前先留快照,写入失败立即还原,写入成功后还有严格 schema 校验兜底。
五、rc.5 修复在回归测试中的落点
rc.5 表里第五行提到"handler 命令路径断言改用精确绝对路径",这类测试断言的强化同样可以在仓库中找到对应物。Codex hooks 形态的安装/重装/卸载端到端断言大量出现在 bug-2760-codex-install-defensive.test.cjs 中,其中对 gsd-check-update.js 处理器的校验通过 path.join(codexHome, 'hooks', 'gsd-check-update.js') 组合出的绝对路径来 assert.strictEqual 精确比对,避免正则把相似路径误判为合法安装。rc.4→rc.5 的治理逻辑一脉相承:先让解析器严格,再让测试严格,两端都堵住"看起来对、实际错"的漏洞。
六、安装与验证预发布版本
若你需要在支持 next 标签期间验证该预发布:
# npm 全局安装 next 标签下的最新 RC
npm install -g get-shit-done-cc@next
# npx 一次性执行(不落盘全局)
npx get-shit-done-cc@next
精确锁定本 RC:
npm install -g get-shit-done-cc@1.39.0-rc.5
对安装了 Codex 的用户,建议在升级前备份 ~/.codex/config.toml,安装后留意安装器是否按"既有形态"写回 hook;对本地小上下文模型用户,可用 --minimal(或 --core-only)体验裁剪安装,随后任意时刻运行不带该标志的 gsd update 即可扩容到完整技能面。
七、发布流水线中的"接下来"
按照版本说明,rc.5 之后的发布管理动作完全由发布流水线驱动:
- 若在正式定稿前还有新修复落入 release 分支,则在发布分支上再次执行
rc,产出 rc.6; - 当 RC 稳定后,在 release workflow 上执行
finalize,将1.39.0提升到 npmlatest标签。
这种"RC 滚动 + finalize 晋升"的机制保证了正式版只会携带经过多轮审查、且被严格 TOML 解析与故障注入测试覆盖的变更——rc.5 对 Codex hooks 迁移器的五处修复,正是这种质量闸门发挥作用的具体样本。
八、小结:从一次 RC 看安装器的工程底线
v1.39.0-rc.5 体量虽小,却浓缩了安装器类工程最重要的三条原则:
- 解析要语义化,不做字符串近似:TOML 键含连字符、引号、点号是常态,只有走 parseTomlKey 这类词法级解析,才能保证迁移不丢键、不误判段(install.js);
- 写入要原子化,失败要可回滚:临时文件 +
renameSync+ 写后严格校验 + 快照恢复,让安装要么改变一切、要么什么都不改变; - 覆盖面要按运行时取舍:
--minimal与 profile 体系让"全量技能面"与"低冷启动开销"不再互斥,而是同一安装器在不同上下文预算下的可切换姿态。
对需要深度定制或审计安装器的开发者,bin/install.js、get-shit-done/bin/lib/install-profiles.cjs 及其回归测试 bug-2760-codex-install-defensive.test.cjs、install-minimal-hooks.test.cjs 是值得逐行研读的范本。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0629
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
HivisionIDPhotos⚡️HivisionIDPhotos: a lightweight and efficient AI ID photos tools. 一个轻量级的AI证件照制作算法。Python07
DragonOSDragonOS is an operating system developed from scratch using Rust, with Linux compatibility. It is designed for **Serverless** scenarios. 使用Rust从0自研内核,具有Linux兼容性的操作系统,面向云计算Serverless场景而设计。Rust00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00