@opengsd/gsd-core 1.15.0 → 1.17.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 (505) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -2
  3. package/.opencode/plugins/gsd-core.js +336 -6
  4. package/.opencode/plugins/gsd-statusline/tui.tsx +55 -0
  5. package/GEMINI.md +1 -1
  6. package/agents/gsd-code-fixer.compact.md +1 -1
  7. package/agents/gsd-code-fixer.md +1 -1
  8. package/agents/gsd-code-reviewer.compact.md +5 -3
  9. package/agents/gsd-code-reviewer.md +8 -6
  10. package/agents/gsd-debug-session-manager.compact.md +7 -1
  11. package/agents/gsd-debug-session-manager.md +7 -1
  12. package/agents/gsd-debugger.md +2 -2
  13. package/agents/gsd-eval-auditor.compact.md +1 -1
  14. package/agents/gsd-eval-auditor.md +1 -1
  15. package/agents/gsd-executor.md +4 -4
  16. package/agents/gsd-intel-updater.compact.md +1 -1
  17. package/agents/gsd-intel-updater.md +1 -1
  18. package/agents/gsd-mempalace-curator.md +2 -2
  19. package/agents/gsd-phase-researcher.md +1 -1
  20. package/agents/gsd-plan-checker.md +7 -2
  21. package/agents/gsd-planner.md +3 -3
  22. package/agents/gsd-project-researcher.compact.md +1 -1
  23. package/agents/gsd-project-researcher.md +1 -1
  24. package/agents/gsd-research-synthesizer.compact.md +1 -1
  25. package/agents/gsd-research-synthesizer.md +1 -1
  26. package/agents/gsd-ui-auditor.compact.md +21 -30
  27. package/agents/gsd-ui-auditor.md +42 -51
  28. package/agents/gsd-ui-researcher.compact.md +1 -1
  29. package/agents/gsd-ui-researcher.md +1 -1
  30. package/agents/gsd-verifier.md +31 -9
  31. package/bin/gsd-mcp-server.js +3 -1
  32. package/bin/install.js +487 -290
  33. package/commands/gsd/add-tests.md +6 -1
  34. package/commands/gsd/ai-integration-phase.md +6 -1
  35. package/commands/gsd/audit-fix.md +5 -0
  36. package/commands/gsd/audit-milestone.md +6 -1
  37. package/commands/gsd/autonomous.md +5 -0
  38. package/commands/gsd/capture.md +8 -4
  39. package/commands/gsd/code-review.md +7 -2
  40. package/commands/gsd/complete-milestone.md +4 -0
  41. package/commands/gsd/config.md +7 -3
  42. package/commands/gsd/debug.md +11 -7
  43. package/commands/gsd/discuss-phase.md +7 -3
  44. package/commands/gsd/docs-update.md +12 -7
  45. package/commands/gsd/eval-review.md +6 -1
  46. package/commands/gsd/execute-phase.md +12 -7
  47. package/commands/gsd/extract-learnings.md +5 -0
  48. package/commands/gsd/fast.md +4 -0
  49. package/commands/gsd/forensics.md +5 -1
  50. package/commands/gsd/graphify.md +10 -6
  51. package/commands/gsd/health.md +5 -0
  52. package/commands/gsd/help.md +7 -2
  53. package/commands/gsd/import.md +7 -3
  54. package/commands/gsd/inbox.md +5 -0
  55. package/commands/gsd/ingest-docs.md +5 -1
  56. package/commands/gsd/manager.md +6 -1
  57. package/commands/gsd/map-codebase.md +7 -3
  58. package/commands/gsd/mempalace-capture.md +5 -1
  59. package/commands/gsd/mempalace-recall.md +5 -1
  60. package/commands/gsd/milestone-summary.md +5 -1
  61. package/commands/gsd/mvp-phase.md +8 -3
  62. package/commands/gsd/new-milestone.md +6 -1
  63. package/commands/gsd/new-project.md +5 -0
  64. package/commands/gsd/next.md +6 -1
  65. package/commands/gsd/ns-context.md +4 -0
  66. package/commands/gsd/ns-ideate.md +4 -0
  67. package/commands/gsd/ns-manage.md +4 -0
  68. package/commands/gsd/ns-project.md +4 -0
  69. package/commands/gsd/ns-review.md +4 -0
  70. package/commands/gsd/ns-workflow.md +4 -0
  71. package/commands/gsd/onboard.md +6 -1
  72. package/commands/gsd/pause-work.md +5 -1
  73. package/commands/gsd/phase.md +8 -4
  74. package/commands/gsd/plan-phase.md +6 -1
  75. package/commands/gsd/plan-review-convergence.md +5 -1
  76. package/commands/gsd/pr-branch.md +4 -0
  77. package/commands/gsd/profile-user.md +5 -1
  78. package/commands/gsd/progress.md +6 -1
  79. package/commands/gsd/quick-batch.md +20 -8
  80. package/commands/gsd/quick.md +12 -7
  81. package/commands/gsd/review.md +5 -1
  82. package/commands/gsd/secure-phase.md +6 -1
  83. package/commands/gsd/ship.md +5 -0
  84. package/commands/gsd/sketch.md +7 -2
  85. package/commands/gsd/spec-phase.md +5 -1
  86. package/commands/gsd/spike.md +8 -3
  87. package/commands/gsd/surface.md +5 -1
  88. package/commands/gsd/thread.md +4 -0
  89. package/commands/gsd/ui-phase.md +6 -1
  90. package/commands/gsd/ui-review.md +6 -1
  91. package/commands/gsd/ultraplan-phase.md +5 -1
  92. package/commands/gsd/undo.md +5 -1
  93. package/commands/gsd/update.md +6 -2
  94. package/commands/gsd/validate-phase.md +6 -1
  95. package/commands/gsd/verify-work.md +6 -1
  96. package/commands/gsd/workspace.md +7 -3
  97. package/gsd-core/bin/gsd-tools.cjs +159 -58
  98. package/gsd-core/bin/lib/active-workstream-store.cjs +15 -0
  99. package/gsd-core/bin/lib/adr-parser.cjs +37 -5
  100. package/gsd-core/bin/lib/agent-install-check.cjs +4 -1
  101. package/gsd-core/bin/lib/audit.cjs +78 -44
  102. package/gsd-core/bin/lib/broken-windows.cjs +13 -13
  103. package/gsd-core/bin/lib/capability-activation.cjs +9 -4
  104. package/gsd-core/bin/lib/capability-registry.cjs +249 -117
  105. package/gsd-core/bin/lib/capability-validator.cjs +18 -1
  106. package/gsd-core/bin/lib/capability-writer.cjs +2 -1
  107. package/gsd-core/bin/lib/check-auto-mode.cjs +35 -0
  108. package/gsd-core/bin/lib/check-command-router.cjs +164 -1712
  109. package/gsd-core/bin/lib/cjs-command-router-adapter.cjs +13 -2
  110. package/gsd-core/bin/lib/cli-exit.cjs +12 -0
  111. package/gsd-core/bin/lib/codex-agent-toml.cjs +11 -8
  112. package/gsd-core/bin/lib/command-aliases.cjs +7 -0
  113. package/gsd-core/bin/lib/command-routing-hub.cjs +48 -1
  114. package/gsd-core/bin/lib/commands.cjs +201 -178
  115. package/gsd-core/bin/lib/complexity-trigger.cjs +8 -7
  116. package/gsd-core/bin/lib/config.cjs +43 -12
  117. package/gsd-core/bin/lib/core-utils.cjs +6 -1
  118. package/gsd-core/bin/lib/coverage.cjs +4 -8
  119. package/gsd-core/bin/lib/decision-coverage-support.cjs +259 -0
  120. package/gsd-core/bin/lib/drift.cjs +177 -42
  121. package/gsd-core/bin/lib/frontmatter-fence.cjs +90 -0
  122. package/gsd-core/bin/lib/frontmatter-splice.cjs +494 -0
  123. package/gsd-core/bin/lib/frontmatter.cjs +413 -234
  124. package/gsd-core/bin/lib/gap-checker.cjs +72 -29
  125. package/gsd-core/bin/lib/gate-api-coverage-verify-pre.cjs +381 -0
  126. package/gsd-core/bin/lib/gate-args.cjs +53 -0
  127. package/gsd-core/bin/lib/gate-codebase-drift.cjs +285 -0
  128. package/gsd-core/bin/lib/gate-config.cjs +46 -0
  129. package/gsd-core/bin/lib/gate-context-drift.cjs +142 -0
  130. package/gsd-core/bin/lib/gate-decision-coverage-plan.cjs +169 -0
  131. package/gsd-core/bin/lib/gate-decision-coverage-verify.cjs +126 -0
  132. package/gsd-core/bin/lib/gate-evaluation-scope.cjs +555 -0
  133. package/gsd-core/bin/lib/gate-evidence.cjs +138 -0
  134. package/gsd-core/bin/lib/gate-exit.cjs +27 -0
  135. package/gsd-core/bin/lib/gate-gap-analysis-plan-post.cjs +61 -0
  136. package/gsd-core/bin/lib/gate-phase-context.cjs +170 -0
  137. package/gsd-core/bin/lib/gate-predicate-evaluator.cjs +1 -1
  138. package/gsd-core/bin/lib/gate-predicate.cjs +165 -0
  139. package/gsd-core/bin/lib/gate-prohibition-enforcement.cjs +94 -0
  140. package/gsd-core/bin/lib/gate-schema-drift.cjs +165 -0
  141. package/gsd-core/bin/lib/gate-tdd-red-evidence.cjs +100 -0
  142. package/gsd-core/bin/lib/gate-tdd-review-checkpoint.cjs +182 -0
  143. package/gsd-core/bin/lib/gate-ui-plan.cjs +86 -0
  144. package/gsd-core/bin/lib/gate-ui-safety.cjs +81 -0
  145. package/gsd-core/bin/lib/gate-verdict.cjs +64 -0
  146. package/gsd-core/bin/lib/gate-verify-command-paths.cjs +78 -0
  147. package/gsd-core/bin/lib/gate-verify-failure-directions.cjs +41 -0
  148. package/gsd-core/bin/lib/graphify.cjs +3 -2
  149. package/gsd-core/bin/lib/health-diagnostic-rules/phase-structure.cjs +43 -47
  150. package/gsd-core/bin/lib/health-diagnostic.cjs +45 -8
  151. package/gsd-core/bin/lib/init.cjs +194 -108
  152. package/gsd-core/bin/lib/install-engine.cjs +30 -35
  153. package/gsd-core/bin/lib/install-profiles.cjs +7 -4
  154. package/gsd-core/bin/lib/install-shadow-report.cjs +12 -0
  155. package/gsd-core/bin/lib/installer-migrations/011-opencode-mcp-no-prompts.cjs +99 -0
  156. package/gsd-core/bin/lib/installer-migrations.cjs +54 -1
  157. package/gsd-core/bin/lib/io.cjs +122 -3
  158. package/gsd-core/bin/lib/jsonc-edit.cjs +418 -0
  159. package/gsd-core/bin/lib/loop-host-contract.cjs +2 -1
  160. package/gsd-core/bin/lib/loop-resolver.cjs +95 -0
  161. package/gsd-core/bin/lib/markdown-sectionizer.cjs +75 -1
  162. package/gsd-core/bin/lib/mcp-server.cjs +5 -1
  163. package/gsd-core/bin/lib/milestone.cjs +19 -1
  164. package/gsd-core/bin/lib/model-resolver.cjs +18 -18
  165. package/gsd-core/bin/lib/observability/event.cjs +1 -1
  166. package/gsd-core/bin/lib/observability/logger.cjs +46 -1
  167. package/gsd-core/bin/lib/opencode-mcp-entry.cjs +39 -0
  168. package/gsd-core/bin/lib/opencode-version.cjs +486 -0
  169. package/gsd-core/bin/lib/pattern.cjs +10 -0
  170. package/gsd-core/bin/lib/phase-command-router.cjs +11 -4
  171. package/gsd-core/bin/lib/phase-estimation.cjs +5 -4
  172. package/gsd-core/bin/lib/phase-id.cjs +1 -1
  173. package/gsd-core/bin/lib/phase-lifecycle.cjs +9 -2
  174. package/gsd-core/bin/lib/phase-status.cjs +360 -0
  175. package/gsd-core/bin/lib/phase.cjs +301 -80
  176. package/gsd-core/bin/lib/plan-document.cjs +93 -19
  177. package/gsd-core/bin/lib/plan-drift-guard.cjs +5 -0
  178. package/gsd-core/bin/lib/planning-document.cjs +273 -40
  179. package/gsd-core/bin/lib/planning-inspect.cjs +42 -8
  180. package/gsd-core/bin/lib/planning-snapshot.cjs +18 -0
  181. package/gsd-core/bin/lib/planning-workspace.cjs +76 -53
  182. package/gsd-core/bin/lib/pristine-baseline.cjs +10 -0
  183. package/gsd-core/bin/lib/profile-output.cjs +6 -3
  184. package/gsd-core/bin/lib/prohibition-enforcement.cjs +0 -55
  185. package/gsd-core/bin/lib/quick-batch-command-router.cjs +35 -9
  186. package/gsd-core/bin/lib/quick-batch-dispatch.cjs +13 -9
  187. package/gsd-core/bin/lib/real-home-guard.cjs +9 -1
  188. package/gsd-core/bin/lib/report-parser.cjs +269 -0
  189. package/gsd-core/bin/lib/roadmap-command-router.cjs +13 -15
  190. package/gsd-core/bin/lib/roadmap-parser.cjs +82 -15
  191. package/gsd-core/bin/lib/roadmap-upgrade.cjs +127 -65
  192. package/gsd-core/bin/lib/roadmap.cjs +169 -72
  193. package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +186 -161
  194. package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +2 -1
  195. package/gsd-core/bin/lib/runtime-artifact-layout.cjs +57 -1
  196. package/gsd-core/bin/lib/runtime-homes.cjs +13 -10
  197. package/gsd-core/bin/lib/runtime-hooks-surface.cjs +365 -594
  198. package/gsd-core/bin/lib/runtime-name-policy.cjs +142 -27
  199. package/gsd-core/bin/lib/runtime-slash.cjs +60 -30
  200. package/gsd-core/bin/lib/shell-command-projection.cjs +37 -2
  201. package/gsd-core/bin/lib/smart-entry.cjs +111 -56
  202. package/gsd-core/bin/lib/stale-bake-guard.cjs +32 -48
  203. package/gsd-core/bin/lib/state-contract.cjs +15 -18
  204. package/gsd-core/bin/lib/state-document.cjs +100 -22
  205. package/gsd-core/bin/lib/state-transition.cjs +67 -9
  206. package/gsd-core/bin/lib/state.cjs +668 -171
  207. package/gsd-core/bin/lib/surface.cjs +2 -1
  208. package/gsd-core/bin/lib/tdd-red-evidence.cjs +48 -152
  209. package/gsd-core/bin/lib/uat-predicate.cjs +313 -35
  210. package/gsd-core/bin/lib/uat.cjs +424 -7
  211. package/gsd-core/bin/lib/ui-frontend-evidence.cjs +94 -58
  212. package/gsd-core/bin/lib/update-context.cjs +18 -1
  213. package/gsd-core/bin/lib/vendor/README.md +31 -9
  214. package/gsd-core/bin/lib/vendor/saxes.cjs +1934 -0
  215. package/gsd-core/bin/lib/vendor/saxes.cjs.LICENSE.txt +92 -0
  216. package/gsd-core/bin/lib/vendor/tap-parser.cjs +8927 -0
  217. package/gsd-core/bin/lib/vendor/tap-parser.cjs.LICENSE.txt +152 -0
  218. package/gsd-core/bin/lib/verification-command-router.cjs +2 -1
  219. package/gsd-core/bin/lib/verification.cjs +1265 -324
  220. package/gsd-core/bin/lib/verify-command-router.cjs +18 -7
  221. package/gsd-core/bin/lib/verify.cjs +286 -567
  222. package/gsd-core/bin/lib/workstream-inventory-builder.cjs +14 -6
  223. package/gsd-core/bin/lib/workstream-inventory.cjs +31 -21
  224. package/gsd-core/bin/lib/workstream-name-policy.cjs +31 -1
  225. package/gsd-core/bin/lib/workstream.cjs +11 -2
  226. package/gsd-core/bin/shared/config-defaults.manifest.json +5 -0
  227. package/gsd-core/bin/shared/config-schema.manifest.json +4 -0
  228. package/gsd-core/references/autonomous-smart-discuss.md +2 -1
  229. package/gsd-core/references/autonomous-ui-design-contract.md +3 -3
  230. package/gsd-core/references/execute-mvp-tdd.md +5 -10
  231. package/gsd-core/references/execute-phase-between-wave-reset.md +3 -0
  232. package/gsd-core/references/execute-phase-response-language.md +1 -1
  233. package/gsd-core/references/gsd-run-resolver.md +1 -1
  234. package/gsd-core/references/loop-hook-dispatch.md +7 -1
  235. package/gsd-core/references/offer-next.md +1 -1
  236. package/gsd-core/references/planning-config.md +1 -1
  237. package/gsd-core/references/spidr-splitting.md +1 -1
  238. package/gsd-core/references/tdd.md +10 -4
  239. package/gsd-core/references/verifier-phase-gates.md +5 -2
  240. package/gsd-core/references/verify-mvp-mode.md +2 -2
  241. package/gsd-core/references/workstream-flag.md +33 -3
  242. package/gsd-core/templates/README.md +1 -1
  243. package/gsd-core/templates/UAT.md +17 -1
  244. package/gsd-core/templates/config.json +2 -11
  245. package/gsd-core/templates/verification-report.md +1 -1
  246. package/gsd-core/workflows/_runtime-launcher.snippet.sh +1 -1
  247. package/gsd-core/workflows/add-backlog.md +1 -1
  248. package/gsd-core/workflows/add-phase.md +8 -7
  249. package/gsd-core/workflows/add-tests.md +3 -2
  250. package/gsd-core/workflows/add-todo.md +4 -3
  251. package/gsd-core/workflows/ai-integration-phase.md +3 -2
  252. package/gsd-core/workflows/audit-fix.md +1 -1
  253. package/gsd-core/workflows/audit-milestone.md +4 -3
  254. package/gsd-core/workflows/audit-uat.md +1 -1
  255. package/gsd-core/workflows/autonomous.md +28 -18
  256. package/gsd-core/workflows/check-todos.md +6 -5
  257. package/gsd-core/workflows/cleanup.md +1 -1
  258. package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +20 -13
  259. package/gsd-core/workflows/code-review-fix.md +5 -4
  260. package/gsd-core/workflows/code-review.md +100 -91
  261. package/gsd-core/workflows/complete-milestone/detail/elaboration.md +4 -3
  262. package/gsd-core/workflows/complete-milestone.md +12 -7
  263. package/gsd-core/workflows/debug.md +30 -5
  264. package/gsd-core/workflows/diagnose-issues.md +3 -2
  265. package/gsd-core/workflows/discuss-phase/modes/advisor.md +1 -1
  266. package/gsd-core/workflows/discuss-phase/modes/chain.md +1 -1
  267. package/gsd-core/workflows/discuss-phase-assumptions.md +4 -3
  268. package/gsd-core/workflows/discuss-phase.md +4 -3
  269. package/gsd-core/workflows/do.md +1 -1
  270. package/gsd-core/workflows/docs-update.md +4 -3
  271. package/gsd-core/workflows/edit-phase.md +4 -3
  272. package/gsd-core/workflows/eval-review.md +5 -3
  273. package/gsd-core/workflows/execute-phase/detail/elaboration.md +1 -1
  274. package/gsd-core/workflows/execute-phase/steps/code-review-disposition.md +4 -2
  275. package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +15 -4
  276. package/gsd-core/workflows/execute-phase/steps/completion-reconciliation.md +10 -7
  277. package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +2 -2
  278. package/gsd-core/workflows/execute-phase/steps/gap-closure-artifacts.md +3 -1
  279. package/gsd-core/workflows/execute-phase/steps/partial-wave.md +2 -2
  280. package/gsd-core/workflows/execute-phase/steps/per-plan-executor-routing.md +1 -1
  281. package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +1 -1
  282. package/gsd-core/workflows/execute-phase/steps/post-merge-gate.md +1 -1
  283. package/gsd-core/workflows/execute-phase/steps/protected-branch.md +1 -1
  284. package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +1 -1
  285. package/gsd-core/workflows/execute-phase/steps/regression-gate.md +2 -0
  286. package/gsd-core/workflows/execute-phase/steps/tdd-applicability-resolution.md +1 -1
  287. package/gsd-core/workflows/execute-phase/steps/verify-phase-goal.md +187 -0
  288. package/gsd-core/workflows/execute-phase/steps/wave-post-gate-hooks.md +2 -3
  289. package/gsd-core/workflows/execute-phase.md +81 -171
  290. package/gsd-core/workflows/execute-plan.md +13 -19
  291. package/gsd-core/workflows/explore.md +2 -2
  292. package/gsd-core/workflows/extract-learnings.md +3 -2
  293. package/gsd-core/workflows/fast.md +1 -1
  294. package/gsd-core/workflows/forensics.md +1 -1
  295. package/gsd-core/workflows/graduation.md +1 -1
  296. package/gsd-core/workflows/health.md +2 -1
  297. package/gsd-core/workflows/import.md +3 -2
  298. package/gsd-core/workflows/inbox.md +1 -1
  299. package/gsd-core/workflows/ingest-docs.md +1 -1
  300. package/gsd-core/workflows/insert-phase.md +4 -3
  301. package/gsd-core/workflows/list-seeds.md +1 -1
  302. package/gsd-core/workflows/list-workspaces.md +1 -1
  303. package/gsd-core/workflows/manager.md +5 -3
  304. package/gsd-core/workflows/map-codebase.md +4 -3
  305. package/gsd-core/workflows/milestone-summary.md +3 -2
  306. package/gsd-core/workflows/mvp-phase.md +14 -14
  307. package/gsd-core/workflows/new-milestone.md +10 -10
  308. package/gsd-core/workflows/new-project/steps/auto-mode-config.md +1 -1
  309. package/gsd-core/workflows/new-project.md +1 -1
  310. package/gsd-core/workflows/new-workspace.md +1 -1
  311. package/gsd-core/workflows/next.md +1 -1
  312. package/gsd-core/workflows/pause-work.md +2 -2
  313. package/gsd-core/workflows/plan-phase/detail/elaboration.md +1 -1
  314. package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +1 -1
  315. package/gsd-core/workflows/plan-phase/steps/closed-phase-gate.md +1 -1
  316. package/gsd-core/workflows/plan-phase/steps/prd-express-path.md +1 -1
  317. package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +1 -1
  318. package/gsd-core/workflows/plan-phase.md +27 -18
  319. package/gsd-core/workflows/plan-review-convergence.md +1 -1
  320. package/gsd-core/workflows/plant-seed.md +1 -1
  321. package/gsd-core/workflows/pr-branch.md +1 -1
  322. package/gsd-core/workflows/profile-user.md +1 -1
  323. package/gsd-core/workflows/progress.md +19 -49
  324. package/gsd-core/workflows/quick/steps/plan-checker-loop.md +4 -2
  325. package/gsd-core/workflows/quick/steps/quick-verification.md +4 -4
  326. package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +30 -11
  327. package/gsd-core/workflows/quick-batch/steps/batch-init.md +1 -1
  328. package/gsd-core/workflows/quick-batch/steps/completion.md +1 -1
  329. package/gsd-core/workflows/quick-batch/steps/merge-wave.md +1 -1
  330. package/gsd-core/workflows/quick-batch/steps/planner-wave.md +1 -1
  331. package/gsd-core/workflows/quick-batch/steps/research-phase.md +1 -1
  332. package/gsd-core/workflows/quick-batch/steps/resume-mode.md +1 -1
  333. package/gsd-core/workflows/quick-batch/steps/verification-wave.md +9 -3
  334. package/gsd-core/workflows/quick-batch/steps/worktree-dispatch.md +1 -1
  335. package/gsd-core/workflows/quick-batch.md +15 -10
  336. package/gsd-core/workflows/quick.md +42 -31
  337. package/gsd-core/workflows/remove-phase.md +3 -2
  338. package/gsd-core/workflows/remove-workspace.md +1 -1
  339. package/gsd-core/workflows/resume-project.md +17 -12
  340. package/gsd-core/workflows/review.md +3 -2
  341. package/gsd-core/workflows/scan.md +3 -2
  342. package/gsd-core/workflows/secure-phase.md +11 -12
  343. package/gsd-core/workflows/settings-advanced.md +1 -1
  344. package/gsd-core/workflows/settings-integrations.md +1 -1
  345. package/gsd-core/workflows/settings.md +1 -1
  346. package/gsd-core/workflows/ship.md +12 -12
  347. package/gsd-core/workflows/sketch-wrap-up.md +1 -1
  348. package/gsd-core/workflows/sketch.md +1 -1
  349. package/gsd-core/workflows/smart-entry.md +1 -1
  350. package/gsd-core/workflows/spec-phase.md +1 -1
  351. package/gsd-core/workflows/spike-wrap-up.md +1 -1
  352. package/gsd-core/workflows/spike.md +1 -1
  353. package/gsd-core/workflows/stats.md +1 -1
  354. package/gsd-core/workflows/sync-skills.md +1 -1
  355. package/gsd-core/workflows/thread.md +2 -2
  356. package/gsd-core/workflows/transition.md +13 -23
  357. package/gsd-core/workflows/ui-phase.md +5 -4
  358. package/gsd-core/workflows/ui-review.md +4 -3
  359. package/gsd-core/workflows/ultraplan-phase.md +3 -2
  360. package/gsd-core/workflows/undo.md +1 -1
  361. package/gsd-core/workflows/validate-phase.md +10 -12
  362. package/gsd-core/workflows/verify-work/detail/elaboration.md +43 -3
  363. package/gsd-core/workflows/verify-work/steps/automated-ui-verification.md +1 -1
  364. package/gsd-core/workflows/verify-work/steps/mvp-uat-framing.md +5 -3
  365. package/gsd-core/workflows/verify-work.md +68 -59
  366. package/hooks/dist/gsd-agent-isolation-guard.js +8 -0
  367. package/hooks/dist/gsd-check-update-worker.js +8 -0
  368. package/hooks/dist/gsd-check-update.js +34 -20
  369. package/hooks/dist/gsd-context-monitor.js +45 -13
  370. package/hooks/dist/gsd-cursor-subagent-start.js +8 -0
  371. package/hooks/dist/gsd-secret-read-guard.js +263 -16
  372. package/hooks/dist/gsd-statusline.js +336 -29
  373. package/hooks/dist/gsd-update-banner.js +8 -0
  374. package/hooks/dist/gsd-windsurf-pre-write.js +11 -2
  375. package/hooks/dist/gsd-workflow-guard.js +5 -4
  376. package/hooks/dist/gsd-worktree-path-guard.js +6 -2
  377. package/hooks/dist/lib/cli-exit.js +12 -0
  378. package/hooks/dist/lib/git-probe.js +17 -1
  379. package/hooks/dist/lib/isolation-sentinel.js +2 -2
  380. package/hooks/gsd-agent-isolation-guard.js +8 -0
  381. package/hooks/gsd-check-update-worker.js +8 -0
  382. package/hooks/gsd-check-update.js +34 -20
  383. package/hooks/gsd-context-monitor.js +45 -13
  384. package/hooks/gsd-cursor-subagent-start.js +8 -0
  385. package/hooks/gsd-secret-read-guard.js +263 -16
  386. package/hooks/gsd-statusline.js +336 -29
  387. package/hooks/gsd-update-banner.js +8 -0
  388. package/hooks/gsd-windsurf-pre-write.js +11 -2
  389. package/hooks/gsd-workflow-guard.js +5 -4
  390. package/hooks/gsd-worktree-path-guard.js +6 -2
  391. package/hooks/hooks.json +5 -5
  392. package/hooks/lib/cli-exit.js +12 -0
  393. package/hooks/lib/git-probe.js +17 -1
  394. package/hooks/lib/isolation-sentinel.js +2 -2
  395. package/package.json +21 -4
  396. package/scripts/changeset/parse.cjs +52 -4
  397. package/scripts/ci-timeout-report.cjs +770 -4
  398. package/scripts/command-contract-helpers.cjs +12 -8
  399. package/scripts/docs-guard-registry.cjs +6 -0
  400. package/scripts/gen-capability-registry.cjs +7 -1
  401. package/scripts/gen-features.cjs +13 -8
  402. package/scripts/gen-hooks-cli-exit.cjs +12 -28
  403. package/scripts/gen-loop-host-contract.cjs +14 -2
  404. package/scripts/gen-platform-conformance-tier.cjs +187 -1
  405. package/scripts/gen-plugin-skills.cjs +87 -1
  406. package/scripts/gen-research-agents.cjs +24 -31
  407. package/scripts/gen-scripts-cli-exit.cjs +30 -3
  408. package/scripts/gen-test-timings.cjs +32 -7
  409. package/scripts/lib/cli-exit.cjs +12 -0
  410. package/scripts/lib/macos-conformance-tier.generated.cjs +24 -2
  411. package/scripts/lib/ndjson-reporter.cjs +28 -3
  412. package/scripts/lib/platform-conformance-tier.generated.cjs +44 -5
  413. package/scripts/lib/registration-ledger-preload.cjs +155 -0
  414. package/scripts/lib/vendor-bundle.cjs +59 -0
  415. package/scripts/lib/vendor-licenses/saxes-6.0.0.txt +64 -0
  416. package/scripts/lint-allow-test-rule-refs.effective-ceiling.json +1 -1
  417. package/scripts/lint-allow-test-rule-refs.unverified-ceiling.json +1 -1
  418. package/scripts/lint-completion-predicate-drift.cjs +18 -19
  419. package/scripts/lint-descriptions.cjs +7 -3
  420. package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +10 -0
  421. package/scripts/lint-eslint-glob-coverage.allowlist.json +20 -0
  422. package/scripts/lint-frontmatter-fence-drift.cjs +313 -0
  423. package/scripts/lint-frontmatter-scalar-broad-grep.cjs +122 -16
  424. package/scripts/lint-phase-enumeration-drift.cjs +12 -8
  425. package/scripts/lint-phase-id-drift.cjs +29 -0
  426. package/scripts/lint-planning-document-positive-control.cjs +329 -0
  427. package/scripts/lint-response-language-coverage.cjs +3 -0
  428. package/scripts/lint-skill-deps.cjs +7 -3
  429. package/scripts/lint-test-file-count.allowlist.json +11 -1
  430. package/scripts/lint-test-file-count.cjs +34 -1
  431. package/scripts/lint-vendored-deps.cjs +41 -5
  432. package/scripts/lint-workflow-shellcheck-baseline.json +10 -10
  433. package/scripts/mutation-matrix.cjs +53 -6
  434. package/scripts/release-tarball-smoke.cjs +14 -7
  435. package/scripts/require-issue-link-policy.cjs +6 -2
  436. package/scripts/sync-runtime-launcher.cjs +184 -2
  437. package/scripts/verify-npm-publish.cjs +76 -20
  438. package/skills/gsd-add-tests/SKILL.md +6 -1
  439. package/skills/gsd-ai-integration-phase/SKILL.md +6 -1
  440. package/skills/gsd-audit-fix/SKILL.md +5 -0
  441. package/skills/gsd-audit-milestone/SKILL.md +6 -1
  442. package/skills/gsd-autonomous/SKILL.md +5 -0
  443. package/skills/gsd-capture/SKILL.md +8 -4
  444. package/skills/gsd-code-review/SKILL.md +7 -2
  445. package/skills/gsd-complete-milestone/SKILL.md +4 -0
  446. package/skills/gsd-config/SKILL.md +8 -4
  447. package/skills/gsd-debug/SKILL.md +11 -7
  448. package/skills/gsd-discuss-phase/SKILL.md +7 -3
  449. package/skills/gsd-docs-update/SKILL.md +12 -7
  450. package/skills/gsd-eval-review/SKILL.md +6 -1
  451. package/skills/gsd-execute-phase/SKILL.md +12 -7
  452. package/skills/gsd-extract-learnings/SKILL.md +5 -0
  453. package/skills/gsd-fast/SKILL.md +4 -0
  454. package/skills/gsd-forensics/SKILL.md +5 -1
  455. package/skills/gsd-graphify/SKILL.md +10 -6
  456. package/skills/gsd-health/SKILL.md +5 -0
  457. package/skills/gsd-help/SKILL.md +7 -2
  458. package/skills/gsd-import/SKILL.md +7 -3
  459. package/skills/gsd-inbox/SKILL.md +5 -0
  460. package/skills/gsd-ingest-docs/SKILL.md +5 -1
  461. package/skills/gsd-manager/SKILL.md +6 -1
  462. package/skills/gsd-map-codebase/SKILL.md +7 -3
  463. package/skills/gsd-mempalace-capture/SKILL.md +5 -1
  464. package/skills/gsd-mempalace-recall/SKILL.md +5 -1
  465. package/skills/gsd-milestone-summary/SKILL.md +5 -1
  466. package/skills/gsd-mvp-phase/SKILL.md +8 -3
  467. package/skills/gsd-new-milestone/SKILL.md +6 -1
  468. package/skills/gsd-new-project/SKILL.md +5 -0
  469. package/skills/gsd-next/SKILL.md +6 -1
  470. package/skills/gsd-ns-context/SKILL.md +4 -0
  471. package/skills/gsd-ns-ideate/SKILL.md +4 -0
  472. package/skills/gsd-ns-manage/SKILL.md +4 -0
  473. package/skills/gsd-ns-project/SKILL.md +4 -0
  474. package/skills/gsd-ns-review/SKILL.md +4 -0
  475. package/skills/gsd-ns-workflow/SKILL.md +4 -0
  476. package/skills/gsd-onboard/SKILL.md +6 -1
  477. package/skills/gsd-pause-work/SKILL.md +5 -1
  478. package/skills/gsd-phase/SKILL.md +8 -4
  479. package/skills/gsd-plan-phase/SKILL.md +6 -1
  480. package/skills/gsd-plan-review-convergence/SKILL.md +5 -1
  481. package/skills/gsd-pr-branch/SKILL.md +4 -0
  482. package/skills/gsd-profile-user/SKILL.md +5 -1
  483. package/skills/gsd-progress/SKILL.md +6 -1
  484. package/skills/gsd-quick/SKILL.md +16 -10
  485. package/skills/gsd-quick-batch/SKILL.md +20 -8
  486. package/skills/gsd-review/SKILL.md +5 -1
  487. package/skills/gsd-review-backlog/SKILL.md +3 -2
  488. package/skills/gsd-secure-phase/SKILL.md +6 -1
  489. package/skills/gsd-ship/SKILL.md +5 -0
  490. package/skills/gsd-sketch/SKILL.md +7 -2
  491. package/skills/gsd-spec-phase/SKILL.md +5 -1
  492. package/skills/gsd-spike/SKILL.md +8 -3
  493. package/skills/gsd-surface/SKILL.md +5 -1
  494. package/skills/gsd-thread/SKILL.md +4 -0
  495. package/skills/gsd-ui-phase/SKILL.md +6 -1
  496. package/skills/gsd-ui-review/SKILL.md +6 -1
  497. package/skills/gsd-ultraplan-phase/SKILL.md +5 -1
  498. package/skills/gsd-undo/SKILL.md +5 -1
  499. package/skills/gsd-update/SKILL.md +6 -2
  500. package/skills/gsd-validate-phase/SKILL.md +6 -1
  501. package/skills/gsd-verify-work/SKILL.md +6 -1
  502. package/skills/gsd-workspace/SKILL.md +7 -3
  503. package/skills/gsd-workstreams/SKILL.md +6 -6
  504. package/vscode/package.json +1 -1
  505. package/gsd-core/workflows/execute-phase/steps/stale-reverification.md +0 -24
