@opengsd/gsd-core 1.14.0 → 1.16.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 (551) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/.opencode/plugins/gsd-core.js +85 -5
  4. package/README.ja-JP.md +3 -3
  5. package/README.ko-KR.md +3 -3
  6. package/README.pt-BR.md +3 -3
  7. package/README.zh-CN.md +3 -3
  8. package/agents/gsd-code-fixer.compact.md +7 -6
  9. package/agents/gsd-code-fixer.md +9 -8
  10. package/agents/gsd-code-reviewer.compact.md +5 -3
  11. package/agents/gsd-code-reviewer.md +8 -6
  12. package/agents/gsd-debug-session-manager.compact.md +17 -2
  13. package/agents/gsd-debug-session-manager.md +17 -2
  14. package/agents/gsd-debugger.md +3 -3
  15. package/agents/gsd-eval-auditor.compact.md +1 -1
  16. package/agents/gsd-eval-auditor.md +1 -1
  17. package/agents/gsd-executor.md +17 -12
  18. package/agents/gsd-intel-updater.compact.md +1 -1
  19. package/agents/gsd-intel-updater.md +1 -1
  20. package/agents/gsd-mempalace-curator.md +2 -2
  21. package/agents/gsd-phase-researcher.md +19 -11
  22. package/agents/gsd-plan-checker.md +15 -9
  23. package/agents/gsd-planner.md +15 -11
  24. package/agents/gsd-project-researcher.compact.md +1 -1
  25. package/agents/gsd-project-researcher.md +1 -1
  26. package/agents/gsd-research-synthesizer.compact.md +1 -1
  27. package/agents/gsd-research-synthesizer.md +1 -1
  28. package/agents/gsd-ui-auditor.compact.md +21 -30
  29. package/agents/gsd-ui-auditor.md +166 -37
  30. package/agents/gsd-ui-researcher.compact.md +1 -1
  31. package/agents/gsd-ui-researcher.md +1 -1
  32. package/agents/gsd-verifier.md +37 -14
  33. package/bin/install.js +764 -287
  34. package/commands/gsd/add-tests.md +6 -1
  35. package/commands/gsd/ai-integration-phase.md +6 -1
  36. package/commands/gsd/audit-fix.md +5 -0
  37. package/commands/gsd/audit-milestone.md +6 -1
  38. package/commands/gsd/autonomous.md +7 -2
  39. package/commands/gsd/capture.md +9 -5
  40. package/commands/gsd/code-review.md +7 -2
  41. package/commands/gsd/complete-milestone.md +4 -0
  42. package/commands/gsd/config.md +7 -3
  43. package/commands/gsd/debug.md +11 -7
  44. package/commands/gsd/discuss-phase.md +7 -3
  45. package/commands/gsd/docs-update.md +12 -7
  46. package/commands/gsd/eval-review.md +6 -1
  47. package/commands/gsd/execute-phase.md +12 -7
  48. package/commands/gsd/extract-learnings.md +5 -0
  49. package/commands/gsd/fast.md +4 -0
  50. package/commands/gsd/forensics.md +5 -1
  51. package/commands/gsd/graphify.md +10 -6
  52. package/commands/gsd/health.md +5 -0
  53. package/commands/gsd/help.md +7 -2
  54. package/commands/gsd/import.md +7 -3
  55. package/commands/gsd/inbox.md +5 -0
  56. package/commands/gsd/ingest-docs.md +5 -1
  57. package/commands/gsd/manager.md +6 -1
  58. package/commands/gsd/map-codebase.md +7 -3
  59. package/commands/gsd/mempalace-capture.md +12 -4
  60. package/commands/gsd/mempalace-recall.md +5 -1
  61. package/commands/gsd/milestone-summary.md +5 -1
  62. package/commands/gsd/mvp-phase.md +8 -3
  63. package/commands/gsd/new-milestone.md +6 -1
  64. package/commands/gsd/new-project.md +5 -0
  65. package/commands/gsd/next.md +6 -1
  66. package/commands/gsd/ns-context.md +4 -0
  67. package/commands/gsd/ns-ideate.md +4 -0
  68. package/commands/gsd/ns-manage.md +4 -0
  69. package/commands/gsd/ns-project.md +4 -0
  70. package/commands/gsd/ns-review.md +4 -0
  71. package/commands/gsd/ns-workflow.md +4 -0
  72. package/commands/gsd/onboard.md +6 -1
  73. package/commands/gsd/pause-work.md +5 -1
  74. package/commands/gsd/phase.md +8 -4
  75. package/commands/gsd/plan-phase.md +6 -1
  76. package/commands/gsd/plan-review-convergence.md +11 -7
  77. package/commands/gsd/pr-branch.md +4 -0
  78. package/commands/gsd/profile-user.md +5 -1
  79. package/commands/gsd/progress.md +7 -2
  80. package/commands/gsd/quick-batch.md +21 -9
  81. package/commands/gsd/quick.md +12 -7
  82. package/commands/gsd/review.md +7 -4
  83. package/commands/gsd/secure-phase.md +6 -1
  84. package/commands/gsd/ship.md +5 -0
  85. package/commands/gsd/sketch.md +7 -2
  86. package/commands/gsd/spec-phase.md +5 -1
  87. package/commands/gsd/spike.md +8 -3
  88. package/commands/gsd/surface.md +5 -1
  89. package/commands/gsd/thread.md +4 -0
  90. package/commands/gsd/ui-phase.md +6 -1
  91. package/commands/gsd/ui-review.md +6 -1
  92. package/commands/gsd/ultraplan-phase.md +5 -1
  93. package/commands/gsd/undo.md +5 -1
  94. package/commands/gsd/update.md +6 -2
  95. package/commands/gsd/validate-phase.md +6 -1
  96. package/commands/gsd/verify-work.md +6 -1
  97. package/commands/gsd/workspace.md +7 -3
  98. package/gsd-core/bin/gsd-tools.cjs +477 -78
  99. package/gsd-core/bin/lib/active-workstream-store.cjs +15 -0
  100. package/gsd-core/bin/lib/adr-parser.cjs +3 -1
  101. package/gsd-core/bin/lib/agent-install-check.cjs +4 -1
  102. package/gsd-core/bin/lib/audit.cjs +144 -42
  103. package/gsd-core/bin/lib/broken-windows.cjs +13 -13
  104. package/gsd-core/bin/lib/capability-activation.cjs +9 -4
  105. package/gsd-core/bin/lib/capability-registry.cjs +197 -222
  106. package/gsd-core/bin/lib/capability-validator.cjs +16 -1
  107. package/gsd-core/bin/lib/check-auto-mode.cjs +35 -0
  108. package/gsd-core/bin/lib/check-command-router.cjs +164 -1625
  109. package/gsd-core/bin/lib/cjs-command-router-adapter.cjs +13 -2
  110. package/gsd-core/bin/lib/cli-exit.cjs +12 -0
  111. package/gsd-core/bin/lib/codex-agent-toml.cjs +32 -33
  112. package/gsd-core/bin/lib/command-aliases.cjs +7 -0
  113. package/gsd-core/bin/lib/command-routing-hub.cjs +48 -1
  114. package/gsd-core/bin/lib/commands.cjs +343 -207
  115. package/gsd-core/bin/lib/complexity-trigger.cjs +8 -7
  116. package/gsd-core/bin/lib/config-loader.cjs +65 -4
  117. package/gsd-core/bin/lib/config.cjs +76 -19
  118. package/gsd-core/bin/lib/core-utils.cjs +6 -1
  119. package/gsd-core/bin/lib/coverage.cjs +4 -8
  120. package/gsd-core/bin/lib/decision-coverage-support.cjs +259 -0
  121. package/gsd-core/bin/lib/decisions.cjs +30 -14
  122. package/gsd-core/bin/lib/drift.cjs +177 -42
  123. package/gsd-core/bin/lib/frontmatter-fence.cjs +90 -0
  124. package/gsd-core/bin/lib/frontmatter-splice.cjs +494 -0
  125. package/gsd-core/bin/lib/frontmatter.cjs +426 -234
  126. package/gsd-core/bin/lib/gap-checker.cjs +72 -29
  127. package/gsd-core/bin/lib/gate-api-coverage-verify-pre.cjs +381 -0
  128. package/gsd-core/bin/lib/gate-args.cjs +53 -0
  129. package/gsd-core/bin/lib/gate-codebase-drift.cjs +285 -0
  130. package/gsd-core/bin/lib/gate-config.cjs +46 -0
  131. package/gsd-core/bin/lib/gate-context-drift.cjs +141 -0
  132. package/gsd-core/bin/lib/gate-decision-coverage-plan.cjs +169 -0
  133. package/gsd-core/bin/lib/gate-decision-coverage-verify.cjs +126 -0
  134. package/gsd-core/bin/lib/gate-evaluation-scope.cjs +555 -0
  135. package/gsd-core/bin/lib/gate-evidence.cjs +138 -0
  136. package/gsd-core/bin/lib/gate-exit.cjs +27 -0
  137. package/gsd-core/bin/lib/gate-gap-analysis-plan-post.cjs +61 -0
  138. package/gsd-core/bin/lib/gate-phase-context.cjs +170 -0
  139. package/gsd-core/bin/lib/gate-predicate-evaluator.cjs +1 -1
  140. package/gsd-core/bin/lib/gate-predicate.cjs +165 -0
  141. package/gsd-core/bin/lib/gate-prohibition-enforcement.cjs +94 -0
  142. package/gsd-core/bin/lib/gate-schema-drift.cjs +165 -0
  143. package/gsd-core/bin/lib/gate-tdd-red-evidence.cjs +100 -0
  144. package/gsd-core/bin/lib/gate-tdd-review-checkpoint.cjs +182 -0
  145. package/gsd-core/bin/lib/gate-ui-plan.cjs +86 -0
  146. package/gsd-core/bin/lib/gate-ui-safety.cjs +80 -0
  147. package/gsd-core/bin/lib/gate-verdict.cjs +64 -0
  148. package/gsd-core/bin/lib/gate-verify-command-paths.cjs +78 -0
  149. package/gsd-core/bin/lib/gate-verify-failure-directions.cjs +41 -0
  150. package/gsd-core/bin/lib/graphify.cjs +10 -2
  151. package/gsd-core/bin/lib/health-diagnostic-rules/phase-structure.cjs +43 -47
  152. package/gsd-core/bin/lib/health-diagnostic.cjs +45 -8
  153. package/gsd-core/bin/lib/host-runtime-detection.cjs +9 -0
  154. package/gsd-core/bin/lib/init.cjs +364 -132
  155. package/gsd-core/bin/lib/install-engine.cjs +30 -33
  156. package/gsd-core/bin/lib/install-profiles.cjs +7 -4
  157. package/gsd-core/bin/lib/installer-migrations.cjs +8 -1
  158. package/gsd-core/bin/lib/io.cjs +122 -3
  159. package/gsd-core/bin/lib/loop-resolver.cjs +95 -0
  160. package/gsd-core/bin/lib/markdown-sectionizer.cjs +75 -1
  161. package/gsd-core/bin/lib/milestone.cjs +37 -6
  162. package/gsd-core/bin/lib/model-resolver.cjs +171 -62
  163. package/gsd-core/bin/lib/observability/event.cjs +1 -1
  164. package/gsd-core/bin/lib/observability/logger.cjs +46 -1
  165. package/gsd-core/bin/lib/pattern.cjs +10 -0
  166. package/gsd-core/bin/lib/phase-command-router.cjs +20 -5
  167. package/gsd-core/bin/lib/phase-estimation.cjs +5 -4
  168. package/gsd-core/bin/lib/phase-id-card.cjs +32 -0
  169. package/gsd-core/bin/lib/phase-id-display.cjs +78 -0
  170. package/gsd-core/bin/lib/phase-id.cjs +110 -8
  171. package/gsd-core/bin/lib/phase-lifecycle.cjs +9 -2
  172. package/gsd-core/bin/lib/phase-locator.cjs +29 -10
  173. package/gsd-core/bin/lib/phase-status.cjs +360 -0
  174. package/gsd-core/bin/lib/phase.cjs +489 -88
  175. package/gsd-core/bin/lib/plan-document.cjs +142 -20
  176. package/gsd-core/bin/lib/plan-drift-guard.cjs +5 -0
  177. package/gsd-core/bin/lib/planning-document.cjs +692 -0
  178. package/gsd-core/bin/lib/planning-inspect.cjs +60 -9
  179. package/gsd-core/bin/lib/planning-snapshot.cjs +18 -0
  180. package/gsd-core/bin/lib/planning-workspace.cjs +83 -55
  181. package/gsd-core/bin/lib/pr-branch-patterns.cjs +57 -0
  182. package/gsd-core/bin/lib/pristine-baseline.cjs +10 -0
  183. package/gsd-core/bin/lib/probe-core.cjs +7 -1
  184. package/gsd-core/bin/lib/profile-output.cjs +6 -3
  185. package/gsd-core/bin/lib/prohibition-enforcement.cjs +0 -55
  186. package/gsd-core/bin/lib/project-root.cjs +41 -2
  187. package/gsd-core/bin/lib/quick-batch-command-router.cjs +35 -9
  188. package/gsd-core/bin/lib/quick-batch-dispatch.cjs +11 -8
  189. package/gsd-core/bin/lib/real-home-guard.cjs +9 -1
  190. package/gsd-core/bin/lib/report-parser.cjs +269 -0
  191. package/gsd-core/bin/lib/review-lane-descriptor.cjs +10 -30
  192. package/gsd-core/bin/lib/review-reviewer-selection.cjs +2 -2
  193. package/gsd-core/bin/lib/roadmap-command-router.cjs +25 -19
  194. package/gsd-core/bin/lib/roadmap-parser.cjs +242 -15
  195. package/gsd-core/bin/lib/roadmap-upgrade.cjs +1653 -65
  196. package/gsd-core/bin/lib/roadmap.cjs +405 -88
  197. package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +373 -187
  198. package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +5 -2
  199. package/gsd-core/bin/lib/runtime-artifact-layout.cjs +57 -1
  200. package/gsd-core/bin/lib/runtime-homes.cjs +14 -7
  201. package/gsd-core/bin/lib/runtime-hooks-surface.cjs +522 -624
  202. package/gsd-core/bin/lib/runtime-name-policy.cjs +246 -21
  203. package/gsd-core/bin/lib/runtime-slash.cjs +47 -30
  204. package/gsd-core/bin/lib/shell-command-projection.cjs +47 -8
  205. package/gsd-core/bin/lib/smart-entry.cjs +19 -3
  206. package/gsd-core/bin/lib/stale-bake-guard.cjs +32 -48
  207. package/gsd-core/bin/lib/state-contract.cjs +15 -18
  208. package/gsd-core/bin/lib/state-document.cjs +100 -22
  209. package/gsd-core/bin/lib/state-transition.cjs +39 -2
  210. package/gsd-core/bin/lib/state.cjs +256 -105
  211. package/gsd-core/bin/lib/surface.cjs +19 -2
  212. package/gsd-core/bin/lib/tdd-red-evidence.cjs +48 -79
  213. package/gsd-core/bin/lib/uat-predicate.cjs +359 -38
  214. package/gsd-core/bin/lib/uat.cjs +432 -7
  215. package/gsd-core/bin/lib/ui-consideration-probe.cjs +15 -2
  216. package/gsd-core/bin/lib/ui-frontend-evidence.cjs +167 -40
  217. package/gsd-core/bin/lib/undo-commit-selection.cjs +131 -0
  218. package/gsd-core/bin/lib/vendor/README.md +31 -9
  219. package/gsd-core/bin/lib/vendor/saxes.cjs +1934 -0
  220. package/gsd-core/bin/lib/vendor/saxes.cjs.LICENSE.txt +92 -0
  221. package/gsd-core/bin/lib/vendor/tap-parser.cjs +8927 -0
  222. package/gsd-core/bin/lib/vendor/tap-parser.cjs.LICENSE.txt +152 -0
  223. package/gsd-core/bin/lib/verification-command-router.cjs +2 -1
  224. package/gsd-core/bin/lib/verification.cjs +1378 -274
  225. package/gsd-core/bin/lib/verify-command-grounding.cjs +46 -2
  226. package/gsd-core/bin/lib/verify-command-router.cjs +18 -7
  227. package/gsd-core/bin/lib/verify.cjs +357 -531
  228. package/gsd-core/bin/lib/workstream-inventory-builder.cjs +14 -6
  229. package/gsd-core/bin/lib/workstream-inventory.cjs +31 -21
  230. package/gsd-core/bin/lib/workstream-name-policy.cjs +31 -1
  231. package/gsd-core/bin/lib/workstream.cjs +11 -2
  232. package/gsd-core/bin/lib/worktree-base-ref.cjs +482 -73
  233. package/gsd-core/bin/lib/worktree-safety.cjs +784 -51
  234. package/gsd-core/bin/shared/config-defaults.manifest.json +8 -0
  235. package/gsd-core/bin/shared/config-schema.manifest.json +5 -0
  236. package/gsd-core/references/autonomous-smart-discuss.md +2 -1
  237. package/gsd-core/references/autonomous-ui-design-contract.md +3 -3
  238. package/gsd-core/references/checkpoints.md +5 -3
  239. package/gsd-core/references/edge-probe-fixtures/01-round-half-even/expected-coverage.json +28 -3
  240. package/gsd-core/references/edge-probe-fixtures/02-merge-intervals/expected-coverage.json +37 -4
  241. package/gsd-core/references/edge-probe-fixtures/03-truncate-graphemes/expected-coverage.json +28 -3
  242. package/gsd-core/references/edge-probe-fixtures/04-money-rounding/expected-coverage.json +28 -3
  243. package/gsd-core/references/edge-probe-fixtures/05-list-dedupe/expected-coverage.json +37 -4
  244. package/gsd-core/references/edge-probe-fixtures/06-resolved-mixed/expected-coverage.json +37 -4
  245. package/gsd-core/references/edge-probe.md +195 -21
  246. package/gsd-core/references/execute-mvp-tdd.md +5 -10
  247. package/gsd-core/references/execute-phase-between-wave-reset.md +10 -6
  248. package/gsd-core/references/execute-phase-response-language.md +1 -1
  249. package/gsd-core/references/execute-phase-wave-guard.md +22 -11
  250. package/gsd-core/references/gsd-run-resolver.md +1 -1
  251. package/gsd-core/references/loop-hook-dispatch.md +7 -1
  252. package/gsd-core/references/model-profiles.md +1 -1
  253. package/gsd-core/references/offer-next.md +1 -1
  254. package/gsd-core/references/phase-argument-parsing.md +9 -7
  255. package/gsd-core/references/phase-id-convention.md +28 -0
  256. package/gsd-core/references/planner-gap-closure.md +2 -0
  257. package/gsd-core/references/planner-load-graph-context.md +24 -13
  258. package/gsd-core/references/planner-verify-command-grounding.md +14 -0
  259. package/gsd-core/references/planning-config.md +12 -3
  260. package/gsd-core/references/spidr-splitting.md +1 -1
  261. package/gsd-core/references/tdd.md +37 -8
  262. package/gsd-core/references/ui-consideration-probe.md +10 -5
  263. package/gsd-core/references/verifier-phase-gates.md +5 -2
  264. package/gsd-core/references/verify-command-path-resolvability.md +10 -2
  265. package/gsd-core/references/verify-mvp-mode.md +2 -2
  266. package/gsd-core/references/workstream-flag.md +33 -3
  267. package/gsd-core/references/worktree-path-safety.md +321 -0
  268. package/gsd-core/templates/README.md +1 -1
  269. package/gsd-core/templates/UAT.md +17 -1
  270. package/gsd-core/templates/config.json +2 -11
  271. package/gsd-core/templates/verification-report.md +1 -1
  272. package/gsd-core/workflows/_runtime-launcher.snippet.sh +1 -1
  273. package/gsd-core/workflows/add-backlog.md +1 -1
  274. package/gsd-core/workflows/add-phase.md +8 -7
  275. package/gsd-core/workflows/add-tests.md +4 -3
  276. package/gsd-core/workflows/add-todo.md +6 -5
  277. package/gsd-core/workflows/ai-integration-phase.md +13 -4
  278. package/gsd-core/workflows/audit-fix.md +1 -1
  279. package/gsd-core/workflows/audit-milestone.md +4 -3
  280. package/gsd-core/workflows/audit-uat.md +1 -1
  281. package/gsd-core/workflows/autonomous/steps/converge-fail-fast.md +9 -18
  282. package/gsd-core/workflows/autonomous.md +43 -23
  283. package/gsd-core/workflows/check-todos.md +7 -6
  284. package/gsd-core/workflows/cleanup.md +2 -2
  285. package/gsd-core/workflows/code-review/steps/dispatch-fix.md +4 -3
  286. package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +20 -13
  287. package/gsd-core/workflows/code-review-fix.md +112 -25
  288. package/gsd-core/workflows/code-review.md +146 -135
  289. package/gsd-core/workflows/complete-milestone/detail/elaboration.md +4 -3
  290. package/gsd-core/workflows/complete-milestone.md +13 -8
  291. package/gsd-core/workflows/debug.md +32 -7
  292. package/gsd-core/workflows/diagnose-issues.md +3 -2
  293. package/gsd-core/workflows/discuss-phase/modes/advisor.md +1 -1
  294. package/gsd-core/workflows/discuss-phase/modes/chain.md +1 -1
  295. package/gsd-core/workflows/discuss-phase-assumptions.md +4 -3
  296. package/gsd-core/workflows/discuss-phase.md +4 -3
  297. package/gsd-core/workflows/do.md +2 -2
  298. package/gsd-core/workflows/docs-update.md +6 -5
  299. package/gsd-core/workflows/edit-phase.md +4 -3
  300. package/gsd-core/workflows/eval-review.md +14 -5
  301. package/gsd-core/workflows/execute-phase/detail/elaboration.md +2 -2
  302. package/gsd-core/workflows/execute-phase/steps/code-review-disposition.md +1019 -0
  303. package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +15 -4
  304. package/gsd-core/workflows/execute-phase/steps/completion-reconciliation.md +10 -7
  305. package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +37 -3
  306. package/gsd-core/workflows/execute-phase/steps/gap-closure-artifacts.md +3 -1
  307. package/gsd-core/workflows/execute-phase/steps/partial-wave.md +2 -2
  308. package/gsd-core/workflows/execute-phase/steps/per-plan-executor-routing.md +1 -1
  309. package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +1 -1
  310. package/gsd-core/workflows/execute-phase/steps/post-merge-gate.md +46 -9
  311. package/gsd-core/workflows/execute-phase/steps/protected-branch.md +1 -1
  312. package/gsd-core/workflows/execute-phase/steps/ready-wave-gate.md +37 -0
  313. package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +1 -1
  314. package/gsd-core/workflows/execute-phase/steps/regression-gate.md +2 -0
  315. package/gsd-core/workflows/execute-phase/steps/tdd-applicability-resolution.md +1 -1
  316. package/gsd-core/workflows/execute-phase/steps/threat-id-gate.md +28 -0
  317. package/gsd-core/workflows/execute-phase/steps/verify-phase-goal.md +187 -0
  318. package/gsd-core/workflows/execute-phase/steps/wave-post-gate-hooks.md +2 -3
  319. package/gsd-core/workflows/execute-phase/steps/worktree-base-check.md +25 -0
  320. package/gsd-core/workflows/execute-phase.md +96 -178
  321. package/gsd-core/workflows/execute-plan.md +18 -23
  322. package/gsd-core/workflows/explore.md +4 -4
  323. package/gsd-core/workflows/extract-learnings.md +4 -2
  324. package/gsd-core/workflows/fast.md +1 -1
  325. package/gsd-core/workflows/forensics.md +1 -1
  326. package/gsd-core/workflows/graduation.md +1 -1
  327. package/gsd-core/workflows/health.md +3 -2
  328. package/gsd-core/workflows/help/modes/full.compact.md +3 -3
  329. package/gsd-core/workflows/help/modes/full.md +5 -5
  330. package/gsd-core/workflows/help/modes/topic.md +15 -5
  331. package/gsd-core/workflows/import.md +4 -3
  332. package/gsd-core/workflows/inbox.md +2 -2
  333. package/gsd-core/workflows/ingest-docs.md +3 -3
  334. package/gsd-core/workflows/insert-phase.md +4 -3
  335. package/gsd-core/workflows/list-seeds.md +1 -1
  336. package/gsd-core/workflows/list-workspaces.md +1 -1
  337. package/gsd-core/workflows/manager.md +6 -4
  338. package/gsd-core/workflows/map-codebase.md +5 -4
  339. package/gsd-core/workflows/milestone-summary.md +3 -2
  340. package/gsd-core/workflows/mvp-phase.md +14 -14
  341. package/gsd-core/workflows/new-milestone.md +11 -11
  342. package/gsd-core/workflows/new-project/steps/auto-mode-config.md +3 -3
  343. package/gsd-core/workflows/new-project/steps/codebase-map-offer.md +1 -1
  344. package/gsd-core/workflows/new-project.md +7 -7
  345. package/gsd-core/workflows/new-workspace.md +2 -2
  346. package/gsd-core/workflows/next.md +1 -1
  347. package/gsd-core/workflows/note.md +1 -1
  348. package/gsd-core/workflows/onboard.md +1 -1
  349. package/gsd-core/workflows/pause-work.md +2 -2
  350. package/gsd-core/workflows/plan-phase/detail/elaboration.md +1 -1
  351. package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +17 -5
  352. package/gsd-core/workflows/plan-phase/steps/closed-phase-gate.md +1 -1
  353. package/gsd-core/workflows/plan-phase/steps/prd-express-path.md +1 -1
  354. package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +23 -5
  355. package/gsd-core/workflows/plan-phase.md +50 -24
  356. package/gsd-core/workflows/plan-review-convergence.md +21 -5
  357. package/gsd-core/workflows/plant-seed.md +62 -20
  358. package/gsd-core/workflows/pr-branch.md +113 -13
  359. package/gsd-core/workflows/profile-user.md +2 -2
  360. package/gsd-core/workflows/progress.md +19 -49
  361. package/gsd-core/workflows/quick/steps/plan-checker-loop.md +27 -0
  362. package/gsd-core/workflows/quick/steps/quick-verification.md +4 -4
  363. package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +30 -11
  364. package/gsd-core/workflows/quick-batch/steps/batch-init.md +1 -1
  365. package/gsd-core/workflows/quick-batch/steps/completion.md +1 -1
  366. package/gsd-core/workflows/quick-batch/steps/merge-wave.md +1 -1
  367. package/gsd-core/workflows/quick-batch/steps/planner-wave.md +1 -1
  368. package/gsd-core/workflows/quick-batch/steps/research-phase.md +1 -1
  369. package/gsd-core/workflows/quick-batch/steps/resume-mode.md +1 -1
  370. package/gsd-core/workflows/quick-batch/steps/verification-wave.md +9 -3
  371. package/gsd-core/workflows/quick-batch/steps/worktree-dispatch.md +1 -1
  372. package/gsd-core/workflows/quick-batch.md +15 -10
  373. package/gsd-core/workflows/quick.md +62 -39
  374. package/gsd-core/workflows/reapply-patches.md +9 -3
  375. package/gsd-core/workflows/remove-phase.md +3 -2
  376. package/gsd-core/workflows/remove-workspace.md +2 -2
  377. package/gsd-core/workflows/resume-project.md +3 -2
  378. package/gsd-core/workflows/review.md +33 -17
  379. package/gsd-core/workflows/scan.md +3 -2
  380. package/gsd-core/workflows/secure-phase.md +13 -13
  381. package/gsd-core/workflows/settings-advanced.md +30 -10
  382. package/gsd-core/workflows/settings-integrations.md +2 -3
  383. package/gsd-core/workflows/settings.md +4 -4
  384. package/gsd-core/workflows/ship.md +14 -13
  385. package/gsd-core/workflows/sketch-wrap-up.md +1 -1
  386. package/gsd-core/workflows/sketch.md +1 -1
  387. package/gsd-core/workflows/smart-entry.md +2 -2
  388. package/gsd-core/workflows/spec-phase.md +15 -5
  389. package/gsd-core/workflows/spike-wrap-up.md +1 -1
  390. package/gsd-core/workflows/spike.md +1 -1
  391. package/gsd-core/workflows/stats.md +1 -1
  392. package/gsd-core/workflows/sync-skills.md +5 -5
  393. package/gsd-core/workflows/thread.md +2 -2
  394. package/gsd-core/workflows/transition.md +13 -23
  395. package/gsd-core/workflows/ui-phase.md +48 -11
  396. package/gsd-core/workflows/ui-review.md +21 -6
  397. package/gsd-core/workflows/ultraplan-phase.md +3 -2
  398. package/gsd-core/workflows/undo.md +339 -20
  399. package/gsd-core/workflows/update.md +7 -7
  400. package/gsd-core/workflows/validate-phase.md +12 -13
  401. package/gsd-core/workflows/verify-work/detail/elaboration.md +43 -3
  402. package/gsd-core/workflows/verify-work/steps/automated-ui-verification.md +1 -1
  403. package/gsd-core/workflows/verify-work/steps/mvp-uat-framing.md +5 -3
  404. package/gsd-core/workflows/verify-work.md +129 -55
  405. package/hooks/dist/gsd-agent-isolation-guard.js +32 -0
  406. package/hooks/dist/gsd-check-update-worker.js +8 -0
  407. package/hooks/dist/gsd-check-update.js +8 -0
  408. package/hooks/dist/gsd-context-monitor.js +31 -8
  409. package/hooks/dist/gsd-cursor-subagent-start.js +8 -0
  410. package/hooks/dist/gsd-secret-read-guard.js +161 -4
  411. package/hooks/dist/gsd-statusline.js +85 -20
  412. package/hooks/dist/gsd-update-banner.js +8 -0
  413. package/hooks/dist/gsd-validate-commit.sh +63 -4
  414. package/hooks/dist/gsd-windsurf-pre-write.js +11 -2
  415. package/hooks/dist/gsd-workflow-guard.js +5 -4
  416. package/hooks/dist/gsd-worktree-path-guard.js +6 -2
  417. package/hooks/dist/lib/cli-exit.js +12 -0
  418. package/hooks/dist/lib/git-probe.js +17 -1
  419. package/hooks/dist/lib/isolation-sentinel.js +2 -2
  420. package/hooks/gsd-agent-isolation-guard.js +32 -0
  421. package/hooks/gsd-check-update-worker.js +8 -0
  422. package/hooks/gsd-check-update.js +8 -0
  423. package/hooks/gsd-context-monitor.js +31 -8
  424. package/hooks/gsd-cursor-subagent-start.js +8 -0
  425. package/hooks/gsd-secret-read-guard.js +161 -4
  426. package/hooks/gsd-statusline.js +85 -20
  427. package/hooks/gsd-update-banner.js +8 -0
  428. package/hooks/gsd-validate-commit.sh +63 -4
  429. package/hooks/gsd-windsurf-pre-write.js +11 -2
  430. package/hooks/gsd-workflow-guard.js +5 -4
  431. package/hooks/gsd-worktree-path-guard.js +6 -2
  432. package/hooks/hooks.json +5 -5
  433. package/hooks/lib/cli-exit.js +12 -0
  434. package/hooks/lib/git-probe.js +17 -1
  435. package/hooks/lib/isolation-sentinel.js +2 -2
  436. package/package.json +22 -4
  437. package/scripts/build-hooks.js +15 -6
  438. package/scripts/changeset/parse.cjs +52 -4
  439. package/scripts/check-contract-drift.cjs +127 -11
  440. package/scripts/ci-timeout-report.cjs +770 -4
  441. package/scripts/command-contract-helpers.cjs +15 -8
  442. package/scripts/docs-guard-registry.cjs +34 -0
  443. package/scripts/gen-features.cjs +13 -8
  444. package/scripts/gen-hooks-cli-exit.cjs +12 -28
  445. package/scripts/gen-loop-host-contract.cjs +79 -1
  446. package/scripts/gen-platform-conformance-tier.cjs +187 -1
  447. package/scripts/gen-plugin-skills.cjs +87 -1
  448. package/scripts/gen-research-agents.cjs +24 -31
  449. package/scripts/gen-scripts-cli-exit.cjs +30 -3
  450. package/scripts/gen-test-timings.cjs +32 -7
  451. package/scripts/lib/cli-exit.cjs +12 -0
  452. package/scripts/lib/macos-conformance-tier.generated.cjs +34 -2
  453. package/scripts/lib/ndjson-reporter.cjs +31 -5
  454. package/scripts/lib/platform-conformance-tier.generated.cjs +45 -5
  455. package/scripts/lib/registration-ledger-preload.cjs +155 -0
  456. package/scripts/lib/vendor-bundle.cjs +59 -0
  457. package/scripts/lib/vendor-licenses/saxes-6.0.0.txt +64 -0
  458. package/scripts/lint-allow-test-rule-refs.effective-ceiling.json +1 -1
  459. package/scripts/lint-allow-test-rule-refs.unverified-ceiling.json +1 -1
  460. package/scripts/lint-completion-predicate-drift.cjs +18 -19
  461. package/scripts/lint-descriptions.cjs +7 -3
  462. package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +38 -1
  463. package/scripts/lint-eslint-glob-coverage.allowlist.json +20 -0
  464. package/scripts/lint-frontmatter-fence-drift.cjs +313 -0
  465. package/scripts/lint-frontmatter-scalar-broad-grep.cjs +122 -16
  466. package/scripts/lint-phase-arg-assignment.cjs +257 -0
  467. package/scripts/lint-phase-enumeration-drift.cjs +12 -8
  468. package/scripts/lint-phase-id-drift.cjs +319 -5
  469. package/scripts/lint-planning-document-positive-control.cjs +329 -0
  470. package/scripts/lint-pr-branch-pattern-drift.cjs +148 -0
  471. package/scripts/lint-response-language-coverage.cjs +3 -0
  472. package/scripts/lint-retired-runtime-name.cjs +619 -0
  473. package/scripts/lint-skill-deps.cjs +7 -3
  474. package/scripts/lint-state-write-path-drift.cjs +93 -0
  475. package/scripts/lint-test-file-count.allowlist.json +38 -9
  476. package/scripts/lint-test-file-count.cjs +34 -1
  477. package/scripts/lint-vendored-deps.cjs +41 -5
  478. package/scripts/lint-workflow-shellcheck-baseline.json +25 -10
  479. package/scripts/mutation-matrix.cjs +50 -5
  480. package/scripts/prompt-injection-scan.sh +4 -0
  481. package/scripts/release-tarball-smoke.cjs +194 -1
  482. package/scripts/require-issue-link-policy.cjs +6 -2
  483. package/scripts/sync-runtime-launcher.cjs +184 -2
  484. package/scripts/verify-npm-publish.cjs +76 -20
  485. package/skills/gsd-add-tests/SKILL.md +6 -1
  486. package/skills/gsd-ai-integration-phase/SKILL.md +6 -1
  487. package/skills/gsd-audit-fix/SKILL.md +5 -0
  488. package/skills/gsd-audit-milestone/SKILL.md +6 -1
  489. package/skills/gsd-autonomous/SKILL.md +7 -2
  490. package/skills/gsd-capture/SKILL.md +9 -5
  491. package/skills/gsd-code-review/SKILL.md +7 -2
  492. package/skills/gsd-complete-milestone/SKILL.md +4 -0
  493. package/skills/gsd-config/SKILL.md +8 -4
  494. package/skills/gsd-debug/SKILL.md +11 -7
  495. package/skills/gsd-discuss-phase/SKILL.md +7 -3
  496. package/skills/gsd-docs-update/SKILL.md +12 -7
  497. package/skills/gsd-eval-review/SKILL.md +6 -1
  498. package/skills/gsd-execute-phase/SKILL.md +12 -7
  499. package/skills/gsd-extract-learnings/SKILL.md +5 -0
  500. package/skills/gsd-fast/SKILL.md +4 -0
  501. package/skills/gsd-forensics/SKILL.md +5 -1
  502. package/skills/gsd-graphify/SKILL.md +10 -6
  503. package/skills/gsd-health/SKILL.md +5 -0
  504. package/skills/gsd-help/SKILL.md +7 -2
  505. package/skills/gsd-import/SKILL.md +7 -3
  506. package/skills/gsd-inbox/SKILL.md +5 -0
  507. package/skills/gsd-ingest-docs/SKILL.md +5 -1
  508. package/skills/gsd-manager/SKILL.md +6 -1
  509. package/skills/gsd-map-codebase/SKILL.md +7 -3
  510. package/skills/gsd-mempalace-capture/SKILL.md +12 -4
  511. package/skills/gsd-mempalace-recall/SKILL.md +5 -1
  512. package/skills/gsd-milestone-summary/SKILL.md +5 -1
  513. package/skills/gsd-mvp-phase/SKILL.md +8 -3
  514. package/skills/gsd-new-milestone/SKILL.md +6 -1
  515. package/skills/gsd-new-project/SKILL.md +5 -0
  516. package/skills/gsd-next/SKILL.md +6 -1
  517. package/skills/gsd-ns-context/SKILL.md +4 -0
  518. package/skills/gsd-ns-ideate/SKILL.md +4 -0
  519. package/skills/gsd-ns-manage/SKILL.md +4 -0
  520. package/skills/gsd-ns-project/SKILL.md +4 -0
  521. package/skills/gsd-ns-review/SKILL.md +4 -0
  522. package/skills/gsd-ns-workflow/SKILL.md +4 -0
  523. package/skills/gsd-onboard/SKILL.md +6 -1
  524. package/skills/gsd-pause-work/SKILL.md +5 -1
  525. package/skills/gsd-phase/SKILL.md +8 -4
  526. package/skills/gsd-plan-phase/SKILL.md +6 -1
  527. package/skills/gsd-plan-review-convergence/SKILL.md +10 -6
  528. package/skills/gsd-pr-branch/SKILL.md +4 -0
  529. package/skills/gsd-profile-user/SKILL.md +5 -1
  530. package/skills/gsd-progress/SKILL.md +7 -2
  531. package/skills/gsd-quick/SKILL.md +16 -10
  532. package/skills/gsd-quick-batch/SKILL.md +21 -9
  533. package/skills/gsd-review/SKILL.md +7 -4
  534. package/skills/gsd-review-backlog/SKILL.md +3 -2
  535. package/skills/gsd-secure-phase/SKILL.md +6 -1
  536. package/skills/gsd-ship/SKILL.md +5 -0
  537. package/skills/gsd-sketch/SKILL.md +7 -2
  538. package/skills/gsd-spec-phase/SKILL.md +5 -1
  539. package/skills/gsd-spike/SKILL.md +8 -3
  540. package/skills/gsd-surface/SKILL.md +5 -1
  541. package/skills/gsd-thread/SKILL.md +4 -0
  542. package/skills/gsd-ui-phase/SKILL.md +6 -1
  543. package/skills/gsd-ui-review/SKILL.md +6 -1
  544. package/skills/gsd-ultraplan-phase/SKILL.md +5 -1
  545. package/skills/gsd-undo/SKILL.md +5 -1
  546. package/skills/gsd-update/SKILL.md +6 -2
  547. package/skills/gsd-validate-phase/SKILL.md +6 -1
  548. package/skills/gsd-verify-work/SKILL.md +6 -1
  549. package/skills/gsd-workspace/SKILL.md +7 -3
  550. package/skills/gsd-workstreams/SKILL.md +6 -6
  551. package/vscode/package.json +1 -1
