news 2026/9/11 5:04:49

get-shit-done 的 gsd-tools --json-errors 如何输出稳定错误码供脚本断言

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
get-shit-done 的 gsd-tools --json-errors 如何输出稳定错误码供脚本断言

get-shit-done 的 gsd-tools --json-errors 如何输出稳定错误码供脚本断言

【免费下载链接】get-shit-doneA light-weight and powerful meta-prompting, context engineering and spec-driven development system for Claude Code by TÂCHES.项目地址: https://gitcode.com/GitHub_Trending/getshi/get-shit-done

当你在测试或 CI 脚本中调用 get-shit-done 的gsd-toolsCLI 时,错误默认以Error: <text>的自由文本写到 stderr。这类文本措辞可能随版本变化,对原始错误串做.includes()或正则匹配会让断言在无害的文案改动上误报、又对真正的错误漏报。gsd-tools内置的 JSON error mode 解决了这个问题:开启后,所有错误以一条结构化 JSON 写到 stderr,其中reason字段是冻结的常量错误码,脚本可以稳定地断言它。本文适用于本仓库的gsd-toolsCLI(入口文件位于 get-shit-done/bin/gsd-tools.cjs),运行环境要求 Node 22 及以上(CONTRIBUTING.md 明确 Node 22 为最低支持版本,Node 24 是主要 CI 目标)。

准备条件

  • Node 22 或更高版本(Node 24 为主 CI 目标;不要使用 Node 22 之外的 API)。
  • 仓库中的gsd-tools入口文件是 get-shit-done/bin/gsd-tools.cjs。docs/json-errors.md 中的示例命令写作node gsd-tools.cjs ...,即在文件所在目录内运行;在仓库根目录执行时等价写法为node get-shit-done/bin/gsd-tools.cjs ...
  • 错误码定义在 get-shit-done/bin/lib/core.cjs 的ERROR_REASON冻结枚举中,断言前先核对该文件确认当前代码集合。

开启 JSON error mode

两种方式任选其一,均为 opt-in,默认关闭,关闭时人类操作者看到的仍是Error: <message>纯文本:

# Flag(测试代码中推荐): node gsd-tools.cjs --json-errors <command> [args] # Env var(shell 包装器与 CI 推荐): GSD_JSON_ERRORS=1 node gsd-tools.cjs <command> [args]

两个实现细节值得注意(见 get-shit-done/bin/gsd-tools.cjs 中的处理逻辑):

  • --json-errors在任何 flag 解析之前被检测并从 argv 中移除,因此它不会被路由器当作未知命令处理,且--cwd或 workstream 解析阶段的失败也会走结构化 stderr。
  • 该标志只改变错误输出形式,对成功命令没有任何影响:成功的命令照常以退出码 0 结束,stdout 内容不变。

错误输出的线格式

任何错误发生时,进程向stderr恰好写一行 JSON 并以退出码1退出:

{ "ok": false, "reason": "<error_code>", "message": "<human text>" }
字段类型说明
okfalse错误对象恒为false
reasonstring下文分类表中的类型化原因码,稳定,应断言这个字段。
messagestring人类可读描述,可能变化,不要断言它

tests/feat-3255-json-errors-mode.test.cjs 锁定了三条可复用的形状契约:错误对象顶层恰好是{ok, reason, message}三个键(无额外键);每次调用 stderr 只有一行 JSON(进程在第一个错误时退出);成功命令不受--json-errors影响。实现位于 get-shit-done/bin/lib/core.cjs 的error()函数:JSON 模式下error(){ ok: false, reason, message }序列化后写入 stderr 并process.exit(1)

稳定错误码分类

reason的取值是get-shit-done/bin/lib/core.cjsERROR_REASON的冻结常量(snake_case、按子系统加前缀分组)。docs/json-errors.md 的分类表如下:

Dispatch 错误(gsd-tools 路由层)