@@ -0,0 +1,486 @@
1
+ "use strict";
2
+ /**
3
+ * OpenCode generation detection (ADR-5331 D2, D5; epic #5331, Phase 1 #5337).
4
+ *
5
+ * OpenCode 1.x and 2.x share one command name (`opencode`), one set of config
6
+ * locations and cannot be installed side by side, so GSD's `opencode` runtime
7
+ * cannot tell them apart from the descriptor alone. This module answers one
8
+ * question — "which generation is installed?" — and adapts the two spawn-time
9
+ * argument shapes that differ between generations.
10
+ *
11
+ * Evidence (ADR-5331 evidence register; reproduced against the real binaries):
12
+ * E2 `opencode --version` prints `1.19.0` on 1.x and `opencode v2.0.27` on 2.x.
13
+ * E3 2.x `opencode run` has no `--dir` and no `--variant`; both exit 1 with usage.
14
+ * Effort travels as a `#variant` suffix on `--model provider/model#variant`.
15
+ *
16
+ * What this module deliberately does NOT do:
17
+ * - It does not infer 1.x from config. 2.x reads GSD's 1.x-shaped keys in place
18
+ * (E7), so a 1.x-shaped config proves nothing about the binary. Only 2.x-shaped
19
+ * keys (or `cli.json`) are evidence, and only for generation 2.
20
+ * - It does not guess. An unresolvable generation is `null`, and callers keep
21
+ * today's behavior.
22
+ * - It does not apply to Kilo. Kilo is a fork on the OpenCode 1.x line with its
23
+ * own binary (ADR-5331 D7); callers gate on the `opencode` runtime / lane slug.
24
+ */
25
+ var __importDefault = (this && this.__importDefault) || function (mod) {
26
+ return (mod && mod.__esModule) ? mod : { "default": mod };
27
+ };
28
+ Object.defineProperty(exports, "__esModule", { value: true });
29
+ exports.OPENCODE_V1_FREEZE_DATE = exports.OPENCODE_GENERATION_ENV = void 0;
30
+ exports.parseOpencodeVersion = parseOpencodeVersion;
31
+ exports.generationForMajor = generationForMajor;
32
+ exports.probeOpencodeVersion = probeOpencodeVersion;
33
+ exports.detectGenerationSignals = detectGenerationSignals;
34
+ exports.parseGenerationOverride = parseGenerationOverride;
35
+ exports.resolveOpencodeGeneration = resolveOpencodeGeneration;
36
+ exports.resetOpencodeGenerationMemo = resetOpencodeGenerationMemo;
37
+ exports.detectOpencodeGeneration = detectOpencodeGeneration;
38
+ exports.adaptOrchestratorExecForGeneration = adaptOrchestratorExecForGeneration;
39
+ exports.adaptLaneInputForGeneration = adaptLaneInputForGeneration;
40
+ exports.adaptLanePlanForGeneration = adaptLanePlanForGeneration;
41
+ exports.classifyOpencodeDatabase = classifyOpencodeDatabase;
42
+ exports.resolveOpencodeDataDir = resolveOpencodeDataDir;
43
+ exports.describeDataDirNotice = describeDataDirNotice;
44
+ exports.describeDeprecationNotice = describeDeprecationNotice;
45
+ const node_fs_1 = __importDefault(require("node:fs"));
46
+ const node_path_1 = __importDefault(require("node:path"));
47
+ const node_child_process_1 = require("node:child_process");
48
+ const review_lane_invocation_cjs_1 = require("./review-lane-invocation.cjs");
49
+ const shell_command_projection_cjs_1 = require("./shell-command-projection.cjs");
50
+ /** Environment variable that forces a generation (`1` or `2`), bypassing the probe. */
51
+ exports.OPENCODE_GENERATION_ENV = 'GSD_OPENCODE_GENERATION';
52
+ // One whole line: optional `opencode` word, optional `v`, semver with optional
53
+ // pre-release/build. Both observed outputs (`1.19.0`, `opencode v2.0.27`) match;
54
+ // log noise, banners and multi-token lines do not.
55
+ const VERSION_LINE = /^(?:opencode\s+)?v?(\d+)\.(\d+)\.(\d+)((?:[-+][0-9A-Za-z.+-]+)?)$/i;
56
+ /**
57
+ * Parse the stdout of `opencode --version`.
58
+ *
59
+ * Only the first non-empty line is considered, and it must be a version and
60
+ * nothing else. Returns `null` for anything unparseable rather than guessing.
61
+ */
62
+ function parseOpencodeVersion(raw) {
63
+ if (typeof raw !== 'string')
64
+ return null;
65
+ const first = raw.split(/\r?\n/).map((l) => l.trim()).find((l) => l.length > 0);
66
+ if (first === undefined)
67
+ return null;
68
+ const m = VERSION_LINE.exec(first);
69
+ if (!m)
70
+ return null;
71
+ const major = Number(m[1]);
72
+ if (!Number.isSafeInteger(major))
73
+ return null;
74
+ return { version: `${m[1]}.${m[2]}.${m[3]}${m[4]}`, major };
75
+ }
76
+ /** Map a parsed major to a generation. Major 0 is not a shipped OpenCode line → `null`. */
77
+ function generationForMajor(major) {
78
+ if (!Number.isInteger(major) || major < 1)
79
+ return null;
80
+ return major === 1 ? 1 : 2;
81
+ }
82
+ const DEFAULT_PROBE_TIMEOUT_MS = 5000;
83
+ const PROBE_OUTPUT_LIMIT = 1 << 16;
84
+ function text(v) {
85
+ if (v === null || v === undefined)
86
+ return '';
87
+ return typeof v === 'string' ? v : v.toString('utf8');
88
+ }
89
+ /** Single-line, length-bounded excerpt for diagnostics; never echoes control characters. */
90
+ function excerpt(s) {
91
+ return s.replace(/[\u0000-\u001f\u007f]+/g, ' ').trim().slice(0, 120);
92
+ }
93
+ /**
94
+ * Run `<binary> --version` and parse the result.
95
+ *
96
+ * Argv only, never a shell: the binary name is the sole variable and is not
97
+ * interpolated into a command string. Never throws.
98
+ */
99
+ function probeOpencodeVersion(opts = {}) {
100
+ const binary = typeof opts.binary === 'string' && opts.binary.length > 0 ? opts.binary : 'opencode';
101
+ const timeout = typeof opts.timeoutMs === 'number' && Number.isFinite(opts.timeoutMs) && opts.timeoutMs > 0
102
+ ? opts.timeoutMs
103
+ : DEFAULT_PROBE_TIMEOUT_MS;
104
+ const spawn = opts.spawn ?? node_child_process_1.spawnSync;
105
+ let result;
106
+ try {
107
+ result = spawn(binary, ['--version'], {
108
+ encoding: 'utf8',
109
+ timeout,
110
+ shell: false,
111
+ windowsHide: true,
112
+ maxBuffer: PROBE_OUTPUT_LIMIT,
113
+ stdio: ['ignore', 'pipe', 'pipe'],
114
+ ...(opts.env ? { env: opts.env } : {}),
115
+ ...(opts.cwd ? { cwd: opts.cwd } : {}),
116
+ });
117
+ }
118
+ catch (e) {
119
+ return { ok: false, reason: 'error', detail: excerpt(e instanceof Error ? e.message : String(e)) };
120
+ }
121
+ if (result.error) {
122
+ const code = result.error.code;
123
+ if (code === 'ENOENT' || code === 'EACCES') {
124
+ return { ok: false, reason: 'missing', detail: `${binary}: ${code}` };
125
+ }
126
+ if (code === 'ETIMEDOUT') {
127
+ return { ok: false, reason: 'timeout', detail: `${binary} --version exceeded ${timeout}ms` };
128
+ }
129
+ return { ok: false, reason: 'error', detail: excerpt(result.error.message) };
130
+ }
131
+ if (result.signal === 'SIGTERM' || result.signal === 'SIGKILL') {
132
+ return { ok: false, reason: 'timeout', detail: `${binary} --version exceeded ${timeout}ms` };
133
+ }
134
+ if (result.status !== 0) {
135
+ return { ok: false, reason: 'nonzero', detail: `${binary} --version exited ${String(result.status)}` };
136
+ }
137
+ const raw = text(result.stdout);
138
+ const parsed = parseOpencodeVersion(raw);
139
+ if (!parsed) {
140
+ return { ok: false, reason: 'unparseable', detail: `unrecognized output: ${excerpt(raw)}` };
141
+ }
142
+ return { ok: true, version: parsed.version, major: parsed.major, raw: raw.trim() };
143
+ }
144
+ function isPlainObject(v) {
145
+ return v !== null && typeof v === 'object' && !Array.isArray(v);
146
+ }
147
+ /**
148
+ * Look for evidence that a 2.x binary has been (or is being) used with this config.
149
+ *
150
+ * Positive evidence only: `cli.json` is created by 2.x on first start, and the
151
+ * following keys exist only in the native 2.x shape ([migrate-v1] renames):
152
+ * `plugins[]`, `agents{}`, `commands{}`, `permissions[]`, `skills[]`,
153
+ * `providers{}`, `snapshots`, `media{}` and `mcp.servers{}`. 1.x-shaped keys are
154
+ * deliberately not evidence of generation 1: 2.x reads them unchanged (E7).
155
+ */
156
+ function detectGenerationSignals(opts) {
157
+ const fs = opts.fs ?? { exists: (p) => node_fs_1.default.existsSync(p) };
158
+ const evidence = [];
159
+ if (typeof opts.configDir === 'string' && opts.configDir.length > 0) {
160
+ try {
161
+ if (fs.exists(node_path_1.default.join(opts.configDir, 'cli.json')))
162
+ evidence.push('cli.json');
163
+ }
164
+ catch {
165
+ /* an unreadable directory is simply no evidence */
166
+ }
167
+ }
168
+ const cfg = opts.config;
169
+ if (isPlainObject(cfg)) {
170
+ if (Array.isArray(cfg['plugins']))
171
+ evidence.push('plugins[]');
172
+ if (isPlainObject(cfg['agents']))
173
+ evidence.push('agents{}');
174
+ if (isPlainObject(cfg['commands']))
175
+ evidence.push('commands{}');
176
+ if (Array.isArray(cfg['permissions']))
177
+ evidence.push('permissions[]');
178
+ if (Array.isArray(cfg['skills']))
179
+ evidence.push('skills[]');
180
+ if (isPlainObject(cfg['providers']))
181
+ evidence.push('providers{}');
182
+ if (typeof cfg['snapshots'] === 'boolean')
183
+ evidence.push('snapshots');
184
+ if (isPlainObject(cfg['media']))
185
+ evidence.push('media{}');
186
+ const mcp = cfg['mcp'];
187
+ if (isPlainObject(mcp) && isPlainObject(mcp['servers']))
188
+ evidence.push('mcp.servers{}');
189
+ }
190
+ return { generation: evidence.length > 0 ? 2 : null, evidence };
191
+ }
192
+ /** Accepts `1`, `2`, `v1`, `v2`, `opencode2`… in any case; anything else is not an override. */
193
+ function parseGenerationOverride(raw) {
194
+ if (typeof raw === 'number')
195
+ return raw === 1 || raw === 2 ? raw : null;
196
+ if (typeof raw !== 'string')
197
+ return null;
198
+ const m = /^\s*(?:opencode\s*)?v?([12])\s*$/i.exec(raw);
199
+ return m ? Number(m[1]) : null;
200
+ }
201
+ /**
202
+ * Combine the evidence in precedence order: explicit override → probe → config
203
+ * signals → unknown. Pure; the caller supplies already-gathered evidence.
204
+ */
205
+ function resolveOpencodeGeneration(inputs) {
206
+ const notes = [];
207
+ if (inputs.override !== undefined && inputs.override !== null && inputs.override !== '') {
208
+ const forced = parseGenerationOverride(inputs.override);
209
+ if (forced !== null) {
210
+ return { generation: forced, version: null, source: 'override', detail: `forced to ${forced}.x` };
211
+ }
212
+ notes.push(`ignored invalid generation override ${JSON.stringify(typeof inputs.override === 'string' ? inputs.override : typeof inputs.override).slice(0, 40)}`);
213
+ }
214
+ const probe = inputs.probe;
215
+ if (probe) {
216
+ if (probe.ok) {
217
+ const gen = generationForMajor(probe.major);
218
+ if (gen !== null) {
219
+ return { generation: gen, version: probe.version, source: 'probe', detail: notes.join('; ') || null };
220
+ }
221
+ notes.push(`opencode --version reported unsupported major ${probe.major}`);
222
+ }
223
+ else {
224
+ notes.push(`probe ${probe.reason}: ${probe.detail}`);
225
+ }
226
+ }
227
+ const signals = inputs.signals;
228
+ if (signals && signals.generation !== null) {
229
+ notes.push(`2.x config signals: ${signals.evidence.join(', ')}`);
230
+ return { generation: signals.generation, version: null, source: 'signals', detail: notes.join('; ') };
231
+ }
232
+ return {
233
+ generation: null,
234
+ version: null,
235
+ source: 'unknown',
236
+ detail: notes.length > 0 ? notes.join('; ') : 'no evidence gathered',
237
+ };
238
+ }
239
+ // ─── Memoized detection for spawn-time callers ───────────────────────────────
240
+ let memo = null;
241
+ /** Test hook: forget the memoized detection. */
242
+ function resetOpencodeGenerationMemo() {
243
+ memo = null;
244
+ }
245
+ /**
246
+ * Detect the installed generation once per process.
247
+ *
248
+ * For callers that build a `opencode run …` command line (worktree dispatch,
249
+ * the reviewer lane): the override environment variable wins, then one
250
+ * `--version` probe, memoized so a multi-lane review spawns it once.
251
+ */
252
+ function detectOpencodeGeneration(opts = {}) {
253
+ const env = opts.overrideEnv ?? process.env;
254
+ const override = env[exports.OPENCODE_GENERATION_ENV];
255
+ const key = `${opts.binary ?? 'opencode'}\u0000${String(override ?? '')}`;
256
+ if (memo && memo.key === key)
257
+ return memo.value;
258
+ const value = resolveOpencodeGeneration({
259
+ override,
260
+ probe: parseGenerationOverride(override) !== null ? null : probeOpencodeVersion(opts),
261
+ });
262
+ memo = { key, value };
263
+ return value;
264
+ }
265
+ /**
266
+ * 2.x `opencode run` has no `--dir` (E3), so a descriptor that binds the worktree
267
+ * through `--dir` must bind it through the spawned process's own working directory
268
+ * instead — the "process-cwd" shape `resolveOrchestratorExec` already supports
269
+ * (`cwdFlag: null`, as for Kimi Code). Every other descriptor and generation is
270
+ * returned untouched.
271
+ */
272
+ function adaptOrchestratorExecForGeneration(orchestratorExec, generation) {
273
+ if (generation !== 2)
274
+ return orchestratorExec;
275
+ if (!orchestratorExec || typeof orchestratorExec !== 'object')
276
+ return orchestratorExec;
277
+ if (orchestratorExec.cwdFlag !== '--dir')
278
+ return orchestratorExec;
279
+ return { ...orchestratorExec, cwdFlag: null };
280
+ }
281
+ /**
282
+ * Adapt an OpenCode reviewer-lane resolution input for generation 2.
283
+ *
284
+ * 2.x rejects `--variant` (E3); a reasoning effort rides on the model reference
285
+ * instead (`provider/model#variant`, [D8] / [D5]). So for the `opencode` lane:
286
+ * - the `--variant` argv is dropped;
287
+ * - when an effort level and a configured model both exist, the model is
288
+ * returned from `configGet` with `#<level>` appended (never doubled: a model
289
+ * that already carries a `#variant` is the operator's explicit choice);
290
+ * - when an effort level exists but no model is configured, nothing can carry
291
+ * it, so the level is dropped and a warning says so.
292
+ * Any other lane, and generation 1 / unknown, is returned unchanged.
293
+ */
294
+ function adaptLaneInputForGeneration(input, generation) {
295
+ const warnings = [];
296
+ if (generation !== 2)
297
+ return { input, warnings };
298
+ const lane = input.lane;
299
+ if (!lane || lane.slug !== 'opencode')
300
+ return { input, warnings };
301
+ const modelKey = typeof lane.modelConfigKey === 'string' ? lane.modelConfigKey : null;
302
+ const effort = typeof input.effortValue === 'string' && input.effortValue.length > 0 ? input.effortValue : null;
303
+ const hadEffortArgs = Array.isArray(input.effortArgs) && input.effortArgs.length > 0;
304
+ let configGet = input.configGet;
305
+ if (effort !== null && modelKey !== null) {
306
+ const configured = (0, review_lane_invocation_cjs_1.configString)(input.configGet(modelKey));
307
+ if (configured === null) {
308
+ warnings.push(`reasoning effort '${effort}' not applied to the OpenCode reviewer: OpenCode 2.x has no --variant ` +
309
+ `flag and no model is configured to carry a #variant. Set a model to apply it.`);
310
+ }
311
+ else if (!configured.includes('#')) {
312
+ const original = input.configGet;
313
+ configGet = (key) => key === modelKey ? `${configured}#${effort}` : original(key);
314
+ }
315
+ }
316
+ else if (effort !== null) {
317
+ warnings.push(`reasoning effort '${effort}' not applied to the OpenCode reviewer: the lane declares no model key to carry a #variant.`);
318
+ }
319
+ if (!hadEffortArgs && configGet === input.configGet && warnings.length === 0) {
320
+ return { input, warnings };
321
+ }
322
+ return { input: { ...input, configGet, effortArgs: [] }, warnings };
323
+ }
324
+ /**
325
+ * 2.x `opencode run` treats a trailing `-` as message text, not as a "read stdin" marker: the model
326
+ * receives `-\n<prompt>` (verified on 2.0.27, E12). Piped stdin is read either way (E4), so for a
327
+ * stdin-fed opencode plan on generation 2 the marker is dropped and the run is made `--standalone`.
328
+ * Everything else is untouched.
329
+ */
330
+ function adaptLanePlanForGeneration(result, generation) {
331
+ if (generation !== 2 || !result || result.ok !== true || !result.plan)
332
+ return result;
333
+ const plan = result.plan;
334
+ if (plan.slug !== 'opencode' || plan.stdin === null || plan.stdin === undefined)
335
+ return result;
336
+ const argv = plan.argv;
337
+ if (!Array.isArray(argv))
338
+ return result;
339
+ let next = argv;
340
+ if (next[next.length - 1] === '-')
341
+ next = next.slice(0, -1);
342
+ // `--standalone` ("Run with a private server instead of the background service", `opencode run
343
+ // --help` on 2.0.27): without it `run` attaches to a long-lived managed service on a fixed port
344
+ // that outlives the review, serves whichever config it booted with, and fails when another
345
+ // process holds the port. A review is one-shot, so it gets its own server.
346
+ const runIdx = next.indexOf('run');
347
+ if (runIdx !== -1 && !next.includes('--standalone')) {
348
+ next = [...next.slice(0, runIdx + 1), '--standalone', ...next.slice(runIdx + 1)];
349
+ }
350
+ if (next === argv)
351
+ return result;
352
+ return { ...result, plan: { ...plan, argv: next } };
353
+ }
354
+ /**
355
+ * Default reader: `node:sqlite`, read-only. Its schema lives in the write-ahead log until a checkpoint,
356
+ * so reading the main file's bytes would see an empty database; SQLite itself merges both. The module
357
+ * prints an ExperimentalWarning on some Node versions, which is swallowed for the duration of the read.
358
+ * Any failure (module missing, file locked or corrupt) is `null`, never a throw.
359
+ */
360
+ function readTableNames(dbPath) {
361
+ const emit = process.emitWarning.bind(process);
362
+ try {
363
+ process.emitWarning = () => undefined;
364
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
365
+ const sqlite = require('node:sqlite');
366
+ const db = new sqlite.DatabaseSync(dbPath, { readOnly: true });
367
+ try {
368
+ return db.prepare("select name from sqlite_master where type='table'").all().map((r) => r.name);
369
+ }
370
+ finally {
371
+ db.close();
372
+ }
373
+ }
374
+ catch {
375
+ return null;
376
+ }
377
+ finally {
378
+ process.emitWarning = emit;
379
+ }
380
+ }
381
+ /**
382
+ * Which generation(s) built an OpenCode database. 1.x keeps sessions in a `session` table; 2.x in
383
+ * `session_v2`. A database 2.x created from scratch has no `session` table and 1.x cannot open it; a 1.x
384
+ * database that 2.x later used gains the 2.x tables beside `session` and 1.x keeps working — both
385
+ * reproduced on 1.18.29 and 2.0.27 (ADR-5331 E8, E18). GSD only reads the schema; it never writes to this
386
+ * database.
387
+ */
388
+ function classifyOpencodeDatabase(dbPath, deps = {}) {
389
+ const exists = deps.exists ?? ((p) => node_fs_1.default.existsSync(p));
390
+ if (!exists(dbPath))
391
+ return 'empty';
392
+ const names = (deps.readTables ?? readTableNames)(dbPath);
393
+ if (names === null)
394
+ return 'unknown';
395
+ const v1 = names.includes('session');
396
+ const v2 = names.includes('session_v2');
397
+ if (v1 && v2)
398
+ return 'both';
399
+ if (v2)
400
+ return 'v2';
401
+ if (v1)
402
+ return 'v1';
403
+ return names.length === 0 ? 'empty' : 'unknown';
404
+ }
405
+ /**
406
+ * The directory holding `opencode.db`: the `data` entry of `opencode debug paths` (the binary's own
407
+ * answer, identical on 1.x and 2.x), else the XDG default every OpenCode generation shares.
408
+ */
409
+ function resolveOpencodeDataDir(opts = {}) {
410
+ const spawn = opts.spawn ?? node_child_process_1.spawnSync;
411
+ const binary = typeof opts.binary === 'string' && opts.binary.length > 0 ? opts.binary : 'opencode';
412
+ try {
413
+ const r = spawn(binary, ['debug', 'paths'], {
414
+ encoding: 'utf8',
415
+ timeout: opts.timeoutMs ?? DEFAULT_PROBE_TIMEOUT_MS,
416
+ shell: false,
417
+ windowsHide: true,
418
+ maxBuffer: PROBE_OUTPUT_LIMIT,
419
+ stdio: ['ignore', 'pipe', 'pipe'],
420
+ ...(opts.env ? { env: opts.env } : {}),
421
+ });
422
+ if (!r.error && r.status === 0) {
423
+ const m = /^data[ \t]+(.+?)[ \t]*$/m.exec(text(r.stdout));
424
+ if (m && m[1] && node_path_1.default.isAbsolute(m[1]))
425
+ return m[1];
426
+ }
427
+ }
428
+ catch {
429
+ /* fall through to the XDG default */
430
+ }
431
+ const env = opts.env ?? process.env;
432
+ const home = opts.home ?? (0, shell_command_projection_cjs_1.envGet)(env, 'HOME') ?? (0, shell_command_projection_cjs_1.envGet)(env, 'USERPROFILE') ?? '';
433
+ const xdgData = (0, shell_command_projection_cjs_1.envGet)(env, 'XDG_DATA_HOME');
434
+ const base = xdgData && node_path_1.default.isAbsolute(xdgData) ? xdgData : node_path_1.default.join(home, '.local', 'share');
435
+ return node_path_1.default.join(base, 'opencode');
436
+ }
437
+ /**
438
+ * What to tell the operator about the data directory, given the installed generation and the schema
439
+ * generation(s) found there; `null` when there is nothing to say.
440
+ */
441
+ function describeDataDirNotice(generation, kind, dataDir) {
442
+ if (generation === 1 && kind === 'v2') {
443
+ return {
444
+ level: 'warn',
445
+ text: `OpenCode 1.x is installed but its data directory (${dataDir}) was created by OpenCode 2.x. ` +
446
+ "1.x cannot open it (\"Database is not empty and has no session table\"). Reinstall 2.x, or restore a " +
447
+ 'backup of the data directory taken before 2.x first ran. GSD never modifies this database.',
448
+ };
449
+ }
450
+ if (generation === 1 && kind === 'both') {
451
+ return {
452
+ level: 'info',
453
+ text: `OpenCode 2.x has also used the data directory (${dataDir}); it keeps its sessions in its own tables ` +
454
+ 'beside the 1.x ones, and 1.x still opens it.',
455
+ };
456
+ }
457
+ if (generation === 2 && kind === 'v1') {
458
+ return {
459
+ level: 'info',
460
+ text: `OpenCode 2.x will add its own tables to the data directory (${dataDir}) beside the 1.x ones; ` +
461
+ 'OpenCode 1.x still opens it afterwards. A data directory that 2.x creates from scratch, by contrast, ' +
462
+ 'cannot be opened by 1.x.',
463
+ };
464
+ }
465
+ return null;
466
+ }
467
+ /**
468
+ * End of the OpenCode 1.x bug-fix-only window (ADR-5331 D7, epic #5331 Phase 3). A maintainer decision:
469
+ * 1.x receives fixes until this date, after which Phase 4 removes the 1.x paths for the `opencode` runtime.
470
+ * Kilo is a separate runtime on the 1.x line and is not affected.
471
+ */
472
+ exports.OPENCODE_V1_FREEZE_DATE = '2026-12-31';
473
+ /**
474
+ * The deprecation notice shown when the installed `opencode` binary is OpenCode 1.x; `null` for 2.x and for an
475
+ * undetected generation. The upgrade commands are the binary's own: `opencode upgrade --major` is a flag of
476
+ * 1.19.0 (absent from 1.18.29) ("upgrade to OpenCode 2 and remove OpenCode 1"), and the V2 installer and package replace the 1.x binary
477
+ * (https://opencode.ai/v2/docs/migrate-v1/).
478
+ */
479
+ function describeDeprecationNotice(generation) {
480
+ if (generation !== 1)
481
+ return null;
482
+ return (`OpenCode 1.x is deprecated for GSD: it receives bug fixes only until ${exports.OPENCODE_V1_FREEZE_DATE}, after which ` +
483
+ 'GSD supports OpenCode 2.x only. Upgrade with `opencode upgrade --major` (OpenCode 1.19 and newer), or install ' +
484
+ 'OpenCode 2 (`curl -fsSL https://opencode.ai/v2/install | bash`, or `npm install -g @opencode/cli`) and re-run the GSD installer. ' +
485
+ 'Your configuration is read in place by 2.x. Kilo is not affected.');
486
+ }
@@ -44,6 +44,7 @@
44
44
  Object.defineProperty(exports, "__esModule", { value: true });
