@opengsd/gsd-core 1.10.0 → 1.12.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 (544) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/agents/gsd-code-fixer.md +1 -1
  4. package/agents/gsd-debug-session-manager.md +12 -1
  5. package/agents/gsd-debugger.md +1 -1
  6. package/agents/gsd-doc-synthesizer.md +2 -4
  7. package/agents/gsd-dom-verifier.md +169 -0
  8. package/agents/gsd-eval-auditor.md +1 -1
  9. package/agents/gsd-executor.md +22 -14
  10. package/agents/gsd-framework-selector.md +1 -3
  11. package/agents/gsd-intel-updater.md +1 -1
  12. package/agents/gsd-mempalace-curator.md +5 -3
  13. package/agents/gsd-pattern-mapper.md +11 -0
  14. package/agents/gsd-phase-researcher.md +23 -2
  15. package/agents/gsd-plan-checker.md +50 -53
  16. package/agents/gsd-planner.md +50 -50
  17. package/agents/gsd-project-researcher.md +1 -1
  18. package/agents/gsd-research-synthesizer.md +2 -2
  19. package/agents/gsd-roadmapper.md +15 -11
  20. package/agents/gsd-ui-checker.md +63 -4
  21. package/agents/gsd-ui-researcher.md +41 -3
  22. package/agents/gsd-user-profiler.md +3 -0
  23. package/agents/gsd-verifier.md +13 -4
  24. package/bin/install.js +1448 -1103
  25. package/commands/gsd/code-review.md +1 -1
  26. package/commands/gsd/discuss-phase.md +1 -1
  27. package/commands/gsd/execute-phase.md +1 -1
  28. package/commands/gsd/import.md +1 -1
  29. package/commands/gsd/map-codebase.md +1 -1
  30. package/commands/gsd/mempalace-capture.md +1 -1
  31. package/commands/gsd/mempalace-recall.md +1 -1
  32. package/commands/gsd/new-milestone.md +1 -1
  33. package/commands/gsd/quick.md +9 -5
  34. package/commands/gsd/review-backlog.md +2 -1
  35. package/commands/gsd/verify-work.md +1 -1
  36. package/gsd-core/bin/gsd-tools.cjs +1035 -138
  37. package/gsd-core/bin/lib/active-workstream-store.cjs +146 -22
  38. package/gsd-core/bin/lib/adr-parser.cjs +13 -7
  39. package/gsd-core/bin/lib/agent-install-check.cjs +392 -32
  40. package/gsd-core/bin/lib/api-coverage.cjs +33 -14
  41. package/gsd-core/bin/lib/artifacts.cjs +5 -0
  42. package/gsd-core/bin/lib/assumption-delta.cjs +32 -15
  43. package/gsd-core/bin/lib/audit-command-router.cjs +9 -2
  44. package/gsd-core/bin/lib/audit.cjs +1026 -268
  45. package/gsd-core/bin/lib/broken-windows.cjs +306 -28
  46. package/gsd-core/bin/lib/capability-consent.cjs +149 -15
  47. package/gsd-core/bin/lib/capability-lifecycle.cjs +45 -0
  48. package/gsd-core/bin/lib/capability-lock.cjs +10 -4
  49. package/gsd-core/bin/lib/capability-registry.cjs +845 -130
  50. package/gsd-core/bin/lib/capability-source.cjs +92 -0
  51. package/gsd-core/bin/lib/capability-state.cjs +18 -3
  52. package/gsd-core/bin/lib/capability-trust.cjs +444 -25
  53. package/gsd-core/bin/lib/capability-validator.cjs +700 -40
  54. package/gsd-core/bin/lib/capability-writer.cjs +3 -2
  55. package/gsd-core/bin/lib/check-command-router.cjs +216 -42
  56. package/gsd-core/bin/lib/claude-orchestration.cjs +56 -3
  57. package/gsd-core/bin/lib/cli-exit.cjs +496 -10
  58. package/gsd-core/bin/lib/code-review-depth.cjs +288 -0
  59. package/gsd-core/bin/lib/codex-agent-toml.cjs +735 -0
  60. package/gsd-core/bin/lib/command-aliases.cjs +22 -0
  61. package/gsd-core/bin/lib/command-arg-projection.cjs +144 -14
  62. package/gsd-core/bin/lib/command-roster.cjs +44 -1
  63. package/gsd-core/bin/lib/command-routing-hub.cjs +31 -2
  64. package/gsd-core/bin/lib/commands.cjs +1172 -108
  65. package/gsd-core/bin/lib/commonjs-marker.cjs +12 -6
  66. package/gsd-core/bin/lib/complexity-trigger.cjs +1192 -0
  67. package/gsd-core/bin/lib/config-loader.cjs +187 -23
  68. package/gsd-core/bin/lib/config.cjs +102 -3
  69. package/gsd-core/bin/lib/configuration.cjs +129 -37
  70. package/gsd-core/bin/lib/core-utils.cjs +208 -33
  71. package/gsd-core/bin/lib/decisions.cjs +23 -0
  72. package/gsd-core/bin/lib/edge-probe.cjs +9 -1
  73. package/gsd-core/bin/lib/estimate-cli.cjs +55 -11
  74. package/gsd-core/bin/lib/exit-code-registry.cjs +98 -0
  75. package/gsd-core/bin/lib/fallow-runner.cjs +20 -44
  76. package/gsd-core/bin/lib/frontmatter.cjs +899 -229
  77. package/gsd-core/bin/lib/gap-checker.cjs +95 -10
  78. package/gsd-core/bin/lib/git-base-branch.cjs +276 -39
  79. package/gsd-core/bin/lib/gsd2-import.cjs +10 -1
  80. package/gsd-core/bin/lib/health-diagnostic-rules/agent-install.cjs +101 -0
  81. package/gsd-core/bin/lib/health-diagnostic-rules/config-validation.cjs +348 -0
  82. package/gsd-core/bin/lib/health-diagnostic-rules/consistency.cjs +149 -0
  83. package/gsd-core/bin/lib/health-diagnostic-rules/install-surface-shadowing.cjs +98 -0
  84. package/gsd-core/bin/lib/health-diagnostic-rules/milestone-archive-hygiene.cjs +100 -0
  85. package/gsd-core/bin/lib/health-diagnostic-rules/phase-structure.cjs +222 -0
  86. package/gsd-core/bin/lib/health-diagnostic-rules/roadmap-disk-consistency.cjs +268 -0
  87. package/gsd-core/bin/lib/health-diagnostic-rules/root-existence.cjs +161 -0
  88. package/gsd-core/bin/lib/health-diagnostic-rules/state-consistency.cjs +303 -0
  89. package/gsd-core/bin/lib/health-diagnostic-rules/worktree-health.cjs +187 -0
  90. package/gsd-core/bin/lib/health-diagnostic-types.cjs +68 -0
  91. package/gsd-core/bin/lib/health-diagnostic.cjs +451 -0
  92. package/gsd-core/bin/lib/host-integration.cjs +39 -6
  93. package/gsd-core/bin/lib/host-runtime-detection.cjs +134 -0
  94. package/gsd-core/bin/lib/init-command-router.cjs +118 -21
  95. package/gsd-core/bin/lib/init.cjs +439 -168
  96. package/gsd-core/bin/lib/install-effort-resolver.cjs +73 -30
  97. package/gsd-core/bin/lib/install-engine.cjs +811 -259
  98. package/gsd-core/bin/lib/install-fs-adapter.cjs +262 -0
  99. package/gsd-core/bin/lib/install-model-override-resolver.cjs +235 -0
  100. package/gsd-core/bin/lib/install-profiles.cjs +212 -61
  101. package/gsd-core/bin/lib/install-scope.cjs +270 -0
  102. package/gsd-core/bin/lib/install-shadow-report.cjs +385 -0
  103. package/gsd-core/bin/lib/installed-surface-resolver.cjs +381 -0
  104. package/gsd-core/bin/lib/installer-migration-report.cjs +3 -0
  105. package/gsd-core/bin/lib/installer-migrations/010-antigravity-retire-confighome-artifacts.cjs +169 -0
  106. package/gsd-core/bin/lib/installer-migrations.cjs +148 -38
  107. package/gsd-core/bin/lib/intel.cjs +101 -26
  108. package/gsd-core/bin/lib/io.cjs +170 -15
  109. package/gsd-core/bin/lib/learnings.cjs +85 -14
  110. package/gsd-core/bin/lib/legacy-cleanup.cjs +8 -2
  111. package/gsd-core/bin/lib/markdown-sectionizer.cjs +2 -1
  112. package/gsd-core/bin/lib/markdown-table.cjs +183 -22
  113. package/gsd-core/bin/lib/milestone-lock.cjs +248 -0
  114. package/gsd-core/bin/lib/milestone.cjs +842 -73
  115. package/gsd-core/bin/lib/model-catalog.cjs +232 -16
  116. package/gsd-core/bin/lib/model-resolver.cjs +193 -68
  117. package/gsd-core/bin/lib/normalize-test-command.cjs +1 -1
  118. package/gsd-core/bin/lib/onboard-projection.cjs +5 -1
  119. package/gsd-core/bin/lib/pattern.cjs +122 -0
  120. package/gsd-core/bin/lib/phase-estimation.cjs +18 -9
  121. package/gsd-core/bin/lib/phase-id.cjs +514 -40
  122. package/gsd-core/bin/lib/phase-lifecycle.cjs +52 -19
  123. package/gsd-core/bin/lib/phase-locator.cjs +262 -34
  124. package/gsd-core/bin/lib/phase.cjs +1038 -214
  125. package/gsd-core/bin/lib/plan-dependency-graph.cjs +72 -1
  126. package/gsd-core/bin/lib/plan-document.cjs +263 -0
  127. package/gsd-core/bin/lib/plan-drift-guard.cjs +120 -0
  128. package/gsd-core/bin/lib/plan-scan.cjs +98 -3
  129. package/gsd-core/bin/lib/planning-command-router.cjs +61 -0
  130. package/gsd-core/bin/lib/planning-inspect.cjs +1168 -0
  131. package/gsd-core/bin/lib/planning-scope.cjs +31 -0
  132. package/gsd-core/bin/lib/planning-snapshot.cjs +894 -0
  133. package/gsd-core/bin/lib/planning-workspace.cjs +112 -6
  134. package/gsd-core/bin/lib/probe-core.cjs +5 -2
  135. package/gsd-core/bin/lib/profile-output.cjs +1 -1
  136. package/gsd-core/bin/lib/profile-pipeline-command-router.cjs +50 -7
  137. package/gsd-core/bin/lib/profile-pipeline.cjs +6 -3
  138. package/gsd-core/bin/lib/real-home-guard.cjs +419 -0
  139. package/gsd-core/bin/lib/refactor-trigger-command-router.cjs +766 -0
  140. package/gsd-core/bin/lib/retired-artifact-cleanup.cjs +11 -6
  141. package/gsd-core/bin/lib/review-lane-descriptor.cjs +22 -13
  142. package/gsd-core/bin/lib/review-lane-invocation.cjs +30 -0
  143. package/gsd-core/bin/lib/review-lane-runner.cjs +421 -66
  144. package/gsd-core/bin/lib/review-reviewer-selection.cjs +13 -18
  145. package/gsd-core/bin/lib/roadmap-command-router.cjs +59 -11
  146. package/gsd-core/bin/lib/roadmap-parser.cjs +1006 -184
  147. package/gsd-core/bin/lib/roadmap-upgrade.cjs +37 -10
  148. package/gsd-core/bin/lib/roadmap.cjs +442 -96
  149. package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +702 -52
  150. package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +14 -2
  151. package/gsd-core/bin/lib/runtime-artifact-layout.cjs +459 -55
  152. package/gsd-core/bin/lib/runtime-config-adapter-registry.cjs +3 -2
  153. package/gsd-core/bin/lib/runtime-homes.cjs +69 -3
  154. package/gsd-core/bin/lib/runtime-hooks-surface.cjs +402 -58
  155. package/gsd-core/bin/lib/runtime-identity.cjs +234 -0
  156. package/gsd-core/bin/lib/runtime-name-policy.cjs +3 -1
  157. package/gsd-core/bin/lib/runtime-slash.cjs +96 -8
  158. package/gsd-core/bin/lib/security.cjs +104 -5
  159. package/gsd-core/bin/lib/shell-command-projection.cjs +342 -7
  160. package/gsd-core/bin/lib/smart-entry.cjs +133 -23
  161. package/gsd-core/bin/lib/spec-section.cjs +12 -7
  162. package/gsd-core/bin/lib/state-command-router.cjs +52 -19
  163. package/gsd-core/bin/lib/state-contract.cjs +359 -0
  164. package/gsd-core/bin/lib/state-document.cjs +338 -8
  165. package/gsd-core/bin/lib/state-md-schema.cjs +221 -0
  166. package/gsd-core/bin/lib/state-transition.cjs +846 -176
  167. package/gsd-core/bin/lib/state.cjs +2589 -369
  168. package/gsd-core/bin/lib/surface.cjs +33 -11
  169. package/gsd-core/bin/lib/task-command-router.cjs +111 -1
  170. package/gsd-core/bin/lib/task-content-resolution.cjs +368 -0
  171. package/gsd-core/bin/lib/teams-status.cjs +4 -1
  172. package/gsd-core/bin/lib/text-lines.cjs +80 -0
  173. package/gsd-core/bin/lib/token-scanner.cjs +76 -0
  174. package/gsd-core/bin/lib/uat-predicate.cjs +67 -23
  175. package/gsd-core/bin/lib/uat.cjs +1761 -167
  176. package/gsd-core/bin/lib/ui-consideration-probe.cjs +9 -1
  177. package/gsd-core/bin/lib/ui-frontend-evidence.cjs +157 -0
  178. package/gsd-core/bin/lib/ui-safety-gate.cjs +51 -12
  179. package/gsd-core/bin/lib/unusable-input.cjs +37 -0
  180. package/gsd-core/bin/lib/update-context.cjs +8 -2
  181. package/gsd-core/bin/lib/user-artifact-staging.cjs +705 -0
  182. package/gsd-core/bin/lib/validate-command-router.cjs +2 -2
  183. package/gsd-core/bin/lib/validate.cjs +20 -6
  184. package/gsd-core/bin/lib/vendor/README.md +75 -0
  185. package/gsd-core/bin/lib/vendor/js-yaml.cjs +3014 -0
  186. package/gsd-core/bin/lib/vendor/re2js.cjs +6480 -0
  187. package/gsd-core/bin/lib/vendor/re2js.d.cts +938 -0
  188. package/gsd-core/bin/lib/verification-command-router.cjs +2 -1
  189. package/gsd-core/bin/lib/verification.cjs +272 -9
  190. package/gsd-core/bin/lib/verify-command-grounding.cjs +846 -0
  191. package/gsd-core/bin/lib/verify.cjs +453 -918
  192. package/gsd-core/bin/lib/workstream-inventory-builder.cjs +53 -32
  193. package/gsd-core/bin/lib/workstream-inventory.cjs +63 -10
  194. package/gsd-core/bin/lib/workstream-name-policy.cjs +25 -4
  195. package/gsd-core/bin/lib/workstream.cjs +2 -2
  196. package/gsd-core/bin/lib/worktree-base-ref.cjs +66 -12
  197. package/gsd-core/bin/lib/worktree-safety.cjs +341 -18
  198. package/gsd-core/bin/shared/config-defaults.manifest.json +8 -1
  199. package/gsd-core/bin/shared/config-schema.manifest.json +12 -1
  200. package/gsd-core/bin/shared/exit-codes.json +8 -0
  201. package/gsd-core/bin/shared/exit-codes.sh +20 -0
  202. package/gsd-core/bin/shared/model-catalog.json +8 -1
  203. package/gsd-core/references/agent-contracts.md +44 -26
  204. package/gsd-core/references/api-coverage.md +24 -2
  205. package/gsd-core/references/autonomous-smart-discuss.md +3 -3
  206. package/gsd-core/references/checkpoints.md +39 -21
  207. package/gsd-core/references/context-budget.md +1 -1
  208. package/gsd-core/references/decimal-phase-calculation.md +5 -5
  209. package/gsd-core/references/dispatch-isolation-gate.md +138 -0
  210. package/gsd-core/references/doc-conflict-engine.md +1 -1
  211. package/gsd-core/references/edge-probe.md +8 -0
  212. package/gsd-core/references/execute-mvp-tdd.md +4 -6
  213. package/gsd-core/references/execute-phase-between-wave-reset.md +15 -14
  214. package/gsd-core/references/execute-phase-context-guard.md +1 -1
  215. package/gsd-core/references/execute-phase-response-language.md +1 -1
  216. package/gsd-core/references/execute-phase-wave-guard.md +17 -11
  217. package/gsd-core/references/failing-direction.md +78 -0
  218. package/gsd-core/references/gate-prompts.md +1 -1
  219. package/gsd-core/references/git-integration.md +5 -5
  220. package/gsd-core/references/git-planning-commit.md +5 -4
  221. package/gsd-core/references/gsd-run-resolver.md +1 -1
  222. package/gsd-core/references/loop-hook-dispatch.md +61 -2
  223. package/gsd-core/references/model-profiles.md +12 -4
  224. package/gsd-core/references/mvp-concepts.md +9 -9
  225. package/gsd-core/references/nyquist-compliance.md +74 -0
  226. package/gsd-core/references/offer-next.md +3 -5
  227. package/gsd-core/references/phase-argument-parsing.md +3 -3
  228. package/gsd-core/references/planner-failing-direction.md +53 -0
  229. package/gsd-core/references/planner-guidance.md +3 -9
  230. package/gsd-core/references/planner-human-verify-mode.md +15 -1
  231. package/gsd-core/references/planner-preconditions.md +1 -1
  232. package/gsd-core/references/planner-reviews.md +1 -1
  233. package/gsd-core/references/planner-revision.md +1 -1
  234. package/gsd-core/references/planner-verify-command-grounding.md +17 -0
  235. package/gsd-core/references/planning-config.md +44 -13
  236. package/gsd-core/references/reviewer-instances.md +31 -0
  237. package/gsd-core/references/revision-loop.md +1 -1
  238. package/gsd-core/references/runtime-aware-dispatch.md +1 -1
  239. package/gsd-core/references/specless-probe-fallback.md +1 -1
  240. package/gsd-core/references/tdd.md +1 -3
  241. package/gsd-core/references/ui-brand.md +65 -21
  242. package/gsd-core/references/ui-consideration-probe.md +1 -1
  243. package/gsd-core/references/universal-anti-patterns.md +5 -5
  244. package/gsd-core/references/verifier-phase-gates.md +192 -0
  245. package/gsd-core/references/verify-command-path-resolvability.md +42 -0
  246. package/gsd-core/references/verify-mvp-mode.md +2 -2
  247. package/gsd-core/references/workstream-flag.md +33 -17
  248. package/gsd-core/templates/README.md +1 -1
  249. package/gsd-core/templates/SECURITY.md +3 -3
  250. package/gsd-core/templates/UI-SPEC.md +25 -3
  251. package/gsd-core/templates/VALIDATION.md +3 -3
  252. package/gsd-core/templates/discussion-log.md +1 -1
  253. package/gsd-core/templates/phase-prompt.md +5 -4
  254. package/gsd-core/templates/state.md +11 -4
  255. package/gsd-core/templates/verification-report.md +9 -1
  256. package/gsd-core/workflows/_runtime-launcher.snippet.sh +1 -1
  257. package/gsd-core/workflows/add-backlog.md +1 -1
  258. package/gsd-core/workflows/add-phase.md +3 -3
  259. package/gsd-core/workflows/add-tests.md +3 -8
  260. package/gsd-core/workflows/add-todo.md +1 -1
  261. package/gsd-core/workflows/ai-integration-phase.md +13 -20
  262. package/gsd-core/workflows/audit-fix.md +12 -3
  263. package/gsd-core/workflows/audit-milestone.md +9 -9
  264. package/gsd-core/workflows/audit-uat.md +17 -2
  265. package/gsd-core/workflows/autonomous/steps/converge-fail-fast.md +2 -2
  266. package/gsd-core/workflows/autonomous.md +11 -27
  267. package/gsd-core/workflows/check-todos.md +1 -1
  268. package/gsd-core/workflows/cleanup.md +64 -5
  269. package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +14 -4
  270. package/gsd-core/workflows/code-review-fix.md +38 -11
  271. package/gsd-core/workflows/code-review.md +159 -52
  272. package/gsd-core/workflows/complete-milestone.md +151 -23
  273. package/gsd-core/workflows/debug.md +12 -8
  274. package/gsd-core/workflows/diagnose-issues.md +47 -15
  275. package/gsd-core/workflows/discuss-phase/modes/advisor.md +1 -1
  276. package/gsd-core/workflows/discuss-phase/modes/chain.md +5 -8
  277. package/gsd-core/workflows/discuss-phase/modes/default.md +1 -1
  278. package/gsd-core/workflows/discuss-phase/modes/text.md +1 -1
  279. package/gsd-core/workflows/discuss-phase-assumptions/steps/auto-advance-dispatch.md +1 -3
  280. package/gsd-core/workflows/discuss-phase-assumptions.md +4 -3
  281. package/gsd-core/workflows/discuss-phase.md +1 -1
  282. package/gsd-core/workflows/do.md +3 -6
  283. package/gsd-core/workflows/docs-update.md +5 -4
  284. package/gsd-core/workflows/edit-phase.md +27 -2
  285. package/gsd-core/workflows/eval-review.md +7 -14
  286. package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +1 -1
  287. package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +142 -15
  288. package/gsd-core/workflows/execute-phase/steps/gap-closure-artifacts.md +1 -1
  289. package/gsd-core/workflows/execute-phase/steps/partial-wave.md +1 -1
  290. package/gsd-core/workflows/execute-phase/steps/per-plan-executor-routing.md +77 -0
  291. package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +24 -4
  292. package/gsd-core/workflows/execute-phase/steps/post-merge-gate.md +2 -2
  293. package/gsd-core/workflows/execute-phase/steps/protected-branch.md +21 -0
  294. package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +2 -2
  295. package/gsd-core/workflows/execute-phase/steps/wave-post-gate-hooks.md +39 -0
  296. package/gsd-core/workflows/execute-phase.md +72 -100
  297. package/gsd-core/workflows/execute-plan.md +52 -15
  298. package/gsd-core/workflows/explore.md +131 -4
  299. package/gsd-core/workflows/extract-learnings.md +1 -1
  300. package/gsd-core/workflows/fast.md +10 -2
  301. package/gsd-core/workflows/forensics.md +1 -1
  302. package/gsd-core/workflows/graduation.md +5 -5
  303. package/gsd-core/workflows/health.md +76 -10
  304. package/gsd-core/workflows/import.md +18 -15
  305. package/gsd-core/workflows/inbox.md +4 -5
  306. package/gsd-core/workflows/ingest-docs.md +49 -16
  307. package/gsd-core/workflows/insert-phase.md +5 -5
  308. package/gsd-core/workflows/list-seeds.md +5 -3
  309. package/gsd-core/workflows/list-workspaces.md +1 -1
  310. package/gsd-core/workflows/manager.md +12 -23
  311. package/gsd-core/workflows/map-codebase.md +1 -1
  312. package/gsd-core/workflows/milestone-summary.md +1 -1
  313. package/gsd-core/workflows/mvp-phase.md +8 -5
  314. package/gsd-core/workflows/new-milestone.md +22 -29
  315. package/gsd-core/workflows/new-project/steps/auto-mode-config.md +1 -1
  316. package/gsd-core/workflows/new-project.md +26 -40
  317. package/gsd-core/workflows/new-workspace.md +1 -1
  318. package/gsd-core/workflows/next.md +14 -2
  319. package/gsd-core/workflows/pause-work.md +1 -1
  320. package/gsd-core/workflows/plan-phase/steps/adr-ingest-express-path.md +1 -1
  321. package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +1 -1
  322. package/gsd-core/workflows/plan-phase/steps/prd-express-path.md +2 -4
  323. package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +3 -3
  324. package/gsd-core/workflows/plan-phase.md +162 -59
  325. package/gsd-core/workflows/plan-review-convergence.md +96 -11
  326. package/gsd-core/workflows/plant-seed.md +2 -2
  327. package/gsd-core/workflows/pr-branch.md +187 -51
  328. package/gsd-core/workflows/profile-user.md +16 -14
  329. package/gsd-core/workflows/progress.md +61 -18
  330. package/gsd-core/workflows/quick/steps/discussion-phase.md +1 -3
  331. package/gsd-core/workflows/quick/steps/plan-checker-loop.md +5 -7
  332. package/gsd-core/workflows/quick/steps/quick-verification.md +28 -9
  333. package/gsd-core/workflows/quick/steps/research-phase.md +4 -6
  334. package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +3 -3
  335. package/gsd-core/workflows/quick.md +55 -44
  336. package/gsd-core/workflows/remove-phase.md +4 -4
  337. package/gsd-core/workflows/remove-workspace.md +2 -2
  338. package/gsd-core/workflows/resume-project.md +8 -12
  339. package/gsd-core/workflows/review.md +219 -20
  340. package/gsd-core/workflows/scan.md +1 -1
  341. package/gsd-core/workflows/secure-phase.md +3 -3
  342. package/gsd-core/workflows/session-report.md +2 -1
  343. package/gsd-core/workflows/settings-advanced.md +7 -9
  344. package/gsd-core/workflows/settings-integrations.md +64 -31
  345. package/gsd-core/workflows/settings.md +69 -7
  346. package/gsd-core/workflows/ship.md +116 -50
  347. package/gsd-core/workflows/sketch-wrap-up.md +11 -17
  348. package/gsd-core/workflows/sketch.md +12 -18
  349. package/gsd-core/workflows/smart-entry.md +3 -5
  350. package/gsd-core/workflows/spec-phase.md +53 -13
  351. package/gsd-core/workflows/spike-wrap-up.md +7 -11
  352. package/gsd-core/workflows/spike.md +20 -31
  353. package/gsd-core/workflows/stats.md +2 -2
  354. package/gsd-core/workflows/sync-skills.md +64 -9
  355. package/gsd-core/workflows/thread.md +11 -7
  356. package/gsd-core/workflows/transition.md +49 -14
  357. package/gsd-core/workflows/ui-phase.md +15 -21
  358. package/gsd-core/workflows/ui-review.md +8 -12
  359. package/gsd-core/workflows/ultraplan-phase.md +5 -13
  360. package/gsd-core/workflows/undo.md +8 -16
  361. package/gsd-core/workflows/update.md +7 -11
  362. package/gsd-core/workflows/validate-phase.md +3 -3
  363. package/gsd-core/workflows/verify-work/steps/automated-ui-verification.md +25 -1
  364. package/gsd-core/workflows/verify-work/steps/mvp-uat-framing.md +1 -1
  365. package/gsd-core/workflows/verify-work.md +66 -25
  366. package/hooks/dist/gsd-agent-isolation-guard.js +158 -30
  367. package/hooks/dist/gsd-check-update-worker.js +56 -13
  368. package/hooks/dist/gsd-check-update.js +19 -1
  369. package/hooks/dist/gsd-config-reload.js +18 -12
  370. package/hooks/dist/gsd-context-monitor.js +19 -10
  371. package/hooks/dist/gsd-cursor-post-tool.js +3 -1
  372. package/hooks/dist/gsd-cursor-pre-tool.js +2 -3
  373. package/hooks/dist/gsd-cursor-session-start.js +2 -1
  374. package/hooks/dist/gsd-cursor-stop.js +2 -1
  375. package/hooks/dist/gsd-cursor-subagent-start.js +83 -3
  376. package/hooks/dist/gsd-cursor-subagent-stop.js +6 -3
  377. package/hooks/dist/gsd-ensure-canonical-path.js +2 -1
  378. package/hooks/dist/gsd-graphify-update.sh +22 -18
  379. package/hooks/dist/gsd-node-runner.sh +76 -0
  380. package/hooks/dist/gsd-phase-boundary.sh +1 -0
  381. package/hooks/dist/gsd-prompt-guard.js +37 -27
  382. package/hooks/dist/gsd-read-guard.js +16 -7
  383. package/hooks/dist/gsd-read-injection-scanner.js +55 -32
  384. package/hooks/dist/gsd-session-state.sh +1 -0
  385. package/hooks/dist/gsd-statusline.js +231 -24
  386. package/hooks/dist/gsd-update-banner.js +22 -1
  387. package/hooks/dist/gsd-validate-commit.sh +80 -6
  388. package/hooks/dist/gsd-windsurf-pre-command.js +16 -11
  389. package/hooks/dist/gsd-windsurf-pre-write.js +22 -13
  390. package/hooks/dist/gsd-workflow-guard.js +162 -46
  391. package/hooks/dist/gsd-worktree-path-guard.js +36 -21
  392. package/hooks/dist/gsd-write-guard.js +35 -25
  393. package/hooks/dist/lib/cli-exit.js +560 -0
  394. package/hooks/dist/lib/exit-code-registry.js +98 -0
  395. package/hooks/dist/lib/git-cmd.js +92 -59
  396. package/hooks/dist/lib/git-probe.js +84 -0
  397. package/hooks/dist/lib/hook-exit.js +81 -0
  398. package/hooks/dist/lib/injection-patterns.js +45 -0
  399. package/hooks/dist/lib/isolation-deny-reason.js +39 -0
  400. package/hooks/dist/lib/isolation-sentinel.js +9 -0
  401. package/hooks/dist/managed-hooks-registry.cjs +3 -0
  402. package/hooks/gsd-agent-isolation-guard.js +158 -30
  403. package/hooks/gsd-check-update-worker.js +56 -13
  404. package/hooks/gsd-check-update.js +19 -1
  405. package/hooks/gsd-config-reload.js +18 -12
  406. package/hooks/gsd-context-monitor.js +19 -10
  407. package/hooks/gsd-cursor-post-tool.js +3 -1
  408. package/hooks/gsd-cursor-pre-tool.js +2 -3
  409. package/hooks/gsd-cursor-session-start.js +2 -1
  410. package/hooks/gsd-cursor-stop.js +2 -1
  411. package/hooks/gsd-cursor-subagent-start.js +83 -3
  412. package/hooks/gsd-cursor-subagent-stop.js +6 -3
  413. package/hooks/gsd-ensure-canonical-path.js +2 -1
  414. package/hooks/gsd-graphify-update.sh +22 -18
  415. package/hooks/gsd-node-runner.sh +76 -0
  416. package/hooks/gsd-phase-boundary.sh +1 -0
  417. package/hooks/gsd-prompt-guard.js +37 -27
  418. package/hooks/gsd-read-guard.js +16 -7
  419. package/hooks/gsd-read-injection-scanner.js +55 -32
  420. package/hooks/gsd-session-state.sh +1 -0
  421. package/hooks/gsd-statusline.js +231 -24
  422. package/hooks/gsd-update-banner.js +22 -1
  423. package/hooks/gsd-validate-commit.sh +80 -6
  424. package/hooks/gsd-windsurf-pre-command.js +16 -11
  425. package/hooks/gsd-windsurf-pre-write.js +22 -13
  426. package/hooks/gsd-workflow-guard.js +162 -46
  427. package/hooks/gsd-worktree-path-guard.js +36 -21
  428. package/hooks/gsd-write-guard.js +35 -25
  429. package/hooks/lib/cli-exit.js +560 -0
  430. package/hooks/lib/exit-code-registry.js +98 -0
  431. package/hooks/lib/git-cmd.js +92 -59
  432. package/hooks/lib/git-probe.js +84 -0
  433. package/hooks/lib/hook-exit.js +81 -0
  434. package/hooks/lib/injection-patterns.js +45 -0
  435. package/hooks/lib/isolation-deny-reason.js +39 -0
  436. package/hooks/lib/isolation-sentinel.js +9 -0
  437. package/hooks/managed-hooks-registry.cjs +3 -0
  438. package/package.json +28 -11
  439. package/pi/gsd.cjs +19 -5
  440. package/scripts/base64-scan.sh +74 -12
  441. package/scripts/baselines/planning-prompt-drift-baseline.json +4 -0
  442. package/scripts/baselines/planning-snapshot-bypass-baseline.json +12 -0
  443. package/scripts/baselines/unreachable-guard-drift-baseline.json +4 -0
  444. package/scripts/build-hooks.js +5 -0
  445. package/scripts/changeset/lint.cjs +60 -5
  446. package/scripts/check-alias-drift.cjs +7 -43
  447. package/scripts/check-contract-drift.cjs +297 -0
  448. package/scripts/check-glossary-refs.cjs +77 -15
  449. package/scripts/check-mutation-score-ratchet.cjs +156 -0
  450. package/scripts/ci-check-job-near-cap.cjs +49 -0
  451. package/scripts/ci-pr-mergeability.cjs +262 -0
  452. package/scripts/ci-test-scope.cjs +64 -14
  453. package/scripts/ci-timeout-report.cjs +230 -0
  454. package/scripts/command-contract-helpers.cjs +903 -1
  455. package/scripts/docs-guard-registry.cjs +396 -0
  456. package/scripts/gen-adr-index.cjs +728 -38
  457. package/scripts/gen-capability-registry.cjs +11 -21
  458. package/scripts/gen-context-index.cjs +2 -11
  459. package/scripts/gen-exit-code-docs.cjs +318 -0
  460. package/scripts/gen-exit-code-registry.cjs +891 -0
  461. package/scripts/gen-features.cjs +836 -0
  462. package/scripts/gen-health-docs.cjs +390 -0
  463. package/scripts/gen-hooks-cli-exit.cjs +239 -0
  464. package/scripts/gen-install-tree-fixtures.cjs +2 -2
  465. package/scripts/gen-inventory-manifest.cjs +50 -4
  466. package/scripts/gen-loop-host-contract.cjs +138 -25
  467. package/scripts/gen-registry.cjs +3 -14
  468. package/scripts/gen-scripts-cli-exit.cjs +185 -0
  469. package/scripts/gen-state-md-docs.cjs +727 -0
  470. package/scripts/{test-failure-reasons.cjs → gsd-test-gate-reasons.cjs} +6 -0
  471. package/scripts/lib/alias-drift-families.cjs +46 -0
  472. package/scripts/lib/ci-job-timing.cjs +72 -0
  473. package/scripts/lib/cli-exit.cjs +546 -44
  474. package/scripts/lib/drift-scan.cjs +308 -0
  475. package/scripts/lib/exit-code-registry.cjs +98 -0
  476. package/scripts/lib/ndjson-reporter.cjs +119 -0
  477. package/scripts/lint-allow-test-rule-refs.allowlist.json +1 -26
  478. package/scripts/lint-allow-test-rule-refs.effective-ceiling.json +4 -0
  479. package/scripts/lint-allow-test-rule-refs.unverified-ceiling.json +3 -0
  480. package/scripts/lint-canary-version-leak.cjs +73 -0
  481. package/scripts/lint-command-contract.cjs +96 -13
  482. package/scripts/lint-completion-predicate-drift.cjs +933 -0
  483. package/scripts/lint-completion-ratio-drift.cjs +214 -0
  484. package/scripts/lint-default-flip-documentation.cjs +193 -0
  485. package/scripts/lint-docs-guard-registration.cjs +495 -0
  486. package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +193 -0
  487. package/scripts/lint-eslint-glob-coverage.allowlist.json +38 -0
  488. package/scripts/lint-eslint-glob-coverage.cjs +340 -0
  489. package/scripts/{lint-fix-has-regression-test.cjs → lint-fix-has-regression-tests.cjs} +12 -6
  490. package/scripts/lint-frontmatter-scalar-broad-grep.cjs +237 -0
  491. package/scripts/lint-health-diagnostic-rule-table.cjs +461 -0
  492. package/scripts/lint-hooks-runtime-build-seam.cjs +262 -0
  493. package/scripts/lint-milestone-window-drift.cjs +468 -0
  494. package/scripts/lint-mutation-test-derivation-drift.cjs +86 -0
  495. package/scripts/lint-phase-enumeration-drift.cjs +492 -0
  496. package/scripts/lint-plan-count-drift.cjs +318 -0
  497. package/scripts/lint-planning-artifact-writer-drift.cjs +398 -0
  498. package/scripts/lint-planning-prompt-drift.cjs +471 -0
  499. package/scripts/lint-planning-snapshot-bypass-drift.cjs +544 -0
  500. package/scripts/lint-regression-test-names.cjs +15 -13
  501. package/scripts/lint-removed-but-needed.cjs +488 -0
  502. package/scripts/lint-seam-enforcement.cjs +182 -0
  503. package/scripts/lint-slug-derivation-drift.cjs +921 -0
  504. package/scripts/lint-source-test-name-collision.cjs +241 -0
  505. package/scripts/lint-state-field-drift.cjs +805 -0
  506. package/scripts/lint-state-write-path-drift.cjs +950 -0
  507. package/scripts/lint-test-file-count.allowlist.json +137 -8
  508. package/scripts/lint-test-file-count.cjs +25 -3
  509. package/scripts/lint-unreachable-guard-drift.cjs +830 -0
  510. package/scripts/lint-vendored-deps.cjs +297 -0
  511. package/scripts/mutation-matrix.cjs +599 -50
  512. package/scripts/pr-changed-files.cjs +63 -0
  513. package/scripts/pr-template-policy.cjs +14 -4
  514. package/scripts/prompt-injection-scan.sh +100 -14
  515. package/scripts/require-issue-link-policy.cjs +192 -0
  516. package/scripts/secret-scan.sh +75 -13
  517. package/scripts/select-docs-guards.cjs +56 -0
  518. package/scripts/sync-runtime-launcher.cjs +24 -7
  519. package/skills/gsd-autonomous/SKILL.md +0 -1
  520. package/skills/gsd-code-review/SKILL.md +1 -1
  521. package/skills/gsd-discuss-phase/SKILL.md +1 -1
  522. package/skills/gsd-execute-phase/SKILL.md +1 -2
  523. package/skills/gsd-import/SKILL.md +1 -1
  524. package/skills/gsd-map-codebase/SKILL.md +1 -1
  525. package/skills/gsd-mempalace-capture/SKILL.md +1 -1
  526. package/skills/gsd-mempalace-recall/SKILL.md +1 -1
  527. package/skills/gsd-new-milestone/SKILL.md +1 -1
  528. package/skills/gsd-next/SKILL.md +0 -1
  529. package/skills/gsd-plan-phase/SKILL.md +0 -1
  530. package/skills/gsd-progress/SKILL.md +0 -1
  531. package/skills/gsd-quick/SKILL.md +9 -5
  532. package/skills/gsd-review-backlog/SKILL.md +2 -1
  533. package/skills/gsd-stats/SKILL.md +0 -1
  534. package/skills/gsd-verify-work/SKILL.md +1 -1
  535. package/vscode/package.json +1 -1
  536. package/bin/lib/ui-safety-gate.cjs +0 -107
  537. package/gsd-core/workflows/discovery-phase.md +0 -298
  538. package/gsd-core/workflows/plan-milestone-gaps.md +0 -281
  539. package/gsd-core/workflows/verify-phase.md +0 -574
  540. package/scripts/affected-tests-lib.cjs +0 -554
  541. package/scripts/lint-allow-test-rule-refs.cjs +0 -162
  542. package/scripts/lint-emitted-drift-ack.cjs +0 -344
  543. package/scripts/run-affected-tests.cjs +0 -7
  544. package/scripts/run-tests.cjs +0 -1051
