@opengsd/gsd-core 1.12.0 → 1.14.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 (455) 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-advisor-researcher.compact.md +85 -0
  5. package/agents/gsd-ai-researcher.compact.md +96 -0
  6. package/agents/gsd-assumptions-analyzer.compact.md +81 -0
  7. package/agents/gsd-code-fixer.compact.md +458 -0
  8. package/agents/gsd-code-fixer.md +5 -5
  9. package/agents/gsd-code-reviewer.compact.md +269 -0
  10. package/agents/gsd-code-reviewer.md +15 -3
  11. package/agents/gsd-codebase-mapper.compact.md +760 -0
  12. package/agents/gsd-debug-session-manager.compact.md +345 -0
  13. package/agents/gsd-doc-classifier.compact.md +192 -0
  14. package/agents/gsd-doc-synthesizer.compact.md +200 -0
  15. package/agents/gsd-doc-verifier.compact.md +143 -0
  16. package/agents/gsd-doc-writer.compact.md +440 -0
  17. package/agents/gsd-dom-verifier.compact.md +138 -0
  18. package/agents/gsd-domain-researcher.compact.md +141 -0
  19. package/agents/gsd-eval-auditor.compact.md +160 -0
  20. package/agents/gsd-eval-planner.compact.md +137 -0
  21. package/agents/gsd-executor.md +63 -35
  22. package/agents/gsd-framework-selector.compact.md +82 -0
  23. package/agents/gsd-integration-checker.compact.md +245 -0
  24. package/agents/gsd-intel-updater.compact.md +226 -0
  25. package/agents/gsd-mempalace-curator.compact.md +45 -0
  26. package/agents/gsd-nyquist-auditor.compact.md +179 -0
  27. package/agents/gsd-pattern-mapper.compact.md +275 -0
  28. package/agents/gsd-plan-checker.md +76 -57
  29. package/agents/gsd-planner.md +14 -0
  30. package/agents/gsd-project-researcher.compact.md +587 -0
  31. package/agents/gsd-research-synthesizer.compact.md +212 -0
  32. package/agents/gsd-roadmapper.compact.md +454 -0
  33. package/agents/gsd-roadmapper.md +13 -0
  34. package/agents/gsd-security-auditor.compact.md +162 -0
  35. package/agents/gsd-ui-auditor.compact.md +404 -0
  36. package/agents/gsd-ui-checker.compact.md +277 -0
  37. package/agents/gsd-ui-checker.md +19 -3
  38. package/agents/gsd-ui-researcher.compact.md +282 -0
  39. package/agents/gsd-ui-researcher.md +29 -0
  40. package/agents/gsd-user-profiler.compact.md +108 -0
  41. package/agents/gsd-verifier.md +23 -1
  42. package/bin/install.js +444 -134
  43. package/commands/gsd/cleanup.md +1 -0
  44. package/commands/gsd/code-review.md +2 -1
  45. package/commands/gsd/complete-milestone.md +1 -0
  46. package/commands/gsd/config.md +1 -0
  47. package/commands/gsd/debug.md +1 -0
  48. package/commands/gsd/execute-phase.md +1 -1
  49. package/commands/gsd/graphify.md +1 -0
  50. package/commands/gsd/health.md +1 -0
  51. package/commands/gsd/mempalace-capture.md +1 -0
  52. package/commands/gsd/mempalace-recall.md +1 -0
  53. package/commands/gsd/new-milestone.md +1 -0
  54. package/commands/gsd/new-project.md +1 -0
  55. package/commands/gsd/next.md +1 -0
  56. package/commands/gsd/ns-workflow.md +2 -1
  57. package/commands/gsd/pause-work.md +1 -0
  58. package/commands/gsd/phase.md +2 -1
  59. package/commands/gsd/pr-branch.md +1 -0
  60. package/commands/gsd/quick-batch.md +105 -0
  61. package/commands/gsd/resume-work.md +1 -0
  62. package/commands/gsd/review-backlog.md +1 -0
  63. package/commands/gsd/settings.md +2 -1
  64. package/commands/gsd/stats.md +1 -0
  65. package/commands/gsd/surface.md +18 -8
  66. package/commands/gsd/thread.md +1 -0
  67. package/commands/gsd/workspace.md +1 -0
  68. package/commands/gsd/workstreams.md +1 -0
  69. package/gsd-core/bin/check-latest-version.cjs +8 -3
  70. package/gsd-core/bin/gsd-tools.cjs +532 -174
  71. package/gsd-core/bin/lib/adr-parser.cjs +1 -1
  72. package/gsd-core/bin/lib/artifacts.cjs +2 -1
  73. package/gsd-core/bin/lib/audit.cjs +39 -22
  74. package/gsd-core/bin/lib/broken-windows.cjs +168 -49
  75. package/gsd-core/bin/lib/capability-activation.cjs +27 -0
  76. package/gsd-core/bin/lib/capability-lifecycle.cjs +10 -6
  77. package/gsd-core/bin/lib/capability-loader.cjs +135 -1
  78. package/gsd-core/bin/lib/capability-registry.cjs +528 -116
  79. package/gsd-core/bin/lib/capability-source.cjs +19 -2
  80. package/gsd-core/bin/lib/capability-state.cjs +7 -1
  81. package/gsd-core/bin/lib/capability-validator.cjs +134 -5
  82. package/gsd-core/bin/lib/capability-writer.cjs +14 -4
  83. package/gsd-core/bin/lib/check-command-router.cjs +198 -38
  84. package/gsd-core/bin/lib/claude-orchestration.cjs +10 -25
  85. package/gsd-core/bin/lib/clusters.cjs +1 -0
  86. package/gsd-core/bin/lib/code-review-depth.cjs +2 -2
  87. package/gsd-core/bin/lib/command-aliases.cjs +16 -0
  88. package/gsd-core/bin/lib/commands.cjs +981 -79
  89. package/gsd-core/bin/lib/config-loader.cjs +4 -0
  90. package/gsd-core/bin/lib/config.cjs +153 -38
  91. package/gsd-core/bin/lib/core-utils.cjs +34 -7
  92. package/gsd-core/bin/lib/coverage.cjs +1 -1
  93. package/gsd-core/bin/lib/decisions.cjs +343 -28
  94. package/gsd-core/bin/lib/edge-probe.cjs +14 -1
  95. package/gsd-core/bin/lib/external-descriptor-trust.cjs +29 -14
  96. package/gsd-core/bin/lib/file-overlap-partitioner.cjs +74 -0
  97. package/gsd-core/bin/lib/frontmatter.cjs +137 -23
  98. package/gsd-core/bin/lib/gap-checker.cjs +22 -13
  99. package/gsd-core/bin/lib/git-base-branch.cjs +10 -2
  100. package/gsd-core/bin/lib/gsd2-import.cjs +1 -2
  101. package/gsd-core/bin/lib/health-diagnostic-rules/phase-structure.cjs +8 -2
  102. package/gsd-core/bin/lib/health-diagnostic-rules/roadmap-disk-consistency.cjs +54 -11
  103. package/gsd-core/bin/lib/health-diagnostic-rules/state-consistency.cjs +87 -23
  104. package/gsd-core/bin/lib/health-diagnostic-rules/worktree-health.cjs +1 -1
  105. package/gsd-core/bin/lib/host-integration.cjs +57 -5
  106. package/gsd-core/bin/lib/init-command-router.cjs +14 -0
  107. package/gsd-core/bin/lib/init.cjs +539 -60
  108. package/gsd-core/bin/lib/install-engine.cjs +199 -14
  109. package/gsd-core/bin/lib/install-model-override-resolver.cjs +45 -0
  110. package/gsd-core/bin/lib/install-profiles.cjs +36 -14
  111. package/gsd-core/bin/lib/installer-migration-report.cjs +1 -0
  112. package/gsd-core/bin/lib/installer-migrations.cjs +33 -4
  113. package/gsd-core/bin/lib/io.cjs +35 -0
  114. package/gsd-core/bin/lib/loop-resolver.cjs +64 -39
  115. package/gsd-core/bin/lib/markdown-table.cjs +123 -0
  116. package/gsd-core/bin/lib/mcp-catalog.cjs +2 -2
  117. package/gsd-core/bin/lib/milestone.cjs +41 -10
  118. package/gsd-core/bin/lib/model-resolver.cjs +101 -10
  119. package/gsd-core/bin/lib/phase-command-router.cjs +20 -7
  120. package/gsd-core/bin/lib/phase-id.cjs +412 -31
  121. package/gsd-core/bin/lib/phase-lifecycle.cjs +61 -0
  122. package/gsd-core/bin/lib/phase.cjs +941 -98
  123. package/gsd-core/bin/lib/plan-document.cjs +10 -0
  124. package/gsd-core/bin/lib/planning-inspect.cjs +34 -18
  125. package/gsd-core/bin/lib/planning-snapshot.cjs +206 -30
  126. package/gsd-core/bin/lib/planning-workspace.cjs +153 -29
  127. package/gsd-core/bin/lib/pristine-baseline.cjs +182 -0
  128. package/gsd-core/bin/lib/prohibition-enforcement.cjs +91 -4
  129. package/gsd-core/bin/lib/quick-batch-command-router.cjs +285 -0
  130. package/gsd-core/bin/lib/quick-batch-dispatch.cjs +250 -0
  131. package/gsd-core/bin/lib/quick-batch.cjs +840 -0
  132. package/gsd-core/bin/lib/refactor-trigger-command-router.cjs +61 -2
  133. package/gsd-core/bin/lib/research-store.cjs +11 -12
  134. package/gsd-core/bin/lib/review-lane-descriptor.cjs +53 -5
  135. package/gsd-core/bin/lib/review-lane-invocation.cjs +96 -1
  136. package/gsd-core/bin/lib/review-lane-runner.cjs +136 -10
  137. package/gsd-core/bin/lib/reviewer-step-dispatch.cjs +337 -0
  138. package/gsd-core/bin/lib/roadmap-parser.cjs +555 -41
  139. package/gsd-core/bin/lib/roadmap.cjs +292 -69
  140. package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +260 -43
  141. package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +28 -20
  142. package/gsd-core/bin/lib/runtime-artifact-layout.cjs +294 -108
  143. package/gsd-core/bin/lib/runtime-hooks-surface.cjs +408 -47
  144. package/gsd-core/bin/lib/security.cjs +126 -7
  145. package/gsd-core/bin/lib/shell-command-projection.cjs +4 -0
  146. package/gsd-core/bin/lib/smart-entry.cjs +7 -9
  147. package/gsd-core/bin/lib/state-document.cjs +159 -32
  148. package/gsd-core/bin/lib/state-md-schema.cjs +44 -27
  149. package/gsd-core/bin/lib/state-transition.cjs +465 -62
  150. package/gsd-core/bin/lib/state.cjs +906 -151
  151. package/gsd-core/bin/lib/surface.cjs +83 -10
  152. package/gsd-core/bin/lib/task-command-router.cjs +12 -6
  153. package/gsd-core/bin/lib/tdd-red-evidence.cjs +133 -0
  154. package/gsd-core/bin/lib/uat.cjs +1420 -516
  155. package/gsd-core/bin/lib/update-context.cjs +36 -26
  156. package/gsd-core/bin/lib/validate.cjs +230 -12
  157. package/gsd-core/bin/lib/vendor/js-yaml.cjs +11 -3
  158. package/gsd-core/bin/lib/verification-command-router.cjs +2 -1
  159. package/gsd-core/bin/lib/verification.cjs +316 -23
  160. package/gsd-core/bin/lib/verify-command-grounding.cjs +1 -1
  161. package/gsd-core/bin/lib/verify-command-router.cjs +1 -0
  162. package/gsd-core/bin/lib/verify.cjs +531 -36
  163. package/gsd-core/bin/lib/workstream-inventory.cjs +21 -2
  164. package/gsd-core/bin/lib/worktree-safety.cjs +21 -7
  165. package/gsd-core/bin/shared/config-defaults.manifest.json +1 -0
  166. package/gsd-core/bin/shared/config-schema.manifest.json +13 -0
  167. package/gsd-core/bin/verify-reapply-patches.cjs +507 -81
  168. package/gsd-core/references/agent-contracts.md +3 -3
  169. package/gsd-core/references/compact-content-gate.md +66 -0
  170. package/gsd-core/references/edge-probe.md +17 -13
  171. package/gsd-core/references/execute-mvp-tdd.md +18 -16
  172. package/gsd-core/references/execute-phase-response-language.md +6 -0
  173. package/gsd-core/references/executor-examples.md +42 -0
  174. package/gsd-core/references/few-shot-examples/plan-checker.md +15 -15
  175. package/gsd-core/references/loop-hook-dispatch.md +18 -0
  176. package/gsd-core/references/model-profiles.md +12 -3
  177. package/gsd-core/references/mvp-concepts.md +2 -2
  178. package/gsd-core/references/plan-checker-examples.md +41 -0
  179. package/gsd-core/references/planner-antipatterns.md +25 -0
  180. package/gsd-core/references/planner-chunked.md +5 -1
  181. package/gsd-core/references/planner-coupling.md +42 -0
  182. package/gsd-core/references/planner-quick-batch.md +71 -0
  183. package/gsd-core/references/planner-reviews.md +47 -0
  184. package/gsd-core/references/planner-revision.md +75 -2
  185. package/gsd-core/references/planning-config.md +5 -1
  186. package/gsd-core/references/response-language-directive.md +9 -0
  187. package/gsd-core/references/revision-loop.md +118 -11
  188. package/gsd-core/references/tdd.md +17 -9
  189. package/gsd-core/references/thinking-models-planning.md +18 -2
  190. package/gsd-core/references/verification-patterns.md +17 -4
  191. package/gsd-core/references/verifier-evidence-gate.md +160 -0
  192. package/gsd-core/references/worktree-path-safety.md +112 -2
  193. package/gsd-core/templates/README.md +7 -1
  194. package/gsd-core/templates/phase-prompt.md +4 -0
  195. package/gsd-core/templates/state.md +6 -3
  196. package/gsd-core/templates/summary.compact.md +212 -0
  197. package/gsd-core/templates/user-setup.compact.md +199 -0
  198. package/gsd-core/templates/user-setup.md +0 -9
  199. package/gsd-core/templates/verification-report.md +5 -0
  200. package/gsd-core/workflows/add-backlog.md +2 -0
  201. package/gsd-core/workflows/add-phase.md +2 -0
  202. package/gsd-core/workflows/add-tests.md +1 -1
  203. package/gsd-core/workflows/add-todo.md +4 -3
  204. package/gsd-core/workflows/ai-integration-phase.md +1 -1
  205. package/gsd-core/workflows/analyze-dependencies.md +2 -0
  206. package/gsd-core/workflows/audit-fix.md +2 -0
  207. package/gsd-core/workflows/audit-milestone.md +2 -0
  208. package/gsd-core/workflows/audit-uat.md +2 -0
  209. package/gsd-core/workflows/autonomous.md +15 -10
  210. package/gsd-core/workflows/check-todos.md +5 -3
  211. package/gsd-core/workflows/cleanup.md +4 -2
  212. package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +22 -13
  213. package/gsd-core/workflows/code-review-fix.md +5 -3
  214. package/gsd-core/workflows/code-review.md +211 -43
  215. package/gsd-core/workflows/complete-milestone/detail/elaboration.md +274 -0
  216. package/gsd-core/workflows/complete-milestone.md +40 -254
  217. package/gsd-core/workflows/debug.md +1 -1
  218. package/gsd-core/workflows/diagnose-issues.md +5 -1
  219. package/gsd-core/workflows/discuss-phase/modes/advisor.md +2 -0
  220. package/gsd-core/workflows/discuss-phase/modes/all.md +2 -0
  221. package/gsd-core/workflows/discuss-phase/modes/analyze.md +2 -0
  222. package/gsd-core/workflows/discuss-phase/modes/auto.md +2 -0
  223. package/gsd-core/workflows/discuss-phase/modes/batch.md +2 -0
  224. package/gsd-core/workflows/discuss-phase/modes/chain.md +2 -0
  225. package/gsd-core/workflows/discuss-phase/modes/default.md +2 -0
  226. package/gsd-core/workflows/discuss-phase/modes/power.md +2 -0
  227. package/gsd-core/workflows/discuss-phase/modes/text.md +2 -0
  228. package/gsd-core/workflows/discuss-phase/templates/context.md +2 -0
  229. package/gsd-core/workflows/discuss-phase/templates/discussion-log.md +2 -0
  230. package/gsd-core/workflows/discuss-phase-assumptions.md +1 -1
  231. package/gsd-core/workflows/discuss-phase-power.md +2 -0
  232. package/gsd-core/workflows/discuss-phase.md +1 -1
  233. package/gsd-core/workflows/do.md +43 -13
  234. package/gsd-core/workflows/docs-update/detail/elaboration.md +179 -0
  235. package/gsd-core/workflows/docs-update.md +15 -156
  236. package/gsd-core/workflows/edit-phase.md +2 -0
  237. package/gsd-core/workflows/eval-review.md +1 -1
  238. package/gsd-core/workflows/execute-phase/detail/elaboration.md +124 -0
  239. package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +20 -3
  240. package/gsd-core/workflows/execute-phase/steps/completion-reconciliation.md +56 -0
  241. package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +24 -3
  242. package/gsd-core/workflows/execute-phase/steps/executor-progress-policy.md +43 -0
  243. package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +8 -2
  244. package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +2 -0
  245. package/gsd-core/workflows/execute-phase/steps/sequential-root-pin.md +35 -0
  246. package/gsd-core/workflows/execute-phase/steps/tdd-applicability-resolution.md +25 -0
  247. package/gsd-core/workflows/execute-phase/steps/worktree-recovery-policy.md +2 -0
  248. package/gsd-core/workflows/execute-phase.md +78 -159
  249. package/gsd-core/workflows/execute-plan.md +28 -15
  250. package/gsd-core/workflows/explore.md +2 -0
  251. package/gsd-core/workflows/extract-learnings.md +2 -0
  252. package/gsd-core/workflows/fast.md +6 -0
  253. package/gsd-core/workflows/forensics.md +2 -0
  254. package/gsd-core/workflows/graduation.md +1 -1
  255. package/gsd-core/workflows/health.md +1 -1
  256. package/gsd-core/workflows/help/modes/brief.md +2 -0
  257. package/gsd-core/workflows/help/modes/default.md +2 -0
  258. package/gsd-core/workflows/help/modes/full.compact.md +398 -0
  259. package/gsd-core/workflows/help/modes/full.md +12 -0
  260. package/gsd-core/workflows/help/modes/topic.md +2 -0
  261. package/gsd-core/workflows/help.md +3 -1
  262. package/gsd-core/workflows/import.md +3 -3
  263. package/gsd-core/workflows/inbox.md +1 -1
  264. package/gsd-core/workflows/ingest-docs.md +1 -1
  265. package/gsd-core/workflows/insert-phase.md +2 -0
  266. package/gsd-core/workflows/list-phase-assumptions.md +2 -0
  267. package/gsd-core/workflows/list-seeds.md +2 -0
  268. package/gsd-core/workflows/list-workspaces.md +2 -0
  269. package/gsd-core/workflows/manager.md +3 -3
  270. package/gsd-core/workflows/map-codebase.md +52 -3
  271. package/gsd-core/workflows/milestone-summary.md +2 -0
  272. package/gsd-core/workflows/mvp-phase.md +1 -1
  273. package/gsd-core/workflows/new-milestone.md +55 -13
  274. package/gsd-core/workflows/new-project/detail/elaboration.md +216 -0
  275. package/gsd-core/workflows/new-project.md +37 -205
  276. package/gsd-core/workflows/new-workspace.md +1 -1
  277. package/gsd-core/workflows/next.md +2 -0
  278. package/gsd-core/workflows/node-repair.md +2 -0
  279. package/gsd-core/workflows/note.md +2 -0
  280. package/gsd-core/workflows/onboard.md +1 -1
  281. package/gsd-core/workflows/pause-work.md +19 -4
  282. package/gsd-core/workflows/plan-phase/detail/elaboration.md +209 -0
  283. package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +100 -18
  284. package/gsd-core/workflows/plan-phase/steps/prd-express-path.md +2 -0
  285. package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +9 -0
  286. package/gsd-core/workflows/plan-phase.md +144 -185
  287. package/gsd-core/workflows/plan-review-convergence.md +102 -10
  288. package/gsd-core/workflows/plant-seed.md +1 -1
  289. package/gsd-core/workflows/pr-branch.md +30 -10
  290. package/gsd-core/workflows/profile-user.md +1 -1
  291. package/gsd-core/workflows/progress/steps/forensic-audit.md +1 -1
  292. package/gsd-core/workflows/progress.md +25 -3
  293. package/gsd-core/workflows/quick/steps/plan-checker-loop.md +37 -2
  294. package/gsd-core/workflows/quick/steps/research-phase.md +3 -3
  295. package/gsd-core/workflows/quick-batch/steps/batch-init.md +55 -0
  296. package/gsd-core/workflows/quick-batch/steps/completion.md +65 -0
  297. package/gsd-core/workflows/quick-batch/steps/merge-wave.md +100 -0
  298. package/gsd-core/workflows/quick-batch/steps/plan-checker-loop.md +147 -0
  299. package/gsd-core/workflows/quick-batch/steps/planner-wave.md +158 -0
  300. package/gsd-core/workflows/quick-batch/steps/research-phase.md +95 -0
  301. package/gsd-core/workflows/quick-batch/steps/resume-mode.md +49 -0
  302. package/gsd-core/workflows/quick-batch/steps/verification-wave.md +73 -0
  303. package/gsd-core/workflows/quick-batch/steps/worktree-dispatch.md +169 -0
  304. package/gsd-core/workflows/quick-batch.md +203 -0
  305. package/gsd-core/workflows/quick.md +21 -4
  306. package/gsd-core/workflows/reapply-patches.md +79 -3
  307. package/gsd-core/workflows/remove-phase.md +2 -0
  308. package/gsd-core/workflows/remove-workspace.md +1 -1
  309. package/gsd-core/workflows/resume-project.md +6 -2
  310. package/gsd-core/workflows/review.md +215 -10
  311. package/gsd-core/workflows/scan.md +2 -0
  312. package/gsd-core/workflows/section-manifest.json +12 -0
  313. package/gsd-core/workflows/secure-phase.md +1 -1
  314. package/gsd-core/workflows/session-report.md +2 -0
  315. package/gsd-core/workflows/settings-advanced.md +2 -0
  316. package/gsd-core/workflows/settings-integrations.md +9 -8
  317. package/gsd-core/workflows/settings.md +19 -6
  318. package/gsd-core/workflows/ship.md +10 -10
  319. package/gsd-core/workflows/sketch-wrap-up.md +2 -0
  320. package/gsd-core/workflows/sketch.md +1 -1
  321. package/gsd-core/workflows/smart-entry.md +1 -1
  322. package/gsd-core/workflows/spec-phase.md +24 -19
  323. package/gsd-core/workflows/spike-wrap-up.md +2 -0
  324. package/gsd-core/workflows/spike.md +1 -1
  325. package/gsd-core/workflows/stats.md +2 -0
  326. package/gsd-core/workflows/sync-skills.md +12 -4
  327. package/gsd-core/workflows/thread.md +2 -0
  328. package/gsd-core/workflows/transition.md +2 -0
  329. package/gsd-core/workflows/ui-phase.md +26 -5
  330. package/gsd-core/workflows/ui-review.md +1 -1
  331. package/gsd-core/workflows/ultraplan-phase.md +2 -0
  332. package/gsd-core/workflows/undo.md +1 -1
  333. package/gsd-core/workflows/update.md +48 -43
  334. package/gsd-core/workflows/validate-phase.md +1 -1
  335. package/gsd-core/workflows/verify-work/detail/elaboration.md +230 -0
  336. package/gsd-core/workflows/verify-work.md +68 -182
  337. package/hooks/dist/gsd-agent-isolation-guard.js +42 -16
  338. package/hooks/dist/gsd-check-update-worker.js +19 -2
  339. package/hooks/dist/gsd-context-monitor.js +371 -27
  340. package/hooks/dist/gsd-cursor-subagent-start.js +34 -14
  341. package/hooks/dist/gsd-node-runner.sh +1 -0
  342. package/hooks/dist/gsd-prompt-guard.js +30 -5
  343. package/hooks/dist/gsd-read-guard.js +2 -0
  344. package/hooks/dist/gsd-read-injection-scanner.js +5 -5
  345. package/hooks/dist/gsd-secret-read-guard.js +1105 -0
  346. package/hooks/dist/gsd-statusline.js +18 -10
  347. package/hooks/dist/gsd-validate-commit.sh +474 -7
  348. package/hooks/dist/gsd-workflow-guard.js +2 -1
  349. package/hooks/dist/gsd-worktree-path-guard.js +25 -14
  350. package/hooks/dist/gsd-write-guard.js +46 -1
  351. package/hooks/dist/lib/dispatch-identity.js +187 -0
  352. package/hooks/dist/lib/filename-classification.js +64 -0
  353. package/hooks/dist/lib/git-cmd.js +210 -1
  354. package/hooks/dist/lib/injection-patterns.js +36 -6
  355. package/hooks/dist/lib/isolation-deny-reason.js +53 -1
  356. package/hooks/dist/lib/isolation-sentinel.js +58 -19
  357. package/hooks/dist/managed-hooks-registry.cjs +1 -0
  358. package/hooks/gsd-agent-isolation-guard.js +42 -16
  359. package/hooks/gsd-check-update-worker.js +19 -2
  360. package/hooks/gsd-context-monitor.js +371 -27
  361. package/hooks/gsd-cursor-subagent-start.js +34 -14
  362. package/hooks/gsd-node-runner.sh +1 -0
  363. package/hooks/gsd-prompt-guard.js +30 -5
  364. package/hooks/gsd-read-guard.js +2 -0
  365. package/hooks/gsd-read-injection-scanner.js +5 -5
  366. package/hooks/gsd-secret-read-guard.js +1105 -0
  367. package/hooks/gsd-statusline.js +18 -10
  368. package/hooks/gsd-validate-commit.sh +474 -7
  369. package/hooks/gsd-workflow-guard.js +2 -1
  370. package/hooks/gsd-worktree-path-guard.js +25 -14
  371. package/hooks/gsd-write-guard.js +46 -1
  372. package/hooks/hooks.json +6 -0
  373. package/hooks/lib/dispatch-identity.js +187 -0
  374. package/hooks/lib/filename-classification.js +64 -0
  375. package/hooks/lib/git-cmd.js +210 -1
  376. package/hooks/lib/injection-patterns.js +36 -6
  377. package/hooks/lib/isolation-deny-reason.js +53 -1
  378. package/hooks/lib/isolation-sentinel.js +58 -19
  379. package/hooks/managed-hooks-registry.cjs +1 -0
  380. package/package.json +13 -9
  381. package/scripts/benchmark-compact-content-variants.cjs +298 -0
  382. package/scripts/benchmark-compact-content.cjs +368 -0
  383. package/scripts/build-hooks.js +11 -4
  384. package/scripts/check-contract-drift.cjs +4 -1
  385. package/scripts/check-env.cjs +36 -8
  386. package/scripts/check-glossary-refs.cjs +25 -21
  387. package/scripts/ci-next-health.cjs +271 -0
  388. package/scripts/ci-prepare-test-scope.cjs +7 -7
  389. package/scripts/ci-test-scope.cjs +133 -20
  390. package/scripts/ci-timeout-report.cjs +1 -1
  391. package/scripts/diff-touches-shipped-paths.cjs +1 -1
  392. package/scripts/docs-guard-registry.cjs +17 -2
  393. package/scripts/gen-adr-index.cjs +8 -2
  394. package/scripts/gen-inventory-manifest.cjs +12 -0
  395. package/scripts/gen-loop-host-contract.cjs +67 -15
  396. package/scripts/gen-platform-conformance-tier.cjs +557 -0
  397. package/scripts/lib/drift-scan.cjs +1 -1
  398. package/scripts/lib/macos-conformance-tier.generated.cjs +210 -0
  399. package/scripts/lib/npm-version-check-diagnosis.cjs +59 -0
  400. package/scripts/lib/platform-conformance-tier.generated.cjs +276 -0
  401. package/scripts/lib/shellcheck-fetch.cjs +247 -0
  402. package/scripts/lib/suite-detection.cjs +32 -0
  403. package/scripts/lint-allow-test-rule-refs.allowlist.json +0 -6
  404. package/scripts/lint-allow-test-rule-refs.effective-ceiling.json +1 -1
  405. package/scripts/lint-allow-test-rule-refs.unverified-ceiling.json +1 -1
  406. package/scripts/lint-allowed-tools-parity.cjs +221 -0
  407. package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +24 -2
  408. package/scripts/lint-phase-enumeration-drift.cjs +24 -6
  409. package/scripts/lint-phase-id-drift.cjs +465 -15
  410. package/scripts/lint-portable-grep.cjs +176 -0
  411. package/scripts/lint-response-language-coverage.cjs +530 -0
  412. package/scripts/lint-source-test-name-collision.cjs +1 -1
  413. package/scripts/lint-test-file-count.allowlist.json +4 -1
  414. package/scripts/lint-vendored-deps.cjs +128 -17
  415. package/scripts/lint-workflow-shellcheck-baseline.json +1112 -0
  416. package/scripts/lint-workflow-shellcheck.cjs +614 -0
  417. package/scripts/npm-audit-baseline.cjs +376 -0
  418. package/scripts/prompt-injection-scan.sh +22 -0
  419. package/scripts/require-issue-link-policy.cjs +16 -1
  420. package/scripts/workflow-size.cjs +139 -0
  421. package/skills/gsd-cleanup/SKILL.md +1 -0
  422. package/skills/gsd-code-review/SKILL.md +2 -1
  423. package/skills/gsd-complete-milestone/SKILL.md +1 -0
  424. package/skills/gsd-config/SKILL.md +1 -0
  425. package/skills/gsd-debug/SKILL.md +1 -0
  426. package/skills/gsd-execute-phase/SKILL.md +1 -1
  427. package/skills/gsd-graphify/SKILL.md +1 -0
  428. package/skills/gsd-health/SKILL.md +1 -0
  429. package/skills/gsd-mempalace-capture/SKILL.md +1 -0
  430. package/skills/gsd-mempalace-recall/SKILL.md +1 -0
  431. package/skills/gsd-new-milestone/SKILL.md +1 -0
  432. package/skills/gsd-new-project/SKILL.md +1 -0
  433. package/skills/gsd-next/SKILL.md +1 -0
  434. package/skills/gsd-ns-workflow/SKILL.md +1 -0
  435. package/skills/gsd-pause-work/SKILL.md +1 -0
  436. package/skills/gsd-phase/SKILL.md +2 -1
  437. package/skills/gsd-pr-branch/SKILL.md +1 -0
  438. package/skills/gsd-quick-batch/SKILL.md +105 -0
  439. package/skills/gsd-resume-work/SKILL.md +1 -0
  440. package/skills/gsd-review-backlog/SKILL.md +1 -0
  441. package/skills/gsd-settings/SKILL.md +2 -1
  442. package/skills/gsd-stats/SKILL.md +1 -0
  443. package/skills/gsd-surface/SKILL.md +18 -8
  444. package/skills/gsd-thread/SKILL.md +1 -0
  445. package/skills/gsd-workspace/SKILL.md +1 -0
  446. package/skills/gsd-workstreams/SKILL.md +1 -0
  447. package/vscode/package.json +1 -1
  448. package/gsd-core/templates/claude-md.md +0 -145
  449. package/gsd-core/templates/codebase/concerns.md +0 -310
  450. package/gsd-core/templates/codebase/conventions.md +0 -307
  451. package/gsd-core/templates/codebase/integrations.md +0 -280
  452. package/gsd-core/templates/codebase/structure.md +0 -285
  453. package/gsd-core/templates/codebase/testing.md +0 -480
  454. package/gsd-core/templates/debug-subagent-prompt.md +0 -91
  455. package/gsd-core/templates/discovery.md +0 -146