45
45
  exports.MAX_USER_PATTERN_LEN = void 0;
46
46
  exports.escapeRegex = escapeRegex;
47
+ exports.escapeEre = escapeEre;
47
48
  exports.literalPattern = literalPattern;
48
49
  exports.compileUserPattern = compileUserPattern;
49
50
  // re2js is vendored, not an npm dependency at runtime: gsd-core/bin/** is
@@ -66,6 +67,15 @@ const escapeMetachars = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
66
67
  function escapeRegex(value) {
67
68
  return (escapeBuiltin ?? escapeMetachars)(value);
68
69
  }
70
+ /**
71
+ * Escape `value` for a POSIX extended regular expression (e.g. `git log --extended-regexp
72
+ * --grep=…`). Always the plain backslash-escape of every ERE metacharacter, never
73
+ * `RegExp.escape`: that built-in writes a leading digit as `\x31`, which ERE does not read as a
74
+ * digit. #5139 (a plan id interpolated into a git `--grep` pattern).
75
+ */
76
+ function escapeEre(value) {
77
+ return escapeMetachars(value);
78
+ }
69
79
  function literalPattern(value, flags) {
70
80
  return new RegExp(escapeRegex(value), flags);
71
81
  }
@@ -22,10 +22,12 @@ const commandRoutingHub = require("./command-routing-hub.cjs");
22
22
  const { createHub, ERROR_KINDS, makeInvalidArgs } = commandRoutingHub;
