@opengsd/gsd-core 1.14.0 → 1.15.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 (283) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/README.ja-JP.md +3 -3
  4. package/README.ko-KR.md +3 -3
  5. package/README.pt-BR.md +3 -3
  6. package/README.zh-CN.md +3 -3
  7. package/agents/gsd-code-fixer.compact.md +7 -6
  8. package/agents/gsd-code-fixer.md +9 -8
  9. package/agents/gsd-debug-session-manager.compact.md +17 -2
  10. package/agents/gsd-debug-session-manager.md +17 -2
  11. package/agents/gsd-debugger.md +2 -2
  12. package/agents/gsd-eval-auditor.compact.md +1 -1
  13. package/agents/gsd-eval-auditor.md +1 -1
  14. package/agents/gsd-executor.md +13 -8
  15. package/agents/gsd-intel-updater.compact.md +1 -1
  16. package/agents/gsd-intel-updater.md +1 -1
  17. package/agents/gsd-phase-researcher.md +19 -11
  18. package/agents/gsd-plan-checker.md +8 -7
  19. package/agents/gsd-planner.md +12 -8
  20. package/agents/gsd-project-researcher.compact.md +1 -1
  21. package/agents/gsd-project-researcher.md +1 -1
  22. package/agents/gsd-research-synthesizer.compact.md +1 -1
  23. package/agents/gsd-research-synthesizer.md +1 -1
  24. package/agents/gsd-ui-auditor.md +155 -17
  25. package/agents/gsd-ui-researcher.compact.md +1 -1
  26. package/agents/gsd-ui-researcher.md +1 -1
  27. package/agents/gsd-verifier.md +10 -9
  28. package/bin/install.js +642 -95
  29. package/commands/gsd/autonomous.md +2 -2
  30. package/commands/gsd/capture.md +1 -1
  31. package/commands/gsd/mempalace-capture.md +7 -3
  32. package/commands/gsd/plan-review-convergence.md +6 -6
  33. package/commands/gsd/progress.md +1 -1
  34. package/commands/gsd/quick-batch.md +1 -1
  35. package/commands/gsd/review.md +2 -3
  36. package/gsd-core/bin/gsd-tools.cjs +335 -22
  37. package/gsd-core/bin/lib/adr-parser.cjs +3 -1
  38. package/gsd-core/bin/lib/audit.cjs +81 -13
  39. package/gsd-core/bin/lib/capability-registry.cjs +82 -187
  40. package/gsd-core/bin/lib/capability-validator.cjs +0 -1
  41. package/gsd-core/bin/lib/check-command-router.cjs +101 -14
  42. package/gsd-core/bin/lib/codex-agent-toml.cjs +21 -25
  43. package/gsd-core/bin/lib/commands.cjs +175 -42
  44. package/gsd-core/bin/lib/config-loader.cjs +65 -4
  45. package/gsd-core/bin/lib/config.cjs +33 -7
  46. package/gsd-core/bin/lib/decisions.cjs +30 -14
  47. package/gsd-core/bin/lib/frontmatter.cjs +13 -0
  48. package/gsd-core/bin/lib/graphify.cjs +10 -2
  49. package/gsd-core/bin/lib/host-runtime-detection.cjs +9 -0
  50. package/gsd-core/bin/lib/init.cjs +207 -41
  51. package/gsd-core/bin/lib/install-engine.cjs +13 -0
  52. package/gsd-core/bin/lib/installer-migrations.cjs +8 -1
  53. package/gsd-core/bin/lib/milestone.cjs +18 -5
  54. package/gsd-core/bin/lib/model-resolver.cjs +159 -50
  55. package/gsd-core/bin/lib/phase-command-router.cjs +9 -1
  56. package/gsd-core/bin/lib/phase-id-card.cjs +32 -0
  57. package/gsd-core/bin/lib/phase-id-display.cjs +78 -0
  58. package/gsd-core/bin/lib/phase-id.cjs +109 -7
  59. package/gsd-core/bin/lib/phase-locator.cjs +29 -10
  60. package/gsd-core/bin/lib/phase.cjs +227 -26
  61. package/gsd-core/bin/lib/plan-document.cjs +49 -1
  62. package/gsd-core/bin/lib/planning-document.cjs +459 -0
  63. package/gsd-core/bin/lib/planning-inspect.cjs +18 -1
  64. package/gsd-core/bin/lib/planning-workspace.cjs +8 -3
  65. package/gsd-core/bin/lib/pr-branch-patterns.cjs +57 -0
  66. package/gsd-core/bin/lib/probe-core.cjs +7 -1
  67. package/gsd-core/bin/lib/project-root.cjs +41 -2
  68. package/gsd-core/bin/lib/review-lane-descriptor.cjs +10 -30
  69. package/gsd-core/bin/lib/review-reviewer-selection.cjs +2 -2
  70. package/gsd-core/bin/lib/roadmap-command-router.cjs +12 -4
  71. package/gsd-core/bin/lib/roadmap-parser.cjs +163 -3
  72. package/gsd-core/bin/lib/roadmap-upgrade.cjs +1539 -13
  73. package/gsd-core/bin/lib/roadmap.cjs +251 -31
  74. package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +283 -31
  75. package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +3 -1
  76. package/gsd-core/bin/lib/runtime-homes.cjs +4 -0
  77. package/gsd-core/bin/lib/runtime-hooks-surface.cjs +215 -33
  78. package/gsd-core/bin/lib/runtime-name-policy.cjs +111 -1
  79. package/gsd-core/bin/lib/shell-command-projection.cjs +10 -6
  80. package/gsd-core/bin/lib/state-transition.cjs +39 -2
  81. package/gsd-core/bin/lib/state.cjs +42 -0
  82. package/gsd-core/bin/lib/surface.cjs +17 -1
  83. package/gsd-core/bin/lib/tdd-red-evidence.cjs +78 -5
  84. package/gsd-core/bin/lib/uat-predicate.cjs +47 -4
  85. package/gsd-core/bin/lib/uat.cjs +8 -0
  86. package/gsd-core/bin/lib/ui-consideration-probe.cjs +15 -2
  87. package/gsd-core/bin/lib/ui-frontend-evidence.cjs +100 -9
  88. package/gsd-core/bin/lib/undo-commit-selection.cjs +131 -0
  89. package/gsd-core/bin/lib/verification.cjs +268 -15
  90. package/gsd-core/bin/lib/verify-command-grounding.cjs +46 -2
  91. package/gsd-core/bin/lib/verify.cjs +132 -25
  92. package/gsd-core/bin/lib/worktree-base-ref.cjs +482 -73
  93. package/gsd-core/bin/lib/worktree-safety.cjs +784 -51
  94. package/gsd-core/bin/shared/config-defaults.manifest.json +3 -0
  95. package/gsd-core/bin/shared/config-schema.manifest.json +1 -0
  96. package/gsd-core/references/checkpoints.md +5 -3
  97. package/gsd-core/references/edge-probe-fixtures/01-round-half-even/expected-coverage.json +28 -3
  98. package/gsd-core/references/edge-probe-fixtures/02-merge-intervals/expected-coverage.json +37 -4
  99. package/gsd-core/references/edge-probe-fixtures/03-truncate-graphemes/expected-coverage.json +28 -3
  100. package/gsd-core/references/edge-probe-fixtures/04-money-rounding/expected-coverage.json +28 -3
  101. package/gsd-core/references/edge-probe-fixtures/05-list-dedupe/expected-coverage.json +37 -4
  102. package/gsd-core/references/edge-probe-fixtures/06-resolved-mixed/expected-coverage.json +37 -4
  103. package/gsd-core/references/edge-probe.md +195 -21
  104. package/gsd-core/references/execute-phase-between-wave-reset.md +7 -6
  105. package/gsd-core/references/execute-phase-wave-guard.md +22 -11
  106. package/gsd-core/references/gsd-run-resolver.md +1 -1
  107. package/gsd-core/references/model-profiles.md +1 -1
  108. package/gsd-core/references/phase-argument-parsing.md +9 -7
  109. package/gsd-core/references/phase-id-convention.md +28 -0
  110. package/gsd-core/references/planner-gap-closure.md +2 -0
  111. package/gsd-core/references/planner-load-graph-context.md +24 -13
  112. package/gsd-core/references/planner-verify-command-grounding.md +14 -0
  113. package/gsd-core/references/planning-config.md +11 -2
  114. package/gsd-core/references/tdd.md +27 -4
  115. package/gsd-core/references/ui-consideration-probe.md +10 -5
  116. package/gsd-core/references/verify-command-path-resolvability.md +10 -2
  117. package/gsd-core/references/worktree-path-safety.md +321 -0
  118. package/gsd-core/templates/verification-report.md +1 -1
  119. package/gsd-core/workflows/_runtime-launcher.snippet.sh +1 -1
  120. package/gsd-core/workflows/add-backlog.md +1 -1
  121. package/gsd-core/workflows/add-phase.md +1 -1
  122. package/gsd-core/workflows/add-tests.md +2 -2
  123. package/gsd-core/workflows/add-todo.md +3 -3
  124. package/gsd-core/workflows/ai-integration-phase.md +11 -3
  125. package/gsd-core/workflows/audit-fix.md +1 -1
  126. package/gsd-core/workflows/audit-milestone.md +1 -1
  127. package/gsd-core/workflows/audit-uat.md +1 -1
  128. package/gsd-core/workflows/autonomous/steps/converge-fail-fast.md +9 -18
  129. package/gsd-core/workflows/autonomous.md +16 -6
  130. package/gsd-core/workflows/check-todos.md +2 -2
  131. package/gsd-core/workflows/cleanup.md +2 -2
  132. package/gsd-core/workflows/code-review/steps/dispatch-fix.md +4 -3
  133. package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +1 -1
  134. package/gsd-core/workflows/code-review-fix.md +108 -22
  135. package/gsd-core/workflows/code-review.md +63 -46
  136. package/gsd-core/workflows/complete-milestone/detail/elaboration.md +1 -1
  137. package/gsd-core/workflows/complete-milestone.md +2 -2
  138. package/gsd-core/workflows/debug.md +3 -3
  139. package/gsd-core/workflows/diagnose-issues.md +1 -1
  140. package/gsd-core/workflows/discuss-phase/modes/advisor.md +1 -1
  141. package/gsd-core/workflows/discuss-phase/modes/chain.md +1 -1
  142. package/gsd-core/workflows/discuss-phase-assumptions.md +1 -1
  143. package/gsd-core/workflows/discuss-phase.md +1 -1
  144. package/gsd-core/workflows/do.md +2 -2
  145. package/gsd-core/workflows/docs-update.md +3 -3
  146. package/gsd-core/workflows/edit-phase.md +1 -1
  147. package/gsd-core/workflows/eval-review.md +10 -3
  148. package/gsd-core/workflows/execute-phase/detail/elaboration.md +2 -2
  149. package/gsd-core/workflows/execute-phase/steps/code-review-disposition.md +1017 -0
  150. package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +1 -1
  151. package/gsd-core/workflows/execute-phase/steps/completion-reconciliation.md +3 -3
  152. package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +37 -3
  153. package/gsd-core/workflows/execute-phase/steps/gap-closure-artifacts.md +1 -1
  154. package/gsd-core/workflows/execute-phase/steps/partial-wave.md +1 -1
  155. package/gsd-core/workflows/execute-phase/steps/per-plan-executor-routing.md +1 -1
  156. package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +1 -1
  157. package/gsd-core/workflows/execute-phase/steps/post-merge-gate.md +46 -9
  158. package/gsd-core/workflows/execute-phase/steps/protected-branch.md +1 -1
  159. package/gsd-core/workflows/execute-phase/steps/ready-wave-gate.md +37 -0
  160. package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +1 -1
  161. package/gsd-core/workflows/execute-phase/steps/stale-reverification.md +24 -0
  162. package/gsd-core/workflows/execute-phase/steps/tdd-applicability-resolution.md +1 -1
  163. package/gsd-core/workflows/execute-phase/steps/threat-id-gate.md +28 -0
  164. package/gsd-core/workflows/execute-phase/steps/wave-post-gate-hooks.md +1 -1
  165. package/gsd-core/workflows/execute-phase/steps/worktree-base-check.md +25 -0
  166. package/gsd-core/workflows/execute-phase.md +36 -26
  167. package/gsd-core/workflows/execute-plan.md +5 -4
  168. package/gsd-core/workflows/explore.md +3 -3
  169. package/gsd-core/workflows/extract-learnings.md +2 -1
  170. package/gsd-core/workflows/fast.md +1 -1
  171. package/gsd-core/workflows/forensics.md +1 -1
  172. package/gsd-core/workflows/graduation.md +1 -1
  173. package/gsd-core/workflows/health.md +2 -2
  174. package/gsd-core/workflows/help/modes/full.compact.md +3 -3
  175. package/gsd-core/workflows/help/modes/full.md +5 -5
  176. package/gsd-core/workflows/help/modes/topic.md +15 -5
  177. package/gsd-core/workflows/import.md +2 -2
  178. package/gsd-core/workflows/inbox.md +2 -2
  179. package/gsd-core/workflows/ingest-docs.md +3 -3
  180. package/gsd-core/workflows/insert-phase.md +1 -1
  181. package/gsd-core/workflows/list-seeds.md +1 -1
  182. package/gsd-core/workflows/list-workspaces.md +1 -1
  183. package/gsd-core/workflows/manager.md +2 -2
  184. package/gsd-core/workflows/map-codebase.md +2 -2
  185. package/gsd-core/workflows/milestone-summary.md +1 -1
  186. package/gsd-core/workflows/mvp-phase.md +1 -1
  187. package/gsd-core/workflows/new-milestone.md +2 -2
  188. package/gsd-core/workflows/new-project/steps/auto-mode-config.md +3 -3
  189. package/gsd-core/workflows/new-project/steps/codebase-map-offer.md +1 -1
  190. package/gsd-core/workflows/new-project.md +7 -7
  191. package/gsd-core/workflows/new-workspace.md +2 -2
  192. package/gsd-core/workflows/next.md +1 -1
  193. package/gsd-core/workflows/note.md +1 -1
  194. package/gsd-core/workflows/onboard.md +1 -1
  195. package/gsd-core/workflows/pause-work.md +1 -1
  196. package/gsd-core/workflows/plan-phase/detail/elaboration.md +1 -1
  197. package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +17 -5
  198. package/gsd-core/workflows/plan-phase/steps/prd-express-path.md +1 -1
  199. package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +23 -5
  200. package/gsd-core/workflows/plan-phase.md +24 -7
  201. package/gsd-core/workflows/plan-review-convergence.md +21 -5
  202. package/gsd-core/workflows/plant-seed.md +62 -20
  203. package/gsd-core/workflows/pr-branch.md +113 -13
  204. package/gsd-core/workflows/profile-user.md +2 -2
  205. package/gsd-core/workflows/progress.md +1 -1
  206. package/gsd-core/workflows/quick/steps/plan-checker-loop.md +25 -0
  207. package/gsd-core/workflows/quick/steps/quick-verification.md +1 -1
  208. package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +1 -1
  209. package/gsd-core/workflows/quick-batch/steps/batch-init.md +1 -1
  210. package/gsd-core/workflows/quick-batch/steps/completion.md +1 -1
  211. package/gsd-core/workflows/quick-batch/steps/merge-wave.md +1 -1
  212. package/gsd-core/workflows/quick-batch/steps/planner-wave.md +1 -1
  213. package/gsd-core/workflows/quick-batch/steps/research-phase.md +1 -1
  214. package/gsd-core/workflows/quick-batch/steps/resume-mode.md +1 -1
  215. package/gsd-core/workflows/quick-batch/steps/verification-wave.md +1 -1
  216. package/gsd-core/workflows/quick-batch/steps/worktree-dispatch.md +1 -1
  217. package/gsd-core/workflows/quick-batch.md +1 -1
  218. package/gsd-core/workflows/quick.md +21 -9
  219. package/gsd-core/workflows/reapply-patches.md +9 -3
  220. package/gsd-core/workflows/remove-phase.md +1 -1
  221. package/gsd-core/workflows/remove-workspace.md +2 -2
  222. package/gsd-core/workflows/resume-project.md +1 -1
  223. package/gsd-core/workflows/review.md +31 -16
  224. package/gsd-core/workflows/scan.md +1 -1
  225. package/gsd-core/workflows/secure-phase.md +3 -2
  226. package/gsd-core/workflows/settings-advanced.md +30 -10
  227. package/gsd-core/workflows/settings-integrations.md +2 -3
  228. package/gsd-core/workflows/settings.md +4 -4
  229. package/gsd-core/workflows/ship.md +3 -2
  230. package/gsd-core/workflows/sketch-wrap-up.md +1 -1
  231. package/gsd-core/workflows/sketch.md +1 -1
  232. package/gsd-core/workflows/smart-entry.md +2 -2
  233. package/gsd-core/workflows/spec-phase.md +15 -5
  234. package/gsd-core/workflows/spike-wrap-up.md +1 -1
  235. package/gsd-core/workflows/spike.md +1 -1
  236. package/gsd-core/workflows/stats.md +1 -1
  237. package/gsd-core/workflows/sync-skills.md +5 -5
  238. package/gsd-core/workflows/thread.md +1 -1
  239. package/gsd-core/workflows/transition.md +1 -1
  240. package/gsd-core/workflows/ui-phase.md +44 -8
  241. package/gsd-core/workflows/ui-review.md +18 -4
  242. package/gsd-core/workflows/ultraplan-phase.md +1 -1
  243. package/gsd-core/workflows/undo.md +339 -20
  244. package/gsd-core/workflows/update.md +7 -7
  245. package/gsd-core/workflows/validate-phase.md +3 -2
  246. package/gsd-core/workflows/verify-work/steps/automated-ui-verification.md +1 -1
  247. package/gsd-core/workflows/verify-work/steps/mvp-uat-framing.md +1 -1
  248. package/gsd-core/workflows/verify-work.md +81 -16
  249. package/hooks/dist/gsd-agent-isolation-guard.js +24 -0
  250. package/hooks/dist/gsd-secret-read-guard.js +27 -1
  251. package/hooks/dist/gsd-statusline.js +70 -13
  252. package/hooks/dist/gsd-validate-commit.sh +63 -4
  253. package/hooks/gsd-agent-isolation-guard.js +24 -0
  254. package/hooks/gsd-secret-read-guard.js +27 -1
  255. package/hooks/gsd-statusline.js +70 -13
  256. package/hooks/gsd-validate-commit.sh +63 -4
  257. package/package.json +3 -2
  258. package/scripts/build-hooks.js +15 -6
  259. package/scripts/check-contract-drift.cjs +127 -11
  260. package/scripts/command-contract-helpers.cjs +3 -0
  261. package/scripts/docs-guard-registry.cjs +28 -0
  262. package/scripts/gen-loop-host-contract.cjs +69 -0
  263. package/scripts/lib/macos-conformance-tier.generated.cjs +14 -0
  264. package/scripts/lib/ndjson-reporter.cjs +3 -2
  265. package/scripts/lib/platform-conformance-tier.generated.cjs +11 -0
  266. package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +28 -1
  267. package/scripts/lint-phase-arg-assignment.cjs +257 -0
  268. package/scripts/lint-phase-id-drift.cjs +290 -5
  269. package/scripts/lint-pr-branch-pattern-drift.cjs +148 -0
  270. package/scripts/lint-retired-runtime-name.cjs +619 -0
  271. package/scripts/lint-state-write-path-drift.cjs +93 -0
  272. package/scripts/lint-test-file-count.allowlist.json +28 -9
  273. package/scripts/lint-workflow-shellcheck-baseline.json +15 -0
  274. package/scripts/prompt-injection-scan.sh +4 -0
  275. package/scripts/release-tarball-smoke.cjs +194 -1
  276. package/skills/gsd-autonomous/SKILL.md +2 -2
  277. package/skills/gsd-capture/SKILL.md +1 -1
  278. package/skills/gsd-mempalace-capture/SKILL.md +7 -3
  279. package/skills/gsd-plan-review-convergence/SKILL.md +5 -5
  280. package/skills/gsd-progress/SKILL.md +1 -1
  281. package/skills/gsd-quick-batch/SKILL.md +1 -1
  282. package/skills/gsd-review/SKILL.md +2 -3
  283. package/vscode/package.json +1 -1