@@ -0,0 +1,376 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ /**
5
+ * #4196: npm-audit baseline diff.
6
+ *
7
+ * The #3588 gate (tests/npm-integrity-gate.test.cjs) used to fail on ANY
8
+ * advisory present in the production tree, regardless of whether the PR
9
+ * being checked introduced it. Because npm's advisory database updates
10
+ * continuously and independently of repo state, that made the gate fail
11
+ * for reasons no PR caused -- see #4196 for the incident where PR #4188
12
+ * passed this gate at merge time and failed it ~15 minutes later on the
13
+ * identical commit, purely because a new advisory was disclosed in the
14
+ * interim.
15
+ *
16
+ * This module computes which vulnerable packages are NEW relative to a
17
+ * baseline tree (typically the PR's target branch), so the gate blocks a
18
+ * PR only for advisories it actually introduces -- a pre-existing advisory
19
+ * in an untouched transitive dependency no longer blocks unrelated work.
20
+ */
21
+
22
+ const fs = require('node:fs');
23
+ const os = require('node:os');
24
+ const path = require('node:path');
25
+ const { execFileSync } = require('node:child_process');
26
+
27
+ // Per-attempt timeout. 60s comfortably covers the worst *working* latency
28
+ // measured against this endpoint (43.41s, see #4260) while staying well
29
+ // under the old single-shot 180s budget once multiplied by AUDIT_MAX_ATTEMPTS.
30
+ const AUDIT_ATTEMPT_TIMEOUT_MS = 60_000;
31
+ // Bounded retry, not unbounded -- a registry-side outage must still fail the
32
+ // gate eventually (see #4260's own caveat: silently disarming a required
33
+ // security check on a transport error is worse than failing it).
34
+ const AUDIT_MAX_ATTEMPTS = 3;
35
+ // Exponential backoff base between attempts (2s, 4s for attempts 1->2, 2->3).
36
+ const AUDIT_BACKOFF_BASE_MS = 2_000;
37
+
38
+ /**
39
+ * Synchronous sleep (execFileSync-based retry logic is itself synchronous,
40
+ * so backoff between attempts must be too). Uses Atomics.wait on a throwaway
41
+ * SharedArrayBuffer, the standard Node pattern for a blocking sleep with no
42
+ * external dependency.
43
+ */
44
+ function sleepSyncMs(ms) {
45
+ const sab = new SharedArrayBuffer(4);
46
+ Atomics.wait(new Int32Array(sab), 0, 0, ms);
47
+ }
48
+
49
+ /**
50
+ * True when `error` represents a child process execFileSync killed via its
51
+ * `timeout` option (e.g. AUDIT_ATTEMPT_TIMEOUT_MS firing against a
52
+ * slow/degraded npm registry) rather than one that exited normally with a
53
+ * non-zero code. Node sets `killed: true` and `signal` to the kill signal in
54
+ * that case (see the child_process docs for execFileSync's `timeout`
55
+ * option); a normal "npm audit found advisories" exit has neither set. The
56
+ * distinction matters because a killed process's stdout is truncated
57
+ * mid-write, not complete JSON -- treating it as recoverable JSON produces a
58
+ * misleading `Unexpected end of JSON input` instead of naming the real
59
+ * cause.
60
+ */
61
+ function isTimeoutKill(error) {
62
+ return Boolean(error && (error.killed === true || error.signal));
63
+ }
64
+
65
+ /**
66
+ * Builds the standard timeout-kill error message, shared by every caller
67
+ * that classifies a killed npm audit process after exhausting retries (see
68
+ * isTimeoutKill, runNpmAuditWithRetry) -- kept in one place so the message
69
+ * can't independently drift between callers, per this repo's Generative Fix
70
+ * Divergence anti-pattern.
71
+ *
72
+ * Includes whatever `error.stderr` execFileSync captured before the last
73
+ * kill (Node buffers stdout/stderr from a killed child in-memory and
74
+ * attaches them to the thrown error; without surfacing it here that data
75
+ * was simply discarded, giving zero diagnostic signal into WHY npm was
76
+ * still running when the timeout fired).
77
+ */
78
+ function buildTimeoutKillError(cwd, error, attempts = 1) {
79
+ const stderr = error && error.stderr
80
+ ? (Buffer.isBuffer(error.stderr) ? error.stderr.toString('utf-8') : String(error.stderr))
81
+ : '';
82
+ const stderrSuffix = stderr.trim()
83
+ ? `\n\nCaptured stderr before the last kill:\n${stderr.trim().slice(0, 2000)}`
84
+ : '\n\n(no stderr was captured before the last kill)';
85
+ const attemptsPhrase = attempts > 1
86
+ ? `after ${attempts} attempts (each up to ${AUDIT_ATTEMPT_TIMEOUT_MS}ms, with exponential backoff between)`
87
+ : `after ${AUDIT_ATTEMPT_TIMEOUT_MS}ms`;
88
+ return new Error(
89
+ `npm audit timed out ${attemptsPhrase} in ${cwd} -- this is not a JSON ` +
90
+ `parse failure, npm audit did not finish. The npm registry's advisories endpoint ` +
91
+ `may be degraded; check https://status.npmjs.org before assuming a code regression.` +
92
+ stderrSuffix,
93
+ );
94
+ }
95
+
96
+ const AUDIT_DIFF_REASON = Object.freeze({
97
+ OK_NO_NEW_VULNERABILITIES: 'ok_no_new_vulnerabilities',
98
+ FAIL_NEW_VULNERABLE_PACKAGE: 'fail_new_vulnerable_package',
99
+ });
100
+
101
+ /**
102
+ * Pure diff: which package names are vulnerable in `headVulnerabilities`
103
+ * but were NOT already vulnerable in `baselineVulnerabilities`.
104
+ *
105
+ * Both args are the `.vulnerabilities` object from `npm audit --json`
106
+ * (keyed by package name). Matched by package NAME only -- not by the
107
+ * specific advisory ID or severity -- so a package that stays vulnerable
108
+ * across a *different* newly-disclosed advisory for the same package is
109
+ * still "pre-existing", not new. A package whose vulnerability *worsens*
110
+ * while remaining the same package name is deliberately NOT flagged here;
111
+ * that tradeoff keeps the predicate simple and matched to the #4196
112
+ * incident shape (a transitive dependency neither side of the diff
113
+ * touched). Severity escalation on an already-known-vulnerable package is
114
+ * exactly the kind of thing the scheduled Dependabot channel should catch
115
+ * instead (see #4196, PR #4200's auto-merge workflow).
116
+ */
117
+ function diffNewVulnerablePackages(baselineVulnerabilities, headVulnerabilities) {
118
+ const baselineNames = new Set(Object.keys(baselineVulnerabilities || {}));
119
+ return Object.keys(headVulnerabilities || {}).filter((name) => !baselineNames.has(name));
120
+ }
121
+
122
+ /**
123
+ * Typed verdict wrapping diffNewVulnerablePackages. `ok: false` means the
124
+ * diff (head vs baseline) is non-empty -- this PR/push introduced at
125
+ * least one newly-vulnerable package.
126
+ */
127
+ function evaluateAuditDiff({ baselineVulnerabilities, headVulnerabilities }) {
128
+ const newlyIntroduced = diffNewVulnerablePackages(baselineVulnerabilities, headVulnerabilities);
129
+ if (newlyIntroduced.length > 0) {
130
+ return { ok: false, reason: AUDIT_DIFF_REASON.FAIL_NEW_VULNERABLE_PACKAGE, newlyIntroduced };
131
+ }
132
+ return {
133
+ ok: true,
134
+ reason: AUDIT_DIFF_REASON.OK_NO_NEW_VULNERABILITIES,
135
+ preExisting: Object.keys(headVulnerabilities || {}),
136
+ };
137
+ }
138
+
139
+ /**
140
+ * Runs `npm audit <args> --json` in `cwd` with bounded retry + exponential
141
+ * backoff. A per-attempt timeout-kill (see isTimeoutKill) is retried rather
142
+ * than failed immediately -- #4260: the audit backend has real, independent
143
+ * latency variance from the rest of the registry (measured: 43.41s vs 0.20s
144
+ * for a plain registry fetch, and two outright non-responses in the same
145
+ * window), and a single 180s attempt with no retry meant any one bad moment
146
+ * failed a REQUIRED gate on a transport hiccup, not a real advisory. A
147
+ * non-timeout failure (e.g. a genuine non-zero exit with recoverable stdout,
148
+ * or an unrecoverable error) is NOT retried -- only a confirmed timeout-kill
149
+ * is, since retrying a deterministic failure wastes the budget without
150
+ * changing the outcome.
151
+ *
152
+ * Exhausting all attempts still fails the gate (see #4260's own caveat:
153
+ * silently skipping a required security check on a transport error is a
154
+ * worse failure mode than occasionally re-running CI).
155
+ */
156
+ function runNpmAuditWithRetry(cwd, args, { execFileSyncImpl = execFileSync, sleepImpl = sleepSyncMs } = {}) {
157
+ const isWindows = process.platform === 'win32';
158
+ const npmCandidates = isWindows ? ['npm.cmd', 'npm'] : ['npm'];
159
+ let lastTimeoutError = null;
160
+
161
+ for (let attempt = 1; attempt <= AUDIT_MAX_ATTEMPTS; attempt += 1) {
162
+ let out;
163
+ let timedOutThisAttempt = false;
164
+ let lastErr = null;
165
+
166
+ for (const npmCmd of npmCandidates) {
167
+ try {
168
+ out = execFileSyncImpl(npmCmd, args, {
169
+ cwd,
170
+ encoding: 'utf-8',
171
+ stdio: ['ignore', 'pipe', 'pipe'],
172
+ timeout: AUDIT_ATTEMPT_TIMEOUT_MS,
173
+ shell: isWindows,
174
+ });
175
+ lastErr = null;
176
+ break;
177
+ } catch (e) {
178
+ if (isTimeoutKill(e)) {
179
+ timedOutThisAttempt = true;
180
+ lastErr = e;
181
+ break; // do not burn the alt npm-candidate slot on a timeout; go to the next retry attempt instead
182
+ }
183
+ // `npm audit` exits non-zero when advisories are present; the JSON is
184
+ // still on stdout in that case. Recover and let the caller classify —
185
+ // but only when stdout actually CARRIES the JSON: an audit that was
186
+ // killed or aborted can exit non-zero with EMPTY stdout, and accepting
187
+ // the empty string here surfaces as a bare `SyntaxError: Unexpected
188
+ // end of JSON input` at the parse below, hiding the captured error
189
+ // (observed on CI 2026-09-03, both lanes; cause undetermined).
190
+ const recovered = e && typeof e.stdout !== 'undefined' && e.stdout !== null
191
+ ? (Buffer.isBuffer(e.stdout) ? e.stdout.toString('utf-8') : String(e.stdout))
192
+ : '';
193
+ if (recovered.trim()) {
194
+ out = recovered;
195
+ lastErr = null;
196
+ break;
197
+ }
198
+ lastErr = e;
199
+ }
200
+ }
201
+
202
+ if (timedOutThisAttempt) {
203
+ lastTimeoutError = lastErr;
204
+ if (attempt < AUDIT_MAX_ATTEMPTS) {
205
+ sleepImpl(AUDIT_BACKOFF_BASE_MS * (2 ** (attempt - 1)));
206
+ continue;
207
+ }
208
+ throw buildTimeoutKillError(cwd, lastTimeoutError, attempt);
209
+ }
210
+
211
+ if (lastErr) throw lastErr; // non-timeout failure: fail immediately, no retry
212
+
213
+ const parsed = JSON.parse(out);
214
+ if (parsed && parsed.metadata && parsed.metadata.vulnerabilities) {
215
+ return parsed;
216
+ }
217
+ throw new Error(`Unexpected npm audit JSON shape in ${cwd}: missing metadata.vulnerabilities`);
218
+ }
219
+ // Unreachable (the loop always returns or throws), but keep a fallback
220
+ // throw so a future refactor mistake fails loudly instead of returning
221
+ // undefined.
222
+ throw buildTimeoutKillError(cwd, lastTimeoutError, AUDIT_MAX_ATTEMPTS);
223
+ }
224
+
225
+ /**
226
+ * Runs `npm audit --package-lock-only --omit=dev --json` in `cwd` and
227
+ * returns the parsed JSON, or `null` if `cwd` has no package.json or no
228
+ * package-lock.json (not an auditable tree -- callers treat this as
229
+ * "skip"/"no baseline available", not an error).
230
+ *
231
+ * `--package-lock-only` deliberately avoids requiring `node_modules/` to
232
+ * be installed: it lets a baseline tree be audited from nothing but an
233
+ * extracted package.json + package-lock.json (see extractBaselineTree),
234
+ * without a second full `npm ci`.
235
+ */
236
+ function runPackageLockAudit(cwd, opts = {}) {
237
+ if (!fs.existsSync(path.join(cwd, 'package.json'))) return null;
238
+ if (!fs.existsSync(path.join(cwd, 'package-lock.json'))) return null;
239
+ return runNpmAuditWithRetry(cwd, ['audit', '--package-lock-only', '--omit=dev', '--json'], opts);
240
+ }
241
+
242
+ /**
243
+ * Runs `npm audit --omit=dev --json` against the REAL installed node_modules
244
+ * tree in `cwd` (unlike runPackageLockAudit's --package-lock-only mode,
245
+ * which only needs package-lock.json on disk). Returns `null` if `cwd` has
246
+ * no package.json or no node_modules/ (not an auditable/installed tree --
247
+ * callers treat this as "skip", not an error).
248
+ */
249
+ function runInstalledTreeAudit(cwd, opts = {}) {
250
+ if (!fs.existsSync(path.join(cwd, 'package.json'))) return null;
251
+ if (!fs.existsSync(path.join(cwd, 'node_modules'))) return null;
252
+ return runNpmAuditWithRetry(cwd, ['audit', '--omit=dev', '--json'], opts);
253
+ }
254
+
255
+ /**
256
+ * Extracts package.json + package-lock.json (optionally under `subdir`,
257
+ * e.g. 'sdk') from `ref` at git object level into a fresh temp directory --
258
+ * no working-tree checkout, no `node_modules` install. Returns the temp
259
+ * dir path, or `null` if `ref` cannot be resolved locally (e.g. a shallow
260
+ * clone that never fetched it) or either file is absent at that ref --
261
+ * callers treat `null` as "no baseline available", not an error.
262
+ */
263
+ function extractBaselineTree(ref, repoRoot, subdir = '') {
264
+ const rel = (name) => (subdir ? path.posix.join(subdir, name) : name);
265
+ let pkgJson;
266
+ let lockJson;
267
+ try {
268
+ pkgJson = execFileSync('git', ['show', `${ref}:${rel('package.json')}`], {
269
+ cwd: repoRoot,
270
+ encoding: 'utf-8',
271
+ stdio: ['ignore', 'pipe', 'ignore'],
272
+ });
273
+ lockJson = execFileSync('git', ['show', `${ref}:${rel('package-lock.json')}`], {
274
+ cwd: repoRoot,
275
+ encoding: 'utf-8',
276
+ stdio: ['ignore', 'pipe', 'ignore'],
277
+ });
278
+ } catch {
279
+ return null;
280
+ }
281
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-audit-baseline-'));
282
+ fs.writeFileSync(path.join(dir, 'package.json'), pkgJson);
283
+ fs.writeFileSync(path.join(dir, 'package-lock.json'), lockJson);
284
+ return dir;
285
+ }
286
+
287
+ // All-zeros is git's documented sentinel for "this ref did not exist
288
+ // before this push" (a brand-new branch's first push) -- never a real
289
+ // commit to diff against.
290
+ const NULL_SHA = '0000000000000000000000000000000000000000';
291
+
292
+ /**
293
+ * Resolves the git ref to diff against, in priority order:
294
+ * 1. AUDIT_BASELINE_REF env var -- the primary mechanism. CI sets this
295
+ * explicitly (see .github/workflows/test.yml) to github.event.pull_
296
+ * request.base.sha on a pull_request event, or github.event.before on
297
+ * a push event -- both pinned, race-free values Git/GitHub track for
298
+ * exactly this purpose. Prefer this over anything below whenever the
299
+ * caller can provide it.
300
+ * 2. GITHUB_BASE_REF (GitHub Actions sets this on pull_request events)
301
+ * resolved against the LIVE origin/<branch> tip. Only reached if
302
+ * AUDIT_BASELINE_REF wasn't set -- e.g. a workflow that forgot to
303
+ * wire it. origin/<branch> can advance mid-run (see the GSD_EMITTED_
304
+ * BASE precedent in test.yml), so this is a degraded fallback, not
305
+ * the intended path for pull_request events in this repo's own CI.
306
+ * 3. On a `push` event, `HEAD~1` -- correct ONLY when the push added
307
+ * exactly one commit (true for a squash-merge or a single ordinary
308
+ * commit). This repo also allows rebase-merge (allow_rebase_merge:
309
+ * true), which can land a PR as several discrete commits in one
310
+ * push -- HEAD~1 then lands on an EARLIER commit in the same push,
311
+ * which may already contain a vulnerable package that commit itself
312
+ * introduced, silently marking it "pre-existing". CI never reaches
313
+ * this branch (AUDIT_BASELINE_REF is always set by test.yml for
314
+ * push events); it exists only for out-of-band invocations (e.g.
315
+ * gsd-test) that don't set any of the above.
316
+ * 4. `origin/next`, else a plain local branch named `next` (gsd-test's
317
+ * sandbox fetches the base as a local branch, not a remote-tracking
318
+ * ref -- see gsd-test-merges-into-LOCAL-base-branch in this repo's
319
+ * own operational notes), if either exists locally (this repo's
320
+ * integration branch -- matches DEFAULT_BASE in
321
+ * scripts/changeset/lint.cjs).
322
+ * Returns '' if none resolve -- callers fall back to strict zero-tolerance
323
+ * rather than silently skipping the gate.
324
+ */
325
+ function resolveBaselineRef(repoRoot) {
326
+ if (process.env.AUDIT_BASELINE_REF) return process.env.AUDIT_BASELINE_REF;
327
+ if (process.env.GITHUB_BASE_REF) return `origin/${process.env.GITHUB_BASE_REF}`;
328
+ if (process.env.GITHUB_EVENT_NAME === 'push') {
329
+ try {
330
+ const parent = execFileSync('git', ['rev-parse', '--verify', 'HEAD~1'], {
331
+ cwd: repoRoot,
332
+ encoding: 'utf-8',
333
+ stdio: ['ignore', 'pipe', 'ignore'],
334
+ }).trim();
335
+ if (parent && parent !== NULL_SHA) return parent;
336
+ } catch {
337
+ // not enough history; fall through
338
+ }
339
+ }
340
+ try {
341
+ execFileSync('git', ['rev-parse', '--verify', 'origin/next'], {
342
+ cwd: repoRoot,
343
+ stdio: 'ignore',
344
+ });
345
+ return 'origin/next';
346
+ } catch {
347
+ // fall through to a plain local branch
348
+ }
349
+ try {
350
+ execFileSync('git', ['rev-parse', '--verify', 'next'], {
351
+ cwd: repoRoot,
352
+ stdio: 'ignore',
353
+ });
354
+ return 'next';
355
+ } catch {
356
+ return '';
357
+ }
358
+ }
359
+
360
+ module.exports = {
361
+ AUDIT_DIFF_REASON,
362
+ diffNewVulnerablePackages,
363
+ evaluateAuditDiff,
364
+ runPackageLockAudit,
365
+ runInstalledTreeAudit,
366
+ runNpmAuditWithRetry,
367
+ extractBaselineTree,
368
+ resolveBaselineRef,
369
+ isTimeoutKill,
370
+ buildTimeoutKillError,
371
+ sleepSyncMs,
372
+ AUDIT_ATTEMPT_TIMEOUT_MS,
373
+ AUDIT_MAX_ATTEMPTS,
374
+ AUDIT_BACKOFF_BASE_MS,
375
+ NULL_SHA,
376
+ };
@@ -171,6 +171,28 @@ ALLOWLIST=(
171
171
  # allowlist cannot reach it either, because the literal `child_process` is
172
172
  # not adjacent to `.exec`. See the note at the pattern itself.
173
173
  'tests/continuation-grammar-parity.test.cjs'
174
+ # #3676 row 11b — quick-batch's task-list parser must treat a
175
+ # prompt-injection-shaped task description as inert data, never
176
+ # interpreted. The fixture has to be a real "ignore all previous
177
+ # instructions…" phrase or the test asserts nothing: it is the payload the
178
+ # parser is required to carry byte-for-byte through createBatch and STATE
179
+ # rendering, never a command. Same DEFECT.PROMPT-INJECTION-SCAN-COLLISION
180
+ # class as the input-validator fixtures above.
181
+ 'tests/quick-batch.test.cjs'
182
+ # #4209 — the regression test pinning gsd-code-reviewer.md's untrusted-evidence
183
+ # contract discusses the injection attack it defends against (embedded
184
+ # redirection, "act as an instruction") without performing it. gsd-code-reviewer.md
185
+ # ITSELF is deliberately NOT allowlisted — R2 (#4209 review): a production prompt
186
+ # that ingests untrusted third-party output should stay in-scope for this scanner,
187
+ # not be exempted wholesale; its defense-contract wording was reworded instead to
188
+ # avoid literally spelling out the trigger phrase (see git blame on that section).
189
+ # Same DEFECT.PROMPT-INJECTION-SCAN-COLLISION class as the entries above.
190
+ 'tests/code-review-pipeline-regression.test.cjs'
191
+ # #4209 agy-F1 regression test — a crafted-filename fixture containing the literal
192
+ # phrase "Ignore all prior instructions." to prove validatePaths rejects it before
193
+ # it ever reaches an external-reviewer prompt. Discusses/detects the attack pattern
194
+ # as test data, never performs it. Same class as the entries above.
195
+ 'tests/reviewer-step-dispatch.test.cjs'
174
196
  )