@@ -19,21 +19,18 @@
19
19
  var __importDefault = (this && this.__importDefault) || function (mod) {
20
20
  return (mod && mod.__esModule) ? mod : { "default": mod };
21
21
  };
22
- const node_fs_1 = __importDefault(require("node:fs"));
23
22
  const node_path_1 = __importDefault(require("node:path"));
24
23
  // eslint-disable-next-line @typescript-eslint/no-require-imports
25
24
  const io = require("./io.cjs");
26
25
  const { output, error, formatDiagnosticToken } = io;
27
26
  const pattern_cjs_1 = require("./pattern.cjs");
27
+ const gate_evidence_cjs_1 = require("./gate-evidence.cjs");
28
28
  // eslint-disable-next-line @typescript-eslint/no-require-imports
29
29
  const planningWorkspace = require("./planning-workspace.cjs");
30
30
  const { planningPaths, planningDir, findContextMdIn } = planningWorkspace;
31
31
  const decisions_cjs_1 = require("./decisions.cjs");
32
32
  const markdown_sectionizer_cjs_1 = require("./markdown-sectionizer.cjs");
33
33
  // eslint-disable-next-line @typescript-eslint/no-require-imports
34
- const planScanMod = require("./plan-scan.cjs");
35
- const { scanPhasePlans } = planScanMod;
36
- // eslint-disable-next-line @typescript-eslint/no-require-imports
37
34
  const phaseIdMod = require("./phase-id.cjs");
