@opengsd/gsd-core 1.13.0 → 1.15.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 (441) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/README.ja-JP.md +3 -3
  4. package/README.ko-KR.md +3 -3
  5. package/README.pt-BR.md +3 -3
  6. package/README.zh-CN.md +3 -3
  7. package/agents/gsd-advisor-researcher.compact.md +85 -0
  8. package/agents/gsd-ai-researcher.compact.md +96 -0
  9. package/agents/gsd-assumptions-analyzer.compact.md +81 -0
  10. package/agents/gsd-code-fixer.compact.md +459 -0
  11. package/agents/gsd-code-fixer.md +9 -8
  12. package/agents/gsd-code-reviewer.compact.md +269 -0
  13. package/agents/gsd-code-reviewer.md +15 -3
  14. package/agents/gsd-codebase-mapper.compact.md +760 -0
  15. package/agents/gsd-debug-session-manager.compact.md +360 -0
  16. package/agents/gsd-debug-session-manager.md +17 -2
  17. package/agents/gsd-debugger.md +2 -2
  18. package/agents/gsd-doc-classifier.compact.md +192 -0
  19. package/agents/gsd-doc-synthesizer.compact.md +200 -0
  20. package/agents/gsd-doc-verifier.compact.md +143 -0
  21. package/agents/gsd-doc-writer.compact.md +440 -0
  22. package/agents/gsd-dom-verifier.compact.md +138 -0
  23. package/agents/gsd-domain-researcher.compact.md +141 -0
  24. package/agents/gsd-eval-auditor.compact.md +160 -0
  25. package/agents/gsd-eval-auditor.md +1 -1
  26. package/agents/gsd-eval-planner.compact.md +137 -0
  27. package/agents/gsd-executor.md +13 -8
  28. package/agents/gsd-framework-selector.compact.md +82 -0
  29. package/agents/gsd-integration-checker.compact.md +245 -0
  30. package/agents/gsd-intel-updater.compact.md +226 -0
  31. package/agents/gsd-intel-updater.md +1 -1
  32. package/agents/gsd-mempalace-curator.compact.md +45 -0
  33. package/agents/gsd-nyquist-auditor.compact.md +179 -0
  34. package/agents/gsd-pattern-mapper.compact.md +275 -0
  35. package/agents/gsd-phase-researcher.md +19 -11
  36. package/agents/gsd-plan-checker.md +8 -7
  37. package/agents/gsd-planner.md +12 -8
  38. package/agents/gsd-project-researcher.compact.md +587 -0
  39. package/agents/gsd-project-researcher.md +1 -1
  40. package/agents/gsd-research-synthesizer.compact.md +212 -0
  41. package/agents/gsd-research-synthesizer.md +1 -1
  42. package/agents/gsd-roadmapper.compact.md +454 -0
  43. package/agents/gsd-roadmapper.md +13 -0
  44. package/agents/gsd-security-auditor.compact.md +162 -0
  45. package/agents/gsd-ui-auditor.compact.md +404 -0
  46. package/agents/gsd-ui-auditor.md +155 -17
  47. package/agents/gsd-ui-checker.compact.md +277 -0
  48. package/agents/gsd-ui-researcher.compact.md +282 -0
  49. package/agents/gsd-ui-researcher.md +1 -1
  50. package/agents/gsd-user-profiler.compact.md +108 -0
  51. package/agents/gsd-verifier.md +10 -9
  52. package/bin/install.js +848 -163
  53. package/commands/gsd/autonomous.md +2 -2
  54. package/commands/gsd/capture.md +1 -1
  55. package/commands/gsd/cleanup.md +1 -0
  56. package/commands/gsd/code-review.md +2 -1
  57. package/commands/gsd/complete-milestone.md +1 -0
  58. package/commands/gsd/config.md +1 -0
  59. package/commands/gsd/debug.md +1 -0
  60. package/commands/gsd/graphify.md +1 -0
  61. package/commands/gsd/health.md +1 -0
  62. package/commands/gsd/mempalace-capture.md +8 -3
  63. package/commands/gsd/mempalace-recall.md +1 -0
  64. package/commands/gsd/new-milestone.md +1 -0
  65. package/commands/gsd/new-project.md +1 -0
  66. package/commands/gsd/next.md +1 -0
  67. package/commands/gsd/pause-work.md +1 -0
  68. package/commands/gsd/phase.md +1 -0
  69. package/commands/gsd/plan-review-convergence.md +6 -6
  70. package/commands/gsd/pr-branch.md +1 -0
  71. package/commands/gsd/progress.md +1 -1
  72. package/commands/gsd/quick-batch.md +1 -1
  73. package/commands/gsd/resume-work.md +1 -0
  74. package/commands/gsd/review-backlog.md +1 -0
  75. package/commands/gsd/review.md +2 -3
  76. package/commands/gsd/settings.md +2 -1
  77. package/commands/gsd/stats.md +1 -0
  78. package/commands/gsd/thread.md +1 -0
  79. package/commands/gsd/workspace.md +1 -0
  80. package/commands/gsd/workstreams.md +1 -0
  81. package/gsd-core/bin/check-latest-version.cjs +8 -3
  82. package/gsd-core/bin/gsd-tools.cjs +672 -146
  83. package/gsd-core/bin/lib/adr-parser.cjs +4 -2
  84. package/gsd-core/bin/lib/artifacts.cjs +2 -1
  85. package/gsd-core/bin/lib/audit.cjs +119 -34
  86. package/gsd-core/bin/lib/broken-windows.cjs +168 -49
  87. package/gsd-core/bin/lib/capability-lifecycle.cjs +10 -6
  88. package/gsd-core/bin/lib/capability-loader.cjs +135 -1
  89. package/gsd-core/bin/lib/capability-registry.cjs +96 -189
  90. package/gsd-core/bin/lib/capability-source.cjs +19 -2
  91. package/gsd-core/bin/lib/capability-validator.cjs +14 -2
  92. package/gsd-core/bin/lib/check-command-router.cjs +213 -49
  93. package/gsd-core/bin/lib/code-review-depth.cjs +2 -2
  94. package/gsd-core/bin/lib/codex-agent-toml.cjs +21 -25
  95. package/gsd-core/bin/lib/commands.cjs +823 -112
  96. package/gsd-core/bin/lib/config-loader.cjs +66 -4
  97. package/gsd-core/bin/lib/config.cjs +186 -45
  98. package/gsd-core/bin/lib/coverage.cjs +1 -1
  99. package/gsd-core/bin/lib/decisions.cjs +164 -45
  100. package/gsd-core/bin/lib/external-descriptor-trust.cjs +29 -14
  101. package/gsd-core/bin/lib/frontmatter.cjs +13 -0
  102. package/gsd-core/bin/lib/graphify.cjs +10 -2
  103. package/gsd-core/bin/lib/gsd2-import.cjs +1 -2
  104. package/gsd-core/bin/lib/health-diagnostic-rules/state-consistency.cjs +12 -1
  105. package/gsd-core/bin/lib/health-diagnostic-rules/worktree-health.cjs +1 -1
  106. package/gsd-core/bin/lib/host-runtime-detection.cjs +9 -0
  107. package/gsd-core/bin/lib/init.cjs +614 -86
  108. package/gsd-core/bin/lib/install-engine.cjs +29 -3
  109. package/gsd-core/bin/lib/install-profiles.cjs +14 -0
  110. package/gsd-core/bin/lib/installer-migrations.cjs +41 -5
  111. package/gsd-core/bin/lib/loop-resolver.cjs +50 -31
  112. package/gsd-core/bin/lib/mcp-catalog.cjs +2 -2
  113. package/gsd-core/bin/lib/milestone.cjs +37 -13
  114. package/gsd-core/bin/lib/model-resolver.cjs +253 -53
  115. package/gsd-core/bin/lib/phase-command-router.cjs +16 -2
  116. package/gsd-core/bin/lib/phase-id-card.cjs +32 -0
  117. package/gsd-core/bin/lib/phase-id-display.cjs +78 -0
  118. package/gsd-core/bin/lib/phase-id.cjs +268 -27
  119. package/gsd-core/bin/lib/phase-lifecycle.cjs +61 -0
  120. package/gsd-core/bin/lib/phase-locator.cjs +29 -10
  121. package/gsd-core/bin/lib/phase.cjs +393 -88
  122. package/gsd-core/bin/lib/plan-document.cjs +49 -1
  123. package/gsd-core/bin/lib/planning-document.cjs +459 -0
  124. package/gsd-core/bin/lib/planning-inspect.cjs +52 -19
  125. package/gsd-core/bin/lib/planning-snapshot.cjs +61 -12
  126. package/gsd-core/bin/lib/planning-workspace.cjs +57 -3
  127. package/gsd-core/bin/lib/pr-branch-patterns.cjs +57 -0
  128. package/gsd-core/bin/lib/pristine-baseline.cjs +182 -0
  129. package/gsd-core/bin/lib/probe-core.cjs +7 -1
  130. package/gsd-core/bin/lib/prohibition-enforcement.cjs +91 -4
  131. package/gsd-core/bin/lib/project-root.cjs +41 -2
  132. package/gsd-core/bin/lib/quick-batch.cjs +1 -1
  133. package/gsd-core/bin/lib/refactor-trigger-command-router.cjs +61 -2
  134. package/gsd-core/bin/lib/research-store.cjs +11 -12
  135. package/gsd-core/bin/lib/review-lane-descriptor.cjs +10 -30
  136. package/gsd-core/bin/lib/review-lane-invocation.cjs +23 -0
  137. package/gsd-core/bin/lib/review-reviewer-selection.cjs +2 -2
  138. package/gsd-core/bin/lib/reviewer-step-dispatch.cjs +337 -0
  139. package/gsd-core/bin/lib/roadmap-command-router.cjs +12 -4
  140. package/gsd-core/bin/lib/roadmap-parser.cjs +219 -18
  141. package/gsd-core/bin/lib/roadmap-upgrade.cjs +1539 -13
  142. package/gsd-core/bin/lib/roadmap.cjs +356 -42
  143. package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +310 -41
  144. package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +15 -4
  145. package/gsd-core/bin/lib/runtime-artifact-layout.cjs +13 -5
  146. package/gsd-core/bin/lib/runtime-homes.cjs +4 -0
  147. package/gsd-core/bin/lib/runtime-hooks-surface.cjs +408 -37
  148. package/gsd-core/bin/lib/runtime-name-policy.cjs +111 -1
  149. package/gsd-core/bin/lib/security.cjs +126 -7
  150. package/gsd-core/bin/lib/shell-command-projection.cjs +10 -6
  151. package/gsd-core/bin/lib/state-document.cjs +130 -28
  152. package/gsd-core/bin/lib/state-md-schema.cjs +21 -14
  153. package/gsd-core/bin/lib/state-transition.cjs +181 -30
  154. package/gsd-core/bin/lib/state.cjs +265 -27
  155. package/gsd-core/bin/lib/surface.cjs +77 -3
  156. package/gsd-core/bin/lib/task-command-router.cjs +12 -6
  157. package/gsd-core/bin/lib/tdd-red-evidence.cjs +78 -5
  158. package/gsd-core/bin/lib/uat-predicate.cjs +47 -4
  159. package/gsd-core/bin/lib/uat.cjs +9 -1
  160. package/gsd-core/bin/lib/ui-consideration-probe.cjs +15 -2
  161. package/gsd-core/bin/lib/ui-frontend-evidence.cjs +100 -9
  162. package/gsd-core/bin/lib/undo-commit-selection.cjs +131 -0
  163. package/gsd-core/bin/lib/update-context.cjs +30 -24
  164. package/gsd-core/bin/lib/vendor/js-yaml.cjs +11 -3
  165. package/gsd-core/bin/lib/verification.cjs +315 -30
  166. package/gsd-core/bin/lib/verify-command-grounding.cjs +47 -3
  167. package/gsd-core/bin/lib/verify.cjs +320 -48
  168. package/gsd-core/bin/lib/workstream-inventory.cjs +1 -0
  169. package/gsd-core/bin/lib/worktree-base-ref.cjs +482 -73
  170. package/gsd-core/bin/lib/worktree-safety.cjs +797 -58
  171. package/gsd-core/bin/shared/config-defaults.manifest.json +4 -0
  172. package/gsd-core/bin/shared/config-schema.manifest.json +6 -0
  173. package/gsd-core/bin/verify-reapply-patches.cjs +439 -80
  174. package/gsd-core/references/checkpoints.md +5 -3
  175. package/gsd-core/references/compact-content-gate.md +66 -0
  176. package/gsd-core/references/edge-probe-fixtures/01-round-half-even/expected-coverage.json +28 -3
  177. package/gsd-core/references/edge-probe-fixtures/02-merge-intervals/expected-coverage.json +37 -4
  178. package/gsd-core/references/edge-probe-fixtures/03-truncate-graphemes/expected-coverage.json +28 -3
  179. package/gsd-core/references/edge-probe-fixtures/04-money-rounding/expected-coverage.json +28 -3
  180. package/gsd-core/references/edge-probe-fixtures/05-list-dedupe/expected-coverage.json +37 -4
  181. package/gsd-core/references/edge-probe-fixtures/06-resolved-mixed/expected-coverage.json +37 -4
  182. package/gsd-core/references/edge-probe.md +195 -21
  183. package/gsd-core/references/execute-phase-between-wave-reset.md +7 -6
  184. package/gsd-core/references/execute-phase-wave-guard.md +22 -11
  185. package/gsd-core/references/gsd-run-resolver.md +1 -1
  186. package/gsd-core/references/loop-hook-dispatch.md +18 -0
  187. package/gsd-core/references/model-profiles.md +13 -4
  188. package/gsd-core/references/phase-argument-parsing.md +9 -7
  189. package/gsd-core/references/phase-id-convention.md +28 -0
  190. package/gsd-core/references/planner-gap-closure.md +2 -0
  191. package/gsd-core/references/planner-load-graph-context.md +24 -13
  192. package/gsd-core/references/planner-verify-command-grounding.md +14 -0
  193. package/gsd-core/references/planning-config.md +14 -2
  194. package/gsd-core/references/tdd.md +30 -4
  195. package/gsd-core/references/thinking-models-planning.md +18 -2
  196. package/gsd-core/references/ui-consideration-probe.md +10 -5
  197. package/gsd-core/references/verification-patterns.md +17 -4
  198. package/gsd-core/references/verify-command-path-resolvability.md +10 -2
  199. package/gsd-core/references/worktree-path-safety.md +433 -2
  200. package/gsd-core/templates/README.md +7 -1
  201. package/gsd-core/templates/state.md +6 -3
  202. package/gsd-core/templates/summary.compact.md +212 -0
  203. package/gsd-core/templates/user-setup.compact.md +199 -0
  204. package/gsd-core/templates/user-setup.md +0 -9
  205. package/gsd-core/templates/verification-report.md +1 -1
  206. package/gsd-core/workflows/_runtime-launcher.snippet.sh +1 -1
  207. package/gsd-core/workflows/add-backlog.md +1 -1
  208. package/gsd-core/workflows/add-phase.md +1 -1
  209. package/gsd-core/workflows/add-tests.md +2 -2
  210. package/gsd-core/workflows/add-todo.md +6 -5
  211. package/gsd-core/workflows/ai-integration-phase.md +11 -3
  212. package/gsd-core/workflows/audit-fix.md +1 -1
  213. package/gsd-core/workflows/audit-milestone.md +1 -1
  214. package/gsd-core/workflows/audit-uat.md +1 -1
  215. package/gsd-core/workflows/autonomous/steps/converge-fail-fast.md +9 -18
  216. package/gsd-core/workflows/autonomous.md +29 -16
  217. package/gsd-core/workflows/check-todos.md +6 -4
  218. package/gsd-core/workflows/cleanup.md +5 -3
  219. package/gsd-core/workflows/code-review/steps/dispatch-fix.md +4 -3
  220. package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +8 -1
  221. package/gsd-core/workflows/code-review-fix.md +108 -22
  222. package/gsd-core/workflows/code-review.md +216 -73
  223. package/gsd-core/workflows/complete-milestone/detail/elaboration.md +274 -0
  224. package/gsd-core/workflows/complete-milestone.md +41 -264
  225. package/gsd-core/workflows/debug.md +3 -3
  226. package/gsd-core/workflows/diagnose-issues.md +1 -1
  227. package/gsd-core/workflows/discuss-phase/modes/advisor.md +1 -1
  228. package/gsd-core/workflows/discuss-phase/modes/chain.md +1 -1
  229. package/gsd-core/workflows/discuss-phase-assumptions.md +1 -1
  230. package/gsd-core/workflows/discuss-phase.md +1 -1
  231. package/gsd-core/workflows/do.md +2 -2
  232. package/gsd-core/workflows/docs-update/detail/elaboration.md +179 -0
  233. package/gsd-core/workflows/docs-update.md +17 -158
  234. package/gsd-core/workflows/edit-phase.md +1 -1
  235. package/gsd-core/workflows/eval-review.md +10 -3
  236. package/gsd-core/workflows/execute-phase/detail/elaboration.md +124 -0
  237. package/gsd-core/workflows/execute-phase/steps/code-review-disposition.md +1017 -0
  238. package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +19 -4
  239. package/gsd-core/workflows/execute-phase/steps/completion-reconciliation.md +56 -0
  240. package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +43 -4
  241. package/gsd-core/workflows/execute-phase/steps/executor-progress-policy.md +43 -0
  242. package/gsd-core/workflows/execute-phase/steps/gap-closure-artifacts.md +1 -1
  243. package/gsd-core/workflows/execute-phase/steps/partial-wave.md +1 -1
  244. package/gsd-core/workflows/execute-phase/steps/per-plan-executor-routing.md +1 -1
  245. package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +1 -1
  246. package/gsd-core/workflows/execute-phase/steps/post-merge-gate.md +46 -9
  247. package/gsd-core/workflows/execute-phase/steps/protected-branch.md +1 -1
  248. package/gsd-core/workflows/execute-phase/steps/ready-wave-gate.md +37 -0
  249. package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +1 -1
  250. package/gsd-core/workflows/execute-phase/steps/sequential-root-pin.md +35 -0
  251. package/gsd-core/workflows/execute-phase/steps/stale-reverification.md +24 -0
  252. package/gsd-core/workflows/execute-phase/steps/tdd-applicability-resolution.md +1 -1
  253. package/gsd-core/workflows/execute-phase/steps/threat-id-gate.md +28 -0
  254. package/gsd-core/workflows/execute-phase/steps/wave-post-gate-hooks.md +1 -1
  255. package/gsd-core/workflows/execute-phase/steps/worktree-base-check.md +25 -0
  256. package/gsd-core/workflows/execute-phase.md +83 -172
  257. package/gsd-core/workflows/execute-plan.md +24 -10
  258. package/gsd-core/workflows/explore.md +3 -3
  259. package/gsd-core/workflows/extract-learnings.md +2 -1
  260. package/gsd-core/workflows/fast.md +1 -1
  261. package/gsd-core/workflows/forensics.md +1 -1
  262. package/gsd-core/workflows/graduation.md +1 -1
  263. package/gsd-core/workflows/health.md +2 -2
  264. package/gsd-core/workflows/help/modes/full.compact.md +398 -0
  265. package/gsd-core/workflows/help/modes/full.md +5 -5
  266. package/gsd-core/workflows/help/modes/topic.md +15 -5
  267. package/gsd-core/workflows/help.md +1 -1
  268. package/gsd-core/workflows/import.md +2 -2
  269. package/gsd-core/workflows/inbox.md +2 -2
  270. package/gsd-core/workflows/ingest-docs.md +3 -3
  271. package/gsd-core/workflows/insert-phase.md +1 -1
  272. package/gsd-core/workflows/list-seeds.md +1 -1
  273. package/gsd-core/workflows/list-workspaces.md +1 -1
  274. package/gsd-core/workflows/manager.md +2 -2
  275. package/gsd-core/workflows/map-codebase.md +52 -5
  276. package/gsd-core/workflows/milestone-summary.md +1 -1
  277. package/gsd-core/workflows/mvp-phase.md +1 -1
  278. package/gsd-core/workflows/new-milestone.md +56 -14
  279. package/gsd-core/workflows/new-project/detail/elaboration.md +216 -0
  280. package/gsd-core/workflows/new-project/steps/auto-mode-config.md +3 -3
  281. package/gsd-core/workflows/new-project/steps/codebase-map-offer.md +1 -1
  282. package/gsd-core/workflows/new-project.md +39 -209
  283. package/gsd-core/workflows/new-workspace.md +2 -2
  284. package/gsd-core/workflows/next.md +1 -1
  285. package/gsd-core/workflows/note.md +1 -1
  286. package/gsd-core/workflows/onboard.md +1 -1
  287. package/gsd-core/workflows/pause-work.md +1 -1
  288. package/gsd-core/workflows/plan-phase/detail/elaboration.md +209 -0
  289. package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +17 -5
  290. package/gsd-core/workflows/plan-phase/steps/prd-express-path.md +1 -1
  291. package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +23 -5
  292. package/gsd-core/workflows/plan-phase.md +45 -187
  293. package/gsd-core/workflows/plan-review-convergence.md +21 -5
  294. package/gsd-core/workflows/plant-seed.md +62 -20
  295. package/gsd-core/workflows/pr-branch.md +132 -20
  296. package/gsd-core/workflows/profile-user.md +2 -2
  297. package/gsd-core/workflows/progress.md +1 -1
  298. package/gsd-core/workflows/quick/steps/plan-checker-loop.md +25 -0
  299. package/gsd-core/workflows/quick/steps/quick-verification.md +1 -1
  300. package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +1 -1
  301. package/gsd-core/workflows/quick-batch/steps/batch-init.md +1 -1
  302. package/gsd-core/workflows/quick-batch/steps/completion.md +1 -1
  303. package/gsd-core/workflows/quick-batch/steps/merge-wave.md +1 -1
  304. package/gsd-core/workflows/quick-batch/steps/planner-wave.md +1 -1
  305. package/gsd-core/workflows/quick-batch/steps/research-phase.md +1 -1
  306. package/gsd-core/workflows/quick-batch/steps/resume-mode.md +1 -1
  307. package/gsd-core/workflows/quick-batch/steps/verification-wave.md +1 -1
  308. package/gsd-core/workflows/quick-batch/steps/worktree-dispatch.md +1 -1
  309. package/gsd-core/workflows/quick-batch.md +1 -1
  310. package/gsd-core/workflows/quick.md +29 -10
  311. package/gsd-core/workflows/reapply-patches.md +86 -6
  312. package/gsd-core/workflows/remove-phase.md +1 -1
  313. package/gsd-core/workflows/remove-workspace.md +2 -2
  314. package/gsd-core/workflows/resume-project.md +1 -1
  315. package/gsd-core/workflows/review.md +31 -16
  316. package/gsd-core/workflows/scan.md +1 -1
  317. package/gsd-core/workflows/secure-phase.md +3 -2
  318. package/gsd-core/workflows/settings-advanced.md +30 -10
  319. package/gsd-core/workflows/settings-integrations.md +2 -3
  320. package/gsd-core/workflows/settings.md +22 -9
  321. package/gsd-core/workflows/ship.md +3 -2
  322. package/gsd-core/workflows/sketch-wrap-up.md +1 -1
  323. package/gsd-core/workflows/sketch.md +1 -1
  324. package/gsd-core/workflows/smart-entry.md +2 -2
  325. package/gsd-core/workflows/spec-phase.md +15 -5
  326. package/gsd-core/workflows/spike-wrap-up.md +1 -1
  327. package/gsd-core/workflows/spike.md +1 -1
  328. package/gsd-core/workflows/stats.md +1 -1
  329. package/gsd-core/workflows/sync-skills.md +5 -5
  330. package/gsd-core/workflows/thread.md +1 -1
  331. package/gsd-core/workflows/transition.md +1 -1
  332. package/gsd-core/workflows/ui-phase.md +44 -8
  333. package/gsd-core/workflows/ui-review.md +18 -4
  334. package/gsd-core/workflows/ultraplan-phase.md +1 -1
  335. package/gsd-core/workflows/undo.md +339 -20
  336. package/gsd-core/workflows/update.md +14 -12
  337. package/gsd-core/workflows/validate-phase.md +3 -2
  338. package/gsd-core/workflows/verify-work/detail/elaboration.md +230 -0
  339. package/gsd-core/workflows/verify-work/steps/automated-ui-verification.md +1 -1
  340. package/gsd-core/workflows/verify-work/steps/mvp-uat-framing.md +1 -1
  341. package/gsd-core/workflows/verify-work.md +101 -196
  342. package/hooks/dist/gsd-agent-isolation-guard.js +66 -16
  343. package/hooks/dist/gsd-context-monitor.js +88 -15
  344. package/hooks/dist/gsd-cursor-subagent-start.js +34 -14
  345. package/hooks/dist/gsd-secret-read-guard.js +71 -19
  346. package/hooks/dist/gsd-statusline.js +81 -20
  347. package/hooks/dist/gsd-validate-commit.sh +97 -8
  348. package/hooks/dist/gsd-worktree-path-guard.js +25 -14
  349. package/hooks/dist/gsd-write-guard.js +46 -1
  350. package/hooks/dist/lib/dispatch-identity.js +187 -0
  351. package/hooks/dist/lib/filename-classification.js +64 -0
  352. package/hooks/dist/lib/isolation-deny-reason.js +53 -1
  353. package/hooks/dist/lib/isolation-sentinel.js +58 -19
  354. package/hooks/gsd-agent-isolation-guard.js +66 -16
  355. package/hooks/gsd-context-monitor.js +88 -15
  356. package/hooks/gsd-cursor-subagent-start.js +34 -14
  357. package/hooks/gsd-secret-read-guard.js +71 -19
  358. package/hooks/gsd-statusline.js +81 -20
  359. package/hooks/gsd-validate-commit.sh +97 -8
  360. package/hooks/gsd-worktree-path-guard.js +25 -14
  361. package/hooks/gsd-write-guard.js +46 -1
  362. package/hooks/lib/dispatch-identity.js +187 -0
  363. package/hooks/lib/filename-classification.js +64 -0
  364. package/hooks/lib/isolation-deny-reason.js +53 -1
  365. package/hooks/lib/isolation-sentinel.js +58 -19
  366. package/package.json +11 -6
  367. package/scripts/benchmark-compact-content-variants.cjs +298 -0
  368. package/scripts/benchmark-compact-content.cjs +368 -0
  369. package/scripts/build-hooks.js +15 -6
  370. package/scripts/check-contract-drift.cjs +131 -12
  371. package/scripts/check-env.cjs +36 -8
  372. package/scripts/check-glossary-refs.cjs +25 -21
  373. package/scripts/ci-next-health.cjs +271 -0
  374. package/scripts/ci-prepare-test-scope.cjs +7 -7
  375. package/scripts/ci-test-scope.cjs +126 -20
  376. package/scripts/ci-timeout-report.cjs +1 -1
  377. package/scripts/command-contract-helpers.cjs +3 -0
  378. package/scripts/diff-touches-shipped-paths.cjs +1 -1
  379. package/scripts/docs-guard-registry.cjs +35 -2
  380. package/scripts/gen-adr-index.cjs +8 -2
  381. package/scripts/gen-inventory-manifest.cjs +12 -0
  382. package/scripts/gen-loop-host-contract.cjs +69 -0
  383. package/scripts/gen-platform-conformance-tier.cjs +557 -0
  384. package/scripts/lib/drift-scan.cjs +1 -1
  385. package/scripts/lib/macos-conformance-tier.generated.cjs +224 -0
  386. package/scripts/lib/ndjson-reporter.cjs +3 -2
  387. package/scripts/lib/npm-version-check-diagnosis.cjs +59 -0
  388. package/scripts/lib/platform-conformance-tier.generated.cjs +287 -0
  389. package/scripts/lib/suite-detection.cjs +32 -0
  390. package/scripts/lint-allowed-tools-parity.cjs +221 -0
  391. package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +47 -3
  392. package/scripts/lint-phase-arg-assignment.cjs +257 -0
  393. package/scripts/lint-phase-id-drift.cjs +623 -13
  394. package/scripts/lint-pr-branch-pattern-drift.cjs +148 -0
  395. package/scripts/lint-response-language-coverage.cjs +9 -3
  396. package/scripts/lint-retired-runtime-name.cjs +619 -0
  397. package/scripts/lint-source-test-name-collision.cjs +1 -1
  398. package/scripts/lint-state-write-path-drift.cjs +93 -0
  399. package/scripts/lint-test-file-count.allowlist.json +29 -9
  400. package/scripts/lint-vendored-deps.cjs +128 -17
  401. package/scripts/lint-workflow-shellcheck-baseline.json +100 -0
  402. package/scripts/prompt-injection-scan.sh +18 -0
  403. package/scripts/release-tarball-smoke.cjs +194 -1
  404. package/scripts/workflow-size.cjs +139 -0
  405. package/skills/gsd-autonomous/SKILL.md +2 -2
  406. package/skills/gsd-capture/SKILL.md +1 -1
  407. package/skills/gsd-cleanup/SKILL.md +1 -0
  408. package/skills/gsd-code-review/SKILL.md +2 -1
  409. package/skills/gsd-complete-milestone/SKILL.md +1 -0
  410. package/skills/gsd-config/SKILL.md +1 -0
  411. package/skills/gsd-debug/SKILL.md +1 -0
  412. package/skills/gsd-graphify/SKILL.md +1 -0
  413. package/skills/gsd-health/SKILL.md +1 -0
  414. package/skills/gsd-mempalace-capture/SKILL.md +8 -3
  415. package/skills/gsd-mempalace-recall/SKILL.md +1 -0
  416. package/skills/gsd-new-milestone/SKILL.md +1 -0
  417. package/skills/gsd-new-project/SKILL.md +1 -0
  418. package/skills/gsd-next/SKILL.md +1 -0
  419. package/skills/gsd-pause-work/SKILL.md +1 -0
  420. package/skills/gsd-phase/SKILL.md +1 -0
  421. package/skills/gsd-plan-review-convergence/SKILL.md +5 -5
  422. package/skills/gsd-pr-branch/SKILL.md +1 -0
  423. package/skills/gsd-progress/SKILL.md +1 -1
  424. package/skills/gsd-quick-batch/SKILL.md +1 -1
  425. package/skills/gsd-resume-work/SKILL.md +1 -0
  426. package/skills/gsd-review/SKILL.md +2 -3
  427. package/skills/gsd-review-backlog/SKILL.md +1 -0
  428. package/skills/gsd-settings/SKILL.md +2 -1
  429. package/skills/gsd-stats/SKILL.md +1 -0
  430. package/skills/gsd-thread/SKILL.md +1 -0
  431. package/skills/gsd-workspace/SKILL.md +1 -0
  432. package/skills/gsd-workstreams/SKILL.md +1 -0
  433. package/vscode/package.json +1 -1
  434. package/gsd-core/templates/claude-md.md +0 -145
  435. package/gsd-core/templates/codebase/concerns.md +0 -310
  436. package/gsd-core/templates/codebase/conventions.md +0 -307
  437. package/gsd-core/templates/codebase/integrations.md +0 -280
  438. package/gsd-core/templates/codebase/structure.md +0 -285
  439. package/gsd-core/templates/codebase/testing.md +0 -480
  440. package/gsd-core/templates/debug-subagent-prompt.md +0 -91
  441. package/gsd-core/templates/discovery.md +0 -146
