ARTICLE DETAIL

资讯详情

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

gsd-core 家族路由器 `--raw` 标量输出修复解析:SDK 分发路径与 CJS 路径的语义对齐

gsd-core 家族路由器 `--raw` 标量输出修复解析:SDK 分发路径与 CJS 路径的语义对齐 【免费下载链接】gsd-coreGit. Ship. Done - Core项目地址https://gitcode.com/gh_mirrors/ge/gsd-core点击查看免费下载本篇技术文章基于.changeset/archived/fix-3631-sdk-raw-flag-routers.md这一变更记录深入剖析 gsd-core 中家族路由器family router在 SDK 分发路径下对--raw标志的语义对齐修复PR #3631。文章将说明该问题的成因、修复的三层机制、涉及的典型命令phase next-decimal、roadmap get-phase在源码中的实际实现以及仓库内对应的回归测试与实战用法帮助读者理解 gsd-core 统一命令输出契约的设计思路。一、变更记录概览修了什么.changeset/archived/fix-3631-sdk-raw-flag-routers.md记录了如下修复SDK dispatch path in family routers now honours--raw—phase next-decimal --raw、roadmap get-phase --raw以及其他通过 SDK bridge 路由的家族命令现在重新输出与 #3577 之前 CJS 路径完全一致的标量字符串。路由器在--raw下向 bridge 请求mode: rawsync-bridge worker 将formatNativeRaw接线到formatQueryRawOutput使 bridge 返回按命令投影per-command projection后的结果路由器随后将该格式化字符串交给output()的rawValue分支输出而不再经过 JSON 序列化。一句话概括同一个命令无论走 CJS 路径还是 SDK bridge 路径在--raw下都必须输出相同的、未经 JSON 包装的标量文本。二、背景--raw在 gsd-core 中的契约语义在深入修复细节之前先明确--raw在整个项目中的含义。gsd-core 的命令输出统一收敛在src/io.cts的output()函数上// src/io.cts#L174-L215 function output(result: unknown, raw: boolean, rawValue?: unknown): void { let data: string; if (raw rawValue ! undefined) { data String(rawValue); // --raw 且提供了投影值 → 直接输出标量字符串 } else { const json serializeForOutput(result); // 否则 JSON 序列化 if (json.length 50000) { // 大载荷写入临时文件输出 file: 前缀路径 ... } else { data json; } } writeAllSync(1, data); }这里可以读出三层设计意图rawtruerawValue提供直接以String(rawValue)输出绕过 JSON 编码。这正是工作流脚本所依赖的形态——例如gsd-core/workflows/plan-phase.md中MVP_MODE_CFG$(gsd_run query config-get workflow.mvp_mode --raw ...)拿到的是一个可直接用于比较的裸值而不是带引号的 JSON 字符串。rawtruerawValue为undefined按tests/io.test.cjs#L120-L130的测试约定回退到 JSON 输出例如check、workstream等命令在--raw下输出 JSON 属于预期行为。rawfalse始终 JSON 序列化。此外docs/adr/1411-resolution-provenance.md第 298 行起专门记录了一条决策——raw 模式 String(value)round-trip 属性只能在 JSON 模式成立raw 输出被冻结为字符串投影。也就是说--raw从不承诺结构化往返它只承诺按命令自己的投影输出人类/脚本可读的裸文本。三、问题成因SDK 分发路径丢失了rawValue投影修复前问题出在家族路由器的sdkHandler调用链上。回归测试文件tests/cjs-command-router-adapter.test.cjs从tests/bug-3631-router-raw-flag.test.cjs按整合史诗 #1969 折叠而来在注释中给出了精确的诊断Before the fix, every*-command-router.cjssdkHandlercalledoutput(result.data)without the second positionalrawargument or the third positionalrawValue. With--rawset, the SDK path therefore emitted JSON-stringified data ({next:2.1,...}) instead of the scalar the CJS path used to print (e.g.2.1).即底层 handlerCJS 侧明明已经计算出正确的标量投影并通过output(result, raw, rawValue)输出但 SDK bridge 这一层在转发时只把result.data交给了output()既没有传raw布尔位也没有传rawValue投影值。于是--raw被静默忽略输出退化为 JSON 对象——命令调用方如工作流脚本、Agent 管线拿到的就变成了{next:2.1}而不是2.1破坏了与 CJS 路径的输出一致性。这正是双路径CJS / SDK bridge共享同一命令语义但分发层各自实现输出转译时典型的漂移问题。四、修复方案三层机制恢复标量投影根据 changeset 的记录修复通过三层协作完成4.1 路由器层向 bridge 显式请求mode: raw家族路由器在检测到--raw时向 SDK bridge 请求mode: raw让 bridge 知道自己需要的是按命令投影后的原始文本而不是通用 JSON 载荷。4.2 sync-bridge worker接线formatNativeRaw→formatQueryRawOutputsync-bridge worker 将原生 raw 格式化器formatNativeRaw与查询 raw 输出格式化器formatQueryRawOutput接线使 bridge 在mode: raw下返回各命令自己的投影结果即 per-command projection。从源码结构看这一层的作用是把每条命令各自定义 raw 投影与统一的分发管道解耦——路由层不必知道每条命令的投影规则投影规则仍归属各命令 handler。4.3 输出层走output()的rawValue分支路由器拿到 bridge 返回的格式化字符串后将其作为第三个位置参数rawValue交给output(result, raw, rawValue)。如上一节源码所示只要rawtrue且rawValue ! undefinedoutput()就会直接String(rawValue)写盘不再 JSON 化。由此SDK 路径与 CJS 路径在输出语义上重新对齐。说明changeset 中的formatNativeRaw/formatQueryRawOutput是当时 sync-bridge worker 的内部接线命名在当前仓库源码中未再直接检索到这两个标识符表明 bridge 内部实现此后已演进。但从src/io.cts、src/phase.cts、src/roadmap.cts等现存代码可以确认其等价机制rawValue分支 各命令投影至今仍在运行。五、源码纵深两条典型命令的 raw 投影实现5.1phase next-decimal --raw basephase next-decimal用于计算下一个十进制阶段编号如999之后返回999.1。其 SDK handler 实现在src/phase.cts#L332-L391function cmdPhaseNextDecimal(cwd: string, basePhase: string, raw: boolean): void { const phasesDir path.join(planningDir(cwd), phases); const normalized normalizePhaseName(basePhase); ... // 1) 扫描 phases/ 目录下的目录名确认基础阶段是否存在 // 2) 读取 ROADMAP.md经 scanExistingDecimalPhaseNumbers 汇总已占用的十进制编号 // #1865 之后同时合并目录名与 ROADMAP 声明ROADMAP 读取失败降级为仅目录扫描 // 3) 无占用 → normalized.1否则 → normalized.(max1) ... output( { found: baseExists, base_phase: normalized, next: nextDecimal, existing: existingDecimals }, raw, nextDecimal, // ← rawValue 投影裸的 999.1 ); }注意最后一个参数JSON 载荷里同时携带found、base_phase、next、existing四个字段供--pick next/--pick base_phase等结构化消费而rawValue只投影nextDecimal这一个标量。这正是JSON 模式全量、raw 模式投影的双轨设计。路由器侧src/phase-command-router.cts#L109-L110将raw布尔位原样透传给 handlernext-decimal: (_ctx: Recordstring, unknown): { ok: true; data: null } { phase.cmdPhaseNextDecimal(cwd, args[2], raw); ... }5.2roadmap get-phase --raw idroadmap get-phase从ROADMAP.md中取出指定阶段的章节文本。实现位于src/roadmap.cts#L316-L383其 raw 投影值是section该阶段的 Markdown 正文for (const source of roadmapPhaseLookupSources(phaseNum)) { const milestoneResult searchPhaseInContent(milestoneContent, source, phaseNum, convention); if (milestoneResult !milestoneResult.error) { output(milestoneResult, raw, milestoneResult.section); // ← rawValue section 文本 return; } const fullResult searchPhaseInContent(fullContent, source, phaseNum, convention); ... } // #3577无标题/清单命中时回退到 Markdown 表格行声明 const tableHit collectTablePhaseRows(milestoneContent).find(...) ?? collectTablePhaseRows(fullContent).find(...); if (tableHit) { output({ found: true, phase_number: phaseNum, phase_name: ..., section: tableHit.row.trim() }, raw, tableHit.row.trim()); return; }这段代码还展示了与 #3577Markdown 表格形式阶段列表的协作--raw下输出的投影值统一是阶段正文/表格行文本无论命中的是标题式声明还是表格式声明。路由器侧src/roadmap-command-router.cts#L150同样是简单透传get-phase: () roadmap.cmdRoadmapGetPhase(cwd, args[2], raw)。5.3 同类模式在更多命令中的体现同一rawValue 第三参数约定遍布其他家族命令。例如gsd-core/bin/gsd-tools.cjs#L4135-L4136的 drift-guard 子命令// Pass rawValue as 3rd arg so --raw returns unquoted string (not JSON) output(effectiveAuthority, raw, effectiveAuthority);src/config.cts#L1340-L1345的模型 profile 查询同样把投影结果作为 rawValue 传入src/audit-command-router.cts#L55、L136的审计报告在--raw下必须绕过 JSON 编码输出人类可读文本。可以说output(result, raw, rawValue)的三参数签名是整个命令族输出一致性的公共契约而 #3631 修复的是SDK bridge 分发层没有遵守这一契约的缺口。六、回归测试如何锁定该行为修复随回归测试一并落地。tests/cjs-command-router-adapter.test.cjs#L493-L635保留了针对 #3631 的两个端到端用例直接以真实gsd-tools.cjs进程驱动 SDK 路径用例 1phase next-decimal --raw 1必须输出标量 tokenconst res run([phase, next-decimal, --raw, 1], tmp); const trimmed res.stdout.trim(); assert.doesNotMatch(trimmed, /^\{/, --raw must not emit JSON; got: ${trimmed}); assert.match(trimmed, /^0*\d(?:\.\d)?$/, --raw must emit a scalar phase id; got: ${trimmed}); // CJS 输出 1.1SDK 归一化为 01.1——两者都是合法的标量投影 assert.ok(trimmed 1.1 || trimmed 01.1, ...);用例 2roadmap get-phase --raw 2必须输出阶段正文assert.doesNotMatch(trimmed, /^\{/, --raw must not emit JSON; ...); assert.match(trimmed, /Phase 2:\s*Second/, --raw must emit the section body ...);测试注释还强调了两点设计细节断言针对结构化标量而非对完整 JSON 做子串 grep符合仓库 CONTRIBUTING.md 的断言规范SDK 与 CJS 的归一化存在合法差异1.1vs01.1测试断言的是计算下一个十进制编号的语义一致性而非精确的填充格式——体现了两条路径共享语义、允许表示层差异的务实立场。七、实战用法--raw在工作流中的典型场景修复的意义在于恢复脚本化消费的可靠性。仓库中有大量依赖--raw裸值输出的工作流场景 A分配 999.x 补丁阶段编号gsd-core/workflows/add-backlog.mdNEXT$(gsd_run query phase.next-decimal 999 --raw) # 若尚不存在 999.x 阶段返回 999.1稀疏编号999.1、999.3是允许的——永远用 next-decimal不要手猜场景 B计算并消费下一个十进制阶段gsd-core/references/decimal-phase-calculation.mdgsd-tools.cjs query phase.next-decimal 6 # 默认 JSON DECIMAL_PHASE$(gsd-tools.cjs query phase.next-decimal ${AFTER_PHASE} --pick next) BASE_PHASE$(gsd-tools.cjs query phase.next-decimal ${AFTER_PHASE} --pick base_phase) DECIMAL_PHASE$(gsd-tools.cjs query phase.next-decimal ${AFTER_PHASE} --raw)场景 C读取配置标量大量工作流通用DISCUSS_MODE$(gsd_run query config-get workflow.discuss_mode --raw 2/dev/null || echo discuss) HUMAN_VERIFY_MODE$(gsd_run query config-get workflow.human_verify_mode --default end-of-phase --raw 2/dev/null || echo end-of-phase)在无jq的 Windows/Git-Bash 环境上这类--raw消费尤为重要——CHANGELOG.md记录了此前多个工作流因… | jq …失败exit 127被2/dev/null || default吞掉、导致配置静默回退默认值的教训改用原生--raw后不再依赖外部工具。SDK 路径此前破坏--raw意味着同样的问题会经 bridge 路径再现#3631 正是堵住了这个洞。八、边界与注意事项--raw不等于永远输出裸文本当命令的 rawValue 未定义时如check、workstream等命令output()会回退到 JSON——这是契约的一部分不是缺陷。错误路径上--raw并非完全一致docs/adr/2980-payload-carried-error-is-a-degraded-result.md指出output(result, raw, rawValue)在错误载荷下打印rawValue的行为存在历史遗留的不均匀性相关语义由 ADR 另行治理。raw 模式无 round-trip 保证按 ADR-1411 的决策raw 输出是冻结的字符串投影程序化解析应使用 JSON 模式或--pick字段选择。当前仓库内formatNativeRaw/formatQueryRawOutput已不可直接检索它们是 changeset 记录时的 bridge 内部命名现仓库中对应机制已由output()三参数签名 各命令投影实现承载。九、小结PR #3631 修复的本质是让命令输出契约在双分发路径上保持一致CJS 路径一直遵守output(result, raw, rawValue)的投影约定SDK bridge 路径在 #3577 之后出现了转发丢参的漂移。修复通过路由器请求mode: raw→ bridge 返回 per-command 投影 →output()走rawValue分支三层机制恢复了对齐并以两个端到端回归测试tests/cjs-command-router-adapter.test.cjs将行为锁定。对于在 gsd-core 上构建工作流或扩展命令的开发者理解这一契约有助于避免在自建分发层中重蹈丢raw位、丢rawValue的覆辙。赞分享【免费下载链接】gsd-coreGit. Ship. Done - Core项目地址https://gitcode.com/gh_mirrors/ge/gsd-core点击查看免费下载相关推荐get-shit-done 深度解析SDK 分发路径如何正确响应 --raw3631 修复全链路get shit done 深度解析SDK 分发路径如何正确响应 raw 3631 修复全链路 在 get shit doneGSD中 gsd to人工智能AI 应用提示工程开发工具工作流自动化AI AgentSea.js中的路径解析相对路径与绝对路径Sea.js中的路径解析相对路径与绝对路径 在前端模块化开发中路径解析是保证模块正确加载的核心环节。Sea.js作为一款轻量级的Web模块加载器Modul前端终极指南InvokeAI路径管理完全解析——从基础到高级配置技巧终极指南InvokeAI路径管理完全解析——从基础到高级配置技巧 InvokeAI作为领先的稳定扩散模型创意引擎其路径管理系统是确保AI绘图工作流顺畅运行的人工智能大模型媒体生成后端前端流程编排上一篇从像素到针法用Python编织图案库实现创意图像转换下一篇DC/OS数据中心操作系统的新时代创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表