@@ -162,6 +162,12 @@ const REASON = Object.freeze({
162
162
  // Axis 2 (§8.6, retained): a raw `fs.writeFileSync(` call targeting the
163
163
  // state path — see `findRawStateWrites`.
164
164
  RAW_STATE_WRITE: 'raw_state_write',
165
+ // ADR-4629 §8.1 (epic #4629, C1): a residual `readModifyWriteStateMd(path,
166
+ // (content) => …)` call whose transform is an inline anonymous arrow/function
167
+ // — the opaque shape §8.1 replaces with a declared StateWriteIntent. Recognized
168
+ // by `findOpaqueStateTransforms`; a CAPABILITY in C1 (not wired into collect()),
169
+ // wired terminal in C2 as the residual callers migrate (ADR-3408 §6 phasing).
170
+ OPAQUE_STATE_TRANSFORM: 'opaque_state_transform',
165
171
  // Axis 4 (§8.3, Decision 4(d)): prompt-layer prose shelling out to a
166
172
  // write-side `gsd-tools` subcommand — see `findPromptSeamUses`.
167
173
  PROMPT_LAYER_STATE_WRITE: 'prompt_layer_state_write',
@@ -645,6 +651,91 @@ function findRawStateWrites(rel, text) {
645
651
  return out;
646
652
  }
647
653
 
654
+ // ADR-4629 §8.1 (epic #4629, C1) — OPAQUE-TRANSFORM RECOGNITION.
655
+ //
656
+ // A residual `readModifyWriteStateMd(path, (content) => …)` call whose transform
657
+ // (2nd) argument is an inline anonymous arrow / function expression is the opaque
658
+ // shape §8.1 replaces with a declared StateWriteIntent: `readModifyWriteStateMd`
659
+ // goes THROUGH the seam (it is NOT a raw-write bypass — Axis 2's concern), but its
660
+ // opaque body transform is neither verified (§8.2) nor bounded (§8.3). This
661
+ // function RECOGNIZES that shape.
662
+ //
663
+ // C1 ships recognition as a CAPABILITY: it is exported and unit-tested (positive
664
+ // control on a seeded fixture) but is DELIBERATELY NOT wired into `collect()`'s
665
+ // failing scan. §8.1's caller-side rule is *Required — Phase 2*; wiring it now
666
+ // would turn the ~16 residual callers red at once, and ADR-3473 §8.6 retired the
667
+ // ratchet that would otherwise be needed to absorb them. C2 wires this terminal as
668
+ // the verifying executor lands and the callers migrate under ADR-3408 §6 phasing.
669
+ //
670
+ // String match, never an AST — same over-report-safe posture as every axis here.
671
+ const OPAQUE_RMW_CALL_RE = /\breadModifyWriteStateMd\s*\(/g;
672
+ // The transform arg is OPAQUE when it BEGINS an inline anonymous function: an
673
+ // arrow (`(…) =>`, `ident =>`, optionally `async`) or a `function` expression. A
674
+ // bare identifier / object (a declared StateWriteIntent, Phase 2+) is NOT opaque.
675
+ const ANON_TRANSFORM_RE =
676
+ /^\s*(?:async\s+)?(?:\([^)]*\)|[A-Za-z_$][\w$]*)\s*=>|^\s*(?:async\s+)?function\b/;
677
+
678
+ /**
679
+ * Capture the top-level, comma-separated argument list of a call, starting at
680
+ * `startIdx` (the index just AFTER the opening `(`) — across newlines and
681
+ * string-aware, tracking `()[]{}` depth. Returns the raw arg strings, or null if
682
+ * the parens never balance (a truncated arg list is never flagged). Generalizes
683
+ * `captureFirstArg`'s depth/inStr bookkeeping to every argument.
684
+ */
685
+ function captureCallArgList(text, startIdx) {
686
+ let depth = 0;
687
+ let inStr = null;
688
+ const args = [];
689
+ let cur = '';
690
+ for (let i = startIdx; i < text.length; i++) {
691
+ const ch = text[i];
692
+ if (inStr) {
693
+ cur += ch;
694
+ if (ch === inStr && text[i - 1] !== '\\') inStr = null;
695
+ continue;
696
+ }
697
+ if (ch === '"' || ch === "'" || ch === '`') { inStr = ch; cur += ch; continue; }
698
+ if (ch === '(' || ch === '[' || ch === '{') { depth++; cur += ch; continue; }
699
+ if (ch === ')' || ch === ']' || ch === '}') {
700
+ if (ch === ')' && depth === 0) {
701
+ if (cur.trim() !== '' || args.length) args.push(cur);
702
+ return args;
703
+ }
704
+ depth--; cur += ch; continue;
705
+ }
706
+ if (ch === ',' && depth === 0) { args.push(cur); cur = ''; continue; }
707
+ cur += ch;
708
+ }
709
+ return null; // parens never balanced
710
+ }
711
+
712
+ /**
713
+ * Recognize residual opaque-transform STATE.md writes (ADR-4629 §8.1). Returns a
714
+ * finding per `readModifyWriteStateMd(` call whose 2nd argument is an inline
715
+ * anonymous transform. CAPABILITY only in C1 — not called by `collect()`.
716
+ */
717
+ function findOpaqueStateTransforms(rel, text) {
718
+ const rawLines = text.split('\n');
719
+ const stripped = stripComments(text).join('\n');
720
+ const out = [];
721
+ let m;
722
+ OPAQUE_RMW_CALL_RE.lastIndex = 0;
723
+ while ((m = OPAQUE_RMW_CALL_RE.exec(stripped)) !== null) {
724
+ const args = captureCallArgList(stripped, m.index + m[0].length);
725
+ if (!args || args.length < 2) continue;
726
+ if (!ANON_TRANSFORM_RE.test(args[1])) continue;
727
+ const lineNo = stripped.slice(0, m.index).split('\n').length;
728
+ out.push({
729
+ reason: REASON.OPAQUE_STATE_TRANSFORM,
730
+ axis: 'opaque-transform',
731
+ file: sanitizeForReport(rel),
732
+ line: lineNo,
733
+ source: sanitizeForReport((rawLines[lineNo - 1] || '').trim()),
734
+ });
735
+ }
736
+ return out;
737
+ }
738
+
648
739
  // The two write-seam STAGE functions, matched only as CALLS (`\(`
649
740
  // immediately after, modulo whitespace) — never as bare mentions of the
650
741
  // name. `writeStateMd(` is deliberately NOT included here (that arm is
@@ -941,6 +1032,8 @@ module.exports = {
941
1032
  nearestPrecedingAssignment,
942
1033
  findRawStateWrites,
943
1034
  targetsStatePath,
1035
+ findOpaqueStateTransforms,
1036
+ captureCallArgList,
944
1037
  findCompositionBypasses,
945
1038
  findPromptSeamUses,
946
1039
  isInsideCodeSpan,
@@ -1,6 +1,15 @@
1
1
  {
2
- "_doc": "Baseline of modules currently exceeding the 2-test-file limit. Each entry locks in TODAY's exact test filenames as the allowlisted set (identity ratchet). Adding a NEW test file to a capped module fails (novel). Removing one requires pruning this list (stale, ratchet-down). When a cluster drops to \u2264 2, remove its entry entirely. New entries require justification in PR description.",
2
+ "_doc": "Baseline of modules currently exceeding the 2-test-file limit. Each entry locks in TODAY's exact test filenames as the allowlisted set (identity ratchet). Adding a NEW test file to a capped module fails (novel). Removing one requires pruning this list (stale, ratchet-down). When a cluster drops to ≤ 2, remove its entry entirely. New entries require justification in PR description.",
3
3
  "modules": {
4
+ "ui-consideration-probe": {
5
+ "files": [
6
+ "ui-consideration-probe-docs-fixtures.test.cjs",
7
+ "ui-consideration-probe-ui-phase-contract.test.cjs",
8
+ "ui-consideration-probe.test.cjs"
9
+ ],
10
+ "issue": "4657",
11
+ "justification": "The ui-consideration-probe cluster gains its workflow-prose contract file (tests/ui-consideration-probe-ui-phase-contract.test.cjs, #4657), mirroring the edge probe's split (edge-probe.test.cjs / edge-probe-docs-fixtures.test.cjs / edge-probe-spec-phase-contract.test.cjs). The contract file reads shipped gsd-core/workflows/ui-phase.md under the source-text-is-the-product exception, which the unit file deliberately does not carry (it asserts typed returns only)."
12
+ },
4
13
  "adr-parser": {
5
14
  "files": [
6
15
  "adr-parser.property.test.cjs",
@@ -40,7 +49,7 @@
40
49
  "frontmatter.unit.test.cjs"
41
50
  ],
42
51
  "issue": "3881",
43
- "justification": "Grandfathered by #3227 for the original 4-file cluster (pre-existing over-cap, not new sprawl). #3881 (ADR-3473 \u00a78.1, the js-yaml parser migration) adds two more: frontmatter-golden-parity.test.cjs (D-series golden-corpus diff against the legacy parser, ~900 real documents \u2014 cannot be folded into an existing file without losing its independent-of-current-parser provenance) and frontmatter-roundtrip.property.test.cjs (fast-check property coverage the migration's bijective-contract rule requires). Both are migration-specific, not incidental sprawl."
52
+ "justification": "Grandfathered by #3227 for the original 4-file cluster (pre-existing over-cap, not new sprawl). #3881 (ADR-3473 §8.1, the js-yaml parser migration) adds two more: frontmatter-golden-parity.test.cjs (D-series golden-corpus diff against the legacy parser, ~900 real documents — cannot be folded into an existing file without losing its independent-of-current-parser provenance) and frontmatter-roundtrip.property.test.cjs (fast-check property coverage the migration's bijective-contract rule requires). Both are migration-specific, not incidental sprawl."
44
53
  },
45
54
  "graphify": {
46
55
  "files": [
@@ -137,10 +146,11 @@
137
146
  "verify-npm-publish.test.cjs",
138
147
  "verify-test-quality.test.cjs",
139
148
  "verify-work-auto-transition.test.cjs",
149
+ "verify-work-deferred-promotion.test.cjs",
140
150
  "verify.test.cjs"
141
151
  ],
142
- "issue": "#3813 \u2014 the live-path #1883 suite drives buildPlanningSnapshot in-process with an fs fault; the verify module suites are CLI-driving and cannot host an fs monkeypatch",
143
- "justification": "verify-command-grounding added by #2401/#3678; allowlist follow-up landed with #3606 (base was red on this lane)."
152
+ "issue": "#3813 — the live-path #1883 suite drives buildPlanningSnapshot in-process with an fs fault; the verify module suites are CLI-driving and cannot host an fs monkeypatch",
153
+ "justification": "verify-command-grounding added by #2401/#3678; allowlist follow-up landed with #3606 (base was red on this lane). #4546 adds verify-work-deferred-promotion (deferred-follow-up promotion writer contract + parity)."
144
154
  },
145
155
  "install": {
146
156
  "files": [
@@ -154,7 +164,7 @@
154
164
  "install-write-confinement.test.cjs",
155
165
  "install.test.cjs"
156
166
  ],
157
- "issue": "#3798 \u2014 the profile-closure spawn test reads the real repo surface (commands+workflows+agents); consolidating it into install.test.cjs would put a whole-repo scan behind the suite's heaviest file"
167
+ "issue": "#3798 — the profile-closure spawn test reads the real repo surface (commands+workflows+agents); consolidating it into install.test.cjs would put a whole-repo scan behind the suite's heaviest file"
158
168
  },
159
169
  "edge-probe": {
160
170
  "files": [
@@ -252,8 +262,8 @@
252
262
  "docs-state-md-locale-parity.test.cjs",
253
263
  "docs-update.test.cjs"
254
264
  ],
255
- "issue": "3873 | #3839 \u2014 the hook-event parity suite cross-checks the four docs hook tables against src/runtime-hooks-surface.cts registrations; a generated-docs concern distinct from content freshness and registry parity",
256
- "justification": "ADR-3473 \u00a78.8 makes docs/reference/state-md.md and its four locale siblings generated-and-committed and adds the repo's first locale-parity check (verified: no locale-parity lint precedent exists here). That check is a distinct concern from docs-update (content freshness) and docs-parity-live-registry (registry parity); folding it into either would place an unrelated subject inside them purely to satisfy a count. The section it guards is absent from all four translations today and documents the status enum behind #3853."
265
+ "issue": "3873 | #3839 — the hook-event parity suite cross-checks the four docs hook tables against src/runtime-hooks-surface.cts registrations; a generated-docs concern distinct from content freshness and registry parity",
266
+ "justification": "ADR-3473 §8.8 makes docs/reference/state-md.md and its four locale siblings generated-and-committed and adds the repo's first locale-parity check (verified: no locale-parity lint precedent exists here). That check is a distinct concern from docs-update (content freshness) and docs-parity-live-registry (registry parity); folding it into either would place an unrelated subject inside them purely to satisfy a count. The section it guards is absent from all four translations today and documents the status enum behind #3853."
257
267
  },
258
268
  "audit": {
259
269
  "files": [
@@ -265,7 +275,7 @@
265
275
  "audit-uat-summary-segmentation.test.cjs",
266
276
  "audit-workstream-layouts.test.cjs"
267
277
  ],
268
- "issue": "#3804/#3805 \u2014 audit-layout and acknowledged-marker suites drive the real audit-uat CLI against on-disk fixtures | #3817 \u2014 regression suite proving countReal counts the truncation remainder marker instead of treating it as one phantom item | #3783 \u2014 dedicated suite for the summary.current_milestone/archived segmentation, matching this module's one-file-per-feature-slice precedent (e.g. audit-uat-acknowledged.test.cjs) rather than growing the unrelated 6900+ line tests/uat.test.cjs (a different module, keyed off uat.cjs)"
278
+ "issue": "#3804/#3805 — audit-layout and acknowledged-marker suites drive the real audit-uat CLI against on-disk fixtures | #3817 — regression suite proving countReal counts the truncation remainder marker instead of treating it as one phantom item | #3783 — dedicated suite for the summary.current_milestone/archived segmentation, matching this module's one-file-per-feature-slice precedent (e.g. audit-uat-acknowledged.test.cjs) rather than growing the unrelated 6900+ line tests/uat.test.cjs (a different module, keyed off uat.cjs)"
269
279
  },
270
280
  "shell-command-projection": {
271
281
  "files": [
@@ -273,7 +283,16 @@
273
283
  "shell-command-projection-md-normalize.test.cjs",
274
284
  "shell-command-projection-path-sep.test.cjs"
275
285
  ],
276
- "issue": "#3854 \u2014 the tight-list suite pins the markdown write-normalizer's blank-line policy through the exported normalizeContent/platformWriteSync seam; a distinct concern from dispatch routing and path separation"
286
+ "issue": "#3854 — the tight-list suite pins the markdown write-normalizer's blank-line policy through the exported normalizeContent/platformWriteSync seam; a distinct concern from dispatch routing and path separation"
287
+ },
288
+ "ui-consideration-probe": {
289
+ "files": [
290
+ "ui-consideration-probe-docs-fixtures.test.cjs",
291
+ "ui-consideration-probe-ui-phase-contract.test.cjs",
292
+ "ui-consideration-probe.test.cjs"
293
+ ],
294
+ "issue": "4657",
295
+ "justification": "The ui-consideration-probe cluster gains its workflow-prose contract file (tests/ui-consideration-probe-ui-phase-contract.test.cjs, #4657), mirroring the edge probe's split (edge-probe.test.cjs / edge-probe-docs-fixtures.test.cjs / edge-probe-spec-phase-contract.test.cjs). The contract file reads shipped gsd-core/workflows/ui-phase.md under the source-text-is-the-product exception, which the unit file deliberately does not carry (it asserts typed returns only)."
277
296
  }
278
297
  }
279
298
  }
@@ -1108,5 +1108,20 @@
1108
1108
  "file": "gsd-core/workflows/verify-work/steps/mvp-uat-framing.md",
1109
1109
  "code": "2086",
1110
1110
  "message": "Double quote to prevent globbing and word splitting."
1111
+ },
1112
+ {
1113
+ "file": "gsd-core/workflows/execute-phase/steps/code-review-disposition.md",
1114
+ "code": "2317",
1115
+ "message": "Command appears to be unreachable. Check usage (or ignore if invoked indirectly)."
1116
+ },
1117
+ {
1118
+ "file": "gsd-core/workflows/execute-phase/steps/code-review-disposition.md",
1119
+ "code": "2317",
1120
+ "message": "Command appears to be unreachable. Check usage (or ignore if invoked indirectly)."
1121
+ },
1122
+ {
1123
+ "file": "gsd-core/workflows/execute-phase/steps/code-review-disposition.md",
1124
+ "code": "2317",
1125
+ "message": "Command appears to be unreachable. Check usage (or ignore if invoked indirectly)."
1111
1126
  }
1112
1127
  ]
@@ -171,6 +171,10 @@ ALLOWLIST=(
171
171
  # allowlist cannot reach it either, because the literal `child_process` is
172
172
  # not adjacent to `.exec`. See the note at the pattern itself.
173
173
  'tests/continuation-grammar-parity.test.cjs'
174
+ # #4906 Phase 5 — regex.exec('### Phase 03: ...') fixtures.
175
+ # Same DEFECT.PROMPT-INJECTION-SCAN-COLLISION class as above:
176
+ # RegExp.prototype.exec, not code execution.
177
+ 'tests/phase-id.test.cjs'
174
178
  # #3676 row 11b — quick-batch's task-list parser must treat a
175
179
  # prompt-injection-shaped task description as inert data, never
176
180
  # interpreted. The fixture has to be a real "ignore all previous
@@ -37,6 +37,12 @@
37
37
  * colon-namespace leaks (WORKFLOW_BODY_COLON_LEAK).
38
38
  * This check populates result.details with counters but does NOT return a
39
39
  * failure code by default; it is informational until enforcement is enabled.
40
+ *
41
+ * Configured-entrypoint checks (Cycle 4 — #4154):
42
+ * For each runtime in entrypointRuntimes, runs the tarball-installed
43
+ * installer into a throwaway HOME, then re-reads that runtime's own written
44
+ * config files and asserts every GSD-managed script path they name resolves
45
+ * to a file (ENTRYPOINT_UNRESOLVED). Requires fixtureDir.
40
46
  */
41
47
 
42
48
  'use strict';
@@ -47,6 +53,8 @@ const os = require('os');
47
53
  const path = require('path');
48
54
  const { PACKAGE_NAME } = require('../gsd-core/bin/lib/package-identity.cjs');
49
55
  const { ExitError, runMain } = require('./lib/cli-exit.cjs');
56
+ const shellCmdProjection = require('../gsd-core/bin/lib/shell-command-projection.cjs');
57
+ const { escapeRegex } = require('../gsd-core/bin/lib/pattern.cjs');
50
58
  // 120 s proved too tight for cold-cache `npm install -g` of a 1499-file tarball:
51
59
  // spawnSync fires SIGTERM at the deadline and returns { status: null, stdout: '',
52
60
  // stderr: '' } (Node docs: status is null when a subprocess is terminated by a
@@ -86,6 +94,8 @@ const SMOKE = Object.freeze({
86
94
  INIT_FAILED: 'init_failed',
87
95
  // Cycle 3 code
88
96
  WORKFLOW_BODY_COLON_LEAK: 'workflow_body_colon_leak',
97
+ // Cycle 4 code (#4154)
98
+ ENTRYPOINT_UNRESOLVED: 'entrypoint_unresolved',
89
99
  });
90
100
 
91
101
  // ---------------------------------------------------------------------------
@@ -274,6 +284,106 @@ function scanWorkflowColonLeak(filePath, cmdNames) {
274
284
  return null;
275
285
  }
276
286
 
287
+ // ---------------------------------------------------------------------------
288
+ // Cycle 4 helpers: configured-entrypoint resolution (#4154)
289
+ // ---------------------------------------------------------------------------
290
+
291
+ /**
292
+ * Top-level config files this scan reads. These are the surfaces that carry
293
+ * every GSD-managed launch path for the runtimes Cycle 4 actually installs
294
+ * (`entrypointRuntimes`, default claude + codex): claude registers into
295
+ * settings.json, codex into hooks.json and config.toml.
296
+ *
297
+ * This is NOT an exhaustive map of where GSD writes launch paths across all
298
+ * runtimes, and the scan is top-level only by design. Two known surfaces sit
299
+ * outside it: Cline registers its hook at `.clinerules/hooks/PreToolUse` (a
300
+ * subdirectory, and not one of these names — see writeClineArtifacts in
301
+ * src/runtime-hooks-surface.cts), and Kimi's native `[[hooks]]` config.toml
302
+ * lives under `resolveKimiHooksTomlDir()` (`~/.kimi`), a directory separate
303
+ * from Kimi's own GSD configDir. Adding either runtime to entrypointRuntimes
304
+ * requires teaching scanConfiguredEntrypoints about its surface first,
305
+ * otherwise the scan reports zero entrypoints and silently proves nothing.
306
+ */
307
+ const RUNTIME_CONFIG_FILES = Object.freeze(['settings.json', 'hooks.json', 'config.toml']);
308
+
309
+ /**
310
+ * Extract every script path `text` names underneath `configDir`.
311
+ *
312
+ * #4249 (antigravity review): anchored on the literal, already-known
313
+ * `configDir` prefix instead of a generic "any absolute path" character
314
+ * class. The prior version excluded whitespace from the match to avoid
315
+ * swallowing a shell command's trailing args, which also truncated any
316
+ * legitimate path containing a space (e.g. `/Users/John Doe/.claude`) —
317
+ * `scanConfiguredEntrypoints` would then silently report zero checked
318
+ * paths. Anchoring on `configDir` removes the ambiguity outright: a match
319
+ * can only start where the known prefix literally occurs in the text, so
320
+ * an interpreter path concatenated ahead of it (`"/usr/bin/node
321
+ * /configDir/hooks/foo.js"`) is never swallowed either, and interior
322
+ * whitespace inside `configDir` or the script's own path segments is safe
323
+ * to allow. This still scans raw, unparsed config text on purpose (see
324
+ * scanConfiguredEntrypoints's doc comment) — it catches a writer that
325
+ * embeds a launch path without registering it, which a structured
326
+ * JSON.parse of the expected schema would miss entirely.
327
+ *
328
+ * Windows configs store paths with backslashes, which JSON/TOML doubles on
329
+ * write; collapsing `\\` to `\` first makes the raw text scan work on both
330
+ * platforms without parsing each config format separately (POSIX text has no
331
+ * backslashes, so the collapse is a no-op there).
332
+ *
333
+ * Every writer bakes `configDir` through the same posixNormalize seam
334
+ * (src/runtime-hooks-surface.cts) before writing it into config text, on
335
+ * every platform — so the anchor must match that projection, not the
336
+ * OS-native `configDir` string this function receives.
337
+ */
338
+ function configuredEntrypointsIn(text, configDir) {
339
+ const normalizedPrefix = shellCmdProjection.posixNormalize(configDir).replace(/\/+$/, '') + '/';
340
+ const scriptPathRe = new RegExp(`${escapeRegex(normalizedPrefix)}[^"']{0,400}?\\.(?:js|cjs|mjs|sh|cmd|ps1)`, 'g');
341
+ const found = new Set();
342
+ for (const match of text.replace(/\\\\/g, '\\').matchAll(scriptPathRe)) {
343
+ found.add(path.resolve(match[0]));
344
+ }
345
+ return [...found];
346
+ }
347
+
348
+ /**
349
+ * Throwaway HOME the Cycle 4 install for `runtime` runs against. Exported so a
350
+ * test can seed that runtime's config before the install rather than
351
+ * hard-coding the layout runSmoke picks.
352
+ */
353
+ function entrypointFixtureHome(fixtureDir, runtime) {
354
+ return path.join(fixtureDir, `entrypoints-${runtime}`);
355
+ }
356
+
357
+ /**
358
+ * Re-derive the configured entrypoints a completed install wrote into a
359
+ * runtime's own config files and report the ones that do not resolve to a
360
+ * file. Internal to Cycle 4; the smoke's verdict is the exported contract.
361
+ *
362
+ * This deliberately does NOT consult the installer's own entrypoint list (the
363
+ * assertConfiguredEntrypoints gate in bin/install.js). That gate can only
364
+ * validate paths a config writer remembered to register; reading the written
365
+ * config back is what catches a writer that emits a launch path without
366
+ * registering it, and a stale registration an install left behind.
367
+ *
368
+ * @param {string} configDir - Absolute path to the runtime config dir.
369
+ * @returns {{ checked: string[], unresolved: { configPath: string, scriptPath: string }[] }}
370
+ */
371
+ function scanConfiguredEntrypoints(configDir) {
372
+ const checked = [];
373
+ const unresolved = [];
374
+ for (const name of RUNTIME_CONFIG_FILES) {
375
+ const configPath = path.join(configDir, name);
376
+ if (!fs.existsSync(configPath) || !fs.statSync(configPath).isFile()) continue;
377
+ const text = fs.readFileSync(configPath, 'utf-8');
378
+ for (const scriptPath of configuredEntrypointsIn(text, configDir)) {
379
+ checked.push(scriptPath);
380
+ if (fs.existsSync(scriptPath) && fs.statSync(scriptPath).isFile()) continue;
381
+ unresolved.push({ configPath, scriptPath });
382
+ }
383
+ }
384
+ return { checked, unresolved };
385
+ }
386
+
277
387
  // ---------------------------------------------------------------------------
278
388
  // Pure function: runSmoke
279
389
  // ---------------------------------------------------------------------------
@@ -285,6 +395,8 @@ function scanWorkflowColonLeak(filePath, cmdNames) {
285
395
  * @param {string} opts.expectedVersion - semver string to assert (e.g. "1.50.0")
286
396
  * @param {string} [opts.fixtureDir] - Temp dir to run `init` into (must NOT be HOME)
287
397
  * @param {string[]} [opts.lifecycleCommands] - Commands to file-check (default: see below)
398
+ * @param {string[]} [opts.entrypointRuntimes] - Runtime profiles whose configured entrypoints are
399
+ * re-checked after a real install (default: see below). Requires fixtureDir; pass [] to skip.
288
400
  * @param {boolean} [opts.dryRun=false] - If true, skip actual npm install; validate input only
289
401
  * @param {object} [opts.npmEnv] - Optional env dict for the internal npm install
290
402
  * spawnSync call. Pass an isolated HOME env (e.g. from isolatedNpmEnv() in tests/helpers.cjs)
@@ -298,6 +410,11 @@ function runSmoke({
298
410
  expectedVersion,
299
411
  fixtureDir,
300
412
  lifecycleCommands = ['init', 'discuss-phase', 'plan-phase', 'execute-phase'],
413
+ // claude and codex cover the two top-level config surfaces this scan knows
414
+ // how to read (settings.json, and hooks.json + config.toml). Most other
415
+ // runtimes reuse one of those two shapes; Cline and Kimi do not (see
416
+ // RUNTIME_CONFIG_FILES), so they are out of scope here rather than covered.
417
+ entrypointRuntimes = ['claude', 'codex'],
301
418
  dryRun = false,
302
419
  npmEnv = undefined,
303
420
  }) {
@@ -551,6 +668,75 @@ function runSmoke({
551
668
  // NOTE: colonLeakCount is informational here. Once the backlog is fixed,
552
669
  // a future enforcement mode can fail on non-zero counts.
553
670
 
671
+ // ─────────────────────────────────────────────────────────────────────────
672
+ // Cycle 4: configured-entrypoint resolution (#4154)
673
+ // ─────────────────────────────────────────────────────────────────────────
674
+
675
+ // The installer's own gate (assertConfiguredEntrypoints) runs in-process and
676
+ // only sees the paths a config writer registered with it. Installing the
677
+ // packed tarball for real and reading each runtime's written config back is
678
+ // what proves the launch paths a user's runtime will actually invoke exist
679
+ // in the shipped layout.
680
+ const entrypointProfiles = [];
681
+ if (fixtureDir && entrypointRuntimes.length > 0) {
682
+ for (const runtime of entrypointRuntimes) {
683
+ // Own HOME per runtime so a --global install cannot reach the real one.
684
+ const runtimeHome = entrypointFixtureHome(fixtureDir, runtime);
685
+ const configDir = path.join(runtimeHome, `.${runtime}`);
686
+ fs.mkdirSync(runtimeHome, { recursive: true });
687
+
688
+ const installResult = spawnSync(
689
+ process.execPath,
690
+ [path.join(pkg, 'bin', 'install.js'), `--${runtime}`, '--global', '--config-dir', configDir],
691
+ {
692
+ encoding: 'utf-8',
693
+ cwd: runtimeHome,
694
+ stdio: ['pipe', 'pipe', 'pipe'],
695
+ env: {
696
+ ...effectiveNpmEnv,
697
+ HOME: runtimeHome,
698
+ USERPROFILE: runtimeHome,
699
+ // Same reason as the init check above: install.js skips its main()
700
+ // block when GSD_TEST_MODE is set and would exit 0 writing nothing.
701
+ GSD_TEST_MODE: '',
702
+ NO_UPDATE_NOTIFIER: '1',
703
+ },
704
+ timeout: CHILD_TIMEOUT_MS,
705
+ },
706
+ );
707
+
708
+ if (installResult.status !== 0) {
709
+ // #4249 (antigravity review): this is the Cycle 4 per-runtime install,
710
+ // not Cycle 1's `gsd init` — SMOKE.INSTALL_FAILED is the code Cycle 2's
711
+ // identical spawnSync-failure check already uses for the same failure
712
+ // class; reusing SMOKE.INIT_FAILED here conflated the two lifecycle
713
+ // stages in the reported code.
714
+ return {
715
+ code: SMOKE.INSTALL_FAILED,
716
+ details: {
717
+ ...details,
718
+ runtime,
719
+ configDir,
720
+ stderr: installResult.stderr,
721
+ stdout: installResult.stdout,
722
+ },
723
+ };
724
+ }
725
+
726
+ const scan = scanConfiguredEntrypoints(configDir);
727
+ if (scan.unresolved.length > 0) {
728
+ return {
729
+ code: SMOKE.ENTRYPOINT_UNRESOLVED,
730
+ details: { ...details, runtime, configDir, unresolved: scan.unresolved },
731
+ };
732
+ }
733
+
734
+ entrypointProfiles.push({ runtime, configDir, entrypointsChecked: scan.checked.length });
735
+ }
736
+ }
737
+
738
+ details.entrypointProfiles = entrypointProfiles;
739
+
554
740
  return { code: SMOKE.OK, details };
555
741
  }
556
742
 
@@ -635,7 +821,14 @@ function cleanup(...dirs) {
635
821
  // Exports
636
822
  // ---------------------------------------------------------------------------
637
823
 
638
- module.exports = { SMOKE, runSmoke, binInvocation, CHILD_TIMEOUT_MS };
824
+ module.exports = {
825
+ SMOKE,
826
+ runSmoke,
827
+ binInvocation,
828
+ entrypointFixtureHome,
829
+ CHILD_TIMEOUT_MS,
830
+ configuredEntrypointsIn,
831
+ };
639
832
 
640
833
  if (require.main === module) {
641
834
  runMain(cliMain);
@@ -36,10 +36,10 @@ Optional flags:
36
36
  - `--to N` — stop after phase N completes (halt instead of advancing to next phase).
37
37
  - `--only N` — execute only phase N (single-phase mode).
38
38
  - `--interactive` — run discuss inline with questions (not auto-answered), then dispatch plan→execute as background agents. Keeps the main context lean while preserving user input on decisions.
39
- - `--converge` — run each phase's planning step through `gsd-plan-review-convergence` instead of plain `gsd-plan-phase`. Requires `workflow.plan_review_convergence=true`.
39
+ - `--converge` — run each phase's planning step through `gsd-plan-review-convergence` instead of plain `gsd-plan-phase`. Works even when `workflow.plan_review_convergence` is `false` — the explicit flag overrides the gate; the gate (`workflow.plan_review_convergence=true` enables it) governs the standalone `gsd-plan-review-convergence` command. Without the flag, planning runs `gsd-plan-phase`.
40
40
  - `--cross-ai` — compatibility alias for `--converge`.
41
41
 
42
- When `--converge` or `--cross-ai` is set, reviewer selector flags supported by `gsd-plan-review-convergence` may be passed through: `--codex`, `--gemini`, `--claude`, `--opencode`, `--ollama`, `--lm-studio`, `--llama-cpp`, `--all`, and `--max-cycles N`.
42
+ When `--converge` or `--cross-ai` is set, reviewer selector flags supported by `gsd-plan-review-convergence` may be passed through: `--codex`, `--claude`, `--opencode`, `--ollama`, `--lm-studio`, `--llama-cpp`, `--all`, and `--max-cycles N`.
43
43
 
44
44
  Project context, phase list, and state are resolved inside the workflow using init commands (`gsd-tools query init.milestone-op`, `gsd-tools query roadmap.analyze`). No upfront context loading needed.
45
45
  </context>
@@ -32,7 +32,7 @@ Mode routing:
32
32
  | (none) | Structured todo in .planning/todos/ | add-todo |
33
33
  | --note | Timestamped note file, list, or promote | note |
34
34
  | --backlog | ROADMAP.md backlog section (999.x) | add-backlog |
35
- | --seed | .planning/seeds/SEED-NNN-slug.md | plant-seed |
35
+ | --seed | .planning/seeds/SEED-YYMMDD-xxx-slug.md | plant-seed |
36
36
  | --list | Interactive todo browser + action router | check-todos |
37
37
  | --list-seeds | Read-only seed list/audit (optional status filter) | list-seeds |
38
38
 
@@ -84,15 +84,19 @@ On any error or timeout, stop and let the phase continue -- capture is best-effo
84
84
  ROOM_DIR="$STAGE/<room>/<phase-id>"
85
85
  mkdir -p "$ROOM_DIR"
86
86
  cp "<artifact-path>" "$ROOM_DIR/<basename>"
87
- # Mine with --wing only — no --room flag; detect_room() assigns from the folder path
88
- mempalace mine "$STAGE" --wing <wing>
87
+ # Mine with --wing only — no --room flag; detect_room() assigns from the folder path.
88
+ # --daemon --background (#4700): MemPalace wraps every mine in a per-palace
89
+ # lock; a concurrent writer would make a foreground mine exit 1
90
+ # (MineAlreadyRunning) and this onError: skip step would silently drop the
91
+ # capture. The background queue defers the job until the lock frees.
92
+ mempalace mine "$STAGE" --wing <wing> --daemon --background
89
93
  ```
90
94
  3. **Mirror KG facts** unless `config.mempalace.mirror_kg === false` (registry default is true — an absent key means enabled): extract decision/delivery facts and `mempalace_kg_add` them with `valid_from` = the phase date (e.g. `(<project>, decided, <decision>)` from CONTEXT; `(<phase>, delivered, <capability>)` from SUMMARY). Under `augment` these are an *additive* mirror of GSD's native `.planning/graphs/`. Under `kg_backend`/`replace` the palace KG is the *authoritative* fact store — GSD still produces `.planning/graphs/` through its normal graphify, so an unreachable palace never loses a fact.
91
95
  4. Re-running a phase MUST NOT create duplicate drawers (deterministic ids + `check_duplicate`).
92
96
 
93
97
  ## Step 4 -- Report
94
98
 
95
- Print a one-line summary: `Filed <artifact> → <wing>/<room> (<n> KG facts)` or `MemPalace unavailable — capture skipped`.
99
+ Print a one-line summary: `Filed <artifact> → <wing>/<room> (<n> KG facts)`, `Capture queued — palace busy; MemPalace will file it when the lock frees` (the background mine was deferred behind another writer), or `MemPalace capture skipped — <reason>` (#4700: a skipped capture is never silent).
96
100
 
97
101
  ## Anti-Patterns
98
102
 
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: gsd-plan-review-convergence
3
3
  description: "Cross-AI plan convergence - replan until review concerns are resolved."
4
- argument-hint: "<phase> [--gemini] [--claude] [--codex] [--coderabbit] [--opencode] [--qwen] [--cursor] [--antigravity] [--agy] [--ollama] [--lm-studio] [--llama-cpp] [--kimi-code] [--text] [--ws <name>] [--all] [--max-cycles N]"
4
+ argument-hint: "<phase> [--claude] [--codex] [--coderabbit] [--opencode] [--qwen] [--cursor] [--antigravity] [--agy] [--ollama] [--lm-studio] [--llama-cpp] [--kimi-code] [--text] [--ws <name>] [--all] [--max-cycles N]"
5
5
  allowed-tools:
6
6
  - Read
7
7
  - Write
@@ -20,7 +20,7 @@ Repeatedly: review plans with external AI CLIs → if HIGH or actionable non-HIG
20
20
 
21
21
  **Flow:** Skill("gsd-plan-phase") → Agent→Skill("gsd-review") → check unresolved HIGH + actionable non-HIGH → Skill("gsd-plan-phase --reviews") → Agent→Skill("gsd-review") → ... → Converge or escalate
22
22
 
23
- Replaces gsd-plan-phase's internal gsd-plan-checker with external AI reviewers (codex, gemini, etc.). Plan-phase runs **inline** (bare Skill at depth 0) so it can spawn gsd-planner/gsd-plan-checker at depth 1. Review runs inside an isolated Agent (gsd-review is a Bash leaf — no sub-agents needed). Orchestrator only does loop control.
23
+ Replaces gsd-plan-phase's internal gsd-plan-checker with external AI reviewers (codex, claude, etc.). Plan-phase runs **inline** (bare Skill at depth 0) so it can spawn gsd-planner/gsd-plan-checker at depth 1. Review runs inside an isolated Agent (gsd-review is a Bash leaf — no sub-agents needed). Orchestrator only does loop control.
24
24
 
25
25
  **Orchestrator role:** Parse arguments, validate phase, run plan-phase inline (Skill at depth 0), spawn an Agent for gsd-review, check unresolved HIGH and actionable non-HIGH counts, stall detection, escalation gate.
26
26
  </objective>
@@ -41,8 +41,7 @@ Phase number: extracted from $ARGUMENTS (required)
41
41
 
42
42
  **Flags:**
43
43
  - `--codex` — Use Codex CLI as reviewer (default if no reviewer flag given AND `review.default_reviewers` is unset; otherwise `review.default_reviewers` wins per ADR-0011 — #2315)
44
- - `--gemini` — Use Gemini CLI as reviewer
45
- - `--agy` / `--antigravity` — Use Antigravity CLI as reviewer (successor to the discontinued Gemini CLI)
44
+ - `--agy` / `--antigravity` — Use Antigravity CLI as reviewer
46
45
  - `--claude` — Use Claude CLI as reviewer (separate session)
47
46
  - `--coderabbit` — Use CodeRabbit as reviewer (reviews the working-tree diff, not the source tree)
48
47
  - `--opencode` — Use OpenCode as reviewer
@@ -56,7 +55,8 @@ Phase number: extracted from $ARGUMENTS (required)
56
55
  - `--max-cycles N` — Maximum replan→review cycles (default: 3)
57
56
 
58
57
  **Feature gate:** This command requires `workflow.plan_review_convergence=true`. Enable with:
59
- `gsd config-set workflow.plan_review_convergence true`
58
+ `gsd config-set workflow.plan_review_convergence true`. A dispatch carrying `--override-gate` —
59
+ how `/gsd-autonomous --converge` invokes this workflow (#4600) — bypasses the gate for that run.
60
60
  </context>
61
61
 
62
62
  <process>
@@ -24,7 +24,7 @@ Three modes:
24
24
  <flags>
25
25
  - **--next**: Detect current project state and automatically invoke the next logical GSD workflow step. Scans all prior phases for incomplete work before routing. `--next --force` bypasses safety gates.
26
26
  - **--next --auto**: Like `--next`, but after the determined step completes, automatically re-invokes `/gsd-progress --next --auto` to continue chaining steps until completion or a blocking decision. Enables hands-free plan→execute→verify→complete progression.
27
- - **--next --converge**: When the next action is planning (Route 3), route it through the plan-review **convergence** loop instead of the standard planner. Requires `workflow.plan_review_convergence=true` (enable with `gsd config-set workflow.plan_review_convergence true`). `--cross-ai` is an alias. Reviewer flags (`--codex`, `--gemini`, `--claude`, `--opencode`, `--ollama`, `--lm-studio`, `--llama-cpp`, `--all`) and `--max-cycles N` are forwarded to the convergence loop.
27
+ - **--next --converge**: When the next action is planning (Route 3), route it through the plan-review **convergence** loop instead of the standard planner. Requires `workflow.plan_review_convergence=true` (enable with `gsd config-set workflow.plan_review_convergence true`). `--cross-ai` is an alias. Reviewer flags (`--codex`, `--claude`, `--opencode`, `--ollama`, `--lm-studio`, `--llama-cpp`, `--all`) and `--max-cycles N` are forwarded to the convergence loop.
28
28
  - **--do "..."**: Smart dispatcher — match freeform intent to the best GSD command using routing rules, confirm the match, then hand off.
29
29
  - **--forensic**: Run 6-check integrity audit after the standard progress report.
30
30
  - **(no flag)**: Standard progress check + intelligent routing (Routes A through F).
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: gsd-quick-batch
3
- description: "Batch several /gsd:quick-shaped tasks together — planned, dispatched, and merged as one run"
3
+ description: "Batch several `/gsd-quick`-shaped tasks together — planned, dispatched, and merged as one run"
4
4
  argument-hint: "[--file <path>] [--jobs auto|N] [--validate] [--research] [--resume <batch-id>] [task list]"
5
5
  allowed-tools:
6
6
  - Read
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: gsd-review
3
3
  description: "Request cross-AI peer review of phase plans from external AI CLIs"
4
- argument-hint: "--phase N [--gemini] [--claude] [--codex] [--opencode] [--qwen] [--cursor] [--agy] [--all]"
4
+ argument-hint: "--phase N [--claude] [--codex] [--opencode] [--qwen] [--cursor] [--agy] [--all]"
5
5
  allowed-tools:
6
6
  - Read
7
7
  - Write
@@ -12,7 +12,7 @@ allowed-tools:
12
12
 
13
13
 
14
14
  <objective>
15
- Invoke external AI CLIs (Gemini, Claude, Codex, OpenCode, Qwen Code, Cursor) to independently review phase plans.
15
+ Invoke external AI CLIs (Claude, Codex, OpenCode, Qwen Code, Cursor, Antigravity) to independently review phase plans.
16
16
  Produces a structured REVIEWS.md with per-reviewer feedback that can be fed back into
17
17
  planning via /gsd-plan-phase --reviews.
18
18
 
@@ -27,7 +27,6 @@ planning via /gsd-plan-phase --reviews.
27
27
  Phase number: extracted from $ARGUMENTS (required)
28
28
 
29
29
  **Flags:**
30
- - `--gemini` — Include Gemini CLI review
31
30
  - `--claude` — Include Claude CLI review (uses separate session)
32
31
  - `--codex` — Include Codex CLI review
33
32
  - `--opencode` — Include OpenCode review (uses model from user's OpenCode config)
@@ -2,7 +2,7 @@
2
2
  "name": "gsd-core-vscode",
3
3
  "displayName": "GSD Core",
4
4
  "description": "GSD orchestration engine embedded in VS Code (ADR-1239 IDE profile).",
5
- "version": "1.14.0",
5
+ "version": "1.15.0",
6
6
  "publisher": "opengsd",
7
7
  "engines": {
8
8
  "vscode": "^1.105.0"