23
23
  // #2620 (ADR-0174 §6): inject the reference DispatchLogger on the live phase
24
24
  // dispatch path, but only when observability is opt-in enabled; otherwise the
25
- // Hub stays byte-for-byte silent via its no-op fallback.
25
+ // Hub stays byte-for-byte silent via its no-op fallback. #4975: the opt-in is
26
+ // GSD_AUDIT=1 or `audit.enabled` in the project config — resolveDispatchLogger
27
+ // owns that whole decision for every live seam.
26
28
  // eslint-disable-next-line @typescript-eslint/no-require-imports
27
29
  const observabilityLogger = require("./observability/logger.cjs");
28
- const { createDefaultLogger, isAuditEnabled } = observabilityLogger;
30
+ const { resolveDispatchLogger } = observabilityLogger;
29
31
  // ─── Implementation ───────────────────────────────────────────────────────────
30
32
  function routePhaseCommand({ phase, args, cwd, raw, error }) {
31
33
  // ── Unsupported subcommands ─────────────────────────────────────────────────
@@ -258,8 +260,8 @@ function routePhaseCommand({ phase, args, cwd, raw, error }) {
258
260
  // #175: Hub is CJS-only — no mode param, no sdkLoader.
259
261
  // #2620: wire the reference logger (ADR-0174 §6) only when observability is
260
262
  // opt-in enabled; otherwise leave it unset so the Hub stays byte-for-byte
261
- // silent via its no-op fallback.
262
- const hub = createHub({ cjsRegistry, manifest, logger: isAuditEnabled() ? createDefaultLogger({ cwd }) : undefined });
263
+ // silent via its no-op fallback. #4975: GSD_AUDIT=1 or `audit.enabled`.
264
+ const hub = createHub({ cjsRegistry, manifest, logger: resolveDispatchLogger(cwd) });
263
265
  // ── Dispatch ────────────────────────────────────────────────────────────────
264
266
  const result = hub.dispatch({
265
267
  family: 'phase',
@@ -282,6 +284,11 @@ function routePhaseCommand({ phase, args, cwd, raw, error }) {
282
284
  error(result.reason);
283
285
  return;
284
286
  }
287
+ if (result.kind === ERROR_KINDS.VerificationStatusInvalid) {
288
+ // #5118: typed reason survives to the CLI surface
289
+ error(result.message, result.reason);
290
+ return;
291
+ }
285
292
  // HandlerFailure: message field
286
293
  error(result.message);
287
294
  return;
@@ -47,6 +47,7 @@ exports.parseCalibrationDocument = parseCalibrationDocument;
47
47
  exports.renderCalibrationDocument = renderCalibrationDocument;
48
48
  // eslint-disable-next-line @typescript-eslint/no-require-imports -- prompt-budget.cjs is an export= CommonJS module
49
49
  const promptBudget = require("./prompt-budget.cjs");
50
+ const frontmatter_fence_cjs_1 = require("./frontmatter-fence.cjs");
50
51
  const { estimateTokens } = promptBudget;
51
52
  /**
52
53
  * Assert that a bare number is an UNCORRECTED projection.
@@ -239,11 +240,11 @@ function applyCalibration(rawTokens, factor) {
239
240
  function extractFrontmatterBlock(text, key) {
240
241
  if (typeof text !== 'string')
241
242
  return null;
242
- // Anchor at byte 0 — CRLF-tolerant.
243
- const fm = /^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|\r?$)/.exec(text);
244
- if (fm === null)
243
+ // The block is the one the one fence owner finds (`locateFrontmatterFence`).
244
+ const fence = (0, frontmatter_fence_cjs_1.locateFrontmatterFence)(text);
245
+ if (!fence?.closed)
245
246
  return null;
246
- const lines = fm[1].split(/\r?\n/);
247
+ const lines = text.slice(fence.openEnd, fence.bodyEnd).split(/\r?\n/);
247
248
  const startIdx = lines.findIndex((l) => l === `${key}:` || l.startsWith(`${key}:`));
248
249
  if (startIdx === -1)
249
250
  return null;
@@ -1342,7 +1342,7 @@ const unpad = (digits) => digits.replace(/^0+(?=\d)/, '');
1342
1342
  * candidates (#2237).
1343
1343
  *
1344
1344
  * TAKE `matches[0]` — `cmdPhasesList`, `cmdInitManager`, `cmdRoadmapAnalyze`,
1345
- * `cmdVerifySchemaDrift`, `detectVerifyFailed`. Each read a directory to
1345
+ * the schema-drift gate (`resolvePhaseDirByToken`), `detectVerifyFailed`. Each read a directory to
1346
1346
  * DECORATE a row they are already emitting; each used `.find()` before this
1347
1347
  * PR, so first-match is their prior behavior preserved verbatim, and each is
1348
1348
  * order-stable because the directory list is sorted and this function filters
@@ -31,6 +31,9 @@ const markdown_table_cjs_1 = require("./markdown-table.cjs");
31
31
  // eslint-disable-next-line @typescript-eslint/no-require-imports -- phase-id.cjs is an export= CommonJS module
32
32
  const phaseIdMod = require("./phase-id.cjs");
33
33
  const { isSentinelPhaseId } = phaseIdMod;
34
+ // #5060: `phase-status.cjs` is a load-time leaf (no top-level requires), safe
35
+ // to import here for the ROADMAP Status-cell reader.
36
+ const phase_status_cjs_1 = require("./phase-status.cjs");
34
37
  /**
35
38
  * #3227: the single owner of "where is this ROADMAP's Progress table".
36
39
  * Lifted verbatim out of deriveProgressFromRoadmap so `state-contract.cts`
@@ -93,8 +96,6 @@ function deriveProgressFromRoadmap(roadmapContent) {
93
96
  const table = locateProgressTable(roadmapContent);
94
97
  if (table) {
95
98
  const allRows = table.rows;
96
- const completed = allRows.filter((r) => /^complete$/i.test((r['Status'] ?? '').trim())).length;
97
- completedPhases = completed > 0 ? completed : null;
98
99
  // Data rows only (exclude sentinel phases 0 and 999.x).
99
100
  // #3185: canonical sentinel predicate (SENTINEL_RANGES [0,999]) — this was a local 999-only literal that admitted Phase 0.
100
101
  const dataRows = allRows.filter((r) => {
@@ -102,6 +103,12 @@ function deriveProgressFromRoadmap(roadmapContent) {
102
103
  return /^\d/.test(phase) && !isSentinelPhaseId(phase);
103
104
  });
104
105
  totalPhases = dataRows.length > 0 ? dataRows.length : null;
106
+ // #5060: routed through the Phase Status Module's `parseRoadmapStatusCell`
107
+ // owner (rather than a local `/^complete$/i` regex) and counted over
108
+ // `dataRows` (not `allRows`) — a sentinel row's Status cell must never
109
+ // contribute to `completedPhases`.
110
+ const completed = dataRows.filter((r) => (0, phase_status_cjs_1.parseRoadmapStatusCell)(r['Status']) === phase_status_cjs_1.WIRE_STATUS.COMPLETE).length;
111
+ completedPhases = completed > 0 ? completed : null;
105
112
  let totalPlansSum = 0;
106
113
  for (const r of allRows) {
107
114
  const cell = (r['Plans Complete'] ?? '').trim();