@opengsd/gsd-core 1.10.0 → 1.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (328) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/agents/gsd-debug-session-manager.md +11 -0
  4. package/agents/gsd-doc-synthesizer.md +2 -4
  5. package/agents/gsd-executor.md +5 -5
  6. package/agents/gsd-mempalace-curator.md +5 -2
  7. package/agents/gsd-phase-researcher.md +20 -1
  8. package/agents/gsd-plan-checker.md +37 -0
  9. package/agents/gsd-planner.md +44 -46
  10. package/agents/gsd-user-profiler.md +3 -0
  11. package/agents/gsd-verifier.md +12 -3
  12. package/bin/install.js +841 -971
  13. package/bin/lib/ui-safety-gate.cjs +2 -0
  14. package/commands/gsd/code-review.md +1 -1
  15. package/commands/gsd/execute-phase.md +1 -1
  16. package/commands/gsd/map-codebase.md +1 -1
  17. package/commands/gsd/mempalace-capture.md +1 -1
  18. package/commands/gsd/mempalace-recall.md +1 -1
  19. package/commands/gsd/new-milestone.md +1 -1
  20. package/commands/gsd/quick.md +1 -1
  21. package/commands/gsd/review-backlog.md +2 -1
  22. package/commands/gsd/verify-work.md +1 -1
  23. package/gsd-core/bin/gsd-tools.cjs +469 -88
  24. package/gsd-core/bin/lib/active-workstream-store.cjs +138 -22
  25. package/gsd-core/bin/lib/agent-install-check.cjs +230 -32
  26. package/gsd-core/bin/lib/api-coverage.cjs +3 -5
  27. package/gsd-core/bin/lib/artifacts.cjs +3 -0
  28. package/gsd-core/bin/lib/assumption-delta.cjs +2 -4
  29. package/gsd-core/bin/lib/audit-command-router.cjs +9 -2
  30. package/gsd-core/bin/lib/audit.cjs +876 -240
  31. package/gsd-core/bin/lib/broken-windows.cjs +1 -1
  32. package/gsd-core/bin/lib/capability-consent.cjs +149 -15
  33. package/gsd-core/bin/lib/capability-lifecycle.cjs +45 -0
  34. package/gsd-core/bin/lib/capability-registry.cjs +575 -101
  35. package/gsd-core/bin/lib/capability-source.cjs +92 -0
  36. package/gsd-core/bin/lib/capability-trust.cjs +444 -25
  37. package/gsd-core/bin/lib/capability-validator.cjs +495 -22
  38. package/gsd-core/bin/lib/capability-writer.cjs +3 -2
  39. package/gsd-core/bin/lib/check-command-router.cjs +71 -37
  40. package/gsd-core/bin/lib/claude-orchestration.cjs +56 -3
  41. package/gsd-core/bin/lib/codex-agent-toml.cjs +329 -0
  42. package/gsd-core/bin/lib/command-aliases.cjs +22 -0
  43. package/gsd-core/bin/lib/command-roster.cjs +44 -1
  44. package/gsd-core/bin/lib/commands.cjs +651 -86
  45. package/gsd-core/bin/lib/commonjs-marker.cjs +12 -6
  46. package/gsd-core/bin/lib/complexity-trigger.cjs +1172 -0
  47. package/gsd-core/bin/lib/config-loader.cjs +75 -0
  48. package/gsd-core/bin/lib/config.cjs +10 -1
  49. package/gsd-core/bin/lib/core-utils.cjs +127 -29
  50. package/gsd-core/bin/lib/decisions.cjs +23 -0
  51. package/gsd-core/bin/lib/fallow-runner.cjs +20 -44
  52. package/gsd-core/bin/lib/frontmatter.cjs +155 -20
  53. package/gsd-core/bin/lib/gap-checker.cjs +68 -7
  54. package/gsd-core/bin/lib/git-base-branch.cjs +102 -0
  55. package/gsd-core/bin/lib/gsd2-import.cjs +10 -1
  56. package/gsd-core/bin/lib/health-diagnostic-rules/agent-install.cjs +101 -0
  57. package/gsd-core/bin/lib/health-diagnostic-rules/config-validation.cjs +348 -0
  58. package/gsd-core/bin/lib/health-diagnostic-rules/consistency.cjs +145 -0
  59. package/gsd-core/bin/lib/health-diagnostic-rules/install-surface-shadowing.cjs +98 -0
  60. package/gsd-core/bin/lib/health-diagnostic-rules/milestone-archive-hygiene.cjs +100 -0
  61. package/gsd-core/bin/lib/health-diagnostic-rules/phase-structure.cjs +222 -0
  62. package/gsd-core/bin/lib/health-diagnostic-rules/roadmap-disk-consistency.cjs +265 -0
  63. package/gsd-core/bin/lib/health-diagnostic-rules/root-existence.cjs +161 -0
  64. package/gsd-core/bin/lib/health-diagnostic-rules/state-consistency.cjs +303 -0
  65. package/gsd-core/bin/lib/health-diagnostic-rules/worktree-health.cjs +173 -0
  66. package/gsd-core/bin/lib/health-diagnostic-types.cjs +68 -0
  67. package/gsd-core/bin/lib/health-diagnostic.cjs +431 -0
  68. package/gsd-core/bin/lib/host-runtime-detection.cjs +134 -0
  69. package/gsd-core/bin/lib/init.cjs +321 -129
  70. package/gsd-core/bin/lib/install-effort-resolver.cjs +73 -30
  71. package/gsd-core/bin/lib/install-engine.cjs +745 -258
  72. package/gsd-core/bin/lib/install-fs-adapter.cjs +262 -0
  73. package/gsd-core/bin/lib/install-model-override-resolver.cjs +203 -0
  74. package/gsd-core/bin/lib/install-profiles.cjs +134 -57
  75. package/gsd-core/bin/lib/install-scope.cjs +270 -0
  76. package/gsd-core/bin/lib/install-shadow-report.cjs +385 -0
  77. package/gsd-core/bin/lib/installed-surface-resolver.cjs +381 -0
  78. package/gsd-core/bin/lib/installer-migrations.cjs +138 -31
  79. package/gsd-core/bin/lib/io.cjs +10 -0
  80. package/gsd-core/bin/lib/markdown-sectionizer.cjs +2 -1
  81. package/gsd-core/bin/lib/markdown-table.cjs +133 -20
  82. package/gsd-core/bin/lib/milestone-lock.cjs +248 -0
  83. package/gsd-core/bin/lib/milestone.cjs +754 -70
  84. package/gsd-core/bin/lib/model-catalog.cjs +59 -1
  85. package/gsd-core/bin/lib/model-resolver.cjs +183 -40
  86. package/gsd-core/bin/lib/normalize-test-command.cjs +1 -1
  87. package/gsd-core/bin/lib/pattern.cjs +122 -0
  88. package/gsd-core/bin/lib/phase-estimation.cjs +1 -1
  89. package/gsd-core/bin/lib/phase-id.cjs +444 -36
  90. package/gsd-core/bin/lib/phase-lifecycle.cjs +28 -3
  91. package/gsd-core/bin/lib/phase-locator.cjs +125 -18
  92. package/gsd-core/bin/lib/phase.cjs +646 -143
  93. package/gsd-core/bin/lib/plan-dependency-graph.cjs +72 -1
  94. package/gsd-core/bin/lib/plan-drift-guard.cjs +120 -0
  95. package/gsd-core/bin/lib/plan-scan.cjs +86 -2
  96. package/gsd-core/bin/lib/planning-scope.cjs +31 -0
  97. package/gsd-core/bin/lib/planning-snapshot.cjs +890 -0
  98. package/gsd-core/bin/lib/planning-workspace.cjs +56 -6
  99. package/gsd-core/bin/lib/probe-core.cjs +1 -1
  100. package/gsd-core/bin/lib/profile-output.cjs +1 -1
  101. package/gsd-core/bin/lib/refactor-trigger-command-router.cjs +740 -0
  102. package/gsd-core/bin/lib/retired-artifact-cleanup.cjs +11 -6
  103. package/gsd-core/bin/lib/review-lane-descriptor.cjs +13 -4
  104. package/gsd-core/bin/lib/review-lane-invocation.cjs +30 -0
  105. package/gsd-core/bin/lib/review-lane-runner.cjs +421 -66
  106. package/gsd-core/bin/lib/review-reviewer-selection.cjs +13 -18
  107. package/gsd-core/bin/lib/roadmap-command-router.cjs +34 -0
  108. package/gsd-core/bin/lib/roadmap-parser.cjs +943 -184
  109. package/gsd-core/bin/lib/roadmap-upgrade.cjs +37 -10
  110. package/gsd-core/bin/lib/roadmap.cjs +385 -94
  111. package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +608 -46
  112. package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +14 -2
  113. package/gsd-core/bin/lib/runtime-artifact-layout.cjs +426 -55
  114. package/gsd-core/bin/lib/runtime-config-adapter-registry.cjs +3 -2
  115. package/gsd-core/bin/lib/runtime-homes.cjs +69 -3
  116. package/gsd-core/bin/lib/runtime-hooks-surface.cjs +115 -3
  117. package/gsd-core/bin/lib/runtime-name-policy.cjs +3 -1
  118. package/gsd-core/bin/lib/runtime-slash.cjs +27 -9
  119. package/gsd-core/bin/lib/security.cjs +104 -5
  120. package/gsd-core/bin/lib/shell-command-projection.cjs +275 -3
  121. package/gsd-core/bin/lib/smart-entry.cjs +142 -22
  122. package/gsd-core/bin/lib/state-command-router.cjs +5 -1
  123. package/gsd-core/bin/lib/state-document.cjs +152 -8
  124. package/gsd-core/bin/lib/state-transition.cjs +371 -117
  125. package/gsd-core/bin/lib/state.cjs +1794 -357
  126. package/gsd-core/bin/lib/surface.cjs +23 -9
  127. package/gsd-core/bin/lib/text-lines.cjs +80 -0
  128. package/gsd-core/bin/lib/token-scanner.cjs +76 -0
  129. package/gsd-core/bin/lib/uat-predicate.cjs +9 -3
  130. package/gsd-core/bin/lib/uat.cjs +399 -56
  131. package/gsd-core/bin/lib/ui-frontend-evidence.cjs +157 -0
  132. package/gsd-core/bin/lib/ui-safety-gate.cjs +14 -5
  133. package/gsd-core/bin/lib/unusable-input.cjs +24 -0
  134. package/gsd-core/bin/lib/update-context.cjs +8 -2
  135. package/gsd-core/bin/lib/user-artifact-staging.cjs +705 -0
  136. package/gsd-core/bin/lib/validate.cjs +20 -6
  137. package/gsd-core/bin/lib/vendor/README.md +37 -0
  138. package/gsd-core/bin/lib/vendor/re2js.cjs +6480 -0
  139. package/gsd-core/bin/lib/vendor/re2js.d.cts +938 -0
  140. package/gsd-core/bin/lib/verification-command-router.cjs +2 -1
  141. package/gsd-core/bin/lib/verification.cjs +258 -8
  142. package/gsd-core/bin/lib/verify.cjs +368 -888
  143. package/gsd-core/bin/lib/workstream-inventory-builder.cjs +53 -32
  144. package/gsd-core/bin/lib/workstream-inventory.cjs +63 -10
  145. package/gsd-core/bin/lib/workstream.cjs +2 -2
  146. package/gsd-core/bin/lib/worktree-safety.cjs +176 -9
  147. package/gsd-core/bin/shared/config-defaults.manifest.json +1 -0
  148. package/gsd-core/bin/shared/config-schema.manifest.json +7 -1
  149. package/gsd-core/references/agent-contracts.md +43 -26
  150. package/gsd-core/references/checkpoints.md +2 -2
  151. package/gsd-core/references/context-budget.md +1 -1
  152. package/gsd-core/references/dispatch-isolation-gate.md +138 -0
  153. package/gsd-core/references/doc-conflict-engine.md +1 -1
  154. package/gsd-core/references/execute-mvp-tdd.md +3 -3
  155. package/gsd-core/references/execute-phase-between-wave-reset.md +6 -2
  156. package/gsd-core/references/execute-phase-context-guard.md +1 -1
  157. package/gsd-core/references/execute-phase-response-language.md +1 -1
  158. package/gsd-core/references/execute-phase-wave-guard.md +6 -2
  159. package/gsd-core/references/gate-prompts.md +1 -1
  160. package/gsd-core/references/git-planning-commit.md +2 -1
  161. package/gsd-core/references/loop-hook-dispatch.md +39 -2
  162. package/gsd-core/references/model-profiles.md +12 -4
  163. package/gsd-core/references/mvp-concepts.md +9 -9
  164. package/gsd-core/references/planner-guidance.md +3 -9
  165. package/gsd-core/references/planner-preconditions.md +1 -1
  166. package/gsd-core/references/planner-reviews.md +1 -1
  167. package/gsd-core/references/planning-config.md +8 -6
  168. package/gsd-core/references/revision-loop.md +1 -1
  169. package/gsd-core/references/specless-probe-fallback.md +1 -1
  170. package/gsd-core/references/universal-anti-patterns.md +3 -3
  171. package/gsd-core/references/verifier-phase-gates.md +192 -0
  172. package/gsd-core/references/verify-mvp-mode.md +1 -1
  173. package/gsd-core/references/workstream-flag.md +22 -6
  174. package/gsd-core/templates/discussion-log.md +1 -1
  175. package/gsd-core/templates/phase-prompt.md +2 -4
  176. package/gsd-core/templates/state.md +4 -4
  177. package/gsd-core/templates/verification-report.md +9 -1
  178. package/gsd-core/workflows/ai-integration-phase.md +9 -11
  179. package/gsd-core/workflows/autonomous.md +1 -1
  180. package/gsd-core/workflows/cleanup.md +62 -3
  181. package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +13 -3
  182. package/gsd-core/workflows/code-review-fix.md +37 -10
  183. package/gsd-core/workflows/code-review.md +38 -12
  184. package/gsd-core/workflows/complete-milestone.md +141 -18
  185. package/gsd-core/workflows/debug.md +7 -5
  186. package/gsd-core/workflows/diagnose-issues.md +35 -9
  187. package/gsd-core/workflows/discuss-phase/modes/chain.md +2 -1
  188. package/gsd-core/workflows/discuss-phase/modes/default.md +1 -1
  189. package/gsd-core/workflows/discuss-phase-assumptions.md +2 -1
  190. package/gsd-core/workflows/edit-phase.md +26 -1
  191. package/gsd-core/workflows/eval-review.md +3 -5
  192. package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +31 -6
  193. package/gsd-core/workflows/execute-phase/steps/per-plan-executor-routing.md +77 -0
  194. package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +2 -0
  195. package/gsd-core/workflows/execute-phase.md +38 -50
  196. package/gsd-core/workflows/execute-plan.md +36 -4
  197. package/gsd-core/workflows/explore.md +131 -4
  198. package/gsd-core/workflows/fast.md +10 -2
  199. package/gsd-core/workflows/health.md +73 -4
  200. package/gsd-core/workflows/import.md +4 -4
  201. package/gsd-core/workflows/ingest-docs.md +5 -5
  202. package/gsd-core/workflows/mvp-phase.md +6 -3
  203. package/gsd-core/workflows/new-milestone.md +14 -9
  204. package/gsd-core/workflows/new-project.md +14 -14
  205. package/gsd-core/workflows/next.md +12 -0
  206. package/gsd-core/workflows/plan-phase.md +41 -17
  207. package/gsd-core/workflows/plan-review-convergence.md +50 -2
  208. package/gsd-core/workflows/progress.md +34 -6
  209. package/gsd-core/workflows/quick/steps/plan-checker-loop.md +4 -4
  210. package/gsd-core/workflows/quick/steps/quick-verification.md +27 -6
  211. package/gsd-core/workflows/quick/steps/research-phase.md +2 -2
  212. package/gsd-core/workflows/quick.md +35 -15
  213. package/gsd-core/workflows/review.md +26 -5
  214. package/gsd-core/workflows/secure-phase.md +1 -1
  215. package/gsd-core/workflows/session-report.md +2 -1
  216. package/gsd-core/workflows/settings.md +66 -2
  217. package/gsd-core/workflows/ship.md +104 -44
  218. package/gsd-core/workflows/spec-phase.md +30 -12
  219. package/gsd-core/workflows/sync-skills.md +63 -8
  220. package/gsd-core/workflows/transition.md +46 -11
  221. package/gsd-core/workflows/ui-phase.md +5 -5
  222. package/gsd-core/workflows/ui-review.md +2 -2
  223. package/gsd-core/workflows/update.md +1 -1
  224. package/gsd-core/workflows/validate-phase.md +1 -1
  225. package/gsd-core/workflows/verify-work.md +9 -7
  226. package/hooks/dist/gsd-agent-isolation-guard.js +103 -14
  227. package/hooks/dist/gsd-check-update-worker.js +56 -13
  228. package/hooks/dist/gsd-check-update.js +19 -1
  229. package/hooks/dist/gsd-cursor-pre-tool.js +0 -3
  230. package/hooks/dist/gsd-cursor-subagent-start.js +77 -2
  231. package/hooks/dist/gsd-cursor-subagent-stop.js +3 -2
  232. package/hooks/dist/gsd-prompt-guard.js +21 -20
  233. package/hooks/dist/gsd-read-injection-scanner.js +38 -24
  234. package/hooks/dist/gsd-statusline.js +18 -0
  235. package/hooks/dist/gsd-update-banner.js +22 -1
  236. package/hooks/dist/gsd-workflow-guard.js +134 -36
  237. package/hooks/dist/lib/git-cmd.js +92 -59
  238. package/hooks/dist/lib/injection-patterns.js +45 -0
  239. package/hooks/dist/lib/isolation-deny-reason.js +39 -0
  240. package/hooks/dist/lib/isolation-sentinel.js +9 -0
  241. package/hooks/gsd-agent-isolation-guard.js +103 -14
  242. package/hooks/gsd-check-update-worker.js +56 -13
  243. package/hooks/gsd-check-update.js +19 -1
  244. package/hooks/gsd-cursor-pre-tool.js +0 -3
  245. package/hooks/gsd-cursor-subagent-start.js +77 -2
  246. package/hooks/gsd-cursor-subagent-stop.js +3 -2
  247. package/hooks/gsd-prompt-guard.js +21 -20
  248. package/hooks/gsd-read-injection-scanner.js +38 -24
  249. package/hooks/gsd-statusline.js +18 -0
  250. package/hooks/gsd-update-banner.js +22 -1
  251. package/hooks/gsd-workflow-guard.js +134 -36
  252. package/hooks/lib/git-cmd.js +92 -59
  253. package/hooks/lib/injection-patterns.js +45 -0
  254. package/hooks/lib/isolation-deny-reason.js +39 -0
  255. package/hooks/lib/isolation-sentinel.js +9 -0
  256. package/package.json +21 -9
  257. package/pi/gsd.cjs +19 -5
  258. package/scripts/baselines/planning-prompt-drift-baseline.json +4 -0
  259. package/scripts/baselines/planning-snapshot-bypass-baseline.json +12 -0
  260. package/scripts/baselines/unreachable-guard-drift-baseline.json +4 -0
  261. package/scripts/changeset/lint.cjs +60 -5
  262. package/scripts/check-alias-drift.cjs +7 -43
  263. package/scripts/check-contract-drift.cjs +297 -0
  264. package/scripts/ci-test-scope.cjs +19 -2
  265. package/scripts/command-contract-helpers.cjs +903 -1
  266. package/scripts/gen-adr-index.cjs +728 -38
  267. package/scripts/gen-capability-registry.cjs +3 -15
  268. package/scripts/gen-context-index.cjs +2 -11
  269. package/scripts/gen-health-docs.cjs +390 -0
  270. package/scripts/gen-inventory-manifest.cjs +50 -4
  271. package/scripts/gen-loop-host-contract.cjs +4 -24
  272. package/scripts/gen-registry.cjs +3 -14
  273. package/scripts/lib/alias-drift-families.cjs +46 -0
  274. package/scripts/lib/drift-scan.cjs +278 -0
  275. package/scripts/lint-allow-test-rule-refs.allowlist.json +1 -26
  276. package/scripts/lint-allow-test-rule-refs.effective-ceiling.json +4 -0
  277. package/scripts/lint-allow-test-rule-refs.unverified-ceiling.json +3 -0
  278. package/scripts/lint-canary-version-leak.cjs +73 -0
  279. package/scripts/lint-command-contract.cjs +96 -13
  280. package/scripts/lint-completion-predicate-drift.cjs +933 -0
  281. package/scripts/lint-completion-ratio-drift.cjs +214 -0
  282. package/scripts/lint-default-flip-documentation.cjs +193 -0
  283. package/scripts/lint-eslint-glob-coverage.allowlist.json +34 -0
  284. package/scripts/lint-eslint-glob-coverage.cjs +340 -0
  285. package/scripts/lint-frontmatter-scalar-broad-grep.cjs +237 -0
  286. package/scripts/lint-health-diagnostic-rule-table.cjs +404 -0
  287. package/scripts/lint-hooks-runtime-build-seam.cjs +262 -0
  288. package/scripts/lint-milestone-window-drift.cjs +468 -0
  289. package/scripts/lint-phase-enumeration-drift.cjs +479 -0
  290. package/scripts/lint-plan-count-drift.cjs +318 -0
  291. package/scripts/lint-planning-artifact-writer-drift.cjs +398 -0
  292. package/scripts/lint-planning-prompt-drift.cjs +434 -0
  293. package/scripts/lint-planning-snapshot-bypass-drift.cjs +544 -0
  294. package/scripts/lint-regression-test-names.cjs +15 -13
  295. package/scripts/lint-removed-but-needed.cjs +320 -0
  296. package/scripts/lint-state-field-drift.cjs +805 -0
  297. package/scripts/lint-state-write-path-drift.cjs +1045 -0
  298. package/scripts/lint-test-file-count.allowlist.json +21 -10
  299. package/scripts/lint-unreachable-guard-drift.cjs +843 -0
  300. package/scripts/lint-vendored-deps.cjs +124 -0
  301. package/scripts/pr-changed-files.cjs +63 -0
  302. package/scripts/pr-template-policy.cjs +14 -4
  303. package/scripts/prompt-injection-scan.sh +25 -0
  304. package/scripts/require-issue-link-policy.cjs +192 -0
  305. package/scripts/state-write-path-drift-baseline.json +19 -0
  306. package/scripts/sync-runtime-launcher.cjs +2 -4
  307. package/skills/gsd-autonomous/SKILL.md +0 -1
  308. package/skills/gsd-code-review/SKILL.md +1 -1
  309. package/skills/gsd-execute-phase/SKILL.md +1 -2
  310. package/skills/gsd-map-codebase/SKILL.md +1 -1
  311. package/skills/gsd-mempalace-capture/SKILL.md +1 -1
  312. package/skills/gsd-mempalace-recall/SKILL.md +1 -1
  313. package/skills/gsd-new-milestone/SKILL.md +1 -1
  314. package/skills/gsd-next/SKILL.md +0 -1
  315. package/skills/gsd-plan-phase/SKILL.md +0 -1
  316. package/skills/gsd-progress/SKILL.md +0 -1
  317. package/skills/gsd-quick/SKILL.md +1 -1
  318. package/skills/gsd-review-backlog/SKILL.md +2 -1
  319. package/skills/gsd-stats/SKILL.md +0 -1
  320. package/skills/gsd-verify-work/SKILL.md +1 -1
  321. package/vscode/package.json +1 -1
  322. package/gsd-core/workflows/discovery-phase.md +0 -298
  323. package/gsd-core/workflows/plan-milestone-gaps.md +0 -281
  324. package/gsd-core/workflows/verify-phase.md +0 -574
  325. package/scripts/affected-tests-lib.cjs +0 -554
  326. package/scripts/lint-allow-test-rule-refs.cjs +0 -162
  327. package/scripts/run-affected-tests.cjs +0 -7
  328. package/scripts/run-tests.cjs +0 -1051