Code触发条件
sdk_unknown_command未知顶层命令(如gsd-tools bogus-cmd)、未知点分命令(gsd-tools foo.barfoo不是已知命令)、域内未知子命令(如gsd-tools intel bogus-sub
sdk_missing_argSDK 层守卫判定必填参数缺失
sdk_fail_fast触发 SDK fail-fast 策略

用法 / flag 错误

Code触发条件
usage--pick后缺少值;gsd-tools 不接受的版本 flag(--version-v);顶层无参数调用

Config 错误(config-getconfig-setconfig-ensure-section

Code触发条件
config_key_not_foundconfig-get的键不存在于配置文件
config_no_file配置操作时.planning/config.json不存在
config_parse_failed配置文件存在但不是合法 JSON
config_invalid_keyconfig-set的键不在允许白名单内

Phase / workflow 错误

Code触发条件
phase_not_foundPhase 目录查找无匹配
summary_no_planning.planning/目录时执行 summary 操作

Graphify 错误

Code触发条件
graphify_no_graph未构建 graph 时执行 graphify 查询或 diff
graphify_invalid_querygraphify 查询串格式错误

Hook / 安全错误

Code触发条件
hooks_opt_outHooks 被 opt-out 配置禁用
security_scan_failed安全扫描产出了阻断操作的发现

兜底

Code触发条件
unknown所有未分配具体原因码的其他错误

SDK 路由层的结构化原因会透传到 CJS 层(gsd-tools.cjs将 SDK 返回的errorDetails.reason传给error()),因此经 SDK 路径失败的命令(如config-get)同样能拿到具体代码(如config_key_not_found)而不是笼统的unknown

在脚本中写断言

docs/json-errors.md 的规则:始终用JSON.parse解析 stderr 并断言类型化字段,绝不对原始错误串使用.includes().match()或正则。CONTRIBUTING.md 的 "Prohibited: Raw Text Matching on Test Outputs" 一节将此列为仓库级禁令(由scripts/lint-no-source-grep.cjs策略强制执行)。

文档给出的正确写法(摘自 docs/json-errors.md):

// CORRECT: parse then assert on typed field const result = runGsdTools(['--json-errors', 'bogus-command'], tmpDir); assert.strictEqual(result.success, false); const err = JSON.parse(result.error); assert.strictEqual(err.ok, false); assert.strictEqual(err.reason, 'sdk_unknown_command'); // WRONG: text matching (banned by lint-no-source-grep policy) // assert.ok(result.error.includes('Unknown command'));

其中runGsdTools是本仓库测试 helper(见 tests/helpers.cjs),返回包含successoutput(stdout)、error(stderr)字段的运行结果。tests/feat-3255-json-errors-mode.test.cjs 中的runJsonErrorshelper 展示了更严格的封装:先断言命令必须失败,再JSON.parse(result.error),解析失败时把完整 stderr 抛进错误信息——这样脚本在 wire 格式被破坏时能给出可读的诊断。

对于 shell 包装器与 CI,用文档给出的环境变量方式开启即可,后续对 stderr 的解析逻辑与 JS 侧相同:

GSD_JSON_ERRORS=1 node gsd-tools.cjs <command> [args]

验证方式:触发已知场景并核对 reason

以下"调用 → 预期 reason"组合均能在 tests/feat-3255-json-errors-mode.test.cjs 中找到对应测试用例,可直接作为你脚本中的断言目标:

调用(带--json-errors预期退出码预期reason
totally-unknown-command-xyzzy(任意未知顶层命令)1sdk_unknown_command
foo.bar(未知点分命令)1sdk_unknown_command
intel bogus-subcommand-xyzzy(域内未知子命令)1sdk_unknown_command
generate-slug test-text --pick--pick缺值)1usage
--version generate-slug x(gsd-tools 不接受--version1usage
config-get nonexistent_config_key_xyzzy(先执行过config-ensure-section建好.planning/config.json1config_key_not_found

对每次失败调用,完整断言链是:退出码为 1;stderr 能JSON.parse成功;ok === falsereason等于预期值;顶层键排序后恰好为['message', 'ok', 'reason'];非空 stderr 行恰好一条。对成功路径(如generate-slug hello-world),断言进程成功、stdout 非空,证明 flag 未污染正常输出。

扩展:新增一个错误码

docs/json-errors.md 的 "Adding a new error code" 给出固定四步流程(get-shit-done/bin/lib/core.cjs 中ERROR_REASON的注释与之一致):

  1. get-shit-done/bin/lib/core.cjsERROR_REASON中加常量,取值用 snake_case 小写(即 JSON 线上的形式),按子系统加前缀分组(如CONFIG_*SDK_*)。
  2. 在调用点把它作为error()的第二个参数传入:error(msg, ERROR_REASON.NEW_CODE)
  3. 在 docs/json-errors.md 的分类表中加一行。
  4. 加一个用JSON.parse断言新reason代码的测试。

四步同步变更是刻意设计:枚举、调用点、文档、测试任何一处遗漏都会导致代码面与测试面漂移被测试发现。

限制

  • message字段不稳定,任何对它的断言都会随文案改动失效;只有reason是稳定契约。
  • 模式默认关闭,且只影响错误输出;成功路径的行为与输出完全不变。
  • 错误码是冻结枚举,未分配具体码的错误落到unknown;你的脚本断言unknown时要意识到这是兜底而非具体原因。
  • 每次调用只输出第一处错误的 JSON 行,进程随即退出,stderr 不会有第二条错误。

【免费下载链接】get-shit-doneA light-weight and powerful meta-prompting, context engineering and spec-driven development system for Claude Code by TÂCHES.项目地址: https://gitcode.com/GitHub_Trending/getshi/get-shit-done

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/11 5:04:45

鸿蒙布局进阶:相对定位、懒加载列表与栅格多设备适配实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/11 5:02:56

多智能体系统核心架构与实战:从拓扑选型到工程避坑

上个月我负责的一个数据处理项目翻车了&#xff1a;四个智能体协作处理一批业务报表&#xff0c;结果两个智能体在“时间字段用什么格式”这个问题上反复争论&#xff0c;任务跑了整整六个小时&#xff0c;光token费用就抵得上一个初级员工一周的工资。复盘的时候我发现&#x…

作者头像 李华
网站建设 2026/9/11 5:02:04

100G UDP FPGA上板测试:系统级压力验证方法论

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/11 4:58:54

Hadoop distcp命令原理与大数据迁移实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华