175
197
 
176
198
  is_allowlisted() {
@@ -30,6 +30,7 @@ const { runMain } = require('./lib/cli-exit.cjs');
30
30
  const ISSUE_LINK_REASON = Object.freeze({
31
31
  OK_CLOSING_KEYWORD: 'ok_closing_keyword',
32
32
  OK_BACKMERGE_EXEMPT: 'ok_backmerge_exempt',
33
+ OK_DEPENDABOT_EXEMPT: 'ok_dependabot_exempt',
33
34
  OK_FOLLOWUP_REFERENCE: 'ok_followup_reference',
34
35
  FAIL_NO_ISSUE_REFERENCE: 'fail_no_issue_reference',
35
36
  FAIL_REFERENCE_NEEDS_CLOSING: 'fail_reference_needs_closing',
@@ -41,6 +42,14 @@ const ISSUE_LINK_REASON = Object.freeze({
41
42
  // ONLY when combined with `sameRepo === true` below (see header comment).
42
43
  const BACKMERGE_BRANCH_PREFIX = 'chore/backmerge-main-to-next-';
43
44
 
45
+ // #4196: Dependabot has no mechanism to link a PR it opens to a repo issue —
46
+ // its alerts live in the Security tab, not as issues, so there is nothing
47
+ // for it to reference. `pr.user.login` is authenticated by GitHub (not
48
+ // forgeable by a crafted title/branch), so this is safe without a sameRepo
49
+ // conjunct: no external actor can make GitHub report this login for a PR
50
+ // they opened.
51
+ const DEPENDABOT_LOGIN = 'dependabot[bot]';
52
+
44
53
  // A follow-up-only PR (references an issue without closing it) is only
45
54
  // allowed to skip the closing keyword when every changed file is a test or
46
55
  // doc file — i.e. it cannot be the PR that actually implements the fix.
@@ -122,7 +131,11 @@ function allPathsAreTestsOrDocs(changedFiles) {
122
131
  });
123
132
  }
124
133
 
125
- function evaluateIssueLink({ prBody, headRef, sameRepo, changedFiles, changedFilesTotal }) {
134
+ function evaluateIssueLink({ prBody, headRef, sameRepo, authorLogin, changedFiles, changedFilesTotal }) {
135
+ if (authorLogin === DEPENDABOT_LOGIN) {
136
+ return { ok: true, reason: ISSUE_LINK_REASON.OK_DEPENDABOT_EXEMPT };
137
+ }
138
+
126
139
  if (hasClosingKeyword(prBody)) {
127
140
  return { ok: true, reason: ISSUE_LINK_REASON.OK_CLOSING_KEYWORD };
128
141
  }
@@ -159,6 +172,7 @@ function main() {
159
172
  prBody: process.env.PR_BODY || '',
160
173
  headRef: process.env.HEAD_REF || '',
161
174
  sameRepo: process.env.SAME_REPO === 'true',
175
+ authorLogin: process.env.PR_AUTHOR_LOGIN || '',
162
176
  changedFiles,
163
177
  changedFilesTotal,
164
178
  });
@@ -179,6 +193,7 @@ if (require.main === module) runMain(main);
179
193
  module.exports = {
180
194
  ISSUE_LINK_REASON,
181
195
  BACKMERGE_BRANCH_PREFIX,
196
+ DEPENDABOT_LOGIN,
182
197
  EXEMPT_PATH_PREFIXES,
183
198
  EXCLUDED_ROOT_DOCS,
184
199
  CLOSING_KEYWORD_REGEX,
@@ -89,10 +89,149 @@ function measureWorkflows(dir = WORKFLOWS_DIR) {
89
89
  return measureMdFiles(dir);
90
90
  }
91
91
 
92
+ /**
93
+ * #4261: the reserved margin, as a fraction of a tier's hard cap.
94
+ *
95
+ * The hard caps are red lines and stay exactly where they are. This is the
96
+ * second, softer level the caps never had: `execute-phase.md` already carries
97
+ * a hand-rolled version of this shape (a hard `< 93600` plus a `<= 93400`
98
+ * margin whose own message says it exists "so minor future edits don't
99
+ * re-trip the gate"), and it is the only capped file that does. Everywhere
100
+ * else a file is either fine or already over, with nothing in between — so
101
+ * the first signal a contributor gets is a failure, and by then the cheap
102
+ * moment to extract has passed.
103
+ *
104
+ * 95% is deliberately not derived from anything. It is the round number the
105
+ * issue proposed, and the census below is what makes it reviewable: if it
106
+ * turns out to name too many or too few files, that is visible in one table
107
+ * rather than argued from first principles.
108
+ */
109
+ const MARGIN_RATIO = 0.95;
110
+
111
+ /**
112
+ * The reserved-margin threshold for a hard cap, in bytes.
113
+ *
114
+ * Floor, not round: the margin must never land ON or above the cap it is
115
+ * meant to sit under, however small the cap.
116
+ *
117
+ * @param {number} cap - Tier hard cap in bytes.
118
+ * @returns {number} Margin threshold in bytes.
119
+ */
120
+ function marginFor(cap) {
121
+ return Math.floor(cap * MARGIN_RATIO);
122
+ }
123
+
124
+ /**
125
+ * Build the headroom census for a set of measured files.
126
+ *
127
+ * Sorted by pressure (least headroom first) because that is the reading
128
+ * order that matters: the top row is the file that will break next.
129
+ *
130
+ * @param {Object<string, number>} sizes - Map of filename -> LF byte size.
131
+ * @param {function(string): {tier: string, cap: number}} capFor - Tier lookup, keyed by stem.
132
+ * @returns {Array<{name: string, tier: string, bytes: number, cap: number, margin: number, headroom: number, usedPct: number, overMargin: boolean}>}
133
+ */
134
+ function buildHeadroomRows(sizes, capFor) {
135
+ return Object.entries(sizes)
136
+ .map(([file, bytes]) => {
137
+ const name = file.replace(/\.md$/, '');
138
+ const { tier, cap } = capFor(name);
139
+ const margin = marginFor(cap);
140
+ return {
141
+ name,
142
+ tier,
143
+ bytes,
144
+ cap,
145
+ margin,
146
+ headroom: cap - bytes,
147
+ usedPct: (bytes / cap) * 100,
148
+ overMargin: bytes > margin,
149
+ };
150
+ })
151
+ .sort((a, b) => a.headroom - b.headroom || a.name.localeCompare(b.name));
152
+ }
153
+
154
+ /**
155
+ * Render the census as a fixed-width text table for the test diagnostics.
156
+ *
157
+ * @param {ReturnType<typeof buildHeadroomRows>} rows
158
+ * @param {{limit?: number}} [opts] - How many rows to render (default: all).
159
+ * @returns {string[]} Lines, ready to hand to `t.diagnostic` one at a time.
160
+ */
161
+ function formatHeadroomTable(rows, { limit = Infinity } = {}) {
162
+ const shown = rows.slice(0, limit);
163
+ const width = Math.max(4, ...shown.map((r) => r.name.length));
164
+ const head = `${'file'.padEnd(width)} ${'tier'.padEnd(7)} ${'bytes'.padStart(7)} ${'cap'.padStart(7)} ${'margin'.padStart(7)} ${'headroom'.padStart(8)} ${'used'.padStart(6)}`;
165
+ const body = shown.map(
166
+ (r) =>
167
+ `${r.name.padEnd(width)} ${r.tier.padEnd(7)} ${String(r.bytes).padStart(7)} ${String(r.cap).padStart(7)} ${String(r.margin).padStart(7)} ${String(r.headroom).padStart(8)} ${r.usedPct.toFixed(1).padStart(5)}%`,
168
+ );
169
+ return [head, ...body];
170
+ }
171
+
172
+ /**
173
+ * Render the census as a GitHub job-summary markdown table.
174
+ *
175
+ * Only the rows over the reserved margin: a job summary that lists all 124
176
+ * capped files is a log dump nobody reads, and every row below the margin is
177
+ * by definition not the problem. The count of the rest is still reported so
178
+ * an empty table cannot be mistaken for an unmeasured one.
179
+ *
180
+ * @param {string} title - Section heading (e.g. `'Agent size headroom'`).
181
+ * @param {ReturnType<typeof buildHeadroomRows>} rows
182
+ * @returns {string} Markdown block.
183
+ */
184
+ function buildHeadroomSummaryMarkdown(title, rows) {
185
+ const pressured = rows.filter((r) => r.overMargin);
186
+ const lines = [`### ${title}`, ''];
187
+ if (pressured.length === 0) {
188
+ lines.push(`All ${rows.length} files are under the ${Math.round(MARGIN_RATIO * 100)}% reserved margin.`);
189
+ return `${lines.join('\n')}\n`;
190
+ }
191
+ lines.push(
192
+ `**${pressured.length} of ${rows.length}** files are over the ${Math.round(MARGIN_RATIO * 100)}% reserved margin.`,
193
+ '',
194
+ '| file | tier | bytes | cap | headroom | used |',
195
+ '| --- | --- | ---: | ---: | ---: | ---: |',
196
+ );
197
+ for (const r of pressured) {
198
+ lines.push(`| \`${r.name}\` | ${r.tier} | ${r.bytes} | ${r.cap} | ${r.headroom} | ${r.usedPct.toFixed(1)}% |`);
199
+ }
200
+ return `${lines.join('\n')}\n`;
201
+ }
202
+
203
+ /**
204
+ * Append a census block to `$GITHUB_STEP_SUMMARY` when running in CI.
205
+ *
206
+ * No-op off CI, and never throws: this is reporting, and a test suite must
207
+ * not go red because a summary file was not writable.
208
+ *
209
+ * @param {string} title - Section heading.
210
+ * @param {ReturnType<typeof buildHeadroomRows>} rows
211
+ * @param {NodeJS.ProcessEnv} [env]
212
+ * @returns {boolean} Whether anything was written.
213
+ */
214
+ function appendHeadroomStepSummary(title, rows, env = process.env) {
215
+ if (!env.GITHUB_STEP_SUMMARY) return false;
216
+ try {
217
+ fs.appendFileSync(env.GITHUB_STEP_SUMMARY, `${buildHeadroomSummaryMarkdown(title, rows)}\n`);
218
+ return true;
219
+ } catch (err) {
220
+ process.stderr.write(`workflow-size: could not write GITHUB_STEP_SUMMARY: ${err.message}\n`);
221
+ return false;
222
+ }
223
+ }
224
+
92
225
  module.exports = {
93
226
  WORKFLOWS_DIR,
227
+ MARGIN_RATIO,
94
228
  lfByteCount,
95
229
  listWorkflowStems,
96
230
  measureMdFiles,
97
231
  measureWorkflows,
232
+ marginFor,
233
+ buildHeadroomRows,
234
+ formatHeadroomTable,
235
+ buildHeadroomSummaryMarkdown,
236
+ appendHeadroomStepSummary,
98
237
  };
@@ -5,6 +5,7 @@ allowed-tools:
5
5
  - Read
6
6
  - Write
7
7
  - Bash
8
+ - Grep
8
9
  - AskUserQuestion
9
10
  ---
10
11
 
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: gsd-code-review
3
3
  description: "Review source files changed during a phase for bugs, security issues, and code quality problems"
4
- argument-hint: "<phase-number> [--depth=quick|standard|deep] [--files file1,file2,...] [--fix [--all] [--auto]]"
4
+ argument-hint: "<phase-number> [--depth=quick|standard|deep] [--files file1,file2,...] [--fix [--all] [--auto]] [reviewer-lane flags]"
5
5
  allowed-tools:
6
6
  - Read
7
7
  - Bash
@@ -26,6 +26,7 @@ Arguments:
26
26
  - `--fix` (optional) — after review completes (or if REVIEW.md already exists), auto-apply fixes found. Spawns gsd-code-fixer agent. Accepts sub-flags:
27
27
  - `--all` — include Info findings in fix scope (default: Critical + Warning only)
28
28
  - `--auto` — enable fix + re-review iteration loop, capped at 3 iterations
29
+ - Optional reviewer-lane flags (#4209) — any flag returned by `gsd_run review-lane flags` (the canonical reviewer-lane roster; e.g. `--codex`, `--agy`) requests that lane independently review the same already-resolved scope alongside the internal `gsd-code-reviewer` agent. Its findings are corroborating evidence only — `gsd-code-reviewer` alone verifies each claim against the actual source and writes REVIEW.md; there is exactly one REVIEW.md schema. No reviewer-lane flag (the default) reviews with only the internal agent, byte-for-byte unchanged from before #4209.
29
30
 
30
31
  Output: {padded_phase}-REVIEW.md in phase directory + inline summary of findings
31
32
  </objective>
@@ -6,6 +6,7 @@ allowed-tools:
6
6
  - Read
7
7
  - Write
8
8
  - Bash
9
+ - Grep
9
10
  ---
10
11
 
11
12
 
@@ -6,6 +6,7 @@ allowed-tools:
6
6
  - Read
7
7
  - Write
8
8
  - Bash
9
+ - Grep
9
10
  - AskUserQuestion
10
11
  ---
11
12
 
@@ -6,6 +6,7 @@ allowed-tools:
6
6
  - Read
7
7
  - Write
8
8
  - Bash
9
+ - Grep
9
10
  - Agent
10
11
  - AskUserQuestion
11
12
  ---
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: gsd-execute-phase
3
- description: "Execute all plans in a phase with wave-based parallelization"
3
+ description: "SDD phase execution — execute all plans in a phase with dependency-aware wave parallelization"
4
4
  argument-hint: "<phase-number> [--wave N] [--gaps-only] [--interactive] [--tdd]"
5
5
  allowed-tools:
6
6
  - Read
@@ -5,6 +5,7 @@ argument-hint: "[build|query <term>|status|diff]"
5
5
  allowed-tools:
6
6
  - Read
7
7
  - Bash
8
+ - Grep
8
9
  ---
9
10
 
10
11