@@ -0,0 +1,39 @@
1
+ 'use strict';
2
+ // hooks/lib/isolation-deny-reason.js — shared, frozen reason-code enum for
3
+ // the #3045 dispatch-isolation guards' block/deny decisions
4
+ // (hooks/gsd-agent-isolation-guard.js, hooks/gsd-cursor-subagent-start.js).
5
+ //
6
+ // CONTRIBUTING.md ("Prohibited: Raw Text Matching on Test Outputs") bans
7
+ // asserting on a hook's free-form, human-readable reason/user_message prose
8
+ // — that text is for the operator/model reading the denial and may change
9
+ // wording without notice. Every block/deny decision therefore ALSO carries
10
+ // one of these STABLE codes (surfaced on the hook's stdout JSON as
11
+ // `reason_code`), so tests assert `out.reason_code === REASON_CODE.X`
12
+ // instead of regexing the message (mirrors the REASON enum convention in
13
+ // gsd-core/bin/verify-reapply-patches.cjs).
14
+ //
15
+ // Adding a new code requires updating this enum AND any test that locks the
16
+ // documented set.
17
+ const REASON_CODE = Object.freeze({
18
+ // The compiled runtime library (gsd-core/bin/lib/*.cjs) is missing and
19
+ // could not be self-built (ensure-runtime-build.cjs's RuntimeBuildError).
20
+ RUNTIME_BUILD_FAILED: 'runtime_build_failed',
21
+ // The project's dispatch-isolation configuration ('.planning/config.json')
22
+ // could not be read or resolved for a reason OTHER than a runtime-build
23
+ // failure (unreadable/malformed config, unexpected resolver error).
24
+ CONFIG_UNREADABLE: 'config_unreadable',
25
+ // Isolation resolves to "harness-worktree" but the Agent()/Task() dispatch
26
+ // is missing the harness's isolation flag/kwarg.
27
+ HARNESS_FLAG_MISSING: 'harness_flag_missing',
28
+ // Isolation resolves to "harness-worktree" but the dispatch payload carries
29
+ // no usable subagent_type, so the guard cannot confirm it is a GSD executor.
30
+ NO_SUBAGENT_TYPE: 'no_subagent_type',
31
+ // Isolation resolves to "harness-worktree" but whether the workspace root
32
+ // is an isolated worktree could not be determined (e.g. git unresponsive).
33
+ CANNOT_DETERMINE_ISOLATION: 'cannot_determine_isolation',
34
+ // Isolation resolves to "harness-worktree" and the workspace root is
35
+ // confirmed NOT an isolated worktree.
36
+ NOT_ISOLATED_WORKTREE: 'not_isolated_worktree',
37
+ });
38
+
39
+ module.exports = { REASON_CODE };
@@ -130,6 +130,15 @@ function resolveSentinelRoot(cwd) {
130
130
  if (fs.existsSync(path.join(cwd, '.planning'))) {
131
131
  return cwd;
132
132
  }
133
+ // #3582: worktree-safety.cjs / project-root.cjs are tsc build artifacts
134
+ // (ADR-457), gitignored and absent on a raw plugin-marketplace / git-clone
135
+ // install that never ran `npm run build:lib`. Self-heal before either
136
+ // require below; a RuntimeBuildError (or any other failure) falls through
137
+ // to the existing catch's degrade-to-raw-`cwd` — unchanged behavior, just
138
+ // now attempted-healed-first rather than silently degrading on the first
139
+ // cold-tree encounter.
140
+ const { ensureRuntimeBuild } = require('../../gsd-core/bin/ensure-runtime-build.cjs');
141
+ ensureRuntimeBuild();
133
142
  const { resolveWorktreeRoot } = require('../../gsd-core/bin/lib/worktree-safety.cjs');
134
143
  const { root } = resolveWorktreeRoot(cwd);
135
144
  const { findProjectRoot } = require('../../gsd-core/bin/lib/project-root.cjs');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opengsd/gsd-core",
3
- "version": "1.10.0",
3
+ "version": "1.11.0",
4
4
  "description": "GSD Core is a meta-prompting, context engineering, and spec-driven development system for AI coding agents.",
5
5
  "main": ".opencode/plugins/gsd-core.js",
6
6
  "bin": {
@@ -23,6 +23,12 @@
23
23
  "scripts",
24
24
  "!scripts/gen-emitted-baseline.cjs",
25
25
  "!scripts/qa-smell-ratchet.cjs",
26
+ "!scripts/live-config-guard.cjs",
27
+ "!scripts/run-tests.cjs",
28
+ "!scripts/affected-tests-lib.cjs",
29
+ "!scripts/run-affected-tests.cjs",
30
+ "!scripts/lint-no-adhoc-regex-escape.cjs",
31
+ "!scripts/lint-allow-test-rule-refs.cjs",
26
32
  "pi",
27
33
  "vscode"
28
34
  ],
@@ -50,7 +56,7 @@
50
56
  "access": "public"
51
57
  },