@@ -19,14 +19,66 @@ const modelProfiles = require("./model-profiles.cjs");
19
19
  const { MODEL_PROFILES } = modelProfiles;
20
20
  const runtime_homes_cjs_1 = require("./runtime-homes.cjs");
21
21
  const runtime_name_policy_cjs_1 = require("./runtime-name-policy.cjs");
22
+ // #3242 — model-catalog is a genuine leaf (only node:path + its own JSON), which is
23
+ // exactly why Phase 1 (#3241) moved isAnthropicFlavoredModel there: this module can
24
+ // consume it without dragging model-resolver's config-loader chain into a
25
+ // pure read/verify surface.
26
+ const model_catalog_cjs_1 = require("./model-catalog.cjs");
27
+ // #3243 — the Codex `.toml` block-range/BOM/scan primitives moved into the typed
28
+ // IR module (Phase 3), which this reader now imports rather than defining
29
+ // locally. Behavior is unchanged: scanTomlLines/stripBOM here are the exact
30
+ // same lenient functions that used to live in this file — see
31
+ // codex-agent-toml.cts's module header for the reader/writer reconciliation.
32
+ // #3897 CAUSE A fix: `deriveCodexSandboxMode` needs the resolved `tools:`
33
+ // frontmatter VALUE, not raw content — this module used to reach that via
34
+ // `runtime-artifact-conversion.cjs`'s general-purpose
35
+ // `extractFrontmatterAndBody`/`extractFrontmatterField`, but that module's
36
+ // dependency chain (`command-roster.cjs` -> `scripts/fix-slash-commands.cjs`,
37
+ // a dev-only repo script) does not resolve from an installed tree — any test
38
+ // exercising a synthetic install dir blew up at module load. `codex-agent-toml.cjs`
39
+ // is already imported here, is a genuine leaf (node builtins only, zero
40
+ // side effects), and now exports `extractToolsValue` — a single-purpose
41
+ // `tools:`-VALUE reader (inline AND YAML block-list form, #3897 list-form
42
+ // parse fix), not a general frontmatter parser — for exactly this caller,
43
+ // shared with `bin/install.js`'s emitter so the two sandbox-feeding paths
44
+ // can never silently disagree, and no fourth copy of frontmatter parsing is
45
+ // added.
46
+ const codex_agent_toml_cjs_1 = require("./codex-agent-toml.cjs");
47
+ /**
48
+ * Frozen reason enum for {@link checkCodexModelPosture}. Per CONTRIBUTING's
49
+ * typed-IR rule ("Error / status / reason → a frozen enum"): callers and tests
50
+ * assert on these wire values, never on prose. Adding a member is a deliberate
51
+ * three-way coordinated change — enum, emitting site, and the enum-lock test.
52
+ */
53
+ const POSTURE_REASON = Object.freeze({
54
+ ANTHROPIC_FLAVORED_MODEL: 'anthropic_flavored_model',
55
+ ORPHANED_REASONING_EFFORT: 'orphaned_reasoning_effort',
56
+ UNREADABLE: 'unreadable',
57
+ NOT_CODEX: 'not_codex',
58
+ AGENTS_DIR_MISSING: 'agents_dir_missing',
59
+ });
60
+ // Matches the value-truncation convention in bin/install.js's
61
+ // _warnCodexModelOverrideDropped: values over 64 chars are capped so an
62
+ // oversized or secret-shaped config value can never reach a report in full.
63
+ function truncatePostureValue(value) {
64
+ return value.length > 64 ? `${value.slice(0, 64)}…` : value;
65
+ }
22
66
  /**
23
67
  * Resolve the agents directory for the given runtime.
24
68
  *
25
69
  * Priority:
26
70
  * 1. GSD_AGENTS_DIR env var (explicit override, any runtime)
27
- * 2. For claude runtime: __dirname-relative path (agents/ sibling of gsd-core/)
28
- * This is correct for both repo runs and real installs (the runtime config dir's
29
- * agents/ folder) because gsd-tools.cjs lives inside gsd-core/bin/ in both cases.
71
+ * 2. For claude runtime: __dirname-relative path (agents/ sibling of
72
+ * gsd-core/) — correct for repo runs and runtime-config-dir installs,
73
+ * where the sibling agents/ IS the user's agents dir — UNLESS that path
74
+ * carries an exact node_modules segment. gsd-tools.cjs lives inside
75
+ * gsd-core/bin/ in every install shape, but on an npm-global install
76
+ * gsd-core/ sits inside the package (not the runtime config dir) and the
77
+ * package ships its own agents/, so the install-relative path resolves
78
+ * to the bundled copy and the check validates the package against
79
+ * itself — agents_installed can never be false. In that case resolve
80
+ * getGlobalConfigDir('claude')/agents (honours CLAUDE_CONFIG_DIR) like
81
+ * every other runtime (#3203).
30
82
  * 3. For non-claude runtimes with a manifest-backed project-local install:
31
83
  * <projectRoot>/<localConfigDir>/agents (or <projectRoot>/agents when
32
84
  * the runtime's local install targets the project root). Requiring the
@@ -43,7 +95,16 @@ function getAgentsDir(runtime, projectRoot) {
43
95
  }
44
96
  const resolved = runtime ?? (process.env['GSD_RUNTIME'] || 'claude');
45
97
  if (resolved === 'claude') {
46
- return node_path_1.default.join(__dirname, '..', '..', '..', 'agents');
98
+ const installRelative = node_path_1.default.join(__dirname, '..', '..', '..', 'agents');
99
+ // #3203: a lexical guard, not an install-shape test. It targets the
100
+ // layouts where the sibling agents/ is the package's own bundled copy and
101
+ // the check would otherwise validate the package against itself; a path
102
+ // merely carrying a directory of that name resolves the same way, and a
103
+ // non-empty GSD_AGENTS_DIR overrides both.
104
+ if (installRelative.split(node_path_1.default.sep).includes('node_modules')) {
105
+ return node_path_1.default.join((0, runtime_homes_cjs_1.getGlobalConfigDir)('claude'), 'agents');
106
+ }
107
+ return installRelative;
47
108
  }
48
109
  if (projectRoot) {
49
110
  // eslint-disable-next-line @typescript-eslint/no-require-imports
@@ -94,18 +155,7 @@ function checkAgentsInstalled(runtime, projectRoot) {
94
155
  };
95
156
  }
96
157
  for (const agent of expectedAgents) {
97
- const agentFile = node_path_1.default.join(agentsDir, `${agent}.md`);
98
- const agentFileCopilot = node_path_1.default.join(agentsDir, `${agent}.agent.md`);
99
- const agentFileCodex = node_path_1.default.join(agentsDir, `${agent}.toml`);
100
- const agentFileKimiYaml = node_path_1.default.join(agentsDir, 'subagents', `${agent}.yaml`);
101
- const agentFileKimiPrompt = node_path_1.default.join(agentsDir, 'subagents', `${agent}.md`);
102
- const kimiAgentInstalled = resolvedRuntime === 'kimi' &&
103
- node_fs_1.default.existsSync(agentFileKimiYaml) &&
104
- node_fs_1.default.existsSync(agentFileKimiPrompt);
105
- if (node_fs_1.default.existsSync(agentFile) ||
106
- node_fs_1.default.existsSync(agentFileCopilot) ||
107
- node_fs_1.default.existsSync(agentFileCodex) ||
108
- kimiAgentInstalled) {
158
+ if (agentFileExists(agentsDir, agent, resolvedRuntime)) {
109
159
  installed.push(agent);
110
160
  }
111
161
  else {
@@ -119,22 +169,13 @@ function checkAgentsInstalled(runtime, projectRoot) {
119
169
  // when the plain presence check above passed (e.g. .md present, .toml absent).
120
170
  // If no manifest is found the check is a no-op (graceful for claude/bundled).
121
171
  const incomplete = [];
122
- const manifestPath = node_path_1.default.join(node_path_1.default.dirname(agentsDir), 'gsd-file-manifest.json');
123
- let manifestFiles = {};
124
- try {
125
- const raw = node_fs_1.default.readFileSync(manifestPath, 'utf8');
126
- const parsed = JSON.parse(raw);
127
- if (parsed !== null &&
128
- typeof parsed === 'object' &&
129
- 'files' in parsed &&
130
- typeof parsed['files'] === 'object' &&
131
- parsed['files'] !== null) {
132
- manifestFiles = parsed['files'];
133
- }
134
- }
135
- catch {
136
- // No manifest or unreadable — completeness check is skipped
137
- }
172
+ // #2872: the manifest read is the Installer Migration Module's, not a
173
+ // fourth private copy of it. Lazily required — matching this file's own
174
+ // capability-registry idiom — so a pure read/verify surface on the
175
+ // init/verify hot path takes no new static dependency.
176
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
177
+ const { readInstallManifest } = require('./installer-migrations.cjs');
178
+ const manifestFiles = readInstallManifest(node_path_1.default.dirname(agentsDir)).files;
138
179
  if (Object.keys(manifestFiles).length > 0) {
139
180
  for (const agent of expectedAgents) {
140
181
  // Find all manifest keys that belong to this agent:
@@ -169,7 +210,326 @@ function checkAgentsInstalled(runtime, projectRoot) {
169
210
  agent_runtime: resolvedRuntime,
170
211
  };
171
212
  }
213
+ /**
214
+ * Validate Codex `.toml` agent files for Anthropic-flavored `model` pins and
215
+ * orphaned `model_reasoning_effort` values (ADR-2313 D6, #3242).
216
+ *
217
+ * A new sibling export to {@link checkAgentsInstalled}, deliberately — that
218
+ * function carries 33 upstream dependents and cyclomatic complexity 25, so this
219
+ * posture check gets zero new branches there (see 40-design.md "Rejected" #1).
220
+ * Presence is `checkAgentsInstalled`'s job; this function's job starts only once
221
+ * the runtime is confirmed `codex` and only inspects posture, never presence.
222
+ *
223
+ * Read-only: detects, never repairs (repair is Phase 3, #3243).
224
+ *
225
+ * @param runtime - the active runtime name; defaults to GSD_RUNTIME env, then 'claude'
226
+ * @param projectRoot - canonical project root for local-install discovery
227
+ */
228
+ function checkCodexModelPosture(runtime, projectRoot) {
229
+ // Short-circuit BEFORE any filesystem access: a non-codex runtime must never
230
+ // have its agents directory resolved or a stray .toml inspected, however
231
+ // violating that file's contents would be if it were ever read (#3242 row 25).
232
+ const resolvedRuntime = runtime ?? (process.env['GSD_RUNTIME'] || 'claude');
233
+ if (resolvedRuntime !== 'codex') {
234
+ return {
235
+ ok: true,
236
+ violations: [],
237
+ checked: [],
238
+ agents_dir: '',
239
+ agent_runtime: resolvedRuntime,
240
+ reason: POSTURE_REASON.NOT_CODEX,
241
+ };
242
+ }
243
+ const agentsDir = getAgentsDir(resolvedRuntime, projectRoot);
244
+ if (!node_fs_1.default.existsSync(agentsDir)) {
245
+ // Presence is checkAgentsInstalled's job — an absent agents dir here is a
246
+ // distinct, non-violating outcome, not a failure of this check.
247
+ return {
248
+ ok: true,
249
+ violations: [],
250
+ checked: [],
251
+ agents_dir: agentsDir,
252
+ agent_runtime: resolvedRuntime,
253
+ reason: POSTURE_REASON.AGENTS_DIR_MISSING,
254
+ };
255
+ }
256
+ // Skip symlinks — matches cmdEffortSync's existing idiom in commands.cts
257
+ // ("Skip symlinks — only write regular files..."). Here the risk is reading
258
+ // (not writing) through a symlink: readFileSync follows symlinks, so an
259
+ // agents-dir symlink pointing at an arbitrary file would let that target's
260
+ // contents be echoed into this function's `value` field. A symlinked agent
261
+ // file is a structural install choice (checkAgentsInstalled's territory),
262
+ // not a model-content posture defect, so it is silently excluded from
263
+ // `checked` rather than reported as a distinct violation — same shape as
264
+ // cmdEffortSync, which silently drops symlinks from its file list rather
265
+ // than inventing a new skip/violation reason.
266
+ const tomlFiles = node_fs_1.default
267
+ .readdirSync(agentsDir)
268
+ .filter((entry) => {
269
+ if (!entry.endsWith('.toml'))
270
+ return false;
271
+ try {
272
+ return node_fs_1.default.lstatSync(node_path_1.default.join(agentsDir, entry)).isFile();
273
+ }
274
+ catch {
275
+ return false;
276
+ }
277
+ })
278
+ .sort();
279
+ const checked = [];
280
+ const violations = [];
281
+ for (const entry of tomlFiles) {
282
+ const agentName = entry.slice(0, -'.toml'.length);
283
+ const filePath = node_path_1.default.join(agentsDir, entry);
284
+ checked.push(agentName);
285
+ let raw;
286
+ try {
287
+ raw = node_fs_1.default.readFileSync(filePath, 'utf8');
288
+ }
289
+ catch {
290
+ // Never throws, never silently skips — an unreadable file is reported and
291
+ // the loop continues checking the rest (40-design.md "Rejected" #5).
292
+ violations.push({ agent: agentName, file: filePath, reason: POSTURE_REASON.UNREADABLE });
293
+ continue;
294
+ }
295
+ const { model, hasReasoningEffort } = (0, codex_agent_toml_cjs_1.scanTomlLines)((0, codex_agent_toml_cjs_1.stripBOM)(raw));
296
+ if (model !== null && (0, model_catalog_cjs_1.isAnthropicFlavoredModel)(model)) {
297
+ violations.push({
298
+ agent: agentName,
299
+ file: filePath,
300
+ reason: POSTURE_REASON.ANTHROPIC_FLAVORED_MODEL,
301
+ value: truncatePostureValue(model),
302
+ });
303
+ }
304
+ else if (model === null && hasReasoningEffort) {
305
+ // #838 coupling: a reasoning-effort pin with no model pin means Codex
306
+ // inherits the session model while the effort pin silently disagrees.
307
+ violations.push({
308
+ agent: agentName,
309
+ file: filePath,
310
+ reason: POSTURE_REASON.ORPHANED_REASONING_EFFORT,
311
+ });
312
+ }
313
+ }
314
+ return {
315
+ ok: violations.length === 0,
316
+ violations,
317
+ checked,
318
+ agents_dir: agentsDir,
319
+ agent_runtime: resolvedRuntime,
320
+ };
321
+ }
322
+ // #3897 rung 3 — the canonical bundled `agents/*.md` source directory (the
323
+ // tool-contract source of truth), resolved the same install-relative way
324
+ // getAgentsDir resolves the claude case, WITHOUT that function's npm-global
325
+ // node_modules redirect: that redirect exists so a Codex/claude INSTALL is
326
+ // never validated against itself, but here we deliberately want the bundled
327
+ // copy every time — it is the only place the `tools:` contract a role
328
+ // derives its sandbox_mode from actually lives, in every install shape
329
+ // (repo-dev tree or npm-global package, where the package still ships its
330
+ // own agents/ alongside bin/ and gsd-core/).
331
+ function _canonicalAgentSourceDir() {
332
+ return node_path_1.default.join(__dirname, '..', '..', '..', 'agents');
333
+ }
334
+ /**
335
+ * Validate installed Codex `.toml` agents' `sandbox_mode` against what each
336
+ * role's own tool contract derives (#3897, ADR-3473 §8.3 criterion 3,
337
+ * HALT.md option 2). Sibling to {@link checkCodexModelPosture} — same shape,
338
+ * same short-circuits — but a different defect class: a TOML whose
339
+ * `sandbox_mode` disagrees with the derived expectation, not a bad `model`.
340
+ *
341
+ * `deriveCodexSandboxMode` (and the `CODEX_SANDBOX_HOLDS` hold list + its own
342
+ * self-invalidation check it embeds) is imported from `codex-agent-toml.cjs`
343
+ * — the shared, side-effect-free leaf both `bin/install.js`'s emitter and
344
+ * this posture check import from (CAUSE A fix, #3897: this function used to
345
+ * lazily `require('bin/install.js')` to reach the same derivation, but
346
+ * requiring `bin/install.js` runs its whole CLI top-level, including an
347
+ * ASCII banner print to stdout, which corrupted every stdout-JSON caller of
348
+ * this posture check, e.g. `gsd-tools validate agents`) — so the emitter and
349
+ * this posture check can never silently diverge on the same tool-contract
350
+ * predicate — the exact generative-fix-divergence shape this epic exists to
351
+ * close. `deriveCodexSandboxMode` itself is total (never throws, #3897
352
+ * CAUSE C fix) — a held role whose supplied content no longer derives
353
+ * broader than its pin simply returns `read-only` rather than failing,
354
+ * because the pin is then a no-op. The staleness invariant (S4/S5) this
355
+ * check's imports still carry is enforced separately, at the real `agents/`
356
+ * roster level, by `validateCodexSandboxHolds` and
357
+ * `tests/codex-config.test.cjs` T24/T25 — not by this per-call derivation.
358
+ *
359
+ * Read-only: detects, never repairs — same posture as {@link checkCodexModelPosture}.
360
+ *
361
+ * @param runtime - the active runtime name; defaults to GSD_RUNTIME env, then 'claude'
362
+ * @param projectRoot - canonical project root for local-install discovery
363
+ */
364
+ function checkCodexSandboxPosture(runtime, projectRoot) {
365
+ const resolvedRuntime = runtime ?? (process.env['GSD_RUNTIME'] || 'claude');
366
+ if (resolvedRuntime !== 'codex') {
367
+ return {
368
+ ok: true,
369
+ violations: [],
370
+ checked: [],
371
+ agents_dir: '',
372
+ agent_runtime: resolvedRuntime,
373
+ reason: POSTURE_REASON.NOT_CODEX,
374
+ };
375
+ }
376
+ const agentsDir = getAgentsDir(resolvedRuntime, projectRoot);
377
+ if (!node_fs_1.default.existsSync(agentsDir)) {
378
+ return {
379
+ ok: true,
380
+ violations: [],
381
+ checked: [],
382
+ agents_dir: agentsDir,
383
+ agent_runtime: resolvedRuntime,
384
+ reason: POSTURE_REASON.AGENTS_DIR_MISSING,
385
+ };
386
+ }
387
+ const canonicalAgentsDir = _canonicalAgentSourceDir();
388
+ // Same symlink guard as checkCodexModelPosture, same reason (never follow
389
+ // an agents-dir symlink into an arbitrary file's content).
390
+ const tomlFiles = node_fs_1.default
391
+ .readdirSync(agentsDir)
392
+ .filter((entry) => {
393
+ if (!entry.endsWith('.toml'))
394
+ return false;
395
+ try {
396
+ return node_fs_1.default.lstatSync(node_path_1.default.join(agentsDir, entry)).isFile();
397
+ }
398
+ catch {
399
+ return false;
400
+ }
401
+ })
402
+ .sort();
403
+ const checked = [];
404
+ const violations = [];
405
+ for (const entry of tomlFiles) {
406
+ const agentName = entry.slice(0, -'.toml'.length);
407
+ const filePath = node_path_1.default.join(agentsDir, entry);
408
+ checked.push(agentName);
409
+ let raw;
410
+ try {
411
+ raw = node_fs_1.default.readFileSync(filePath, 'utf8');
412
+ }
413
+ catch {
414
+ violations.push({ agent: agentName, file: filePath, reason: POSTURE_REASON.UNREADABLE });
415
+ continue;
416
+ }
417
+ // #3897 rung 4 (isolated correctness review, MINOR finding 2): route
418
+ // through the same block-aware `scanTomlLines` the sibling
419
+ // `checkCodexModelPosture` already uses, rather than a naive whole-file
420
+ // regex — a `sandbox_mode = "..."`-shaped line inside the
421
+ // `developer_instructions` block (prose) must never be read as a live
422
+ // value. A prior naive `raw.match(/^sandbox_mode.../m)` here produced a
423
+ // FALSE violation whenever an agent's own prompt prose happened to
424
+ // contain that shape.
425
+ const found = (0, codex_agent_toml_cjs_1.scanTomlLines)((0, codex_agent_toml_cjs_1.stripBOM)(raw)).sandboxMode;
426
+ if (found === null) {
427
+ // No sandbox_mode line at all (e.g. sandboxTier "none") is a deliberate,
428
+ // documented state elsewhere — not this check's business.
429
+ continue;
430
+ }
431
+ const canonicalFile = node_path_1.default.join(canonicalAgentsDir, `${agentName}.md`);
432
+ let canonicalContent;
433
+ try {
434
+ canonicalContent = node_fs_1.default.readFileSync(canonicalFile, 'utf8');
435
+ }
436
+ catch {
437
+ // No canonical role source (a custom/non-roster agent) — nothing to
438
+ // derive an expectation from, so this is not this check's business.
439
+ continue;
440
+ }
441
+ // `canonicalContent` is always a real string here (read via fs.readFileSync
442
+ // above), so extractToolsValue's `undefined` (non-string input) branch is
443
+ // unreachable on this path — the `?? ''` is a type-level formality, not a
444
+ // behavior change (F4, #3897 security review: extractToolsValue is TOTAL).
445
+ const toolsRaw = (0, codex_agent_toml_cjs_1.extractToolsValue)(canonicalContent) ?? '';
446
+ const expected = (0, codex_agent_toml_cjs_1.deriveCodexSandboxMode)(agentName, toolsRaw);
447
+ if (expected !== found) {
448
+ // #3897 rung 4 (isolated correctness review, MINOR finding 3):
449
+ // truncatePostureValue matches the sibling checkCodexModelPosture's
450
+ // convention (see its own `value: truncatePostureValue(model)` above)
451
+ // so an oversized or secret-shaped `sandbox_mode` value can never
452
+ // reach `validate agents --raw` output at full length.
453
+ violations.push({
454
+ agent: agentName,
455
+ file: filePath,
456
+ expected: truncatePostureValue(expected),
457
+ found: truncatePostureValue(found),
458
+ });
459
+ }
460
+ }
461
+ return {
462
+ ok: violations.length === 0,
463
+ violations,
464
+ checked,
465
+ agents_dir: agentsDir,
466
+ agent_runtime: resolvedRuntime,
467
+ };
468
+ }
469
+ /**
470
+ * Probe a single agents dir for `<name>` across runtime filename variants.
471
+ * Mirrors {@link checkAgentsInstalled}'s probe (`.md`, `.agent.md`, `.toml`,
472
+ * and the kimi `subagents/<name>.{yaml,md}` pair) so the two can never disagree
473
+ * about which on-disk shapes count as "installed". Not exported — internal to
474
+ * {@link resolveAgentHint}.
475
+ */
476
+ function agentFileExists(agentsDir, name, runtime) {
477
+ const base = node_path_1.default.join(agentsDir, `${name}.md`);
478
+ const copilot = node_path_1.default.join(agentsDir, `${name}.agent.md`);
479
+ const codex = node_path_1.default.join(agentsDir, `${name}.toml`);
480
+ if (node_fs_1.default.existsSync(base) || node_fs_1.default.existsSync(copilot) || node_fs_1.default.existsSync(codex)) {
481
+ return true;
482
+ }
483
+ // kimi requires BOTH the persona yaml and the prompt md (same as checkAgentsInstalled).
484
+ const kimiYaml = node_path_1.default.join(agentsDir, 'subagents', `${name}.yaml`);
485
+ const kimiPrompt = node_path_1.default.join(agentsDir, 'subagents', `${name}.md`);
486
+ return runtime === 'kimi' && node_fs_1.default.existsSync(kimiYaml) && node_fs_1.default.existsSync(kimiPrompt);
487
+ }
488
+ /**
489
+ * Resolve a per-plan `agent_hint` specialist name to a dispatchable subagent
490
+ * type on the active runtime (#1689). Unlike {@link checkAgentsInstalled},
491
+ * which validates the fixed GSD roster, this answers "does an agent file for
492
+ * this ARBITRARY name exist in the active runtime's agent dir(s)?" — so a plan
493
+ * can opt into a domain specialist (e.g. a Flutter engineer) that shares the
494
+ * gsd-executor contract without being part of the built-in roster.
495
+ *
496
+ * Probes BOTH the runtime-canonical agents dir ({@link getAgentsDir}, which
497
+ * honors `GSD_AGENTS_DIR`, project-local manifest-backed installs, and the
498
+ * claude install-relative path) AND the runtime's global config agents dir, so
499
+ * a specialist installed at either level is recognized. The decision in #1689
500
+ * explicitly requires consulting the active runtime's agent dir rather than
501
+ * only the Claude runtime's user-global and project-local agent dirs.
502
+ *
503
+ * @returns the name when a matching agent file exists; `null` when it does not
504
+ * (the caller falls back to `gsd-executor`). An empty/whitespace name always
505
+ * returns `null`.
506
+ */
507
+ function resolveAgentHint(name, runtime, projectRoot) {
508
+ const trimmed = String(name ?? '').trim();
509
+ if (trimmed === '')
510
+ return null;
511
+ // A hint is a bare agent name. Reject path separators and `..` so a value
512
+ // like `../../README` cannot path-traverse out of the agents dir via
513
+ // path.join and match an unrelated file — that would echo an invalid
514
+ // subagent_type and block the wave, defeating fail-closed resolution.
515
+ if (trimmed.includes('/') || trimmed.includes('\\') || trimmed.includes('..'))
516
+ return null;
517
+ const resolvedRuntime = runtime ?? (process.env['GSD_RUNTIME'] || 'claude');
518
+ const candidateDirs = new Set();
519
+ candidateDirs.add(getAgentsDir(resolvedRuntime, projectRoot));
520
+ candidateDirs.add(node_path_1.default.join((0, runtime_homes_cjs_1.getGlobalConfigDir)(resolvedRuntime), 'agents'));
521
+ for (const dir of candidateDirs) {
522
+ if (agentFileExists(dir, trimmed, resolvedRuntime)) {
523
+ return trimmed;
524
+ }
525
+ }
526
+ return null;
527
+ }
172
528
  module.exports = {
173
529
  getAgentsDir,
174
530
  checkAgentsInstalled,
531
+ checkCodexModelPosture,
532
+ checkCodexSandboxPosture,
533
+ POSTURE_REASON,
534
+ resolveAgentHint,
175
535
  };
