【免费下载链接】gsd-coreGit. Ship. Done - Core项目地址https://gitcode.com/gh_mirrors/ge/gsd-core点击查看免费下载本文以归档 changesetlively-newts-rompPR 539为主线讲解 gsd-core 中「UI 设计契约门禁UI Design Contract gate」如何检测前端阶段并触发 UI-SPEC 提示以及为何该门禁的探测脚本必须相对 GSD 安装目录RUNTIME_DIR而非消费项目的 git 根目录来解析。读完你将理解ui-safety-gate的令牌检测原理、ui-plan-gate路由层判定逻辑、$RUNTIME_DIR运行时解析机制并能自行验证门禁行为。1. 变更本身这条 Fixed changeset 说了什么归档文件 lively-newts-romp.md 的完整内容为--- type: Fixed pr: 539 --- **UI Design Contract gate no longer silently no-ops in installed projects** — /gsd-plan-phase §5.6 and the autonomous workflow now resolve ui-safety-gate.cjs against the GSD install dir (RUNTIME_DIR) instead of the consuming projects git root, so frontend phases correctly trigger the UI-SPEC prompt. ui-safety-gate.cjs is now also deployed to get-shit-done/bin/lib/ (the path the GSD installer copies to $RUNTIME_DIR) and probed there first, ensuring it is found in installed runtimes where root bin/lib/ is not present.拆开来看这条修复包含两个动作解析根修正/gsd-plan-phase工作流的 §5.6 与 autonomous 工作流从此相对GSD 安装目录RUNTIME_DIR解析ui-safety-gate.cjs而不是消费项目用户自己的业务仓库的 git 根目录部署路径补齐ui-safety-gate.cjs同时部署到安装器实际会拷贝进$RUNTIME_DIR的包内bin/lib/路径changeset 写作时为get-shit-done/bin/lib/即本仓库改名前的包目录名当前树中的规范位置是gsd-core/bin/lib/ui-safety-gate.cjs见第 3 节并优先在该位置探测确保在「仓库根下没有bin/lib/」的已安装运行时中也能被找到。修复前的问题形态是静默失效在通过安装器部署到某个业务项目里运行时工作流按旧逻辑在业务项目的 git 根下找ui-safety-gate.cjs找不到后门禁整体 no-op——前端阶段既不会提示「缺少 UI-SPEC.md」也不报错。用户感知到的现象是「规划阶段该出现的 UI 设计契约提醒消失了」。2. 门禁的位置plan-phase §5.6「Plan:Pre Capability Dispatch and UI Design Contract Gate」门禁所在章节是 plan-phase.md 的 §5.6标题为Plan:Pre Capability Dispatch and UI Design Contract Gate。其职责是通过能力注册表解析激活的plan:pre钩子并对 UI 门禁运行确定性检查。配置语义文档中的 cutover fix 说明原文要点workflow.ui_phase控制 UI-SPEC 的生成stepworkflow.ui_safety_gate控制规划阻断gate两者全开与旧版 §5.6 行为一致组合{ui_phase:true, ui_safety_gate:false}表示流水线中自动生成 UI-SPEC但不阻断手动规划。当前版本中§5.6 的关键调用序列为# 1) 解析激活的 plan:pre 钩子能力注册表负责 when 条件求值 PLAN_PRE_HOOKS_JSON${PLAN_PRE_HOOKS_JSON:-$(gsd_run loop render-hooks plan:pre --raw)} HOOKS_JSON$PLAN_PRE_HOOKS_JSON # 2) 只要有任何 plan:pre UI 钩子激活包括仅 step 未开 gate 的情况就跑 UI 确定性门禁 GATE$(gsd_run check ui-plan-gate ${PHASE} --raw) # 从 GATE 读取 frontend、hasUiSpec、block 三个字段随后按六个分支处理分支条件行为Branch 1所有 plan:pre 钩子未激活跳到 step 6Branch 2frontend为false静默跳到 step 6Branch 3hasUiSpec为trueUI_SPEC_FILE$(ls ${PHASE_DIR}/*-UI-SPEC.md 2/dev/null \| head -1)显示Using UI design contract: ${UI_SPEC_PATH}继续Branch 4$ARGUMENTS含--skip-ui静默跳到 step 6Branch 5前端检测到、UI-SPEC 缺失、无--skip-ui且AUTO_CHAIN为truepipeline /--auto依次触发激活的 UI step 钩子Skill(skillgsd-${ref.skill}, args${PHASE} --auto ${GSD_WS})返回后重读 UI-SPEC 文件继续 step 6Branch 6同上但AUTO_CHAIN为false手动模式若存在激活的阻断型 gate 且block:true输出下方阻断信息并EXIT 工作流若无激活的阻断 gate如ui_safety_gate关闭继续 step 6Branch 6 的阻断输出原文模板## ⚠ UI-SPEC.md missing for Phase {N} ▶ Recommended next step: /gsd:ui-phase {N} ${GSD_WS} — generate UI design contract before planning --- Also available: - /gsd:plan-phase {N} --skip-ui ${GSD_WS} — plan without UI-SPEC (not recommended for frontend phases)退出 plan-phase 工作流不继续。这条阻断输出正是 changeset 所说「frontend phases correctly trigger the UI-SPEC prompt」的落点。3. 检测器本体ui-safety-gate 的词边界令牌嗅探门禁的确定性检查最终来自ui-safety-gate模块。当前仓库中它的 TypeScript 源码为真源ADR-457 的 build-at-publish 机制将其编译为gsd-core/bin/lib/ui-safety-gate.cjs文件头注释明确写着Canonical location:gsd-core/bin/lib/ui-safety-gate.cjssrc/ui-safety-gate.cts。该文件头部同时交代了历史它取代了旧的 bash 单行实现——后者在 Windows PowerShell / cmd.exe 下因为 locale 环境变量前缀不被识别而静默降级这正是「静默失效」问题的另一面Node 实现无 shell 依赖在 bash、Git-Bash、PowerShell、cmd.exe 下行为一致。令牌表与匹配规则src/ui-safety-gate.ctsexport const UI_TOKENS: ReadonlyArraystring [ UI, interface, frontend, component, layout, page, screen, view, form, dashboard, widget, ]; // 模块加载时构建一次无逐次调用编译开销。 const UI_GATE_PATTERN new RegExp( (^|[^a-zA-Z0-9])( UI_TOKENS.join(|) )([^a-zA-Z0-9]|$), i, );关键实现细节ASCII 词边界锚定(^|[^a-zA-Z0-9])(TOKEN)([^a-zA-Z0-9]|$)等价于 POSIX ERE 的[^[:alnum:]]意图——microfrontend不算匹配而micro-frontend、micro frontend会匹配frontend。文件注释特别指出 JS 的[a-zA-Z0-9]是 ASCII-only与 locale 敏感的 POSIX[[:alnum:]]不等价CRLF 归一化进入匹配前先text.replace(/\r\n/g, \n)**UI hint**: yes/no权威声明短路#2150作者显式写出的**UI hint**: no会直接返回hasUI: falseyes直接返回hasUI: true。且所有**UI hint**:行在令牌嗅探前被整行剔除避免行内的裸UI词造成误报首个命中记录#3312返回结构中携带matchedToken与matchedLine让门禁消费者能直接展示「是什么触发了嗅探」无需重新读源文件。公共 API 与 CLI 契约checkUiPresence(text: string): { hasUI, tokens, matchedToken, matchedLine } CLI从 STDIN 读取阶段文本规避 ARG_MAX 限制 echo $PHASE_SECTION | node gsd-core/bin/lib/ui-safety-gate.cjs 退出码0 发现 UI 令牌1 无 UI真实输入、已检查 NO_INPUT / UNAVAILABLE 注册表编码见 src/cli-exit.ctsADR-3889 Phase 3#3907退出码设计值得一提旧的单一「2 startup error」分支把「没给我输入」和「这个 phase 没有 UI」混为一谈新契约中真实输入上的hint no仍然退出 1那是作者自己的声明而非空输入假象。ADR-3889 中给出了示例验证命令docs/adr/3889-process-exit-contract.md$ printf Build a React component with a button | node gsd-core/bin/lib/ui-safety-gate.cjs; echo $? $ printf | node gsd-core/bin/lib/ui-safety-gate.cjs; echo $?4. 路由层gsd_run check ui-plan-gate如何算出block工作流并不直接内联调用检测器而是经由 check-command-router.cts 中的ui-plan-gate子命令§5.6 的check.query ui.plan-gate路由层把点号归一化为连字符。核心逻辑在computeUiPlanGatesrc/check-command-router.cts两段式查找读取 ROADMAP.md 中的 phase 文本与roadmap.get-phase相同的「当前里程碑优先 → stripShippedMilestones 回退」查找保证跨里程碑的前端 phase 也能正确解析ROADMAP.md 缺失时视为非前端项目但若 ROADMAP.md 存在而 phase 头缺失会置phaseLookupFailed向onError:halt门禁显式上报——不静默降级为frontend:false复用checkUiPresence做前端嗅探不重新实现结构性佐证#3312实现在 src/ui-frontend-evidence.ctsfrontend只是词汇集合信号门禁仅当令牌匹配被仓库中的静态前端证据佐证时才阻断——证据包括 package.json 中的 UI 框架依赖、组件框架文件或原生 UI 证据.xaml文件或带 UI 导入标记的.swift/.kt/.dart文件#4658UI-SPEC 存在性通过 phase 目录定位器解析 phase 目录查找*-UI-SPEC.md。返回值与阻断判定src/check-command-router.ctsReturns JSON: { frontend, hasFrontendEvidence, hasUiSpec, block, uiSpecPath, matchedToken, matchedLine, phaseLookupFailed? } block frontend hasFrontendEvidence !hasUiSpecmatchedToken/matchedLine直通到工作流让操作者在一秒内判断这个 flag 是否合理而不是只能伸手去--skip-ui。5. RUNTIME_DIR 解析修复的核心机制理解这个 bug关键是理解 gsd-core 的运行时解析模型。所有工作流共享一段运行时启动器片段gsd-core/workflows/_runtime-launcher.snippet.sh其核心解析规则为_GSD_SHIM_NAMEgsd-tools.cjs _GSD_RUNTIME_ROOT${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2/dev/null || pwd)} GSD_TOOLS${_GSD_RUNTIME_ROOT}/gsd-core/bin/${_GSD_SHIM_NAME}即优先取环境变量RUNTIME_DIRGSD 安装目录未设置时回退到当前 git 仓库根或pwd。在 gsd-core 自己的开发仓库里git rev-parse --show-toplevel恰好指向 gsd-core 本体gsd-core/bin/lib/存在于根目录下一切正常。但在通过安装器部署到用户业务项目的场景中业务项目的 git 根下没有gsd-core/bin/lib/安装器只把包内容拷贝到用户配置目录下的$RUNTIME_DIR/gsd-core/bin/...旧逻辑若相对 git 根解析ui-safety-gate.cjs探测落空 → 门禁 no-opUI-SPEC 提示消失且无任何报错——即 changeset 标题的silently no-ops in installed projects。PR 539 的修复因此是双管齐下动作内容效果解析根切换到RUNTIME_DIRplan-phase §5.6 与 autonomous 工作流改为相对 GSD 安装目录解析已安装运行时中探测路径存在部署路径补齐 优先探测文件部署到安装器实际拷贝进$RUNTIME_DIR的包内bin/lib/并先探测该位置即使根级bin/lib/不存在安装态常态也能命中autonomous 工作流侧面对应的是 step 3a.5gsd-core/workflows/autonomous.md「Resolves whether the phase needs a UI-SPEC.md generated before planning via active plan:pre step hooks. Always non-blocking — proceeds to 3b regardless of outcome.」即自治模式下同样依赖同一解析链判断是否需要先生成 UI-SPEC但保持非阻断。值得说明的后续演进仓库后续重构#1031 等已把工作流里的内联 shell 路径探测进一步收敛为gsd_run check ui-plan-gate单一入口——测试 tests/plan-phase-ui-redirect.test.cjs 明确断言「§5.6 must NOT contain the old shell-based ui-safety-gate.cjs path-search (now delegated to check ui-plan-gate)」tests/autonomous-ui-steps.test.cjs 同样断言 §3a.5「must NOT inline ui-safety-gate.cjs (replaced by check ui-plan-gate)」。PR 539 解决的是「探测在哪个根下找文件」的问题后续重构则把「在 shell 里找文件」这件事整体移进了 Node 路由层。两者叠加才消除了整类静默失效。6. 防回归护栏这一修复为什么不会退回来围绕这条变更仓库布了多层可验证的护栏读者可按图索骥行为测试tests/check-ui-safety-gate.test.cjs 覆盖 CLI 退出码契约含NO_INPUT/UNAVAILABLE分支对应 ADR-3889 Phase 3 的 #3907、词边界行为以及工作流不得回退到旧式 shell 路径搜索的断言死代码防护根级手写副本bin/lib/ui-safety-gate.cjs曾在 #3907 被删除且 scripts/lint-removed-but-needed.cjs 的注释指出该删除的原始缺陷形状正是「删掉bin/lib/ui-safety-gate.cjs的同时仍然在用的gsd-core/bin/lib/ui-safety-gate.cjs被误伤」——配套测试 tests/removed-but-needed-lint.test.cjs 验证了「同名基名存活集」判定逻辑防止文档/代码里对已删除旧路径的引用被再次误判清单登记docs/INVENTORY.md 中ui-safety-gate.cjs的条目完整记录了部署语义「也部署到gsd-core/bin/lib/以便 GSD 安装程序将其传送到$RUNTIME_DIR#448」与 changeset 的部署声明相互印证架构上下文CONTEXT.md 将该门禁列为能力驱动切换ADR-894 self-gating cutover的 worked example——plan-phase §5.6 的 UI 门禁前端检测 --auto/手动分支 --skip-ui旁路必须先迁入gsd-ui-phaseskill其plan:pre钩子才能在不损失行为的前提下替换内联调用。7. 实战验证清单在 gsd-core 仓库内或任何含安装后运行时的环境可按以下顺序验证整条链路# 1) 词边界嗅探真实 UI 描述 → 0 printf Build a React dashboard with a login form | node gsd-core/bin/lib/ui-safety-gate.cjs; echo $? # 2) 词边界嗅探无 UI 语义 → 1 printf Add an API endpoint for invoice export | node gsd-core/bin/lib/ui-safety-gate.cjs; echo $? # 3) 空输入 → NO_INPUT 注册表码非 0/1 printf | node gsd-core/bin/lib/ui-safety-gate.cjs; echo $? # 4) 路由层完整判定需要项目内存在 .planning/ROADMAP.md 与 phase 目录 gsd_run check ui-plan-gate 1 --raw # 期望 JSON{ frontend, hasFrontendEvidence, hasUiSpec, block, uiSpecPath, matchedToken, matchedLine } # 5) 验证安装态解析确认 RUNTIME_DIR 优先于 git 根 echo ${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2/dev/null || pwd)}/gsd-core/bin/lib/ui-safety-gate.cjs适用前提与限制以上gsd-core/bin/lib/ui-safety-gate.cjs是发布构建产物源自 src/ui-safety-gate.ctsADR-457 build-at-publish在纯源码工作区中若该.cjs未构建应通过gsd_run check ui-plan-gate路由层验证check ui-plan-gate的block判定要求结构性佐证#3312只有 phase 词汇命中而仓库中没有任何前端文件/依赖的项目不会被阻断这是有意设计而非漏检本文描述的解析行为对应当前仓库快照changeset 中的目录名get-shit-done/bin/lib/为改名前的包路径现行规范位置是gsd-core/bin/lib/。小结这条 Fixed changeset 的价值不在单点而在于它揭示了自动化规划门禁的一类系统性风险依赖「当前 git 根 工具仓库根」这一隐含假设的路径解析在安装态部署中会静默失效。gsd-core 的解法是三层收敛解析根统一走$RUNTIME_DIR回退链、探测路径与安装器部署路径对齐并优先探测、以及最终把探测逻辑从工作流内联 shell 收敛进 Node 路由层check ui-plan-gate并由行为测试与 lint 双重锁定——前端阶段该触发的 UI-SPEC 契约提示从此在已安装项目中不再是概率事件。赞分享【免费下载链接】gsd-coreGit. Ship. Done - Core项目地址https://gitcode.com/gh_mirrors/ge/gsd-core点击查看免费下载相关推荐esp-idf NVS 分区解析工具 nvs_partition_tool读取、调试与完整性检查 NVS 存储分区的实战指南esp idf NVS 分区解析工具 nvs_partition_tool读取、调试与完整性检查 NVS 存储分区的实战指南 本文围绕 ESP IDF 的 Ngsd-core 安装器 --sdk 标志接线修复从静默跳过到 forceSdk 强制部署gsd core 安装器 sdk 标志接线修复从静默跳过到 forceSdk 强制部署 本文基于 gsd core 仓库归档 changeset 3033 sget-shit-done 中的 gsd-ui-checker基于六维度校验的 UI 设计契约只读验证 Agentget shit done 中的 gsd ui checker基于六维度校验的 UI 设计契约只读验证 Agent 本文以 agents/gsd ui che人工智能AI 应用提示工程开发工具工作流自动化AI Agent上一篇阿里开源Wan2.2-Animate-14B影视级角色动画生成的开源革命下一篇Arthas keymap 命令与快捷键配置完全指南inputrc 自定义、Tab 补全与异步命令控制创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考