38
35
  const { scopeToPhase } = phaseIdMod;
39
36
  // eslint-disable-next-line @typescript-eslint/no-require-imports
@@ -143,21 +140,42 @@ function formatGapTable(rows) {
143
140
  }).join('\n');
144
141
  return `## Post-Planning Gap Analysis\n\n${header}\n${body}\n`;
145
142
  }
143
+ function parseJsonEvidence(text, span) {
144
+ try {
145
+ return (0, gate_evidence_cjs_1.evidenceFound)(JSON.parse(text));
146
+ }
147
+ catch (err) {
148
+ return (0, gate_evidence_cjs_1.evidenceFromError)(err, span);
149
+ }
150
+ }
151
+ /**
152
+ * Is the gap analysis enabled? An ABSENT config means the default (enabled). A config that exists
153
+ * but cannot be read or parsed also runs the analysis (the conservative direction: the check is not
154
+ * silently switched off), and is reported in `unreadable` so the verdict is never a clean pass
155
+ * (#5170, ADR-5057 §4).
156
+ */
146
157
  function readGate(cwd) {
147
158
  const cfgPath = node_path_1.default.join(planningDir(cwd), 'config.json');
148
- try {
149
- const raw = JSON.parse(node_fs_1.default.readFileSync(cfgPath, 'utf-8'));
159
+ const text = (0, gate_evidence_cjs_1.readTextEvidence)(cfgPath);
160
+ if (text.kind === 'none')
161
+ return { enabled: true, unreadable: [] };
162
+ if (text.kind === 'unreadable')
163
+ return { enabled: true, unreadable: [{ reason: text.reason, span: cfgPath }] };
164
+ const parsed = parseJsonEvidence(text.value, cfgPath);
165
+ if (parsed.kind === 'unreadable')
166
+ return { enabled: true, unreadable: [{ reason: parsed.reason, span: cfgPath }] };
167
+ if (parsed.kind === 'found') {
168
+ const raw = parsed.value;
150
169
  if (raw && typeof raw === 'object' && 'workflow' in raw) {
151
170
  const wf = raw['workflow'];
152
171
  if (wf && typeof wf === 'object' && 'post_planning_gaps' in wf) {
153
172
  const val = wf['post_planning_gaps'];
154
173
  if (typeof val === 'boolean')
155
- return val;
174
+ return { enabled: val, unreadable: [] };
156
175
  }
157
176
  }
158
177
  }
159
- catch { /* fall through */ }
160
- return true;
178
+ return { enabled: true, unreadable: [] };
161
179
  }
162
180
  /**
163
181
  * Same-prefix ascending numeric range, e.g. `SEL-01..SEL-03`. Both sides must
@@ -298,7 +316,10 @@ function normalizePhaseReqIds(rawVal) {
298
316
  }
299
317
  function runGapAnalysis(cwd, phaseDir, options = {}) {
300
318
  const phaseReqIds = normalizePhaseReqIds(options.phaseReqIds);
301
- if (!readGate(cwd)) {
319
+ const gate = readGate(cwd);
320
+ const unreadable = [...gate.unreadable];
321
+ const unreadableField = () => (unreadable.length > 0 ? { unreadable } : {});
322
+ if (!gate.enabled) {
302
323
  return {
303
324
  enabled: false,
304
325
  rows: [],
@@ -311,7 +332,12 @@ function runGapAnalysis(cwd, phaseDir, options = {}) {
311
332
  }
312
333
  const absPhaseDir = node_path_1.default.isAbsolute(phaseDir) ? phaseDir : node_path_1.default.join(cwd, phaseDir);
313
334
  const reqPath = planningPaths(cwd).requirements;
314
- const reqMd = node_fs_1.default.existsSync(reqPath) ? node_fs_1.default.readFileSync(reqPath, 'utf-8') : '';
335
+ // An absent REQUIREMENTS.md has no requirements; one that exists but cannot be read is `unreadable`
336
+ // (a thrown read used to crash, and `existsSync` said "absent" for an EACCES on a parent).
337
+ const reqRead = (0, gate_evidence_cjs_1.readTextEvidence)(reqPath);
338
+ if (reqRead.kind === 'unreadable')
339
+ unreadable.push({ reason: reqRead.reason, span: reqPath });
340
+ const reqMd = reqRead.kind === 'found' ? reqRead.value : '';
315
341
  let reqItems = parseRequirements(reqMd).map(r => ({ ...r, source: 'REQUIREMENTS.md' }));
316
342
  // Scope the requirements comparison to the phase's mapped REQ-IDs (#447).
317
343
  // A phase that maps no requirements (phase_req_ids null/TBD) must not report
@@ -325,7 +351,9 @@ function runGapAnalysis(cwd, phaseDir, options = {}) {
325
351
  const wanted = new Set(phaseReqIds);
326
352
  const foundIds = new Set(reqItems.map(r => r.id));
327
353
  reqItems = reqItems.filter(r => wanted.has(r.id));
328
- ghostReqIds = phaseReqIds.filter(id => !foundIds.has(id));
354
+ // An unreadable REQUIREMENTS.md registers nothing, so "missing from REQUIREMENTS.md" would be a
355
+ // false claim about every ID; the unreadable read is reported instead.
356
+ ghostReqIds = reqRead.kind === 'unreadable' ? [] : phaseReqIds.filter(id => !foundIds.has(id));
329
357
  }
330
358
  // Read the phase directory once; reuse the listing for both context detection
331
359
  // and plan-file enumeration (avoids redundant readdirSync calls).
@@ -343,6 +371,8 @@ function runGapAnalysis(cwd, phaseDir, options = {}) {
343
371
  const phaseDirReadError = phaseDirScope === SCOPE.UNREADABLE
344
372
  ? `Could not read phase directory ${formatDiagnosticToken(absPhaseDir)}`
345
373
  : null;
374
+ if (phaseDirScope === SCOPE.UNREADABLE)
375
+ unreadable.push({ reason: 'the directory could not be listed', span: absPhaseDir });
346
376
  // #3511-class: scope the raw listing to this phase dir before the
347
377
  // phase-numbered -CONTEXT.md predicate. `phaseDirFiles` itself stays raw —
348
378
  // it is also reused below only as a `.length > 0` guard ahead of
@@ -351,31 +381,40 @@ function runGapAnalysis(cwd, phaseDir, options = {}) {
351
381
  const scopedPhaseDirFiles = scopeToPhase(phaseDirFiles, node_path_1.default.basename(absPhaseDir));
352
382
  const ctxFile = findContextMdIn(scopedPhaseDirFiles);
353
383
  const ctxPath = ctxFile ? node_path_1.default.join(absPhaseDir, ctxFile) : null;
354
- const ctxMd = ctxPath ? node_fs_1.default.readFileSync(ctxPath, 'utf-8') : '';
384
+ const ctxRead = ctxPath ? (0, gate_evidence_cjs_1.readTextEvidence)(ctxPath) : null;
385
+ if (ctxPath && ctxRead && ctxRead.kind === 'unreadable')
386
+ unreadable.push({ reason: ctxRead.reason, span: ctxPath });
387
+ const ctxMd = ctxRead && ctxRead.kind === 'found' ? ctxRead.value : '';
355
388
  // Use extractDecisions so gap-checker can distinguish could-not-parse from none-present.
356
389
  const ctxExtraction = (0, decisions_cjs_1.extractDecisions)(ctxMd);
357
390
  const dItems = ctxExtraction.decisions.map(d => ({ ...d, source: 'CONTEXT.md' }));
358
391
  const items = [...reqItems, ...dItems];
359
392
  let planText = '';
360
- try {
361
- if (phaseDirFiles.length > 0) {
362
- // #3183 (lint-plan-count-drift): source the live plan-file list from
363
- // the single owner (scanPhasePlans) instead of a local `-PLAN\.md$`
364
- // filter on the already-read listing — picks up bare PLAN.md, nested
365
- // plans/, and excludes superseded plans, none of which the prior
366
- // root-only exact-suffix filter did.
367
- const files = scanPhasePlans(absPhaseDir).planFiles;
368
- planText = files.map(f => {
369
- try {
370
- return node_fs_1.default.readFileSync(node_path_1.default.join(absPhaseDir, f), 'utf-8');
371
- }
372
- catch {
373
- return '';
374
- }
393
+ if (phaseDirFiles.length > 0) {
394
+ // #3183 (lint-plan-count-drift): source the live plan-file list from
395
+ // the single owner (scanPhasePlans) instead of a local `-PLAN\.md$`
396
+ // filter on the already-read listing — picks up bare PLAN.md, nested
397
+ // plans/, and excludes superseded plans, none of which the prior
398
+ // root-only exact-suffix filter did.
399
+ // #5170: a scan that did not see every plan (an existing nested plans/ that could not be read,
400
+ // SCOPE.TRUNCATED) is `unreadable`, never a short plan set that reports the missing plans' IDs
401
+ // as "Not covered".
402
+ const planSet = (0, gate_evidence_cjs_1.readPlanSetEvidence)(absPhaseDir);
403
+ if (planSet.kind === 'unreadable') {
404
+ unreadable.push({ reason: planSet.reason, span: planSet.span ?? absPhaseDir });
405
+ }
406
+ else {
407
+ planText = planSet.value.map(f => {
408
+ const planPath = node_path_1.default.join(absPhaseDir, f);
409
+ const plan = (0, gate_evidence_cjs_1.readTextEvidence)(planPath);
410
+ // A plan that exists but cannot be read is `unreadable`, never an empty slice of the text the
411
+ // coverage is detected in (it would report every ID it holds as "Not covered").
412
+ if (plan.kind === 'unreadable')
413
+ unreadable.push({ reason: plan.reason, span: planPath });
414
+ return plan.kind === 'found' ? plan.value : '';
375
415
  }).join('\n');
376
416
  }
377
417
  }
378
- catch { /* unreadable */ }
379
418
  // FIX D (#1365): surface decision could-not-parse independently of whether
