@opengsd/gsd-core 1.11.0 → 1.13.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 (498) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/.opencode/plugins/gsd-core.js +12 -0
  4. package/agents/gsd-code-fixer.md +1 -1
  5. package/agents/gsd-debug-session-manager.md +1 -1
  6. package/agents/gsd-debugger.md +1 -1
  7. package/agents/gsd-dom-verifier.md +169 -0
  8. package/agents/gsd-eval-auditor.md +1 -1
  9. package/agents/gsd-executor.md +78 -42
  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 +0 -1
  13. package/agents/gsd-pattern-mapper.md +11 -0
  14. package/agents/gsd-phase-researcher.md +3 -1
  15. package/agents/gsd-plan-checker.md +91 -112
  16. package/agents/gsd-planner.md +20 -4
  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 +82 -7
  21. package/agents/gsd-ui-researcher.md +70 -3
  22. package/agents/gsd-verifier.md +24 -2
  23. package/bin/install.js +847 -200
  24. package/commands/gsd/discuss-phase.md +1 -1
  25. package/commands/gsd/execute-phase.md +1 -1
  26. package/commands/gsd/import.md +1 -1
  27. package/commands/gsd/ns-workflow.md +2 -1
  28. package/commands/gsd/phase.md +1 -1
  29. package/commands/gsd/quick-batch.md +105 -0
  30. package/commands/gsd/quick.md +8 -4
  31. package/commands/gsd/surface.md +18 -8
  32. package/gsd-core/bin/gsd-tools.cjs +761 -100
  33. package/gsd-core/bin/lib/active-workstream-store.cjs +8 -0
  34. package/gsd-core/bin/lib/adr-parser.cjs +13 -7
  35. package/gsd-core/bin/lib/agent-install-check.cjs +162 -0
  36. package/gsd-core/bin/lib/api-coverage.cjs +30 -9
  37. package/gsd-core/bin/lib/artifacts.cjs +2 -0
  38. package/gsd-core/bin/lib/assumption-delta.cjs +30 -11
  39. package/gsd-core/bin/lib/audit.cjs +163 -41
  40. package/gsd-core/bin/lib/broken-windows.cjs +306 -28
  41. package/gsd-core/bin/lib/capability-activation.cjs +27 -0
  42. package/gsd-core/bin/lib/capability-lock.cjs +10 -4
  43. package/gsd-core/bin/lib/capability-registry.cjs +785 -144
  44. package/gsd-core/bin/lib/capability-state.cjs +25 -4
  45. package/gsd-core/bin/lib/capability-validator.cjs +321 -18
  46. package/gsd-core/bin/lib/capability-writer.cjs +14 -4
  47. package/gsd-core/bin/lib/check-command-router.cjs +229 -6
  48. package/gsd-core/bin/lib/claude-orchestration.cjs +10 -25
  49. package/gsd-core/bin/lib/cli-exit.cjs +496 -10
  50. package/gsd-core/bin/lib/clusters.cjs +1 -0
  51. package/gsd-core/bin/lib/code-review-depth.cjs +288 -0
  52. package/gsd-core/bin/lib/codex-agent-toml.cjs +410 -4
  53. package/gsd-core/bin/lib/command-aliases.cjs +16 -0
  54. package/gsd-core/bin/lib/command-arg-projection.cjs +144 -14
  55. package/gsd-core/bin/lib/command-routing-hub.cjs +31 -2
  56. package/gsd-core/bin/lib/commands.cjs +877 -54
  57. package/gsd-core/bin/lib/complexity-trigger.cjs +26 -6
  58. package/gsd-core/bin/lib/config-loader.cjs +121 -29
  59. package/gsd-core/bin/lib/config.cjs +92 -2
  60. package/gsd-core/bin/lib/configuration.cjs +129 -37
  61. package/gsd-core/bin/lib/core-utils.cjs +118 -14
  62. package/gsd-core/bin/lib/decisions.cjs +213 -1
  63. package/gsd-core/bin/lib/edge-probe.cjs +23 -2
  64. package/gsd-core/bin/lib/estimate-cli.cjs +55 -11
  65. package/gsd-core/bin/lib/exit-code-registry.cjs +98 -0
  66. package/gsd-core/bin/lib/file-overlap-partitioner.cjs +74 -0
  67. package/gsd-core/bin/lib/frontmatter.cjs +975 -326
  68. package/gsd-core/bin/lib/gap-checker.cjs +41 -8
  69. package/gsd-core/bin/lib/git-base-branch.cjs +182 -39
  70. package/gsd-core/bin/lib/health-diagnostic-rules/consistency.cjs +7 -3
  71. package/gsd-core/bin/lib/health-diagnostic-rules/phase-structure.cjs +8 -2
  72. package/gsd-core/bin/lib/health-diagnostic-rules/roadmap-disk-consistency.cjs +60 -14
  73. package/gsd-core/bin/lib/health-diagnostic-rules/state-consistency.cjs +75 -22
  74. package/gsd-core/bin/lib/health-diagnostic-rules/worktree-health.cjs +22 -8
  75. package/gsd-core/bin/lib/health-diagnostic.cjs +23 -3
  76. package/gsd-core/bin/lib/host-integration.cjs +96 -11
  77. package/gsd-core/bin/lib/init-command-router.cjs +132 -21
  78. package/gsd-core/bin/lib/init.cjs +252 -56
  79. package/gsd-core/bin/lib/install-engine.cjs +252 -15
  80. package/gsd-core/bin/lib/install-model-override-resolver.cjs +78 -1
  81. package/gsd-core/bin/lib/install-profiles.cjs +100 -18
  82. package/gsd-core/bin/lib/installer-migration-report.cjs +4 -0
  83. package/gsd-core/bin/lib/installer-migrations/010-antigravity-retire-confighome-artifacts.cjs +169 -0
  84. package/gsd-core/bin/lib/installer-migrations.cjs +10 -7
  85. package/gsd-core/bin/lib/intel.cjs +101 -26
  86. package/gsd-core/bin/lib/io.cjs +195 -15
  87. package/gsd-core/bin/lib/learnings.cjs +85 -14
  88. package/gsd-core/bin/lib/legacy-cleanup.cjs +8 -2
  89. package/gsd-core/bin/lib/loop-resolver.cjs +14 -8
  90. package/gsd-core/bin/lib/markdown-table.cjs +175 -4
  91. package/gsd-core/bin/lib/milestone.cjs +112 -7
  92. package/gsd-core/bin/lib/model-catalog.cjs +177 -19
  93. package/gsd-core/bin/lib/model-resolver.cjs +10 -28
  94. package/gsd-core/bin/lib/onboard-projection.cjs +5 -1
  95. package/gsd-core/bin/lib/phase-command-router.cjs +13 -6
  96. package/gsd-core/bin/lib/phase-estimation.cjs +17 -8
  97. package/gsd-core/bin/lib/phase-id.cjs +321 -13
  98. package/gsd-core/bin/lib/phase-lifecycle.cjs +24 -16
  99. package/gsd-core/bin/lib/phase-locator.cjs +138 -17
  100. package/gsd-core/bin/lib/phase.cjs +1175 -115
  101. package/gsd-core/bin/lib/plan-document.cjs +273 -0
  102. package/gsd-core/bin/lib/plan-scan.cjs +13 -2
  103. package/gsd-core/bin/lib/planning-command-router.cjs +61 -0
  104. package/gsd-core/bin/lib/planning-inspect.cjs +1168 -0
  105. package/gsd-core/bin/lib/planning-snapshot.cjs +165 -34
  106. package/gsd-core/bin/lib/planning-workspace.cjs +159 -28
  107. package/gsd-core/bin/lib/probe-core.cjs +4 -1
  108. package/gsd-core/bin/lib/profile-pipeline-command-router.cjs +50 -7
  109. package/gsd-core/bin/lib/profile-pipeline.cjs +6 -3
  110. package/gsd-core/bin/lib/quick-batch-command-router.cjs +285 -0
  111. package/gsd-core/bin/lib/quick-batch-dispatch.cjs +250 -0
  112. package/gsd-core/bin/lib/quick-batch.cjs +840 -0
  113. package/gsd-core/bin/lib/real-home-guard.cjs +419 -0
  114. package/gsd-core/bin/lib/refactor-trigger-command-router.cjs +71 -45
  115. package/gsd-core/bin/lib/review-lane-descriptor.cjs +62 -14
  116. package/gsd-core/bin/lib/review-lane-invocation.cjs +73 -1
  117. package/gsd-core/bin/lib/review-lane-runner.cjs +136 -10
  118. package/gsd-core/bin/lib/roadmap-command-router.cjs +45 -31
  119. package/gsd-core/bin/lib/roadmap-parser.cjs +577 -41
  120. package/gsd-core/bin/lib/roadmap.cjs +248 -64
  121. package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +329 -41
  122. package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +16 -17
  123. package/gsd-core/bin/lib/runtime-artifact-layout.cjs +320 -109
  124. package/gsd-core/bin/lib/runtime-hooks-surface.cjs +487 -83
  125. package/gsd-core/bin/lib/runtime-identity.cjs +234 -0
  126. package/gsd-core/bin/lib/runtime-slash.cjs +72 -2
  127. package/gsd-core/bin/lib/shell-command-projection.cjs +75 -8
  128. package/gsd-core/bin/lib/smart-entry.cjs +19 -31
  129. package/gsd-core/bin/lib/spec-section.cjs +12 -7
  130. package/gsd-core/bin/lib/state-command-router.cjs +47 -18
  131. package/gsd-core/bin/lib/state-contract.cjs +359 -0
  132. package/gsd-core/bin/lib/state-document.cjs +216 -5
  133. package/gsd-core/bin/lib/state-md-schema.cjs +231 -0
  134. package/gsd-core/bin/lib/state-transition.cjs +850 -145
  135. package/gsd-core/bin/lib/state.cjs +1629 -287
  136. package/gsd-core/bin/lib/surface.cjs +33 -10
  137. package/gsd-core/bin/lib/task-command-router.cjs +111 -1
  138. package/gsd-core/bin/lib/task-content-resolution.cjs +368 -0
  139. package/gsd-core/bin/lib/tdd-red-evidence.cjs +133 -0
  140. package/gsd-core/bin/lib/teams-status.cjs +4 -1
  141. package/gsd-core/bin/lib/uat-predicate.cjs +58 -20
  142. package/gsd-core/bin/lib/uat.cjs +2542 -387
  143. package/gsd-core/bin/lib/ui-consideration-probe.cjs +9 -1
  144. package/gsd-core/bin/lib/ui-safety-gate.cjs +37 -7
  145. package/gsd-core/bin/lib/unusable-input.cjs +13 -0
  146. package/gsd-core/bin/lib/update-context.cjs +6 -2
  147. package/gsd-core/bin/lib/validate-command-router.cjs +2 -2
  148. package/gsd-core/bin/lib/validate.cjs +230 -12
  149. package/gsd-core/bin/lib/vendor/README.md +43 -5
  150. package/gsd-core/bin/lib/vendor/js-yaml.cjs +3014 -0
  151. package/gsd-core/bin/lib/verification-command-router.cjs +2 -1
  152. package/gsd-core/bin/lib/verification.cjs +287 -13
  153. package/gsd-core/bin/lib/verify-command-grounding.cjs +846 -0
  154. package/gsd-core/bin/lib/verify-command-router.cjs +1 -0
  155. package/gsd-core/bin/lib/verify.cjs +441 -56
  156. package/gsd-core/bin/lib/workstream-inventory.cjs +20 -2
  157. package/gsd-core/bin/lib/workstream-name-policy.cjs +25 -4
  158. package/gsd-core/bin/lib/worktree-base-ref.cjs +66 -12
  159. package/gsd-core/bin/lib/worktree-safety.cjs +185 -21
  160. package/gsd-core/bin/shared/config-defaults.manifest.json +7 -1
  161. package/gsd-core/bin/shared/config-schema.manifest.json +13 -0
  162. package/gsd-core/bin/shared/exit-codes.json +8 -0
  163. package/gsd-core/bin/shared/exit-codes.sh +20 -0
  164. package/gsd-core/bin/shared/model-catalog.json +8 -1
  165. package/gsd-core/bin/verify-reapply-patches.cjs +70 -3
  166. package/gsd-core/references/agent-contracts.md +6 -5
  167. package/gsd-core/references/api-coverage.md +24 -2
  168. package/gsd-core/references/autonomous-smart-discuss.md +3 -3
  169. package/gsd-core/references/checkpoints.md +37 -19
  170. package/gsd-core/references/decimal-phase-calculation.md +5 -5
  171. package/gsd-core/references/edge-probe.md +17 -5
  172. package/gsd-core/references/execute-mvp-tdd.md +18 -18
  173. package/gsd-core/references/execute-phase-between-wave-reset.md +9 -12
  174. package/gsd-core/references/execute-phase-response-language.md +6 -0
  175. package/gsd-core/references/execute-phase-wave-guard.md +11 -9
  176. package/gsd-core/references/executor-examples.md +42 -0
  177. package/gsd-core/references/failing-direction.md +78 -0
  178. package/gsd-core/references/few-shot-examples/plan-checker.md +15 -15
  179. package/gsd-core/references/gate-prompts.md +1 -1
  180. package/gsd-core/references/git-integration.md +5 -5
  181. package/gsd-core/references/git-planning-commit.md +3 -3
  182. package/gsd-core/references/gsd-run-resolver.md +1 -1
  183. package/gsd-core/references/loop-hook-dispatch.md +22 -0
  184. package/gsd-core/references/model-profiles.md +1 -1
  185. package/gsd-core/references/mvp-concepts.md +2 -2
  186. package/gsd-core/references/nyquist-compliance.md +74 -0
  187. package/gsd-core/references/offer-next.md +3 -5
  188. package/gsd-core/references/phase-argument-parsing.md +3 -3
  189. package/gsd-core/references/plan-checker-examples.md +41 -0
  190. package/gsd-core/references/planner-antipatterns.md +25 -0
  191. package/gsd-core/references/planner-chunked.md +5 -1
  192. package/gsd-core/references/planner-coupling.md +42 -0
  193. package/gsd-core/references/planner-failing-direction.md +53 -0
  194. package/gsd-core/references/planner-human-verify-mode.md +15 -1
  195. package/gsd-core/references/planner-quick-batch.md +71 -0
  196. package/gsd-core/references/planner-reviews.md +47 -0
  197. package/gsd-core/references/planner-revision.md +76 -3
  198. package/gsd-core/references/planner-verify-command-grounding.md +17 -0
  199. package/gsd-core/references/planning-config.md +39 -9
  200. package/gsd-core/references/response-language-directive.md +9 -0
  201. package/gsd-core/references/reviewer-instances.md +31 -0
  202. package/gsd-core/references/revision-loop.md +118 -11
  203. package/gsd-core/references/runtime-aware-dispatch.md +1 -1
  204. package/gsd-core/references/tdd.md +15 -12
  205. package/gsd-core/references/ui-brand.md +65 -21
  206. package/gsd-core/references/ui-consideration-probe.md +1 -1
  207. package/gsd-core/references/universal-anti-patterns.md +2 -2
  208. package/gsd-core/references/verifier-evidence-gate.md +160 -0
  209. package/gsd-core/references/verify-command-path-resolvability.md +42 -0
  210. package/gsd-core/references/verify-mvp-mode.md +1 -1
  211. package/gsd-core/references/workstream-flag.md +11 -11
  212. package/gsd-core/templates/README.md +1 -1
  213. package/gsd-core/templates/SECURITY.md +3 -3
  214. package/gsd-core/templates/UI-SPEC.md +25 -3
  215. package/gsd-core/templates/VALIDATION.md +3 -3
  216. package/gsd-core/templates/phase-prompt.md +7 -0
  217. package/gsd-core/templates/state.md +7 -0
  218. package/gsd-core/templates/verification-report.md +5 -0
  219. package/gsd-core/workflows/_runtime-launcher.snippet.sh +1 -1
  220. package/gsd-core/workflows/add-backlog.md +3 -1
  221. package/gsd-core/workflows/add-phase.md +5 -3
  222. package/gsd-core/workflows/add-tests.md +4 -9
  223. package/gsd-core/workflows/add-todo.md +2 -2
  224. package/gsd-core/workflows/ai-integration-phase.md +5 -10
  225. package/gsd-core/workflows/analyze-dependencies.md +2 -0
  226. package/gsd-core/workflows/audit-fix.md +14 -3
  227. package/gsd-core/workflows/audit-milestone.md +11 -9
  228. package/gsd-core/workflows/audit-uat.md +19 -2
  229. package/gsd-core/workflows/autonomous/steps/converge-fail-fast.md +2 -2
  230. package/gsd-core/workflows/autonomous.md +12 -26
  231. package/gsd-core/workflows/check-todos.md +2 -2
  232. package/gsd-core/workflows/cleanup.md +3 -3
  233. package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +16 -14
  234. package/gsd-core/workflows/code-review-fix.md +3 -1
  235. package/gsd-core/workflows/code-review.md +192 -69
  236. package/gsd-core/workflows/complete-milestone.md +28 -14
  237. package/gsd-core/workflows/debug.md +6 -4
  238. package/gsd-core/workflows/diagnose-issues.md +17 -7
  239. package/gsd-core/workflows/discuss-phase/modes/advisor.md +3 -1
  240. package/gsd-core/workflows/discuss-phase/modes/all.md +2 -0
  241. package/gsd-core/workflows/discuss-phase/modes/analyze.md +2 -0
  242. package/gsd-core/workflows/discuss-phase/modes/auto.md +2 -0
  243. package/gsd-core/workflows/discuss-phase/modes/batch.md +2 -0
  244. package/gsd-core/workflows/discuss-phase/modes/chain.md +5 -7
  245. package/gsd-core/workflows/discuss-phase/modes/default.md +2 -0
  246. package/gsd-core/workflows/discuss-phase/modes/power.md +2 -0
  247. package/gsd-core/workflows/discuss-phase/modes/text.md +3 -1
  248. package/gsd-core/workflows/discuss-phase/templates/context.md +2 -0
  249. package/gsd-core/workflows/discuss-phase/templates/discussion-log.md +2 -0
  250. package/gsd-core/workflows/discuss-phase-assumptions/steps/auto-advance-dispatch.md +1 -3
  251. package/gsd-core/workflows/discuss-phase-assumptions.md +3 -3
  252. package/gsd-core/workflows/discuss-phase-power.md +2 -0
  253. package/gsd-core/workflows/discuss-phase.md +2 -2
  254. package/gsd-core/workflows/do.md +46 -19
  255. package/gsd-core/workflows/docs-update.md +6 -5
  256. package/gsd-core/workflows/edit-phase.md +3 -1
  257. package/gsd-core/workflows/eval-review.md +5 -10
  258. package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +3 -1
  259. package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +129 -11
  260. package/gsd-core/workflows/execute-phase/steps/gap-closure-artifacts.md +1 -1
  261. package/gsd-core/workflows/execute-phase/steps/partial-wave.md +1 -1
  262. package/gsd-core/workflows/execute-phase/steps/per-plan-executor-routing.md +1 -1
  263. package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +29 -5
  264. package/gsd-core/workflows/execute-phase/steps/post-merge-gate.md +2 -2
  265. package/gsd-core/workflows/execute-phase/steps/protected-branch.md +21 -0
  266. package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +4 -2
  267. package/gsd-core/workflows/execute-phase/steps/tdd-applicability-resolution.md +25 -0
  268. package/gsd-core/workflows/execute-phase/steps/wave-post-gate-hooks.md +39 -0
  269. package/gsd-core/workflows/execute-phase/steps/worktree-recovery-policy.md +2 -0
  270. package/gsd-core/workflows/execute-phase.md +68 -66
  271. package/gsd-core/workflows/execute-plan.md +25 -20
  272. package/gsd-core/workflows/explore.md +3 -1
  273. package/gsd-core/workflows/extract-learnings.md +3 -1
  274. package/gsd-core/workflows/fast.md +8 -2
  275. package/gsd-core/workflows/forensics.md +3 -1
  276. package/gsd-core/workflows/graduation.md +6 -6
  277. package/gsd-core/workflows/health.md +4 -7
  278. package/gsd-core/workflows/help/modes/brief.md +2 -0
  279. package/gsd-core/workflows/help/modes/default.md +2 -0
  280. package/gsd-core/workflows/help/modes/full.md +12 -0
  281. package/gsd-core/workflows/help/modes/topic.md +2 -0
  282. package/gsd-core/workflows/help.md +2 -0
  283. package/gsd-core/workflows/import.md +17 -14
  284. package/gsd-core/workflows/inbox.md +5 -6
  285. package/gsd-core/workflows/ingest-docs.md +45 -12
  286. package/gsd-core/workflows/insert-phase.md +7 -5
  287. package/gsd-core/workflows/list-phase-assumptions.md +2 -0
  288. package/gsd-core/workflows/list-seeds.md +7 -3
  289. package/gsd-core/workflows/list-workspaces.md +3 -1
  290. package/gsd-core/workflows/manager.md +15 -26
  291. package/gsd-core/workflows/map-codebase.md +3 -1
  292. package/gsd-core/workflows/milestone-summary.md +3 -1
  293. package/gsd-core/workflows/mvp-phase.md +3 -3
  294. package/gsd-core/workflows/new-milestone.md +10 -22
  295. package/gsd-core/workflows/new-project/steps/auto-mode-config.md +1 -1
  296. package/gsd-core/workflows/new-project.md +17 -29
  297. package/gsd-core/workflows/new-workspace.md +2 -2
  298. package/gsd-core/workflows/next.md +4 -2
  299. package/gsd-core/workflows/node-repair.md +2 -0
  300. package/gsd-core/workflows/note.md +2 -0
  301. package/gsd-core/workflows/onboard.md +1 -1
  302. package/gsd-core/workflows/pause-work.md +20 -5
  303. package/gsd-core/workflows/plan-phase/steps/adr-ingest-express-path.md +1 -1
  304. package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +100 -18
  305. package/gsd-core/workflows/plan-phase/steps/prd-express-path.md +4 -4
  306. package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +12 -3
  307. package/gsd-core/workflows/plan-phase.md +251 -54
  308. package/gsd-core/workflows/plan-review-convergence.md +148 -19
  309. package/gsd-core/workflows/plant-seed.md +3 -3
  310. package/gsd-core/workflows/pr-branch.md +195 -51
  311. package/gsd-core/workflows/profile-user.md +17 -15
  312. package/gsd-core/workflows/progress/steps/forensic-audit.md +1 -1
  313. package/gsd-core/workflows/progress.md +52 -15
  314. package/gsd-core/workflows/quick/steps/discussion-phase.md +1 -3
  315. package/gsd-core/workflows/quick/steps/plan-checker-loop.md +38 -5
  316. package/gsd-core/workflows/quick/steps/quick-verification.md +2 -4
  317. package/gsd-core/workflows/quick/steps/research-phase.md +5 -7
  318. package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +3 -3
  319. package/gsd-core/workflows/quick-batch/steps/batch-init.md +55 -0
  320. package/gsd-core/workflows/quick-batch/steps/completion.md +65 -0
  321. package/gsd-core/workflows/quick-batch/steps/merge-wave.md +100 -0
  322. package/gsd-core/workflows/quick-batch/steps/plan-checker-loop.md +147 -0
  323. package/gsd-core/workflows/quick-batch/steps/planner-wave.md +158 -0
  324. package/gsd-core/workflows/quick-batch/steps/research-phase.md +95 -0
  325. package/gsd-core/workflows/quick-batch/steps/resume-mode.md +49 -0
  326. package/gsd-core/workflows/quick-batch/steps/verification-wave.md +73 -0
  327. package/gsd-core/workflows/quick-batch/steps/worktree-dispatch.md +169 -0
  328. package/gsd-core/workflows/quick-batch.md +203 -0
  329. package/gsd-core/workflows/quick.md +33 -32
  330. package/gsd-core/workflows/reapply-patches.md +2 -0
  331. package/gsd-core/workflows/remove-phase.md +6 -4
  332. package/gsd-core/workflows/remove-workspace.md +3 -3
  333. package/gsd-core/workflows/resume-project.md +14 -14
  334. package/gsd-core/workflows/review.md +404 -21
  335. package/gsd-core/workflows/scan.md +3 -1
  336. package/gsd-core/workflows/section-manifest.json +12 -0
  337. package/gsd-core/workflows/secure-phase.md +3 -3
  338. package/gsd-core/workflows/session-report.md +2 -0
  339. package/gsd-core/workflows/settings-advanced.md +9 -9
  340. package/gsd-core/workflows/settings-integrations.md +66 -32
  341. package/gsd-core/workflows/settings.md +4 -6
  342. package/gsd-core/workflows/ship.md +22 -16
  343. package/gsd-core/workflows/sketch-wrap-up.md +13 -17
  344. package/gsd-core/workflows/sketch.md +13 -19
  345. package/gsd-core/workflows/smart-entry.md +4 -6
  346. package/gsd-core/workflows/spec-phase.md +31 -4
  347. package/gsd-core/workflows/spike-wrap-up.md +9 -11
  348. package/gsd-core/workflows/spike.md +21 -32
  349. package/gsd-core/workflows/stats.md +4 -2
  350. package/gsd-core/workflows/sync-skills.md +13 -5
  351. package/gsd-core/workflows/thread.md +13 -7
  352. package/gsd-core/workflows/transition.md +7 -5
  353. package/gsd-core/workflows/ui-phase.md +36 -21
  354. package/gsd-core/workflows/ui-review.md +7 -11
  355. package/gsd-core/workflows/ultraplan-phase.md +7 -13
  356. package/gsd-core/workflows/undo.md +9 -17
  357. package/gsd-core/workflows/update.md +47 -48
  358. package/gsd-core/workflows/validate-phase.md +3 -3
  359. package/gsd-core/workflows/verify-work/steps/automated-ui-verification.md +25 -1
  360. package/gsd-core/workflows/verify-work/steps/mvp-uat-framing.md +1 -1
  361. package/gsd-core/workflows/verify-work.md +106 -21
  362. package/hooks/dist/gsd-agent-isolation-guard.js +77 -38
  363. package/hooks/dist/gsd-check-update-worker.js +19 -2
  364. package/hooks/dist/gsd-config-reload.js +18 -12
  365. package/hooks/dist/gsd-context-monitor.js +302 -22
  366. package/hooks/dist/gsd-cursor-post-tool.js +3 -1
  367. package/hooks/dist/gsd-cursor-pre-tool.js +3 -1
  368. package/hooks/dist/gsd-cursor-session-start.js +2 -1
  369. package/hooks/dist/gsd-cursor-stop.js +2 -1
  370. package/hooks/dist/gsd-cursor-subagent-start.js +28 -23
  371. package/hooks/dist/gsd-cursor-subagent-stop.js +3 -1
  372. package/hooks/dist/gsd-ensure-canonical-path.js +2 -1
  373. package/hooks/dist/gsd-graphify-update.sh +22 -18
  374. package/hooks/dist/gsd-node-runner.sh +77 -0
  375. package/hooks/dist/gsd-phase-boundary.sh +1 -0
  376. package/hooks/dist/gsd-prompt-guard.js +46 -12
  377. package/hooks/dist/gsd-read-guard.js +18 -7
  378. package/hooks/dist/gsd-read-injection-scanner.js +22 -13
  379. package/hooks/dist/gsd-secret-read-guard.js +1079 -0
  380. package/hooks/dist/gsd-session-state.sh +1 -0
  381. package/hooks/dist/gsd-statusline.js +222 -29
  382. package/hooks/dist/gsd-validate-commit.sh +523 -12
  383. package/hooks/dist/gsd-windsurf-pre-command.js +16 -11
  384. package/hooks/dist/gsd-windsurf-pre-write.js +22 -13
  385. package/hooks/dist/gsd-workflow-guard.js +36 -17
  386. package/hooks/dist/gsd-worktree-path-guard.js +36 -21
  387. package/hooks/dist/gsd-write-guard.js +35 -25
  388. package/hooks/dist/lib/cli-exit.js +560 -0
  389. package/hooks/dist/lib/exit-code-registry.js +98 -0
  390. package/hooks/dist/lib/git-cmd.js +210 -1
  391. package/hooks/dist/lib/git-probe.js +84 -0
  392. package/hooks/dist/lib/hook-exit.js +81 -0
  393. package/hooks/dist/lib/injection-patterns.js +36 -6
  394. package/hooks/dist/managed-hooks-registry.cjs +4 -0
  395. package/hooks/gsd-agent-isolation-guard.js +77 -38
  396. package/hooks/gsd-check-update-worker.js +19 -2
  397. package/hooks/gsd-config-reload.js +18 -12
  398. package/hooks/gsd-context-monitor.js +302 -22
  399. package/hooks/gsd-cursor-post-tool.js +3 -1
  400. package/hooks/gsd-cursor-pre-tool.js +3 -1
  401. package/hooks/gsd-cursor-session-start.js +2 -1
  402. package/hooks/gsd-cursor-stop.js +2 -1
  403. package/hooks/gsd-cursor-subagent-start.js +28 -23
  404. package/hooks/gsd-cursor-subagent-stop.js +3 -1
  405. package/hooks/gsd-ensure-canonical-path.js +2 -1
  406. package/hooks/gsd-graphify-update.sh +22 -18
  407. package/hooks/gsd-node-runner.sh +77 -0
  408. package/hooks/gsd-phase-boundary.sh +1 -0
  409. package/hooks/gsd-prompt-guard.js +46 -12
  410. package/hooks/gsd-read-guard.js +18 -7
  411. package/hooks/gsd-read-injection-scanner.js +22 -13
  412. package/hooks/gsd-secret-read-guard.js +1079 -0
  413. package/hooks/gsd-session-state.sh +1 -0
  414. package/hooks/gsd-statusline.js +222 -29
  415. package/hooks/gsd-validate-commit.sh +523 -12
  416. package/hooks/gsd-windsurf-pre-command.js +16 -11
  417. package/hooks/gsd-windsurf-pre-write.js +22 -13
  418. package/hooks/gsd-workflow-guard.js +36 -17
  419. package/hooks/gsd-worktree-path-guard.js +36 -21
  420. package/hooks/gsd-write-guard.js +35 -25
  421. package/hooks/hooks.json +6 -0
  422. package/hooks/lib/cli-exit.js +560 -0
  423. package/hooks/lib/exit-code-registry.js +98 -0
  424. package/hooks/lib/git-cmd.js +210 -1
  425. package/hooks/lib/git-probe.js +84 -0
  426. package/hooks/lib/hook-exit.js +81 -0
  427. package/hooks/lib/injection-patterns.js +36 -6
  428. package/hooks/managed-hooks-registry.cjs +4 -0
  429. package/package.json +14 -9
  430. package/scripts/base64-scan.sh +74 -12
  431. package/scripts/build-hooks.js +12 -0
  432. package/scripts/check-glossary-refs.cjs +77 -15
  433. package/scripts/check-mutation-score-ratchet.cjs +156 -0
  434. package/scripts/ci-check-job-near-cap.cjs +49 -0
  435. package/scripts/ci-pr-mergeability.cjs +262 -0
  436. package/scripts/ci-test-scope.cjs +52 -12
  437. package/scripts/ci-timeout-report.cjs +230 -0
  438. package/scripts/docs-guard-registry.cjs +406 -0
  439. package/scripts/gen-capability-registry.cjs +8 -6
  440. package/scripts/gen-exit-code-docs.cjs +318 -0
  441. package/scripts/gen-exit-code-registry.cjs +891 -0
  442. package/scripts/gen-features.cjs +836 -0
  443. package/scripts/gen-hooks-cli-exit.cjs +239 -0
  444. package/scripts/gen-install-tree-fixtures.cjs +2 -2
  445. package/scripts/gen-loop-host-contract.cjs +189 -4
  446. package/scripts/gen-scripts-cli-exit.cjs +185 -0
  447. package/scripts/gen-state-md-docs.cjs +727 -0
  448. package/scripts/{test-failure-reasons.cjs → gsd-test-gate-reasons.cjs} +6 -0
  449. package/scripts/lib/ci-job-timing.cjs +72 -0
  450. package/scripts/lib/cli-exit.cjs +546 -44
  451. package/scripts/lib/drift-scan.cjs +32 -2
  452. package/scripts/lib/exit-code-registry.cjs +98 -0
  453. package/scripts/lib/ndjson-reporter.cjs +119 -0
  454. package/scripts/lib/shellcheck-fetch.cjs +247 -0
  455. package/scripts/lint-allow-test-rule-refs.allowlist.json +0 -6
  456. package/scripts/lint-allow-test-rule-refs.effective-ceiling.json +1 -1
  457. package/scripts/lint-allow-test-rule-refs.unverified-ceiling.json +1 -1
  458. package/scripts/lint-docs-guard-registration.cjs +495 -0
  459. package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +198 -0
  460. package/scripts/lint-eslint-glob-coverage.allowlist.json +4 -0
  461. package/scripts/{lint-fix-has-regression-test.cjs → lint-fix-has-regression-tests.cjs} +12 -6
  462. package/scripts/lint-health-diagnostic-rule-table.cjs +65 -8
  463. package/scripts/lint-mutation-test-derivation-drift.cjs +86 -0
  464. package/scripts/lint-phase-enumeration-drift.cjs +45 -14
  465. package/scripts/lint-phase-id-drift.cjs +133 -8
  466. package/scripts/lint-planning-prompt-drift.cjs +38 -1
  467. package/scripts/lint-portable-grep.cjs +176 -0
  468. package/scripts/lint-removed-but-needed.cjs +184 -16
  469. package/scripts/lint-response-language-coverage.cjs +524 -0
  470. package/scripts/lint-seam-enforcement.cjs +182 -0
  471. package/scripts/lint-slug-derivation-drift.cjs +921 -0
  472. package/scripts/lint-source-test-name-collision.cjs +241 -0
  473. package/scripts/lint-state-write-path-drift.cjs +337 -432
  474. package/scripts/lint-test-file-count.allowlist.json +124 -4
  475. package/scripts/lint-test-file-count.cjs +25 -3
  476. package/scripts/lint-unreachable-guard-drift.cjs +51 -64
  477. package/scripts/lint-vendored-deps.cjs +208 -35
  478. package/scripts/lint-workflow-shellcheck-baseline.json +1027 -0
  479. package/scripts/lint-workflow-shellcheck.cjs +614 -0
  480. package/scripts/mutation-matrix.cjs +599 -50
  481. package/scripts/npm-audit-baseline.cjs +376 -0
  482. package/scripts/prompt-injection-scan.sh +83 -14
  483. package/scripts/require-issue-link-policy.cjs +16 -1
  484. package/scripts/secret-scan.sh +75 -13
  485. package/scripts/select-docs-guards.cjs +56 -0
  486. package/scripts/sync-runtime-launcher.cjs +22 -3
  487. package/skills/gsd-discuss-phase/SKILL.md +1 -1
  488. package/skills/gsd-execute-phase/SKILL.md +1 -1
  489. package/skills/gsd-import/SKILL.md +1 -1
  490. package/skills/gsd-ns-workflow/SKILL.md +1 -0
  491. package/skills/gsd-phase/SKILL.md +1 -1
  492. package/skills/gsd-quick/SKILL.md +8 -4
  493. package/skills/gsd-quick-batch/SKILL.md +105 -0
  494. package/skills/gsd-surface/SKILL.md +18 -8
  495. package/vscode/package.json +1 -1
  496. package/bin/lib/ui-safety-gate.cjs +0 -109
  497. package/scripts/lint-emitted-drift-ack.cjs +0 -344
  498. package/scripts/state-write-path-drift-baseline.json +0 -19