52
58
  "engines": {
53
- "node": ">=22.0.0",
59
+ "node": ">=24.0.0",
54
60
  "npm": ">=10.0.0"
55
61
  },
56
62
  "dependencies": {
@@ -65,9 +71,11 @@
65
71
  "eslint": "^9.39.4",
66
72
  "eslint-plugin-n": "^17.24.0",
67
73
  "eslint-plugin-no-only-tests": "^3.4.0",
74
+ "espree": "^10.4.0",
68
75
  "fast-check": "^4.8.0",
69
76
  "globals": "^16.5.0",
70
- "js-yaml": "^4.2.1",
77
+ "js-yaml": "^4.3.1",
78
+ "re2js": "^2.8.6",
71
79
  "typescript": "^6.0.3",
72
80
  "typescript-eslint": "^8.60.0"
73
81
  },
@@ -81,6 +89,7 @@
81
89
  },
82
90
  "scripts": {
83
91
  "sync:launcher": "node scripts/sync-runtime-launcher.cjs",
92
+ "check:contract-drift": "node scripts/check-contract-drift.cjs",
84
93
  "check:env": "node scripts/check-env.cjs",
85
94
  "check:alias-drift": "node scripts/check-alias-drift.cjs",
86
95
  "check:identity-drift": "node scripts/lint-package-identity-drift.cjs",
@@ -105,10 +114,12 @@
105
114
  "prepublishOnly": "npm run build:lib && npm run build:hooks",
106
115
  "pretest": "npm run build:lib && npm run lint:skill-deps",
107
116
  "pretest:coverage": "npm run build:lib && npm run lint:skill-deps",
108
- "lint": "eslint . --cache --cache-location node_modules/.cache/eslint/",
117
+ "lint": "eslint . --cache --cache-location node_modules/.cache/eslint/ --max-warnings 0",
109
118
  "lint:fix": "eslint . --fix",
110
119
  "lint:table-schema-drift": "node scripts/lint-table-schema-drift.cjs",
111
- "lint:ci": "npm run lint && npm run lint:skill-deps && npm run lint:generated-sync && node scripts/lint-test-file-count.cjs && node scripts/lint-command-contract.cjs && node scripts/lint-pr-check-project-dir.cjs && npm run lint:legacy-name && node scripts/lint-regression-test-names.cjs && node scripts/lint-allow-test-rule-refs.cjs && node scripts/lint-resolution-provenance.cjs && node scripts/lint-emitted-drift-ack.cjs && node scripts/lint-portable-timeout.cjs && node scripts/validate-registry.cjs && node scripts/lint-table-schema-drift.cjs && node scripts/lint-fix-has-regression-test.cjs && node scripts/lint-example-parser-parity.cjs && node scripts/lint-docs-command-form.cjs",
120
+ "lint:frontmatter-scalar-broad-grep": "node scripts/lint-frontmatter-scalar-broad-grep.cjs",
121
+ "lint:removed-but-needed": "node scripts/lint-removed-but-needed.cjs",
122
+ "lint:ci": "npm run lint && npm run lint:skill-deps && npm run lint:generated-sync && node scripts/lint-test-file-count.cjs && node scripts/lint-command-contract.cjs && node scripts/lint-pr-check-project-dir.cjs && npm run lint:legacy-name && node scripts/lint-regression-test-names.cjs && node scripts/lint-allow-test-rule-refs.cjs && node scripts/lint-resolution-provenance.cjs && node scripts/lint-emitted-drift-ack.cjs && node scripts/lint-portable-timeout.cjs && node scripts/validate-registry.cjs && node scripts/lint-table-schema-drift.cjs && node scripts/lint-fix-has-regression-test.cjs && node scripts/lint-example-parser-parity.cjs && node scripts/lint-docs-command-form.cjs && node scripts/lint-plan-count-drift.cjs && node scripts/lint-milestone-window-drift.cjs && node scripts/lint-phase-enumeration-drift.cjs && node scripts/lint-planning-prompt-drift.cjs && node scripts/lint-unreachable-guard-drift.cjs && node scripts/lint-completion-ratio-drift.cjs && node scripts/lint-state-field-drift.cjs && node scripts/lint-state-write-path-drift.cjs && node scripts/lint-completion-predicate-drift.cjs && node scripts/lint-planning-snapshot-bypass-drift.cjs && node scripts/lint-health-diagnostic-rule-table.cjs && node scripts/lint-planning-artifact-writer-drift.cjs && node scripts/lint-frontmatter-scalar-broad-grep.cjs && node scripts/lint-removed-but-needed.cjs && node scripts/lint-no-adhoc-regex-escape.cjs && node scripts/lint-vendored-deps.cjs && npm run lint:hooks-runtime-build-seam && node scripts/check-contract-drift.cjs",
112
123
  "lint:allow-test-rule-refs": "node scripts/lint-allow-test-rule-refs.cjs",
113
124
  "lint:regression-names": "node scripts/lint-regression-test-names.cjs",
114
125
  "lint:descriptions": "node scripts/lint-descriptions.cjs",
@@ -116,11 +127,12 @@
116
127
  "lint:test-file-count": "node scripts/lint-test-file-count.cjs",
117
128
  "lint:pr-checks": "node scripts/lint-pr-check-project-dir.cjs",
118
129
  "lint:changeset": "node scripts/changeset/lint.cjs",
119
- "lint:generated-sync": "node scripts/gen-capability-registry.cjs --check && node scripts/gen-loop-host-contract.cjs --check && node scripts/gen-capability-matrix.cjs --check && node scripts/sync-manifest-versions.cjs --check && node scripts/gen-inventory-manifest.cjs --check && node scripts/generate-package-identity.cjs --check && node scripts/gen-plugin-skills.cjs --check && node scripts/gen-registry.cjs --check && node scripts/gen-adr-index.cjs --check && node scripts/check-glossary-refs.cjs --check && node scripts/lint-compiled-artifact-sync.cjs --check && node scripts/gen-context-index.cjs --check && node scripts/gen-section-manifest.cjs --check",
130
+ "lint:generated-sync": "node scripts/gen-capability-registry.cjs --check && node scripts/gen-loop-host-contract.cjs --check && node scripts/gen-capability-matrix.cjs --check && node scripts/sync-manifest-versions.cjs --check && node scripts/gen-inventory-manifest.cjs --check && node scripts/generate-package-identity.cjs --check && node scripts/gen-plugin-skills.cjs --check && node scripts/gen-registry.cjs --check && node scripts/gen-adr-index.cjs --check && node scripts/check-glossary-refs.cjs --check && node scripts/lint-compiled-artifact-sync.cjs --check && node scripts/gen-context-index.cjs --check && node scripts/gen-section-manifest.cjs --check && node scripts/gen-health-docs.cjs --check",
120
131
  "lint:docs": "node scripts/lint-docs-required.cjs",
121
132
  "lint:qa-smells": "node scripts/qa-smell-ratchet.cjs",
122
133
  "lint:legacy-name": "node scripts/lint-legacy-dir-name.cjs",
123
134
  "lint:docs-command-form": "node scripts/lint-docs-command-form.cjs",
135
+ "lint:hooks-runtime-build-seam": "node scripts/lint-hooks-runtime-build-seam.cjs",
124
136
  "ci:test-scope": "node scripts/ci-test-scope.cjs",
125
137
  "changeset": "node scripts/changeset/new.cjs",
126
138
  "changelog:render": "node scripts/changeset/cli.cjs render",
@@ -132,11 +144,11 @@
132
144
  "test:slow": "node scripts/run-tests.cjs --suite slow",
133
145
  "test:qa": "node scripts/run-tests.cjs --suite qa",
134
146
  "test:affected": "node scripts/run-affected-tests.cjs",
135
- "test:coverage": "c8 --check-coverage --lines 70 --branches 60 --reporter text --include 'gsd-core/bin/lib/*.cjs' --exclude 'tests/**' --all node scripts/run-tests.cjs",
147
+ "test:coverage": "c8 --check-coverage --lines 70 --branches 60 --reporter text --include 'gsd-core/bin/lib/**/*.cjs' --exclude 'tests/**' --all node scripts/run-tests.cjs",
136
148
  "test:coverage:scripts-floor": "c8 check-coverage --lines 55 --include 'scripts/**/*.cjs' --exclude 'tests/**' --all",
137
- "test:coverage:unit": "c8 --reporter text --reporter json-summary --include 'gsd-core/bin/lib/*.cjs' --exclude 'tests/**' --all node scripts/run-tests.cjs --suite unit && node scripts/check-coverage-gate.cjs",
149
+ "test:coverage:unit": "c8 --reporter text --reporter json-summary --include 'gsd-core/bin/lib/**/*.cjs' --exclude 'tests/**' --all node scripts/run-tests.cjs --suite unit && node scripts/check-coverage-gate.cjs",
138
150
  "test:coverage:unit:raw": "c8 --reporter none node scripts/run-tests.cjs --suite unit",
139
- "test:coverage:report": "c8 report --reporter text --reporter json-summary --include 'gsd-core/bin/lib/*.cjs' --exclude 'tests/**' --all && node scripts/check-coverage-gate.cjs",
151
+ "test:coverage:report": "c8 report --reporter text --reporter json-summary --include 'gsd-core/bin/lib/**/*.cjs' --exclude 'tests/**' --all && node scripts/check-coverage-gate.cjs",
140
152
  "test:coverage:all": "npm run test:coverage",
141
153
  "test:mutation": "stryker run",
142
154
  "test:mutation:since": "stryker run --incremental --since origin/next"
package/pi/gsd.cjs CHANGED
@@ -320,21 +320,35 @@ module.exports = function gsdPiExtension(pi) {
320
320
  getArgumentCompletions,
321
321
  handler: async (args, ctx) => {
322
322
  const cwd = (ctx && ctx.cwd) || process.cwd();
323
+ // #3456: Pi's command dispatcher awaits the handler and DISCARDS its
324
+ // return value (agent-session.ts: `await command.handler(args, ctx);
325
+ // return true;`) — #3097's `{ content: [...] }` return was silently
326
+ // dropped exactly like the pre-#3097 bare string. The ONLY command-
327
+ // output mechanism Pi consumes is `ctx.ui.notify(message, type)`
328
+ // (pi docs: extensions.md#piregistercommandname-options), so the output
329
+ // is pushed as a side effect on both the success and error paths.
330
+ // Guarded so a host ctx without `ui` degrades silently instead of
331
+ // crashing the command.
332
+ const notify = (ctx && ctx.ui && typeof ctx.ui.notify === 'function')
333
+ ? (message, type) => ctx.ui.notify(message, type)
334
+ : null;
323
335
  const { family, subcommand, args: rest } = parseGsdCommandArgs(args);
324
336
  let dispatchGsdCommand;
325
337
  try {
326
338
  ({ dispatchGsdCommand } = require(path.join(GSD_CORE, 'bin', 'lib', 'shell-command-projection.cjs')));
327
339
  } catch (e) {
328
- // #2991: return the structured { content } shape Pi's ExtensionAPI
329
- // displays, not a bare string (which Pi silently drops).
330
- return { content: [{ type: 'text', text: `GSD engine unavailable: ${e && e.message ? e.message : String(e)}` }] };
340
+ if (notify) {
341
+ notify(`GSD engine unavailable: ${e && e.message ? e.message : String(e)}`, 'error');
342
+ }
343
+ return;
331
344
  }
332
345
  const result = dispatchGsdCommand({ family, subcommand, args: rest, cwd });
333
- // #2991: match gsd_invoke's proven output shape so Pi actually displays it.
334
346
  const text = result.ok
335
347
  ? result.stdout
336
348
  : `GSD error: ${result.stderr || result.stdout || `dispatch failed (exit ${result.code})`}`;
337
- return { content: [{ type: 'text', text }] };
349
+ if (notify) {
350
+ notify(text, result.ok ? 'info' : 'error');
351
+ }
338
352
  },
339
353
  });