380
419
  // requirements items exist. Without this, a could-not-parse on decisions is
381
420
  // silently masked whenever REQUIREMENTS.md has ≥1 item — the mismatch must
@@ -411,6 +450,7 @@ function runGapAnalysis(cwd, phaseDir, options = {}) {
411
450
  counts: { total: rows.length, covered, uncovered },
412
451
  phase_dir_read_error: phaseDirReadError,
413
452
  phase_dir_scope: phaseDirScope,
453
+ ...unreadableField(),
414
454
  };
415
455
  }
416
456
  return {
@@ -421,6 +461,7 @@ function runGapAnalysis(cwd, phaseDir, options = {}) {
421
461
  counts: { total: 0, covered: 0, uncovered: 0 },
422
462
  phase_dir_read_error: phaseDirReadError,
423
463
  phase_dir_scope: phaseDirScope,
464
+ ...unreadableField(),
424
465
  };
425
466
  }
426
467
  // #1365: if no items at all, surface a clean no-check message.
@@ -439,6 +480,7 @@ function runGapAnalysis(cwd, phaseDir, options = {}) {
439
480
  counts: { total: 0, covered: 0, uncovered: 0 },
440
481
  phase_dir_read_error: phaseDirReadError,
441
482
  phase_dir_scope: phaseDirScope,
483
+ ...unreadableField(),
442
484
  };
