十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

get-shit-done `gsd-tools` JSON 结构化错误模式(--json-errors)完整指南:从线格式、错误码分类到测试断言实践

get-shit-done `gsd-tools` JSON 结构化错误模式(--json-errors)完整指南:从线格式、错误码分类到测试断言实践 get-shit-donegsd-toolsJSON 结构化错误模式--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-doneget-shit-done 为gsd-toolsCLI 内置了一套JSON 错误模式JSON Error Mode开启后任何错误都会以单行结构化 JSON 写入 stderr而不是自由文本。本文围绕 docs/json-errors.md 展开讲解其激活方式、wire 格式、错误码分类error code taxonomy、如何在测试中按类型断言以及如何为系统新增一个错误码——并深入对应源码core.cjs、gsd-tools.cjs与测试实现feat-3255-json-errors-mode.test.cjs让读者既可直接上手调用也能理解其底层设计动机。JSON 错误模式是什么为什么要用它gsd-tools是 get-shit-done 的 CLI 工具层入口文件 头注释将其定位为“CLI utility for GSD workflow operations”集中承载了配置解析、模型解析、phase 查找、git 提交、summary 校验等约几十个原子命令与命令族。在默认模式下error()会把Error: message这样的自由文本写到 stderr——对人友好但对测试与自动化工具不友好断言一个错误只能对原始文本做子串匹配或正则匹配而文本内容随时可能被改写。JSON 错误模式正是为程序化消费方设计的结构化表面错误对象携带类型化错误码typed reason code测试与工具可以稳定地断言错误类型无需对 stderr 原始文本做grep/.includes()/正则规避了脆弱匹配这是仓库测试规范的推荐表面对应 CONTRIBUTING.md 中Prohibited: Raw Text Matching on Test Outputs一节的强制要求。从源码看这一能力最初随 issue #2974 落地冻结枚举注释、测试文件头部均引用该编号随后在 #3255 中补全了模式开关与测试覆盖并在 #3310 中把检测时机提前到所有 flag 解析之前确保连--cwd与 workstream 解析失败也能输出结构化 stderr。激活方式两种开关各有用武之地JSON 错误模式既可以通过命令行 flag 开启也可以通过环境变量开启两种方式的底层效果完全一致都会调用core.setJsonErrorMode(true)# 方式一命令行 flag测试代码中推荐 node gsd-tools.cjs --json-errors command [args] # 方式二环境变量shell 包装与 CI 推荐 GSD_JSON_ERRORS1 node gsd-tools.cjs command [args]flag 的解析时机在一切错误发生之前--json-errors的检测在 gsd-tools.cjs 中处于最优先位置——在进入任何命令分发、--pick/--cwd等 flag 解析之前完成const jsonErrorsIdx args.indexOf(--json-errors); if (jsonErrorsIdx ! -1) { core.setJsonErrorMode(true); args.splice(jsonErrorsIdx, 1); } else if (process.env.GSD_JSON_ERRORS 1) { core.setJsonErrorMode(true); }代码中有三点值得注意的设计先从 argv 中剔除该 flag。如果不splice调度器后续会把--json-errors当成一个未知命令文档给出的命令形态node gsd-tools.cjs --json-errors commandflag 在前正是依赖这一步。提前检测是为了全链路结构化。即使--cwd path传入的目录不存在、甚至 workstream 解析失败也已经在 JSON 模式下产生的仍是结构化 stderr源码注释中明确指向 #3310。默认关闭。core.cjs中_jsonErrorMode默认false普通人类用户的操作始终拿到的是可读的纯文本诊断信息getJsonErrorMode/setJsonErrorMode定义见 core.cjs结构化形式是按需启用的不影响既有调用方。Wire 格式与字段契约发生任何错误时进程只向stderr写入恰好一行JSON然后以退出码1结束{ ok: false, reason: error_code, message: human text }字段契约如下表字段类型说明okfalse错误对象中恒为false。reasonstring来自下方错误码分类的类型化错误码稳定可断言。messagestring人类可读的错误描述可能变动不要对其断言。底层实现error() 如何切换两种输出reason的默认兜底与输出逻辑都收敛在 core.cjs 的error()函数中function error(message, reason ERROR_REASON.UNKNOWN) { if (_jsonErrorMode) { const payload JSON.stringify({ ok: false, reason, message }) \n; fs.writeSync(2, payload); } else { fs.writeSync(2, Error: message \n); } process.exit(1); }要点reason是error()的第二个参数缺省为ERROR_REASON.UNKNOWNJSON 模式下通过fs.writeSync(2, ...)同步阻塞写入单行 payload 后再process.exit(1)避免管道场景下异步 stdout/stderr 缓冲未被消费就退出进程对象顶层结构恰好是{ok, reason, message}三个键无多余字段——这在测试中被显式验证见下文“单次调用只输出一行”。当命令经由 SDK bridge 转发时SDK 侧带.reason的GSDError也会把类型化错误码透传回error()见 gsd-tools.cjs 的_dispatchNonFamily注释点名了config_key_not_found这类 reason 的透传链路涉及 Bugs #2943、#3086确保跨 CJS/SDK 分发的错误码不退化回unknown。错误码分类Error Code Taxonomy错误码是定义在 core.cjs 中ERROR_REASON冻结常量对象的全小写 snake_case 字符串const ERROR_REASON Object.freeze({ // config-get / config-set CONFIG_KEY_NOT_FOUND: config_key_not_found, CONFIG_NO_FILE: config_no_file, CONFIG_PARSE_FAILED: config_parse_failed, CONFIG_INVALID_KEY: config_invalid_key, // SDK / gsd-tools dispatch SDK_FAIL_FAST: sdk_fail_fast, SDK_UNKNOWN_COMMAND: sdk_unknown_command, SDK_MISSING_ARG: sdk_missing_arg, // workflow / phase PHASE_NOT_FOUND: phase_not_found, SUMMARY_NO_PLANNING: summary_no_planning, // graphify GRAPHIFY_NO_GRAPH: graphify_no_graph, GRAPHIFY_INVALID_QUERY: graphify_invalid_query, // hooks HOOKS_OPT_OUT: hooks_opt_out, // security-scan SECURITY_SCAN_FAILED: security_scan_failed, // generic USAGE: usage, UNKNOWN: unknown, });该对象通过Object.freeze冻结防止运行时被篡改命名上按子系统前缀分组CONFIG_*、SDK_*等并在 gsd-tools.cjs 顶部随core一起导出core.cjs。下面是文档给出的完整发射场景对照。Dispatch 错误gsd-tools 路由层Code发射时机sdk_unknown_command未知顶层命令gsd-tools bogus-cmdsdk_unknown_command未知点分命令gsd-tools foo.bar其中foo不是已知命令sdk_unknown_command域内未知子命令如gsd-tools intel bogus-subsdk_missing_argSDK 层守卫发现缺少必填参数sdk_fail_fast触发 SDK fail-fast 策略补充在 gsd-tools.cjs 的命令路由里多个命令族如template、frontmatter、requirements、milestone对未知子命令统一用error(Unknown ... subcommand. Available: ..., ERROR_REASON.SDK_UNKNOWN_COMMAND)抛错这与上表“域内未知子命令”行相互印证。Usage / flag 错误Code发射时机usage--pickflag 后未跟值usage版本 flag--version、-v——gsd-tools永不接受usage顶层无参调用打印 usage 文本源码佐证在 gsd-tools.cjs 中--pick后缺值会调用error(Missing value for --pick, ERROR_REASON.USAGE)NEVER_VALID_FLAGS集合--version/-v命中后调用error(..., ERROR_REASON.USAGE)。之所以显式拒绝版本 flag是因为 AI Agent 偶尔会幻觉出--version静默忽略可能让破坏性操作在未经确认的情况下继续执行源码注释 #3019 附近的说明而--help类 flag 则被单独提前处理渲染 usage 后以 0 退出。Config 错误config-get、config-set、config-ensure-sectionCode发射时机config_key_not_foundconfig-get查询配置文件中不存在的键config_no_file配置文件.planning/config.json不存在时执行配置操作config_parse_failed配置文件存在但不是合法 JSONconfig_invalid_keyconfig-set写入白名单之外的键实践提示若要稳定触发config_key_not_found分支需先执行config-ensure-section初始化出配置文件否则会落入config_no_file分支这正是 feat-3255-json-errors-mode.test.cjs 的做法。Phase / workflow 错误Code发射时机phase_not_foundphase 目录查找无匹配summary_no_planning不存在.planning/目录时执行 summary 操作Graphify 错误Code发射时机graphify_no_graph尚未构建 graph 时执行 graphify query 或 diffgraphify_invalid_querygraphify query 携带格式错误的查询串Hook / 安全错误Code发射时机hooks_opt_out通过 opt-out 配置禁用了 hookssecurity_scan_failed安全扫描产生阻断性 finding兜底Code发射时机unknown所有未显式分配具体 reason code 的其他错误测试断言规范解析后按类型断言绝不匹配原始文本JSON 错误模式存在的根本目的是服务测试。文档给出的正确/错误写法对照如下// CORRECT: 先 JSON.parse 再断言类型化字段 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: 文本匹配被 lint-no-source-grep 策略禁止 // assert.ok(result.error.includes(Unknown command));其制度性根源在 CONTRIBUTING.md 的Prohibited: Raw Text Matching on Test Outputs一节无论文本来自源码文件、渲染产物、子进程 stdout 还是自由格式的reason字符串对被测系统产出的文本做子串/正则匹配一律禁止。该节给出了一组典型违规样例对.cmd内容做.includes、对 stdout 做assert.match、用“结构化解析器”包装字符串操作、对 JSON 报告中自由格式的reason做正则等并总结了规则表输出类型要求的结构化表面测试断言的依据CLI 人类可读格式化输出提供--json模式结构化地输出同一份数据report.results[0].reason REASON.FAIL_X错误 / 状态 / reason冻结枚举Object.freeze({ FAIL_X: fail_x, ... })assert.equal(result.reason, REASON.FAIL_X)其核心规则可概括为如果被测代码产出文本被测代码必须同时暴露一个类型化的结构化中间表示测试只断言该 IR绝不针对渲染后的文本。--json-errors正是error/reason这一行“结构化的 IR”在 CLI 边界的承载者测试则一律JSON.parse(stderr)后断言ok/reason字段。官方测试如何验证这套契约feat-3255-json-errors-mode.test.cjs 是该模式的专项测试其辅助函数runJsonErrors先把--json-errors拼到参数最前然后断言进程失败、并强制要求 stderr 可被JSON.parse解析否则直接抛出“必须输出合法 JSON”的错误。它覆盖了十个典型分支未知顶层命令 →sdk_unknown_command未知点分命令foo.bar→sdk_unknown_command--pick缺值 →usageconfig-get缺失键先跑config-ensure-section初始化→config_key_not_found域内未知子命令intel bogus-subcommand-xyzzy→sdk_unknown_commandGSD_JSON_ERRORS1环境变量产出与 flag 相同的结构化错误成功命令不受--json-errors影响generate-slug hello-world依旧成功、stdout 非空错误对象恰好只有{ok, reason, message}三个顶层键无多余字段单次调用只输出一行 JSON进程在首个错误处即退出未知版本 flag--version→usage。第 6 条验证了环境变量路径与 flag 路径的等价性第 8、9 条把“wire 格式”从文档承诺固化成了可回归的机器约束。仓库中的runGsdTools测试辅助函数tests/helpers.cjs负责在临时项目目录中启动真实 CLI 进程并收集 stdout/stderr测试可直接复用。如何新增一个错误码如果需要为某个新错误路径提供结构化码按文档给出的四步走在 core.cjs 的ERROR_REASON中新增常量——取值使用snake_case 小写并按子系统前缀分组命名如CONFIG_*、SDK_*、PHASE_*。常量名与 wire 值是两个东西常量名是源码内引用句柄wire 值是reason字段实际出现的字符串。在调用点把它作为error()的第二个参数传入例如error(some message, ERROR_REASON.YOUR_NEW_CODE)若省略该参数会自动落到unknown兜底码。在本错误码分类文档中补一行更新 docs/json-errors.md 对应分组表格。新增一个测试通过--json-errors运行并JSON.parse(stderr)断言新的reason值。遵循这些约定后新错误码会自动具备稳定可断言的语义上层工具无需解析自然语言即可判断“哪类操作失败了”而message字段仍可自由演进以优化人类可读性两者互不耦合。结语结构化错误的收益边界把gsd-tools的错误输出从“给人看的一段话”升级为“给机器读的一行 JSON”换来的是测试与自动化链路的确定性稳定性契约清晰reason冻结在 core.cjs 的ERROR_REASON枚举中断言reason而非message文本可自由演进人类文案的润色、格式重排不再破坏任何消费方纯文本诊断保留模式默认关闭人机两套输出互不干扰error()在 core.cjs 中一条函数同时服务两种形态。对于希望稳健消费gsd-tools的测试套件、CI 脚本或封装工具请把--json-errors或GSD_JSON_ERRORS1当作标准姿势先JSON.parse(stderr)再对reason做相等断言并克制住对错误文本做.includes()的冲动——这正是本仓库 test-output 规范的核心理念。【免费下载链接】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),仅供参考
返回列表