@opengsd/gsd-core 1.9.1 → 1.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (426) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +2 -3
  3. package/.opencode/plugins/gsd-core.js +8 -1
  4. package/agents/gsd-code-fixer.md +27 -3
  5. package/agents/gsd-debug-session-manager.md +11 -0
  6. package/agents/gsd-debugger.md +12 -246
  7. package/agents/gsd-doc-synthesizer.md +2 -4
  8. package/agents/gsd-executor.md +12 -10
  9. package/agents/gsd-integration-checker.md +3 -0
  10. package/agents/gsd-mempalace-curator.md +5 -2
  11. package/agents/gsd-phase-researcher.md +20 -1
  12. package/agents/gsd-plan-checker.md +46 -0
  13. package/agents/gsd-planner.md +49 -54
  14. package/agents/gsd-roadmapper.md +21 -3
  15. package/agents/gsd-user-profiler.md +3 -0
  16. package/agents/gsd-verifier.md +26 -73
  17. package/bin/install.js +1272 -1238
  18. package/bin/lib/ui-safety-gate.cjs +2 -0
  19. package/commands/gsd/code-review.md +1 -1
  20. package/commands/gsd/execute-phase.md +1 -1
  21. package/commands/gsd/map-codebase.md +1 -1
  22. package/commands/gsd/mempalace-capture.md +2 -2
  23. package/commands/gsd/mempalace-recall.md +1 -1
  24. package/commands/gsd/new-milestone.md +2 -2
  25. package/commands/gsd/plan-phase.md +1 -1
  26. package/commands/gsd/quick.md +1 -1
  27. package/commands/gsd/review-backlog.md +2 -1
  28. package/commands/gsd/verify-work.md +1 -1
  29. package/gsd-core/bin/gsd-tools.cjs +1009 -115
  30. package/gsd-core/bin/lib/active-workstream-store.cjs +153 -12
  31. package/gsd-core/bin/lib/agent-install-check.cjs +268 -38
  32. package/gsd-core/bin/lib/api-coverage.cjs +123 -5
  33. package/gsd-core/bin/lib/artifacts.cjs +3 -0
  34. package/gsd-core/bin/lib/assumption-delta.cjs +2 -4
  35. package/gsd-core/bin/lib/audit-command-router.cjs +9 -2
  36. package/gsd-core/bin/lib/audit.cjs +926 -202
  37. package/gsd-core/bin/lib/broken-windows.cjs +36 -6
  38. package/gsd-core/bin/lib/capability-consent.cjs +149 -15
  39. package/gsd-core/bin/lib/capability-lifecycle.cjs +45 -0
  40. package/gsd-core/bin/lib/capability-registry.cjs +608 -148
  41. package/gsd-core/bin/lib/capability-source.cjs +92 -0
  42. package/gsd-core/bin/lib/capability-trust.cjs +444 -25
  43. package/gsd-core/bin/lib/capability-validator.cjs +507 -24
  44. package/gsd-core/bin/lib/capability-writer.cjs +3 -2
  45. package/gsd-core/bin/lib/check-command-router.cjs +114 -38
  46. package/gsd-core/bin/lib/claude-orchestration.cjs +56 -3
  47. package/gsd-core/bin/lib/codex-agent-toml.cjs +329 -0
  48. package/gsd-core/bin/lib/command-aliases.cjs +94 -0
  49. package/gsd-core/bin/lib/command-roster.cjs +44 -1
  50. package/gsd-core/bin/lib/commands.cjs +665 -99
  51. package/gsd-core/bin/lib/commonjs-marker.cjs +142 -0
  52. package/gsd-core/bin/lib/complexity-trigger.cjs +1172 -0
  53. package/gsd-core/bin/lib/config-loader.cjs +76 -0
  54. package/gsd-core/bin/lib/config.cjs +22 -2
  55. package/gsd-core/bin/lib/context-composer.cjs +278 -0
  56. package/gsd-core/bin/lib/context-predicates.cjs +506 -0
  57. package/gsd-core/bin/lib/core-utils.cjs +217 -40
  58. package/gsd-core/bin/lib/decisions.cjs +23 -0
  59. package/gsd-core/bin/lib/docs.cjs +3 -2
  60. package/gsd-core/bin/lib/external-job.cjs +19 -4
  61. package/gsd-core/bin/lib/fallow-runner.cjs +20 -44
  62. package/gsd-core/bin/lib/frontmatter.cjs +239 -32
  63. package/gsd-core/bin/lib/gap-checker.cjs +68 -7
  64. package/gsd-core/bin/lib/gate-predicate-evaluator.cjs +57 -6
  65. package/gsd-core/bin/lib/git-base-branch.cjs +160 -15
  66. package/gsd-core/bin/lib/graphify.cjs +142 -27
  67. package/gsd-core/bin/lib/gsd2-import.cjs +37 -5
  68. package/gsd-core/bin/lib/health-diagnostic-rules/agent-install.cjs +101 -0
  69. package/gsd-core/bin/lib/health-diagnostic-rules/config-validation.cjs +348 -0
  70. package/gsd-core/bin/lib/health-diagnostic-rules/consistency.cjs +145 -0
  71. package/gsd-core/bin/lib/health-diagnostic-rules/install-surface-shadowing.cjs +98 -0
  72. package/gsd-core/bin/lib/health-diagnostic-rules/milestone-archive-hygiene.cjs +100 -0
  73. package/gsd-core/bin/lib/health-diagnostic-rules/phase-structure.cjs +222 -0
  74. package/gsd-core/bin/lib/health-diagnostic-rules/roadmap-disk-consistency.cjs +265 -0
  75. package/gsd-core/bin/lib/health-diagnostic-rules/root-existence.cjs +161 -0
  76. package/gsd-core/bin/lib/health-diagnostic-rules/state-consistency.cjs +303 -0
  77. package/gsd-core/bin/lib/health-diagnostic-rules/worktree-health.cjs +173 -0
  78. package/gsd-core/bin/lib/health-diagnostic-types.cjs +68 -0
  79. package/gsd-core/bin/lib/health-diagnostic.cjs +431 -0
  80. package/gsd-core/bin/lib/host-integration.cjs +13 -1
  81. package/gsd-core/bin/lib/host-runtime-detection.cjs +134 -0
  82. package/gsd-core/bin/lib/init-command-router.cjs +83 -8
  83. package/gsd-core/bin/lib/init.cjs +1325 -169
  84. package/gsd-core/bin/lib/install-effort-resolver.cjs +73 -30
  85. package/gsd-core/bin/lib/install-engine.cjs +805 -264
  86. package/gsd-core/bin/lib/install-fs-adapter.cjs +262 -0
  87. package/gsd-core/bin/lib/install-model-override-resolver.cjs +203 -0
  88. package/gsd-core/bin/lib/install-profiles.cjs +160 -57
  89. package/gsd-core/bin/lib/install-scope.cjs +270 -0
  90. package/gsd-core/bin/lib/install-shadow-report.cjs +385 -0
  91. package/gsd-core/bin/lib/installed-surface-resolver.cjs +381 -0
  92. package/gsd-core/bin/lib/installer-migration-authoring.cjs +3 -1
  93. package/gsd-core/bin/lib/installer-migration-report.cjs +4 -0
  94. package/gsd-core/bin/lib/installer-migrations/007-retire-config-root-commonjs-marker.cjs +149 -0
  95. package/gsd-core/bin/lib/installer-migrations/008-cursor-retire-commands-surface.cjs +55 -0
  96. package/gsd-core/bin/lib/installer-migrations/009-pi-retire-reserved-hooks-dir.cjs +199 -0
  97. package/gsd-core/bin/lib/installer-migrations.cjs +206 -13
  98. package/gsd-core/bin/lib/io.cjs +38 -3
  99. package/gsd-core/bin/lib/markdown-sectionizer.cjs +8 -1
  100. package/gsd-core/bin/lib/markdown-table.cjs +133 -20
  101. package/gsd-core/bin/lib/mcp-catalog.cjs +518 -0
  102. package/gsd-core/bin/lib/mcp-server.cjs +135 -3
  103. package/gsd-core/bin/lib/milestone-lock.cjs +248 -0
  104. package/gsd-core/bin/lib/milestone.cjs +821 -109
  105. package/gsd-core/bin/lib/model-catalog.cjs +59 -1
  106. package/gsd-core/bin/lib/model-resolver.cjs +183 -40
  107. package/gsd-core/bin/lib/normalize-test-command.cjs +1 -1
  108. package/gsd-core/bin/lib/pattern.cjs +122 -0
  109. package/gsd-core/bin/lib/phase-estimation.cjs +1 -1
  110. package/gsd-core/bin/lib/phase-id.cjs +507 -36
  111. package/gsd-core/bin/lib/phase-lifecycle.cjs +28 -3
  112. package/gsd-core/bin/lib/phase-locator.cjs +258 -58
  113. package/gsd-core/bin/lib/phase.cjs +891 -156
  114. package/gsd-core/bin/lib/plan-dependency-graph.cjs +303 -0
  115. package/gsd-core/bin/lib/plan-drift-guard.cjs +120 -0
  116. package/gsd-core/bin/lib/plan-scan.cjs +86 -2
  117. package/gsd-core/bin/lib/planning-scope.cjs +31 -0
  118. package/gsd-core/bin/lib/planning-snapshot.cjs +890 -0
  119. package/gsd-core/bin/lib/planning-workspace.cjs +60 -6
  120. package/gsd-core/bin/lib/probe-core.cjs +1 -1
  121. package/gsd-core/bin/lib/profile-output.cjs +1 -1
  122. package/gsd-core/bin/lib/prompt-budget.cjs +128 -165
  123. package/gsd-core/bin/lib/refactor-trigger-command-router.cjs +740 -0
  124. package/gsd-core/bin/lib/retired-artifact-cleanup.cjs +85 -0
  125. package/gsd-core/bin/lib/review-lane-descriptor.cjs +108 -0
  126. package/gsd-core/bin/lib/review-lane-invocation.cjs +30 -0
  127. package/gsd-core/bin/lib/review-lane-runner.cjs +447 -68
  128. package/gsd-core/bin/lib/review-reviewer-selection.cjs +13 -18
  129. package/gsd-core/bin/lib/roadmap-command-router.cjs +76 -9
  130. package/gsd-core/bin/lib/roadmap-parser.cjs +1035 -194
  131. package/gsd-core/bin/lib/roadmap-upgrade.cjs +37 -10
  132. package/gsd-core/bin/lib/roadmap.cjs +405 -84
  133. package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +795 -100
  134. package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +14 -2
  135. package/gsd-core/bin/lib/runtime-artifact-layout.cjs +440 -57
  136. package/gsd-core/bin/lib/runtime-config-adapter-registry.cjs +3 -2
  137. package/gsd-core/bin/lib/runtime-homes.cjs +220 -41
  138. package/gsd-core/bin/lib/runtime-hooks-surface.cjs +220 -44
  139. package/gsd-core/bin/lib/runtime-name-policy.cjs +3 -1
  140. package/gsd-core/bin/lib/runtime-slash.cjs +27 -9
  141. package/gsd-core/bin/lib/section-manifest.cjs +209 -0
  142. package/gsd-core/bin/lib/security.cjs +104 -5
  143. package/gsd-core/bin/lib/shell-command-projection.cjs +388 -30
  144. package/gsd-core/bin/lib/smart-entry.cjs +154 -22
  145. package/gsd-core/bin/lib/state-command-router.cjs +5 -1
  146. package/gsd-core/bin/lib/state-document.cjs +152 -8
  147. package/gsd-core/bin/lib/state-transition.cjs +424 -105
  148. package/gsd-core/bin/lib/state.cjs +1927 -401
  149. package/gsd-core/bin/lib/surface.cjs +35 -10
  150. package/gsd-core/bin/lib/text-lines.cjs +80 -0
  151. package/gsd-core/bin/lib/token-scanner.cjs +76 -0
  152. package/gsd-core/bin/lib/uat-predicate.cjs +20 -4
  153. package/gsd-core/bin/lib/uat.cjs +706 -64
  154. package/gsd-core/bin/lib/ui-frontend-evidence.cjs +157 -0
  155. package/gsd-core/bin/lib/ui-safety-gate.cjs +14 -5
  156. package/gsd-core/bin/lib/unusable-input.cjs +33 -0
  157. package/gsd-core/bin/lib/update-context.cjs +8 -2
  158. package/gsd-core/bin/lib/user-artifact-staging.cjs +705 -0
  159. package/gsd-core/bin/lib/validate.cjs +20 -6
  160. package/gsd-core/bin/lib/vendor/README.md +37 -0
  161. package/gsd-core/bin/lib/vendor/re2js.cjs +6480 -0
  162. package/gsd-core/bin/lib/vendor/re2js.d.cts +938 -0
  163. package/gsd-core/bin/lib/verification-command-router.cjs +2 -1
  164. package/gsd-core/bin/lib/verification.cjs +287 -20
  165. package/gsd-core/bin/lib/verify.cjs +368 -880
  166. package/gsd-core/bin/lib/workflow-fragments.cjs +557 -0
  167. package/gsd-core/bin/lib/workstream-inventory-builder.cjs +203 -19
  168. package/gsd-core/bin/lib/workstream-inventory.cjs +576 -31
  169. package/gsd-core/bin/lib/workstream.cjs +8 -2
  170. package/gsd-core/bin/lib/worktree-base-ref.cjs +50 -6
  171. package/gsd-core/bin/lib/worktree-safety.cjs +450 -125
  172. package/gsd-core/bin/shared/config-defaults.manifest.json +1 -0
  173. package/gsd-core/bin/shared/config-schema.manifest.json +9 -1
  174. package/gsd-core/references/agent-contracts.md +43 -26
  175. package/gsd-core/references/artifact-types.md +10 -3
  176. package/gsd-core/references/autonomous-ui-design-contract.md +42 -0
  177. package/gsd-core/references/checkpoints.md +2 -2
  178. package/gsd-core/references/context-budget.md +1 -1
  179. package/gsd-core/references/debugger-techniques.md +255 -0
  180. package/gsd-core/references/dispatch-isolation-gate.md +138 -0
  181. package/gsd-core/references/doc-conflict-engine.md +1 -1
  182. package/gsd-core/references/execute-mvp-tdd.md +3 -3
  183. package/gsd-core/references/execute-phase-between-wave-reset.md +6 -2
  184. package/gsd-core/references/execute-phase-context-guard.md +1 -1
  185. package/gsd-core/references/execute-phase-response-language.md +1 -1
  186. package/gsd-core/references/execute-phase-wave-guard.md +6 -2
  187. package/gsd-core/references/gate-prompts.md +1 -1
  188. package/gsd-core/references/git-planning-commit.md +2 -1
  189. package/gsd-core/references/loop-hook-dispatch.md +39 -2
  190. package/gsd-core/references/model-profiles.md +12 -4
  191. package/gsd-core/references/mvp-concepts.md +9 -9
  192. package/gsd-core/references/planner-guidance.md +3 -9
  193. package/gsd-core/references/planner-preconditions.md +1 -1
  194. package/gsd-core/references/planner-reviews.md +1 -1
  195. package/gsd-core/references/planning-config.md +8 -6
  196. package/gsd-core/references/research-documentation-lookup.md +5 -3
  197. package/gsd-core/references/revision-loop.md +1 -1
  198. package/gsd-core/references/specless-probe-fallback.md +8 -7
  199. package/gsd-core/references/universal-anti-patterns.md +3 -3
  200. package/gsd-core/references/verifier-phase-gates.md +192 -0
  201. package/gsd-core/references/verifier-wiring-patterns.md +100 -0
  202. package/gsd-core/references/verify-mvp-mode.md +1 -1
  203. package/gsd-core/references/workstream-flag.md +22 -6
  204. package/gsd-core/references/worktree-branch-check.md +2 -2
  205. package/gsd-core/templates/discussion-log.md +1 -1
  206. package/gsd-core/templates/phase-prompt.md +2 -4
  207. package/gsd-core/templates/state.md +4 -4
  208. package/gsd-core/templates/summary-complex.md +2 -0
  209. package/gsd-core/templates/summary-minimal.md +2 -0
  210. package/gsd-core/templates/summary-standard.md +2 -0
  211. package/gsd-core/templates/summary.md +2 -0
  212. package/gsd-core/templates/verification-report.md +9 -1
  213. package/gsd-core/workflows/ai-integration-phase.md +9 -11
  214. package/gsd-core/workflows/audit-milestone.md +3 -0
  215. package/gsd-core/workflows/autonomous/steps/converge-banner.md +1 -0
  216. package/gsd-core/workflows/autonomous/steps/converge-dispatch-bg.md +11 -0
  217. package/gsd-core/workflows/autonomous/steps/converge-dispatch-inline.md +7 -0
  218. package/gsd-core/workflows/autonomous/steps/converge-fail-fast.md +21 -0
  219. package/gsd-core/workflows/autonomous/steps/converge-loop.md +7 -0
  220. package/gsd-core/workflows/autonomous.md +33 -70
  221. package/gsd-core/workflows/cleanup.md +62 -3
  222. package/gsd-core/workflows/code-review/steps/dispatch-fix.md +39 -0
  223. package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +93 -0
  224. package/gsd-core/workflows/code-review-fix.md +37 -10
  225. package/gsd-core/workflows/code-review.md +74 -166
  226. package/gsd-core/workflows/complete-milestone/steps/git-tag.md +29 -0
  227. package/gsd-core/workflows/complete-milestone.md +160 -95
  228. package/gsd-core/workflows/debug.md +16 -17
  229. package/gsd-core/workflows/diagnose-issues.md +56 -8
  230. package/gsd-core/workflows/discuss-phase/modes/chain.md +2 -1
  231. package/gsd-core/workflows/discuss-phase/modes/default.md +1 -1
  232. package/gsd-core/workflows/discuss-phase-assumptions/steps/auto-advance-dispatch.md +15 -0
  233. package/gsd-core/workflows/discuss-phase-assumptions.md +7 -17
  234. package/gsd-core/workflows/docs-update/steps/dispatch-monorepo-packages.md +51 -0
  235. package/gsd-core/workflows/docs-update.md +8 -51
  236. package/gsd-core/workflows/edit-phase.md +26 -1
  237. package/gsd-core/workflows/eval-review.md +3 -5
  238. package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +64 -7
  239. package/gsd-core/workflows/execute-phase/steps/gap-closure-artifacts.md +50 -0
  240. package/gsd-core/workflows/execute-phase/steps/partial-wave.md +31 -0
  241. package/gsd-core/workflows/execute-phase/steps/per-plan-executor-routing.md +77 -0
  242. package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +21 -0
  243. package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +42 -0
  244. package/gsd-core/workflows/execute-phase/steps/regression-gate.md +43 -37
  245. package/gsd-core/workflows/execute-phase.md +103 -187
  246. package/gsd-core/workflows/execute-plan.md +36 -4
  247. package/gsd-core/workflows/explore.md +131 -4
  248. package/gsd-core/workflows/fast.md +10 -2
  249. package/gsd-core/workflows/health.md +73 -4
  250. package/gsd-core/workflows/help/modes/full.md +6 -1
  251. package/gsd-core/workflows/import.md +4 -4
  252. package/gsd-core/workflows/ingest-docs.md +7 -6
  253. package/gsd-core/workflows/mvp-phase.md +6 -3
  254. package/gsd-core/workflows/new-milestone/steps/project-md-milestone-write.md +16 -0
  255. package/gsd-core/workflows/new-milestone/steps/reset-phase-safety.md +19 -0
  256. package/gsd-core/workflows/new-milestone.md +35 -47
  257. package/gsd-core/workflows/new-project/steps/auto-mode-config.md +176 -0
  258. package/gsd-core/workflows/new-project/steps/auto-mode-detection.md +32 -0
  259. package/gsd-core/workflows/new-project/steps/codebase-map-offer.md +18 -0
  260. package/gsd-core/workflows/new-project.md +27 -240
  261. package/gsd-core/workflows/next.md +12 -0
  262. package/gsd-core/workflows/plan-phase/steps/adr-ingest-express-path.md +15 -0
  263. package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +110 -0
  264. package/gsd-core/workflows/plan-phase/steps/prd-express-gate.md +8 -0
  265. package/gsd-core/workflows/plan-phase/steps/research-only-early-exit.md +17 -0
  266. package/gsd-core/workflows/plan-phase/steps/research-only-modifiers.md +16 -0
  267. package/gsd-core/workflows/plan-phase/steps/reviews-prerequisite.md +17 -0
  268. package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +149 -0
  269. package/gsd-core/workflows/plan-phase.md +89 -209
  270. package/gsd-core/workflows/plan-review-convergence.md +50 -2
  271. package/gsd-core/workflows/progress/steps/forensic-audit.md +125 -0
  272. package/gsd-core/workflows/progress/steps/mvp-display.md +18 -0
  273. package/gsd-core/workflows/progress.md +45 -159
  274. package/gsd-core/workflows/quick/steps/discussion-phase.md +124 -0
  275. package/gsd-core/workflows/quick/steps/plan-checker-loop.md +111 -0
  276. package/gsd-core/workflows/quick/steps/quick-verification.md +67 -0
  277. package/gsd-core/workflows/quick/steps/research-phase.md +72 -0
  278. package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +37 -0
  279. package/gsd-core/workflows/quick.md +55 -405
  280. package/gsd-core/workflows/resume-project.md +3 -0
  281. package/gsd-core/workflows/review/steps/reviewer-instances-note-1.md +4 -0
  282. package/gsd-core/workflows/review/steps/reviewer-instances-note-2.md +3 -0
  283. package/gsd-core/workflows/review.md +41 -13
  284. package/gsd-core/workflows/section-manifest.json +219 -0
  285. package/gsd-core/workflows/secure-phase.md +1 -1
  286. package/gsd-core/workflows/session-report.md +2 -1
  287. package/gsd-core/workflows/settings.md +66 -2
  288. package/gsd-core/workflows/ship.md +104 -44
  289. package/gsd-core/workflows/sketch.md +1 -1
  290. package/gsd-core/workflows/spec-phase.md +41 -20
  291. package/gsd-core/workflows/spike-wrap-up.md +20 -5
  292. package/gsd-core/workflows/spike.md +50 -16
  293. package/gsd-core/workflows/sync-skills.md +106 -13
  294. package/gsd-core/workflows/transition/steps/workstream-collision-check.md +17 -0
  295. package/gsd-core/workflows/transition.md +53 -31
  296. package/gsd-core/workflows/ui-phase.md +13 -12
  297. package/gsd-core/workflows/ui-review.md +2 -2
  298. package/gsd-core/workflows/update/steps/channel-banner.md +7 -0
  299. package/gsd-core/workflows/update.md +19 -8
  300. package/gsd-core/workflows/validate-phase.md +1 -1
  301. package/gsd-core/workflows/verify-work/steps/automated-ui-verification.md +36 -0
  302. package/gsd-core/workflows/verify-work/steps/mvp-uat-framing.md +21 -0
  303. package/gsd-core/workflows/verify-work.md +17 -65
  304. package/hooks/dist/gsd-agent-isolation-guard.js +517 -0
  305. package/hooks/dist/gsd-check-update-worker.js +64 -12
  306. package/hooks/dist/gsd-check-update.js +19 -1
  307. package/hooks/dist/gsd-cursor-pre-tool.js +0 -3
  308. package/hooks/dist/gsd-cursor-subagent-start.js +607 -26
  309. package/hooks/dist/gsd-cursor-subagent-stop.js +3 -2
  310. package/hooks/dist/gsd-prompt-guard.js +21 -20
  311. package/hooks/dist/gsd-read-injection-scanner.js +45 -24
  312. package/hooks/dist/gsd-statusline.js +90 -6
  313. package/hooks/dist/gsd-update-banner.js +22 -1
  314. package/hooks/dist/gsd-workflow-guard.js +134 -36
  315. package/hooks/dist/gsd-worktree-path-guard.js +2 -1
  316. package/hooks/dist/gsd-write-guard.js +359 -0
  317. package/hooks/dist/lib/git-cmd.js +92 -59
  318. package/hooks/dist/lib/injection-patterns.js +45 -0
  319. package/hooks/dist/lib/isolation-deny-reason.js +39 -0
  320. package/hooks/dist/lib/isolation-sentinel.js +277 -0
  321. package/hooks/dist/managed-hooks-registry.cjs +2 -0
  322. package/hooks/gsd-agent-isolation-guard.js +517 -0
  323. package/hooks/gsd-check-update-worker.js +64 -12
  324. package/hooks/gsd-check-update.js +19 -1
  325. package/hooks/gsd-cursor-pre-tool.js +0 -3
  326. package/hooks/gsd-cursor-subagent-start.js +607 -26
  327. package/hooks/gsd-cursor-subagent-stop.js +3 -2
  328. package/hooks/gsd-prompt-guard.js +21 -20
  329. package/hooks/gsd-read-injection-scanner.js +45 -24
  330. package/hooks/gsd-statusline.js +90 -6
  331. package/hooks/gsd-update-banner.js +22 -1
  332. package/hooks/gsd-workflow-guard.js +134 -36
  333. package/hooks/gsd-worktree-path-guard.js +2 -1
  334. package/hooks/gsd-write-guard.js +359 -0
  335. package/hooks/hooks.json +12 -0
  336. package/hooks/lib/git-cmd.js +92 -59
  337. package/hooks/lib/injection-patterns.js +45 -0
  338. package/hooks/lib/isolation-deny-reason.js +39 -0
  339. package/hooks/lib/isolation-sentinel.js +277 -0
  340. package/hooks/managed-hooks-registry.cjs +2 -0
  341. package/package.json +31 -10
  342. package/pi/gsd.cjs +71 -12
  343. package/scripts/baselines/planning-prompt-drift-baseline.json +4 -0
  344. package/scripts/baselines/planning-snapshot-bypass-baseline.json +12 -0
  345. package/scripts/baselines/unreachable-guard-drift-baseline.json +4 -0
  346. package/scripts/build-hooks.js +9 -0
  347. package/scripts/changeset/lint.cjs +68 -6
  348. package/scripts/changeset/serialize.cjs +5 -1
  349. package/scripts/check-alias-drift.cjs +7 -43
  350. package/scripts/check-contract-drift.cjs +297 -0
  351. package/scripts/ci-test-scope.cjs +19 -2
  352. package/scripts/command-contract-helpers.cjs +903 -1
  353. package/scripts/gen-adr-index.cjs +728 -38
  354. package/scripts/gen-capability-matrix.cjs +1 -1
  355. package/scripts/gen-capability-registry.cjs +3 -15
  356. package/scripts/gen-context-index.cjs +439 -0
  357. package/scripts/gen-health-docs.cjs +390 -0
  358. package/scripts/gen-inventory-manifest.cjs +150 -4
  359. package/scripts/gen-loop-host-contract.cjs +4 -24
  360. package/scripts/gen-prompt-budget-parity-corpus.cjs +645 -0
  361. package/scripts/gen-registry.cjs +3 -14
  362. package/scripts/gen-section-manifest.cjs +638 -0
  363. package/scripts/generate-package-identity.cjs +4 -2
  364. package/scripts/lib/alias-drift-families.cjs +46 -0
  365. package/scripts/lib/drift-scan.cjs +278 -0
  366. package/scripts/lint-allow-test-rule-refs.allowlist.json +15 -54
  367. package/scripts/lint-allow-test-rule-refs.effective-ceiling.json +4 -0
  368. package/scripts/lint-allow-test-rule-refs.unverified-ceiling.json +3 -0
  369. package/scripts/lint-canary-version-leak.cjs +73 -0
  370. package/scripts/lint-command-contract.cjs +96 -13
  371. package/scripts/lint-compiled-artifact-sync.cjs +6 -1
  372. package/scripts/lint-completion-predicate-drift.cjs +933 -0
  373. package/scripts/lint-completion-ratio-drift.cjs +214 -0
  374. package/scripts/lint-default-flip-documentation.cjs +193 -0
  375. package/scripts/lint-docs-command-form.cjs +195 -0
  376. package/scripts/lint-docs-required.cjs +9 -1
  377. package/scripts/lint-emitted-drift-ack.cjs +215 -20
  378. package/scripts/lint-eslint-glob-coverage.allowlist.json +34 -0
  379. package/scripts/lint-eslint-glob-coverage.cjs +340 -0
  380. package/scripts/lint-example-parser-parity.cjs +395 -0
  381. package/scripts/lint-frontmatter-scalar-broad-grep.cjs +237 -0
  382. package/scripts/lint-health-diagnostic-rule-table.cjs +404 -0
  383. package/scripts/lint-hooks-runtime-build-seam.cjs +262 -0
  384. package/scripts/lint-milestone-window-drift.cjs +468 -0
  385. package/scripts/lint-phase-enumeration-drift.cjs +479 -0
  386. package/scripts/lint-plan-count-drift.cjs +318 -0
  387. package/scripts/lint-planning-artifact-writer-drift.cjs +398 -0
  388. package/scripts/lint-planning-prompt-drift.cjs +434 -0
  389. package/scripts/lint-planning-snapshot-bypass-drift.cjs +544 -0
  390. package/scripts/lint-regression-test-names.cjs +15 -13
  391. package/scripts/lint-removed-but-needed.cjs +320 -0
  392. package/scripts/lint-state-field-drift.cjs +805 -0
  393. package/scripts/lint-state-write-path-drift.cjs +1045 -0
  394. package/scripts/lint-test-file-count.allowlist.json +40 -3
  395. package/scripts/lint-unreachable-guard-drift.cjs +843 -0
  396. package/scripts/lint-vendored-deps.cjs +124 -0
  397. package/scripts/mutation-matrix.cjs +13 -0
  398. package/scripts/pr-changed-files.cjs +63 -0
  399. package/scripts/pr-template-policy.cjs +14 -4
  400. package/scripts/prompt-injection-scan.sh +52 -6
  401. package/scripts/require-issue-link-policy.cjs +192 -0
  402. package/scripts/state-write-path-drift-baseline.json +19 -0
  403. package/scripts/sync-runtime-launcher.cjs +2 -4
  404. package/skills/gsd-autonomous/SKILL.md +0 -1
  405. package/skills/gsd-code-review/SKILL.md +1 -1
  406. package/skills/gsd-execute-phase/SKILL.md +1 -2
  407. package/skills/gsd-map-codebase/SKILL.md +1 -1
  408. package/skills/gsd-mempalace-capture/SKILL.md +2 -2
  409. package/skills/gsd-mempalace-recall/SKILL.md +1 -1
  410. package/skills/gsd-new-milestone/SKILL.md +2 -2
  411. package/skills/gsd-next/SKILL.md +0 -1
  412. package/skills/gsd-plan-phase/SKILL.md +1 -2
  413. package/skills/gsd-progress/SKILL.md +0 -1
  414. package/skills/gsd-quick/SKILL.md +1 -1
  415. package/skills/gsd-review-backlog/SKILL.md +2 -1
  416. package/skills/gsd-stats/SKILL.md +0 -1
  417. package/skills/gsd-verify-work/SKILL.md +1 -1
  418. package/vscode/package.json +1 -1
  419. package/gsd-core/workflows/discovery-phase.md +0 -298
  420. package/gsd-core/workflows/plan-milestone-gaps.md +0 -281
  421. package/gsd-core/workflows/verify-phase.md +0 -577
  422. package/scripts/affected-tests-lib.cjs +0 -554
  423. package/scripts/gen-emitted-baseline.cjs +0 -145
  424. package/scripts/lint-allow-test-rule-refs.cjs +0 -162
  425. package/scripts/run-affected-tests.cjs +0 -7
  426. package/scripts/run-tests.cjs +0 -1050