@@ -162,6 +162,12 @@ const REASON = Object.freeze({
162
162
  // Axis 2 (§8.6, retained): a raw `fs.writeFileSync(` call targeting the
163
163
  // state path — see `findRawStateWrites`.
164
164
  RAW_STATE_WRITE: 'raw_state_write',
165
+ // ADR-4629 §8.1 (epic #4629, C1): a residual `readModifyWriteStateMd(path,
166
+ // (content) => …)` call whose transform is an inline anonymous arrow/function
167
+ // — the opaque shape §8.1 replaces with a declared StateWriteIntent. Recognized
168
+ // by `findOpaqueStateTransforms`; a CAPABILITY in C1 (not wired into collect()),
169
+ // wired terminal in C2 as the residual callers migrate (ADR-3408 §6 phasing).
170
+ OPAQUE_STATE_TRANSFORM: 'opaque_state_transform',
165
171
  // Axis 4 (§8.3, Decision 4(d)): prompt-layer prose shelling out to a
166
172
  // write-side `gsd-tools` subcommand — see `findPromptSeamUses`.
167
173
  PROMPT_LAYER_STATE_WRITE: 'prompt_layer_state_write',
@@ -645,6 +651,91 @@ function findRawStateWrites(rel, text) {
645
651
  return out;
646
652
  }
647
653
 
654
+ // ADR-4629 §8.1 (epic #4629, C1) — OPAQUE-TRANSFORM RECOGNITION.
655
+ //
656
+ // A residual `readModifyWriteStateMd(path, (content) => …)` call whose transform
657
+ // (2nd) argument is an inline anonymous arrow / function expression is the opaque
658
+ // shape §8.1 replaces with a declared StateWriteIntent: `readModifyWriteStateMd`
659
+ // goes THROUGH the seam (it is NOT a raw-write bypass — Axis 2's concern), but its
660
+ // opaque body transform is neither verified (§8.2) nor bounded (§8.3). This
661
+ // function RECOGNIZES that shape.
662
+ //
663
+ // C1 ships recognition as a CAPABILITY: it is exported and unit-tested (positive
664
+ // control on a seeded fixture) but is DELIBERATELY NOT wired into `collect()`'s
665
+ // failing scan. §8.1's caller-side rule is *Required — Phase 2*; wiring it now
666
+ // would turn the ~16 residual callers red at once, and ADR-3473 §8.6 retired the
667
+ // ratchet that would otherwise be needed to absorb them. C2 wires this terminal as
668
+ // the verifying executor lands and the callers migrate under ADR-3408 §6 phasing.
669
+ //
670
+ // String match, never an AST — same over-report-safe posture as every axis here.
671
+ const OPAQUE_RMW_CALL_RE = /\breadModifyWriteStateMd\s*\(/g;
672
+ // The transform arg is OPAQUE when it BEGINS an inline anonymous function: an
673
+ // arrow (`(…) =>`, `ident =>`, optionally `async`) or a `function` expression. A
674
+ // bare identifier / object (a declared StateWriteIntent, Phase 2+) is NOT opaque.
675
+ const ANON_TRANSFORM_RE =
676
+ /^\s*(?:async\s+)?(?:\([^)]*\)|[A-Za-z_$][\w$]*)\s*=>|^\s*(?:async\s+)?function\b/;
677
+
678
+ /**
679
+ * Capture the top-level, comma-separated argument list of a call, starting at
680
+ * `startIdx` (the index just AFTER the opening `(`) — across newlines and
681
+ * string-aware, tracking `()[]{}` depth. Returns the raw arg strings, or null if
682
+ * the parens never balance (a truncated arg list is never flagged). Generalizes
683
+ * `captureFirstArg`'s depth/inStr bookkeeping to every argument.
684
+ */
685
+ function captureCallArgList(text, startIdx) {
686
+ let depth = 0;
687
+ let inStr = null;
688
+ const args = [];
689
+ let cur = '';
690
+ for (let i = startIdx; i < text.length; i++) {
691
+ const ch = text[i];
692
+ if (inStr) {
693
+ cur += ch;
694
+ if (ch === inStr && text[i - 1] !== '\\') inStr = null;
695
+ continue;
696
+ }
697
+ if (ch === '"' || ch === "'" || ch === '`') { inStr = ch; cur += ch; continue; }
698
+ if (ch === '(' || ch === '[' || ch === '{') { depth++; cur += ch; continue; }
699
+ if (ch === ')' || ch === ']' || ch === '}') {
700
+ if (ch === ')' && depth === 0) {
701
+ if (cur.trim() !== '' || args.length) args.push(cur);
702
+ return args;
703
+ }
704
+ depth--; cur += ch; continue;
705
+ }
706
+ if (ch === ',' && depth === 0) { args.push(cur); cur = ''; continue; }
707
+ cur += ch;
708
+ }
709
+ return null; // parens never balanced
710
+ }
711
+
712
+ /**
713
+ * Recognize residual opaque-transform STATE.md writes (ADR-4629 §8.1). Returns a
714
+ * finding per `readModifyWriteStateMd(` call whose 2nd argument is an inline
715
+ * anonymous transform. CAPABILITY only in C1 — not called by `collect()`.
716
+ */
717
+ function findOpaqueStateTransforms(rel, text) {
718
+ const rawLines = text.split('\n');
719
+ const stripped = stripComments(text).join('\n');
720
+ const out = [];
721
+ let m;
722
+ OPAQUE_RMW_CALL_RE.lastIndex = 0;
723
+ while ((m = OPAQUE_RMW_CALL_RE.exec(stripped)) !== null) {
724
+ const args = captureCallArgList(stripped, m.index + m[0].length);
725
+ if (!args || args.length < 2) continue;
726
+ if (!ANON_TRANSFORM_RE.test(args[1])) continue;
727
+ const lineNo = stripped.slice(0, m.index).split('\n').length;
728
+ out.push({
729
+ reason: REASON.OPAQUE_STATE_TRANSFORM,
730
+ axis: 'opaque-transform',
731
+ file: sanitizeForReport(rel),
732
+ line: lineNo,
733
+ source: sanitizeForReport((rawLines[lineNo - 1] || '').trim()),
734
+ });
735
+ }
736
+ return out;
737
+ }
738
+
648
739
  // The two write-seam STAGE functions, matched only as CALLS (`\(`
649
740
  // immediately after, modulo whitespace) — never as bare mentions of the
650
741
  // name. `writeStateMd(` is deliberately NOT included here (that arm is
@@ -941,6 +1032,8 @@ module.exports = {
941
1032
  nearestPrecedingAssignment,
942
1033
  findRawStateWrites,
943
1034
  targetsStatePath,
1035
+ findOpaqueStateTransforms,
1036
+ captureCallArgList,
944
1037
  findCompositionBypasses,
945
1038
  findPromptSeamUses,
946
1039
  isInsideCodeSpan,
@@ -1,6 +1,15 @@
1
1
  {
2
- "_doc": "Baseline of modules currently exceeding the 2-test-file limit. Each entry locks in TODAY's exact test filenames as the allowlisted set (identity ratchet). Adding a NEW test file to a capped module fails (novel). Removing one requires pruning this list (stale, ratchet-down). When a cluster drops to \u2264 2, remove its entry entirely. New entries require justification in PR description.",
2
+ "_doc": "Baseline of modules currently exceeding the 2-test-file limit. Each entry locks in TODAY's exact test filenames as the allowlisted set (identity ratchet). Adding a NEW test file to a capped module fails (novel). Removing one requires pruning this list (stale, ratchet-down). When a cluster drops to ≤ 2, remove its entry entirely. New entries require justification in PR description.",
3
3
  "modules": {
4
+ "ui-consideration-probe": {
5
+ "files": [
6
+ "ui-consideration-probe-docs-fixtures.test.cjs",
7
+ "ui-consideration-probe-ui-phase-contract.test.cjs",
8
+ "ui-consideration-probe.test.cjs"
9
+ ],
10
+ "issue": "4657",
11
+ "justification": "The ui-consideration-probe cluster gains its workflow-prose contract file (tests/ui-consideration-probe-ui-phase-contract.test.cjs, #4657), mirroring the edge probe's split (edge-probe.test.cjs / edge-probe-docs-fixtures.test.cjs / edge-probe-spec-phase-contract.test.cjs). The contract file reads shipped gsd-core/workflows/ui-phase.md under the source-text-is-the-product exception, which the unit file deliberately does not carry (it asserts typed returns only)."
12
+ },
4
13
  "adr-parser": {
5
14
  "files": [
6
15
  "adr-parser.property.test.cjs",
@@ -40,7 +49,7 @@
40
49
  "frontmatter.unit.test.cjs"
41
50
  ],
42
51
  "issue": "3881",
43
- "justification": "Grandfathered by #3227 for the original 4-file cluster (pre-existing over-cap, not new sprawl). #3881 (ADR-3473 \u00a78.1, the js-yaml parser migration) adds two more: frontmatter-golden-parity.test.cjs (D-series golden-corpus diff against the legacy parser, ~900 real documents \u2014 cannot be folded into an existing file without losing its independent-of-current-parser provenance) and frontmatter-roundtrip.property.test.cjs (fast-check property coverage the migration's bijective-contract rule requires). Both are migration-specific, not incidental sprawl."
52
+ "justification": "Grandfathered by #3227 for the original 4-file cluster (pre-existing over-cap, not new sprawl). #3881 (ADR-3473 §8.1, the js-yaml parser migration) adds two more: frontmatter-golden-parity.test.cjs (D-series golden-corpus diff against the legacy parser, ~900 real documents — cannot be folded into an existing file without losing its independent-of-current-parser provenance) and frontmatter-roundtrip.property.test.cjs (fast-check property coverage the migration's bijective-contract rule requires). Both are migration-specific, not incidental sprawl."
44
53
  },
45
54
  "graphify": {
46
55
  "files": [
@@ -123,6 +132,7 @@
123
132
  "state-prune.test.cjs",
124
133
  "state-rebuild-cli.test.cjs",
125
134
  "state-rebuild.test.cjs",
135
+ "state-todos-render.test.cjs",
126
136
  "state-write-path-drift-guard.test.cjs",
127
137
  "state.test.cjs"
128
138
  ],
@@ -136,10 +146,11 @@
136
146
  "verify-npm-publish.test.cjs",
137
147
  "verify-test-quality.test.cjs",
138
148
  "verify-work-auto-transition.test.cjs",
149
+ "verify-work-deferred-promotion.test.cjs",
139
150
  "verify.test.cjs"
140
151
  ],
141
- "issue": "#3813 \u2014 the live-path #1883 suite drives buildPlanningSnapshot in-process with an fs fault; the verify module suites are CLI-driving and cannot host an fs monkeypatch",
142
- "justification": "verify-command-grounding added by #2401/#3678; allowlist follow-up landed with #3606 (base was red on this lane)."
152
+ "issue": "#3813 — the live-path #1883 suite drives buildPlanningSnapshot in-process with an fs fault; the verify module suites are CLI-driving and cannot host an fs monkeypatch",
153
+ "justification": "verify-command-grounding added by #2401/#3678; allowlist follow-up landed with #3606 (base was red on this lane). #4546 adds verify-work-deferred-promotion (deferred-follow-up promotion writer contract + parity)."
143
154
  },
144
155
  "install": {
145
156
  "files": [
@@ -153,7 +164,7 @@
153
164
  "install-write-confinement.test.cjs",
154
165
  "install.test.cjs"
155
166
  ],
156
- "issue": "#3798 \u2014 the profile-closure spawn test reads the real repo surface (commands+workflows+agents); consolidating it into install.test.cjs would put a whole-repo scan behind the suite's heaviest file"
167
+ "issue": "#3798 — the profile-closure spawn test reads the real repo surface (commands+workflows+agents); consolidating it into install.test.cjs would put a whole-repo scan behind the suite's heaviest file"
157
168
  },
158
169
  "edge-probe": {
159
170
  "files": [
@@ -251,8 +262,8 @@
251
262
  "docs-state-md-locale-parity.test.cjs",
252
263
  "docs-update.test.cjs"
253
264
  ],
254
- "issue": "3873 | #3839 \u2014 the hook-event parity suite cross-checks the four docs hook tables against src/runtime-hooks-surface.cts registrations; a generated-docs concern distinct from content freshness and registry parity",
255
- "justification": "ADR-3473 \u00a78.8 makes docs/reference/state-md.md and its four locale siblings generated-and-committed and adds the repo's first locale-parity check (verified: no locale-parity lint precedent exists here). That check is a distinct concern from docs-update (content freshness) and docs-parity-live-registry (registry parity); folding it into either would place an unrelated subject inside them purely to satisfy a count. The section it guards is absent from all four translations today and documents the status enum behind #3853."
265
+ "issue": "3873 | #3839 — the hook-event parity suite cross-checks the four docs hook tables against src/runtime-hooks-surface.cts registrations; a generated-docs concern distinct from content freshness and registry parity",
266
+ "justification": "ADR-3473 §8.8 makes docs/reference/state-md.md and its four locale siblings generated-and-committed and adds the repo's first locale-parity check (verified: no locale-parity lint precedent exists here). That check is a distinct concern from docs-update (content freshness) and docs-parity-live-registry (registry parity); folding it into either would place an unrelated subject inside them purely to satisfy a count. The section it guards is absent from all four translations today and documents the status enum behind #3853."
256
267
  },
257
268
  "audit": {
258
269
  "files": [
@@ -264,7 +275,7 @@
264
275
  "audit-uat-summary-segmentation.test.cjs",
265
276
  "audit-workstream-layouts.test.cjs"
266
277
  ],
267
- "issue": "#3804/#3805 \u2014 audit-layout and acknowledged-marker suites drive the real audit-uat CLI against on-disk fixtures | #3817 \u2014 regression suite proving countReal counts the truncation remainder marker instead of treating it as one phantom item | #3783 \u2014 dedicated suite for the summary.current_milestone/archived segmentation, matching this module's one-file-per-feature-slice precedent (e.g. audit-uat-acknowledged.test.cjs) rather than growing the unrelated 6900+ line tests/uat.test.cjs (a different module, keyed off uat.cjs)"
278
+ "issue": "#3804/#3805 — audit-layout and acknowledged-marker suites drive the real audit-uat CLI against on-disk fixtures | #3817 — regression suite proving countReal counts the truncation remainder marker instead of treating it as one phantom item | #3783 — dedicated suite for the summary.current_milestone/archived segmentation, matching this module's one-file-per-feature-slice precedent (e.g. audit-uat-acknowledged.test.cjs) rather than growing the unrelated 6900+ line tests/uat.test.cjs (a different module, keyed off uat.cjs)"
268
279
  },
269
280
  "shell-command-projection": {
270
281
  "files": [
@@ -272,7 +283,16 @@
272
283
  "shell-command-projection-md-normalize.test.cjs",
273
284
  "shell-command-projection-path-sep.test.cjs"
274
285
  ],
275
- "issue": "#3854 \u2014 the tight-list suite pins the markdown write-normalizer's blank-line policy through the exported normalizeContent/platformWriteSync seam; a distinct concern from dispatch routing and path separation"
286
+ "issue": "#3854 — the tight-list suite pins the markdown write-normalizer's blank-line policy through the exported normalizeContent/platformWriteSync seam; a distinct concern from dispatch routing and path separation"
287
+ },
288
+ "ui-consideration-probe": {
289
+ "files": [
290
+ "ui-consideration-probe-docs-fixtures.test.cjs",
291
+ "ui-consideration-probe-ui-phase-contract.test.cjs",
292
+ "ui-consideration-probe.test.cjs"
293
+ ],
294
+ "issue": "4657",
295
+ "justification": "The ui-consideration-probe cluster gains its workflow-prose contract file (tests/ui-consideration-probe-ui-phase-contract.test.cjs, #4657), mirroring the edge probe's split (edge-probe.test.cjs / edge-probe-docs-fixtures.test.cjs / edge-probe-spec-phase-contract.test.cjs). The contract file reads shipped gsd-core/workflows/ui-phase.md under the source-text-is-the-product exception, which the unit file deliberately does not carry (it asserts typed returns only)."
276
296
  }
277
297
  }
278
298
  }
@@ -161,8 +161,24 @@ function compareFiles(relA, relB) {
161
161
  * @param {string} spec
162
162
  * @returns {string}
163
163
  */
164
+ const PIN_OPERATOR_RE = /^(\^|~|>=|<=|>|<|=)?/;
165
+
164
166
  function stripRangeOperator(spec) {
165
- return String(spec || '').trim().replace(/^[\^~]|^>=|^<=|^>|^<|^=/, '').trim();
167
+ return String(spec || '').trim().replace(PIN_OPERATOR_RE, '').trim();
168
+ }
169
+
170
+ /**
171
+ * The leading range-operator token (if any) a package.json dependency spec
172
+ * was written with — the inverse half of stripRangeOperator, needed by
173
+ * `fixRow` to rebuild a pin (`<same operator>` + `<new version>`) that
174
+ * preserves the author's original range style instead of collapsing every
175
+ * pin to an exact version.
176
+ * @param {string} spec
177
+ * @returns {string} the operator (e.g. "^", "~", ">="), or "" for an exact pin
178
+ */
179
+ function pinOperatorPrefix(spec) {
180
+ const m = String(spec || '').trim().match(PIN_OPERATOR_RE);
181
+ return (m && m[1]) || '';
166
182
  }
167
183
 
168
184
  /**
@@ -211,12 +227,40 @@ function checkHandAuthoredTwin(row) {
211
227
  return findings;
212
228
  }
213
229
 
230
+ /**
231
+ * Read a row's pin state: the package.json devDependencies spec for
232
+ * `row.name` and, if `node_modules/<row.name>/package.json` exists, its
233
+ * installed version. Shared by checkRow (compares) and fixRow (rewrites) so
234
+ * the two can never silently diverge on how a pin is read.
235
+ * @param {VendoredPackage} row
236
+ * @param {string} [pkgRoot] Override for testing -- defaults to the real repo ROOT. Lets a
237
+ * test point fixRow's pin-rewrite at an isolated temp package.json instead of writing the
238
+ * real, shared one, which other concurrently-running node --test files read at module
239
+ * top-level (the same race class already fixed for the vendored .cjs copy).
240
+ * @returns {{pinnedSpec: string | undefined, installedVersion: string | undefined}}
241
+ */
242
+ function readPinState(row, pkgRoot = ROOT) {
243
+ const pkgPath = path.join(pkgRoot, 'package.json');
244
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
245
+ const pinnedSpec = pkg.devDependencies && pkg.devDependencies[row.name];
246
+ const installedPkgPath = path.join(pkgRoot, 'node_modules', row.name, 'package.json');
247
+ let installedVersion;
248
+ if (fs.existsSync(installedPkgPath)) {
249
+ installedVersion = JSON.parse(fs.readFileSync(installedPkgPath, 'utf8')).version;
250
+ }
251
+ return { pinnedSpec, installedVersion };
252
+ }
253
+
214
254
  /**
215
255
  * Run all applicable freshness checks for one vendored package row.
216
256
  * @param {VendoredPackage} row
257
+ * @param {string} [pkgRoot] Override for testing -- defaults to the real repo ROOT. Lets a
258
+ * test point fixRow's pin-rewrite at an isolated temp package.json instead of writing the
259
+ * real, shared one, which other concurrently-running node --test files read at module
260
+ * top-level (the same race class already fixed for the vendored .cjs copy).
217
261
  * @returns {string[]} findings (empty when the row is fresh)
218
262
  */
219
- function checkRow(row) {
263
+ function checkRow(row, pkgRoot = ROOT) {
220
264
  const findings = [];
221
265
 
222
266
  const cjsDrift = compareFiles(row.vendoredCjs, row.upstreamCjs);
@@ -235,31 +279,96 @@ function checkRow(row) {
235
279
  findings.push(...checkHandAuthoredTwin(row));
236
280
  }
237
281
 
238
- const pkgPath = path.join(ROOT, 'package.json');
239
- const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
240
- const pinnedSpec = pkg.devDependencies && pkg.devDependencies[row.name];
282
+ const { pinnedSpec, installedVersion } = readPinState(row, pkgRoot);
241
283
  if (!pinnedSpec) {
242
284
  findings.push(`package.json devDependencies.${row.name} is missing`);
285
+ } else if (installedVersion === undefined) {
286
+ findings.push(`node_modules/${row.name}/package.json does not exist (run npm install)`);
243
287
  } else {
244
- const installedPkgPath = path.join(ROOT, 'node_modules', row.name, 'package.json');
245
- if (!fs.existsSync(installedPkgPath)) {
246
- findings.push(`node_modules/${row.name}/package.json does not exist (run npm install)`);
247
- } else {
248
- const installed = JSON.parse(fs.readFileSync(installedPkgPath, 'utf8'));
249
- const pinned = stripRangeOperator(pinnedSpec);
250
- if (pinned !== installed.version) {
251
- findings.push(
252
- `package.json devDependencies.${row.name} ("${pinnedSpec}" -> "${pinned}") != `
253
- + `node_modules/${row.name}/package.json version ("${installed.version}")`,
254
- );
255
- }
288
+ const pinned = stripRangeOperator(pinnedSpec);
289
+ if (pinned !== installedVersion) {
290
+ findings.push(
291
+ `package.json devDependencies.${row.name} ("${pinnedSpec}" -> "${pinned}") != `
292
+ + `node_modules/${row.name}/package.json version ("${installedVersion}")`,
293
+ );
256
294
  }
257
295
  }
258
296
 
259
297
  return findings;
260
298
  }
261
299
 
300
+ /**
301
+ * Mechanically resolve a vendored package's byte/pin drift: copy the
302
+ * upstream .cjs (and, for `upstream-verbatim` rows, the .d.cts twins) over
303
+ * the vendored copy, and bump the package.json pin to the installed
304
+ * version, preserving the original range-operator prefix. Then re-runs
305
+ * `checkRow` and returns whatever findings remain.
306
+ *
307
+ * This NEVER hand-edits a `hand-authored` twin (e.g. js-yaml.d.cts) — that
308
+ * file encodes a human's deliberate judgment about which exports are safe
309
+ * to expose, and only a human can tell whether a declared-export-missing
310
+ * finding is mechanical drift or a real upstream API break. If one remains
311
+ * after this runs, that is by design: the caller must not treat it as
312
+ * fixed.
313
+ * @param {VendoredPackage} row
314
+ * @param {string} [pkgRoot] Override for testing -- defaults to the real repo ROOT. Lets a
315
+ * test point fixRow's pin-rewrite at an isolated temp package.json instead of writing the
316
+ * real, shared one, which other concurrently-running node --test files read at module
317
+ * top-level (the same race class already fixed for the vendored .cjs copy).
318
+ * @returns {string[]} findings remaining after the fix (empty when fully resolved)
319
+ */
320
+ function fixRow(row, pkgRoot = ROOT) {
321
+ fs.copyFileSync(resolvePath(row.upstreamCjs), resolvePath(row.vendoredCjs));
322
+
323
+ if (row.twinKind === 'upstream-verbatim' && row.upstreamDts) {
324
+ if (row.vendoredDts) fs.copyFileSync(resolvePath(row.upstreamDts), resolvePath(row.vendoredDts));
325
+ if (row.srcTwin) fs.copyFileSync(resolvePath(row.upstreamDts), resolvePath(row.srcTwin));
326
+ }
327
+
328
+ const { pinnedSpec, installedVersion } = readPinState(row, pkgRoot);
329
+ if (pinnedSpec && installedVersion !== undefined) {
330
+ const newPin = `${pinOperatorPrefix(pinnedSpec)}${installedVersion}`;
331
+ if (newPin !== pinnedSpec) {
332
+ const pkgPath = path.join(pkgRoot, 'package.json');
333
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
334
+ pkg.devDependencies[row.name] = newPin;
335
+ fs.writeFileSync(pkgPath, `${JSON.stringify(pkg, null, 2)}\n`);
336
+ }
337
+ }
338
+
339
+ return checkRow(row, pkgRoot);
340
+ }
341
+
262
342
  function main() {
343
+ if (process.argv.includes('--fix')) {
344
+ /** @type {Record<string, string[]>} */
345
+ const remaining = {};
346
+ for (const row of VENDORED) {
347
+ const findings = fixRow(row);
348
+ if (findings.length > 0) remaining[row.name] = findings;
349
+ }
350
+
351
+ const names = VENDORED.map((row) => row.name).join(', ');
352
+
353
+ if (Object.keys(remaining).length === 0) {
354
+ process.stdout.write(
355
+ `ok lint-vendored-deps --fix: gsd-core/bin/lib/vendor/{${names}} refreshed and now match node_modules and their pinned versions\n`,
356
+ );
357
+ return 0;
358
+ }
359
+
360
+ const detail = Object.entries(remaining)
361
+ .map(([name, findings]) => ` ${name}:\n${findings.map((f) => ` ${f}`).join('\n')}`)
362
+ .join('\n');
363
+ throw new ExitError(
364
+ 1,
365
+ `lint-vendored-deps --fix: mechanical drift refreshed, but the following row(s)\n`
366
+ + 'still have findings that --fix cannot resolve automatically — these need a\n'
367
+ + 'human, not just a re-run of --fix:\n'
368
+ + detail,
369
+ );
370
+ }
371
+
263
372
  const findings = [];
264
373
  for (const row of VENDORED) {
265
374
  findings.push(...checkRow(row));
@@ -288,9 +397,11 @@ if (require.main === module) runMain(main);
288
397
  module.exports = {
289
398
  compareFiles,
290
399
  stripRangeOperator,
400
+ pinOperatorPrefix,
291
401
  VENDORED,
292
402
  buildRefreshCommand,
293
403
  checkRow,
404
+ fixRow,
294
405
  declaredValueExports,
295
406
  checkHandAuthoredTwin,
296
407
  resolvePath,
@@ -274,6 +274,26 @@
274
274
  "code": "2086",
275
275
  "message": "Double quote to prevent globbing and word splitting."
276
276
  },
277
+ {
278
+ "file": "gsd-core/workflows/complete-milestone/detail/elaboration.md",
279
+ "code": "2001",
280
+ "message": "See if you can use ${variable//search/replace} instead."
281
+ },
282
+ {
283
+ "file": "gsd-core/workflows/complete-milestone/detail/elaboration.md",
284
+ "code": "2001",
285
+ "message": "See if you can use ${variable//search/replace} instead."
286
+ },
287
+ {
288
+ "file": "gsd-core/workflows/complete-milestone/detail/elaboration.md",
289
+ "code": "2086",
290
+ "message": "Double quote to prevent globbing and word splitting."
291
+ },
292
+ {
293
+ "file": "gsd-core/workflows/complete-milestone/detail/elaboration.md",
294
+ "code": "2086",
295
+ "message": "Double quote to prevent globbing and word splitting."
296
+ },
277
297
  {
278
298
  "file": "gsd-core/workflows/debug.md",
279
299
  "code": "2010",
@@ -369,6 +389,11 @@
369
389
  "code": "2086",
370
390
  "message": "Double quote to prevent globbing and word splitting."
371
391
  },
392
+ {
393
+ "file": "gsd-core/workflows/execute-phase/detail/elaboration.md",
394
+ "code": "2086",
395
+ "message": "Double quote to prevent globbing and word splitting."
396
+ },
372
397
  {
373
398
  "file": "gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md",
374
399
  "code": "2016",
@@ -469,6 +494,56 @@
469
494
  "code": "2012",
470
495
  "message": "Use find instead of ls to better handle non-alphanumeric filenames."
471
496
  },
497
+ {
498
+ "file": "gsd-core/workflows/new-milestone.md",
499
+ "code": "2086",
500
+ "message": "Double quote to prevent globbing and word splitting."
501
+ },
502
+ {
503
+ "file": "gsd-core/workflows/new-milestone.md",
504
+ "code": "2086",
505
+ "message": "Double quote to prevent globbing and word splitting."
506
+ },
507
+ {
508
+ "file": "gsd-core/workflows/new-milestone.md",
509
+ "code": "2086",
510
+ "message": "Double quote to prevent globbing and word splitting."
511
+ },
512
+ {
513
+ "file": "gsd-core/workflows/new-milestone.md",
514
+ "code": "2086",
515
+ "message": "Double quote to prevent globbing and word splitting."
516
+ },
517
+ {
518
+ "file": "gsd-core/workflows/new-milestone.md",
519
+ "code": "2086",
520
+ "message": "Double quote to prevent globbing and word splitting."
521
+ },
522
+ {
523
+ "file": "gsd-core/workflows/new-milestone.md",
524
+ "code": "2086",
525
+ "message": "Double quote to prevent globbing and word splitting."
526
+ },
527
+ {
528
+ "file": "gsd-core/workflows/new-milestone.md",
529
+ "code": "2086",
530
+ "message": "Double quote to prevent globbing and word splitting."
531
+ },
532
+ {
533
+ "file": "gsd-core/workflows/new-milestone.md",
534
+ "code": "2086",
535
+ "message": "Double quote to prevent globbing and word splitting."
536
+ },
537
+ {
538
+ "file": "gsd-core/workflows/new-milestone.md",
539
+ "code": "2086",
540
+ "message": "Double quote to prevent globbing and word splitting."
541
+ },
542
+ {
543
+ "file": "gsd-core/workflows/new-milestone.md",
544
+ "code": "2086",
545
+ "message": "Double quote to prevent globbing and word splitting."
546
+ },
472
547
  {
473
548
  "file": "gsd-core/workflows/new-project.md",
474
549
  "code": "2012",
@@ -479,6 +554,16 @@
479
554
  "code": "2012",
480
555
  "message": "Use find instead of ls to better handle non-alphanumeric filenames."
481
556
  },
557
+ {
558
+ "file": "gsd-core/workflows/new-project/detail/elaboration.md",
559
+ "code": "2012",
560
+ "message": "Use find instead of ls to better handle non-alphanumeric filenames."
561
+ },
562
+ {
563
+ "file": "gsd-core/workflows/new-project/detail/elaboration.md",
564
+ "code": "2012",
565
+ "message": "Use find instead of ls to better handle non-alphanumeric filenames."
566
+ },
482
567
  {
483
568
  "file": "gsd-core/workflows/new-workspace.md",
484
569
  "code": "2164",
@@ -1023,5 +1108,20 @@
1023
1108
  "file": "gsd-core/workflows/verify-work/steps/mvp-uat-framing.md",
1024
1109
  "code": "2086",
1025
1110
  "message": "Double quote to prevent globbing and word splitting."
1111
+ },
1112
+ {
1113
+ "file": "gsd-core/workflows/execute-phase/steps/code-review-disposition.md",
1114
+ "code": "2317",
1115
+ "message": "Command appears to be unreachable. Check usage (or ignore if invoked indirectly)."
1116
+ },
1117
+ {
1118
+ "file": "gsd-core/workflows/execute-phase/steps/code-review-disposition.md",
1119
+ "code": "2317",
1120
+ "message": "Command appears to be unreachable. Check usage (or ignore if invoked indirectly)."
1121
+ },
1122
+ {
1123
+ "file": "gsd-core/workflows/execute-phase/steps/code-review-disposition.md",
1124
+ "code": "2317",
1125
+ "message": "Command appears to be unreachable. Check usage (or ignore if invoked indirectly)."
1026
1126
  }
1027
1127
  ]
@@ -171,6 +171,10 @@ 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
+ # #4906 Phase 5 — regex.exec('### Phase 03: ...') fixtures.
175
+ # Same DEFECT.PROMPT-INJECTION-SCAN-COLLISION class as above:
176
+ # RegExp.prototype.exec, not code execution.
177
+ 'tests/phase-id.test.cjs'
174
178
  # #3676 row 11b — quick-batch's task-list parser must treat a
175
179
  # prompt-injection-shaped task description as inert data, never
176
180
  # interpreted. The fixture has to be a real "ignore all previous
@@ -179,6 +183,20 @@ ALLOWLIST=(
179
183
  # rendering, never a command. Same DEFECT.PROMPT-INJECTION-SCAN-COLLISION
180
184
  # class as the input-validator fixtures above.
181
185
  'tests/quick-batch.test.cjs'
186
+ # #4209 — the regression test pinning gsd-code-reviewer.md's untrusted-evidence
187
+ # contract discusses the injection attack it defends against (embedded
188
+ # redirection, "act as an instruction") without performing it. gsd-code-reviewer.md
189
+ # ITSELF is deliberately NOT allowlisted — R2 (#4209 review): a production prompt
190
+ # that ingests untrusted third-party output should stay in-scope for this scanner,
191
+ # not be exempted wholesale; its defense-contract wording was reworded instead to
192
+ # avoid literally spelling out the trigger phrase (see git blame on that section).
193
+ # Same DEFECT.PROMPT-INJECTION-SCAN-COLLISION class as the entries above.
194
+ 'tests/code-review-pipeline-regression.test.cjs'
195
+ # #4209 agy-F1 regression test — a crafted-filename fixture containing the literal
196
+ # phrase "Ignore all prior instructions." to prove validatePaths rejects it before
197
+ # it ever reaches an external-reviewer prompt. Discusses/detects the attack pattern
198
+ # as test data, never performs it. Same class as the entries above.
199
+ 'tests/reviewer-step-dispatch.test.cjs'
182
200
  )
183
201
 
184
202
  is_allowlisted() {