@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
@@ -0,0 +1,451 @@
1
+ "use strict";
2
+ /**
3
+ * Health Diagnostic — frozen rule-table types, enums, and evaluator for
4
+ * `validate health` (Phase 11, #3309, ADR-3180 §8.2/§8.3/§8.5).
5
+ *
6
+ * Establishes the exact contract every extracted rule builds onto: the
7
+ * frozen `SEVERITY`/`REMEDY_ACTION`/`REMEDY_RISK` enums, the
8
+ * `Diagnostic`/`Remedy`/`Rule` shapes, the `RULES` container (the 32 rules
9
+ * extracted from `cmdValidateHealth`, `src/verify.cts:1616-2577`, are
10
+ * concatenated in from each rule-group file under
11
+ * `src/health-diagnostic-rules/`), the `evaluateRules` evaluator, and the
12
+ * `applyRepairs` `--repair`/`--backfill` dispatcher — whose per-action
13
+ * handlers are REAL here (ported behavior-preserving from
14
+ * `verify.cts:2405-2553`'s repair switch), not stubs.
15
+ *
16
+ * `applyRepairs` does not receive a `PlanningSnapshot` (its call-site
17
+ * signature, `(cwd, diagnostics, repair, backfill)`, is a locked contract —
18
+ * see `tests/health-diagnostic.test.cjs`) — so, like `cmdValidateHealth`
19
+ * itself before this migration, it performs its own bounded filesystem I/O
20
+ * to apply a repair. This is not a §8.1 rule 1 violation: that rule
21
+ * constrains a RULE's `check(snapshot)` signature (no ambient I/O), not the
22
+ * evaluator/dispatcher, which the design doc's "subject-surface gap" section
23
+ * already establishes performs I/O once, up front, on the rules' behalf.
24
+ *
25
+ * `PlanningSnapshot` is deliberately NOT re-exported as a type from
26
+ * `planning-snapshot.cts` here (see the design doc's "Known limits" and this
27
+ * phase's brief): `ReturnType<typeof buildPlanningSnapshot>` is used inline
28
+ * instead, via a type-only `import ... = require(...)` that is fully erased
29
+ * at compile time — zero changes to the already-shipped, already-tested
30
+ * `planning-snapshot.cts`.
31
+ *
32
+ * Design: .gsd/phase/refactor-3309-health-diagnostic-rule-table/40-design.md
33
+ * Test matrix: .gsd/phase/refactor-3309-health-diagnostic-rule-table/50-test-matrix.md
34
+ *
35
+ * ADR-457 build-at-publish: source in src/health-diagnostic.cts, compiled to
36
+ * gsd-core/bin/lib/health-diagnostic.cjs (gitignored).
37
+ */
38
+ var __importDefault = (this && this.__importDefault) || function (mod) {
39
+ return (mod && mod.__esModule) ? mod : { "default": mod };
40
+ };
41
+ const node_fs_1 = __importDefault(require("node:fs"));
42
+ const node_path_1 = __importDefault(require("node:path"));
43
+ // Runtime values (SEVERITY/REMEDY_ACTION/REMEDY_RISK) are needed here — not
44
+ // just types — for `applyRepairs`'s comparisons, so this is a normal
45
+ // (non type-only) `import ... = require(...)`. `health-diagnostic-types.cjs`
46
+ // is the leaf module these enums/types were extracted to, so that this file
47
+ // can `require()` every rule-group file below without a circular dependency
48
+ // (see that module's file-level comment for the full explanation).
49
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
50
+ const healthDiagnosticTypesMod = require("./health-diagnostic-types.cjs");
51
+ const { SEVERITY, REMEDY_ACTION, REMEDY_RISK } = healthDiagnosticTypesMod;
52
+ // ─── Rule table ─────────────────────────────────────────────────────────────
53
+ // Populated by concatenating each rule group's exported `RULES` array (design
54
+ // doc, "Rule table organization" section) — the 32 rule functions extracted
55
+ // from `cmdValidateHealth`, `src/verify.cts:1616-2577`.
56
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
57
+ const rootExistenceMod = require("./health-diagnostic-rules/root-existence.cjs");
58
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
59
+ const stateConsistencyMod = require("./health-diagnostic-rules/state-consistency.cjs");
60
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
61
+ const configValidationMod = require("./health-diagnostic-rules/config-validation.cjs");
62
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
63
+ const phaseStructureMod = require("./health-diagnostic-rules/phase-structure.cjs");
64
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
65
+ const agentInstallMod = require("./health-diagnostic-rules/agent-install.cjs");
66
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
67
+ const roadmapDiskConsistencyMod = require("./health-diagnostic-rules/roadmap-disk-consistency.cjs");
68
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
69
+ const worktreeHealthMod = require("./health-diagnostic-rules/worktree-health.cjs");
70
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
71
+ const milestoneArchiveHygieneMod = require("./health-diagnostic-rules/milestone-archive-hygiene.cjs");
72
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
73
+ const consistencyMod = require("./health-diagnostic-rules/consistency.cjs");
74
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
75
+ const installSurfaceShadowingMod = require("./health-diagnostic-rules/install-surface-shadowing.cjs");
76
+ const RULES = [
77
+ ...rootExistenceMod.RULES,
78
+ ...stateConsistencyMod.RULES,
79
+ ...configValidationMod.RULES,
80
+ ...phaseStructureMod.RULES,
81
+ ...agentInstallMod.RULES,
82
+ ...roadmapDiskConsistencyMod.RULES,
83
+ ...worktreeHealthMod.RULES,
84
+ ...milestoneArchiveHygieneMod.RULES,
85
+ ...installSurfaceShadowingMod.RULES,
86
+ ];
87
+ /**
88
+ * `validate.consistency`'s own rule set (Phase 12, #3310, ADR-3180 §8.4,
89
+ * design doc "Which rules run where") — W006/W007 REUSED (the exact same
90
+ * `Rule` objects `RULES` above already carries, not new copies) plus the
91
+ * four new C0NN rules from `consistency.cts`. Deliberately NOT the full
92
+ * `RULES` table: running `validate.health`'s config/state/worktree rules
93
+ * under `validate.consistency` would be scope creep the issue never asked
94
+ * for.
95
+ */
96
+ const CONSISTENCY_RULES = [
97
+ ...roadmapDiskConsistencyMod.RULES.filter((r) => ['W006', 'W007'].includes(r.code)),
98
+ ...consistencyMod.RULES,
99
+ ];
100
+ // ─── Repair-handler runtime dependencies ───────────────────────────────────
101
+ //
102
+ // Same owners `cmdValidateHealth`'s pre-migration repair switch used
103
+ // (`verify.cts:2405-2553`) — ported verbatim, not reinvented.
104
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
105
+ const planningWorkspaceMod = require("./planning-workspace.cjs");
106
+ const { planningDir } = planningWorkspaceMod;
107
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
108
+ const configLoaderMod = require("./config-loader.cjs");
109
+ const { CONFIG_DEFAULTS } = configLoaderMod;
110
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
111
+ const roadmapParserMod = require("./roadmap-parser.cjs");
112
+ const { getMilestoneInfo } = roadmapParserMod;
113
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
114
+ const stateMod = require("./state.cjs");
115
+ const { writeStateMd } = stateMod;
116
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
117
+ const frontmatter = require("./frontmatter.cjs");
118
+ const { extractFrontmatter } = frontmatter;
119
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
120
+ const stateTransitionMod = require("./state-transition.cjs");
121
+ const { rebuildStateTransaction } = stateTransitionMod;
122
+ const clock_cjs_1 = require("./clock.cjs");
123
+ const shell_command_projection_cjs_1 = require("./shell-command-projection.cjs");
124
+ const runtime_slash_cjs_1 = require("./runtime-slash.cjs");
125
+ // ─── Evaluator ──────────────────────────────────────────────────────────────
126
+ /**
127
+ * Evaluate an explicit `rules` array against `snapshot`, throwing if any two
128
+ * entries share a `code` (defense in depth beside the static lint guard,
129
+ * §8.2 rule 1, `scripts/lint-health-diagnostic-rule-table.cjs`). Separated
130
+ * from `evaluateRules` so the duplicate-code guard is unit-testable against
131
+ * a small, locally-constructed fake rule array, independent of the real
132
+ * `RULES` table.
133
+ */
134
+ function evaluateRuleTable(rules, snapshot) {
135
+ const seen = new Set();
136
+ for (const rule of rules) {
137
+ if (seen.has(rule.code)) {
138
+ throw new Error(`health-diagnostic: duplicate rule code "${rule.code}" in rule table`);
139
+ }
140
+ seen.add(rule.code);
141
+ }
142
+ return rules.flatMap((rule) => rule.check(snapshot));
143
+ }
144
+ /**
145
+ * Evaluate every rule in `RULES` against `snapshot`, flattening each rule's
146
+ * `Diagnostic[]` into one array.
147
+ */
148
+ function evaluateRules(snapshot) {
149
+ return evaluateRuleTable(RULES, snapshot);
150
+ }
151
+ /**
152
+ * Evaluate `CONSISTENCY_RULES` (W006/W007 + C001-C004) against `snapshot` —
153
+ * `validate.consistency`'s evaluator entry point, mirroring `evaluateRules`
154
+ * exactly but over the smaller, command-specific rule subset.
155
+ */
156
+ function evaluateConsistencyRules(snapshot) {
157
+ return evaluateRuleTable(CONSISTENCY_RULES, snapshot);
158
+ }
159
+ /**
160
+ * Derive every filesystem path a repair handler needs, from `cwd` alone —
161
+ * exactly how `cmdValidateHealth` derived them pre-migration
162
+ * (`verify.cts:1644-1652`/`2301-2302`). `config.json`/`MILESTONES.md`/
163
+ * `milestones/` are root-scoped (`planningRoot`); `STATE.md` is
164
+ * workstream-scoped (`planningDir`) — the same root-vs-workstream split
165
+ * `buildConfigField`/`buildStateFields` (`planning-snapshot.cts`) already
166
+ * document for the read side.
167
+ */
168
+ function repairPaths(cwd) {
169
+ // #3749: the project root is PROJECT-aware but deliberately NOT workstream-
170
+ // scoped — under GSD_PROJECT, config.json/MILESTONES.md/milestones belong to
171
+ // `.planning/<project>/` (the same base init.new-project's config_path
172
+ // names); under GSD_WORKSTREAM they stay at the workstream PARENT, keeping
173
+ // the documented root-vs-workstream split. planningDir(cwd, null) is exactly
174
+ // that base: project env honored, ws env suppressed.
175
+ const rootBase = planningDir(cwd, null);
176
+ const wsBase = planningDir(cwd);
177
+ return {
178
+ rootBase,
179
+ configPath: node_path_1.default.join(rootBase, 'config.json'),
180
+ statePath: node_path_1.default.join(wsBase, 'STATE.md'),
181
+ milestonesPath: node_path_1.default.join(rootBase, 'MILESTONES.md'),
182
+ milestonesArchiveDir: node_path_1.default.join(rootBase, 'milestones'),
183
+ };
184
+ }
185
+ /** `verify.cts:2413-2429`'s default config.json payload, ported verbatim. */
186
+ function defaultConfigPayload() {
187
+ return {
188
+ model_profile: CONFIG_DEFAULTS.model_profile,
189
+ commit_docs: CONFIG_DEFAULTS.commit_docs,
190
+ search_gitignored: CONFIG_DEFAULTS.search_gitignored,
191
+ branching_strategy: CONFIG_DEFAULTS.branching_strategy,
192
+ phase_branch_template: CONFIG_DEFAULTS.phase_branch_template,
193
+ milestone_branch_template: CONFIG_DEFAULTS.milestone_branch_template,
194
+ quick_branch_template: CONFIG_DEFAULTS.quick_branch_template,
195
+ workflow: {
196
+ research: CONFIG_DEFAULTS.research,
197
+ plan_check: CONFIG_DEFAULTS.plan_checker,
198
+ verifier: CONFIG_DEFAULTS.verifier,
199
+ nyquist_validation: CONFIG_DEFAULTS.nyquist_validation,
200
+ },
201
+ parallelization: CONFIG_DEFAULTS.parallelization,
202
+ brave_search: CONFIG_DEFAULTS.brave_search,
203
+ };
204
+ }
205
+ /**
206
+ * `verify.cts:2301-2335`'s W018 archived-vs-documented-versions diff,
207
+ * relocated verbatim (same two regexes, same two-file read) so
208
+ * `backfillMilestones` can recompute exactly which versions are missing
209
+ * without a `PlanningSnapshot` (`applyRepairs` is not a `Rule` and is not
210
+ * handed one — see this file's header comment). This is the same
211
+ * derivation `buildMilestoneArchiveStatusField`
212
+ * (`src/planning-snapshot.cts`) already performs for the W018 RULE's read
213
+ * side; recomputed here, not re-invented, because the rule's own
214
+ * `Diagnostic.remedy.args` carries no version list (confirmed by direct
215
+ * read of `src/health-diagnostic-rules/milestone-archive-hygiene.cts`).
216
+ */
217
+ function computeMissingMilestoneVersions(milestonesArchiveDir, milestonesPath) {
218
+ let archivedVersions = [];
219
+ try {
220
+ if (node_fs_1.default.existsSync(milestonesArchiveDir)) {
221
+ const archiveFiles = node_fs_1.default.readdirSync(milestonesArchiveDir);
222
+ archivedVersions = archiveFiles
223
+ .map((f) => f.match(/^(v\d+\.\d+(?:\.\d+)?)-ROADMAP\.md$/))
224
+ .filter((m) => m !== null)
225
+ .map((m) => m[1]);
226
+ }
227
+ }
228
+ catch {
229
+ /* intentionally empty — mirrors the original's advisory try/catch */
230
+ }
231
+ let documentedVersions = [];
232
+ try {
233
+ if (node_fs_1.default.existsSync(milestonesPath)) {
234
+ const registryContent = node_fs_1.default.readFileSync(milestonesPath, 'utf-8');
235
+ documentedVersions = [...registryContent.matchAll(/^##\s+(v\d+\.\d+(?:\.\d+)?)/gm)].map((m) => m[1]);
236
+ }
237
+ }
238
+ catch {
239
+ /* intentionally empty */
240
+ }
241
+ const documented = new Set(documentedVersions);
242
+ return archivedVersions.filter((v) => !documented.has(v));
243
+ }
244
+ /**
245
+ * Execute exactly one real repair action, ported behavior-preserving from
246
+ * `verify.cts:2405-2553`'s `switch (repair)`. Throws are the caller's
247
+ * responsibility to catch (mirrors the original's per-action try/catch
248
+ * shape, collapsed to one seam here since every case now shares one
249
+ * caller).
250
+ */
251
+ function runRepairAction(cwd, action, paths) {
252
+ const { rootBase, configPath, statePath, milestonesPath, milestonesArchiveDir } = paths;
253
+ switch (action) {
254
+ case REMEDY_ACTION.CREATE_CONFIG:
255
+ case REMEDY_ACTION.RESET_CONFIG: {
256
+ (0, shell_command_projection_cjs_1.platformWriteSync)(configPath, JSON.stringify(defaultConfigPayload(), null, 2));
257
+ return { success: true, path: 'config.json' };
258
+ }
259
+ case REMEDY_ACTION.REGENERATE_STATE: {
260
+ const extraDetails = [];
261
+ if (node_fs_1.default.existsSync(statePath)) {
262
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);
263
+ const backupPath = `${statePath}.bak-${timestamp}`;
264
+ node_fs_1.default.copyFileSync(statePath, backupPath);
265
+ extraDetails.push({ action: 'backupState', success: true, path: backupPath });
266
+ }
267
+ const milestone = getMilestoneInfo(cwd).value;
268
+ const projectRef = node_path_1.default
269
+ .relative(cwd, node_path_1.default.join(rootBase, 'PROJECT.md'))
270
+ .split(node_path_1.default.sep)
271
+ .join('/');
272
+ const slashRuntime = (0, runtime_slash_cjs_1.resolveRuntime)(cwd);
273
+ const slash = (name) => (0, runtime_slash_cjs_1.formatGsdSlash)(name, slashRuntime);
274
+ let stateContent = `# Session State\n\n`;
275
+ stateContent += `## Project Reference\n\n`;
276
+ stateContent += `See: ${projectRef}\n\n`;
277
+ stateContent += `## Position\n\n`;
278
+ stateContent += `**Milestone:** ${milestone?.version ?? ''} ${milestone?.name ?? ''}\n`;
279
+ stateContent += `**Current phase:** (determining...)\n`;
280
+ stateContent += `**Status:** Resuming\n\n`;
281
+ stateContent += `## Session Log\n\n`;
282
+ stateContent += `- ${clock_cjs_1.realClock.localToday()}: STATE.md regenerated by ${slash('health')} --repair\n`;
283
+ // ADR-3473 §8.6: `/gsd-health --repair` is a factory reset, so
284
+ // preservation must not run; the snapshot of the file being replaced is
285
+ // still captured, and `{}` is the correct, legal snapshot of a
286
+ // STATE.md that had no parseable frontmatter — which is the usual
287
+ // reason this repair fires.
288
+ const priorState = node_fs_1.default.existsSync(statePath) ? ((0, shell_command_projection_cjs_1.platformReadSync)(statePath) ?? '') : '';
289
+ writeStateMd(statePath, stateContent, rebuildStateTransaction({
290
+ snapshot: extractFrontmatter(priorState, statePath),
291
+ }), cwd);
292
+ return { success: true, path: 'STATE.md', extraDetails };
293
+ }
294
+ case REMEDY_ACTION.ADD_NYQUIST_KEY:
295
+ case REMEDY_ACTION.ADD_AI_INTEGRATION_PHASE_KEY: {
296
+ const key = action === REMEDY_ACTION.ADD_NYQUIST_KEY ? 'nyquist_validation' : 'ai_integration_phase';
297
+ const configRaw = node_fs_1.default.readFileSync(configPath, 'utf-8');
298
+ const configParsed = JSON.parse(configRaw);
299
+ if (!configParsed['workflow'])
300
+ configParsed['workflow'] = {};
301
+ const wf = configParsed['workflow'];
302
+ if (wf[key] === undefined) {
303
+ wf[key] = true;
304
+ (0, shell_command_projection_cjs_1.platformWriteSync)(configPath, JSON.stringify(configParsed, null, 2));
305
+ }
306
+ return { success: true, path: 'config.json' };
307
+ }
308
+ case REMEDY_ACTION.BACKFILL_MILESTONES: {
309
+ const missing = computeMissingMilestoneVersions(milestonesArchiveDir, milestonesPath);
310
+ const today = clock_cjs_1.realClock.localToday();
311
+ const slashRuntime = (0, runtime_slash_cjs_1.resolveRuntime)(cwd);
312
+ const slash = (name) => (0, runtime_slash_cjs_1.formatGsdSlash)(name, slashRuntime);
313
+ let backfilled = 0;
314
+ for (const ver of missing) {
315
+ try {
316
+ const snapshotPath = node_path_1.default.join(milestonesArchiveDir, `${ver}-ROADMAP.md`);
317
+ const snapshot = (0, shell_command_projection_cjs_1.platformReadSync)(snapshotPath);
318
+ const titleMatch = snapshot && snapshot.match(/^#\s+(.+)$/m);
319
+ const milestoneName = titleMatch
320
+ ? titleMatch[1].replace(/^Milestone\s+/i, '').replace(/^v[\d.]+\s*/, '').trim()
321
+ : ver;
322
+ const entry = `## ${ver}${milestoneName && milestoneName !== ver ? ` ${milestoneName}` : ''} (Backfilled: ${today})\n\n**Note:** Synthesized from archive snapshot by \`${slash('health')} --backfill\`. Original completion date unknown.\n\n---\n\n`;
323
+ const milestonesContent = node_fs_1.default.existsSync(milestonesPath)
324
+ ? node_fs_1.default.readFileSync(milestonesPath, 'utf-8')
325
+ : '';
326
+ if (!milestonesContent.trim()) {
327
+ (0, shell_command_projection_cjs_1.platformWriteSync)(milestonesPath, `# Milestones\n\n${entry}`);
328
+ }
329
+ else {
330
+ const headerMatch = milestonesContent.match(/^(#{1,3}\s+[^\n]*\n\n?)/);
331
+ if (headerMatch) {
332
+ const header = headerMatch[1];
333
+ const rest = milestonesContent.slice(header.length);
334
+ (0, shell_command_projection_cjs_1.platformWriteSync)(milestonesPath, header + entry + rest);
335
+ }
336
+ else {
337
+ (0, shell_command_projection_cjs_1.platformWriteSync)(milestonesPath, entry + milestonesContent);
338
+ }
339
+ }
340
+ backfilled++;
341
+ }
342
+ catch {
343
+ /* intentionally empty — partial backfill is acceptable */
344
+ }
345
+ }
346
+ return { success: true, detail: `Backfilled ${backfilled} milestone(s) into MILESTONES.md` };
347
+ }
348
+ default:
349
+ return { success: false, error: `no repair handler registered for action "${action}"` };
350
+ }
351
+ }
352
+ /**
353
+ * `--repair`/`--backfill` dispatcher (design doc "`--repair` behavior
354
+ * change" section; §8.3 rule 3). For each diagnostic whose remedy is not
355
+ * `ADVISE`:
356
+ *
357
+ * - Not requested — `repair` is false, and for `backfillMilestones`
358
+ * specifically `backfill` is also false (mirrors `cmdValidateHealth`'s
359
+ * existing `backfillMilestones` gate, `verify.cts:2504`:
360
+ * `if (!options['backfill'] && !options['repair']) break;`) — skipped
361
+ * entirely, recorded in neither `applied` nor `refused`.
362
+ * - Requested and `remedy.risk === DESTRUCTIVE` — pushed onto `refused`,
363
+ * handler never invoked. This is the §8.3 rule 3 breaking-change
364
+ * enforcement point: a DESTRUCTIVE remedy is describable but is never
365
+ * applied by `--repair`. A `details` row is still recorded, so the
366
+ * refusal is VISIBLE in `cmdValidateHealth`'s `repairs_performed` output,
367
+ * not silently dropped.
368
+ * - Requested and `remedy.risk === NONE` — the real handler is invoked,
369
+ * pushed onto `applied`.
370
+ *
371
+ * `applied`/`refused` are unchanged in shape from the pre-existing skeleton
372
+ * (locked by `tests/health-diagnostic.test.cjs`, rows 11-12): arrays of
373
+ * diagnostic `code`s. `details` is ADDITIVE — every real action maps 1:1 to
374
+ * exactly one code in this rule table (confirmed: no `REMEDY_ACTION` other
375
+ * than `ADVISE` is used by more than one rule), so `cmdValidateHealth` can
376
+ * rebuild the legacy action-keyed `repairs_performed` shape directly from
377
+ * it.
378
+ */
379
+ function applyRepairs(cwd, diagnostics, repair, backfill) {
380
+ const applied = [];
381
+ const refused = [];
382
+ const details = [];
383
+ const paths = repairPaths(cwd);
384
+ for (const diagnostic of diagnostics) {
385
+ const { remedy, code } = diagnostic;
386
+ if (remedy.action === REMEDY_ACTION.ADVISE)
387
+ continue;
388
+ const requested = remedy.action === REMEDY_ACTION.BACKFILL_MILESTONES ? repair || backfill : repair;
389
+ if (!requested)
390
+ continue;
391
+ if (remedy.risk === REMEDY_RISK.DESTRUCTIVE) {
392
+ refused.push(code);
393
+ details.push({
394
+ code,
395
+ action: remedy.action,
396
+ success: false,
397
+ error: `refused: '${remedy.action}' is a destructive remedy and is not auto-applied by --repair`,
398
+ });
399
+ continue;
400
+ }
401
+ try {
402
+ const outcome = runRepairAction(cwd, remedy.action, paths);
403
+ if (outcome.extraDetails) {
404
+ for (const extra of outcome.extraDetails) {
405
+ details.push({ code, action: extra.action, success: extra.success, ...(extra.path ? { path: extra.path } : {}) });
406
+ }
407
+ }
408
+ details.push({
409
+ code,
410
+ action: remedy.action,
411
+ success: outcome.success,
412
+ ...(outcome.path ? { path: outcome.path } : {}),
413
+ ...(outcome.detail ? { detail: outcome.detail } : {}),
414
+ ...(outcome.error ? { error: outcome.error } : {}),
415
+ });
416
+ // `applied` means "the repair actually succeeded", not "was attempted"
417
+ // — a handler that returns `{success: false}` (or throws, caught
418
+ // below) is recorded in `details` with its failure, but must not be
419
+ // reported as applied. `refused` is reserved for the DESTRUCTIVE-risk
420
+ // gate above; a failed attempt is neither applied nor refused.
421
+ if (outcome.success)
422
+ applied.push(code);
423
+ }
424
+ catch (err) {
425
+ details.push({
426
+ code,
427
+ action: remedy.action,
428
+ success: false,
429
+ error: err instanceof Error ? err.message : String(err),
430
+ });
431
+ }
432
+ }
433
+ return { applied, refused, details };
434
+ }
435
+ // ─── Exports ────────────────────────────────────────────────────────────────
436
+ const healthDiagnostic = {
437
+ SEVERITY,
438
+ REMEDY_ACTION,
439
+ REMEDY_RISK,
440
+ RULES,
441
+ evaluateRules,
442
+ // Additive beyond the phase's required-exports list — exposed so the
443
+ // duplicate-code guard (row 13) is directly unit-testable against a fake
444
+ // rule array without mutating the real, still-empty `RULES` export.
445
+ evaluateRuleTable,
446
+ applyRepairs,
447
+ // Phase 12 (#3310) — `validate.consistency`'s own rule subset + evaluator.
448
+ CONSISTENCY_RULES,
449
+ evaluateConsistencyRules,
450
+ };
451
+ module.exports = healthDiagnostic;
@@ -653,10 +653,25 @@ function extensionEventSurfaceFor(extensionEvents) {
653
653
  * per-host branch ADR-1239 exists to remove. Omit `prompt` entirely and the
654
654
  * resolution is byte-identical to Phase 2's (the unconsumed-resolver shape).
655
655
  *
656
- * Argv order is base args → cwd flag → prompt, so the prompt stays the final
657
- * positional token for the hosts that read it that way.
656
+ * Argv order is base args → model flag → cwd flag → prompt, so the prompt
657
+ * stays the final positional token for the hosts that read it that way. The
658
+ * model flag is placed BEFORE the cwd flag (not after, and not appended at
659
+ * the very end) purely to keep it clear of that trailing positional — the
660
+ * model value itself is never the prompt-adjacent token a host might scan
661
+ * for last.
662
+ *
663
+ * `model` (Phase 4, #3714) is optional, descriptor-gated exactly like prompt:
664
+ * a `modelFlag` string on the descriptor names the flag that pins the
665
+ * spawned executor's model (codex: `--model`); `null`/absent means the host
666
+ * exposes no such override on this exec path, and `[modelFlag, model]` is
667
+ * appended ONLY when both the descriptor's `modelFlag` and the caller's
668
+ * `model` are non-empty strings. Omitting `model` entirely (or passing it to
669
+ * a host with no `modelFlag`) is byte-identical to the resolver's behavior
670
+ * before this parameter existed. This function decides no policy about WHICH
671
+ * model to pass or what 'inherit' means — that is entirely the caller's job;
672
+ * this seam only shapes descriptor + values into argv.
658
673
  */
659
- function resolveOrchestratorExec(orchestratorExec, cwd, prompt) {
674
+ function resolveOrchestratorExec(orchestratorExec, cwd, prompt, model) {
660
675
  if (!orchestratorExec || typeof orchestratorExec !== 'object' || Array.isArray(orchestratorExec)) {
661
676
  return { ok: false, reason: 'missing_command' };
662
677
  }
@@ -676,11 +691,22 @@ function resolveOrchestratorExec(orchestratorExec, cwd, prompt) {
676
691
  if (oe.promptFlag !== undefined && oe.promptFlag !== null && typeof oe.promptFlag !== 'string') {
677
692
  return { ok: false, reason: 'invalid_prompt_flag' };
678
693
  }
694
+ if (oe.modelFlag !== undefined && oe.modelFlag !== null && typeof oe.modelFlag !== 'string') {
695
+ return { ok: false, reason: 'invalid_model_flag' };
696
+ }
679
697
  // An executor spawned with no instruction is a hang, not a degraded run —
680
698
  // fail closed rather than launching a prompt-less process.
681
699
  if (prompt !== undefined && (typeof prompt !== 'string' || prompt.length === 0)) {
682
700
  return { ok: false, reason: 'invalid_prompt' };
683
701
  }
702
+ // Unlike `prompt` — where empty is a hang, not a degraded run, hence the
703
+ // fail-closed check above — an absent/null/empty model is simply "use the
704
+ // host default", the same benign degradation `cwdFlag: null` already
705
+ // expresses. Only a present-but-non-string value (number/bool/array/object)
706
+ // is a caller error; null/undefined/'' fall through to "omit the flag".
707
+ if (model !== undefined && model !== null && typeof model !== 'string') {
708
+ return { ok: false, reason: 'invalid_model' };
709
+ }
684
710
  // Leading-dash guard, mirroring worktree-safety.cts's `unsafe_leading_dash`
685
711
  // check on git arguments. A positional prompt (or a cwd) beginning with '-'
686
712
  // is parsed by the spawned CLI as a FLAG, not a value — the same failure the
@@ -695,10 +721,17 @@ function resolveOrchestratorExec(orchestratorExec, cwd, prompt) {
695
721
  if (cwd.startsWith('-')) {
696
722
  return { ok: false, reason: 'unsafe_leading_dash_cwd' };
697
723
  }
724
+ if (typeof model === 'string' && model.startsWith('-')) {
725
+ return { ok: false, reason: 'unsafe_leading_dash_model' };
726
+ }
698
727
  const baseArgs = Array.isArray(oe.args) ? [...oe.args] : [];
699
- const args = typeof oe.cwdFlag === 'string' && oe.cwdFlag.length > 0
700
- ? [...baseArgs, oe.cwdFlag, cwd]
701
- : baseArgs;
728
+ let args = baseArgs;
729
+ if (typeof oe.modelFlag === 'string' && oe.modelFlag.length > 0 && typeof model === 'string' && model.length > 0) {
730
+ args = [...args, oe.modelFlag, model];
731
+ }
732
+ args = typeof oe.cwdFlag === 'string' && oe.cwdFlag.length > 0
733
+ ? [...args, oe.cwdFlag, cwd]
734
+ : args;
702
735
  if (typeof prompt === 'string') {
703
736
  if (typeof oe.promptFlag === 'string' && oe.promptFlag.length > 0) {
704
737
  args.push(oe.promptFlag, prompt);
@@ -0,0 +1,134 @@
1
+ "use strict";
2
+ /**
3
+ * Host runtime detection — ADR-2313 Phase 5 (#3245, folded from #2320).
4
+ *
5
+ * `init`'s reported `agent_runtime` was hardcoding `claude` even when run
6
+ * inside a Codex session, because resolveRuntime's ladder only checks the
7
+ * explicit `GSD_RUNTIME` env var and `.planning/config.json`'s `runtime`
8
+ * field — there was no fallback that looked at the actual host process.
9
+ *
10
+ * This module adds a host-detection rung strictly BELOW those two explicit
11
+ * sources: it only runs when neither `GSD_RUNTIME` nor config `runtime` is
12
+ * set. It never writes anything (#2297 — no shared-defaults poisoning: this
13
+ * module never touches .planning/config.json or any other file). It never
14
+ * shells out, so there is no subprocess to time-bound — detection is pure
15
+ * env-var and existence-check inspection.
16
+ */
17
+ var __importDefault = (this && this.__importDefault) || function (mod) {
18
+ return (mod && mod.__esModule) ? mod : { "default": mod };
19
+ };
20
+ Object.defineProperty(exports, "__esModule", { value: true });
21
+ exports.CODEX_CONFIG_HOME_ENV = exports.CODEX_SESSION_ENV_SIGNALS = exports.CODEX_CONFIG_MARKER = void 0;
22
+ exports.detectHostRuntime = detectHostRuntime;
23
+ exports.resolveReportedRuntime = resolveReportedRuntime;
24
+ const node_fs_1 = __importDefault(require("node:fs"));
25
+ const node_path_1 = __importDefault(require("node:path"));
26
+ const runtime_slash_cjs_1 = require("./runtime-slash.cjs");
27
+ const update_context_cjs_1 = require("./update-context.cjs");
28
+ Object.defineProperty(exports, "CODEX_CONFIG_MARKER", { enumerable: true, get: function () { return update_context_cjs_1.CODEX_CONFIG_MARKER; } });
29
+ // Codex sandbox env vars set by the shell tool / Seatbelt child-process spawn.
30
+ // Evidence: openai/codex AGENTS.md — "The sandbox environment automatically
31
+ // sets CODEX_SANDBOX_NETWORK_DISABLED=1 when using the shell tool, and
32
+ // CODEX_SANDBOX=seatbelt for child processes spawned via Seatbelt." (injected
33
+ // by spawn_child_async in codex-rs/core/src/spawn.rs). These are absent under
34
+ // sandbox_mode = "danger-full-access", so this signal is best-effort and
35
+ // degrades to the default when unset.
36
+ //
37
+ // Note: CODEX_THREAD_ID (which appears in src/active-workstream-store.cts's
38
+ // WORKSTREAM_SESSION_ENV_KEYS) is deliberately NOT used here — it is
39
+ // undocumented in Codex's published env-var reference and source, so it
40
+ // fails this repo's citation bar.
41
+ exports.CODEX_SESSION_ENV_SIGNALS = Object.freeze([
42
+ 'CODEX_SANDBOX',
43
+ 'CODEX_SANDBOX_NETWORK_DISABLED',
44
+ ]);
45
+ // Evidence: learn.chatgpt.com/docs/config-file/environment-variables —
46
+ // "Sets the root for Codex state, including config…". The marker FILENAME
47
+ // (`config.toml`) is single-sourced from `update-context.cts`'s
48
+ // `inferPreferredRuntime` (imported above and re-exported for existing
49
+ // importers) — that is the only thing shared between the two functions. The
50
+ // TRUTHINESS RULE deliberately differs: `inferPreferredRuntime` treats a
51
+ // bare, unchecked `CODEX_HOME` as sufficient to resolve an update context,
52
+ // while THIS module additionally requires the marker file to exist, because
53
+ // it is asserting session identity rather than resolving an update context
54
+ // and needs the stronger signal. That difference is intentional and pinned
55
+ // by a test in `tests/host-runtime-detection.test.cjs` rather than left
56
+ // implicit.
57
+ //
58
+ // The DEFAULT `~/.codex/config.toml` is deliberately NEVER probed here:
59
+ // every machine that has ever run Codex has that file, so probing it
60
+ // unconditionally would misreport Claude Code sessions (or any other
61
+ // runtime) as codex just because Codex was installed at some point. An
62
+ // explicitly-exported CODEX_HOME is the user designating a Codex root for
63
+ // the CURRENT session, which is a much stronger signal.
64
+ exports.CODEX_CONFIG_HOME_ENV = 'CODEX_HOME';
65
+ // The degraded no-detection result. Also the fallback returned when ANY step
66
+ // of detection throws (see the module's stated no-throw premise below).
67
+ const NO_DETECTION = { runtime: null, source: 'none', signal: null };
68
+ /**
69
+ * Detect the host runtime from process environment signals, without ever
70
+ * consulting the explicit GSD_RUNTIME/config.json sources (those are a
71
+ * higher-priority rung handled by resolveExplicitRuntime).
72
+ *
73
+ * Never throws: the whole body — including the raw `env[key]` reads, which a
74
+ * caller could supply as a throwing Proxy — is wrapped in a single guarded
75
+ * region that degrades to `NO_DETECTION` on any unexpected error, rather than
76
+ * only guarding the `fileExists` probe.
77
+ */
78
+ function detectHostRuntime(deps) {
79
+ try {
80
+ const env = deps?.env ?? process.env;
81
+ const fileExists = deps?.fileExists ?? ((p) => node_fs_1.default.existsSync(p));
82
+ for (const key of exports.CODEX_SESSION_ENV_SIGNALS) {
83
+ const value = env[key];
84
+ if (typeof value === 'string' && value.trim() !== '') {
85
+ return { runtime: 'codex', source: 'session-env', signal: key };
86
+ }
87
+ }
88
+ const codexHome = env[exports.CODEX_CONFIG_HOME_ENV];
89
+ if (typeof codexHome === 'string' && codexHome.trim() !== '') {
90
+ try {
91
+ if (fileExists(node_path_1.default.join(codexHome, update_context_cjs_1.CODEX_CONFIG_MARKER))) {
92
+ return { runtime: 'codex', source: 'config-home', signal: exports.CODEX_CONFIG_HOME_ENV };
93
+ }
94
+ }
95
+ catch {
96
+ // Swallow probe failures (EACCES etc.) and fall through to no-detection.
97
+ }
98
+ }
99
+ return NO_DETECTION;
100
+ }
101
+ catch {
102
+ // A malformed `deps.env` (e.g. a throwing Proxy) must degrade like any
103
+ // other unreadable signal, not propagate — this function's contract is
104
+ // that it never throws.
105
+ return NO_DETECTION;
106
+ }
107
+ }
108
+ /**
109
+ * Resolve the runtime to report from init: explicit sources first, then the
110
+ * host-detection rung, then the 'claude' default. This is intentionally
111
+ * separate from resolveRuntime — only init's agent_runtime reporting call
112
+ * site uses this ladder; every other resolveRuntime caller is unaffected.
113
+ *
114
+ * Never throws: degrades to the 'claude' default on any unexpected error
115
+ * (e.g. a throwing `deps.env`), matching detectHostRuntime's no-throw
116
+ * contract.
117
+ */
118
+ function resolveReportedRuntime(projectDir, deps) {
119
+ try {
120
+ return resolveReportedRuntimeUnsafe(projectDir, deps);
121
+ }
122
+ catch {
123
+ return 'claude';
124
+ }
125
+ }
126
+ function resolveReportedRuntimeUnsafe(projectDir, deps) {
127
+ const explicit = (0, runtime_slash_cjs_1.resolveExplicitRuntime)(projectDir, deps?.env ?? process.env);
128
+ if (explicit)
129
+ return explicit;
130
+ const detected = detectHostRuntime(deps);
131
+ if (detected.runtime)
132
+ return detected.runtime;
133
+ return 'claude';
134
+ }