@opengsd/gsd-core 1.11.0 → 1.13.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 (498) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/.opencode/plugins/gsd-core.js +12 -0
  4. package/agents/gsd-code-fixer.md +1 -1
  5. package/agents/gsd-debug-session-manager.md +1 -1
  6. package/agents/gsd-debugger.md +1 -1
  7. package/agents/gsd-dom-verifier.md +169 -0
  8. package/agents/gsd-eval-auditor.md +1 -1
  9. package/agents/gsd-executor.md +78 -42
  10. package/agents/gsd-framework-selector.md +1 -3
  11. package/agents/gsd-intel-updater.md +1 -1
  12. package/agents/gsd-mempalace-curator.md +0 -1
  13. package/agents/gsd-pattern-mapper.md +11 -0
  14. package/agents/gsd-phase-researcher.md +3 -1
  15. package/agents/gsd-plan-checker.md +91 -112
  16. package/agents/gsd-planner.md +20 -4
  17. package/agents/gsd-project-researcher.md +1 -1
  18. package/agents/gsd-research-synthesizer.md +2 -2
  19. package/agents/gsd-roadmapper.md +15 -11
  20. package/agents/gsd-ui-checker.md +82 -7
  21. package/agents/gsd-ui-researcher.md +70 -3
  22. package/agents/gsd-verifier.md +24 -2
  23. package/bin/install.js +847 -200
  24. package/commands/gsd/discuss-phase.md +1 -1
  25. package/commands/gsd/execute-phase.md +1 -1
  26. package/commands/gsd/import.md +1 -1
  27. package/commands/gsd/ns-workflow.md +2 -1
  28. package/commands/gsd/phase.md +1 -1
  29. package/commands/gsd/quick-batch.md +105 -0
  30. package/commands/gsd/quick.md +8 -4
  31. package/commands/gsd/surface.md +18 -8
  32. package/gsd-core/bin/gsd-tools.cjs +761 -100
  33. package/gsd-core/bin/lib/active-workstream-store.cjs +8 -0
  34. package/gsd-core/bin/lib/adr-parser.cjs +13 -7
  35. package/gsd-core/bin/lib/agent-install-check.cjs +162 -0
  36. package/gsd-core/bin/lib/api-coverage.cjs +30 -9
  37. package/gsd-core/bin/lib/artifacts.cjs +2 -0
  38. package/gsd-core/bin/lib/assumption-delta.cjs +30 -11
  39. package/gsd-core/bin/lib/audit.cjs +163 -41
  40. package/gsd-core/bin/lib/broken-windows.cjs +306 -28
  41. package/gsd-core/bin/lib/capability-activation.cjs +27 -0
  42. package/gsd-core/bin/lib/capability-lock.cjs +10 -4
  43. package/gsd-core/bin/lib/capability-registry.cjs +785 -144
  44. package/gsd-core/bin/lib/capability-state.cjs +25 -4
  45. package/gsd-core/bin/lib/capability-validator.cjs +321 -18
  46. package/gsd-core/bin/lib/capability-writer.cjs +14 -4
  47. package/gsd-core/bin/lib/check-command-router.cjs +229 -6
  48. package/gsd-core/bin/lib/claude-orchestration.cjs +10 -25
  49. package/gsd-core/bin/lib/cli-exit.cjs +496 -10
  50. package/gsd-core/bin/lib/clusters.cjs +1 -0
  51. package/gsd-core/bin/lib/code-review-depth.cjs +288 -0
  52. package/gsd-core/bin/lib/codex-agent-toml.cjs +410 -4
  53. package/gsd-core/bin/lib/command-aliases.cjs +16 -0
  54. package/gsd-core/bin/lib/command-arg-projection.cjs +144 -14
  55. package/gsd-core/bin/lib/command-routing-hub.cjs +31 -2
  56. package/gsd-core/bin/lib/commands.cjs +877 -54
  57. package/gsd-core/bin/lib/complexity-trigger.cjs +26 -6
  58. package/gsd-core/bin/lib/config-loader.cjs +121 -29
  59. package/gsd-core/bin/lib/config.cjs +92 -2
  60. package/gsd-core/bin/lib/configuration.cjs +129 -37
  61. package/gsd-core/bin/lib/core-utils.cjs +118 -14
  62. package/gsd-core/bin/lib/decisions.cjs +213 -1
  63. package/gsd-core/bin/lib/edge-probe.cjs +23 -2
  64. package/gsd-core/bin/lib/estimate-cli.cjs +55 -11
  65. package/gsd-core/bin/lib/exit-code-registry.cjs +98 -0
  66. package/gsd-core/bin/lib/file-overlap-partitioner.cjs +74 -0
  67. package/gsd-core/bin/lib/frontmatter.cjs +975 -326
  68. package/gsd-core/bin/lib/gap-checker.cjs +41 -8
  69. package/gsd-core/bin/lib/git-base-branch.cjs +182 -39
  70. package/gsd-core/bin/lib/health-diagnostic-rules/consistency.cjs +7 -3
  71. package/gsd-core/bin/lib/health-diagnostic-rules/phase-structure.cjs +8 -2
  72. package/gsd-core/bin/lib/health-diagnostic-rules/roadmap-disk-consistency.cjs +60 -14
  73. package/gsd-core/bin/lib/health-diagnostic-rules/state-consistency.cjs +75 -22
  74. package/gsd-core/bin/lib/health-diagnostic-rules/worktree-health.cjs +22 -8
  75. package/gsd-core/bin/lib/health-diagnostic.cjs +23 -3
  76. package/gsd-core/bin/lib/host-integration.cjs +96 -11
  77. package/gsd-core/bin/lib/init-command-router.cjs +132 -21
  78. package/gsd-core/bin/lib/init.cjs +252 -56
  79. package/gsd-core/bin/lib/install-engine.cjs +252 -15
  80. package/gsd-core/bin/lib/install-model-override-resolver.cjs +78 -1
  81. package/gsd-core/bin/lib/install-profiles.cjs +100 -18
  82. package/gsd-core/bin/lib/installer-migration-report.cjs +4 -0
  83. package/gsd-core/bin/lib/installer-migrations/010-antigravity-retire-confighome-artifacts.cjs +169 -0
  84. package/gsd-core/bin/lib/installer-migrations.cjs +10 -7
  85. package/gsd-core/bin/lib/intel.cjs +101 -26
  86. package/gsd-core/bin/lib/io.cjs +195 -15
  87. package/gsd-core/bin/lib/learnings.cjs +85 -14
  88. package/gsd-core/bin/lib/legacy-cleanup.cjs +8 -2
  89. package/gsd-core/bin/lib/loop-resolver.cjs +14 -8
  90. package/gsd-core/bin/lib/markdown-table.cjs +175 -4
  91. package/gsd-core/bin/lib/milestone.cjs +112 -7
  92. package/gsd-core/bin/lib/model-catalog.cjs +177 -19
  93. package/gsd-core/bin/lib/model-resolver.cjs +10 -28
  94. package/gsd-core/bin/lib/onboard-projection.cjs +5 -1
  95. package/gsd-core/bin/lib/phase-command-router.cjs +13 -6
  96. package/gsd-core/bin/lib/phase-estimation.cjs +17 -8
  97. package/gsd-core/bin/lib/phase-id.cjs +321 -13
  98. package/gsd-core/bin/lib/phase-lifecycle.cjs +24 -16
  99. package/gsd-core/bin/lib/phase-locator.cjs +138 -17
  100. package/gsd-core/bin/lib/phase.cjs +1175 -115
  101. package/gsd-core/bin/lib/plan-document.cjs +273 -0
  102. package/gsd-core/bin/lib/plan-scan.cjs +13 -2
  103. package/gsd-core/bin/lib/planning-command-router.cjs +61 -0
  104. package/gsd-core/bin/lib/planning-inspect.cjs +1168 -0
  105. package/gsd-core/bin/lib/planning-snapshot.cjs +165 -34
  106. package/gsd-core/bin/lib/planning-workspace.cjs +159 -28
  107. package/gsd-core/bin/lib/probe-core.cjs +4 -1
  108. package/gsd-core/bin/lib/profile-pipeline-command-router.cjs +50 -7
  109. package/gsd-core/bin/lib/profile-pipeline.cjs +6 -3
  110. package/gsd-core/bin/lib/quick-batch-command-router.cjs +285 -0
  111. package/gsd-core/bin/lib/quick-batch-dispatch.cjs +250 -0
  112. package/gsd-core/bin/lib/quick-batch.cjs +840 -0
  113. package/gsd-core/bin/lib/real-home-guard.cjs +419 -0
  114. package/gsd-core/bin/lib/refactor-trigger-command-router.cjs +71 -45
  115. package/gsd-core/bin/lib/review-lane-descriptor.cjs +62 -14
  116. package/gsd-core/bin/lib/review-lane-invocation.cjs +73 -1
  117. package/gsd-core/bin/lib/review-lane-runner.cjs +136 -10
  118. package/gsd-core/bin/lib/roadmap-command-router.cjs +45 -31
  119. package/gsd-core/bin/lib/roadmap-parser.cjs +577 -41
  120. package/gsd-core/bin/lib/roadmap.cjs +248 -64
  121. package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +329 -41
  122. package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +16 -17
  123. package/gsd-core/bin/lib/runtime-artifact-layout.cjs +320 -109
  124. package/gsd-core/bin/lib/runtime-hooks-surface.cjs +487 -83
  125. package/gsd-core/bin/lib/runtime-identity.cjs +234 -0
  126. package/gsd-core/bin/lib/runtime-slash.cjs +72 -2
  127. package/gsd-core/bin/lib/shell-command-projection.cjs +75 -8
  128. package/gsd-core/bin/lib/smart-entry.cjs +19 -31
  129. package/gsd-core/bin/lib/spec-section.cjs +12 -7
  130. package/gsd-core/bin/lib/state-command-router.cjs +47 -18
  131. package/gsd-core/bin/lib/state-contract.cjs +359 -0
  132. package/gsd-core/bin/lib/state-document.cjs +216 -5
  133. package/gsd-core/bin/lib/state-md-schema.cjs +231 -0
  134. package/gsd-core/bin/lib/state-transition.cjs +850 -145
  135. package/gsd-core/bin/lib/state.cjs +1629 -287
  136. package/gsd-core/bin/lib/surface.cjs +33 -10
  137. package/gsd-core/bin/lib/task-command-router.cjs +111 -1
  138. package/gsd-core/bin/lib/task-content-resolution.cjs +368 -0
  139. package/gsd-core/bin/lib/tdd-red-evidence.cjs +133 -0
  140. package/gsd-core/bin/lib/teams-status.cjs +4 -1
  141. package/gsd-core/bin/lib/uat-predicate.cjs +58 -20
  142. package/gsd-core/bin/lib/uat.cjs +2542 -387
  143. package/gsd-core/bin/lib/ui-consideration-probe.cjs +9 -1
  144. package/gsd-core/bin/lib/ui-safety-gate.cjs +37 -7
  145. package/gsd-core/bin/lib/unusable-input.cjs +13 -0
  146. package/gsd-core/bin/lib/update-context.cjs +6 -2
  147. package/gsd-core/bin/lib/validate-command-router.cjs +2 -2
  148. package/gsd-core/bin/lib/validate.cjs +230 -12
  149. package/gsd-core/bin/lib/vendor/README.md +43 -5
  150. package/gsd-core/bin/lib/vendor/js-yaml.cjs +3014 -0
  151. package/gsd-core/bin/lib/verification-command-router.cjs +2 -1
  152. package/gsd-core/bin/lib/verification.cjs +287 -13
  153. package/gsd-core/bin/lib/verify-command-grounding.cjs +846 -0
  154. package/gsd-core/bin/lib/verify-command-router.cjs +1 -0
  155. package/gsd-core/bin/lib/verify.cjs +441 -56
  156. package/gsd-core/bin/lib/workstream-inventory.cjs +20 -2
  157. package/gsd-core/bin/lib/workstream-name-policy.cjs +25 -4
  158. package/gsd-core/bin/lib/worktree-base-ref.cjs +66 -12
  159. package/gsd-core/bin/lib/worktree-safety.cjs +185 -21
  160. package/gsd-core/bin/shared/config-defaults.manifest.json +7 -1
  161. package/gsd-core/bin/shared/config-schema.manifest.json +13 -0
  162. package/gsd-core/bin/shared/exit-codes.json +8 -0
  163. package/gsd-core/bin/shared/exit-codes.sh +20 -0
  164. package/gsd-core/bin/shared/model-catalog.json +8 -1
  165. package/gsd-core/bin/verify-reapply-patches.cjs +70 -3
  166. package/gsd-core/references/agent-contracts.md +6 -5
  167. package/gsd-core/references/api-coverage.md +24 -2
  168. package/gsd-core/references/autonomous-smart-discuss.md +3 -3
  169. package/gsd-core/references/checkpoints.md +37 -19
  170. package/gsd-core/references/decimal-phase-calculation.md +5 -5
  171. package/gsd-core/references/edge-probe.md +17 -5
  172. package/gsd-core/references/execute-mvp-tdd.md +18 -18
  173. package/gsd-core/references/execute-phase-between-wave-reset.md +9 -12
  174. package/gsd-core/references/execute-phase-response-language.md +6 -0
  175. package/gsd-core/references/execute-phase-wave-guard.md +11 -9
  176. package/gsd-core/references/executor-examples.md +42 -0
  177. package/gsd-core/references/failing-direction.md +78 -0
  178. package/gsd-core/references/few-shot-examples/plan-checker.md +15 -15
  179. package/gsd-core/references/gate-prompts.md +1 -1
  180. package/gsd-core/references/git-integration.md +5 -5
  181. package/gsd-core/references/git-planning-commit.md +3 -3
  182. package/gsd-core/references/gsd-run-resolver.md +1 -1
  183. package/gsd-core/references/loop-hook-dispatch.md +22 -0
  184. package/gsd-core/references/model-profiles.md +1 -1
  185. package/gsd-core/references/mvp-concepts.md +2 -2
  186. package/gsd-core/references/nyquist-compliance.md +74 -0
  187. package/gsd-core/references/offer-next.md +3 -5
  188. package/gsd-core/references/phase-argument-parsing.md +3 -3
  189. package/gsd-core/references/plan-checker-examples.md +41 -0
  190. package/gsd-core/references/planner-antipatterns.md +25 -0
  191. package/gsd-core/references/planner-chunked.md +5 -1
  192. package/gsd-core/references/planner-coupling.md +42 -0
  193. package/gsd-core/references/planner-failing-direction.md +53 -0
  194. package/gsd-core/references/planner-human-verify-mode.md +15 -1
  195. package/gsd-core/references/planner-quick-batch.md +71 -0
  196. package/gsd-core/references/planner-reviews.md +47 -0
  197. package/gsd-core/references/planner-revision.md +76 -3
  198. package/gsd-core/references/planner-verify-command-grounding.md +17 -0
  199. package/gsd-core/references/planning-config.md +39 -9
  200. package/gsd-core/references/response-language-directive.md +9 -0
  201. package/gsd-core/references/reviewer-instances.md +31 -0
  202. package/gsd-core/references/revision-loop.md +118 -11
  203. package/gsd-core/references/runtime-aware-dispatch.md +1 -1
  204. package/gsd-core/references/tdd.md +15 -12
  205. package/gsd-core/references/ui-brand.md +65 -21
  206. package/gsd-core/references/ui-consideration-probe.md +1 -1
  207. package/gsd-core/references/universal-anti-patterns.md +2 -2
  208. package/gsd-core/references/verifier-evidence-gate.md +160 -0
  209. package/gsd-core/references/verify-command-path-resolvability.md +42 -0
  210. package/gsd-core/references/verify-mvp-mode.md +1 -1
  211. package/gsd-core/references/workstream-flag.md +11 -11
  212. package/gsd-core/templates/README.md +1 -1
  213. package/gsd-core/templates/SECURITY.md +3 -3
  214. package/gsd-core/templates/UI-SPEC.md +25 -3
  215. package/gsd-core/templates/VALIDATION.md +3 -3
  216. package/gsd-core/templates/phase-prompt.md +7 -0
  217. package/gsd-core/templates/state.md +7 -0
  218. package/gsd-core/templates/verification-report.md +5 -0
  219. package/gsd-core/workflows/_runtime-launcher.snippet.sh +1 -1
  220. package/gsd-core/workflows/add-backlog.md +3 -1
  221. package/gsd-core/workflows/add-phase.md +5 -3
  222. package/gsd-core/workflows/add-tests.md +4 -9
  223. package/gsd-core/workflows/add-todo.md +2 -2
  224. package/gsd-core/workflows/ai-integration-phase.md +5 -10
  225. package/gsd-core/workflows/analyze-dependencies.md +2 -0
  226. package/gsd-core/workflows/audit-fix.md +14 -3
  227. package/gsd-core/workflows/audit-milestone.md +11 -9
  228. package/gsd-core/workflows/audit-uat.md +19 -2
  229. package/gsd-core/workflows/autonomous/steps/converge-fail-fast.md +2 -2
  230. package/gsd-core/workflows/autonomous.md +12 -26
  231. package/gsd-core/workflows/check-todos.md +2 -2
  232. package/gsd-core/workflows/cleanup.md +3 -3
  233. package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +16 -14
  234. package/gsd-core/workflows/code-review-fix.md +3 -1
  235. package/gsd-core/workflows/code-review.md +192 -69
  236. package/gsd-core/workflows/complete-milestone.md +28 -14
  237. package/gsd-core/workflows/debug.md +6 -4
  238. package/gsd-core/workflows/diagnose-issues.md +17 -7
  239. package/gsd-core/workflows/discuss-phase/modes/advisor.md +3 -1
  240. package/gsd-core/workflows/discuss-phase/modes/all.md +2 -0
  241. package/gsd-core/workflows/discuss-phase/modes/analyze.md +2 -0
  242. package/gsd-core/workflows/discuss-phase/modes/auto.md +2 -0
  243. package/gsd-core/workflows/discuss-phase/modes/batch.md +2 -0
  244. package/gsd-core/workflows/discuss-phase/modes/chain.md +5 -7
  245. package/gsd-core/workflows/discuss-phase/modes/default.md +2 -0
  246. package/gsd-core/workflows/discuss-phase/modes/power.md +2 -0
  247. package/gsd-core/workflows/discuss-phase/modes/text.md +3 -1
  248. package/gsd-core/workflows/discuss-phase/templates/context.md +2 -0
  249. package/gsd-core/workflows/discuss-phase/templates/discussion-log.md +2 -0
  250. package/gsd-core/workflows/discuss-phase-assumptions/steps/auto-advance-dispatch.md +1 -3
  251. package/gsd-core/workflows/discuss-phase-assumptions.md +3 -3
  252. package/gsd-core/workflows/discuss-phase-power.md +2 -0
  253. package/gsd-core/workflows/discuss-phase.md +2 -2
  254. package/gsd-core/workflows/do.md +46 -19
  255. package/gsd-core/workflows/docs-update.md +6 -5
  256. package/gsd-core/workflows/edit-phase.md +3 -1
  257. package/gsd-core/workflows/eval-review.md +5 -10
  258. package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +3 -1
  259. package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +129 -11
  260. package/gsd-core/workflows/execute-phase/steps/gap-closure-artifacts.md +1 -1
  261. package/gsd-core/workflows/execute-phase/steps/partial-wave.md +1 -1
  262. package/gsd-core/workflows/execute-phase/steps/per-plan-executor-routing.md +1 -1
  263. package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +29 -5
  264. package/gsd-core/workflows/execute-phase/steps/post-merge-gate.md +2 -2
  265. package/gsd-core/workflows/execute-phase/steps/protected-branch.md +21 -0
  266. package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +4 -2
  267. package/gsd-core/workflows/execute-phase/steps/tdd-applicability-resolution.md +25 -0
  268. package/gsd-core/workflows/execute-phase/steps/wave-post-gate-hooks.md +39 -0
  269. package/gsd-core/workflows/execute-phase/steps/worktree-recovery-policy.md +2 -0
  270. package/gsd-core/workflows/execute-phase.md +68 -66
  271. package/gsd-core/workflows/execute-plan.md +25 -20
  272. package/gsd-core/workflows/explore.md +3 -1
  273. package/gsd-core/workflows/extract-learnings.md +3 -1
  274. package/gsd-core/workflows/fast.md +8 -2
  275. package/gsd-core/workflows/forensics.md +3 -1
  276. package/gsd-core/workflows/graduation.md +6 -6
  277. package/gsd-core/workflows/health.md +4 -7
  278. package/gsd-core/workflows/help/modes/brief.md +2 -0
  279. package/gsd-core/workflows/help/modes/default.md +2 -0
  280. package/gsd-core/workflows/help/modes/full.md +12 -0
  281. package/gsd-core/workflows/help/modes/topic.md +2 -0
  282. package/gsd-core/workflows/help.md +2 -0
  283. package/gsd-core/workflows/import.md +17 -14
  284. package/gsd-core/workflows/inbox.md +5 -6
  285. package/gsd-core/workflows/ingest-docs.md +45 -12
  286. package/gsd-core/workflows/insert-phase.md +7 -5
  287. package/gsd-core/workflows/list-phase-assumptions.md +2 -0
  288. package/gsd-core/workflows/list-seeds.md +7 -3
  289. package/gsd-core/workflows/list-workspaces.md +3 -1
  290. package/gsd-core/workflows/manager.md +15 -26
  291. package/gsd-core/workflows/map-codebase.md +3 -1
  292. package/gsd-core/workflows/milestone-summary.md +3 -1
  293. package/gsd-core/workflows/mvp-phase.md +3 -3
  294. package/gsd-core/workflows/new-milestone.md +10 -22
  295. package/gsd-core/workflows/new-project/steps/auto-mode-config.md +1 -1
  296. package/gsd-core/workflows/new-project.md +17 -29
  297. package/gsd-core/workflows/new-workspace.md +2 -2
  298. package/gsd-core/workflows/next.md +4 -2
  299. package/gsd-core/workflows/node-repair.md +2 -0
  300. package/gsd-core/workflows/note.md +2 -0
  301. package/gsd-core/workflows/onboard.md +1 -1
  302. package/gsd-core/workflows/pause-work.md +20 -5
  303. package/gsd-core/workflows/plan-phase/steps/adr-ingest-express-path.md +1 -1
  304. package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +100 -18
  305. package/gsd-core/workflows/plan-phase/steps/prd-express-path.md +4 -4
  306. package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +12 -3
  307. package/gsd-core/workflows/plan-phase.md +251 -54
  308. package/gsd-core/workflows/plan-review-convergence.md +148 -19
  309. package/gsd-core/workflows/plant-seed.md +3 -3
  310. package/gsd-core/workflows/pr-branch.md +195 -51
  311. package/gsd-core/workflows/profile-user.md +17 -15
  312. package/gsd-core/workflows/progress/steps/forensic-audit.md +1 -1
  313. package/gsd-core/workflows/progress.md +52 -15
  314. package/gsd-core/workflows/quick/steps/discussion-phase.md +1 -3
  315. package/gsd-core/workflows/quick/steps/plan-checker-loop.md +38 -5
  316. package/gsd-core/workflows/quick/steps/quick-verification.md +2 -4
  317. package/gsd-core/workflows/quick/steps/research-phase.md +5 -7
  318. package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +3 -3
  319. package/gsd-core/workflows/quick-batch/steps/batch-init.md +55 -0
  320. package/gsd-core/workflows/quick-batch/steps/completion.md +65 -0
  321. package/gsd-core/workflows/quick-batch/steps/merge-wave.md +100 -0
  322. package/gsd-core/workflows/quick-batch/steps/plan-checker-loop.md +147 -0
  323. package/gsd-core/workflows/quick-batch/steps/planner-wave.md +158 -0
  324. package/gsd-core/workflows/quick-batch/steps/research-phase.md +95 -0
  325. package/gsd-core/workflows/quick-batch/steps/resume-mode.md +49 -0
  326. package/gsd-core/workflows/quick-batch/steps/verification-wave.md +73 -0
  327. package/gsd-core/workflows/quick-batch/steps/worktree-dispatch.md +169 -0
  328. package/gsd-core/workflows/quick-batch.md +203 -0
  329. package/gsd-core/workflows/quick.md +33 -32
  330. package/gsd-core/workflows/reapply-patches.md +2 -0
  331. package/gsd-core/workflows/remove-phase.md +6 -4
  332. package/gsd-core/workflows/remove-workspace.md +3 -3
  333. package/gsd-core/workflows/resume-project.md +14 -14
  334. package/gsd-core/workflows/review.md +404 -21
  335. package/gsd-core/workflows/scan.md +3 -1
  336. package/gsd-core/workflows/section-manifest.json +12 -0
  337. package/gsd-core/workflows/secure-phase.md +3 -3
  338. package/gsd-core/workflows/session-report.md +2 -0
  339. package/gsd-core/workflows/settings-advanced.md +9 -9
  340. package/gsd-core/workflows/settings-integrations.md +66 -32
  341. package/gsd-core/workflows/settings.md +4 -6
  342. package/gsd-core/workflows/ship.md +22 -16
  343. package/gsd-core/workflows/sketch-wrap-up.md +13 -17
  344. package/gsd-core/workflows/sketch.md +13 -19
  345. package/gsd-core/workflows/smart-entry.md +4 -6
  346. package/gsd-core/workflows/spec-phase.md +31 -4
  347. package/gsd-core/workflows/spike-wrap-up.md +9 -11
  348. package/gsd-core/workflows/spike.md +21 -32
  349. package/gsd-core/workflows/stats.md +4 -2
  350. package/gsd-core/workflows/sync-skills.md +13 -5
  351. package/gsd-core/workflows/thread.md +13 -7
  352. package/gsd-core/workflows/transition.md +7 -5
  353. package/gsd-core/workflows/ui-phase.md +36 -21
  354. package/gsd-core/workflows/ui-review.md +7 -11
  355. package/gsd-core/workflows/ultraplan-phase.md +7 -13
  356. package/gsd-core/workflows/undo.md +9 -17
  357. package/gsd-core/workflows/update.md +47 -48
  358. package/gsd-core/workflows/validate-phase.md +3 -3
  359. package/gsd-core/workflows/verify-work/steps/automated-ui-verification.md +25 -1
  360. package/gsd-core/workflows/verify-work/steps/mvp-uat-framing.md +1 -1
  361. package/gsd-core/workflows/verify-work.md +106 -21
  362. package/hooks/dist/gsd-agent-isolation-guard.js +77 -38
  363. package/hooks/dist/gsd-check-update-worker.js +19 -2
  364. package/hooks/dist/gsd-config-reload.js +18 -12
  365. package/hooks/dist/gsd-context-monitor.js +302 -22
  366. package/hooks/dist/gsd-cursor-post-tool.js +3 -1
  367. package/hooks/dist/gsd-cursor-pre-tool.js +3 -1
  368. package/hooks/dist/gsd-cursor-session-start.js +2 -1
  369. package/hooks/dist/gsd-cursor-stop.js +2 -1
  370. package/hooks/dist/gsd-cursor-subagent-start.js +28 -23
  371. package/hooks/dist/gsd-cursor-subagent-stop.js +3 -1
  372. package/hooks/dist/gsd-ensure-canonical-path.js +2 -1
  373. package/hooks/dist/gsd-graphify-update.sh +22 -18
  374. package/hooks/dist/gsd-node-runner.sh +77 -0
  375. package/hooks/dist/gsd-phase-boundary.sh +1 -0
  376. package/hooks/dist/gsd-prompt-guard.js +46 -12
  377. package/hooks/dist/gsd-read-guard.js +18 -7
  378. package/hooks/dist/gsd-read-injection-scanner.js +22 -13
  379. package/hooks/dist/gsd-secret-read-guard.js +1079 -0
  380. package/hooks/dist/gsd-session-state.sh +1 -0
  381. package/hooks/dist/gsd-statusline.js +222 -29
  382. package/hooks/dist/gsd-validate-commit.sh +523 -12
  383. package/hooks/dist/gsd-windsurf-pre-command.js +16 -11
  384. package/hooks/dist/gsd-windsurf-pre-write.js +22 -13
  385. package/hooks/dist/gsd-workflow-guard.js +36 -17
  386. package/hooks/dist/gsd-worktree-path-guard.js +36 -21
  387. package/hooks/dist/gsd-write-guard.js +35 -25
  388. package/hooks/dist/lib/cli-exit.js +560 -0
  389. package/hooks/dist/lib/exit-code-registry.js +98 -0
  390. package/hooks/dist/lib/git-cmd.js +210 -1
  391. package/hooks/dist/lib/git-probe.js +84 -0
  392. package/hooks/dist/lib/hook-exit.js +81 -0
  393. package/hooks/dist/lib/injection-patterns.js +36 -6
  394. package/hooks/dist/managed-hooks-registry.cjs +4 -0
  395. package/hooks/gsd-agent-isolation-guard.js +77 -38
  396. package/hooks/gsd-check-update-worker.js +19 -2
  397. package/hooks/gsd-config-reload.js +18 -12
  398. package/hooks/gsd-context-monitor.js +302 -22
  399. package/hooks/gsd-cursor-post-tool.js +3 -1
  400. package/hooks/gsd-cursor-pre-tool.js +3 -1
  401. package/hooks/gsd-cursor-session-start.js +2 -1
  402. package/hooks/gsd-cursor-stop.js +2 -1
  403. package/hooks/gsd-cursor-subagent-start.js +28 -23
  404. package/hooks/gsd-cursor-subagent-stop.js +3 -1
  405. package/hooks/gsd-ensure-canonical-path.js +2 -1
  406. package/hooks/gsd-graphify-update.sh +22 -18
  407. package/hooks/gsd-node-runner.sh +77 -0
  408. package/hooks/gsd-phase-boundary.sh +1 -0
  409. package/hooks/gsd-prompt-guard.js +46 -12
  410. package/hooks/gsd-read-guard.js +18 -7
  411. package/hooks/gsd-read-injection-scanner.js +22 -13
  412. package/hooks/gsd-secret-read-guard.js +1079 -0
  413. package/hooks/gsd-session-state.sh +1 -0
  414. package/hooks/gsd-statusline.js +222 -29
  415. package/hooks/gsd-validate-commit.sh +523 -12
  416. package/hooks/gsd-windsurf-pre-command.js +16 -11
  417. package/hooks/gsd-windsurf-pre-write.js +22 -13
  418. package/hooks/gsd-workflow-guard.js +36 -17
  419. package/hooks/gsd-worktree-path-guard.js +36 -21
  420. package/hooks/gsd-write-guard.js +35 -25
  421. package/hooks/hooks.json +6 -0
  422. package/hooks/lib/cli-exit.js +560 -0
  423. package/hooks/lib/exit-code-registry.js +98 -0
  424. package/hooks/lib/git-cmd.js +210 -1
  425. package/hooks/lib/git-probe.js +84 -0
  426. package/hooks/lib/hook-exit.js +81 -0
  427. package/hooks/lib/injection-patterns.js +36 -6
  428. package/hooks/managed-hooks-registry.cjs +4 -0
  429. package/package.json +14 -9
  430. package/scripts/base64-scan.sh +74 -12
  431. package/scripts/build-hooks.js +12 -0
  432. package/scripts/check-glossary-refs.cjs +77 -15
  433. package/scripts/check-mutation-score-ratchet.cjs +156 -0
  434. package/scripts/ci-check-job-near-cap.cjs +49 -0
  435. package/scripts/ci-pr-mergeability.cjs +262 -0
  436. package/scripts/ci-test-scope.cjs +52 -12
  437. package/scripts/ci-timeout-report.cjs +230 -0
  438. package/scripts/docs-guard-registry.cjs +406 -0
  439. package/scripts/gen-capability-registry.cjs +8 -6
  440. package/scripts/gen-exit-code-docs.cjs +318 -0
  441. package/scripts/gen-exit-code-registry.cjs +891 -0
  442. package/scripts/gen-features.cjs +836 -0
  443. package/scripts/gen-hooks-cli-exit.cjs +239 -0
  444. package/scripts/gen-install-tree-fixtures.cjs +2 -2
  445. package/scripts/gen-loop-host-contract.cjs +189 -4
  446. package/scripts/gen-scripts-cli-exit.cjs +185 -0
  447. package/scripts/gen-state-md-docs.cjs +727 -0
  448. package/scripts/{test-failure-reasons.cjs → gsd-test-gate-reasons.cjs} +6 -0
  449. package/scripts/lib/ci-job-timing.cjs +72 -0
  450. package/scripts/lib/cli-exit.cjs +546 -44
  451. package/scripts/lib/drift-scan.cjs +32 -2
  452. package/scripts/lib/exit-code-registry.cjs +98 -0
  453. package/scripts/lib/ndjson-reporter.cjs +119 -0
  454. package/scripts/lib/shellcheck-fetch.cjs +247 -0
  455. package/scripts/lint-allow-test-rule-refs.allowlist.json +0 -6
  456. package/scripts/lint-allow-test-rule-refs.effective-ceiling.json +1 -1
  457. package/scripts/lint-allow-test-rule-refs.unverified-ceiling.json +1 -1
  458. package/scripts/lint-docs-guard-registration.cjs +495 -0
  459. package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +198 -0
  460. package/scripts/lint-eslint-glob-coverage.allowlist.json +4 -0
  461. package/scripts/{lint-fix-has-regression-test.cjs → lint-fix-has-regression-tests.cjs} +12 -6
  462. package/scripts/lint-health-diagnostic-rule-table.cjs +65 -8
  463. package/scripts/lint-mutation-test-derivation-drift.cjs +86 -0
  464. package/scripts/lint-phase-enumeration-drift.cjs +45 -14
  465. package/scripts/lint-phase-id-drift.cjs +133 -8
  466. package/scripts/lint-planning-prompt-drift.cjs +38 -1
  467. package/scripts/lint-portable-grep.cjs +176 -0
  468. package/scripts/lint-removed-but-needed.cjs +184 -16
  469. package/scripts/lint-response-language-coverage.cjs +524 -0
  470. package/scripts/lint-seam-enforcement.cjs +182 -0
  471. package/scripts/lint-slug-derivation-drift.cjs +921 -0
  472. package/scripts/lint-source-test-name-collision.cjs +241 -0
  473. package/scripts/lint-state-write-path-drift.cjs +337 -432
  474. package/scripts/lint-test-file-count.allowlist.json +124 -4
  475. package/scripts/lint-test-file-count.cjs +25 -3
  476. package/scripts/lint-unreachable-guard-drift.cjs +51 -64
  477. package/scripts/lint-vendored-deps.cjs +208 -35
  478. package/scripts/lint-workflow-shellcheck-baseline.json +1027 -0
  479. package/scripts/lint-workflow-shellcheck.cjs +614 -0
  480. package/scripts/mutation-matrix.cjs +599 -50
  481. package/scripts/npm-audit-baseline.cjs +376 -0
  482. package/scripts/prompt-injection-scan.sh +83 -14
  483. package/scripts/require-issue-link-policy.cjs +16 -1
  484. package/scripts/secret-scan.sh +75 -13
  485. package/scripts/select-docs-guards.cjs +56 -0
  486. package/scripts/sync-runtime-launcher.cjs +22 -3
  487. package/skills/gsd-discuss-phase/SKILL.md +1 -1
  488. package/skills/gsd-execute-phase/SKILL.md +1 -1
  489. package/skills/gsd-import/SKILL.md +1 -1
  490. package/skills/gsd-ns-workflow/SKILL.md +1 -0
  491. package/skills/gsd-phase/SKILL.md +1 -1
  492. package/skills/gsd-quick/SKILL.md +8 -4
  493. package/skills/gsd-quick-batch/SKILL.md +105 -0
  494. package/skills/gsd-surface/SKILL.md +18 -8
  495. package/vscode/package.json +1 -1
  496. package/bin/lib/ui-safety-gate.cjs +0 -109
  497. package/scripts/lint-emitted-drift-ack.cjs +0 -344
  498. package/scripts/state-write-path-drift-baseline.json +0 -19