@@ -52,9 +52,13 @@
52
52
  * renderCoverageMatrix(rows) -> string
53
53
  * DEFAULT_API_COVERAGE_TERMS
54
54
  *
55
- * CLI:
55
+ * CLI (ADR-3889 Phase 3, #3907):
56
56
  * echo "$SCOPE" | node gsd-core/bin/lib/api-coverage.cjs [--json]
57
- * exit 0 = integration detected, 1 = none, 2 = startup error
57
+ * exit 0 = integration detected, 1 = none (real input, examined, no signal),
58
+ * NO_INPUT (registry, src/cli-exit.cts) = stdin empty/whitespace-only,
59
+ * UNAVAILABLE (registry) = stdin read failed
60
+ * --json additionally prints the typed IR on stdout (unchanged for 0/1);
61
+ * NO_INPUT/UNAVAILABLE print {skipped:true, reason:"no_input"|"stdin_error"}
58
62
  */
59
63
  Object.defineProperty(exports, "__esModule", { value: true });
60
64
  exports.DEFAULT_API_COVERAGE_TERMS = void 0;
@@ -63,6 +67,7 @@ exports.parseCoverageMatrix = parseCoverageMatrix;
63
67
  exports.validateCoverageMatrix = validateCoverageMatrix;
64
68
  exports.renderCoverageMatrix = renderCoverageMatrix;
65
69
  const markdown_sectionizer_cjs_1 = require("./markdown-sectionizer.cjs");
70
+ const pattern_cjs_1 = require("./pattern.cjs");
66
71
  /**
67
72
  * Curated default trigger vocabulary. ADDITIVE-ONLY (Hyrum's Law). Tunable via
68
73
  * the `terms` parameter.
@@ -156,9 +161,6 @@ function resolveTerms(terms) {
156
161
  };
157
162
  return { verbs: merge('verbs'), nouns: merge('nouns') };
158
163
  }
159
- function escapeRegex(s) {
160
- return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
161
- }
162
164
  function makeSnippet(line, anchor) {
163
165
  const cleaned = line.replace(/\s+/g, ' ').trim();
164
166
  if (cleaned.length <= 120)
@@ -402,10 +404,10 @@ function detectApiIntegration(text, terms) {
402
404
  // Trailing boundary is a LOOKAHEAD (not consumed) so back-to-back terms
403
405
  // separated by one boundary char are both found.
404
406
  const verbRe = hasCompoundTerms
405
- ? new RegExp('(^|[^a-zA-Z0-9])(' + effective.verbs.map(escapeRegex).join('|') + ')(?=[^a-zA-Z0-9]|$)', 'gi')
407
+ ? new RegExp('(^|[^a-zA-Z0-9])(' + effective.verbs.map(pattern_cjs_1.escapeRegex).join('|') + ')(?=[^a-zA-Z0-9]|$)', 'gi')
406
408
  : null;
407
409
  const nounRe = hasCompoundTerms
408
- ? new RegExp('(^|[^a-zA-Z0-9])(' + effective.nouns.map(escapeRegex).join('|') + ')(?=[^a-zA-Z0-9]|$)', 'gi')
410
+ ? new RegExp('(^|[^a-zA-Z0-9])(' + effective.nouns.map(pattern_cjs_1.escapeRegex).join('|') + ')(?=[^a-zA-Z0-9]|$)', 'gi')
409
411
  : null;
410
412
  const surfaceRe = new RegExp(SERVICE_SURFACE_API_RE.source, 'g');
411
413
  const nounSet = new Set(effective.nouns);
@@ -851,11 +853,24 @@ function renderCoverageMatrix(rows) {
851
853
  // ── CLI entry point ──────────────────────────────────────────────────────────
852
854
  // Reads phase-scope text from STDIN (not argv) to avoid OS ARG_MAX limits.
853
855
  // Invoked by workflow bash as: echo "$SCOPE" | node .../api-coverage.cjs [--json]
854
- // Exit 0 = integration detected, 1 = none, 2 = startup error. Mirrors
855
- // assumption-delta.cjs / ui-safety-gate.cjs.
856
+ //
857
+ // Exit codes (ADR-3889 Phase 3, #3907): 0 = integration detected, 1 = none
858
+ // (real input, examined, no signal), NO_INPUT (registry — src/cli-exit.cts) =
859
+ // stdin empty/whitespace-only, UNAVAILABLE (registry) = stdin read failed.
860
+ // The prior single "2 = startup error" arm let empty input flow into the
861
+ // detector and exit 1 — an unexamined input reported as an authoritative
862
+ // negative. Under --json, NO_INPUT/UNAVAILABLE emit `{skipped:true,
863
+ // reason:"no_input"|"stdin_error"}` — no `detected` key, so a stale
864
+ // `detected:false` can never sit beside `skipped:true`; the detected/no-signal
865
+ // `--json` payloads are byte-identical to before. Terminates via terminateNow
866
+ // (write-then-terminate, total by construction), not raw process.exit — these
867
+ // exits fire from inside a stdin event handler. Mirrors assumption-delta.cjs /
868
+ // ui-safety-gate.cjs.
856
869
  if (require.main === module) {
857
870
  const argv = process.argv.slice(2);
858
871
  const wantJson = argv.includes('--json');
872
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
873
+ const cliExit = require('./cli-exit.cjs');
859
874
  let termsOverride;
860
875
  const verbsIdx = argv.indexOf('--verbs');
861
876
  const verbsVal = verbsIdx !== -1 ? argv[verbsIdx + 1] : undefined;
@@ -879,14 +894,18 @@ if (require.main === module) {
879
894
  process.stdin.on('data', (chunk) => chunks.push(chunk));
880
895
  process.stdin.on('end', () => {
881
896
  const input = chunks.join('');
882
- const result = detectApiIntegration(input, termsOverride);
883
- if (wantJson) {
884
- process.stdout.write(JSON.stringify(result) + '\n');
897
+ // Whitespace-only counts as empty (ADR-3889 §1's NO_INPUT: "zero units
898
+ // were in scope, and that emptiness is known to be genuine"). Real input
899
+ // — including a lone NUL byte, which .trim() does not strip — always
900
+ // falls through to the detector.
901
+ if (input.trim().length === 0) {
902
+ cliExit.terminateNow('NO_INPUT', wantJson ? { skipped: true, reason: 'no_input' } : undefined);
885
903
  }
886
- process.exit(result.detected ? 0 : 1);
904
+ const result = detectApiIntegration(input, termsOverride);
905
+ cliExit.terminateNow(result.detected ? 'PASS' : 'FAIL', wantJson ? result : undefined);
887
906
  });
888
907
  process.stdin.on('error', (err) => {
889
908
  process.stderr.write(`ERROR: api-coverage.cjs stdin read failed: ${err.message}\n`);
890
- process.exit(2);
909
+ cliExit.terminateNow('UNAVAILABLE', wantJson ? { skipped: true, reason: 'stdin_error' } : undefined);
891
910
  });
892
911
  }
@@ -27,6 +27,11 @@ exports.CANONICAL_EXACT = new Set([
27
27
  'config.json',
28
28
  'CLAUDE.md',
29
29
  'RETROSPECTIVE.md',
30
+ 'WINDOWS.md', // #3224: broken-windows ledger (src/broken-windows.cts, LEDGER_FILE_NAME)
31
+ 'STATE-ARCHIVE.md', // state.cts's cmdStatePrune writes this at the .planning/ root
32
+ 'milestone.lock', // #3311: milestone (phase + session) claim (src/milestone-lock.cts); persistent, unlike the transient STATE.md.lock/WAITING.json
33
+ 'state.json', // #3227: machine-readable state contract published at step boundaries (src/state-contract.cts)
34
+ 'skill-manifest.json', // init.cts routeSkillManifest --write (project-scoped planning root, #3964)
30
35
  ]);
31
36
  // Pattern-match canonical file names (regex tests on the basename)
32
37
  // Each pattern includes the name of the workflow that produces it as a comment.