@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,303 @@
1
+ "use strict";
2
+ /**
3
+ * Health Diagnostic Rules — STATE.md consistency group (Phase 11, #3309,
4
+ * ADR-3180 §8.2/§8.3/§8.5).
5
+ *
6
+ * Five rules, each a near-mechanical extraction of an already-working
7
+ * `addIssue` call site in `cmdValidateHealth` (Gall's Law, design doc "Rule
8
+ * table organization" / "Laws applied"):
9
+ *
10
+ * - W024 (`verify.cts:1709-1729`) — STATE.md `state_head` commit-age
11
+ * freshness vs. git HEAD. GENUINE GAP, deliberately NOT migrated — see the
12
+ * `RULE_W024` comment below for exactly why.
13
+ * - W002 (`verify.cts:1731-1774`) — STATE.md references a phase token not
14
+ * declared anywhere (disk or ROADMAP).
15
+ * - W011 (`verify.cts:2104-2134`) — STATE's current-phase status disagrees
16
+ * with ROADMAP's `[x]` checkbox for that same phase.
17
+ * - W021 (`verify.cts:2270-2299`, the FIRST `addIssue('warning', 'W021', ...)`
18
+ * call site) — under the `'milestone-prefixed'` `phase_id_convention`, a
19
+ * phase's integer prefix implies a different milestone than the ROADMAP
20
+ * section it is actually listed under.
21
+ * - W026 (`verify.cts:2356-2399`, the SECOND `addIssue('warning', 'W021', ...)`
22
+ * call site — split off per the design doc's "New codes for the two split
23
+ * subjects" section, since one code covering two unrelated subjects is a
24
+ * genuine conflation) — STATE says the milestone is complete/archived, but
25
+ * ROADMAP (scoped to that same milestone) still lists a phase with no
26
+ * matching disk directory.
27
+ *
28
+ * - W002's original message interpolates `${slash('health')}`
29
+ * (`verify.cts:1770`) and W011's interpolates `${slash('progress')}`
30
+ * (`verify.cts:2126`) — both per-project runtime-resolved values
31
+ * (`formatGsdSlash`, `src/runtime-slash.cts`) this rule's
32
+ * `(snapshot) => Diagnostic[]` signature has no access to. Hardcodes the
33
+ * canonical `/gsd-health`/`/gsd-progress` hyphen form instead, mirroring
34
+ * the sibling "config.json validation" group's W016 rule
35
+ * (`src/health-diagnostic-rules/config-validation.cts`), which hardcodes
36
+ * `/gsd-ai-integration-phase` the same way for the identical reason.
37
+ *
38
+ * Design: .gsd/phase/refactor-3309-health-diagnostic-rule-table/40-design.md
39
+ */
40
+ // Runtime values (SEVERITY/REMEDY_ACTION/REMEDY_RISK) are needed here, not
41
+ // just types, so this is a normal (non type-only) `import ... = require(...)`
42
+ // — unlike `health-diagnostic.cts`'s own type-only import of
43
+ // `planning-snapshot.cjs`, which never touches that module's runtime values.
44
+ // eslint-disable-next-line @typescript-eslint/no-require-imports -- export= CommonJS module
45
+ const healthDiagnosticMod = require("../health-diagnostic-types.cjs");
46
+ const { SEVERITY, adviseRemedy } = healthDiagnosticMod;
47
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
48
+ const phaseIdMod = require("../phase-id.cjs");
49
+ const { getMilestoneFromPhaseId, matchPhaseDirs, normalizePhaseName, extractPhaseToken, PHASE_NUMBER_TOKEN_SOURCE } = phaseIdMod;
50
+ // eslint-disable-next-line @typescript-eslint/no-require-imports -- the single owner of the persisted status vocabulary
51
+ const stateDocumentMod = require("../state-document.cjs");
52
+ const { normalizeStateStatus } = stateDocumentMod;
53
+ // ─── W024 — STATE.md commit-age freshness (DELIBERATELY INERT) ─────────────
54
+ /**
55
+ * W024's real check (`verify.cts:1709-1729`) calls
56
+ * `readStateHeadFreshness(cwd, fm['state_head'])`, which shells out to `git
57
+ * log` to count commits between the frontmatter's `state_head` and the
58
+ * current HEAD. That is ambient I/O (git history), not `.planning/` content —
59
+ * confirmed against `src/planning-snapshot.cts`'s full 15-field
60
+ * `PlanningSnapshot` interface: no field wraps `readStateHeadFreshness` or
61
+ * exposes a commits-behind count.
62
+ *
63
+ * §8.1 rule 1 requires a rule's signature to be `(snapshot) => Diagnostic[]`
64
+ * with no ambient I/O inside `check` — so this rule does NOT call
65
+ * `readStateHeadFreshness` itself (that would violate the constraint the
66
+ * skeleton's own `Rule.check` type exists to enforce). Adding a 16th
67
+ * `PlanningSnapshot` field (e.g. `stateHeadFreshness: {value:
68
+ * {commitsBehind, stateHead}, scope}`) is the fix, but is out of this
69
+ * group's scope (`src/planning-snapshot.cts` is a shared file this task was
70
+ * not dispatched to extend).
71
+ *
72
+ * Registered here, `check` always returning `[]`, so the code table stays
73
+ * complete per §8.2's 1:1 invariant (every code the old `verify.cts` emitted
74
+ * has exactly one `Rule` entry) rather than silently dropping W024 from the
75
+ * table. This is a documented, deliberate deferral pending the 16th snapshot
76
+ * field — flagged prominently rather than quietly ported as a no-op.
77
+ */
78
+ const RULE_W024 = {
79
+ code: 'W024',
80
+ severity: SEVERITY.WARNING,
81
+ description: 'STATE.md was written many commits ago — treat its contents as approximate',
82
+ repairable: false,
83
+ check: (_snapshot) => [],
84
+ };
85
+ // ─── W002 — STATE.md references an undeclared phase token ──────────────────
86
+ /**
87
+ * The "valid phase" set the original code builds from
88
+ * `collectDiskPhases(planBase)` (disk dir tokens) + ROADMAP heading tokens +
89
+ * `forEachArchivedPhaseToken` (archived milestone-phase-dir tokens,
90
+ * `verify.cts:1748`). This rebuilds the disk+ROADMAP two-thirds from parsed
91
+ * snapshot fields only: `phaseDirs.value` (disk dir names, tokenized the same
92
+ * way `collectDiskPhaseEntries` does — via `extractPhaseToken`) and
93
+ * `roadmapDeclaredPhases.value.map(p => p.phaseId)` (ROADMAP-declared phase
94
+ * ids). Archived-phase-token coverage is NOT included — no
95
+ * `PlanningSnapshot` field exposes archived milestone-phase-dir tokens
96
+ * (confirmed against the 15-field interface). Omitting it makes this valid
97
+ * set a SUBSET of the original's, which can only make MORE STATE.md phase
98
+ * tokens look "invalid" (never fewer) — a conservative, safe direction; a
99
+ * project with archived phases still referenced from STATE.md is the
100
+ * fixture shape that would expose a false positive, and none of this
101
+ * group's fixtures exercise archives, so this gap is disclosed rather than
102
+ * silently absorbed.
103
+ *
104
+ * UPDATE (#3652): archived-phase-token coverage IS now included, via the
105
+ * additive `snapshot.archivedPhaseTokens` field
106
+ * (`src/planning-snapshot.cts`, added for this fix) — the disclosed gap
107
+ * above is closed; the paragraph is kept for the "conservative direction"
108
+ * reasoning, which still explains why every OTHER omission in this
109
+ * function is safe.
110
+ */
111
+ function buildValidPhaseSet(snapshot) {
112
+ const valid = new Set();
113
+ for (const dir of snapshot.phaseDirs.value) {
114
+ const token = extractPhaseToken(dir);
115
+ if (token)
116
+ valid.add(token);
117
+ }
118
+ for (const entry of snapshot.roadmapDeclaredPhases.value) {
119
+ valid.add(entry.phaseId);
120
+ }
121
+ for (const token of snapshot.archivedPhaseTokens.value) {
122
+ valid.add(token);
123
+ }
124
+ return valid;
125
+ }
126
+ /** Mirrors `verify.cts:1749-1758`'s zero-padding normalization exactly. */
127
+ function normalizePhaseTokenSet(valid) {
128
+ const normalized = new Set();
129
+ for (const p of valid) {
130
+ normalized.add(p);
131
+ const dotIdx = p.indexOf('.');
132
+ const head = dotIdx === -1 ? p : p.slice(0, dotIdx);
133
+ const tail = dotIdx === -1 ? '' : p.slice(dotIdx);
134
+ if (/^\d+$/.test(head)) {
135
+ normalized.add(head.padStart(2, '0') + tail);
136
+ }
137
+ }
138
+ return normalized;
139
+ }
140
+ const RULE_W002 = {
141
+ code: 'W002',
142
+ severity: SEVERITY.WARNING,
143
+ description: 'STATE.md references invalid phase',
144
+ repairable: false,
145
+ check: (snapshot) => {
146
+ const validPhases = buildValidPhaseSet(snapshot);
147
+ // Mirrors `verify.cts:1765`'s `if (normalizedValid.size > 0)` guard
148
+ // exactly — a project with zero declared phases emits nothing, never a
149
+ // false positive on every STATE.md phase mention.
150
+ if (validPhases.size === 0)
151
+ return [];
152
+ const normalizedValid = normalizePhaseTokenSet(validPhases);
153
+ const sortedValid = [...validPhases].sort((a, b) => a.localeCompare(b, undefined, { numeric: true }));
154
+ const diagnostics = [];
155
+ for (const ref of snapshot.statePhaseTokens.value) {
156
+ const dotIdx = ref.indexOf('.');
157
+ const head = dotIdx === -1 ? ref : ref.slice(0, dotIdx);
158
+ const tail = dotIdx === -1 ? '' : ref.slice(dotIdx);
159
+ const padded = /^\d+$/.test(head) ? head.padStart(2, '0') + tail : ref;
160
+ if (normalizedValid.has(ref) || normalizedValid.has(padded))
161
+ continue;
162
+ diagnostics.push({
163
+ code: 'W002',
164
+ severity: SEVERITY.WARNING,
165
+ message: `STATE.md references phase ${ref}, but only phases ${sortedValid.join(', ')} are declared`,
166
+ remedy: adviseRemedy('Review STATE.md manually before changing it; /gsd-health --repair will not overwrite an existing STATE.md for phase mismatches'),
167
+ });
168
+ }
169
+ return diagnostics;
170
+ },
171
+ };
172
+ // ─── W011 — STATE current-phase status vs. ROADMAP checkbox disagree ───────
173
+ /**
174
+ * `currentPhaseLabel.value` is a prose string (e.g. `"3 of 8 (User Auth)"`),
175
+ * not a clean phase id — the leading integer (optionally letter-suffixed /
176
+ * dotted, the same `PHASE_NUMBER_TOKEN_SOURCE` grammar) is the "current
177
+ * phase" proxy the original `verify.cts:2109-2113` derives via its own
178
+ * `**Current Phase:**`/`Current Phase:` regex + `.replace(/^0+/, '')`. That
179
+ * literal field name does not exist in the current `state.md` template
180
+ * (which uses `Phase: [X] of [Y] ([Phase name])` under `## Current
181
+ * Position`) — `currentPhaseLabel` is the parsed owner of that exact field,
182
+ * so extracting its leading number is the equivalent-intent read against
183
+ * the template STATE.md actually ships. #3280: the label's ladder
184
+ * (`buildStateFields`, `src/planning-snapshot.cts`) now leads with the
185
+ * frontmatter `current_phase` scalar — the key `gsd-tools state update` /
186
+ * `state begin-phase` persist — so a bare `"2"` is the expected value on
187
+ * the machine-readable format, and this leading-number extraction handles
188
+ * it identically.
189
+ */
190
+ function currentPhaseIdFromLabel(label) {
191
+ if (!label)
192
+ return null;
193
+ const m = label.match(new RegExp(`^0*(${PHASE_NUMBER_TOKEN_SOURCE})`));
194
+ return m ? m[1] : null;
195
+ }
196
+ const RULE_W011 = {
197
+ code: 'W011',
198
+ severity: SEVERITY.WARNING,
199
+ description: 'STATE.md current-phase status disagrees with ROADMAP.md checkbox',
200
+ repairable: false,
201
+ check: (snapshot) => {
202
+ const phaseId = currentPhaseIdFromLabel(snapshot.currentPhaseLabel.value);
203
+ if (phaseId === null)
204
+ return [];
205
+ const checked = snapshot.roadmapPhaseCheckboxes.value[phaseId];
206
+ if (checked !== true)
207
+ return [];
208
+ // #3280: the state writer persists `status` through `normalizeStateStatus`
209
+ // (`state.cts`'s syncStateFrontmatter), whose completion token is
210
+ // `completed` — an exact `'complete' || 'done'` comparison rejects the
211
+ // exact vocabulary the product writes and turns every legitimately
212
+ // completed frontmatter STATE.md into a false positive. Route the
213
+ // comparison through the same seam that owns the vocabulary
214
+ // (`state-document.cjs`'s `normalizeStateStatus`) rather than growing a
215
+ // second bespoke token list here.
216
+ const statusVal = (snapshot.stateStatus.value ?? '').trim();
217
+ if (normalizeStateStatus(statusVal, null) === 'completed')
218
+ return [];
219
+ return [
220
+ {
221
+ code: 'W011',
222
+ severity: SEVERITY.WARNING,
223
+ message: `STATE.md says current phase is ${phaseId} (status: ${statusVal.toLowerCase() || 'unknown'}) but ROADMAP.md shows it as [x] complete — state files may be out of sync`,
224
+ remedy: adviseRemedy('Run /gsd-progress to re-derive current position, or manually update STATE.md'),
225
+ },
226
+ ];
227
+ },
228
+ };
229
+ // ─── W021 — phase_id_convention integer-prefix/milestone mismatch ──────────
230
+ const RULE_W021 = {
231
+ code: 'W021',
232
+ severity: SEVERITY.WARNING,
233
+ description: "Phase's integer prefix implies a different milestone than its ROADMAP section (phase_id_convention: milestone-prefixed)",
234
+ repairable: false,
235
+ check: (snapshot) => {
236
+ const convention = snapshot.config.value?.['phase_id_convention'];
237
+ if (convention !== 'milestone-prefixed')
238
+ return [];
239
+ const diagnostics = [];
240
+ for (const entry of snapshot.roadmapDeclaredPhases.value) {
241
+ // `entry.milestone === null` means the builder never found this phase
242
+ // heading inside any versioned (`v\d+\.\d+`) section — the original
243
+ // `checkMilestonePrefixMismatches` only ever iterates phases found
244
+ // WITHIN a section, so a phase outside any section is equivalently
245
+ // never checked here.
246
+ if (entry.milestone === null)
247
+ continue;
248
+ const expectedMilestone = getMilestoneFromPhaseId(entry.phaseId);
249
+ if (expectedMilestone === null || expectedMilestone === entry.milestone)
250
+ continue;
251
+ diagnostics.push({
252
+ code: 'W021',
253
+ severity: SEVERITY.WARNING,
254
+ message: `Phase ${entry.phaseId}: integer prefix implies ${expectedMilestone} but listed under ${entry.milestone}`,
255
+ remedy: adviseRemedy('gsd-tools roadmap upgrade --convention milestone-prefixed'),
256
+ });
257
+ }
258
+ return diagnostics;
259
+ },
260
+ };
261
+ // ─── W026 — STATE says milestone complete but ROADMAP lists unstarted phase ─
262
+ const RULE_W026 = {
263
+ code: 'W026',
264
+ severity: SEVERITY.WARNING,
265
+ description: 'STATE says milestone complete but ROADMAP lists an unstarted phase for that milestone',
266
+ repairable: false,
267
+ check: (snapshot) => {
268
+ const statusVal = (snapshot.stateStatus.value ?? '').trim().toLowerCase();
269
+ if (!/milestone complete|archived/.test(statusVal))
270
+ return [];
271
+ // `currentMilestoneRoadmapPhaseIds` is already scoped to the current
272
+ // milestone (`extractCurrentMilestone(roadmapRaw, cwd)`, the same
273
+ // `<details>`/`<summary>`-tolerant owner `verify.cts:2364` used) — no
274
+ // separate `currentMilestone` resolution/filter needed here (see the
275
+ // field's own doc comment on `PlanningSnapshot` for why
276
+ // `roadmapDeclaredPhases`'s `milestone` attribution is the wrong fit).
277
+ const unstarted = [];
278
+ for (const phaseId of snapshot.currentMilestoneRoadmapPhaseIds.value) {
279
+ const normalized = normalizePhaseName(phaseId);
280
+ // `allPhaseDirNames` — every directory under `phases/`, UNWINDOWED by
281
+ // ROADMAP-declaration membership — mirrors the original's own
282
+ // unwindowed `phaseDirNames2` (`verify.cts:2372-2382`, a direct
283
+ // `readdirSync` of the phases dir), not the current-milestone-windowed
284
+ // `phaseDirs`.
285
+ const hasDirectory = matchPhaseDirs(snapshot.allPhaseDirNames.value, normalized).matches.length > 0;
286
+ if (!hasDirectory)
287
+ unstarted.push(phaseId);
288
+ }
289
+ if (unstarted.length === 0)
290
+ return [];
291
+ return [
292
+ {
293
+ code: 'W026',
294
+ severity: SEVERITY.WARNING,
295
+ message: `STATE says milestone complete but ROADMAP lists ${unstarted.length} unstarted phase(s) (e.g. Phase ${unstarted[0]})`,
296
+ remedy: adviseRemedy('Run validate consistency or re-run complete-milestone after verifying all phases are done'),
297
+ },
298
+ ];
299
+ },
300
+ };
301
+ // ─── Exports ────────────────────────────────────────────────────────────────
302
+ const RULES = [RULE_W024, RULE_W002, RULE_W011, RULE_W021, RULE_W026];
303
+ module.exports = { RULES };
@@ -0,0 +1,173 @@
1
+ "use strict";
2
+ /**
3
+ * Health Diagnostic — Worktree health rules (Phase 11, #3309, ADR-3180
4
+ * §8.2/§8.3/§8.5).
5
+ *
6
+ * Group: "Worktree health" (design doc, "Rule table organization" table) —
7
+ * W020 (×3 internal conditions, one subject: "the worktree health scan
8
+ * itself is degraded", design doc "Rejected alternatives" §3), W017 (orphan
9
+ * worktree), W027 (NEW — the split-off "stale worktree" subject, design
10
+ * doc's "New codes for the two split subjects" section).
11
+ *
12
+ * Ported behavior-preserving from `cmdValidateHealth`
13
+ * (`src/verify.cts:2193-2268`), the exact call sites for W020/W017/W027 (the
14
+ * pre-migration source still names the split-off stale-worktree site
15
+ * 'W017' — this batch is what actually applies the W027 split).
16
+ *
17
+ * W020's original THREE conditions were git_timed_out / git_list_failed / a
18
+ * per-finding 'unverified' kind, each with its own message. The first two
19
+ * are scan-level failures reported by `inspectWorktreeHealth`'s own `reason`
20
+ * field ('git_timed_out' vs 'git_list_failed' vs 'not_a_git_repo') —
21
+ * `planning-snapshot.cts`'s `buildWorktreeHealthField` now carries `reason`
22
+ * straight through on `PlanningSnapshot.worktreeHealth`, so `checkW020`
23
+ * below reproduces the original's exact branch-per-reason messages instead
24
+ * of collapsing them (a prior version of this file collapsed both into one
25
+ * message AND, worse, warned on 'not_a_git_repo' too — a regression, since
26
+ * the original silently skips a non-git cwd; see `verify.cts:2202-2217`).
27
+ *
28
+ * W027 restores the pre-migration active-worktree exclusion
29
+ * (`verify.cts:2233-2242`) via `PlanningSnapshot.cwd` — see `checkW027`'s own
30
+ * comment below for the mechanism.
31
+ *
32
+ * Design: .gsd/phase/refactor-3309-health-diagnostic-rule-table/40-design.md
33
+ *
34
+ * ADR-457 build-at-publish: source in
35
+ * src/health-diagnostic-rules/worktree-health.cts, compiled to
36
+ * gsd-core/bin/lib/health-diagnostic-rules/worktree-health.cjs (gitignored).
37
+ */
38
+ var __importDefault = (this && this.__importDefault) || function (mod) {
39
+ return (mod && mod.__esModule) ? mod : { "default": mod };
40
+ };
41
+ const node_path_1 = __importDefault(require("node:path"));
42
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
43
+ const healthDiagnosticMod = require("../health-diagnostic-types.cjs");
44
+ const { SEVERITY, adviseRemedy } = healthDiagnosticMod;
45
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
46
+ const planningScopeMod = require("../planning-scope.cjs");
47
+ const { SCOPE } = planningScopeMod;
48
+ // ─── W020 — worktree health scan itself is degraded (verify.cts:2193-2264) ─
49
+ //
50
+ // ONE rule, THREE internal conditions, all the same subject ("the worktree
51
+ // health scan itself is degraded" — design doc "Rejected alternatives" §3):
52
+ // (a) `git worktree list` timed out (verify.cts:2202-2209), (b) `git
53
+ // worktree list` failed outright (verify.cts:2210-2217), (c) a specific
54
+ // 'unverified' finding (existsSync ok, statSync threw,
55
+ // verify.cts:2256-2263). A fourth `!ok` reason, 'not_a_git_repo', and a
56
+ // thrown exception ('exception') are DELIBERATELY silent — the original's
57
+ // `if` ladder never matches 'not_a_git_repo', and the outer try/catch around
58
+ // the whole block is commented "git worktree not available or not a git
59
+ // repo — skip silently".
60
+ function checkW020(snapshot) {
61
+ const diagnostics = [];
62
+ const { scope, reason } = snapshot.worktreeHealth;
63
+ const degraded = scope === SCOPE.UNREADABLE;
64
+ // (a) — git worktree list timed out (verify.cts:2202-2209).
65
+ if (degraded && reason === 'git_timed_out') {
66
+ diagnostics.push({
67
+ code: 'W020',
68
+ severity: SEVERITY.WARNING,
69
+ message: 'Worktree health check degraded: git worktree list timed out after 10s — orphan/stale worktrees could not be inspected',
70
+ remedy: adviseRemedy('Run: git worktree list --porcelain to diagnose; check for .git/index.lock or a hung git process'),
71
+ });
72
+ }
73
+ // (b) — git worktree list failed outright (verify.cts:2210-2217).
74
+ if (degraded && reason === 'git_list_failed') {
75
+ diagnostics.push({
76
+ code: 'W020',
77
+ severity: SEVERITY.WARNING,
78
+ message: 'Worktree health check degraded: git worktree list failed — orphan/stale worktrees could not be inspected',
79
+ remedy: adviseRemedy('Run: git worktree list --porcelain to diagnose; check git repository state and permissions'),
80
+ });
81
+ }
82
+ // (c) — per-finding 'unverified' (existsSync ok, statSync threw).
83
+ for (const finding of snapshot.worktreeHealth.value) {
84
+ if (finding.kind !== 'unverified')
85
+ continue;
86
+ diagnostics.push({
87
+ code: 'W020',
88
+ severity: SEVERITY.WARNING,
89
+ message: `Worktree health check degraded: could not stat ${finding.path} — presence/staleness could not be verified`,
90
+ remedy: adviseRemedy('Check filesystem permissions on the worktree path, or investigate why statSync failed for it'),
91
+ });
92
+ }
93
+ return diagnostics;
94
+ }
95
+ // ─── W017 — orphan git worktree (verify.cts:2222-2229) ─────────────────────
96
+ //
97
+ // `finding.kind === 'orphan'` — path no longer exists on disk. One
98
+ // Diagnostic per orphan finding. Remedy mirrors the exact original literal
99
+ // fix, `verify.cts:2227`: `'Run: git worktree prune'`.
100
+ function checkW017(snapshot) {
101
+ const diagnostics = [];
102
+ for (const finding of snapshot.worktreeHealth.value) {
103
+ if (finding.kind !== 'orphan')
104
+ continue;
105
+ diagnostics.push({
106
+ code: 'W017',
107
+ severity: SEVERITY.WARNING,
108
+ message: `Orphan git worktree: ${finding.path} (path no longer exists on disk)`,
109
+ remedy: adviseRemedy('git worktree prune'),
110
+ });
111
+ }
112
+ return diagnostics;
113
+ }
114
+ // ─── W027 — stale git worktree (verify.cts:2232-2249, the split-off half of
115
+ // the pre-migration 'W017' site) ─────────────────────────────────────────
116
+ //
117
+ // `finding.kind === 'stale'` — age-based. Excludes the active session's own
118
+ // worktree, restored via `snapshot.cwd` (see module doc, gap 2 — RESOLVED):
119
+ // a 'stale' finding is skipped when `snapshot.cwd` equals the finding's path
120
+ // or is nested under it, the exact comparison `verify.cts:2238-2241` made
121
+ // against `process.cwd()`. Per this batch's brief: the interpolated command
122
+ // (with the real path) lives in `message`; `remedy.args.command` stays a
123
+ // static `<path>` template, mirroring the split the brief specifies.
124
+ function checkW027(snapshot) {
125
+ const diagnostics = [];
126
+ const activeCwd = snapshot.cwd;
127
+ for (const finding of snapshot.worktreeHealth.value) {
128
+ if (finding.kind !== 'stale')
129
+ continue;
130
+ const normalizedWorktree = node_path_1.default.resolve(finding.path);
131
+ const isActiveWorktree = activeCwd === normalizedWorktree || activeCwd.startsWith(normalizedWorktree + node_path_1.default.sep);
132
+ if (isActiveWorktree)
133
+ continue;
134
+ diagnostics.push({
135
+ code: 'W027',
136
+ severity: SEVERITY.WARNING,
137
+ // #3280: staleness is a pure mtime heuristic and carries no information
138
+ // about whether the tree is clean — git's own refusal of a non-forced
139
+ // removal on a dirty tree is the safety net, so the remediation must
140
+ // direct the operator (or an agent executing this literally) to check
141
+ // for uncommitted work FIRST and keep `--force` an explicit discard
142
+ // opt-in, never the default instruction.
143
+ message: `Stale git worktree: ${finding.path} (last modified ${finding.ageMinutes} minutes ago). Inspect uncommitted work first: git -C ${finding.path} status --porcelain; if clean run: git worktree remove ${finding.path}; only add --force to discard changes`,
144
+ remedy: adviseRemedy('git -C <path> status --porcelain; if clean: git worktree remove <path>; add --force only to discard changes'),
145
+ });
146
+ }
147
+ return diagnostics;
148
+ }
149
+ // ─── Exports ────────────────────────────────────────────────────────────────
150
+ const RULES = [
151
+ {
152
+ code: 'W020',
153
+ severity: SEVERITY.WARNING,
154
+ description: 'Worktree health scan degraded — git worktree list timed out, failed, or a finding could not be verified',
155
+ repairable: false,
156
+ check: checkW020,
157
+ },
158
+ {
159
+ code: 'W017',
160
+ severity: SEVERITY.WARNING,
161
+ description: 'Orphan git worktree (path no longer exists on disk)',
162
+ repairable: false,
163
+ check: checkW017,
164
+ },
165
+ {
166
+ code: 'W027',
167
+ severity: SEVERITY.WARNING,
168
+ description: 'Stale git worktree (not modified in a long time)',
169
+ repairable: false,
170
+ check: checkW027,
171
+ },
172
+ ];
173
+ module.exports = { RULES };
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ /**
3
+ * Health Diagnostic Types — shared, dependency-free rule-table types (Phase
4
+ * 11, #3309, ADR-3180 §8.2/§8.3/§8.5).
5
+ *
6
+ * Split out from `src/health-diagnostic.cts` to break a CJS circular
7
+ * dependency between the evaluator and its own rule-group files
8
+ * (`src/health-diagnostic-rules/*.cts`): those files need the frozen
9
+ * `SEVERITY`/`REMEDY_ACTION`/`REMEDY_RISK` enums and the `Diagnostic`/
10
+ * `Remedy`/`Rule` shapes, but the evaluator (`health-diagnostic.cts`) also
11
+ * needs to `require()` every rule-group file to populate its `RULES` array —
12
+ * a rule-group file requiring `health-diagnostic.cjs` back, mid-load, reads
13
+ * `module.exports` before it is assigned, so the destructured enums come
14
+ * back `undefined`. This leaf has NO runtime dependency on anything in that
15
+ * cycle, so both sides can depend on it directly.
16
+ *
17
+ * Design: .gsd/phase/refactor-3309-health-diagnostic-rule-table/40-design.md
18
+ * Test matrix: .gsd/phase/refactor-3309-health-diagnostic-rule-table/50-test-matrix.md
19
+ *
20
+ * ADR-457 build-at-publish: source in src/health-diagnostic-types.cts,
21
+ * compiled to gsd-core/bin/lib/health-diagnostic-types.cjs (gitignored).
22
+ */
23
+ // ─── Severity ───────────────────────────────────────────────────────────────
24
+ const SEVERITY = Object.freeze({
25
+ ERROR: 'error',
26
+ WARNING: 'warning',
27
+ INFO: 'info',
28
+ });
29
+ // ─── Remedy action / risk ───────────────────────────────────────────────────
30
+ // Harvested from health.md's published table + the corrected 6-action
31
+ // implementation (`src/verify.cts:2405-2553`) — not 5; `addAiIntegrationPhaseKey`
32
+ // (verify.cts:1860/2481-2502) was live in code, missing from docs (design
33
+ // doc, "Ground truth vs. issue #3309's claims" section).
34
+ const REMEDY_ACTION = Object.freeze({
35
+ CREATE_CONFIG: 'createConfig',
36
+ RESET_CONFIG: 'resetConfig',
37
+ REGENERATE_STATE: 'regenerateState',
38
+ ADD_NYQUIST_KEY: 'addNyquistKey',
39
+ ADD_AI_INTEGRATION_PHASE_KEY: 'addAiIntegrationPhaseKey',
40
+ BACKFILL_MILESTONES: 'backfillMilestones',
41
+ // §8.3 rule 5 — every non-repairable finding's `fix` string becomes an
42
+ // ADVISE payload; ADVISE never acts, only describes.
43
+ ADVISE: 'advise',
44
+ });
45
+ const REMEDY_RISK = Object.freeze({
46
+ NONE: 'none',
47
+ DESTRUCTIVE: 'destructive',
48
+ });
49
+ // ─── adviseRemedy — shared ADVISE-remedy builder ───────────────────────────
50
+ /**
51
+ * Every rule-group file needs the same `{action: ADVISE, risk: NONE, args:
52
+ * {command}}` shape for a non-repairable finding's `fix` string (§8.3 rule
53
+ * 5). Was defined identically in `config-validation.cts` and
54
+ * `agent-install.cts`, and repeated inline elsewhere — moved to this shared,
55
+ * dependency-free leaf so every rule-group file imports one implementation
56
+ * instead of duplicating it.
57
+ */
58
+ function adviseRemedy(command) {
59
+ return { action: REMEDY_ACTION.ADVISE, risk: REMEDY_RISK.NONE, args: { command } };
60
+ }
61
+ // ─── Exports ────────────────────────────────────────────────────────────────
62
+ const healthDiagnosticTypes = {
63
+ SEVERITY,
64
+ REMEDY_ACTION,
65
+ REMEDY_RISK,
66
+ adviseRemedy,
67
+ };
68
+ module.exports = healthDiagnosticTypes;