@opengsd/gsd-core 1.10.0 → 1.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (544) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/agents/gsd-code-fixer.md +1 -1
  4. package/agents/gsd-debug-session-manager.md +12 -1
  5. package/agents/gsd-debugger.md +1 -1
  6. package/agents/gsd-doc-synthesizer.md +2 -4
  7. package/agents/gsd-dom-verifier.md +169 -0
  8. package/agents/gsd-eval-auditor.md +1 -1
  9. package/agents/gsd-executor.md +22 -14
  10. package/agents/gsd-framework-selector.md +1 -3
  11. package/agents/gsd-intel-updater.md +1 -1
  12. package/agents/gsd-mempalace-curator.md +5 -3
  13. package/agents/gsd-pattern-mapper.md +11 -0
  14. package/agents/gsd-phase-researcher.md +23 -2
  15. package/agents/gsd-plan-checker.md +50 -53
  16. package/agents/gsd-planner.md +50 -50
  17. package/agents/gsd-project-researcher.md +1 -1
  18. package/agents/gsd-research-synthesizer.md +2 -2
  19. package/agents/gsd-roadmapper.md +15 -11
  20. package/agents/gsd-ui-checker.md +63 -4
  21. package/agents/gsd-ui-researcher.md +41 -3
  22. package/agents/gsd-user-profiler.md +3 -0
  23. package/agents/gsd-verifier.md +13 -4
  24. package/bin/install.js +1448 -1103
  25. package/commands/gsd/code-review.md +1 -1
  26. package/commands/gsd/discuss-phase.md +1 -1
  27. package/commands/gsd/execute-phase.md +1 -1
  28. package/commands/gsd/import.md +1 -1
  29. package/commands/gsd/map-codebase.md +1 -1
  30. package/commands/gsd/mempalace-capture.md +1 -1
  31. package/commands/gsd/mempalace-recall.md +1 -1
  32. package/commands/gsd/new-milestone.md +1 -1
  33. package/commands/gsd/quick.md +9 -5
  34. package/commands/gsd/review-backlog.md +2 -1
  35. package/commands/gsd/verify-work.md +1 -1
  36. package/gsd-core/bin/gsd-tools.cjs +1035 -138
  37. package/gsd-core/bin/lib/active-workstream-store.cjs +146 -22
  38. package/gsd-core/bin/lib/adr-parser.cjs +13 -7
  39. package/gsd-core/bin/lib/agent-install-check.cjs +392 -32
  40. package/gsd-core/bin/lib/api-coverage.cjs +33 -14
  41. package/gsd-core/bin/lib/artifacts.cjs +5 -0
  42. package/gsd-core/bin/lib/assumption-delta.cjs +32 -15
  43. package/gsd-core/bin/lib/audit-command-router.cjs +9 -2
  44. package/gsd-core/bin/lib/audit.cjs +1026 -268
  45. package/gsd-core/bin/lib/broken-windows.cjs +306 -28
  46. package/gsd-core/bin/lib/capability-consent.cjs +149 -15
  47. package/gsd-core/bin/lib/capability-lifecycle.cjs +45 -0
  48. package/gsd-core/bin/lib/capability-lock.cjs +10 -4
  49. package/gsd-core/bin/lib/capability-registry.cjs +845 -130
  50. package/gsd-core/bin/lib/capability-source.cjs +92 -0
  51. package/gsd-core/bin/lib/capability-state.cjs +18 -3
  52. package/gsd-core/bin/lib/capability-trust.cjs +444 -25
  53. package/gsd-core/bin/lib/capability-validator.cjs +700 -40
  54. package/gsd-core/bin/lib/capability-writer.cjs +3 -2
  55. package/gsd-core/bin/lib/check-command-router.cjs +216 -42
  56. package/gsd-core/bin/lib/claude-orchestration.cjs +56 -3
  57. package/gsd-core/bin/lib/cli-exit.cjs +496 -10
  58. package/gsd-core/bin/lib/code-review-depth.cjs +288 -0
  59. package/gsd-core/bin/lib/codex-agent-toml.cjs +735 -0
  60. package/gsd-core/bin/lib/command-aliases.cjs +22 -0
  61. package/gsd-core/bin/lib/command-arg-projection.cjs +144 -14
  62. package/gsd-core/bin/lib/command-roster.cjs +44 -1
  63. package/gsd-core/bin/lib/command-routing-hub.cjs +31 -2
  64. package/gsd-core/bin/lib/commands.cjs +1172 -108
  65. package/gsd-core/bin/lib/commonjs-marker.cjs +12 -6
  66. package/gsd-core/bin/lib/complexity-trigger.cjs +1192 -0
  67. package/gsd-core/bin/lib/config-loader.cjs +187 -23
  68. package/gsd-core/bin/lib/config.cjs +102 -3
  69. package/gsd-core/bin/lib/configuration.cjs +129 -37
  70. package/gsd-core/bin/lib/core-utils.cjs +208 -33
  71. package/gsd-core/bin/lib/decisions.cjs +23 -0
  72. package/gsd-core/bin/lib/edge-probe.cjs +9 -1
  73. package/gsd-core/bin/lib/estimate-cli.cjs +55 -11
  74. package/gsd-core/bin/lib/exit-code-registry.cjs +98 -0
  75. package/gsd-core/bin/lib/fallow-runner.cjs +20 -44
  76. package/gsd-core/bin/lib/frontmatter.cjs +899 -229
  77. package/gsd-core/bin/lib/gap-checker.cjs +95 -10
  78. package/gsd-core/bin/lib/git-base-branch.cjs +276 -39
  79. package/gsd-core/bin/lib/gsd2-import.cjs +10 -1
  80. package/gsd-core/bin/lib/health-diagnostic-rules/agent-install.cjs +101 -0
  81. package/gsd-core/bin/lib/health-diagnostic-rules/config-validation.cjs +348 -0
  82. package/gsd-core/bin/lib/health-diagnostic-rules/consistency.cjs +149 -0
  83. package/gsd-core/bin/lib/health-diagnostic-rules/install-surface-shadowing.cjs +98 -0
  84. package/gsd-core/bin/lib/health-diagnostic-rules/milestone-archive-hygiene.cjs +100 -0
  85. package/gsd-core/bin/lib/health-diagnostic-rules/phase-structure.cjs +222 -0
  86. package/gsd-core/bin/lib/health-diagnostic-rules/roadmap-disk-consistency.cjs +268 -0
  87. package/gsd-core/bin/lib/health-diagnostic-rules/root-existence.cjs +161 -0
  88. package/gsd-core/bin/lib/health-diagnostic-rules/state-consistency.cjs +303 -0
  89. package/gsd-core/bin/lib/health-diagnostic-rules/worktree-health.cjs +187 -0
  90. package/gsd-core/bin/lib/health-diagnostic-types.cjs +68 -0
  91. package/gsd-core/bin/lib/health-diagnostic.cjs +451 -0
  92. package/gsd-core/bin/lib/host-integration.cjs +39 -6
  93. package/gsd-core/bin/lib/host-runtime-detection.cjs +134 -0
  94. package/gsd-core/bin/lib/init-command-router.cjs +118 -21
  95. package/gsd-core/bin/lib/init.cjs +439 -168
  96. package/gsd-core/bin/lib/install-effort-resolver.cjs +73 -30
  97. package/gsd-core/bin/lib/install-engine.cjs +811 -259
  98. package/gsd-core/bin/lib/install-fs-adapter.cjs +262 -0
  99. package/gsd-core/bin/lib/install-model-override-resolver.cjs +235 -0
  100. package/gsd-core/bin/lib/install-profiles.cjs +212 -61
  101. package/gsd-core/bin/lib/install-scope.cjs +270 -0
  102. package/gsd-core/bin/lib/install-shadow-report.cjs +385 -0
  103. package/gsd-core/bin/lib/installed-surface-resolver.cjs +381 -0
  104. package/gsd-core/bin/lib/installer-migration-report.cjs +3 -0
  105. package/gsd-core/bin/lib/installer-migrations/010-antigravity-retire-confighome-artifacts.cjs +169 -0
  106. package/gsd-core/bin/lib/installer-migrations.cjs +148 -38
  107. package/gsd-core/bin/lib/intel.cjs +101 -26
  108. package/gsd-core/bin/lib/io.cjs +170 -15
  109. package/gsd-core/bin/lib/learnings.cjs +85 -14
  110. package/gsd-core/bin/lib/legacy-cleanup.cjs +8 -2
  111. package/gsd-core/bin/lib/markdown-sectionizer.cjs +2 -1
  112. package/gsd-core/bin/lib/markdown-table.cjs +183 -22
  113. package/gsd-core/bin/lib/milestone-lock.cjs +248 -0
  114. package/gsd-core/bin/lib/milestone.cjs +842 -73
  115. package/gsd-core/bin/lib/model-catalog.cjs +232 -16
  116. package/gsd-core/bin/lib/model-resolver.cjs +193 -68
  117. package/gsd-core/bin/lib/normalize-test-command.cjs +1 -1
  118. package/gsd-core/bin/lib/onboard-projection.cjs +5 -1
  119. package/gsd-core/bin/lib/pattern.cjs +122 -0
  120. package/gsd-core/bin/lib/phase-estimation.cjs +18 -9
  121. package/gsd-core/bin/lib/phase-id.cjs +514 -40
  122. package/gsd-core/bin/lib/phase-lifecycle.cjs +52 -19
  123. package/gsd-core/bin/lib/phase-locator.cjs +262 -34
  124. package/gsd-core/bin/lib/phase.cjs +1038 -214
  125. package/gsd-core/bin/lib/plan-dependency-graph.cjs +72 -1
  126. package/gsd-core/bin/lib/plan-document.cjs +263 -0
  127. package/gsd-core/bin/lib/plan-drift-guard.cjs +120 -0
  128. package/gsd-core/bin/lib/plan-scan.cjs +98 -3
  129. package/gsd-core/bin/lib/planning-command-router.cjs +61 -0
  130. package/gsd-core/bin/lib/planning-inspect.cjs +1168 -0
  131. package/gsd-core/bin/lib/planning-scope.cjs +31 -0
  132. package/gsd-core/bin/lib/planning-snapshot.cjs +894 -0
  133. package/gsd-core/bin/lib/planning-workspace.cjs +112 -6
  134. package/gsd-core/bin/lib/probe-core.cjs +5 -2
  135. package/gsd-core/bin/lib/profile-output.cjs +1 -1
  136. package/gsd-core/bin/lib/profile-pipeline-command-router.cjs +50 -7
  137. package/gsd-core/bin/lib/profile-pipeline.cjs +6 -3
  138. package/gsd-core/bin/lib/real-home-guard.cjs +419 -0
  139. package/gsd-core/bin/lib/refactor-trigger-command-router.cjs +766 -0
  140. package/gsd-core/bin/lib/retired-artifact-cleanup.cjs +11 -6
  141. package/gsd-core/bin/lib/review-lane-descriptor.cjs +22 -13
  142. package/gsd-core/bin/lib/review-lane-invocation.cjs +30 -0
  143. package/gsd-core/bin/lib/review-lane-runner.cjs +421 -66
  144. package/gsd-core/bin/lib/review-reviewer-selection.cjs +13 -18
  145. package/gsd-core/bin/lib/roadmap-command-router.cjs +59 -11
  146. package/gsd-core/bin/lib/roadmap-parser.cjs +1006 -184
  147. package/gsd-core/bin/lib/roadmap-upgrade.cjs +37 -10
  148. package/gsd-core/bin/lib/roadmap.cjs +442 -96
  149. package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +702 -52
  150. package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +14 -2
  151. package/gsd-core/bin/lib/runtime-artifact-layout.cjs +459 -55
  152. package/gsd-core/bin/lib/runtime-config-adapter-registry.cjs +3 -2
  153. package/gsd-core/bin/lib/runtime-homes.cjs +69 -3
  154. package/gsd-core/bin/lib/runtime-hooks-surface.cjs +402 -58
  155. package/gsd-core/bin/lib/runtime-identity.cjs +234 -0
  156. package/gsd-core/bin/lib/runtime-name-policy.cjs +3 -1
  157. package/gsd-core/bin/lib/runtime-slash.cjs +96 -8
  158. package/gsd-core/bin/lib/security.cjs +104 -5
  159. package/gsd-core/bin/lib/shell-command-projection.cjs +342 -7
  160. package/gsd-core/bin/lib/smart-entry.cjs +133 -23
  161. package/gsd-core/bin/lib/spec-section.cjs +12 -7
  162. package/gsd-core/bin/lib/state-command-router.cjs +52 -19
  163. package/gsd-core/bin/lib/state-contract.cjs +359 -0
  164. package/gsd-core/bin/lib/state-document.cjs +338 -8
  165. package/gsd-core/bin/lib/state-md-schema.cjs +221 -0
  166. package/gsd-core/bin/lib/state-transition.cjs +846 -176
  167. package/gsd-core/bin/lib/state.cjs +2589 -369
  168. package/gsd-core/bin/lib/surface.cjs +33 -11
  169. package/gsd-core/bin/lib/task-command-router.cjs +111 -1
  170. package/gsd-core/bin/lib/task-content-resolution.cjs +368 -0
  171. package/gsd-core/bin/lib/teams-status.cjs +4 -1
  172. package/gsd-core/bin/lib/text-lines.cjs +80 -0
  173. package/gsd-core/bin/lib/token-scanner.cjs +76 -0
  174. package/gsd-core/bin/lib/uat-predicate.cjs +67 -23
  175. package/gsd-core/bin/lib/uat.cjs +1761 -167
  176. package/gsd-core/bin/lib/ui-consideration-probe.cjs +9 -1
  177. package/gsd-core/bin/lib/ui-frontend-evidence.cjs +157 -0
  178. package/gsd-core/bin/lib/ui-safety-gate.cjs +51 -12
  179. package/gsd-core/bin/lib/unusable-input.cjs +37 -0
  180. package/gsd-core/bin/lib/update-context.cjs +8 -2
  181. package/gsd-core/bin/lib/user-artifact-staging.cjs +705 -0
  182. package/gsd-core/bin/lib/validate-command-router.cjs +2 -2
  183. package/gsd-core/bin/lib/validate.cjs +20 -6
  184. package/gsd-core/bin/lib/vendor/README.md +75 -0
  185. package/gsd-core/bin/lib/vendor/js-yaml.cjs +3014 -0
  186. package/gsd-core/bin/lib/vendor/re2js.cjs +6480 -0
  187. package/gsd-core/bin/lib/vendor/re2js.d.cts +938 -0
  188. package/gsd-core/bin/lib/verification-command-router.cjs +2 -1
  189. package/gsd-core/bin/lib/verification.cjs +272 -9
  190. package/gsd-core/bin/lib/verify-command-grounding.cjs +846 -0
  191. package/gsd-core/bin/lib/verify.cjs +453 -918
  192. package/gsd-core/bin/lib/workstream-inventory-builder.cjs +53 -32
  193. package/gsd-core/bin/lib/workstream-inventory.cjs +63 -10
  194. package/gsd-core/bin/lib/workstream-name-policy.cjs +25 -4
  195. package/gsd-core/bin/lib/workstream.cjs +2 -2
  196. package/gsd-core/bin/lib/worktree-base-ref.cjs +66 -12
  197. package/gsd-core/bin/lib/worktree-safety.cjs +341 -18
  198. package/gsd-core/bin/shared/config-defaults.manifest.json +8 -1
  199. package/gsd-core/bin/shared/config-schema.manifest.json +12 -1
  200. package/gsd-core/bin/shared/exit-codes.json +8 -0
  201. package/gsd-core/bin/shared/exit-codes.sh +20 -0
  202. package/gsd-core/bin/shared/model-catalog.json +8 -1
  203. package/gsd-core/references/agent-contracts.md +44 -26
  204. package/gsd-core/references/api-coverage.md +24 -2
  205. package/gsd-core/references/autonomous-smart-discuss.md +3 -3
  206. package/gsd-core/references/checkpoints.md +39 -21
  207. package/gsd-core/references/context-budget.md +1 -1
  208. package/gsd-core/references/decimal-phase-calculation.md +5 -5
  209. package/gsd-core/references/dispatch-isolation-gate.md +138 -0
  210. package/gsd-core/references/doc-conflict-engine.md +1 -1
  211. package/gsd-core/references/edge-probe.md +8 -0
  212. package/gsd-core/references/execute-mvp-tdd.md +4 -6
  213. package/gsd-core/references/execute-phase-between-wave-reset.md +15 -14
  214. package/gsd-core/references/execute-phase-context-guard.md +1 -1
  215. package/gsd-core/references/execute-phase-response-language.md +1 -1
  216. package/gsd-core/references/execute-phase-wave-guard.md +17 -11
  217. package/gsd-core/references/failing-direction.md +78 -0
  218. package/gsd-core/references/gate-prompts.md +1 -1
  219. package/gsd-core/references/git-integration.md +5 -5
  220. package/gsd-core/references/git-planning-commit.md +5 -4
  221. package/gsd-core/references/gsd-run-resolver.md +1 -1
  222. package/gsd-core/references/loop-hook-dispatch.md +61 -2
  223. package/gsd-core/references/model-profiles.md +12 -4
  224. package/gsd-core/references/mvp-concepts.md +9 -9
  225. package/gsd-core/references/nyquist-compliance.md +74 -0
  226. package/gsd-core/references/offer-next.md +3 -5
  227. package/gsd-core/references/phase-argument-parsing.md +3 -3
  228. package/gsd-core/references/planner-failing-direction.md +53 -0
  229. package/gsd-core/references/planner-guidance.md +3 -9
  230. package/gsd-core/references/planner-human-verify-mode.md +15 -1
  231. package/gsd-core/references/planner-preconditions.md +1 -1
  232. package/gsd-core/references/planner-reviews.md +1 -1
  233. package/gsd-core/references/planner-revision.md +1 -1
  234. package/gsd-core/references/planner-verify-command-grounding.md +17 -0
  235. package/gsd-core/references/planning-config.md +44 -13
  236. package/gsd-core/references/reviewer-instances.md +31 -0
  237. package/gsd-core/references/revision-loop.md +1 -1
  238. package/gsd-core/references/runtime-aware-dispatch.md +1 -1
  239. package/gsd-core/references/specless-probe-fallback.md +1 -1
  240. package/gsd-core/references/tdd.md +1 -3
  241. package/gsd-core/references/ui-brand.md +65 -21
  242. package/gsd-core/references/ui-consideration-probe.md +1 -1
  243. package/gsd-core/references/universal-anti-patterns.md +5 -5
  244. package/gsd-core/references/verifier-phase-gates.md +192 -0
  245. package/gsd-core/references/verify-command-path-resolvability.md +42 -0
  246. package/gsd-core/references/verify-mvp-mode.md +2 -2
  247. package/gsd-core/references/workstream-flag.md +33 -17
  248. package/gsd-core/templates/README.md +1 -1
  249. package/gsd-core/templates/SECURITY.md +3 -3
  250. package/gsd-core/templates/UI-SPEC.md +25 -3
  251. package/gsd-core/templates/VALIDATION.md +3 -3
  252. package/gsd-core/templates/discussion-log.md +1 -1
  253. package/gsd-core/templates/phase-prompt.md +5 -4
  254. package/gsd-core/templates/state.md +11 -4
  255. package/gsd-core/templates/verification-report.md +9 -1
  256. package/gsd-core/workflows/_runtime-launcher.snippet.sh +1 -1
  257. package/gsd-core/workflows/add-backlog.md +1 -1
  258. package/gsd-core/workflows/add-phase.md +3 -3
  259. package/gsd-core/workflows/add-tests.md +3 -8
  260. package/gsd-core/workflows/add-todo.md +1 -1
  261. package/gsd-core/workflows/ai-integration-phase.md +13 -20
  262. package/gsd-core/workflows/audit-fix.md +12 -3
  263. package/gsd-core/workflows/audit-milestone.md +9 -9
  264. package/gsd-core/workflows/audit-uat.md +17 -2
  265. package/gsd-core/workflows/autonomous/steps/converge-fail-fast.md +2 -2
  266. package/gsd-core/workflows/autonomous.md +11 -27
  267. package/gsd-core/workflows/check-todos.md +1 -1
  268. package/gsd-core/workflows/cleanup.md +64 -5
  269. package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +14 -4
  270. package/gsd-core/workflows/code-review-fix.md +38 -11
  271. package/gsd-core/workflows/code-review.md +159 -52
  272. package/gsd-core/workflows/complete-milestone.md +151 -23
  273. package/gsd-core/workflows/debug.md +12 -8
  274. package/gsd-core/workflows/diagnose-issues.md +47 -15
  275. package/gsd-core/workflows/discuss-phase/modes/advisor.md +1 -1
  276. package/gsd-core/workflows/discuss-phase/modes/chain.md +5 -8
  277. package/gsd-core/workflows/discuss-phase/modes/default.md +1 -1
  278. package/gsd-core/workflows/discuss-phase/modes/text.md +1 -1
  279. package/gsd-core/workflows/discuss-phase-assumptions/steps/auto-advance-dispatch.md +1 -3
  280. package/gsd-core/workflows/discuss-phase-assumptions.md +4 -3
  281. package/gsd-core/workflows/discuss-phase.md +1 -1
  282. package/gsd-core/workflows/do.md +3 -6
  283. package/gsd-core/workflows/docs-update.md +5 -4
  284. package/gsd-core/workflows/edit-phase.md +27 -2
  285. package/gsd-core/workflows/eval-review.md +7 -14
  286. package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +1 -1
  287. package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +142 -15
  288. package/gsd-core/workflows/execute-phase/steps/gap-closure-artifacts.md +1 -1
  289. package/gsd-core/workflows/execute-phase/steps/partial-wave.md +1 -1
  290. package/gsd-core/workflows/execute-phase/steps/per-plan-executor-routing.md +77 -0
  291. package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +24 -4
  292. package/gsd-core/workflows/execute-phase/steps/post-merge-gate.md +2 -2
  293. package/gsd-core/workflows/execute-phase/steps/protected-branch.md +21 -0
  294. package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +2 -2
  295. package/gsd-core/workflows/execute-phase/steps/wave-post-gate-hooks.md +39 -0
  296. package/gsd-core/workflows/execute-phase.md +72 -100
  297. package/gsd-core/workflows/execute-plan.md +52 -15
  298. package/gsd-core/workflows/explore.md +131 -4
  299. package/gsd-core/workflows/extract-learnings.md +1 -1
  300. package/gsd-core/workflows/fast.md +10 -2
  301. package/gsd-core/workflows/forensics.md +1 -1
  302. package/gsd-core/workflows/graduation.md +5 -5
  303. package/gsd-core/workflows/health.md +76 -10
  304. package/gsd-core/workflows/import.md +18 -15
  305. package/gsd-core/workflows/inbox.md +4 -5
  306. package/gsd-core/workflows/ingest-docs.md +49 -16
  307. package/gsd-core/workflows/insert-phase.md +5 -5
  308. package/gsd-core/workflows/list-seeds.md +5 -3
  309. package/gsd-core/workflows/list-workspaces.md +1 -1
  310. package/gsd-core/workflows/manager.md +12 -23
  311. package/gsd-core/workflows/map-codebase.md +1 -1
  312. package/gsd-core/workflows/milestone-summary.md +1 -1
  313. package/gsd-core/workflows/mvp-phase.md +8 -5
  314. package/gsd-core/workflows/new-milestone.md +22 -29
  315. package/gsd-core/workflows/new-project/steps/auto-mode-config.md +1 -1
  316. package/gsd-core/workflows/new-project.md +26 -40
  317. package/gsd-core/workflows/new-workspace.md +1 -1
  318. package/gsd-core/workflows/next.md +14 -2
  319. package/gsd-core/workflows/pause-work.md +1 -1
  320. package/gsd-core/workflows/plan-phase/steps/adr-ingest-express-path.md +1 -1
  321. package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +1 -1
  322. package/gsd-core/workflows/plan-phase/steps/prd-express-path.md +2 -4
  323. package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +3 -3
  324. package/gsd-core/workflows/plan-phase.md +162 -59
  325. package/gsd-core/workflows/plan-review-convergence.md +96 -11
  326. package/gsd-core/workflows/plant-seed.md +2 -2
  327. package/gsd-core/workflows/pr-branch.md +187 -51
  328. package/gsd-core/workflows/profile-user.md +16 -14
  329. package/gsd-core/workflows/progress.md +61 -18
  330. package/gsd-core/workflows/quick/steps/discussion-phase.md +1 -3
  331. package/gsd-core/workflows/quick/steps/plan-checker-loop.md +5 -7
  332. package/gsd-core/workflows/quick/steps/quick-verification.md +28 -9
  333. package/gsd-core/workflows/quick/steps/research-phase.md +4 -6
  334. package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +3 -3
  335. package/gsd-core/workflows/quick.md +55 -44
  336. package/gsd-core/workflows/remove-phase.md +4 -4
  337. package/gsd-core/workflows/remove-workspace.md +2 -2
  338. package/gsd-core/workflows/resume-project.md +8 -12
  339. package/gsd-core/workflows/review.md +219 -20
  340. package/gsd-core/workflows/scan.md +1 -1
  341. package/gsd-core/workflows/secure-phase.md +3 -3
  342. package/gsd-core/workflows/session-report.md +2 -1
  343. package/gsd-core/workflows/settings-advanced.md +7 -9
  344. package/gsd-core/workflows/settings-integrations.md +64 -31
  345. package/gsd-core/workflows/settings.md +69 -7
  346. package/gsd-core/workflows/ship.md +116 -50
  347. package/gsd-core/workflows/sketch-wrap-up.md +11 -17
  348. package/gsd-core/workflows/sketch.md +12 -18
  349. package/gsd-core/workflows/smart-entry.md +3 -5
  350. package/gsd-core/workflows/spec-phase.md +53 -13
  351. package/gsd-core/workflows/spike-wrap-up.md +7 -11
  352. package/gsd-core/workflows/spike.md +20 -31
  353. package/gsd-core/workflows/stats.md +2 -2
  354. package/gsd-core/workflows/sync-skills.md +64 -9
  355. package/gsd-core/workflows/thread.md +11 -7
  356. package/gsd-core/workflows/transition.md +49 -14
  357. package/gsd-core/workflows/ui-phase.md +15 -21
  358. package/gsd-core/workflows/ui-review.md +8 -12
  359. package/gsd-core/workflows/ultraplan-phase.md +5 -13
  360. package/gsd-core/workflows/undo.md +8 -16
  361. package/gsd-core/workflows/update.md +7 -11
  362. package/gsd-core/workflows/validate-phase.md +3 -3
  363. package/gsd-core/workflows/verify-work/steps/automated-ui-verification.md +25 -1
  364. package/gsd-core/workflows/verify-work/steps/mvp-uat-framing.md +1 -1
  365. package/gsd-core/workflows/verify-work.md +66 -25
  366. package/hooks/dist/gsd-agent-isolation-guard.js +158 -30
  367. package/hooks/dist/gsd-check-update-worker.js +56 -13
  368. package/hooks/dist/gsd-check-update.js +19 -1
  369. package/hooks/dist/gsd-config-reload.js +18 -12
  370. package/hooks/dist/gsd-context-monitor.js +19 -10
  371. package/hooks/dist/gsd-cursor-post-tool.js +3 -1
  372. package/hooks/dist/gsd-cursor-pre-tool.js +2 -3
  373. package/hooks/dist/gsd-cursor-session-start.js +2 -1
  374. package/hooks/dist/gsd-cursor-stop.js +2 -1
  375. package/hooks/dist/gsd-cursor-subagent-start.js +83 -3
  376. package/hooks/dist/gsd-cursor-subagent-stop.js +6 -3
  377. package/hooks/dist/gsd-ensure-canonical-path.js +2 -1
  378. package/hooks/dist/gsd-graphify-update.sh +22 -18
  379. package/hooks/dist/gsd-node-runner.sh +76 -0
  380. package/hooks/dist/gsd-phase-boundary.sh +1 -0
  381. package/hooks/dist/gsd-prompt-guard.js +37 -27
  382. package/hooks/dist/gsd-read-guard.js +16 -7
  383. package/hooks/dist/gsd-read-injection-scanner.js +55 -32
  384. package/hooks/dist/gsd-session-state.sh +1 -0
  385. package/hooks/dist/gsd-statusline.js +231 -24
  386. package/hooks/dist/gsd-update-banner.js +22 -1
  387. package/hooks/dist/gsd-validate-commit.sh +80 -6
  388. package/hooks/dist/gsd-windsurf-pre-command.js +16 -11
  389. package/hooks/dist/gsd-windsurf-pre-write.js +22 -13
  390. package/hooks/dist/gsd-workflow-guard.js +162 -46
  391. package/hooks/dist/gsd-worktree-path-guard.js +36 -21
  392. package/hooks/dist/gsd-write-guard.js +35 -25
  393. package/hooks/dist/lib/cli-exit.js +560 -0
  394. package/hooks/dist/lib/exit-code-registry.js +98 -0
  395. package/hooks/dist/lib/git-cmd.js +92 -59
  396. package/hooks/dist/lib/git-probe.js +84 -0
  397. package/hooks/dist/lib/hook-exit.js +81 -0
  398. package/hooks/dist/lib/injection-patterns.js +45 -0
  399. package/hooks/dist/lib/isolation-deny-reason.js +39 -0
  400. package/hooks/dist/lib/isolation-sentinel.js +9 -0
  401. package/hooks/dist/managed-hooks-registry.cjs +3 -0
  402. package/hooks/gsd-agent-isolation-guard.js +158 -30
  403. package/hooks/gsd-check-update-worker.js +56 -13
  404. package/hooks/gsd-check-update.js +19 -1
  405. package/hooks/gsd-config-reload.js +18 -12
  406. package/hooks/gsd-context-monitor.js +19 -10
  407. package/hooks/gsd-cursor-post-tool.js +3 -1
  408. package/hooks/gsd-cursor-pre-tool.js +2 -3
  409. package/hooks/gsd-cursor-session-start.js +2 -1
  410. package/hooks/gsd-cursor-stop.js +2 -1
  411. package/hooks/gsd-cursor-subagent-start.js +83 -3
  412. package/hooks/gsd-cursor-subagent-stop.js +6 -3
  413. package/hooks/gsd-ensure-canonical-path.js +2 -1
  414. package/hooks/gsd-graphify-update.sh +22 -18
  415. package/hooks/gsd-node-runner.sh +76 -0
  416. package/hooks/gsd-phase-boundary.sh +1 -0
  417. package/hooks/gsd-prompt-guard.js +37 -27
  418. package/hooks/gsd-read-guard.js +16 -7
  419. package/hooks/gsd-read-injection-scanner.js +55 -32
  420. package/hooks/gsd-session-state.sh +1 -0
  421. package/hooks/gsd-statusline.js +231 -24
  422. package/hooks/gsd-update-banner.js +22 -1
  423. package/hooks/gsd-validate-commit.sh +80 -6
  424. package/hooks/gsd-windsurf-pre-command.js +16 -11
  425. package/hooks/gsd-windsurf-pre-write.js +22 -13
  426. package/hooks/gsd-workflow-guard.js +162 -46
  427. package/hooks/gsd-worktree-path-guard.js +36 -21
  428. package/hooks/gsd-write-guard.js +35 -25
  429. package/hooks/lib/cli-exit.js +560 -0
  430. package/hooks/lib/exit-code-registry.js +98 -0
  431. package/hooks/lib/git-cmd.js +92 -59
  432. package/hooks/lib/git-probe.js +84 -0
  433. package/hooks/lib/hook-exit.js +81 -0
  434. package/hooks/lib/injection-patterns.js +45 -0
  435. package/hooks/lib/isolation-deny-reason.js +39 -0
  436. package/hooks/lib/isolation-sentinel.js +9 -0
  437. package/hooks/managed-hooks-registry.cjs +3 -0
  438. package/package.json +28 -11
  439. package/pi/gsd.cjs +19 -5
  440. package/scripts/base64-scan.sh +74 -12
  441. package/scripts/baselines/planning-prompt-drift-baseline.json +4 -0
  442. package/scripts/baselines/planning-snapshot-bypass-baseline.json +12 -0
  443. package/scripts/baselines/unreachable-guard-drift-baseline.json +4 -0
  444. package/scripts/build-hooks.js +5 -0
  445. package/scripts/changeset/lint.cjs +60 -5
  446. package/scripts/check-alias-drift.cjs +7 -43
  447. package/scripts/check-contract-drift.cjs +297 -0
  448. package/scripts/check-glossary-refs.cjs +77 -15
  449. package/scripts/check-mutation-score-ratchet.cjs +156 -0
  450. package/scripts/ci-check-job-near-cap.cjs +49 -0
  451. package/scripts/ci-pr-mergeability.cjs +262 -0
  452. package/scripts/ci-test-scope.cjs +64 -14
  453. package/scripts/ci-timeout-report.cjs +230 -0
  454. package/scripts/command-contract-helpers.cjs +903 -1
  455. package/scripts/docs-guard-registry.cjs +396 -0
  456. package/scripts/gen-adr-index.cjs +728 -38
  457. package/scripts/gen-capability-registry.cjs +11 -21
  458. package/scripts/gen-context-index.cjs +2 -11
  459. package/scripts/gen-exit-code-docs.cjs +318 -0
  460. package/scripts/gen-exit-code-registry.cjs +891 -0
  461. package/scripts/gen-features.cjs +836 -0
  462. package/scripts/gen-health-docs.cjs +390 -0
  463. package/scripts/gen-hooks-cli-exit.cjs +239 -0
  464. package/scripts/gen-install-tree-fixtures.cjs +2 -2
  465. package/scripts/gen-inventory-manifest.cjs +50 -4
  466. package/scripts/gen-loop-host-contract.cjs +138 -25
  467. package/scripts/gen-registry.cjs +3 -14
  468. package/scripts/gen-scripts-cli-exit.cjs +185 -0
  469. package/scripts/gen-state-md-docs.cjs +727 -0
  470. package/scripts/{test-failure-reasons.cjs → gsd-test-gate-reasons.cjs} +6 -0
  471. package/scripts/lib/alias-drift-families.cjs +46 -0
  472. package/scripts/lib/ci-job-timing.cjs +72 -0
  473. package/scripts/lib/cli-exit.cjs +546 -44
  474. package/scripts/lib/drift-scan.cjs +308 -0
  475. package/scripts/lib/exit-code-registry.cjs +98 -0
  476. package/scripts/lib/ndjson-reporter.cjs +119 -0
  477. package/scripts/lint-allow-test-rule-refs.allowlist.json +1 -26
  478. package/scripts/lint-allow-test-rule-refs.effective-ceiling.json +4 -0
  479. package/scripts/lint-allow-test-rule-refs.unverified-ceiling.json +3 -0
  480. package/scripts/lint-canary-version-leak.cjs +73 -0
  481. package/scripts/lint-command-contract.cjs +96 -13
  482. package/scripts/lint-completion-predicate-drift.cjs +933 -0
  483. package/scripts/lint-completion-ratio-drift.cjs +214 -0
  484. package/scripts/lint-default-flip-documentation.cjs +193 -0
  485. package/scripts/lint-docs-guard-registration.cjs +495 -0
  486. package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +193 -0
  487. package/scripts/lint-eslint-glob-coverage.allowlist.json +38 -0
  488. package/scripts/lint-eslint-glob-coverage.cjs +340 -0
  489. package/scripts/{lint-fix-has-regression-test.cjs → lint-fix-has-regression-tests.cjs} +12 -6
  490. package/scripts/lint-frontmatter-scalar-broad-grep.cjs +237 -0
  491. package/scripts/lint-health-diagnostic-rule-table.cjs +461 -0
  492. package/scripts/lint-hooks-runtime-build-seam.cjs +262 -0
  493. package/scripts/lint-milestone-window-drift.cjs +468 -0
  494. package/scripts/lint-mutation-test-derivation-drift.cjs +86 -0
  495. package/scripts/lint-phase-enumeration-drift.cjs +492 -0
  496. package/scripts/lint-plan-count-drift.cjs +318 -0
  497. package/scripts/lint-planning-artifact-writer-drift.cjs +398 -0
  498. package/scripts/lint-planning-prompt-drift.cjs +471 -0
  499. package/scripts/lint-planning-snapshot-bypass-drift.cjs +544 -0
  500. package/scripts/lint-regression-test-names.cjs +15 -13
  501. package/scripts/lint-removed-but-needed.cjs +488 -0
  502. package/scripts/lint-seam-enforcement.cjs +182 -0
  503. package/scripts/lint-slug-derivation-drift.cjs +921 -0
  504. package/scripts/lint-source-test-name-collision.cjs +241 -0
  505. package/scripts/lint-state-field-drift.cjs +805 -0
  506. package/scripts/lint-state-write-path-drift.cjs +950 -0
  507. package/scripts/lint-test-file-count.allowlist.json +137 -8
  508. package/scripts/lint-test-file-count.cjs +25 -3
  509. package/scripts/lint-unreachable-guard-drift.cjs +830 -0
  510. package/scripts/lint-vendored-deps.cjs +297 -0
  511. package/scripts/mutation-matrix.cjs +599 -50
  512. package/scripts/pr-changed-files.cjs +63 -0
  513. package/scripts/pr-template-policy.cjs +14 -4
  514. package/scripts/prompt-injection-scan.sh +100 -14
  515. package/scripts/require-issue-link-policy.cjs +192 -0
  516. package/scripts/secret-scan.sh +75 -13
  517. package/scripts/select-docs-guards.cjs +56 -0
  518. package/scripts/sync-runtime-launcher.cjs +24 -7
  519. package/skills/gsd-autonomous/SKILL.md +0 -1
  520. package/skills/gsd-code-review/SKILL.md +1 -1
  521. package/skills/gsd-discuss-phase/SKILL.md +1 -1
  522. package/skills/gsd-execute-phase/SKILL.md +1 -2
  523. package/skills/gsd-import/SKILL.md +1 -1
  524. package/skills/gsd-map-codebase/SKILL.md +1 -1
  525. package/skills/gsd-mempalace-capture/SKILL.md +1 -1
  526. package/skills/gsd-mempalace-recall/SKILL.md +1 -1
  527. package/skills/gsd-new-milestone/SKILL.md +1 -1
  528. package/skills/gsd-next/SKILL.md +0 -1
  529. package/skills/gsd-plan-phase/SKILL.md +0 -1
  530. package/skills/gsd-progress/SKILL.md +0 -1
  531. package/skills/gsd-quick/SKILL.md +9 -5
  532. package/skills/gsd-review-backlog/SKILL.md +2 -1
  533. package/skills/gsd-stats/SKILL.md +0 -1
  534. package/skills/gsd-verify-work/SKILL.md +1 -1
  535. package/vscode/package.json +1 -1
  536. package/bin/lib/ui-safety-gate.cjs +0 -107
  537. package/gsd-core/workflows/discovery-phase.md +0 -298
  538. package/gsd-core/workflows/plan-milestone-gaps.md +0 -281
  539. package/gsd-core/workflows/verify-phase.md +0 -574
  540. package/scripts/affected-tests-lib.cjs +0 -554
  541. package/scripts/lint-allow-test-rule-refs.cjs +0 -162
  542. package/scripts/lint-emitted-drift-ack.cjs +0 -344
  543. package/scripts/run-affected-tests.cjs +0 -7
  544. package/scripts/run-tests.cjs +0 -1051