@@ -0,0 +1,431 @@
1
+ "use strict";
2
+ /**
3
+ * Health Diagnostic — frozen rule-table types, enums, and evaluator for
4
+ * `validate health` (Phase 11, #3309, ADR-3180 §8.2/§8.3/§8.5).
5
+ *
6
+ * Establishes the exact contract every extracted rule builds onto: the
7
+ * frozen `SEVERITY`/`REMEDY_ACTION`/`REMEDY_RISK` enums, the
8
+ * `Diagnostic`/`Remedy`/`Rule` shapes, the `RULES` container (the 32 rules
9
+ * extracted from `cmdValidateHealth`, `src/verify.cts:1616-2577`, are
10
+ * concatenated in from each rule-group file under
11
+ * `src/health-diagnostic-rules/`), the `evaluateRules` evaluator, and the
12
+ * `applyRepairs` `--repair`/`--backfill` dispatcher — whose per-action
13
+ * handlers are REAL here (ported behavior-preserving from
14
+ * `verify.cts:2405-2553`'s repair switch), not stubs.
15
+ *
16
+ * `applyRepairs` does not receive a `PlanningSnapshot` (its call-site
17
+ * signature, `(cwd, diagnostics, repair, backfill)`, is a locked contract —
18
+ * see `tests/health-diagnostic.test.cjs`) — so, like `cmdValidateHealth`
19
+ * itself before this migration, it performs its own bounded filesystem I/O
20
+ * to apply a repair. This is not a §8.1 rule 1 violation: that rule
21
+ * constrains a RULE's `check(snapshot)` signature (no ambient I/O), not the
22
+ * evaluator/dispatcher, which the design doc's "subject-surface gap" section
23
+ * already establishes performs I/O once, up front, on the rules' behalf.
24
+ *
25
+ * `PlanningSnapshot` is deliberately NOT re-exported as a type from
26
+ * `planning-snapshot.cts` here (see the design doc's "Known limits" and this
27
+ * phase's brief): `ReturnType<typeof buildPlanningSnapshot>` is used inline
28
+ * instead, via a type-only `import ... = require(...)` that is fully erased
29
+ * at compile time — zero changes to the already-shipped, already-tested
30
+ * `planning-snapshot.cts`.
31
+ *
32
+ * Design: .gsd/phase/refactor-3309-health-diagnostic-rule-table/40-design.md
33
+ * Test matrix: .gsd/phase/refactor-3309-health-diagnostic-rule-table/50-test-matrix.md
34
+ *
35
+ * ADR-457 build-at-publish: source in src/health-diagnostic.cts, compiled to
36
+ * gsd-core/bin/lib/health-diagnostic.cjs (gitignored).
37
+ */
38
+ var __importDefault = (this && this.__importDefault) || function (mod) {
39
+ return (mod && mod.__esModule) ? mod : { "default": mod };
40
+ };
41
+ const node_fs_1 = __importDefault(require("node:fs"));
42
+ const node_path_1 = __importDefault(require("node:path"));
43
+ // Runtime values (SEVERITY/REMEDY_ACTION/REMEDY_RISK) are needed here — not
44
+ // just types — for `applyRepairs`'s comparisons, so this is a normal
45
+ // (non type-only) `import ... = require(...)`. `health-diagnostic-types.cjs`
46
+ // is the leaf module these enums/types were extracted to, so that this file
47
+ // can `require()` every rule-group file below without a circular dependency
48
+ // (see that module's file-level comment for the full explanation).
49
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
50
+ const healthDiagnosticTypesMod = require("./health-diagnostic-types.cjs");
51
+ const { SEVERITY, REMEDY_ACTION, REMEDY_RISK } = healthDiagnosticTypesMod;
52
+ // ─── Rule table ─────────────────────────────────────────────────────────────
53
+ // Populated by concatenating each rule group's exported `RULES` array (design
54
+ // doc, "Rule table organization" section) — the 32 rule functions extracted
55
+ // from `cmdValidateHealth`, `src/verify.cts:1616-2577`.
56
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
57
+ const rootExistenceMod = require("./health-diagnostic-rules/root-existence.cjs");
58
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
59
+ const stateConsistencyMod = require("./health-diagnostic-rules/state-consistency.cjs");
60
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
61
+ const configValidationMod = require("./health-diagnostic-rules/config-validation.cjs");
62
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
63
+ const phaseStructureMod = require("./health-diagnostic-rules/phase-structure.cjs");
64
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
65
+ const agentInstallMod = require("./health-diagnostic-rules/agent-install.cjs");
66
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
67
+ const roadmapDiskConsistencyMod = require("./health-diagnostic-rules/roadmap-disk-consistency.cjs");
68
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
69
+ const worktreeHealthMod = require("./health-diagnostic-rules/worktree-health.cjs");
70
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
71
+ const milestoneArchiveHygieneMod = require("./health-diagnostic-rules/milestone-archive-hygiene.cjs");
72
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
73
+ const consistencyMod = require("./health-diagnostic-rules/consistency.cjs");
74
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
75
+ const installSurfaceShadowingMod = require("./health-diagnostic-rules/install-surface-shadowing.cjs");
76
+ const RULES = [
77
+ ...rootExistenceMod.RULES,
78
+ ...stateConsistencyMod.RULES,
79
+ ...configValidationMod.RULES,
80
+ ...phaseStructureMod.RULES,
81
+ ...agentInstallMod.RULES,
82
+ ...roadmapDiskConsistencyMod.RULES,
83
+ ...worktreeHealthMod.RULES,
84
+ ...milestoneArchiveHygieneMod.RULES,
85
+ ...installSurfaceShadowingMod.RULES,
86
+ ];
87
+ /**
88
+ * `validate.consistency`'s own rule set (Phase 12, #3310, ADR-3180 §8.4,
89
+ * design doc "Which rules run where") — W006/W007 REUSED (the exact same
90
+ * `Rule` objects `RULES` above already carries, not new copies) plus the
91
+ * four new C0NN rules from `consistency.cts`. Deliberately NOT the full
92
+ * `RULES` table: running `validate.health`'s config/state/worktree rules
93
+ * under `validate.consistency` would be scope creep the issue never asked
94
+ * for.
95
+ */
96
+ const CONSISTENCY_RULES = [
97
+ ...roadmapDiskConsistencyMod.RULES.filter((r) => ['W006', 'W007'].includes(r.code)),
98
+ ...consistencyMod.RULES,
99
+ ];
100
+ // ─── Repair-handler runtime dependencies ───────────────────────────────────
101
+ //
102
+ // Same owners `cmdValidateHealth`'s pre-migration repair switch used
103
+ // (`verify.cts:2405-2553`) — ported verbatim, not reinvented.
104
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
105
+ const planningWorkspaceMod = require("./planning-workspace.cjs");
106
+ const { planningRoot, planningDir } = planningWorkspaceMod;
107
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
108
+ const configLoaderMod = require("./config-loader.cjs");
109
+ const { CONFIG_DEFAULTS } = configLoaderMod;
110
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
111
+ const roadmapParserMod = require("./roadmap-parser.cjs");
112
+ const { getMilestoneInfo } = roadmapParserMod;
113
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
114
+ const stateMod = require("./state.cjs");
115
+ const { writeStateMd } = stateMod;
116
+ const clock_cjs_1 = require("./clock.cjs");
117
+ const shell_command_projection_cjs_1 = require("./shell-command-projection.cjs");
118
+ const runtime_slash_cjs_1 = require("./runtime-slash.cjs");
119
+ // ─── Evaluator ──────────────────────────────────────────────────────────────
120
+ /**
121
+ * Evaluate an explicit `rules` array against `snapshot`, throwing if any two
122
+ * entries share a `code` (defense in depth beside the static lint guard,
123
+ * §8.2 rule 1, `scripts/lint-health-diagnostic-rule-table.cjs`). Separated
124
+ * from `evaluateRules` so the duplicate-code guard is unit-testable against
125
+ * a small, locally-constructed fake rule array, independent of the real
126
+ * `RULES` table.
127
+ */
128
+ function evaluateRuleTable(rules, snapshot) {
129
+ const seen = new Set();
130
+ for (const rule of rules) {
131
+ if (seen.has(rule.code)) {
132
+ throw new Error(`health-diagnostic: duplicate rule code "${rule.code}" in rule table`);
133
+ }
134
+ seen.add(rule.code);
135
+ }
136
+ return rules.flatMap((rule) => rule.check(snapshot));
137
+ }
138
+ /**
139
+ * Evaluate every rule in `RULES` against `snapshot`, flattening each rule's
140
+ * `Diagnostic[]` into one array.
141
+ */
142
+ function evaluateRules(snapshot) {
143
+ return evaluateRuleTable(RULES, snapshot);
144
+ }
145
+ /**
146
+ * Evaluate `CONSISTENCY_RULES` (W006/W007 + C001-C004) against `snapshot` —
147
+ * `validate.consistency`'s evaluator entry point, mirroring `evaluateRules`
148
+ * exactly but over the smaller, command-specific rule subset.
149
+ */
150
+ function evaluateConsistencyRules(snapshot) {
151
+ return evaluateRuleTable(CONSISTENCY_RULES, snapshot);
152
+ }
153
+ /**
154
+ * Derive every filesystem path a repair handler needs, from `cwd` alone —
155
+ * exactly how `cmdValidateHealth` derived them pre-migration
156
+ * (`verify.cts:1644-1652`/`2301-2302`). `config.json`/`MILESTONES.md`/
157
+ * `milestones/` are root-scoped (`planningRoot`); `STATE.md` is
158
+ * workstream-scoped (`planningDir`) — the same root-vs-workstream split
159
+ * `buildConfigField`/`buildStateFields` (`planning-snapshot.cts`) already
160
+ * document for the read side.
161
+ */
162
+ function repairPaths(cwd) {
163
+ const rootBase = planningRoot(cwd);
164
+ const wsBase = planningDir(cwd);
165
+ return {
166
+ rootBase,
167
+ configPath: node_path_1.default.join(rootBase, 'config.json'),
168
+ statePath: node_path_1.default.join(wsBase, 'STATE.md'),
169
+ milestonesPath: node_path_1.default.join(rootBase, 'MILESTONES.md'),
170
+ milestonesArchiveDir: node_path_1.default.join(rootBase, 'milestones'),
171
+ };
172
+ }
173
+ /** `verify.cts:2413-2429`'s default config.json payload, ported verbatim. */
174
+ function defaultConfigPayload() {
175
+ return {
176
+ model_profile: CONFIG_DEFAULTS.model_profile,
177
+ commit_docs: CONFIG_DEFAULTS.commit_docs,
178
+ search_gitignored: CONFIG_DEFAULTS.search_gitignored,
179
+ branching_strategy: CONFIG_DEFAULTS.branching_strategy,
180
+ phase_branch_template: CONFIG_DEFAULTS.phase_branch_template,
181
+ milestone_branch_template: CONFIG_DEFAULTS.milestone_branch_template,
182
+ quick_branch_template: CONFIG_DEFAULTS.quick_branch_template,
183
+ workflow: {
184
+ research: CONFIG_DEFAULTS.research,
185
+ plan_check: CONFIG_DEFAULTS.plan_checker,
186
+ verifier: CONFIG_DEFAULTS.verifier,
187
+ nyquist_validation: CONFIG_DEFAULTS.nyquist_validation,
188
+ },
189
+ parallelization: CONFIG_DEFAULTS.parallelization,
190
+ brave_search: CONFIG_DEFAULTS.brave_search,
191
+ };
192
+ }
193
+ /**
194
+ * `verify.cts:2301-2335`'s W018 archived-vs-documented-versions diff,
195
+ * relocated verbatim (same two regexes, same two-file read) so
196
+ * `backfillMilestones` can recompute exactly which versions are missing
197
+ * without a `PlanningSnapshot` (`applyRepairs` is not a `Rule` and is not
198
+ * handed one — see this file's header comment). This is the same
199
+ * derivation `buildMilestoneArchiveStatusField`
200
+ * (`src/planning-snapshot.cts`) already performs for the W018 RULE's read
201
+ * side; recomputed here, not re-invented, because the rule's own
202
+ * `Diagnostic.remedy.args` carries no version list (confirmed by direct
203
+ * read of `src/health-diagnostic-rules/milestone-archive-hygiene.cts`).
204
+ */
205
+ function computeMissingMilestoneVersions(milestonesArchiveDir, milestonesPath) {
206
+ let archivedVersions = [];
207
+ try {
208
+ if (node_fs_1.default.existsSync(milestonesArchiveDir)) {
209
+ const archiveFiles = node_fs_1.default.readdirSync(milestonesArchiveDir);
210
+ archivedVersions = archiveFiles
211
+ .map((f) => f.match(/^(v\d+\.\d+(?:\.\d+)?)-ROADMAP\.md$/))
212
+ .filter((m) => m !== null)
213
+ .map((m) => m[1]);
214
+ }
215
+ }
216
+ catch {
217
+ /* intentionally empty — mirrors the original's advisory try/catch */
218
+ }
219
+ let documentedVersions = [];
220
+ try {
221
+ if (node_fs_1.default.existsSync(milestonesPath)) {
222
+ const registryContent = node_fs_1.default.readFileSync(milestonesPath, 'utf-8');
223
+ documentedVersions = [...registryContent.matchAll(/^##\s+(v\d+\.\d+(?:\.\d+)?)/gm)].map((m) => m[1]);
224
+ }
225
+ }
226
+ catch {
227
+ /* intentionally empty */
228
+ }
229
+ const documented = new Set(documentedVersions);
230
+ return archivedVersions.filter((v) => !documented.has(v));
231
+ }
232
+ /**
233
+ * Execute exactly one real repair action, ported behavior-preserving from
234
+ * `verify.cts:2405-2553`'s `switch (repair)`. Throws are the caller's
235
+ * responsibility to catch (mirrors the original's per-action try/catch
236
+ * shape, collapsed to one seam here since every case now shares one
237
+ * caller).
238
+ */
239
+ function runRepairAction(cwd, action, paths) {
240
+ const { rootBase, configPath, statePath, milestonesPath, milestonesArchiveDir } = paths;
241
+ switch (action) {
242
+ case REMEDY_ACTION.CREATE_CONFIG:
243
+ case REMEDY_ACTION.RESET_CONFIG: {
244
+ (0, shell_command_projection_cjs_1.platformWriteSync)(configPath, JSON.stringify(defaultConfigPayload(), null, 2));
245
+ return { success: true, path: 'config.json' };
246
+ }
247
+ case REMEDY_ACTION.REGENERATE_STATE: {
248
+ const extraDetails = [];
249
+ if (node_fs_1.default.existsSync(statePath)) {
250
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);
251
+ const backupPath = `${statePath}.bak-${timestamp}`;
252
+ node_fs_1.default.copyFileSync(statePath, backupPath);
253
+ extraDetails.push({ action: 'backupState', success: true, path: backupPath });
254
+ }
255
+ const milestone = getMilestoneInfo(cwd).value;
256
+ const projectRef = node_path_1.default
257
+ .relative(cwd, node_path_1.default.join(rootBase, 'PROJECT.md'))
258
+ .split(node_path_1.default.sep)
259
+ .join('/');
260
+ const slashRuntime = (0, runtime_slash_cjs_1.resolveRuntime)(cwd);
261
+ const slash = (name) => (0, runtime_slash_cjs_1.formatGsdSlash)(name, slashRuntime);
262
+ let stateContent = `# Session State\n\n`;
263
+ stateContent += `## Project Reference\n\n`;
264
+ stateContent += `See: ${projectRef}\n\n`;
265
+ stateContent += `## Position\n\n`;
266
+ stateContent += `**Milestone:** ${milestone?.version ?? ''} ${milestone?.name ?? ''}\n`;
267
+ stateContent += `**Current phase:** (determining...)\n`;
268
+ stateContent += `**Status:** Resuming\n\n`;
269
+ stateContent += `## Session Log\n\n`;
270
+ stateContent += `- ${clock_cjs_1.realClock.localToday()}: STATE.md regenerated by ${slash('health')} --repair\n`;
271
+ writeStateMd(statePath, stateContent, cwd);
272
+ return { success: true, path: 'STATE.md', extraDetails };
273
+ }
274
+ case REMEDY_ACTION.ADD_NYQUIST_KEY:
275
+ case REMEDY_ACTION.ADD_AI_INTEGRATION_PHASE_KEY: {
276
+ const key = action === REMEDY_ACTION.ADD_NYQUIST_KEY ? 'nyquist_validation' : 'ai_integration_phase';
277
+ const configRaw = node_fs_1.default.readFileSync(configPath, 'utf-8');
278
+ const configParsed = JSON.parse(configRaw);
279
+ if (!configParsed['workflow'])
280
+ configParsed['workflow'] = {};
281
+ const wf = configParsed['workflow'];
282
+ if (wf[key] === undefined) {
283
+ wf[key] = true;
284
+ (0, shell_command_projection_cjs_1.platformWriteSync)(configPath, JSON.stringify(configParsed, null, 2));
285
+ }
286
+ return { success: true, path: 'config.json' };
287
+ }
288
+ case REMEDY_ACTION.BACKFILL_MILESTONES: {
289
+ const missing = computeMissingMilestoneVersions(milestonesArchiveDir, milestonesPath);
290
+ const today = clock_cjs_1.realClock.localToday();
291
+ const slashRuntime = (0, runtime_slash_cjs_1.resolveRuntime)(cwd);
292
+ const slash = (name) => (0, runtime_slash_cjs_1.formatGsdSlash)(name, slashRuntime);
293
+ let backfilled = 0;
294
+ for (const ver of missing) {
295
+ try {
296
+ const snapshotPath = node_path_1.default.join(milestonesArchiveDir, `${ver}-ROADMAP.md`);
297
+ const snapshot = (0, shell_command_projection_cjs_1.platformReadSync)(snapshotPath);
298
+ const titleMatch = snapshot && snapshot.match(/^#\s+(.+)$/m);
299
+ const milestoneName = titleMatch
300
+ ? titleMatch[1].replace(/^Milestone\s+/i, '').replace(/^v[\d.]+\s*/, '').trim()
301
+ : ver;
302
+ const entry = `## ${ver}${milestoneName && milestoneName !== ver ? ` ${milestoneName}` : ''} (Backfilled: ${today})\n\n**Note:** Synthesized from archive snapshot by \`${slash('health')} --backfill\`. Original completion date unknown.\n\n---\n\n`;
303
+ const milestonesContent = node_fs_1.default.existsSync(milestonesPath)
304
+ ? node_fs_1.default.readFileSync(milestonesPath, 'utf-8')
305
+ : '';
306
+ if (!milestonesContent.trim()) {
307
+ (0, shell_command_projection_cjs_1.platformWriteSync)(milestonesPath, `# Milestones\n\n${entry}`);
308
+ }
309
+ else {
310
+ const headerMatch = milestonesContent.match(/^(#{1,3}\s+[^\n]*\n\n?)/);
311
+ if (headerMatch) {
312
+ const header = headerMatch[1];
313
+ const rest = milestonesContent.slice(header.length);
314
+ (0, shell_command_projection_cjs_1.platformWriteSync)(milestonesPath, header + entry + rest);
315
+ }
316
+ else {
317
+ (0, shell_command_projection_cjs_1.platformWriteSync)(milestonesPath, entry + milestonesContent);
318
+ }
319
+ }
320
+ backfilled++;
321
+ }
322
+ catch {
323
+ /* intentionally empty — partial backfill is acceptable */
324
+ }
325
+ }
326
+ return { success: true, detail: `Backfilled ${backfilled} milestone(s) into MILESTONES.md` };
327
+ }
328
+ default:
329
+ return { success: false, error: `no repair handler registered for action "${action}"` };
330
+ }
331
+ }
332
+ /**
333
+ * `--repair`/`--backfill` dispatcher (design doc "`--repair` behavior
334
+ * change" section; §8.3 rule 3). For each diagnostic whose remedy is not
335
+ * `ADVISE`:
336
+ *
337
+ * - Not requested — `repair` is false, and for `backfillMilestones`
338
+ * specifically `backfill` is also false (mirrors `cmdValidateHealth`'s
339
+ * existing `backfillMilestones` gate, `verify.cts:2504`:
340
+ * `if (!options['backfill'] && !options['repair']) break;`) — skipped
341
+ * entirely, recorded in neither `applied` nor `refused`.
342
+ * - Requested and `remedy.risk === DESTRUCTIVE` — pushed onto `refused`,
343
+ * handler never invoked. This is the §8.3 rule 3 breaking-change
344
+ * enforcement point: a DESTRUCTIVE remedy is describable but is never
345
+ * applied by `--repair`. A `details` row is still recorded, so the
346
+ * refusal is VISIBLE in `cmdValidateHealth`'s `repairs_performed` output,
347
+ * not silently dropped.
348
+ * - Requested and `remedy.risk === NONE` — the real handler is invoked,
349
+ * pushed onto `applied`.
350
+ *
351
+ * `applied`/`refused` are unchanged in shape from the pre-existing skeleton
352
+ * (locked by `tests/health-diagnostic.test.cjs`, rows 11-12): arrays of
353
+ * diagnostic `code`s. `details` is ADDITIVE — every real action maps 1:1 to
354
+ * exactly one code in this rule table (confirmed: no `REMEDY_ACTION` other
355
+ * than `ADVISE` is used by more than one rule), so `cmdValidateHealth` can
356
+ * rebuild the legacy action-keyed `repairs_performed` shape directly from
357
+ * it.
358
+ */
359
+ function applyRepairs(cwd, diagnostics, repair, backfill) {
360
+ const applied = [];
361
+ const refused = [];
362
+ const details = [];
363
+ const paths = repairPaths(cwd);
364
+ for (const diagnostic of diagnostics) {
365
+ const { remedy, code } = diagnostic;
366
+ if (remedy.action === REMEDY_ACTION.ADVISE)
367
+ continue;
368
+ const requested = remedy.action === REMEDY_ACTION.BACKFILL_MILESTONES ? repair || backfill : repair;
369
+ if (!requested)
370
+ continue;
371
+ if (remedy.risk === REMEDY_RISK.DESTRUCTIVE) {
372
+ refused.push(code);
373
+ details.push({
374
+ code,
375
+ action: remedy.action,
376
+ success: false,
377
+ error: `refused: '${remedy.action}' is a destructive remedy and is not auto-applied by --repair`,
378
+ });
379
+ continue;
380
+ }
381
+ try {
382
+ const outcome = runRepairAction(cwd, remedy.action, paths);
383
+ if (outcome.extraDetails) {
384
+ for (const extra of outcome.extraDetails) {
385
+ details.push({ code, action: extra.action, success: extra.success, ...(extra.path ? { path: extra.path } : {}) });
386
+ }
387
+ }
388
+ details.push({
389
+ code,
390
+ action: remedy.action,
391
+ success: outcome.success,
392
+ ...(outcome.path ? { path: outcome.path } : {}),
393
+ ...(outcome.detail ? { detail: outcome.detail } : {}),
394
+ ...(outcome.error ? { error: outcome.error } : {}),
395
+ });
396
+ // `applied` means "the repair actually succeeded", not "was attempted"
397
+ // — a handler that returns `{success: false}` (or throws, caught
398
+ // below) is recorded in `details` with its failure, but must not be
399
+ // reported as applied. `refused` is reserved for the DESTRUCTIVE-risk
400
+ // gate above; a failed attempt is neither applied nor refused.
401
+ if (outcome.success)
402
+ applied.push(code);
403
+ }
404
+ catch (err) {
405
+ details.push({
406
+ code,
407
+ action: remedy.action,
408
+ success: false,
409
+ error: err instanceof Error ? err.message : String(err),
410
+ });
411
+ }
412
+ }
413
+ return { applied, refused, details };
414
+ }
415
+ // ─── Exports ────────────────────────────────────────────────────────────────
416
+ const healthDiagnostic = {
417
+ SEVERITY,
418
+ REMEDY_ACTION,
419
+ REMEDY_RISK,
420
+ RULES,
421
+ evaluateRules,
422
+ // Additive beyond the phase's required-exports list — exposed so the
423
+ // duplicate-code guard (row 13) is directly unit-testable against a fake
424
+ // rule array without mutating the real, still-empty `RULES` export.
425
+ evaluateRuleTable,
426
+ applyRepairs,
427
+ // Phase 12 (#3310) — `validate.consistency`'s own rule subset + evaluator.
428
+ CONSISTENCY_RULES,
429
+ evaluateConsistencyRules,
430
+ };
431
+ module.exports = healthDiagnostic;
@@ -464,8 +464,20 @@ function negotiateHostCapabilities(host, engine = DEFAULT_ENGINE) {
464
464
  function shouldFlattenDispatch(dispatch) {
465
465
  if (!dispatch || typeof dispatch !== 'object')
466
466
  return true;
467
+ // Can background at all: both background flags must be explicitly true.
467
468
  const canBackground = dispatch.background === true && dispatch.backgroundDispatch === true;
468
- return !canBackground;
469
+ if (!canBackground)
470
+ return true;
471
+ // #2939: can background a NESTING orchestrator with room to delegate. A depth budget of 1
472
+ // is consumed by the backgrounded orchestrator itself; it needs > 1 (or unbounded, maxDepth < 0)
473
+ // to host a delegated leaf at depth 2. Non-finite/missing maxDepth fails closed (no budget →
474
+ // flatten), mirroring degradationFor's treatment of non-finite depth as 0.
475
+ const canNest = dispatch.nested === true && dispatch.subagentToolkit === 'full';
476
+ if (!canNest)
477
+ return true;
478
+ const depth = typeof dispatch.maxDepth === 'number' && Number.isFinite(dispatch.maxDepth) ? dispatch.maxDepth : 0;
479
+ const depthSufficient = depth < 0 || depth > 1;
480
+ return !depthSufficient;
469
481
  }
470
482
  // ---------------------------------------------------------------------------
471
483
  // resolveDispatchType — ADR-1239 / epic #2505 Phase 4 (Option A)
@@ -0,0 +1,134 @@
1
+ "use strict";
2
+ /**
3
+ * Host runtime detection — ADR-2313 Phase 5 (#3245, folded from #2320).
4
+ *
5
+ * `init`'s reported `agent_runtime` was hardcoding `claude` even when run
6
+ * inside a Codex session, because resolveRuntime's ladder only checks the
7
+ * explicit `GSD_RUNTIME` env var and `.planning/config.json`'s `runtime`
8
+ * field — there was no fallback that looked at the actual host process.
9
+ *
10
+ * This module adds a host-detection rung strictly BELOW those two explicit
11
+ * sources: it only runs when neither `GSD_RUNTIME` nor config `runtime` is
12
+ * set. It never writes anything (#2297 — no shared-defaults poisoning: this
13
+ * module never touches .planning/config.json or any other file). It never
14
+ * shells out, so there is no subprocess to time-bound — detection is pure
15
+ * env-var and existence-check inspection.
16
+ */
17
+ var __importDefault = (this && this.__importDefault) || function (mod) {
18
+ return (mod && mod.__esModule) ? mod : { "default": mod };
19
+ };
20
+ Object.defineProperty(exports, "__esModule", { value: true });
21
+ exports.CODEX_CONFIG_HOME_ENV = exports.CODEX_SESSION_ENV_SIGNALS = exports.CODEX_CONFIG_MARKER = void 0;
22
+ exports.detectHostRuntime = detectHostRuntime;
23
+ exports.resolveReportedRuntime = resolveReportedRuntime;
24
+ const node_fs_1 = __importDefault(require("node:fs"));
25
+ const node_path_1 = __importDefault(require("node:path"));
26
+ const runtime_slash_cjs_1 = require("./runtime-slash.cjs");
27
+ const update_context_cjs_1 = require("./update-context.cjs");
28
+ Object.defineProperty(exports, "CODEX_CONFIG_MARKER", { enumerable: true, get: function () { return update_context_cjs_1.CODEX_CONFIG_MARKER; } });
29
+ // Codex sandbox env vars set by the shell tool / Seatbelt child-process spawn.
30
+ // Evidence: openai/codex AGENTS.md — "The sandbox environment automatically
31
+ // sets CODEX_SANDBOX_NETWORK_DISABLED=1 when using the shell tool, and
32
+ // CODEX_SANDBOX=seatbelt for child processes spawned via Seatbelt." (injected
33
+ // by spawn_child_async in codex-rs/core/src/spawn.rs). These are absent under
34
+ // sandbox_mode = "danger-full-access", so this signal is best-effort and
35
+ // degrades to the default when unset.
36
+ //
37
+ // Note: CODEX_THREAD_ID (which appears in src/active-workstream-store.cts's
38
+ // WORKSTREAM_SESSION_ENV_KEYS) is deliberately NOT used here — it is
39
+ // undocumented in Codex's published env-var reference and source, so it
40
+ // fails this repo's citation bar.
41
+ exports.CODEX_SESSION_ENV_SIGNALS = Object.freeze([
42
+ 'CODEX_SANDBOX',
43
+ 'CODEX_SANDBOX_NETWORK_DISABLED',
44
+ ]);
45
+ // Evidence: learn.chatgpt.com/docs/config-file/environment-variables —
46
+ // "Sets the root for Codex state, including config…". The marker FILENAME
47
+ // (`config.toml`) is single-sourced from `update-context.cts`'s
48
+ // `inferPreferredRuntime` (imported above and re-exported for existing
49
+ // importers) — that is the only thing shared between the two functions. The
50
+ // TRUTHINESS RULE deliberately differs: `inferPreferredRuntime` treats a
51
+ // bare, unchecked `CODEX_HOME` as sufficient to resolve an update context,
52
+ // while THIS module additionally requires the marker file to exist, because
53
+ // it is asserting session identity rather than resolving an update context
54
+ // and needs the stronger signal. That difference is intentional and pinned
55
+ // by a test in `tests/host-runtime-detection.test.cjs` rather than left
56
+ // implicit.
57
+ //
58
+ // The DEFAULT `~/.codex/config.toml` is deliberately NEVER probed here:
59
+ // every machine that has ever run Codex has that file, so probing it
60
+ // unconditionally would misreport Claude Code sessions (or any other
61
+ // runtime) as codex just because Codex was installed at some point. An
62
+ // explicitly-exported CODEX_HOME is the user designating a Codex root for
63
+ // the CURRENT session, which is a much stronger signal.
64
+ exports.CODEX_CONFIG_HOME_ENV = 'CODEX_HOME';
65
+ // The degraded no-detection result. Also the fallback returned when ANY step
66
+ // of detection throws (see the module's stated no-throw premise below).
67
+ const NO_DETECTION = { runtime: null, source: 'none', signal: null };
68
+ /**
69
+ * Detect the host runtime from process environment signals, without ever
70
+ * consulting the explicit GSD_RUNTIME/config.json sources (those are a
71
+ * higher-priority rung handled by resolveExplicitRuntime).
72
+ *
73
+ * Never throws: the whole body — including the raw `env[key]` reads, which a
74
+ * caller could supply as a throwing Proxy — is wrapped in a single guarded
75
+ * region that degrades to `NO_DETECTION` on any unexpected error, rather than
76
+ * only guarding the `fileExists` probe.
77
+ */
78
+ function detectHostRuntime(deps) {
79
+ try {
80
+ const env = deps?.env ?? process.env;
81
+ const fileExists = deps?.fileExists ?? ((p) => node_fs_1.default.existsSync(p));
82
+ for (const key of exports.CODEX_SESSION_ENV_SIGNALS) {
83
+ const value = env[key];
84
+ if (typeof value === 'string' && value.trim() !== '') {
85
+ return { runtime: 'codex', source: 'session-env', signal: key };
86
+ }
87
+ }
88
+ const codexHome = env[exports.CODEX_CONFIG_HOME_ENV];
89
+ if (typeof codexHome === 'string' && codexHome.trim() !== '') {
90
+ try {
91
+ if (fileExists(node_path_1.default.join(codexHome, update_context_cjs_1.CODEX_CONFIG_MARKER))) {
92
+ return { runtime: 'codex', source: 'config-home', signal: exports.CODEX_CONFIG_HOME_ENV };
93
+ }
94
+ }
95
+ catch {
96
+ // Swallow probe failures (EACCES etc.) and fall through to no-detection.
97
+ }
98
+ }
99
+ return NO_DETECTION;
100
+ }
101
+ catch {
102
+ // A malformed `deps.env` (e.g. a throwing Proxy) must degrade like any
103
+ // other unreadable signal, not propagate — this function's contract is
104
+ // that it never throws.
105
+ return NO_DETECTION;
106
+ }
107
+ }
108
+ /**
109
+ * Resolve the runtime to report from init: explicit sources first, then the
110
+ * host-detection rung, then the 'claude' default. This is intentionally
111
+ * separate from resolveRuntime — only init's agent_runtime reporting call
112
+ * site uses this ladder; every other resolveRuntime caller is unaffected.
113
+ *
114
+ * Never throws: degrades to the 'claude' default on any unexpected error
115
+ * (e.g. a throwing `deps.env`), matching detectHostRuntime's no-throw
116
+ * contract.
117
+ */
118
+ function resolveReportedRuntime(projectDir, deps) {
119
+ try {
120
+ return resolveReportedRuntimeUnsafe(projectDir, deps);
121
+ }
122
+ catch {
123
+ return 'claude';
124
+ }
125
+ }
126
+ function resolveReportedRuntimeUnsafe(projectDir, deps) {
127
+ const explicit = (0, runtime_slash_cjs_1.resolveExplicitRuntime)(projectDir, deps?.env ?? process.env);
128
+ if (explicit)
129
+ return explicit;
130
+ const detected = detectHostRuntime(deps);
131
+ if (detected.runtime)
132
+ return detected.runtime;
133
+ return 'claude';
134
+ }