443
485
  }
444
486
  const rows = sortRows([
@@ -458,6 +500,7 @@ function runGapAnalysis(cwd, phaseDir, options = {}) {
458
500
  counts: { total: rows.length, covered, uncovered },
459
501
  phase_dir_read_error: phaseDirReadError,
460
502
  phase_dir_scope: phaseDirScope,
503
+ ...unreadableField(),
461
504
  };
462
505
  }
463
506
  function cmdGapAnalysis(cwd, args, raw) {
@@ -0,0 +1,381 @@
1
+ "use strict";
2
+ /**
3
+ * `check api-coverage.verify-pre` as a gate module (#5139, epic #5056, ADR-5057 §4 first bullet):
4
+ * it returns a `GateResult`; the command router formats it. Imports no io module and performs no
5
+ * direct console/stdout/stderr write (ESLint-enforced).
6
+ *
7
+ * BLOCKING seal-time gate for the ai-integration capability (#1562). Enforces "Full API Coverage by
8
+ * Default — Opt Out, Never Opt In." A phase that integrates an external API/SDK/service may not seal
9
+ * until a COVERAGE.md matrix enumerates the surface and every non-integrated capability is an
10
+ * explicit, reasoned opt-out.
11
+ *
12
+ * Contract (two touch points composed into one check):
13
+ * 1. If COVERAGE.md exists in the phase dir → validate it (acceptance #2).
14
+ * Block on any validation error (empty matrix, OPT-OUT without reason,
15
+ * duplicate/empty capability).
16
+ * 2. If COVERAGE.md is absent → run detectApiIntegration over the phase scope
17
+ * (PLAN.md body, then ROADMAP phase section as fallback). If a strong
18
+ * external-API-integration signal is detected → BLOCK ("integration
19
+ * detected without coverage matrix"). If no signal → PASS (treat as a
20
+ * non-API phase; acceptance #4 — low false positives).
21
+ *
22
+ * The detector is the FALLBACK for the "nobody decided / forgot the matrix" case; the primary path
23
+ * is the plan:pre contribution prompting COVERAGE.md.
24
+ *
25
+ * Argv after the verb: `<phase-dir-or-token>`. Payload: the uniform gate contract
26
+ * `{ block, passed, message, ...details }`.
27
+ */
28
+ var __importDefault = (this && this.__importDefault) || function (mod) {
29
+ return (mod && mod.__esModule) ? mod : { "default": mod };
30
+ };
31
+ Object.defineProperty(exports, "__esModule", { value: true });
32
+ exports.readPhaseScope = readPhaseScope;
33
+ exports.evaluateApiCoverageVerifyPre = evaluateApiCoverageVerifyPre;
34
+ const node_path_1 = __importDefault(require("node:path"));
35
+ const gate_verdict_cjs_1 = require("./gate-verdict.cjs");
36
+ const gate_evidence_cjs_1 = require("./gate-evidence.cjs");
37
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
38
+ const planningWorkspaceMod = require("./planning-workspace.cjs");
39
+ const { planningDir } = planningWorkspaceMod;
40
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
41
+ const phaseLocatorMod = require("./phase-locator.cjs");
42
+ const { findPhaseInternal } = phaseLocatorMod;
43
+ const security_cjs_1 = require("./security.cjs");
44
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
45
+ const roadmapModule = require("./roadmap.cjs");
46
+ const { getRoadmapPhaseWithFallback } = roadmapModule;
47
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
48
+ const apiCoverageMod = require("./api-coverage.cjs");
49
+ const { detectApiIntegration, validateCoverageMatrix } = apiCoverageMod;
50
+ const shell_command_projection_cjs_1 = require("./shell-command-projection.cjs");
51
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
52
+ const planScanMod = require("./plan-scan.cjs");
53
+ const { scanPhasePlans } = planScanMod;
54
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
55
+ const planningScopeMod = require("./planning-scope.cjs");
56
+ const { SCOPE } = planningScopeMod;
57
+ // NOTE: `fs` is used as a namespace object at call time (never destructured at load) so tests can
58
+ // monkeypatch its methods for failure injection.
59
+ function readPhaseScope(projectDir, phaseDir, phaseNumber) {
60
+ const chunks = [];
61
+ let readError = null;
62
+ // A MISSING phase directory is fine (no plans yet → fall through to the
63
+ // roadmap). Checked up front (rather than via a readdirSync catch) because
64
+ // #3183 (lint-plan-count-drift) now sources the plan-file list from the
65
+ // single owner (scanPhasePlans) instead of a local `-PLAN\.md$` readdirSync
66
+ // filter — picks up bare PLAN.md and nested plans/, and excludes
67
+ // superseded plans, none of which the prior root-only exact-suffix filter
68
+ // did.
69
+ // `fs.existsSync` answered `false` for an EACCES on a parent, skipping plans the gate never saw and
70
+ // letting detection run over a roadmap fallback; the stat keeps that case an unreadable scope (#5170).
71
+ const phaseDirStat = (0, gate_evidence_cjs_1.statEvidence)(phaseDir);
72
+ if (phaseDirStat.kind === 'unreadable') {
73
+ return {
74
+ text: '',
75
+ readError: `could not read the phase directory: ${phaseDirStat.reason}`,
76
+ };
77
+ }
78
+ if (phaseDirStat.kind === 'found') {
79
+ const scan = scanPhasePlans(phaseDir);
80
+ if (scan.scope !== SCOPE.COMPLETE) {
81
+ // Directory exists but scanPhasePlans could not see all of it: its own readdirSync(phaseDir)
82
+ // failed (UNREADABLE) or the nested plans/ directory exists and could not be read
83
+ // (TRUNCATED). Only COMPLETE is a real answer; a short plan set is never evidence of "no
84
+ // plans" (#2365 review, #5170), so the gate must not pass over it.
85
+ return {
86
+ text: '',
87
+ readError: `could not read the phase directory: scanPhasePlans reported scope ${scan.scope.toUpperCase()}`,
88
+ };
89
+ }
90
+ const plans = [...scan.planFiles].sort();
91
+ for (const p of plans) {
92
+ const plan = (0, gate_evidence_cjs_1.readTextEvidence)(node_path_1.default.join(phaseDir, p));
93
+ if (plan.kind === 'found') {
94
+ chunks.push(plan.value);
95
+ }
96
+ else if (!readError) {
97
+ // A plan file the scan listed that cannot be read (or vanished since) — record it and keep
98
+ // reading the rest so the message names the first failure.
99
+ readError = `could not read ${p}: ${plan.kind === 'unreadable' ? plan.reason : 'it disappeared since the scan'}`;
100
+ }
101
+ }
102
+ }
103
+ if (readError)
104
+ return { text: chunks.join('\n\n'), readError };
105
+ if (chunks.join('').trim().length > 0)
106
+ return { text: chunks.join('\n\n'), readError: null };
107
+ // Fallback: ONLY this phase's ROADMAP section (not the whole file, which
108
+ // would pollute detection with sibling-phase prose). A MISSING roadmap/section
109
+ // is non-fatal; a roadmap that exists but cannot be read is a real failure.
110
+ if (phaseNumber) {
111
+ try {
112
+ const section = getRoadmapPhaseWithFallback(projectDir, phaseNumber);
113
+ if (section)
114
+ return { text: section, readError: null };
115
+ }
116
+ catch (err) {
117
+ // An absent roadmap/section is "not there yet"; any other failure is a real read failure.
118
+ if ((0, gate_evidence_cjs_1.evidenceFromError)(err, 'ROADMAP.md').kind === 'unreadable') {
119
+ return {
120
+ text: '',
121
+ readError: `could not read the roadmap fallback: ${err instanceof Error ? err.message : String(err)}`,
122
+ };
123
+ }
124
+ }
125
+ }
126
+ return { text: '', readError: null };
127
+ }
128
+ function evaluateApiCoverageVerifyPre(input) {
129
+ const { projectDir, args } = input;
130
+ const phaseArg = typeof args[0] === 'string' ? args[0] : '';
131
+ if (!phaseArg) {
132
+ return (0, gate_verdict_cjs_1.gateUsageFailure)(gate_verdict_cjs_1.GATE_FAILURE_CODE.SDK_MISSING_ARG, 'api-coverage.verify-pre requires a phase argument: check api-coverage.verify-pre <phase-dir-or-token>');
133
+ }
134
+ const pDir = planningDir(projectDir);
135
+ const phasesRoot = node_path_1.default.join(pDir, 'phases');
136
+ // SECURITY (path traversal): the phase argument is taken ONLY as a phase
137
+ // token — its basename — and resolved by findPhaseInternal strictly under
138
+ // .planning/phases/ (or a milestone archive). The raw arg is never used as a
139
+ // path, so `..`, absolute paths, and arbitrary directories cannot reach a
140
+ // file read. Mirrors the schema-drift gate's (gate-schema-drift.cts) token-match approach.
141
+ let token = (0, shell_command_projection_cjs_1.posixNormalize)(phaseArg).split('/').filter(Boolean).pop() || '';
142
+ // A token like ".." or "." carries no phase identity → unresolvable.
143
+ if (token === '.' || token === '..')
144
+ token = '';
145
+ // Not a GSD project (no phases tree at all) → fail-open: nothing to gate. Only an ABSENT tree
146
+ // (`none`) is that answer; one that exists but cannot be examined (an EACCES on a parent) is
147
+ // `unreadable` — `fs.existsSync` said `false` for it and certified "not a GSD project" (#5170).
148
+ const phasesRootStat = (0, gate_evidence_cjs_1.statEvidence)(phasesRoot);
149
+ if (phasesRootStat.kind === 'unreadable') {
150
+ return (0, gate_verdict_cjs_1.gateUnreadable)(true, {
151
+ block: true,
152
+ passed: false,
153
+ coverage_present: false,
154
+ detected: false,
155
+ read_error: phasesRootStat.reason,
156
+ message: `api-coverage: could not examine .planning/phases (${phasesRootStat.reason}) — ` +
157
+ 'refusing to treat an unreadable phases tree as "not a GSD project". ' +
158
+ 'Fix the directory permissions before sealing.',
159
+ });
160
+ }
161
+ if (phasesRootStat.kind === 'none') {
162
+ return (0, gate_verdict_cjs_1.gateVerdict)('pass', false, {
163
+ block: false,
164
+ passed: true,
165
+ coverage_present: false,
166
+ detected: false,
167
+ message: 'api-coverage: no .planning/phases directory; gate skipped (not a GSD project layout)',
168
+ });
169
+ }
170
+ // Resolve the phase dir under the contained phases root.
171
+ let resolvedDir = null;
172
+ let phaseNumber = '';
173
+ if (token) {
174
+ const found = findPhaseInternal(projectDir, token);
175
+ if (found && found.directory) {
176
+ // findPhaseInternal's `directory` is relative to the project root; anchor it to `projectDir`
177
+ // (not the process cwd) so the gate reads the same files in-process as it does from the CLI.
178
+ resolvedDir = node_path_1.default.resolve(projectDir, found.directory);
179
+ phaseNumber = found.phase_number || '';
180
+ }
181
+ }
182
+ if (!resolvedDir) {
183
+ // The phases tree EXISTS but THIS phase could not be resolved. For a
184
+ // BLOCKING gate, fail-closed: a missing phase dir must not silently bypass
185
+ // the coverage requirement. (Distinguished from "no .planning at all"
186
+ // above, which is a genuine non-GSD-project → pass.)
187
+ return (0, gate_verdict_cjs_1.gateVerdict)('block', true, {
188
+ block: true,
189
+ passed: false,
190
+ coverage_present: false,
191
+ detected: false,
192
+ phase_lookup_failed: true,
193
+ message: `api-coverage: could not resolve phase "${phaseArg}" under .planning/phases/. ` +
194
+ 'Resolve the phase directory (or produce COVERAGE.md) before sealing.',
195
+ });
196
+ }
197
+ // Defense-in-depth: the resolved dir must be inside the phases root (or a
198
+ // milestone archive under .planning/milestones).
199
+ const milestonesRoot = node_path_1.default.join(pDir, 'milestones');
200
+ // Lexical containment (ADR-4650): resolvedDir is a directory path, not read
201
+ // through here — mirrors the prior path.resolve(root, candidate)-based check
202
+ // without introducing a filesystem/realpath dependency this defense-in-depth
203
+ // recheck never had.
204
+ if ((0, security_cjs_1.tryWithinRootLexical)(resolvedDir, phasesRoot) === null &&
205
+ (0, security_cjs_1.tryWithinRootLexical)(resolvedDir, milestonesRoot) === null) {
206
+ return (0, gate_verdict_cjs_1.gateVerdict)('block', true, {
207
+ block: true,
208
+ passed: false,
209
+ coverage_present: false,
210
+ detected: false,
211
+ message: 'api-coverage: resolved phase dir escapes .planning/ — refusing to evaluate',
212
+ });
213
+ }
214
+ // (1) locate COVERAGE.md — prefer the exact name, then a single *-COVERAGE.md.
215
+ let coverageFile = '';
216
+ let suffixed = [];
217
+ // #5170 (ADR-5057 §4): a phase directory that EXISTS but cannot be listed is `unreadable` —
218
+ // a COVERAGE.md may be in it — and never falls through to the detector, whose pass would be
219
+ // certified from a directory the gate never saw. An ABSENT directory (`none`) has no matrix and
220
+ // proceeds to detection, as before. The blocking policy is unchanged (fail-closed).
221
+ const listing = (0, gate_evidence_cjs_1.readDirEntriesEvidence)(resolvedDir);
222
+ if (listing.kind === 'unreadable') {
223
+ return (0, gate_verdict_cjs_1.gateUnreadable)(true, {
224
+ block: true,
225
+ passed: false,
226
+ coverage_present: false,
227
+ detected: false,
228
+ read_error: listing.reason,
229
+ message: `api-coverage: could not read the phase directory (${listing.reason}) — ` +
230
+ 'refusing to certify the coverage matrix from a directory that could not be listed. ' +
231
+ 'Fix the directory permissions before sealing.',
232
+ });
233
+ }
234
+ if (listing.kind === 'found') {
235
+ const files = listing.value.filter((e) => e.isFile()).map((e) => e.name);
236
+ const exact = files.find((f) => /^COVERAGE\.md$/i.test(f));
237
+ if (exact) {
238
+ coverageFile = exact;
239
+ }
240
+ else {
241
+ suffixed = files.filter((f) => /-COVERAGE\.md$/i.test(f)).sort();
242
+ if (suffixed.length === 1)
243
+ coverageFile = suffixed[0];
244
+ }
245
+ }
246
+ if (coverageFile) {
247
+ const matrix = (0, gate_evidence_cjs_1.readTextEvidence)(node_path_1.default.join(resolvedDir, coverageFile));
248
+ if (matrix.kind !== 'found') {
249
+ // COVERAGE.md exists but is unreadable (EACCES/EIO/encoding), or vanished between the
250
+ // listing and the read. Fail-closed (policy unchanged) and `unreadable` (outcome).
251
+ return (0, gate_verdict_cjs_1.gateUnreadable)(true, {
252
+ block: true,
253
+ passed: false,
254
+ coverage_present: true,
255
+ message: `api-coverage: COVERAGE.md exists but is unreadable — fix file permissions/encoding before sealing`,
256
+ });
257
+ }
258
+ const matrixText = matrix.value;
259
+ const v = validateCoverageMatrix(matrixText);
260
+ if (v.valid) {
261
+ if (v.none_declared) {
262
+ // The declaration is the human override for the detector — it PASSES
263
+ // even when detection fires (that is acceptance #5's point: the
264
+ // detector is fallible and the declaration is the reasoned overrule).
265
+ // But a contradiction must be VISIBLE, not silent: re-run detection
266
+ // over the phase scope and surface any signals it still finds
267
+ // (#2365 review S-1).
268
+ const declScope = readPhaseScope(projectDir, resolvedDir, phaseNumber);
269
+ const declDetection = detectApiIntegration(declScope.text);
270
+ const declSignals = declDetection.signals.map((s) => ({ verb: s.verb, noun: s.noun }));
271
+ // The declaration legitimately wins even over a read error (it is the
272
+ // human overrule), but if scope was incomplete we say so — the contract
273
+ // is that contradictions stay visible, not silent (#2365 review).
274
+ const baseMsg = declDetection.detected
275
+ ? `api-coverage: COVERAGE.md declares no external API integration, overriding ${declSignals.length} detected signal(s) — confirm the declaration is accurate`
276
+ : 'api-coverage: COVERAGE.md declares no external API integration — matrix not required';
277
+ return (0, gate_verdict_cjs_1.gateVerdict)('pass', false, {
278
+ block: false,
279
+ passed: true,
280
+ coverage_present: true,
281
+ matrix: coverageFile,
282
+ counts: v.counts,
283
+ none_declared: true,
284
+ detected: declDetection.detected,
285
+ ...(declDetection.detected ? { signals: declSignals } : {}),
286
+ ...(declScope.readError ? { scope_read_error: declScope.readError } : {}),
287
+ message: declScope.readError
288
+ ? `${baseMsg} (note: phase scope was incompletely read — ${declScope.readError})`
289
+ : baseMsg,
290
+ });
291
+ }
292
+ return (0, gate_verdict_cjs_1.gateVerdict)('pass', false, {
293
+ block: false,
294
+ passed: true,
295
+ coverage_present: true,
296
+ matrix: coverageFile,
297
+ counts: v.counts,
298
+ message: `api-coverage: matrix present (${v.counts.surface} capabilities, ${v.counts.optout} opt-out)`,
299
+ });
300
+ }
301
+ // Fixed-template message (no raw cell content echoed into the LLM-facing
302
+ // message). The structured `errors` array is safe (row-indexed, no cell
303
+ // values) and travels as data for tooling that wants detail.
304
+ return (0, gate_verdict_cjs_1.gateVerdict)('block', true, {
305
+ block: true,
306
+ passed: false,
307
+ coverage_present: true,
308
+ matrix: coverageFile,
309
+ error_count: v.errors.length,
310
+ errors: v.errors,
311
+ message: `api-coverage: COVERAGE.md has ${v.errors.length} problem(s) — fix the matrix (every capability INTEGRATE or OPT-OUT with a reason) before sealing`,
312
+ });
313
+ }
314
+ if (suffixed.length > 1) {
315
+ return (0, gate_verdict_cjs_1.gateVerdict)('block', true, {
316
+ block: true,
317
+ passed: false,
318
+ coverage_present: false,
319
+ message: `api-coverage: multiple *-COVERAGE.md files found (${suffixed.length}) — consolidate into one COVERAGE.md before sealing`,
320
+ });
321
+ }
322
+ // (2) no matrix — detect whether this phase integrates an external API.
323
+ const scope = readPhaseScope(projectDir, resolvedDir, phaseNumber);
324
+ if (scope.readError) {
325
+ // Fail-closed: an unreadable plan could be the one describing the
326
+ // integration, so we cannot certify "no integration" — block and surface it. The blocking
327
+ // policy is unchanged; the outcome is `unreadable` (exit UNAVAILABLE, #5170).
328
+ return (0, gate_verdict_cjs_1.gateUnreadable)(true, {
329
+ block: true,
330
+ passed: false,
331
+ coverage_present: false,
332
+ detected: false,
333
+ message: `api-coverage: could not read the phase scope (${scope.readError}); ` +
334
+ 'refusing to certify no external-API integration from incomplete scope. ' +
335
+ 'Fix the unreadable plan file, or add a COVERAGE.md declaration.',
336
+ });
337
+ }
338
+ // An EMPTY scope is not a negative verdict. This gate's neighbouring arms
339
+ // already fail closed (unresolvable phase → block; unreadable plan → block),
340
+ // but a phase with no plan body AND no roadmap section fell through to
341
+ // detection over zero bytes and CERTIFIED "no external-API integration" —
342
+ // clearing a blocking seal gate on a probe that examined nothing
343
+ // (ADR-3889 failure class (c), #3909). The discriminator is BYTES EXAMINED,
344
+ // never SIGNALS FOUND: a phase with real plans and no API vocabulary still
345
+ // reaches the pass below unchanged.
346
+ if (scope.text.trim() === '') {
347
+ return (0, gate_verdict_cjs_1.gateVerdict)('block', true, {
348
+ block: true,
349
+ passed: false,
350
+ coverage_present: false,
351
+ detected: false,
352
+ scope_unavailable: true,
353
+ message: 'api-coverage: the phase scope is empty — no plan body and no roadmap section were ' +
354
+ 'found, so nothing was examined. Refusing to certify no external-API integration ' +
355
+ 'from an unestablished scope. Add the phase plan, or add a COVERAGE.md declaration.',
356
+ });
357
+ }
358
+ const detection = detectApiIntegration(scope.text);
359
+ if (detection.detected) {
360
+ // Surface only verb/noun (typed, bounded) — NOT raw prose snippets — so the
361
+ // gate output cannot relay injected PLAN.md instructions to the orchestrator.
362
+ const signals = detection.signals.map((s) => ({ verb: s.verb, noun: s.noun }));
363
+ return (0, gate_verdict_cjs_1.gateVerdict)('block', true, {
364
+ block: true,
365
+ passed: false,
366
+ coverage_present: false,
367
+ detected: true,
368
+ signals,
369
+ message: 'api-coverage: external-API integration detected without a coverage matrix. ' +
370
+ 'Produce COVERAGE.md enumerating the API surface (every capability INTEGRATE or ' +
371
+ 'OPT-OUT with a reason) before sealing. Full coverage is the default.',
372
+ });
373
+ }
374
+ return (0, gate_verdict_cjs_1.gateVerdict)('pass', false, {
375
+ block: false,
376
+ passed: true,
377
+ coverage_present: false,
378
+ detected: false,
379
+ message: 'api-coverage: no external-API integration detected; coverage matrix not required',
380
+ });
381
+ }
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ /**
3
+ * Gate argv parsing — the one `--flag value` / positional splitter the flag-taking `check` verbs
4
+ * share (#5139, epic #5056, design D2/D3).
5
+ *
6
+ * Moved verbatim from `check-command-router.cts` so a gate module can take the argv after its verb
7
+ * and the router's `check predicate` arm can keep using the same parser: there is exactly one, so
8
+ * the flag-taking check verbs cannot drift apart. Pure; no I/O.
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.partitionPredicateArgs = partitionPredicateArgs;
12
+ exports.parsePredicateFlags = parsePredicateFlags;
13
+ /**
14
+ * Split an args array into `--flag value` pairs and the leftover positional
15
+ * tokens, in ONE pass, with the semantics `check predicate` established
16
+ * (#2008): a `--flag` followed by a non-`--` token consumes it as the value
17
+ * (last write wins); a `--flag` with no value stays a bare token and moves to
18
+ * the positionals; everything else is positional. `parsePredicateFlags` is
19
+ * the flags half of this same pass — there is exactly one parser, so the
20
+ * flag-taking check verbs cannot drift apart (#4130 follow-up: `check
21
+ * decision-coverage-plan --context <path>` shares it).
22
+ */
23
+ function partitionPredicateArgs(args) {
24
+ const flags = {};
25
+ const positionals = [];
26
+ for (let i = 0; i < args.length; i++) {
27
+ const a = args[i];
28
+ if (typeof a !== 'string')
29
+ continue;
30
+ if (!a.startsWith('--')) {
31
+ positionals.push(a);
32
+ continue;
33
+ }
34
+ const key = a.slice(2);
35
+ const next = args[i + 1];
36
+ if (key.length > 0 && typeof next === 'string' && !next.startsWith('--')) {
37
+ // defineProperty, not `flags[key] = next`: an own data property for EVERY caller-supplied
38
+ // key. A plain assignment of `--__proto__ v` set nothing (the pair was consumed and its
39
+ // value silently lost), and assigning through a caller-controlled key is the
40
+ // prototype-pollution sink shape.
41
+ Object.defineProperty(flags, key, { value: next, enumerable: true, writable: true, configurable: true });
42
+ i++;
43
+ }
44
+ else {
45
+ positionals.push(a);
46
+ }
47
+ }
48
+ return { flags, positionals };
49
+ }
50
+ /** Parse `--flag value` pairs from an args array into a map (last write wins). */
51
+ function parsePredicateFlags(args) {
52
+ return partitionPredicateArgs(args).flags;
53
+ }