@@ -19,9 +19,19 @@
19
19
  * hook's own __dirname:
20
20
  *
21
21
  * const { isGitSubcommand } = require(path.join(__dirname, 'lib', 'git-cmd.js'));
22
+ *
23
+ * `tokenize()` delegates to the shared `src/token-scanner.cts` seam (ADR-3212
24
+ * §4, epic #3212 Phase 3, #3414) — the built `gsd-core/bin/lib/token-scanner.cjs`
25
+ * artifact, not a sibling hooks/-tree file, because hook scripts are staged as
26
+ * standalone files at install time and a sibling require is a staging
27
+ * dependency that can fail silently (see gsd-workflow-guard.js's own
28
+ * KIMI_TOOL_NAMES comment for the precedent this follows). Re-exported here
29
+ * unchanged — every existing caller's behavior is identical (parity-asserted
30
+ * in tests/token-scanner.test.cjs row 5).
22
31
  */
23
32
 
24
33
  const path = require('path');
34
+ const { tokenizeShellLike } = require(path.join(__dirname, '..', '..', 'gsd-core', 'bin', 'lib', 'token-scanner.cjs'));
25
35
 
26
36
  /**
27
37
  * Git global options that take a following argument.
@@ -29,6 +39,7 @@ const path = require('path');
29
39
  */