340
354
 
@@ -0,0 +1,4 @@
1
+ {
2
+ "$comment": "ADR-3180 Decision 4(e) ratchet, owned by Phase 8 (#3218). See scripts/lint-planning-prompt-drift.cjs. SHRINK-ONLY: entries are removed as sites migrate to the gsd-core CLI; new or changed entries fail lint:ci. `count` is the number of byte-identical (file, text) occurrences acknowledged at this site — a run producing fewer fails as a partial migration, more fails as an unacknowledged new copy. Emptied by #3218: all 6 recorded sites (7 occurrences) migrated to `gsd_run query find-phase` — see gsd-core/workflows/{execute-plan,plan-phase,plan-review-convergence,progress}.md.",
3
+ "entries": []
4
+ }
@@ -0,0 +1,12 @@
1
+ {
2
+ "$comment": "ADR-3180 §8.1 rule 2 ratchet, owned by Phase 11 (#3309). See scripts/lint-planning-snapshot-bypass-drift.cjs. SHRINK-ONLY: entries are removed as cmdValidateHealth migrates onto src/planning-snapshot.cts; new or changed entries fail lint:ci. `count` is the number of byte-identical (file, text) occurrences acknowledged at this site — a run producing fewer fails as a partial migration, more fails as an unacknowledged new copy.",
3
+ "entries": [
4
+ {
5
+ "file": "src/verify.cts",
6
+ "text": "const stateContent = fs.readFileSync(statePath, 'utf-8');",
7
+ "derivation": "planning-snapshot-bypass",
8
+ "owner_issue": "#3309",
9
+ "count": 1
10
+ }
11
+ ]
12
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "$comment": "#3409 unreachable-shell-guard ratchet. See scripts/lint-unreachable-guard-drift.cjs. SHRINK-ONLY: entries are removed as sites migrate off the unreachable-arm shape; new or changed entries fail lint:ci. `count` is the number of byte-identical (file, text) occurrences acknowledged at this site — a run producing fewer fails as a partial migration, more fails as an unacknowledged new copy.",
3
+ "entries": []
4
+ }
@@ -22,6 +22,7 @@ const LINT_REASON = Object.freeze({
22
22
  OK_NO_USER_FACING_CHANGES: 'ok_no_user_facing_changes',
23
23
  FAIL_MISSING_FRAGMENT: 'fail_missing_fragment',
24
24
  FAIL_INVALID_FRAGMENT: 'fail_invalid_fragment',
25
+ FAIL_PR_FIELD_DRIFT: 'fail_pr_field_drift',
25
26
  });