@@ -15,6 +15,9 @@ const node_fs_1 = __importDefault(require("node:fs"));
15
15
  const node_os_1 = __importDefault(require("node:os"));
16
16
  const node_path_1 = __importDefault(require("node:path"));
17
17
  const shell_command_projection_cjs_1 = require("./shell-command-projection.cjs");
18
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
19
+ const cliExitModule = require("./cli-exit.cjs");
20
+ const { setJsonErrorMode, getJsonErrorMode, EXIT_ENVELOPE_REASON, ExitError, setPendingOutcome, projectOutcome, getContractVersion, } = cliExitModule;
18
21
  // ─── Temp-file helpers (needed by output()) ──────────────────────────────────
19
22
  /**
20
23
  * Dedicated GSD temp directory: path.join(os.tmpdir(), 'gsd').
@@ -134,7 +137,48 @@ function writeAllSync(fd, data) {
134
137
  function serializeForOutput(result) {
135
138
  return JSON.stringify(result, null, 2);
136
139
  }
140
+ /**
141
+ * A payload-carried error, per ADR-2980's own definition (#3912, ADR-3889
142
+ * §4): `result` is an object carrying a SERIALIZABLE `error` property, in
143
+ * ANY key order — `{ found: false, error }` counts exactly the same as
144
+ * `{ error, found: false }`. The discriminator is a serializable error
145
+ * value, NOT mere key presence: `result.error`'s own truthiness is
146
+ * irrelevant (falsy `0`/`null`/`''` all count), and neither is `result`'s
147
+ * prototype (a plain object literal is all any call site here ever
148
+ * passes) — but `error: undefined` does NOT count, because
149
+ * `JSON.stringify` (the exact serializer `serializeForOutput` uses to
150
+ * build the payload the caller actually receives) drops an object
151
+ * property whose value is `undefined` entirely. A payload built as
152
+ * `{ found: false, error: undefined }` therefore reaches the wire as
153
+ * `{"found":false}` — no error at all — and recording DEGRADED for it
154
+ * would be a false verdict: exit 80 under v2 for output the user sees as
155
+ * clean. `hasOwnProperty` alone is not enough to answer "does this payload
156
+ * declare an error"; it must also survive `JSON.stringify`.
157
+ */
158
+ function isPayloadCarriedError(result) {
159
+ return typeof result === 'object' && result !== null
160
+ && Object.prototype.hasOwnProperty.call(result, 'error')
161
+ && result.error !== undefined;
162
+ }
137
163
  function output(result, raw, rawValue) {
164
+ // #3912 (ADR-3889 §4): a payload-carried error declares DEGRADED into the
165
+ // pending-outcome cell runMain reads. This is the ONLY new thing output()
166
+ // does — it still just writes fd 1 and returns; the exit code stays
167
+ // whatever it already was under v1 (DEGRADED projects to 0), and nothing
168
+ // here touches process.exitCode directly.
169
+ //
170
+ // LAST-WRITE-WINS (review fix): a clean (non-error-shaped) payload CLEARS
171
+ // the cell rather than leaving a prior degraded declaration in place. A
172
+ // handler that calls output() more than once per invocation — a
173
+ // diagnostic error payload followed by a clean final payload — must have
174
+ // its LATEST declaration win, not its first: the cell reflects "is a
175
+ // degraded outcome pending right now", not "was one ever declared".
176
+ if (isPayloadCarriedError(result)) {
177
+ setPendingOutcome('DEGRADED');
178
+ }
179
+ else {
180
+ setPendingOutcome(undefined);
181
+ }
138
182
  let data;
139
183
  if (raw && rawValue !== undefined) {
140
184
  // eslint-disable-next-line @typescript-eslint/no-base-to-string
@@ -161,6 +205,40 @@ function output(result, raw, rawValue) {
161
205
  // and skipping process.exit() lets the event loop drain naturally.
162
206
  writeAllSync(1, data);
163
207
  }
208
+ /**
209
+ * Single owner of the "a no-op decline reports the real condition" pairing:
210
+ * a `[gsd-tools] WARNING:` stderr disclosure plus the matching
211
+ * `{ [flagKey]: false, ...computed, reason }` JSON payload (#3957, epic
212
+ * #3473 B9). Before this helper, each CLI command's no-op arm hand-wrote
213
+ * both halves independently, and #3957's own sweep found sites where one
214
+ * half drifted: a decline that discarded values it had already computed, a
215
+ * `reason` string naming a condition that hadn't actually fired, or no
216
+ * stderr disclosure at all (missing the `[gsd-tools] WARNING:` convention
217
+ * #3217, ADR-3180 §7.6 rule 4, established for exactly this situation —
218
+ * a JSON `reason` field alone is easy for a caller piping stdout through
219
+ * `--json` to never read). Routing every no-op decline through one call
220
+ * site makes the convention structural — a call site, not a habit a fifth
221
+ * arm can independently forget — rather than leaving it to per-site
222
+ * discipline.
223
+ *
224
+ * `disclosure` is written to stderr VERBATIM. Like `error()`'s `message`
225
+ * argument (see that function's own doc comment above `formatDiagnosticToken`),
226
+ * this function stays a dumb, faithful writer and does not sanitize it — a
227
+ * caller that interpolates an UNTRUSTED substring (a caller-supplied
228
+ * blocker/session-field string, an argv token) into `disclosure` MUST pass
229
+ * that substring through `formatDiagnosticToken` first. Skipping that step
230
+ * lets an embedded `\n` forge a second, attacker-authored
231
+ * `[gsd-tools] WARNING:` line — the same risk `error()`'s doc comment
232
+ * documents for its own stderr write.
233
+ */
234
+ function declineNoOp(raw, flagKey, reason, disclosure, computed = {}) {
235
+ // `process.stderr.write`, matching the `[gsd-tools] WARNING:` call sites
236
+ // this helper replaces (state.cts's stateReplaceFieldWithFallback and the
237
+ // cmdStateUpdateProgress decline arms) — not the `writeAllSync(2, …)`
238
+ // primitive `error()` uses, which is reserved for the fatal-exit path.
239
+ process.stderr.write(`[gsd-tools] WARNING: ${disclosure}\n`);
240
+ output({ [flagKey]: false, ...computed, reason }, raw, 'false');
241
+ }
164
242
  /**
165
243
  * Frozen enum of typed reason codes used by error() for structured errors.
166
244
  * Each subcommand contributes its own codes; the enum exists so tests can
@@ -178,7 +256,7 @@ const ERROR_REASON = Object.freeze({
178
256
  CONFIG_PARSE_FAILED: 'config_parse_failed',
179
257
  CONFIG_INVALID_KEY: 'config_invalid_key',
180
258
  // SDK / gsd-tools dispatch
181
- SDK_FAIL_FAST: 'sdk_fail_fast',
259
+ SDK_FAIL_FAST: EXIT_ENVELOPE_REASON,
182
260
  SDK_UNKNOWN_COMMAND: 'sdk_unknown_command',
183
261
  SDK_MISSING_ARG: 'sdk_missing_arg',
184
262
  // workflow / phase
@@ -195,6 +273,10 @@ const ERROR_REASON = Object.freeze({
195
273
  // graphify
196
274
  GRAPHIFY_NO_GRAPH: 'graphify_no_graph',
197
275
  GRAPHIFY_INVALID_QUERY: 'graphify_invalid_query',
276
+ // estimate-calibrate (#3882, ADR-3473 §8.2): the phases directory exists
277
+ // but could not be read — a NON-answer, distinct from a project that
278
+ // genuinely has zero completed phases yet.
279
+ ESTIMATE_PHASES_UNREADABLE: 'estimate_phases_unreadable',
198
280
  // hooks
199
281
  HOOKS_OPT_OUT: 'hooks_opt_out',
200
282
  // commit-docs-guard (#3588)
@@ -203,22 +285,17 @@ const ERROR_REASON = Object.freeze({
203
285
  COMMIT_DOCS_GUARD_HOOKS_PATH_SET: 'commit_docs_guard_hooks_path_set',
204
286
  // security-scan
205
287
  SECURITY_SCAN_FAILED: 'security_scan_failed',
288
+ // --pick (#3365 / #3358, ADR-3473 §8.4): an absent field or non-JSON
289
+ // command output is a failure, never a demotion to an empty answer at
290
+ // exit 0. See .gsd/phase/feat-3884-failure-is-a-value/40-design.md.
291
+ PICK_FIELD_ABSENT: 'pick_field_absent',
292
+ PICK_OUTPUT_NOT_JSON: 'pick_output_not_json',
206
293
  // generic
207
294
  USAGE: 'usage',
208
295
  UNKNOWN: 'unknown',
209
296
  });
210
- /**
211
- * Process-level flag: when true, error() emits structured JSON to stderr
212
- * instead of plain "Error: <message>" text. Set by gsd-tools.cjs when the
213
- * CLI is invoked with `--json-errors`. Tests opt in to typed-IR error
214
- * assertions by passing that flag and parsing the JSON.
215
- *
216
- * Default off so existing callers and human operators keep their plain-text
217
- * diagnostics. The structured form is opt-in for tooling and tests (#2974).
218
- */
219
- let _jsonErrorMode = false;
220
- function setJsonErrorMode(v) { _jsonErrorMode = !!v; }
221
- function getJsonErrorMode() { return _jsonErrorMode; }
297
+ // setJsonErrorMode / getJsonErrorMode now live in cli-exit.cts (imported above)
298
+ // and are re-exported here for the callers that already import them from io.
222
299
  /**
223
300
  * Emit an error and exit. When the second argument is provided it must be
224
301
  * a value from ERROR_REASON; tests can assert on `result.reason`. When the
@@ -233,24 +310,127 @@ function getJsonErrorMode() { return _jsonErrorMode; }
233
310
  * human-readable text. Ignored entirely in plain-text mode — the human
234
311
  * message is the only thing an operator sees there.
235
312
  */
313
+ /**
314
+ * Render an UNTRUSTED string for embedding inside a human-readable,
315
+ * plain-text diagnostic (the `'Error: ' + message` line `error()` writes in
316
+ * non-JSON mode).
317
+ *
318
+ * WHY THIS EXISTS AND WHY `error()` DOES NOT DO IT ITSELF: `error()`
319
+ * deliberately writes its `message` argument verbatim — several callers in
320
+ * this repo intentionally emit multi-line diagnostics (e.g. the phase-gate
321
+ * messages), and `error()` has no way to distinguish a legitimate multi-line
322
+ * message from a hostile one, so it must not mangle newlines generically.
323
+ * That means any UNTRUSTED substring a caller interpolates into `message`
324
+ * (an argv token, a JSON key/value read back from a command's own output,
325
+ * etc.) can smuggle its own `\n` and forge a second `Error: ` line on
326
+ * stderr — a caller that parses stderr line-by-line would then see a second,
327
+ * attacker-authored error. Every call site that interpolates untrusted data
328
+ * into a diagnostic MUST pass that substring through this function first;
329
+ * `error()` itself stays a dumb, faithful writer.
330
+ *
331
+ * `JSON.stringify` is the primitive: it wraps the value in quotes and
332
+ * escapes control characters (`\n`, `\r`, `\t`, and the rest of the C0
333
+ * range, plus the quote character itself), so the result can never span
334
+ * more than one line or introduce an unescaped `"`. Callers embedding the
335
+ * result MUST NOT add their own surrounding quotes — that would
336
+ * double-quote it.
337
+ */
338
+ function formatDiagnosticToken(value) {
339
+ return JSON.stringify(value);
340
+ }
341
+ /**
342
+ * Map an ERROR_REASON wire value onto a declared outcome name (#3912,
343
+ * ADR-3889 §4). Closed over the 25-member enum: every reason gets an
344
+ * explicit entry below, so a 26th member added without a mapping falls
345
+ * through to the `?? 'FAIL'` default rather than silently mis-projecting —
346
+ * and tests/A1 iterates `Object.values(ERROR_REASON)`, so that default is
347
+ * exactly what makes an unmapped addition visible instead of invisible.
348
+ *
349
+ * This function's result is ONLY consulted under v2 (see `error()` below) —
350
+ * it is deliberately never routed through `projectOutcome` under v1, which
351
+ * is what keeps the v1 pin intact (`projectOutcome` treats registered names
352
+ * as version-invariant, so e.g. USAGE would otherwise become 64 today).
353
+ *
354
+ * Each non-FAIL choice below is justified inline; `UNKNOWN` and anything
355
+ * with no clearly better fit stays `FAIL` — the honest default the design
356
+ * calls for, not a guess dressed up as a specific outcome.
357
+ */
358
+ const REASON_TO_OUTCOME = Object.freeze({
359
+ // Bad argv/subcommand/argument — the caller, not the run, is at fault.
360
+ [ERROR_REASON.CONFIG_INVALID_KEY]: 'USAGE',
361
+ [ERROR_REASON.SDK_UNKNOWN_COMMAND]: 'USAGE',
362
+ [ERROR_REASON.SDK_MISSING_ARG]: 'USAGE',
363
+ [ERROR_REASON.GRAPHIFY_INVALID_QUERY]: 'USAGE',
364
+ [ERROR_REASON.USAGE]: 'USAGE',
365
+ // A specific, named thing does not exist / nothing was there to find —
366
+ // genuine, known emptiness rather than a broken prerequisite.
367
+ [ERROR_REASON.CONFIG_KEY_NOT_FOUND]: 'NO_INPUT',
368
+ [ERROR_REASON.SUMMARY_NO_PLANNING]: 'NO_INPUT',
369
+ [ERROR_REASON.WORKSTREAM_MODE_NONE_ACTIVE]: 'NO_INPUT',
370
+ // A prerequisite is absent, unreadable, or otherwise not in a state the
371
+ // run could proceed from — distinct from NO_INPUT's genuine emptiness.
372
+ [ERROR_REASON.CONFIG_NO_FILE]: 'UNAVAILABLE',
373
+ [ERROR_REASON.CONFIG_PARSE_FAILED]: 'UNAVAILABLE',
374
+ [ERROR_REASON.PHASE_NOT_FOUND]: 'UNAVAILABLE',
375
+ [ERROR_REASON.PHASE_VERIFICATION_INCOMPLETE]: 'UNAVAILABLE',
376
+ [ERROR_REASON.PHASE_PLAN_COVERAGE_INCOMPLETE]: 'UNAVAILABLE',
377
+ // Its own docstring: "a marker exists but didn't resolve" — a broken
378
+ // prerequisite, not the "no marker anywhere" emptiness NONE_ACTIVE covers.
379
+ [ERROR_REASON.WORKSTREAM_MODE_MARKER_UNRESOLVED]: 'UNAVAILABLE',
380
+ [ERROR_REASON.GRAPHIFY_NO_GRAPH]: 'UNAVAILABLE',
381
+ // Its own docstring: "a NON-answer, distinct from a project that
382
+ // genuinely has zero completed phases yet" — UNAVAILABLE, not NO_INPUT.
383
+ [ERROR_REASON.ESTIMATE_PHASES_UNREADABLE]: 'UNAVAILABLE',
384
+ [ERROR_REASON.COMMIT_DOCS_GUARD_NOT_A_REPO]: 'UNAVAILABLE',
385
+ [ERROR_REASON.COMMIT_DOCS_GUARD_FOREIGN_HOOK]: 'UNAVAILABLE',
386
+ [ERROR_REASON.COMMIT_DOCS_GUARD_HOOKS_PATH_SET]: 'UNAVAILABLE',
387
+ // Its own docstring: "an absent field or non-JSON command output is a
388
+ // failure, never a demotion to an empty answer" — the field/output was
389
+ // supposed to be there and was not; a prerequisite of the query failed.
390
+ [ERROR_REASON.PICK_FIELD_ABSENT]: 'UNAVAILABLE',
391
+ [ERROR_REASON.PICK_OUTPUT_NOT_JSON]: 'UNAVAILABLE',
392
+ // Self-failure: the run itself broke, not its inputs.
393
+ [ERROR_REASON.SDK_FAIL_FAST]: 'INTERNAL',
394
+ [ERROR_REASON.SECURITY_SCAN_FAILED]: 'INTERNAL',
395
+ // No clearly better fit — the honest default, per design.
396
+ [ERROR_REASON.HOOKS_OPT_OUT]: 'FAIL',
397
+ [ERROR_REASON.UNKNOWN]: 'FAIL',
398
+ });
399
+ function outcomeForReason(reason) {
400
+ return REASON_TO_OUTCOME[reason] ?? 'FAIL';
401
+ }
236
402
  function error(message, reason = ERROR_REASON.UNKNOWN, extra) {
237
- if (_jsonErrorMode) {
403
+ if (getJsonErrorMode()) {
238
404
  const payload = JSON.stringify({ ok: false, reason, message, ...(extra || {}) }) + '\n';
239
405
  writeAllSync(2, payload);
240
406
  }
241
407
  else {
242
408
  writeAllSync(2, 'Error: ' + message + '\n');
243
409
  }
244
- process.exit(1);
410
+ // #3912 (ADR-3889 §4): the declaration is version-gated HERE, not inside
411
+ // projectOutcome — registered names are version-invariant there, so
412
+ // routing every reason through it unconditionally would change v1 exit
413
+ // codes today (e.g. USAGE -> 64) and break the pin. Under v1 the exit
414
+ // stays ExitError(1) unconditionally, byte-identical to every prior
415
+ // release; only v2 projects the declared outcome through the registry.
416
+ if (getContractVersion() === 'v2') {
417
+ throw new ExitError(projectOutcome(outcomeForReason(reason), 'v2'));
418
+ }
419
+ // No message passed to ExitError: the stderr write above is already done,
420
+ // byte-identical to the prior process.exit(1) behavior, and ExitError with
421
+ // no message means runMain's catch adds nothing further to stderr.
422
+ throw new ExitError(1);
245
423
  }
246
424
  module.exports = {
247
425
  GSD_TEMP_DIR,
248
426
  ensureGsdTempDir,
249
427
  reapStaleTempFiles,
250
428
  output,
429
+ declineNoOp,
251
430
  serializeForOutput,
252
431
  ERROR_REASON,
253
432
  setJsonErrorMode,
254
433
  getJsonErrorMode,
255
434
  error,
435
+ formatDiagnosticToken,
256
436
  };
@@ -21,6 +21,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
21
21
  const node_fs_1 = __importDefault(require("node:fs"));
22
22
  const node_path_1 = __importDefault(require("node:path"));
23
23
  const node_crypto_1 = __importDefault(require("node:crypto"));
24
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
25
+ const phaseLocator = require("./phase-locator.cjs");
24
26
  const node_os_1 = __importDefault(require("node:os"));
25
27
  // eslint-disable-next-line @typescript-eslint/no-require-imports
26
28
  const ioMod = require("./io.cjs");
@@ -145,9 +147,55 @@ function learningsDelete(id, opts) {
145
147
  node_fs_1.default.unlinkSync(filePath);
146
148
  return true;
147
149
  }
150
+ /**
151
+ * #3683 — resolve which learnings artifact a copy reads. The extractor writes
152
+ * phase-scoped `{PHASE_DIR}/{PADDED}-LEARNINGS.md`; the legacy shape is a
153
+ * project-root `LEARNINGS.md`. The MOST RECENT phase-scoped artifact wins (a
154
+ * gated completion copies the phase it just wrote); the project-root file is
155
+ * the fallback when no phase artifact exists. Returns null when neither shape
156
+ * is present.
157
+ */
158
+ function resolveLearningsSource(planningDir) {
159
+ let best = null;
160
+ const phasesDir = node_path_1.default.join(planningDir, 'phases');
161
+ // Phase enumeration routes through the sanctioned seam (the #3185 drift
162
+ // guard rejects ad-hoc re-derivations): no cwd → every phase dir in the
163
+ // tree, sentinel dirs excluded, unreadable phases dir already degraded to
164
+ // an empty list by the locator itself.
165
+ const { value: phaseDirNames } = phaseLocator.listMilestonePhaseDirs(phasesDir);
166
+ for (const entry of phaseDirNames) {
167
+ const phaseDir = node_path_1.default.join(phasesDir, entry);
168
+ let files;
169
+ try {
170
+ files = node_fs_1.default.readdirSync(phaseDir);
171
+ }
172
+ catch {
173
+ // An unreadable phase dir (ACL, removal race) must not crash the copy —
174
+ // skip it and keep scanning.
175
+ continue;
176
+ }
177
+ for (const f of files) {
178
+ if (!/-LEARNINGS\.md$/i.test(f))
179
+ continue;
180
+ const p = node_path_1.default.join(phaseDir, f);
181
+ try {
182
+ const m = node_fs_1.default.statSync(p).mtimeMs;
183
+ if (best === null || m > best.m)
184
+ best = { p, m };
185
+ }
186
+ catch {
187
+ continue;
188
+ }
189
+ }
190
+ }
191
+ if (best !== null)
192
+ return best.p;
193
+ const rootPath = node_path_1.default.join(planningDir, 'LEARNINGS.md');
194
+ return node_fs_1.default.existsSync(rootPath) ? rootPath : null;
195
+ }
148
196
  function learningsCopyFromProject(planningDir, opts) {
149
- const learningsPath = node_path_1.default.join(planningDir, 'LEARNINGS.md');
150
- if (!node_fs_1.default.existsSync(learningsPath)) {
197
+ const learningsPath = resolveLearningsSource(planningDir);
198
+ if (learningsPath === null) {
151
199
  return { total: 0, created: 0, skipped: 0 };
152
200
  }
153
201
  const content = node_fs_1.default.readFileSync(learningsPath, 'utf-8');
@@ -167,29 +215,52 @@ function learningsCopyFromProject(planningDir, opts) {
167
215
  dedupeIndex.set(existing.content_hash, existing.id);
168
216
  }
169
217
  }
170
- // Parse markdown: split on ## headings
218
+ // Parse markdown: split on ## category headings.
219
+ // #3683: the real producer (extract-learnings.md write_learnings) writes ##
220
+ // categories containing ### item headings — each item is ONE learning (the
221
+ // store's relevance contract caps injection by count, so category-sized
222
+ // blobs defeat it). A bare ## section with no ### items keeps the legacy
223
+ // single-learning shape.
171
224
  const sections = content.split(/^## /m).slice(1); // skip preamble before first ##
172
225
  let created = 0;
173
226
  let skipped = 0;
174
- for (const section of sections) {
175
- const lines = section.trim().split('\n');
176
- const title = lines[0].trim();
177
- const body = lines.slice(1).join('\n').trim();
178
- if (!body)
179
- continue;
180
- // Extract tags from title (simple: use words as tags)
181
- const tags = title.toLowerCase().split(/\s+/).filter(w => w.length > 2);
227
+ const writeOne = (title, body, extraTags) => {
228
+ const tags = Array.from(new Set([
229
+ ...extraTags,
230
+ ...title.toLowerCase().split(/\s+/).filter(w => w.length > 2),
231
+ ]));
182
232
  const result = learningsWrite({
183
233
  source_project: sourceProject,
184
234
  learning: body,
185
235
  context: title,
186
236
  tags,
187
237
  }, { ...opts, dedupeIndex });
188
- if (result.created) {
238
+ if (result.created)
189
239
  created++;
190
- }
191
- else {
240
+ else
192
241
  skipped++;
242
+ };
243
+ for (const section of sections) {
244
+ const lines = section.trim().split('\n');
245
+ const category = lines[0].trim();
246
+ const body = lines.slice(1).join('\n').trim();
247
+ if (!body)
248
+ continue;
249
+ const categoryTag = category.toLowerCase().split(/\s+/)[0] || '';
250
+ // Split into ### items when present; otherwise one learning per section.
251
+ const items = body.split(/^### /m).map(s => s.trim()).filter(s => s.length > 0);
252
+ const hasItemHeadings = /^### /m.test(body);
253
+ if (!hasItemHeadings) {
254
+ writeOne(category, body, categoryTag ? [categoryTag] : []);
255
+ continue;
256
+ }
257
+ for (const item of items) {
258
+ const itemLines = item.split('\n');
259
+ const title = itemLines[0].trim();
260
+ const itemBody = itemLines.slice(1).join('\n').trim();
261
+ if (!itemBody && !title)
262
+ continue;
263
+ writeOne(title, itemBody || title, categoryTag ? [categoryTag] : []);
193
264
  }
194
265
  }
195
266
  return { total: created + skipped, created, skipped };
@@ -262,8 +262,14 @@ function planLegacyCleanup(configDirs, opts = {}) {
262
262
  }
263
263
  }
264
264
 
265
- // Legacy shared cache (fixed name from the old package)
266
- const legacyCachePath = path.join(homeDir, '.cache', 'gsd', 'gsd-update-check.json');
265
+ // Legacy shared cache (fixed name from the old package). #3799: under an
266
+ // explicit configDirs override the cache lives under the SCOPE root(s), not
267
+ // the default home — the override means "clean only what this redirected
268
+ // install owns", and the default home's cache belongs to the live install.
269
+ const cacheRoot = (Array.isArray(opts.configDirs) && opts.configDirs.length > 0)
270
+ ? opts.configDirs[0]
271
+ : homeDir;
272
+ const legacyCachePath = path.join(cacheRoot, '.cache', 'gsd', 'gsd-update-check.json');
267
273
  try {
268
274
  const stat = fsMod.statSync(legacyCachePath);
269
275
  if (stat.isFile()) {
@@ -40,7 +40,7 @@ const { resolveCapabilityRuntimeState } = capabilityStateModule;
40
40
  // ─── Capability-activation engine (single owner for config-key precedence) ────
41
41
  // eslint-disable-next-line @typescript-eslint/no-require-imports
42
42
  const capabilityActivationModule = require("./capability-activation.cjs");
43
- const { _getNestedConfigValue, _readRawConfigKey, _resolveActivationValue, resolveConfigKey } = capabilityActivationModule;
43
+ const { _getNestedConfigValue, _readRawConfigKey, _resolveActivationValue, _resolvePointGate, resolveConfigKey } = capabilityActivationModule;
44
44
  // ─── Canonical points (derived from LOOP_HOST_CONTRACT — authoritative 12) ───
45
45
  // FIX 2: Derive the authoritative canonical set from LOOP_HOST_CONTRACT so it
46
46
  // cannot drift from the host contract. CANONICAL_POINTS_FALLBACK is kept as an
@@ -125,13 +125,15 @@ function resolveLoopHooks(input) {
125
125
  // Helper: check activation using single-key precedence resolver (FIX 1 + FIX 3)
126
126
  function isActive(hook) {
127
127
  const when = hook['when'];
128
- // No `when` → unconditional hook, always active
129
- if (when === undefined || when === null)
130
- return true;
131
- // FIX 3: `when` present but not a non-empty string → malformed registry data → INACTIVE
132
- if (typeof when !== 'string' || when.length === 0)
133
- return false;
134
- return _resolveActivationValue(when, config, cwd, registry);
128
+ if (when !== undefined && when !== null) {
129
+ // FIX 3: `when` present but not a non-empty string → malformed registry data → INACTIVE
130
+ if (typeof when !== 'string' || when.length === 0)
131
+ return false;
132
+ if (!_resolveActivationValue(when, config, cwd, registry))
133
+ return false;
134
+ }
135
+ // #3661: optional point-selection gate — see capability-activation.cts.
136
+ return _resolvePointGate(hook['pointFrom'], point, config, cwd, registry);
135
137
  }
136
138
  function isCapabilityActive(capId) {
137
139
  if (!capabilityStatesById)
@@ -555,6 +557,10 @@ module.exports = {
555
557
  // Re-exported for identity parity guard (FIX 2: resolveConfigValues in this module
556
558
  // calls resolveConfigKey; exporting it here makes the single-owner contract testable).
557
559
  resolveConfigKey,
560
+ // #3661: re-exported for the same identity parity guard — isActive calls
561
+ // _resolvePointGate; exporting it here makes the single-owner contract testable
562
+ // (see tests/capability-precedence-parity.test.cjs's identity guard describe block).
563
+ _resolvePointGate,
558
564
  CANONICAL_POINTS_FALLBACK,
559
565
  CANONICAL_POINTS,
560
566
  };