30
40
  const ARGUMENT_TAKING_FLAGS = new Set([
31
41
  '-C', // working directory
42
+ '-c', // config override (separate-arg form: `git -c k=v …`; #3504)
32
43
  '--git-dir', // path to git repository
33
44
  '--work-tree', // path to working tree
34
45
  '--namespace', // git namespace
@@ -57,94 +68,116 @@ const BOOLEAN_FLAGS = new Set([
57
68
  * Handles single-quoted strings, double-quoted strings, and unquoted tokens.
58
69
  * Does NOT perform variable expansion or brace expansion.
59
70
  *
71
+ * Delegates to the shared `src/token-scanner.cts` seam — see the module
72
+ * header comment for why the built artifact, not a sibling require, is used.
73
+ *
60
74
  * @param {string} cmd
61
75
  * @returns {string[]}
62
76
  */
63
77
  function tokenize(cmd) {
64
- const tokens = [];
65
- let i = 0;
66
- const len = cmd.length;
67
-
68
- while (i < len) {
69
- // Skip whitespace
70
- while (i < len && /\s/.test(cmd[i])) i++;
71
- if (i >= len) break;
72
-
73
- let token = '';
74
- while (i < len && !/\s/.test(cmd[i])) {
75
- if (cmd[i] === "'") {
76
- // Single-quoted string: take everything until closing '
77
- i++;
78
- while (i < len && cmd[i] !== "'") token += cmd[i++];
79
- if (i < len) i++; // consume closing '
80
- } else if (cmd[i] === '"') {
81
- // Double-quoted string: take everything until closing " (no escape handling)
82
- i++;
83
- while (i < len && cmd[i] !== '"') token += cmd[i++];
84
- if (i < len) i++; // consume closing "
85
- } else {
86
- token += cmd[i++];
87
- }
88
- }
89
- if (token) tokens.push(token);
90
- }
91
-
92
- return tokens;
78
+ return tokenizeShellLike(cmd);
93
79
  }
94
80
 
95
81
  /**
96
- * Return true if `cmd` invokes the git subcommand `sub`.
82
+ * Walk past leading env-prefix assignments and global git options, same as
83
+ * `isGitSubcommand`'s phases 1-3. Returns the index of the subcommand token,
84
+ * or -1 if the command does not resolve to a git invocation at all.
97
85
  *
98
- * @param {string} cmd - Full shell command string (may include env vars, full paths)
99
- * @param {string} sub - Subcommand to test for, e.g. 'commit'
100
- * @returns {boolean}
86
+ * @param {string[]} tokens
87
+ * @returns {number}
101
88
  */
102
- function isGitSubcommand(cmd, sub) {
103
- if (!cmd || !sub) return false;
104
-
105
- const tokens = tokenize(cmd);
89
+ function skipToSubcommand(tokens) {
106
90
  let i = 0;
107
-
108
- // Phase 1: skip leading VAR=VALUE environment assignments
109
91
  while (i < tokens.length && /^[A-Za-z_][A-Za-z0-9_]*=/.test(tokens[i])) {
110
92
  i++;
111
93
  }
112
-
113
- // Phase 2: the next token must be the git executable
114
- if (i >= tokens.length) return false;
94
+ if (i >= tokens.length) return -1;
115
95
  const gitToken = tokens[i++];
116
- if (path.basename(gitToken) !== 'git') return false;
96
+ if (path.basename(gitToken) !== 'git') return -1;
117
97
 
118
- // Phase 3: consume git global options
119
98
  while (i < tokens.length) {
120
99
  const t = tokens[i];
121
-
122
- // --flag=value form for argument-taking flags
123
100
  const eqIdx = t.indexOf('=');
124
101
  const flagName = eqIdx !== -1 ? t.slice(0, eqIdx) : t;
125
102
  if (ARGUMENT_TAKING_FLAGS.has(flagName)) {
126
- if (eqIdx !== -1) {
127
- // consumed as one token: --git-dir=.git
128
- i++;
129
- } else {
130
- // consumed as two tokens: -C /path
131
- i += 2;
132
- }
103
+ i += eqIdx !== -1 ? 1 : 2;
104
+ continue;
105
+ }
106
+ // #3504: glued `-ckey=value` form — git accepts the config override with
107
+ // its argument attached (`git -cfoo.bar=1 …`). The eq-slice above yields
108
+ // flagName `-cfoo`, which no set contains, so without this arm the walk
109
+ // stops and the whole invocation is misclassified as not-git.
110
+ if (/^-c\S*=/.test(t)) {
111
+ i++;
133
112
  continue;
134
113
  }
135
-
136
114
  if (BOOLEAN_FLAGS.has(t)) {
137
115
  i++;
138
116
  continue;
139
117
  }
140
-
141
- // Not a global option — this is the subcommand
142
118
  break;
143
119
  }
120
+ return i;
121
+ }
122
+
123
+ /**
124
+ * Extract the branch-name argument from a git command line that creates or
125
+ * references one — `git checkout -b <name>` or `git branch <name>`. Returns
126
+ * null for any other command, including plain `git checkout <ref>` (switches
127
+ * branches, does not create one) and commands where a checkout/branch-shaped
128
+ * substring appears only inside a quoted argument (e.g. a commit message).
129
+ *
130
+ * New capability (ADR-3212 §4, epic #3212 Phase 3, #3414) exercising the
131
+ * shared scanner on the domain the ADR names ("a branch name... [is] not
132
+ * regular") — not a migration of existing duplicated logic; no prior
133
+ * implementation of this existed in the repo (design doc §1.2).
134
+ *
135
+ * @param {string} cmd
136
+ * @returns {string | null}
137
+ */
138
+ function extractBranchArgument(cmd) {
139
+ if (!cmd) return null;
140
+ const tokens = tokenizeShellLike(cmd);
141
+ const subIdx = skipToSubcommand(tokens);
142
+ if (subIdx === -1 || subIdx >= tokens.length) return null;
143
+ const sub = tokens[subIdx];
144
+
145
+ if (sub === 'checkout') {
146
+ for (let j = subIdx + 1; j < tokens.length; j++) {
147
+ if (tokens[j] === '-b' && j + 1 < tokens.length) return tokens[j + 1];
148
+ }
149
+ return null;
150
+ }
151
+
152
+ if (sub === 'branch') {
153
+ for (let j = subIdx + 1; j < tokens.length; j++) {
154
+ if (!tokens[j].startsWith('-')) return tokens[j];
155
+ }
156
+ return null;
157
+ }
158
+
159
+ return null;
160
+ }
161
+
162
+ /**
163
+ * Return true if `cmd` invokes the git subcommand `sub`.
164
+ *
165
+ * @param {string} cmd - Full shell command string (may include env vars, full paths)
166
+ * @param {string} sub - Subcommand to test for, e.g. 'commit'
167
+ * @returns {boolean}
168
+ */
169
+ function isGitSubcommand(cmd, sub) {
170
+ if (!cmd || !sub) return false;
171
+
172
+ // Phases 1-3 (env-prefix skip, git-executable check, global-option consume)
173
+ // extracted verbatim into skipToSubcommand — byte-identical logic, shared
174
+ // with extractBranchArgument rather than a second copy (#3212 Phase 3).
175
+ const tokens = tokenizeShellLike(cmd);
176
+ const subIdx = skipToSubcommand(tokens);
144
177
 
145
178
  // Phase 4: check the subcommand
146
- if (i >= tokens.length) return false;
147
- return tokens[i] === sub;
179
+ if (subIdx === -1 || subIdx >= tokens.length) return false;
180
+ return tokens[subIdx] === sub;
148
181
  }
149
182
 
150
- module.exports = { isGitSubcommand, tokenize };
183
+ module.exports = { isGitSubcommand, tokenize, extractBranchArgument, skipToSubcommand };
@@ -0,0 +1,84 @@
1
+ 'use strict';
2
+ // hooks/lib/git-probe.js — classify a bounded spawnSync(git, ...) result,
3
+ // distinguishing a GENUINE negative answer (git ran and said "no") from
4
+ // "could not determine" (timeout / spawn failure / signal kill) — #3911.
5
+ //
6
+ // Proven defect: hooks/gsd-worktree-path-guard.js, hooks/gsd-workflow-guard.js,
7
+ // and hooks/gsd-windsurf-pre-write.js each treat spawnSync(git, ..., {timeout})
8
+ // returning a non-zero/empty result as "not applicable" and allow silently.
9
+ // A macOS CI run showed three deny cases land at 2084ms/2112ms/2177ms — just
10
+ // past the 2000ms budget — each returning exit 0 with EMPTY stdout AND EMPTY
11
+ // stderr: a timeout is INDISTINGUISHABLE, at the call site, from git cleanly
12
+ // answering "not a repo" / "not this worktree" unless the spawnSync() result
13
+ // itself is inspected for `error`/`signal`, not just `status`/`stdout`.
14
+ //
15
+ // This module does not change any hook's decision or exit code — it only
16
+ // answers "was this probe's answer real?" so a caller can emit a diagnostic
17
+ // on the undetermined branch while keeping the existing fail-open behavior.
18
+ //
19
+ // Classification mirrors tests/helpers/process-seam.cjs's OUTCOME vocabulary
20
+ // (EXITED vs TIMED_OUT/SPAWN_FAILED/KILLED) — same evidence-over-classification
21
+ // ordering (a populated `status` outranks an attached `error`, since Node can
22
+ // report `error.code === 'ETIMEDOUT'` on a result that also carried a real
23
+ // exit that beat the timer) — so a probe here and a subprocess outcome in the
24
+ // test suite never disagree on the same raw spawnSync() shape.
25
+
26
+ /**
27
+ * @param {{error?: (Error & {code?: string})|null, status: number|null, signal: string|null}} result
28
+ * the raw return value of `spawnSync('git', ...)`.
29
+ * @returns {{determined: true} | {determined: false, reason: string}}
30
+ */
31
+ function classifyGitProbe(result) {
32
+ const error = result && result.error;
33
+ const status = result ? result.status : null;
34
+ const signal = result ? result.signal : null;
35
+
36
+ if (!error && signal === null) {
37
+ // A real exit — status 0 or non-zero is a genuine, trustworthy answer.
38
+ return { determined: true };
39
+ }
40
+ if (status !== null) {
41
+ // `status` is only ever populated by a real exit; it outranks an attached
42
+ // `error` even at the exact timeout boundary (process-seam.cjs's own
43
+ // "evidence over classification" rule).
44
+ return { determined: true };
45
+ }
46
+
47
+ const code = error ? (error.code ?? null) : null;
48
+ let reason;
49
+ if (code === 'ETIMEDOUT' || signal !== null) {
50
+ reason = signal ? `timed out (signal ${signal})` : 'timed out';
51
+ } else if (code) {
52
+ reason = `spawn failed (${code})`;
53
+ } else {
54
+ reason = 'could not run (unknown reason)';
55
+ }
56
+ return { determined: false, reason };
57
+ }
58
+
59
+ /**
60
+ * If `result` could not be determined (timeout / spawn failure / signal
61
+ * kill), write a stderr diagnostic naming the probe and why — never changes
62
+ * any exit code, never throws. A no-op when the probe genuinely ran and
63
+ * answered (status 0 or non-zero with no error/signal).
64
+ *
65
+ * @param {string} hookName - e.g. 'gsd-worktree-path-guard'
66
+ * @param {string} probeLabel - e.g. "git rev-parse --show-toplevel"
67
+ * @param {*} result - the raw spawnSync() return value
68
+ */
69
+ function reportIfUndetermined(hookName, probeLabel, result) {
70
+ const classification = classifyGitProbe(result);
71
+ if (classification.determined) return;
72
+ try {
73
+ process.stderr.write(
74
+ `${hookName}: git probe '${probeLabel}' ${classification.reason} — ` +
75
+ `allowing this call because the probe's answer is unknown, not because ` +
76
+ `git answered "no" (#3911).\n`
77
+ );
78
+ } catch {
79
+ // A stderr write failing (EPIPE, closed fd) must never itself change the
80
+ // hook's fail-open outcome.
81
+ }
82
+ }
83
+
84
+ module.exports = { classifyGitProbe, reportIfUndetermined };
@@ -0,0 +1,81 @@
1
+ 'use strict';
2
+ // hooks/lib/hook-exit.js — hand-written, NOT generated. A tiny hook-facing
3
+ // vocabulary layered over hooks/lib/cli-exit.js's terminateNow (ADR-3889 §3),
4
+ // for the 19 enforcement hooks P7/#3911 is migrating off raw process.exit().
5
+ //
6
+ // WHY onCrash is a REQUIRED argument, with no default (this is the entire
7
+ // point of this module): every hook audited for #3911 ended its outer
8
+ // try/catch in ONE of two ways — some `process.exit(0)` (fail open: a hook
9
+ // error must never block a legitimate tool call), others `process.exit(2)`
10
+ // (fail closed: a hook whose whole job is a security/safety denial must not
11
+ // let its own bug wave the denial through). Both are legitimate policies for
12
+ // DIFFERENT hooks — but neither is the "obviously correct" one, and a shared
13
+ // helper that silently defaulted to either would let a future hook inherit
14
+ // the wrong policy by omission, which is exactly the "nothing fails with
15
+ // success" defect ADR-3889 exists to close. Requiring the caller to name its
16
+ // policy at every call site — not just once at module load — makes "I forgot
17
+ // to decide" a load-time/call-time crash instead of a silent behavior. A
18
+ // caller that truly wants "allow on crash" must still write ALLOW; there is
19
+ // no path that reaches terminateNow without a declared choice.
20
+ //
21
+ // crash() itself is total: it does not throw on a bad `onCrash`, because
22
+ // throwing would unwind into the CALLER's own outer catch — the exact
23
+ // fail-open-by-accident hazard this module removes. Instead an unrecognized
24
+ // policy terminates via terminateNow('INTERNAL', ...) with a diagnostic
25
+ // payload naming the offending value, so a typo'd/misspelled policy is
26
+ // debuggable on stderr rather than silently reinterpreted as ALLOW or DENY.
27
+ const { terminateNow } = require('./cli-exit.js');
28
+
29
+ /** Frozen enum of the two declarable crash policies. No third option. */
30
+ const HOOK_ON_CRASH = Object.freeze({
31
+ ALLOW: 'allow',
32
+ DENY: 'deny',
33
+ });
34
+
35
+ /** Terminate with the hook-protocol PASS outcome (exit 0). */
36
+ function allow(payload) {
37
+ terminateNow('PASS', payload);
38
+ }
39
+
40
+ /**
41
+ * Terminate with the hook-protocol deny outcome (exit 2, stdout+stderr).
42
+ *
43
+ * @param {*} payload - JSON-serializable value written to fd 1 (and, when
44
+ * `stderrPayload` is omitted, fd 2 too).
45
+ * @param {*} [stderrPayload] - optional distinct value for fd 2, forwarded
46
+ * verbatim to terminateNow's own `stderrPayload` param — a string is
47
+ * written raw, anything else is JSON-stringified.
48
+ */
49
+ function deny(payload, stderrPayload) {
50
+ terminateNow('HOOK_DENY', payload, stderrPayload);
51
+ }
52
+
53
+ /**
54
+ * Dispatch to allow()/deny() per a DECLARED crash policy. `onCrash` is
55
+ * required — see the module header for why there is no default.
56
+ *
57
+ * @param {'allow'|'deny'} onCrash - one of HOOK_ON_CRASH's two values.
58
+ * @param {*} payload - JSON-serializable value forwarded to terminateNow.
59
+ */
60
+ function crash(onCrash, payload) {
61
+ if (onCrash === HOOK_ON_CRASH.ALLOW) {
62
+ allow(payload);
63
+ return;
64
+ }
65
+ if (onCrash === HOOK_ON_CRASH.DENY) {
66
+ deny(payload);
67
+ return;
68
+ }
69
+ // Never guess a policy and never throw (a throw would unwind into the
70
+ // caller's own outer catch — the fail-open-by-accident defect this module
71
+ // exists to remove). Terminate deterministically with INTERNAL, naming the
72
+ // offending value so a misspelled/omitted policy is diagnosable.
73
+ terminateNow('INTERNAL', {
74
+ error: 'hook-exit: crash() called with an unrecognized onCrash policy',
75
+ receivedOnCrash: onCrash,
76
+ expectedOneOf: [HOOK_ON_CRASH.ALLOW, HOOK_ON_CRASH.DENY],
77
+ originalPayload: payload,
78
+ });
79
+ }
80
+
81
+ module.exports = { HOOK_ON_CRASH, allow, deny, crash };
@@ -0,0 +1,45 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * injection-patterns.js — the shared prompt-injection pattern list (#3504, epic #1900).
5
+ *
6
+ * Single source of truth for the standard injection signatures used by BOTH
7
+ * gsd-prompt-guard.js (PreToolUse scan of writes into .planning/) and
8
+ * gsd-read-injection-scanner.js (PostToolUse scan of Read/WebFetch/WebSearch
9
+ * content). Previously each hook carried a byte-identical copy ("inlined for
10
+ * hook independence") that could silently drift — a pattern tightened in one
11
+ * would stop protecting the other surface.
12
+ *
13
+ * Why a shared lib require is safe here (the old inlining rationale, retired):
14
+ * the installer stages hooks/lib/ from the GSD_HOOK_LIB_FILES allowlist for the
15
+ * shared-bundle surfaces (Claude-family settings.json runtimes and Kimi), the
16
+ * Cursor stager auto-discovers require('./lib/...') in staged scripts and fails
17
+ * the install loudly when a helper is missing (#2587), and the plugin path
18
+ * ships this directory wholesale.
19
+ *
20
+ * Deliberately NOT unified with src/security.cts's scanForInjection set: that
21
+ * set runs inside the compiled lib tree; hooks must stay loadable standalone
22
+ * without it. The two lists are different surfaces by design, not drift.
23
+ *
24
+ * Keep this file free of literal 'gsd:' text — the stager rewrites that marker
25
+ * in staged hook content.
26
+ */
27
+
28
+ const INJECTION_PATTERNS = Object.freeze([
29
+ /ignore\s+(all\s+)?previous\s+instructions/i,
30
+ /ignore\s+(all\s+)?above\s+instructions/i,
31
+ /disregard\s+(all\s+)?previous/i,
32
+ /forget\s+(all\s+)?(your\s+)?instructions/i,
33
+ /override\s+(system|previous)\s+(prompt|instructions)/i,
34
+ /you\s+are\s+now\s+(?:a|an|the)\s+/i,
35
+ /act\s+as\s+(?:a|an|the)\s+(?!plan|phase|wave)/i,
36
+ /pretend\s+(?:you(?:'re| are)\s+|to\s+be\s+)/i,
37
+ /from\s+now\s+on,?\s+you\s+(?:are|will|should|must)/i,
38
+ /(?:print|output|reveal|show|display|repeat)\s+(?:your\s+)?(?:system\s+)?(?:prompt|instructions)/i,
39
+ /<\/?(?:system|assistant|human)>/i,
40
+ /\[SYSTEM\]/i,
41
+ /\[INST\]/i,
42
+ /<<\s*SYS\s*>>/i,
43
+ ]);
44
+
45
+ module.exports = { INJECTION_PATTERNS };
@@ -0,0 +1,39 @@
1
+ 'use strict';
2
+ // hooks/lib/isolation-deny-reason.js — shared, frozen reason-code enum for
3
+ // the #3045 dispatch-isolation guards' block/deny decisions
4
+ // (hooks/gsd-agent-isolation-guard.js, hooks/gsd-cursor-subagent-start.js).
5
+ //
6
+ // CONTRIBUTING.md ("Prohibited: Raw Text Matching on Test Outputs") bans
7
+ // asserting on a hook's free-form, human-readable reason/user_message prose
8
+ // — that text is for the operator/model reading the denial and may change
9
+ // wording without notice. Every block/deny decision therefore ALSO carries
10
+ // one of these STABLE codes (surfaced on the hook's stdout JSON as
11
+ // `reason_code`), so tests assert `out.reason_code === REASON_CODE.X`
12
+ // instead of regexing the message (mirrors the REASON enum convention in
13
+ // gsd-core/bin/verify-reapply-patches.cjs).
14
+ //
15
+ // Adding a new code requires updating this enum AND any test that locks the
16
+ // documented set.
17
+ const REASON_CODE = Object.freeze({
18
+ // The compiled runtime library (gsd-core/bin/lib/*.cjs) is missing and
19
+ // could not be self-built (ensure-runtime-build.cjs's RuntimeBuildError).
20
+ RUNTIME_BUILD_FAILED: 'runtime_build_failed',
21
+ // The project's dispatch-isolation configuration ('.planning/config.json')
22
+ // could not be read or resolved for a reason OTHER than a runtime-build
23
+ // failure (unreadable/malformed config, unexpected resolver error).
24
+ CONFIG_UNREADABLE: 'config_unreadable',
25
+ // Isolation resolves to "harness-worktree" but the Agent()/Task() dispatch
26
+ // is missing the harness's isolation flag/kwarg.
27
+ HARNESS_FLAG_MISSING: 'harness_flag_missing',
28
+ // Isolation resolves to "harness-worktree" but the dispatch payload carries
29
+ // no usable subagent_type, so the guard cannot confirm it is a GSD executor.
30
+ NO_SUBAGENT_TYPE: 'no_subagent_type',
31
+ // Isolation resolves to "harness-worktree" but whether the workspace root
32
+ // is an isolated worktree could not be determined (e.g. git unresponsive).
33
+ CANNOT_DETERMINE_ISOLATION: 'cannot_determine_isolation',
34
+ // Isolation resolves to "harness-worktree" and the workspace root is
35
+ // confirmed NOT an isolated worktree.
36
+ NOT_ISOLATED_WORKTREE: 'not_isolated_worktree',
37
+ });
38
+
39
+ module.exports = { REASON_CODE };
@@ -130,6 +130,15 @@ function resolveSentinelRoot(cwd) {
130
130
  if (fs.existsSync(path.join(cwd, '.planning'))) {
131
131
  return cwd;
132
132
  }
133
+ // #3582: worktree-safety.cjs / project-root.cjs are tsc build artifacts
134
+ // (ADR-457), gitignored and absent on a raw plugin-marketplace / git-clone
135
+ // install that never ran `npm run build:lib`. Self-heal before either
136
+ // require below; a RuntimeBuildError (or any other failure) falls through
137
+ // to the existing catch's degrade-to-raw-`cwd` — unchanged behavior, just
138
+ // now attempted-healed-first rather than silently degrading on the first
139
+ // cold-tree encounter.
140
+ const { ensureRuntimeBuild } = require('../../gsd-core/bin/ensure-runtime-build.cjs');
141
+ ensureRuntimeBuild();
133
142
  const { resolveWorktreeRoot } = require('../../gsd-core/bin/lib/worktree-safety.cjs');
134
143
  const { root } = resolveWorktreeRoot(cwd);
135
144
  const { findProjectRoot } = require('../../gsd-core/bin/lib/project-root.cjs');
@@ -29,6 +29,9 @@ const MANAGED_HOOKS = [
29
29
  'gsd-cursor-subagent-stop.js',
30
30
  'gsd-ensure-canonical-path.js',
31
31
  'gsd-graphify-update.sh',
32
+ // #3662: portable node resolver (helper staged in hooks/; managed JS hook
33
+ // commands route through it under --portable-hooks).
34
+ 'gsd-node-runner.sh',
32
35
  'gsd-phase-boundary.sh',
33
36
  'gsd-prompt-guard.js',
34
37
  'gsd-read-guard.js',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opengsd/gsd-core",
3
- "version": "1.10.0",
3
+ "version": "1.12.0",
4
4
  "description": "GSD Core is a meta-prompting, context engineering, and spec-driven development system for AI coding agents.",
5
5
  "main": ".opencode/plugins/gsd-core.js",
6
6
  "bin": {
@@ -23,6 +23,12 @@
23
23
  "scripts",
24
24
  "!scripts/gen-emitted-baseline.cjs",
25
25
  "!scripts/qa-smell-ratchet.cjs",
26
+ "!scripts/live-config-guard.cjs",
27
+ "!scripts/run-tests.cjs",
28
+ "!scripts/affected-tests-lib.cjs",
29
+ "!scripts/run-affected-tests.cjs",
30
+ "!scripts/lint-no-adhoc-regex-escape.cjs",
31
+ "!scripts/lint-allow-test-rule-refs.cjs",
26
32
  "pi",
27
33
  "vscode"
28
34
  ],
@@ -50,7 +56,7 @@
50
56
  "access": "public"
51
57
  },
52
58
  "engines": {
53
- "node": ">=22.0.0",
59
+ "node": ">=24.0.0",
54
60
  "npm": ">=10.0.0"
55
61
  },
56
62
  "dependencies": {
@@ -60,14 +66,18 @@
60
66
  "devDependencies": {
61
67
  "@eslint/js": "^9.39.4",
62
68
  "@stryker-mutator/core": "^9.6.1",
69
+ "@stryker-mutator/tap-runner": "^9.6.1",
63
70
  "@types/node": "^22.19.19",
64
71
  "c8": "^11.0.0",
65
72
  "eslint": "^9.39.4",
66
73
  "eslint-plugin-n": "^17.24.0",
67
74
  "eslint-plugin-no-only-tests": "^3.4.0",
75
+ "espree": "^10.4.0",
68
76
  "fast-check": "^4.8.0",
69
77
  "globals": "^16.5.0",
70
- "js-yaml": "^4.2.1",
78
+ "js-yaml": "^4.3.1",
79
+ "mutation-testing-metrics": "^3.7.3",
80
+ "re2js": "^2.8.6",
71
81
  "typescript": "^6.0.3",
72
82
  "typescript-eslint": "^8.60.0"
73
83
  },
@@ -81,6 +91,7 @@
81
91
  },
82
92
  "scripts": {
83
93
  "sync:launcher": "node scripts/sync-runtime-launcher.cjs",
94
+ "check:contract-drift": "node scripts/check-contract-drift.cjs",
84
95
  "check:env": "node scripts/check-env.cjs",
85
96
  "check:alias-drift": "node scripts/check-alias-drift.cjs",
86
97
  "check:identity-drift": "node scripts/lint-package-identity-drift.cjs",
@@ -97,7 +108,7 @@
97
108
  "gen:registry": "node scripts/gen-registry.cjs --write",
98
109
  "gen:install-tree": "node scripts/gen-install-tree-fixtures.cjs",
99
110
  "gen:section-manifest": "node scripts/gen-section-manifest.cjs --write",
100
- "regen:derived": "npm run build && npm run gen:registry && node scripts/gen-adr-index.cjs --write && node scripts/gen-capability-matrix.cjs --write && node scripts/gen-inventory-manifest.cjs --write && node scripts/gen-context-index.cjs --write && npm run gen:section-manifest && node scripts/sync-manifest-versions.cjs && npm run gen:install-tree",
111
+ "regen:derived": "npm run build && npm run gen:registry && node scripts/gen-adr-index.cjs --write && node scripts/gen-features.cjs --write && node scripts/gen-capability-matrix.cjs --write && node scripts/gen-inventory-manifest.cjs --write && node scripts/gen-context-index.cjs --write && node scripts/gen-state-md-docs.cjs --write && npm run gen:section-manifest && node scripts/sync-manifest-versions.cjs && npm run gen:install-tree && node scripts/gen-scripts-cli-exit.cjs --write && node scripts/gen-hooks-cli-exit.cjs --write && node scripts/gen-exit-code-registry.cjs --write && node scripts/gen-exit-code-docs.cjs --write",
101
112
  "validate:registry": "node scripts/validate-registry.cjs",
102
113
  "prepack": "npm run build:lib",
103
114
  "prepare": "npm run build:lib",
@@ -105,10 +116,12 @@
105
116
  "prepublishOnly": "npm run build:lib && npm run build:hooks",
106
117
  "pretest": "npm run build:lib && npm run lint:skill-deps",
107
118
  "pretest:coverage": "npm run build:lib && npm run lint:skill-deps",
108
- "lint": "eslint . --cache --cache-location node_modules/.cache/eslint/",
119
+ "lint": "eslint . --cache --cache-location node_modules/.cache/eslint/ --max-warnings 0",
109
120
  "lint:fix": "eslint . --fix",
110
121
  "lint:table-schema-drift": "node scripts/lint-table-schema-drift.cjs",
111
- "lint:ci": "npm run lint && npm run lint:skill-deps && npm run lint:generated-sync && node scripts/lint-test-file-count.cjs && node scripts/lint-command-contract.cjs && node scripts/lint-pr-check-project-dir.cjs && npm run lint:legacy-name && node scripts/lint-regression-test-names.cjs && node scripts/lint-allow-test-rule-refs.cjs && node scripts/lint-resolution-provenance.cjs && node scripts/lint-emitted-drift-ack.cjs && node scripts/lint-portable-timeout.cjs && node scripts/validate-registry.cjs && node scripts/lint-table-schema-drift.cjs && node scripts/lint-fix-has-regression-test.cjs && node scripts/lint-example-parser-parity.cjs && node scripts/lint-docs-command-form.cjs",
122
+ "lint:frontmatter-scalar-broad-grep": "node scripts/lint-frontmatter-scalar-broad-grep.cjs",
123
+ "lint:removed-but-needed": "node scripts/lint-removed-but-needed.cjs",
124
+ "lint:ci": "npm run lint && npm run lint:skill-deps && npm run lint:generated-sync && node scripts/lint-test-file-count.cjs && node scripts/lint-command-contract.cjs && node scripts/lint-pr-check-project-dir.cjs && npm run lint:legacy-name && node scripts/lint-regression-test-names.cjs && node scripts/lint-allow-test-rule-refs.cjs && node scripts/lint-resolution-provenance.cjs && node scripts/lint-portable-timeout.cjs && node scripts/validate-registry.cjs && node scripts/lint-table-schema-drift.cjs && node scripts/lint-fix-has-regression-tests.cjs && node scripts/lint-example-parser-parity.cjs && node scripts/lint-docs-command-form.cjs && node scripts/lint-plan-count-drift.cjs && node scripts/lint-milestone-window-drift.cjs && node scripts/lint-phase-enumeration-drift.cjs && node scripts/lint-planning-prompt-drift.cjs && node scripts/lint-unreachable-guard-drift.cjs && node scripts/lint-completion-ratio-drift.cjs && node scripts/lint-slug-derivation-drift.cjs && node scripts/lint-state-field-drift.cjs && node scripts/lint-state-write-path-drift.cjs && node scripts/lint-completion-predicate-drift.cjs && node scripts/lint-planning-snapshot-bypass-drift.cjs && node scripts/lint-health-diagnostic-rule-table.cjs && node scripts/lint-planning-artifact-writer-drift.cjs && node scripts/lint-frontmatter-scalar-broad-grep.cjs && node scripts/lint-removed-but-needed.cjs && node scripts/lint-no-adhoc-regex-escape.cjs && node scripts/lint-vendored-deps.cjs && node scripts/lint-docs-guard-registration.cjs && node scripts/lint-source-test-name-collision.cjs && npm run lint:hooks-runtime-build-seam && node scripts/check-contract-drift.cjs && node scripts/lint-mutation-test-derivation-drift.cjs && node scripts/lint-seam-enforcement.cjs",
112
125
  "lint:allow-test-rule-refs": "node scripts/lint-allow-test-rule-refs.cjs",
113
126
  "lint:regression-names": "node scripts/lint-regression-test-names.cjs",
114
127
  "lint:descriptions": "node scripts/lint-descriptions.cjs",
@@ -116,11 +129,13 @@
116
129
  "lint:test-file-count": "node scripts/lint-test-file-count.cjs",
117
130
  "lint:pr-checks": "node scripts/lint-pr-check-project-dir.cjs",
118
131
  "lint:changeset": "node scripts/changeset/lint.cjs",
119
- "lint:generated-sync": "node scripts/gen-capability-registry.cjs --check && node scripts/gen-loop-host-contract.cjs --check && node scripts/gen-capability-matrix.cjs --check && node scripts/sync-manifest-versions.cjs --check && node scripts/gen-inventory-manifest.cjs --check && node scripts/generate-package-identity.cjs --check && node scripts/gen-plugin-skills.cjs --check && node scripts/gen-registry.cjs --check && node scripts/gen-adr-index.cjs --check && node scripts/check-glossary-refs.cjs --check && node scripts/lint-compiled-artifact-sync.cjs --check && node scripts/gen-context-index.cjs --check && node scripts/gen-section-manifest.cjs --check",
132
+ "lint:generated-sync": "node scripts/gen-capability-registry.cjs --check && node scripts/gen-loop-host-contract.cjs --check && node scripts/gen-capability-matrix.cjs --check && node scripts/sync-manifest-versions.cjs --check && node scripts/gen-inventory-manifest.cjs --check && node scripts/generate-package-identity.cjs --check && node scripts/gen-plugin-skills.cjs --check && node scripts/gen-registry.cjs --check && node scripts/gen-adr-index.cjs --check && node scripts/gen-features.cjs --check && node scripts/check-glossary-refs.cjs --check && node scripts/lint-compiled-artifact-sync.cjs --check && node scripts/gen-context-index.cjs --check && node scripts/gen-section-manifest.cjs --check && node scripts/gen-health-docs.cjs --check && node scripts/gen-state-md-docs.cjs --check && node scripts/gen-scripts-cli-exit.cjs --check && node scripts/gen-hooks-cli-exit.cjs --check && node scripts/gen-exit-code-registry.cjs --check && node scripts/gen-exit-code-docs.cjs --check",
120
133
  "lint:docs": "node scripts/lint-docs-required.cjs",
121
134
  "lint:qa-smells": "node scripts/qa-smell-ratchet.cjs",
122
135
  "lint:legacy-name": "node scripts/lint-legacy-dir-name.cjs",
136
+ "lint:seam-enforcement": "node scripts/lint-seam-enforcement.cjs",
123
137
  "lint:docs-command-form": "node scripts/lint-docs-command-form.cjs",
138
+ "lint:hooks-runtime-build-seam": "node scripts/lint-hooks-runtime-build-seam.cjs",
124
139
  "ci:test-scope": "node scripts/ci-test-scope.cjs",
125
140
  "changeset": "node scripts/changeset/new.cjs",
126
141
  "changelog:render": "node scripts/changeset/cli.cjs render",
@@ -132,14 +147,16 @@
132
147
  "test:slow": "node scripts/run-tests.cjs --suite slow",
133
148
  "test:qa": "node scripts/run-tests.cjs --suite qa",
134
149
  "test:affected": "node scripts/run-affected-tests.cjs",
135
- "test:coverage": "c8 --check-coverage --lines 70 --branches 60 --reporter text --include 'gsd-core/bin/lib/*.cjs' --exclude 'tests/**' --all node scripts/run-tests.cjs",
150
+ "test:coverage": "c8 --check-coverage --lines 70 --branches 60 --reporter text --include 'gsd-core/bin/lib/**/*.cjs' --exclude 'tests/**' --all node scripts/run-tests.cjs",
136
151
  "test:coverage:scripts-floor": "c8 check-coverage --lines 55 --include 'scripts/**/*.cjs' --exclude 'tests/**' --all",
137
- "test:coverage:unit": "c8 --reporter text --reporter json-summary --include 'gsd-core/bin/lib/*.cjs' --exclude 'tests/**' --all node scripts/run-tests.cjs --suite unit && node scripts/check-coverage-gate.cjs",
152
+ "test:coverage:unit": "c8 --reporter text --reporter json-summary --merge-async --include 'gsd-core/bin/lib/**/*.cjs' --exclude 'tests/**' --all node scripts/run-tests.cjs --suite unit && node scripts/check-coverage-gate.cjs",
138
153
  "test:coverage:unit:raw": "c8 --reporter none node scripts/run-tests.cjs --suite unit",
139
- "test:coverage:report": "c8 report --reporter text --reporter json-summary --include 'gsd-core/bin/lib/*.cjs' --exclude 'tests/**' --all && node scripts/check-coverage-gate.cjs",
154
+ "test:coverage:report": "c8 report --reporter text --reporter json-summary --merge-async --include 'gsd-core/bin/lib/**/*.cjs' --exclude 'tests/**' --all && node scripts/check-coverage-gate.cjs",
140
155
  "test:coverage:all": "npm run test:coverage",
141
156
  "test:mutation": "stryker run",
142
- "test:mutation:since": "stryker run --incremental --since origin/next"
157
+ "test:mutation:since": "stryker run --incremental --since origin/next",
158
+ "gen:features": "node scripts/gen-features.cjs",
159
+ "gen:state-md-docs": "node scripts/gen-state-md-docs.cjs"
143
160
  },
144
161
  "allowScripts": {
145
162
  "fallow@2.70.0": true
package/pi/gsd.cjs CHANGED
@@ -320,21 +320,35 @@ module.exports = function gsdPiExtension(pi) {
320
320
  getArgumentCompletions,
321
321
  handler: async (args, ctx) => {
322
322
  const cwd = (ctx && ctx.cwd) || process.cwd();
323
+ // #3456: Pi's command dispatcher awaits the handler and DISCARDS its
324
+ // return value (agent-session.ts: `await command.handler(args, ctx);
325
+ // return true;`) — #3097's `{ content: [...] }` return was silently
326
+ // dropped exactly like the pre-#3097 bare string. The ONLY command-
327
+ // output mechanism Pi consumes is `ctx.ui.notify(message, type)`
328
+ // (pi docs: extensions.md#piregistercommandname-options), so the output
329
+ // is pushed as a side effect on both the success and error paths.
330
+ // Guarded so a host ctx without `ui` degrades silently instead of
331
+ // crashing the command.
332
+ const notify = (ctx && ctx.ui && typeof ctx.ui.notify === 'function')
333
+ ? (message, type) => ctx.ui.notify(message, type)
334
+ : null;
323
335
  const { family, subcommand, args: rest } = parseGsdCommandArgs(args);
324
336
  let dispatchGsdCommand;
325
337
  try {
326
338
  ({ dispatchGsdCommand } = require(path.join(GSD_CORE, 'bin', 'lib', 'shell-command-projection.cjs')));
327
339
  } catch (e) {
328
- // #2991: return the structured { content } shape Pi's ExtensionAPI
329
- // displays, not a bare string (which Pi silently drops).
330
- return { content: [{ type: 'text', text: `GSD engine unavailable: ${e && e.message ? e.message : String(e)}` }] };
340
+ if (notify) {
341
+ notify(`GSD engine unavailable: ${e && e.message ? e.message : String(e)}`, 'error');
342
+ }
343
+ return;
331
344
  }
332
345
  const result = dispatchGsdCommand({ family, subcommand, args: rest, cwd });
333
- // #2991: match gsd_invoke's proven output shape so Pi actually displays it.
334
346
  const text = result.ok
335
347
  ? result.stdout
336
348
  : `GSD error: ${result.stderr || result.stdout || `dispatch failed (exit ${result.code})`}`;
337
- return { content: [{ type: 'text', text }] };
349
+ if (notify) {
350
+ notify(text, result.ok ? 'info' : 'error');
351
+ }
338
352
  },
339
353
  });
340
354