26
27
 
27
28
  const OPT_OUT_LABEL = 'no-changelog';
@@ -35,8 +36,6 @@ const USER_FACING_PREFIXES = [
35
36
  'agents/',
36
37
  'commands/',
37
38
  'hooks/',
38
- 'sdk/src/',
39
- 'sdk/prompts/',
40
39
  ];
41
40
 
42
41
  // Exact-match user-facing files. Any direct edit to one of these without a
@@ -53,10 +52,47 @@ function isFragment(file) {
53
52
  return /^\.changeset\/[^/]+\.md$/.test(file) && !file.endsWith('/README.md');
54
53
  }
55
54
 
56
- function evaluateLint({ changedFiles, labels, fragmentFailures = [] }) {
55
+ /**
56
+ * DEFECT.CHANGESET-PR-FIELD-DRIFT (#3316, #3325): a fragment's `pr:` field is
57
+ * a guess (issue number, stacked-PR leftover) that never got backfilled to
58
+ * the real PR number after `gh api POST /pulls` returned it.
59
+ *
60
+ * Pure: given `prEntries` (`[{ file, pr }]`, one entry per successfully
61
+ * parsed changed fragment — `pr` is always a positive integer, since
62
+ * `parseFragment` already rejects `pr: 0` / non-numeric values as
63
+ * `invalid_pr` before a fragment ever reaches this function) and
64
+ * `realPrNumber` (the PR this run belongs to, or `null` when unknown —
65
+ * push/non-PR runs), returns every fragment whose `pr` disagrees with
66
+ * `realPrNumber`. `realPrNumber == null` always yields `[]`: with no PR
67
+ * event payload to compare against, there is nothing to drift-check.
68
+ *
69
+ * `pr === 0` is always silent regardless of `realPrNumber` — CONTRIBUTING.md
70
+ * documents `pr: 0` as the deliberate placeholder used "during initial
71
+ * commit" before `gh api POST /pulls` returns the real number, so it is not
72
+ * yet a drifted value, just an unbackfilled one. (In practice `parseFragment`
73
+ * already rejects `pr: 0` as `invalid_pr` before a fragment reaches this
74
+ * function via `main()`'s wiring — this guard documents and locks in the
75
+ * pure function's own contract independent of that upstream check.)
76
+ */
77
+ function findPrFieldDrift(prEntries, realPrNumber) {
78
+ if (realPrNumber == null) return [];
79
+ const drift = [];
80
+ for (const { file, pr } of prEntries) {
81
+ if (pr === 0) continue;
82
+ if (pr !== realPrNumber) {
83
+ drift.push({ file, found: pr, expected: realPrNumber });
84
+ }
85
+ }
86
+ return drift;
87
+ }
88
+
89
+ function evaluateLint({ changedFiles, labels, fragmentFailures = [], prFieldDrift = [] }) {
57
90
  if (fragmentFailures.length > 0) {
58
91
  return { ok: false, reason: LINT_REASON.FAIL_INVALID_FRAGMENT, failures: fragmentFailures };
59
92
  }
93
+ if (prFieldDrift.length > 0) {
94
+ return { ok: false, reason: LINT_REASON.FAIL_PR_FIELD_DRIFT, drift: prFieldDrift };
95
+ }
60
96
  if (changedFiles.some(isFragment)) {
61
97
  return { ok: true, reason: LINT_REASON.OK_FRAGMENT_PRESENT };
62
98
  }
@@ -78,10 +114,18 @@ function main() {
78
114
  // GitHub Actions event payload path
79
115
  const eventPath = process.env.GITHUB_EVENT_PATH;
80
116
  let labels = [];
117
+ // DEFECT.CHANGESET-PR-FIELD-DRIFT: the real PR number this run belongs to,
118
+ // read from the same event payload. `null` on a push / non-PR run (no
119
+ // `pull_request` in the payload, or no payload at all) — the drift check
120
+ // below is a no-op in that case, it never fails a push run.
121
+ let realPrNumber = null;
81
122
  if (eventPath && fs.existsSync(eventPath)) {
82
123
  try {
83
124
  const event = JSON.parse(fs.readFileSync(eventPath, 'utf8'));
84
125
  labels = (event.pull_request?.labels || []).map((l) => l.name);
126
+ if (event.pull_request && Number.isInteger(event.pull_request.number)) {
127
+ realPrNumber = event.pull_request.number;
128
+ }
85
129
  } catch { /* fall through */ }
86
130
  }
87
131
  // #2988: local fallback must match the repo's integration branch (`next`),
@@ -107,6 +151,7 @@ function main() {
107
151
 
108
152
  // Validate the content of every changed fragment file.
109
153
  const fragmentFailures = [];
154
+ const prEntries = [];
110
155
  for (const file of changedFiles) {
111
156
  if (!isFragment(file)) continue;
112
157
  // A fragment path in the diff that no longer exists on disk was deleted in
@@ -125,10 +170,13 @@ function main() {
125
170
  const result = parseFragment(src);
126
171
  if (!result.ok) {
127
172
  fragmentFailures.push({ file, reason: result.reason, detail: result.detail });
173
+ continue;
128
174
  }
175
+ prEntries.push({ file, pr: result.fragment.pr });
129
176
  }
130
177
 
131
- const verdict = evaluateLint({ changedFiles, labels, fragmentFailures });
178
+ const prFieldDrift = findPrFieldDrift(prEntries, realPrNumber);
179
+ const verdict = evaluateLint({ changedFiles, labels, fragmentFailures, prFieldDrift });
132
180
  if (process.argv.includes('--json')) {
133
181
  process.stdout.write(JSON.stringify({ ...verdict, changedFiles, labels }, null, 2) + '\n');
134
182
  } else if (verdict.ok) {
@@ -141,6 +189,13 @@ function main() {
141
189
  process.stderr.write(` ${f.file}: ${f.reason}${detail}\n`);
142
190
  }
143
191
  process.stderr.write(`Fix the fragment(s) above before merging.\n`);
192
+ } else if (verdict.reason === LINT_REASON.FAIL_PR_FIELD_DRIFT) {
193
+ process.stderr.write(`\nERROR changeset-lint: ${verdict.reason}\n`);
194
+ process.stderr.write(`The following .changeset fragment(s) have a stale \`pr:\` field (DEFECT.CHANGESET-PR-FIELD-DRIFT):\n`);
195
+ for (const d of verdict.drift) {
196
+ process.stderr.write(` ${d.file}: pr: ${d.found}, expected pr: ${d.expected}\n`);
197
+ }
198
+ process.stderr.write(`Backfill \`pr:\` with this PR's real number (see .changeset/README.md), then push again.\n`);
144
199
  } else {
145
200
  process.stderr.write(`\nERROR changeset-lint: ${verdict.reason}\n`);
146
201
  process.stderr.write(`PR touches user-facing files but does not include a .changeset/*.md fragment.\n`);
@@ -152,4 +207,4 @@ function main() {
152
207
 
153
208
  if (require.main === module) runMain(main);
154
209
 
155
- module.exports = { evaluateLint, LINT_REASON, OPT_OUT_LABEL, isUserFacing, isFragment, DEFAULT_BASE };
210
+ module.exports = { evaluateLint, LINT_REASON, OPT_OUT_LABEL, isUserFacing, isFragment, DEFAULT_BASE, findPrFieldDrift };
@@ -4,9 +4,10 @@ const fs = require('node:fs');
4
4
  const path = require('node:path');
5
5
 
6
6
  const { ExitError, runMain } = require('./lib/cli-exit.cjs');
7
+ const { FAMILIES, ALIAS_TABLE } = require('./lib/alias-drift-families.cjs');
7
8
 
8
9
  const ROOT = path.resolve(__dirname, '..');
9
- const aliasesPath = path.join(ROOT, 'gsd-core', 'bin', 'lib', 'command-aliases.cjs');
10
+ const aliasesPath = path.join(ROOT, 'gsd-core', 'bin', 'lib', `${ALIAS_TABLE}.cjs`);
10
11
 
11
12
  function fail(message) {
12
13
  process.stderr.write(`${message}\n`);
@@ -36,48 +37,11 @@ function main() {
36
37
 
37
38
  const aliases = require(aliasesPath);
38
39
 
39
- const families = [
40
- {
41
- commandAliases: 'STATE_COMMAND_ALIASES',
42
- subcommands: 'STATE_SUBCOMMANDS',
43
- routerPath: path.join(ROOT, 'gsd-core', 'bin', 'lib', 'state-command-router.cjs'),
44
- },
45
- {
46
- commandAliases: 'VERIFY_COMMAND_ALIASES',
47
- subcommands: 'VERIFY_SUBCOMMANDS',
48
- routerPath: path.join(ROOT, 'gsd-core', 'bin', 'lib', 'verify-command-router.cjs'),
49
- },
50
- {
51
- commandAliases: 'INIT_COMMAND_ALIASES',
52
- subcommands: 'INIT_SUBCOMMANDS',
53
- routerPath: path.join(ROOT, 'gsd-core', 'bin', 'lib', 'init-command-router.cjs'),
54
- },
55
- {
56
- commandAliases: 'PHASE_COMMAND_ALIASES',
57
- subcommands: 'PHASE_SUBCOMMANDS',
58
- routerPath: path.join(ROOT, 'gsd-core', 'bin', 'lib', 'phase-command-router.cjs'),
59
- },
60
- {
61
- commandAliases: 'PHASES_COMMAND_ALIASES',
62
- subcommands: 'PHASES_SUBCOMMANDS',
63
- routerPath: path.join(ROOT, 'gsd-core', 'bin', 'lib', 'phases-command-router.cjs'),
64
- },
65
- {
66
- commandAliases: 'VALIDATE_COMMAND_ALIASES',
67
- subcommands: 'VALIDATE_SUBCOMMANDS',
68
- routerPath: path.join(ROOT, 'gsd-core', 'bin', 'lib', 'validate-command-router.cjs'),
69
- },
70
- {
71
- commandAliases: 'ROADMAP_COMMAND_ALIASES',
72
- subcommands: 'ROADMAP_SUBCOMMANDS',
73
- routerPath: path.join(ROOT, 'gsd-core', 'bin', 'lib', 'roadmap-command-router.cjs'),
74
- },
75
- {
76
- commandAliases: 'EVAL_COMMAND_ALIASES',
77
- subcommands: 'EVAL_SUBCOMMANDS',
78
- routerPath: path.join(ROOT, 'gsd-core', 'bin', 'lib', 'eval-command-router.cjs'),
79
- },
80
- ];
40
+ const families = FAMILIES.map((family) => ({
41
+ commandAliases: family.commandAliases,
42
+ subcommands: family.subcommands,
43
+ routerPath: path.join(ROOT, 'gsd-core', 'bin', 'lib', `${family.router}.cjs`),
44
+ }));
81
45
 
82
46
  for (const family of families) {
83
47
  const commandAliases = aliases[family.commandAliases];