@@ -61,17 +61,43 @@ const SKIP_DIR_NAMES = new Set(['node_modules', 'dist', '.git']);
61
61
  * previous regex silently MISSED every re-derivation using a
62
62
  * cross-platform path-separator class for exactly this reason.
63
63
  */
64
+ // Deterministic regression seam for the MAJOR-2 bound (issue #3951/#3987): a
65
+ // counter of how many characters this tokenizer has actually examined, so a
66
+ // test can assert the bound HOLDS (total work stays a small linear multiple
67
+ // of the number of scan attempts × MAX_REGEX_LITERAL_LEN) without resorting
68
+ // to a wall-clock elapsed-time assertion, which this repo's test rules ban
69
+ // ("Clock Seams: Do not assert on wall-clock time.") and which is exactly
70
+ // what flaked on a slow shared CI runner. `resetRegexScanStats`/
71
+ // `getRegexScanStats` are read-modify-reset around a single scan under test;
72
+ // they are process-global and NOT safe under concurrent scans, which is fine
73
+ // for this synchronous, single-threaded CLI tool and its tests.
74
+ let regexScanStats = { calls: 0, charsExamined: 0 };
75
+
76
+ function resetRegexScanStats() {
77
+ regexScanStats = { calls: 0, charsExamined: 0 };
78
+ }
79
+
80
+ function getRegexScanStats() {
81
+ return { ...regexScanStats };
82
+ }
83
+
64
84
  function readRegexLiteralAt(line, start) {
65
85
  if (line[start] !== '/') return null;
86
+ regexScanStats.calls++;
66
87
  const limit = Math.min(line.length, start + MAX_REGEX_LITERAL_LEN);
67
88
  let inClass = false;
68
- for (let i = start + 1; i < limit; i++) {
89
+ let i = start + 1;
90
+ for (; i < limit; i++) {
69
91
  const ch = line[i];
70
92
  if (ch === '\\') {
71
93
  i++; // escape consumes the next character, whatever it is
72
94
  continue;
73
95
  }
74
- if (ch === '\r' || ch === '\n') return null; // a literal cannot span lines
96
+ if (ch === '\r' || ch === '\n') {
97
+ // a literal cannot span lines
98
+ regexScanStats.charsExamined += i - start;
99
+ return null;
100
+ }
75
101
  if (ch === '[') {
76
102
  inClass = true;
77
103
  } else if (ch === ']') {
@@ -83,9 +109,11 @@ function readRegexLiteralAt(line, start) {
83
109
  // MAX_REGEX_LITERAL_LEN either.
84
110
  let end = i + 1;
85
111
  while (end < limit && line[end] >= 'a' && line[end] <= 'z') end++;
112
+ regexScanStats.charsExamined += end - start;
86
113
  return { text: line.slice(start, end), end };
87
114
  }
88
115
  }
116
+ regexScanStats.charsExamined += limit - start;
89
117
  return null;
90
118
  }
91
119
 
@@ -275,4 +303,6 @@ module.exports = {
275
303
  MAX_REGEX_LITERAL_LEN,
276
304
  sanitizeForReport,
277
305
  scanTree,
306
+ resetRegexScanStats,
307
+ getRegexScanStats,
278
308
  };
@@ -0,0 +1,98 @@
1
+ 'use strict';
2
+
3
+ // GENERATED FILE — DO NOT EDIT BY HAND.
4
+ // Source of truth: gsd-core/bin/shared/exit-codes.json. Regenerate with:
5
+ // node scripts/gen-exit-code-registry.cjs --write
6
+ // This exact content is emitted to THREE locations — gsd-core/bin/lib/exit-code-registry.cjs,
7
+ // scripts/lib/exit-code-registry.cjs, and hooks/lib/exit-code-registry.js (the latter two
8
+ // committed so scripts/ and hooks/ consumers work on an unbuilt clone) — all byte-compared by
9
+ // `npm run lint:generated-sync` (#3905 ADR-3889 Phase 1; #3906 Phase 2 added the second copy;
10
+ // #3911 ADR-3889 Phase 7 added the hooks/lib/ copy).
11
+ //
12
+ // exitCodeFor(name) / nameForExitCode(code) are pure and total over this
13
+ // closed table — each throws for anything not registered here.
14
+
15
+ const EXIT_CODES = Object.freeze([
16
+ Object.freeze({
17
+ code: 2,
18
+ name: "HOOK_DENY",
19
+ meaning: "Hook protocol deny — the harness blocks the tool call",
20
+ owner: "hook-adapter",
21
+ authorizedBy: "ADR-3889",
22
+ }),
23
+ Object.freeze({
24
+ code: 64,
25
+ name: "USAGE",
26
+ meaning: "Caller error — bad argv, unknown subcommand, missing argument",
27
+ owner: "generic",
28
+ authorizedBy: "ADR-3889",
29
+ }),
30
+ Object.freeze({
31
+ code: 66,
32
+ name: "NO_INPUT",
33
+ meaning: "Ran; zero units were in scope, and that emptiness is known to be genuine",
34
+ owner: "generic",
35
+ authorizedBy: "ADR-3889",
36
+ }),
37
+ Object.freeze({
38
+ code: 69,
39
+ name: "UNAVAILABLE",
40
+ meaning: "Could not run — prerequisite absent, input unreadable, scope unestablished",
41
+ owner: "generic",
42
+ authorizedBy: "ADR-3889",
43
+ }),
44
+ Object.freeze({
45
+ code: 70,
46
+ name: "INTERNAL",
47
+ meaning: "Self-failure — crash, timeout, killed subprocess",
48
+ owner: "generic",
49
+ authorizedBy: "ADR-3889",
50
+ }),
51
+ Object.freeze({
52
+ code: 80,
53
+ name: "DEGRADED",
54
+ meaning: "Ran to completion and is reporting a condition through its result payload rather than as a process failure",
55
+ owner: "gsd-tools",
56
+ authorizedBy: "ADR-3889 + ADR-2980",
57
+ })
58
+ ]);
59
+
60
+ const NAME_TO_CODE = new Map(EXIT_CODES.map((entry) => [entry.name, entry.code]));
61
+ const CODE_TO_NAME = new Map(EXIT_CODES.map((entry) => [entry.code, entry.name]));
62
+
63
+ /**
64
+ * Resolve the registered exit code for a symbolic name. Pure, total: throws
65
+ * for anything not an exact, registered, exact-case key — including
66
+ * non-strings, the empty string, untrimmed strings, wrong case, and
67
+ * prototype-chain names like `__proto__`/`constructor`/`toString` (a Map
68
+ * lookup never touches the prototype chain, so these are indistinguishable
69
+ * from any other unregistered name).
70
+ *
71
+ * @param {string} name
72
+ * @returns {number}
73
+ */
74
+ function exitCodeFor(name) {
75
+ if (typeof name !== 'string' || name.length === 0) {
76
+ throw new Error(`exitCodeFor: name must be a non-empty string, received ${JSON.stringify(name)}`);
77
+ }
78
+ if (!NAME_TO_CODE.has(name)) {
79
+ throw new Error(`exitCodeFor: unregistered exit code name: ${JSON.stringify(name)}`);
80
+ }
81
+ return NAME_TO_CODE.get(name);
82
+ }
83
+
84
+ /**
85
+ * Reverse of exitCodeFor: resolve the symbolic name for a registered exit
86
+ * code. Pure, total: throws for anything not an exact, registered code.
87
+ *
88
+ * @param {number} code
89
+ * @returns {string}
90
+ */
91
+ function nameForExitCode(code) {
92
+ if (!CODE_TO_NAME.has(code)) {
93
+ throw new Error(`nameForExitCode: unregistered exit code: ${JSON.stringify(code)}`);
94
+ }
95
+ return CODE_TO_NAME.get(code);
96
+ }
97
+
98
+ module.exports = { EXIT_CODES, exitCodeFor, nameForExitCode };
@@ -0,0 +1,119 @@
1
+ 'use strict';
2
+
3
+ // Machine-readable companion reporter for scripts/run-tests.cjs (#3889).
4
+ //
5
+ // node:test's built-in reporters (spec/tap) are human-formatted and
6
+ // scripts/run-tests.cjs spawns the child with `stdio: 'inherit'` — by design,
7
+ // per #3597/#1051, to avoid the maxBuffer and live-output risks of piping —
8
+ // so the parent process has no way to see WHICH file was executing when a
9
+ // per-chunk timeout kills the child. This reporter runs ALONGSIDE the normal
10
+ // human reporter (a second `--test-reporter` on the same invocation, per
11
+ // Node's documented multi-reporter pairing) and appends one JSON object per
12
+ // line to a path supplied via the GSD_RUN_TESTS_EVENTS_FILE env var. On a
13
+ // timeout, run-tests.cjs reads that file back to name the file(s) still
14
+ // in flight (a `test:dequeue` with no matching `test:pass`/`test:fail`).
15
+ //
16
+ // Durability, not `--test-reporter-destination` (#3889 root cause): a
17
+ // reporter that YIELDS strings has them piped by Node into a
18
+ // `fs.WriteStream` targeting the destination path, and that stream buffers.
19
+ // The parent's `execFileSync` timeout SIGKILLs the child on a hang, and
20
+ // SIGKILL is uncatchable and gives the process zero chance to flush — so a
21
+ // yield-based reporter can lose every event still sitting in the stream's
22
+ // buffer, which is exactly the case this feature exists to diagnose (proven
23
+ // live: a chunk killed at 2006ms produced a `killed after 2006ms` line from
24
+ // the TIMER, which lives in the parent, but zero usable events from the
25
+ // reporter, which lives in the child and never flushed). Writing each event
26
+ // with `fs.appendFileSync` — synchronous and unbuffered — makes it durable
27
+ // the instant it happens, before the process can be killed out from under
28
+ // it. The reporter therefore yields NOTHING; it is a pure side-effecting
29
+ // sink. Node still requires a `--test-reporter-destination` to pair with
30
+ // this `--test-reporter` (see run-tests.cjs's reporterArgsFor), but that
31
+ // destination is a throwaway sink that stays empty by design — the durable
32
+ // path is GSD_RUN_TESTS_EVENTS_FILE, not the destination Node manages.
33
+ //
34
+ // Contract targeted: Node's "Custom reporters" contract
35
+ // (https://nodejs.org/api/test.html#custom-reporters) — a reporter module's
36
+ // default export is a function receiving the test runner's event stream (an
37
+ // AsyncIterable of `{ type, data }` objects). Node feeds that function to
38
+ // `stream.compose` as the stream's "body". When the body is an async
39
+ // FUNCTION (not an `async function*` generator), `stream.compose`'s own
40
+ // contract (https://nodejs.org/api/stream.html#streamcomposestreams)
41
+ // requires it to return nully (undefined/null) — returning anything else,
42
+ // including an array, throws `ERR_INVALID_RETURN_VALUE` ("Expected nully to
43
+ // be returned from the 'body' function but got an instance of Array")
44
+ // exactly once the promise resolves. Verified directly against
45
+ // `stream.compose` in this repo's Node: calling it with a body that
46
+ // `return`s `[]` reproduces that same TypeError. A generator form
47
+ // (`async function*`) is the one that yields an iterable; the plain
48
+ // `async function` form used here is the one that must return nully. This
49
+ // repo's `engines.node` requires >=24.0.0 (package.json), where both
50
+ // contracts have been stable since Node 20.
51
+ //
52
+ // Kept intentionally tiny: only the five event types run-tests.cjs needs are
53
+ // handled — `test:enqueue`/`test:dequeue` (emitted by the RUNNER as it queues
54
+ // and begins each spawned test-file child, independent of whether anything
55
+ // inside that file ever completes) plus `test:start`/`test:pass`/`test:fail`
56
+ // (emitted per-subtest, once the child reports it). `test:dequeue` is the
57
+ // event that actually means "in flight": a subtest inside a file that hangs
58
+ // forever never reaches `test:start`/`test:pass`/`test:fail` at all, because
59
+ // node:test only surfaces those to the parent once the child COMPLETES that
60
+ // test — a hang, by definition, never completes. Recording `test:dequeue`
61
+ // closes that gap: it fires the moment the runner begins the file, so a
62
+ // killed hang still leaves a durable "this file was running" record.
63
+ // Everything else (diagnostics, plans, coverage) is ignored so a truncated
64
+ // events file (the process is SIGKILLed mid-`appendFileSync` on timeout — an
65
+ // individual write is unbuffered but not atomic, so the OS can still
66
+ // interleave a partial write with the kill) never leaves more than one
67
+ // dangling unparsable trailing line.
68
+ module.exports = async function ndjsonEventReporter(source) {
69
+ const eventsPath = process.env.GSD_RUN_TESTS_EVENTS_FILE;
70
+ // #3889: an init marker, written as this reporter's FIRST action — before
71
+ // the `for await` loop even begins consuming the event stream — so the
72
+ // events file's mere existence (and its exact contents) can distinguish
73
+ // "the reporter module never loaded in the child at all" (file absent)
74
+ // from "it loaded fine but no test:start reached it before the kill"
75
+ // (file contains only this one line) from "it's working" (file contains
76
+ // more than this line). Same appendFileSync durability rationale as every
77
+ // other write in this file: synchronous and unbuffered, so it survives an
78
+ // uncatchable SIGKILL landing a moment later.
79
+ if (eventsPath) {
80
+ try {
81
+ require('fs').appendFileSync(eventsPath, `${JSON.stringify({ type: 'reporter:init', ts: Date.now() })}\n`);
82
+ } catch {
83
+ // Best-effort, same as every other write below — must never crash the
84
+ // test run this reporter is only observing.
85
+ }
86
+ }
87
+ for await (const event of source) {
88
+ if (!eventsPath) continue; // no destination configured — nothing to record
89
+ if (
90
+ event.type === 'test:enqueue' ||
91
+ event.type === 'test:dequeue' ||
92
+ event.type === 'test:start' ||
93
+ event.type === 'test:pass' ||
94
+ event.type === 'test:fail'
95
+ ) {
96
+ const { file, name, nesting, testNumber } = event.data || {};
97
+ const line = `${JSON.stringify({
98
+ type: event.type,
99
+ file,
100
+ name,
101
+ nesting,
102
+ testNumber,
103
+ ts: Date.now(),
104
+ })}\n`;
105
+ try {
106
+ require('fs').appendFileSync(eventsPath, line);
107
+ } catch {
108
+ // Best-effort: a write failure here (e.g. the events dir vanished)
109
+ // must never crash the test run this reporter is only observing.
110
+ }
111
+ }
112
+ }
113
+ // Falls through to an implicit `return undefined` (nully): this reporter is
114
+ // a pure side-effecting sink (see the durability note above), never a
115
+ // source of reporter OUTPUT, and `stream.compose` requires its async
116
+ // FUNCTION body to return nully — returning an iterable (e.g. `[]`) here
117
+ // raises `ERR_INVALID_RETURN_VALUE` (observed live: this exact `return []`
118
+ // crashed every chunk on the real remote run this regresses).
119
+ };
@@ -0,0 +1,247 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * shellcheck-fetch.cjs
5
+ *
6
+ * Dependency-free replacement for the `shellcheck` npm package (removed in
7
+ * #4120 — its extraction step pulled in `decompress@4.2.1`, which carries an
8
+ * unpatched CRITICAL zip-slip vulnerability, GHSA-mp2f-45pm-3cg9, CVSS 9.1,
9
+ * plus two moderate findings, with no patched version available upstream).
10
+ *
11
+ * This module fetches a PINNED koalaman/shellcheck release directly from
12
+ * GitHub releases (never "latest" — see SHELLCHECK_VERSION below), extracts
13
+ * the single `shellcheck` binary from the release's `.tar.gz` asset using
14
+ * only Node's built-in `https`/`zlib` modules plus a small hand-written tar
15
+ * reader (no third-party archive library), and caches the extracted binary
16
+ * for reuse across runs.
17
+ *
18
+ * Zip-slip defense: unlike `decompress`, which wrote extracted files using
19
+ * PATHS TAKEN FROM THE ARCHIVE (the exact defect class in GHSA-mp2f-45pm-
20
+ * 3cg9 — a malicious archive entry named e.g. `../../etc/passwd` gets
21
+ * written there verbatim), this reader NEVER uses an archive-supplied name
22
+ * as a filesystem path. `extractFileFromTar` only ever returns the matched
23
+ * entry's raw byte content; the caller (`resolveShellcheckBin`) writes those
24
+ * bytes to a path it constructs itself (`<cacheDir>/shellcheck`), and the
25
+ * archive's own name field is used only for a string-equality/suffix CHECK
26
+ * (`name === targetName || name.endsWith('/' + targetName)`), never
27
+ * interpolated into a path passed to `fs.writeFileSync`/`fs.mkdirSync`/etc.
28
+ */
29
+
30
+ const fs = require('node:fs');
31
+ const path = require('node:path');
32
+ const zlib = require('node:zlib');
33
+ const https = require('node:https');
34
+ const { ExitError } = require('./cli-exit.cjs');
35
+
36
+ // Pinned explicitly — verified against `koalaman/shellcheck`'s GitHub
37
+ // releases API as the current latest tag at the time this was written
38
+ // (2026-08-31). Never resolved dynamically ("latest") — a moving target
39
+ // would make this lint's exact ShellCheck version, and therefore its exact
40
+ // finding set against scripts/lint-workflow-shellcheck-baseline.json,
41
+ // non-reproducible across runs/machines/CI.
42
+ const SHELLCHECK_VERSION = 'v0.11.0';
43
+
44
+ const ROOT = path.join(__dirname, '..', '..');
45
+ const CACHE_DIR = path.join(ROOT, 'node_modules', '.cache', 'shellcheck', SHELLCHECK_VERSION);
46
+ const CACHED_BIN_PATH = path.join(CACHE_DIR, 'shellcheck');
47
+
48
+ // process.arch -> the arch token ShellCheck's release asset names use.
49
+ // Only the two architectures that actually matter for this repo (per
50
+ // .github/workflows/test.yml: the lint-tests job that runs this script only
51
+ // runs on ubuntu-latest, which is x86_64; and Apple Silicon dev machines are
52
+ // aarch64) are supported — anything else fails with a clear error rather
53
+ // than guessing.
54
+ const ARCH_MAP = { x64: 'x86_64', arm64: 'aarch64' };
55
+
56
+ const MAX_REDIRECTS = 5;
57
+
58
+ // Bounds each individual HTTP hop (the initial request AND every redirect
59
+ // hop get their own fresh 30s budget, rather than one shared budget across
60
+ // the whole redirect chain) — a stalled connection on any single hop is
61
+ // caught in a bounded time, mirroring lint-workflow-shellcheck.cjs's own
62
+ // SHELLCHECK_TIMEOUT_MS bound on the ShellCheck subprocess. A bare `timeout`
63
+ // option on the request does NOT abort it by itself — Node only emits a
64
+ // 'timeout' event, which must be handled by destroying the request (see the
65
+ // `req.on('timeout', ...)` below).
66
+ const DOWNLOAD_TIMEOUT_MS = 30_000;
67
+
68
+ /**
69
+ * Issue one real HTTPS request. Exists as its own function purely so tests
70
+ * can inject a fake in its place (see `httpsGetFollowingRedirects`'s
71
+ * `requestFn` parameter) — production callers never pass an override, so
72
+ * the real download path always uses this exact implementation.
73
+ */
74
+ function defaultRequestFn(url, options, callback) {
75
+ return https.get(url, options, callback);
76
+ }
77
+
78
+ /**
79
+ * GET `url` following HTTP redirects manually — `https.get` does NOT follow
80
+ * redirects automatically, and GitHub release asset URLs redirect through
81
+ * `objects.githubusercontent.com`. Resolves with the full response body as a
82
+ * Buffer once a 200 response is received.
83
+ *
84
+ * `requestFn` defaults to a real `https.get`-based transport
85
+ * (`defaultRequestFn`) and is only ever overridden in tests, so calling this
86
+ * with zero/one arg from `resolveShellcheckBin` is unchanged behavior.
87
+ */
88
+ function httpsGetFollowingRedirects(url, redirectsLeft = MAX_REDIRECTS, requestFn = defaultRequestFn) {
89
+ return new Promise((resolve, reject) => {
90
+ const req = requestFn(
91
+ url,
92
+ { headers: { 'User-Agent': 'gsd-core-shellcheck-fetch' }, timeout: DOWNLOAD_TIMEOUT_MS },
93
+ (res) => {
94
+ const status = res.statusCode || 0;
95
+ if (status >= 300 && status < 400 && res.headers.location) {
96
+ res.resume(); // drain so the socket can be reused/closed
97
+ if (redirectsLeft <= 0) {
98
+ reject(new Error(`too many redirects fetching ${url}`));
99
+ return;
100
+ }
101
+ const next = new URL(res.headers.location, url).toString();
102
+ httpsGetFollowingRedirects(next, redirectsLeft - 1, requestFn).then(resolve, reject);
103
+ return;
104
+ }
105
+ if (status !== 200) {
106
+ res.resume();
107
+ reject(new Error(`unexpected HTTP ${status} fetching ${url}`));
108
+ return;
109
+ }
110
+ const chunks = [];
111
+ res.on('data', (chunk) => chunks.push(chunk));
112
+ res.on('end', () => resolve(Buffer.concat(chunks)));
113
+ res.on('error', reject);
114
+ },
115
+ );
116
+ req.on('error', reject);
117
+ // `timeout` in the options above only ARMS a timer — Node emits a
118
+ // 'timeout' event on the request but does not abort it. Without this
119
+ // handler the request (and this Promise) would hang indefinitely past
120
+ // the configured bound on a stalled connection.
121
+ req.on('timeout', () => {
122
+ req.destroy(new Error(`timed out after ${DOWNLOAD_TIMEOUT_MS}ms fetching ${url}`));
123
+ });
124
+ });
125
+ }
126
+
127
+ /**
128
+ * Find the entry named (or path-ending-in) `targetName` inside a raw
129
+ * (already gunzipped) POSIX tar byte stream and return its content as a
130
+ * Buffer, or `null` if not found.
131
+ *
132
+ * Tar format: a sequence of 512-byte headers — name at offset 0/length 100,
133
+ * size at offset 124/length 12 (octal ASCII), typeflag at offset 156 — each
134
+ * followed by that many content bytes, padded up to the next 512-byte
135
+ * boundary, terminated by an all-zero 512-byte block. This deliberately
136
+ * implements only enough to locate ONE known entry name (no general
137
+ * multi-file extraction, no symlink handling, no GNU long-name `@LongLink`
138
+ * entries — ShellCheck's own release tarballs never need them) — see this
139
+ * module's header comment for why the entry's NAME is never used as a
140
+ * filesystem path.
141
+ */
142
+ function extractFileFromTar(buffer, targetName) {
143
+ let offset = 0;
144
+ while (offset + 512 <= buffer.length) {
145
+ const header = buffer.subarray(offset, offset + 512);
146
+ if (header.every((b) => b === 0)) break; // end-of-archive marker
147
+ const name = header.subarray(0, 100).toString('utf8').replace(/\0.*$/, '');
148
+ const sizeRaw = header.subarray(124, 136).toString('utf8').replace(/\0.*$/, '').trim();
149
+ const size = sizeRaw === '' ? 0 : parseInt(sizeRaw, 8);
150
+ const typeflag = String.fromCharCode(header[156]);
151
+ const dataStart = offset + 512;
152
+ const isRegularFile = typeflag === '0' || typeflag === '\0';
153
+ if (isRegularFile && (name === targetName || name.endsWith(`/${targetName}`))) {
154
+ return buffer.subarray(dataStart, dataStart + size);
155
+ }
156
+ const contentBlocks = Math.ceil(size / 512);
157
+ offset = dataStart + contentBlocks * 512;
158
+ }
159
+ return null;
160
+ }
161
+
162
+ /**
163
+ * Resolve the local path to a working, executable `shellcheck` binary,
164
+ * downloading and caching the pinned release on first use. Subsequent calls
165
+ * (same version) reuse the cached binary with no network activity — mirrors
166
+ * the `fs.accessSync(bin, F_OK | X_OK)` cache-check pattern already used by
167
+ * this script's own `runShellcheck`.
168
+ */
169
+ async function resolveShellcheckBin() {
170
+ try {
171
+ fs.accessSync(CACHED_BIN_PATH, fs.constants.F_OK | fs.constants.X_OK);
172
+ return CACHED_BIN_PATH;
173
+ } catch {
174
+ // not cached yet — fall through to download
175
+ }
176
+
177
+ if (process.platform === 'win32') {
178
+ throw new ExitError(
179
+ 1,
180
+ 'lint-workflow-shellcheck: automatic ShellCheck download is not supported on Windows yet ' +
181
+ '(this lint only ever runs in the ubuntu-latest lint-tests CI job — see .github/workflows/test.yml — ' +
182
+ 'so this is an honest platform gap, not expected to be hit in CI).',
183
+ );
184
+ }
185
+ const platform = process.platform === 'darwin' || process.platform === 'linux' ? process.platform : null;
186
+ if (!platform) {
187
+ throw new ExitError(
188
+ 1,
189
+ `lint-workflow-shellcheck: unsupported platform '${process.platform}' for ShellCheck auto-download ` +
190
+ `(supported: linux, darwin).`,
191
+ );
192
+ }
193
+ const arch = ARCH_MAP[process.arch];
194
+ if (!arch) {
195
+ throw new ExitError(
196
+ 1,
197
+ `lint-workflow-shellcheck: unsupported architecture '${process.arch}' for ShellCheck auto-download ` +
198
+ `(supported: x86_64 [node arch 'x64'], aarch64 [node arch 'arm64']).`,
199
+ );
200
+ }
201
+
202
+ const assetName = `shellcheck-${SHELLCHECK_VERSION}.${platform}.${arch}.tar.gz`;
203
+ const url = `https://github.com/koalaman/shellcheck/releases/download/${SHELLCHECK_VERSION}/${assetName}`;
204
+
205
+ let gz;
206
+ try {
207
+ gz = await httpsGetFollowingRedirects(url);
208
+ } catch (e) {
209
+ throw new ExitError(1, `lint-workflow-shellcheck: failed to download ShellCheck (${url}): ${e.message}`);
210
+ }
211
+
212
+ let tarBuf;
213
+ try {
214
+ tarBuf = zlib.gunzipSync(gz);
215
+ } catch (e) {
216
+ throw new ExitError(1, `lint-workflow-shellcheck: failed to gunzip downloaded ShellCheck archive: ${e.message}`);
217
+ }
218
+
219
+ const entry = extractFileFromTar(tarBuf, 'shellcheck');
220
+ if (!entry) {
221
+ throw new ExitError(
222
+ 1,
223
+ `lint-workflow-shellcheck: could not find a 'shellcheck' entry inside downloaded archive ${assetName}`,
224
+ );
225
+ }
226
+
227
+ fs.mkdirSync(CACHE_DIR, { recursive: true });
228
+ // Write to a per-process temp path and rename into place — avoids any
229
+ // other concurrent invocation observing (and trying to execute) a
230
+ // partially-written binary at the real cache path.
231
+ const tmpPath = path.join(CACHE_DIR, `.shellcheck.tmp-${process.pid}`);
232
+ fs.writeFileSync(tmpPath, entry);
233
+ fs.chmodSync(tmpPath, 0o755);
234
+ fs.renameSync(tmpPath, CACHED_BIN_PATH);
235
+
236
+ return CACHED_BIN_PATH;
237
+ }
238
+
239
+ module.exports = {
240
+ SHELLCHECK_VERSION,
241
+ CACHED_BIN_PATH,
242
+ MAX_REDIRECTS,
243
+ DOWNLOAD_TIMEOUT_MS,
244
+ extractFileFromTar,
245
+ httpsGetFollowingRedirects,
246
+ resolveShellcheckBin,
247
+ };
@@ -24,7 +24,6 @@
24
24
  "tests/code-review-pipeline-regression.test.cjs :: source-text-is-the-product",
25
25
  "tests/code-review.test.cjs :: source-text-is-the-product",
26
26
  "tests/codebuddy-install.test.cjs :: source-text-is-the-product",
27
- "tests/codex-config.test.cjs :: source-text-is-the-product",
28
27
  "tests/command-contract.test.cjs :: source-text-is-the-product",
29
28
  "tests/commands.test.cjs :: source-text-is-the-product",
30
29
  "tests/config-field-docs.test.cjs :: docs-parity",
@@ -52,7 +51,6 @@
52
51
  "tests/frontmatter-cli.test.cjs :: source-text-is-the-product",
53
52
  "tests/gates-taxonomy.test.cjs :: source-text-is-the-product",
54
53
  "tests/git-base-branch.test.cjs :: source-text-is-the-product",
55
- "tests/gsd-check-update-worker-platform-gate.test.cjs :: structural-regression-guard",
56
54
  "tests/gsd-researcher-app-aware.test.cjs :: source-text-is-the-product",
57
55
  "tests/gsd-researcher-flow-diagram.test.cjs :: source-text-is-the-product",
58
56
  "tests/gsd-settings-advanced.test.cjs :: source-text-is-the-product",
@@ -74,13 +72,11 @@
74
72
  "tests/next-safety-gates.test.cjs :: source-text-is-the-product",
75
73
  "tests/next-up-clear-order.test.cjs :: source-text-is-the-product",
76
74
  "tests/no-hardcoded-home-gsd-tools.test.cjs :: source-text-is-the-product",
77
- "tests/orphaned-hooks.test.cjs :: structural-regression-guard",
78
75
  "tests/package-legitimacy-gate.test.cjs :: source-text-is-the-product",
79
76
  "tests/parallel-dependent-plans.test.cjs :: source-text-is-the-product",
80
77
  "tests/path-replacement.test.cjs :: source-text-is-the-product",
81
78
  "tests/phase.test.cjs :: source-text-is-the-product",
82
79
  "tests/phase6-capability-docs.test.cjs :: source-text-is-the-product",
83
- "tests/phase6-capstone-conformance.test.cjs :: source-text-is-the-product",
84
80
  "tests/phase6-planning-capabilities.test.cjs :: source-text-is-the-product",
85
81
  "tests/plan-bounce.test.cjs :: source-text-is-the-product",
86
82
  "tests/plan-phase-drift-guard.test.cjs :: source-text-is-the-product",
@@ -105,7 +101,6 @@
105
101
  "tests/research-agent-profiles.test.cjs :: source-text-is-the-product",
106
102
  "tests/roadmap.test.cjs :: source-text-is-the-product",
107
103
  "tests/runtime-launcher-parity.test.cjs :: structural-regression-guard",
108
- "tests/runtime-name-policy.test.cjs :: source-text-is-the-product",
109
104
  "tests/scan-command.test.cjs :: source-text-is-the-product",
110
105
  "tests/secret-scan-lint.security.test.cjs :: source-text-is-the-product",
111
106
  "tests/secure-phase.test.cjs :: source-text-is-the-product",
@@ -113,7 +108,6 @@
113
108
  "tests/security-scan.security.test.cjs :: source-text-is-the-product",
114
109
  "tests/seed-scan-new-milestone.test.cjs :: source-text-is-the-product",
115
110
  "tests/settings-integrations.test.cjs :: source-text-is-the-product",
116
- "tests/settings-jsonc.test.cjs :: structural-regression-guard",
117
111
  "tests/skill-frontmatter-contract.test.cjs :: source-text-is-the-product",
118
112
  "tests/spawn-liveness-banner.test.cjs :: source-text-is-the-product",
119
113
  "tests/state.test.cjs :: source-text-is-the-product",
@@ -1,4 +1,4 @@
1
1
  {
2
- "maxSites": 10,
2
+ "maxSites": 84,
3
3
  "grace": 2
4
4
  }
@@ -1,3 +1,3 @@
1
1
  {
2
- "maxFiles": 280
2
+ "maxFiles": 283
3
3
  }