@opengsd/gsd-core 1.10.0 → 1.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (544) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/agents/gsd-code-fixer.md +1 -1
  4. package/agents/gsd-debug-session-manager.md +12 -1
  5. package/agents/gsd-debugger.md +1 -1
  6. package/agents/gsd-doc-synthesizer.md +2 -4
  7. package/agents/gsd-dom-verifier.md +169 -0
  8. package/agents/gsd-eval-auditor.md +1 -1
  9. package/agents/gsd-executor.md +22 -14
  10. package/agents/gsd-framework-selector.md +1 -3
  11. package/agents/gsd-intel-updater.md +1 -1
  12. package/agents/gsd-mempalace-curator.md +5 -3
  13. package/agents/gsd-pattern-mapper.md +11 -0
  14. package/agents/gsd-phase-researcher.md +23 -2
  15. package/agents/gsd-plan-checker.md +50 -53
  16. package/agents/gsd-planner.md +50 -50
  17. package/agents/gsd-project-researcher.md +1 -1
  18. package/agents/gsd-research-synthesizer.md +2 -2
  19. package/agents/gsd-roadmapper.md +15 -11
  20. package/agents/gsd-ui-checker.md +63 -4
  21. package/agents/gsd-ui-researcher.md +41 -3
  22. package/agents/gsd-user-profiler.md +3 -0
  23. package/agents/gsd-verifier.md +13 -4
  24. package/bin/install.js +1448 -1103
  25. package/commands/gsd/code-review.md +1 -1
  26. package/commands/gsd/discuss-phase.md +1 -1
  27. package/commands/gsd/execute-phase.md +1 -1
  28. package/commands/gsd/import.md +1 -1
  29. package/commands/gsd/map-codebase.md +1 -1
  30. package/commands/gsd/mempalace-capture.md +1 -1
  31. package/commands/gsd/mempalace-recall.md +1 -1
  32. package/commands/gsd/new-milestone.md +1 -1
  33. package/commands/gsd/quick.md +9 -5
  34. package/commands/gsd/review-backlog.md +2 -1
  35. package/commands/gsd/verify-work.md +1 -1
  36. package/gsd-core/bin/gsd-tools.cjs +1035 -138
  37. package/gsd-core/bin/lib/active-workstream-store.cjs +146 -22
  38. package/gsd-core/bin/lib/adr-parser.cjs +13 -7
  39. package/gsd-core/bin/lib/agent-install-check.cjs +392 -32
  40. package/gsd-core/bin/lib/api-coverage.cjs +33 -14
  41. package/gsd-core/bin/lib/artifacts.cjs +5 -0
  42. package/gsd-core/bin/lib/assumption-delta.cjs +32 -15
  43. package/gsd-core/bin/lib/audit-command-router.cjs +9 -2
  44. package/gsd-core/bin/lib/audit.cjs +1026 -268
  45. package/gsd-core/bin/lib/broken-windows.cjs +306 -28
  46. package/gsd-core/bin/lib/capability-consent.cjs +149 -15
  47. package/gsd-core/bin/lib/capability-lifecycle.cjs +45 -0
  48. package/gsd-core/bin/lib/capability-lock.cjs +10 -4
  49. package/gsd-core/bin/lib/capability-registry.cjs +845 -130
  50. package/gsd-core/bin/lib/capability-source.cjs +92 -0
  51. package/gsd-core/bin/lib/capability-state.cjs +18 -3
  52. package/gsd-core/bin/lib/capability-trust.cjs +444 -25
  53. package/gsd-core/bin/lib/capability-validator.cjs +700 -40
  54. package/gsd-core/bin/lib/capability-writer.cjs +3 -2
  55. package/gsd-core/bin/lib/check-command-router.cjs +216 -42
  56. package/gsd-core/bin/lib/claude-orchestration.cjs +56 -3
  57. package/gsd-core/bin/lib/cli-exit.cjs +496 -10
  58. package/gsd-core/bin/lib/code-review-depth.cjs +288 -0
  59. package/gsd-core/bin/lib/codex-agent-toml.cjs +735 -0
  60. package/gsd-core/bin/lib/command-aliases.cjs +22 -0
  61. package/gsd-core/bin/lib/command-arg-projection.cjs +144 -14
  62. package/gsd-core/bin/lib/command-roster.cjs +44 -1
  63. package/gsd-core/bin/lib/command-routing-hub.cjs +31 -2
  64. package/gsd-core/bin/lib/commands.cjs +1172 -108
  65. package/gsd-core/bin/lib/commonjs-marker.cjs +12 -6
  66. package/gsd-core/bin/lib/complexity-trigger.cjs +1192 -0
  67. package/gsd-core/bin/lib/config-loader.cjs +187 -23
  68. package/gsd-core/bin/lib/config.cjs +102 -3
  69. package/gsd-core/bin/lib/configuration.cjs +129 -37
  70. package/gsd-core/bin/lib/core-utils.cjs +208 -33
  71. package/gsd-core/bin/lib/decisions.cjs +23 -0
  72. package/gsd-core/bin/lib/edge-probe.cjs +9 -1
  73. package/gsd-core/bin/lib/estimate-cli.cjs +55 -11
  74. package/gsd-core/bin/lib/exit-code-registry.cjs +98 -0
  75. package/gsd-core/bin/lib/fallow-runner.cjs +20 -44
  76. package/gsd-core/bin/lib/frontmatter.cjs +899 -229
  77. package/gsd-core/bin/lib/gap-checker.cjs +95 -10
  78. package/gsd-core/bin/lib/git-base-branch.cjs +276 -39
  79. package/gsd-core/bin/lib/gsd2-import.cjs +10 -1
  80. package/gsd-core/bin/lib/health-diagnostic-rules/agent-install.cjs +101 -0
  81. package/gsd-core/bin/lib/health-diagnostic-rules/config-validation.cjs +348 -0
  82. package/gsd-core/bin/lib/health-diagnostic-rules/consistency.cjs +149 -0
  83. package/gsd-core/bin/lib/health-diagnostic-rules/install-surface-shadowing.cjs +98 -0
  84. package/gsd-core/bin/lib/health-diagnostic-rules/milestone-archive-hygiene.cjs +100 -0
  85. package/gsd-core/bin/lib/health-diagnostic-rules/phase-structure.cjs +222 -0
  86. package/gsd-core/bin/lib/health-diagnostic-rules/roadmap-disk-consistency.cjs +268 -0
  87. package/gsd-core/bin/lib/health-diagnostic-rules/root-existence.cjs +161 -0
  88. package/gsd-core/bin/lib/health-diagnostic-rules/state-consistency.cjs +303 -0
  89. package/gsd-core/bin/lib/health-diagnostic-rules/worktree-health.cjs +187 -0
  90. package/gsd-core/bin/lib/health-diagnostic-types.cjs +68 -0
  91. package/gsd-core/bin/lib/health-diagnostic.cjs +451 -0
  92. package/gsd-core/bin/lib/host-integration.cjs +39 -6
  93. package/gsd-core/bin/lib/host-runtime-detection.cjs +134 -0
  94. package/gsd-core/bin/lib/init-command-router.cjs +118 -21
  95. package/gsd-core/bin/lib/init.cjs +439 -168
  96. package/gsd-core/bin/lib/install-effort-resolver.cjs +73 -30
  97. package/gsd-core/bin/lib/install-engine.cjs +811 -259
  98. package/gsd-core/bin/lib/install-fs-adapter.cjs +262 -0
  99. package/gsd-core/bin/lib/install-model-override-resolver.cjs +235 -0
  100. package/gsd-core/bin/lib/install-profiles.cjs +212 -61
  101. package/gsd-core/bin/lib/install-scope.cjs +270 -0
  102. package/gsd-core/bin/lib/install-shadow-report.cjs +385 -0
  103. package/gsd-core/bin/lib/installed-surface-resolver.cjs +381 -0
  104. package/gsd-core/bin/lib/installer-migration-report.cjs +3 -0
  105. package/gsd-core/bin/lib/installer-migrations/010-antigravity-retire-confighome-artifacts.cjs +169 -0
  106. package/gsd-core/bin/lib/installer-migrations.cjs +148 -38
  107. package/gsd-core/bin/lib/intel.cjs +101 -26
  108. package/gsd-core/bin/lib/io.cjs +170 -15
  109. package/gsd-core/bin/lib/learnings.cjs +85 -14
  110. package/gsd-core/bin/lib/legacy-cleanup.cjs +8 -2
  111. package/gsd-core/bin/lib/markdown-sectionizer.cjs +2 -1
  112. package/gsd-core/bin/lib/markdown-table.cjs +183 -22
  113. package/gsd-core/bin/lib/milestone-lock.cjs +248 -0
  114. package/gsd-core/bin/lib/milestone.cjs +842 -73
  115. package/gsd-core/bin/lib/model-catalog.cjs +232 -16
  116. package/gsd-core/bin/lib/model-resolver.cjs +193 -68
  117. package/gsd-core/bin/lib/normalize-test-command.cjs +1 -1
  118. package/gsd-core/bin/lib/onboard-projection.cjs +5 -1
  119. package/gsd-core/bin/lib/pattern.cjs +122 -0
  120. package/gsd-core/bin/lib/phase-estimation.cjs +18 -9
  121. package/gsd-core/bin/lib/phase-id.cjs +514 -40
  122. package/gsd-core/bin/lib/phase-lifecycle.cjs +52 -19
  123. package/gsd-core/bin/lib/phase-locator.cjs +262 -34
  124. package/gsd-core/bin/lib/phase.cjs +1038 -214
  125. package/gsd-core/bin/lib/plan-dependency-graph.cjs +72 -1
  126. package/gsd-core/bin/lib/plan-document.cjs +263 -0
  127. package/gsd-core/bin/lib/plan-drift-guard.cjs +120 -0
  128. package/gsd-core/bin/lib/plan-scan.cjs +98 -3
  129. package/gsd-core/bin/lib/planning-command-router.cjs +61 -0
  130. package/gsd-core/bin/lib/planning-inspect.cjs +1168 -0
  131. package/gsd-core/bin/lib/planning-scope.cjs +31 -0
  132. package/gsd-core/bin/lib/planning-snapshot.cjs +894 -0
  133. package/gsd-core/bin/lib/planning-workspace.cjs +112 -6
  134. package/gsd-core/bin/lib/probe-core.cjs +5 -2
  135. package/gsd-core/bin/lib/profile-output.cjs +1 -1
  136. package/gsd-core/bin/lib/profile-pipeline-command-router.cjs +50 -7
  137. package/gsd-core/bin/lib/profile-pipeline.cjs +6 -3
  138. package/gsd-core/bin/lib/real-home-guard.cjs +419 -0
  139. package/gsd-core/bin/lib/refactor-trigger-command-router.cjs +766 -0
  140. package/gsd-core/bin/lib/retired-artifact-cleanup.cjs +11 -6
  141. package/gsd-core/bin/lib/review-lane-descriptor.cjs +22 -13
  142. package/gsd-core/bin/lib/review-lane-invocation.cjs +30 -0
  143. package/gsd-core/bin/lib/review-lane-runner.cjs +421 -66
  144. package/gsd-core/bin/lib/review-reviewer-selection.cjs +13 -18
  145. package/gsd-core/bin/lib/roadmap-command-router.cjs +59 -11
  146. package/gsd-core/bin/lib/roadmap-parser.cjs +1006 -184
  147. package/gsd-core/bin/lib/roadmap-upgrade.cjs +37 -10
  148. package/gsd-core/bin/lib/roadmap.cjs +442 -96
  149. package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +702 -52
  150. package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +14 -2
  151. package/gsd-core/bin/lib/runtime-artifact-layout.cjs +459 -55
  152. package/gsd-core/bin/lib/runtime-config-adapter-registry.cjs +3 -2
  153. package/gsd-core/bin/lib/runtime-homes.cjs +69 -3
  154. package/gsd-core/bin/lib/runtime-hooks-surface.cjs +402 -58
  155. package/gsd-core/bin/lib/runtime-identity.cjs +234 -0
  156. package/gsd-core/bin/lib/runtime-name-policy.cjs +3 -1
  157. package/gsd-core/bin/lib/runtime-slash.cjs +96 -8
  158. package/gsd-core/bin/lib/security.cjs +104 -5
  159. package/gsd-core/bin/lib/shell-command-projection.cjs +342 -7
  160. package/gsd-core/bin/lib/smart-entry.cjs +133 -23
  161. package/gsd-core/bin/lib/spec-section.cjs +12 -7
  162. package/gsd-core/bin/lib/state-command-router.cjs +52 -19
  163. package/gsd-core/bin/lib/state-contract.cjs +359 -0
  164. package/gsd-core/bin/lib/state-document.cjs +338 -8
  165. package/gsd-core/bin/lib/state-md-schema.cjs +221 -0
  166. package/gsd-core/bin/lib/state-transition.cjs +846 -176
  167. package/gsd-core/bin/lib/state.cjs +2589 -369
  168. package/gsd-core/bin/lib/surface.cjs +33 -11
  169. package/gsd-core/bin/lib/task-command-router.cjs +111 -1
  170. package/gsd-core/bin/lib/task-content-resolution.cjs +368 -0
  171. package/gsd-core/bin/lib/teams-status.cjs +4 -1
  172. package/gsd-core/bin/lib/text-lines.cjs +80 -0
  173. package/gsd-core/bin/lib/token-scanner.cjs +76 -0
  174. package/gsd-core/bin/lib/uat-predicate.cjs +67 -23
  175. package/gsd-core/bin/lib/uat.cjs +1761 -167
  176. package/gsd-core/bin/lib/ui-consideration-probe.cjs +9 -1
  177. package/gsd-core/bin/lib/ui-frontend-evidence.cjs +157 -0
  178. package/gsd-core/bin/lib/ui-safety-gate.cjs +51 -12
  179. package/gsd-core/bin/lib/unusable-input.cjs +37 -0
  180. package/gsd-core/bin/lib/update-context.cjs +8 -2
  181. package/gsd-core/bin/lib/user-artifact-staging.cjs +705 -0
  182. package/gsd-core/bin/lib/validate-command-router.cjs +2 -2
  183. package/gsd-core/bin/lib/validate.cjs +20 -6
  184. package/gsd-core/bin/lib/vendor/README.md +75 -0
  185. package/gsd-core/bin/lib/vendor/js-yaml.cjs +3014 -0
  186. package/gsd-core/bin/lib/vendor/re2js.cjs +6480 -0
  187. package/gsd-core/bin/lib/vendor/re2js.d.cts +938 -0
  188. package/gsd-core/bin/lib/verification-command-router.cjs +2 -1
  189. package/gsd-core/bin/lib/verification.cjs +272 -9
  190. package/gsd-core/bin/lib/verify-command-grounding.cjs +846 -0
  191. package/gsd-core/bin/lib/verify.cjs +453 -918
  192. package/gsd-core/bin/lib/workstream-inventory-builder.cjs +53 -32
  193. package/gsd-core/bin/lib/workstream-inventory.cjs +63 -10
  194. package/gsd-core/bin/lib/workstream-name-policy.cjs +25 -4
  195. package/gsd-core/bin/lib/workstream.cjs +2 -2
  196. package/gsd-core/bin/lib/worktree-base-ref.cjs +66 -12
  197. package/gsd-core/bin/lib/worktree-safety.cjs +341 -18
  198. package/gsd-core/bin/shared/config-defaults.manifest.json +8 -1
  199. package/gsd-core/bin/shared/config-schema.manifest.json +12 -1
  200. package/gsd-core/bin/shared/exit-codes.json +8 -0
  201. package/gsd-core/bin/shared/exit-codes.sh +20 -0
  202. package/gsd-core/bin/shared/model-catalog.json +8 -1
  203. package/gsd-core/references/agent-contracts.md +44 -26
  204. package/gsd-core/references/api-coverage.md +24 -2
  205. package/gsd-core/references/autonomous-smart-discuss.md +3 -3
  206. package/gsd-core/references/checkpoints.md +39 -21
  207. package/gsd-core/references/context-budget.md +1 -1
  208. package/gsd-core/references/decimal-phase-calculation.md +5 -5
  209. package/gsd-core/references/dispatch-isolation-gate.md +138 -0
  210. package/gsd-core/references/doc-conflict-engine.md +1 -1
  211. package/gsd-core/references/edge-probe.md +8 -0
  212. package/gsd-core/references/execute-mvp-tdd.md +4 -6
  213. package/gsd-core/references/execute-phase-between-wave-reset.md +15 -14
  214. package/gsd-core/references/execute-phase-context-guard.md +1 -1
  215. package/gsd-core/references/execute-phase-response-language.md +1 -1
  216. package/gsd-core/references/execute-phase-wave-guard.md +17 -11
  217. package/gsd-core/references/failing-direction.md +78 -0
  218. package/gsd-core/references/gate-prompts.md +1 -1
  219. package/gsd-core/references/git-integration.md +5 -5
  220. package/gsd-core/references/git-planning-commit.md +5 -4
  221. package/gsd-core/references/gsd-run-resolver.md +1 -1
  222. package/gsd-core/references/loop-hook-dispatch.md +61 -2
  223. package/gsd-core/references/model-profiles.md +12 -4
  224. package/gsd-core/references/mvp-concepts.md +9 -9
  225. package/gsd-core/references/nyquist-compliance.md +74 -0
  226. package/gsd-core/references/offer-next.md +3 -5
  227. package/gsd-core/references/phase-argument-parsing.md +3 -3
  228. package/gsd-core/references/planner-failing-direction.md +53 -0
  229. package/gsd-core/references/planner-guidance.md +3 -9
  230. package/gsd-core/references/planner-human-verify-mode.md +15 -1
  231. package/gsd-core/references/planner-preconditions.md +1 -1
  232. package/gsd-core/references/planner-reviews.md +1 -1
  233. package/gsd-core/references/planner-revision.md +1 -1
  234. package/gsd-core/references/planner-verify-command-grounding.md +17 -0
  235. package/gsd-core/references/planning-config.md +44 -13
  236. package/gsd-core/references/reviewer-instances.md +31 -0
  237. package/gsd-core/references/revision-loop.md +1 -1
  238. package/gsd-core/references/runtime-aware-dispatch.md +1 -1
  239. package/gsd-core/references/specless-probe-fallback.md +1 -1
  240. package/gsd-core/references/tdd.md +1 -3
  241. package/gsd-core/references/ui-brand.md +65 -21
  242. package/gsd-core/references/ui-consideration-probe.md +1 -1
  243. package/gsd-core/references/universal-anti-patterns.md +5 -5
  244. package/gsd-core/references/verifier-phase-gates.md +192 -0
  245. package/gsd-core/references/verify-command-path-resolvability.md +42 -0
  246. package/gsd-core/references/verify-mvp-mode.md +2 -2
  247. package/gsd-core/references/workstream-flag.md +33 -17
  248. package/gsd-core/templates/README.md +1 -1
  249. package/gsd-core/templates/SECURITY.md +3 -3
  250. package/gsd-core/templates/UI-SPEC.md +25 -3
  251. package/gsd-core/templates/VALIDATION.md +3 -3
  252. package/gsd-core/templates/discussion-log.md +1 -1
  253. package/gsd-core/templates/phase-prompt.md +5 -4
  254. package/gsd-core/templates/state.md +11 -4
  255. package/gsd-core/templates/verification-report.md +9 -1
  256. package/gsd-core/workflows/_runtime-launcher.snippet.sh +1 -1
  257. package/gsd-core/workflows/add-backlog.md +1 -1
  258. package/gsd-core/workflows/add-phase.md +3 -3
  259. package/gsd-core/workflows/add-tests.md +3 -8
  260. package/gsd-core/workflows/add-todo.md +1 -1
  261. package/gsd-core/workflows/ai-integration-phase.md +13 -20
  262. package/gsd-core/workflows/audit-fix.md +12 -3
  263. package/gsd-core/workflows/audit-milestone.md +9 -9
  264. package/gsd-core/workflows/audit-uat.md +17 -2
  265. package/gsd-core/workflows/autonomous/steps/converge-fail-fast.md +2 -2
  266. package/gsd-core/workflows/autonomous.md +11 -27
  267. package/gsd-core/workflows/check-todos.md +1 -1
  268. package/gsd-core/workflows/cleanup.md +64 -5
  269. package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +14 -4
  270. package/gsd-core/workflows/code-review-fix.md +38 -11
  271. package/gsd-core/workflows/code-review.md +159 -52
  272. package/gsd-core/workflows/complete-milestone.md +151 -23
  273. package/gsd-core/workflows/debug.md +12 -8
  274. package/gsd-core/workflows/diagnose-issues.md +47 -15
  275. package/gsd-core/workflows/discuss-phase/modes/advisor.md +1 -1
  276. package/gsd-core/workflows/discuss-phase/modes/chain.md +5 -8
  277. package/gsd-core/workflows/discuss-phase/modes/default.md +1 -1
  278. package/gsd-core/workflows/discuss-phase/modes/text.md +1 -1
  279. package/gsd-core/workflows/discuss-phase-assumptions/steps/auto-advance-dispatch.md +1 -3
  280. package/gsd-core/workflows/discuss-phase-assumptions.md +4 -3
  281. package/gsd-core/workflows/discuss-phase.md +1 -1
  282. package/gsd-core/workflows/do.md +3 -6
  283. package/gsd-core/workflows/docs-update.md +5 -4
  284. package/gsd-core/workflows/edit-phase.md +27 -2
  285. package/gsd-core/workflows/eval-review.md +7 -14
  286. package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +1 -1
  287. package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +142 -15
  288. package/gsd-core/workflows/execute-phase/steps/gap-closure-artifacts.md +1 -1
  289. package/gsd-core/workflows/execute-phase/steps/partial-wave.md +1 -1
  290. package/gsd-core/workflows/execute-phase/steps/per-plan-executor-routing.md +77 -0
  291. package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +24 -4
  292. package/gsd-core/workflows/execute-phase/steps/post-merge-gate.md +2 -2
  293. package/gsd-core/workflows/execute-phase/steps/protected-branch.md +21 -0
  294. package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +2 -2
  295. package/gsd-core/workflows/execute-phase/steps/wave-post-gate-hooks.md +39 -0
  296. package/gsd-core/workflows/execute-phase.md +72 -100
  297. package/gsd-core/workflows/execute-plan.md +52 -15
  298. package/gsd-core/workflows/explore.md +131 -4
  299. package/gsd-core/workflows/extract-learnings.md +1 -1
  300. package/gsd-core/workflows/fast.md +10 -2
  301. package/gsd-core/workflows/forensics.md +1 -1
  302. package/gsd-core/workflows/graduation.md +5 -5
  303. package/gsd-core/workflows/health.md +76 -10
  304. package/gsd-core/workflows/import.md +18 -15
  305. package/gsd-core/workflows/inbox.md +4 -5
  306. package/gsd-core/workflows/ingest-docs.md +49 -16
  307. package/gsd-core/workflows/insert-phase.md +5 -5
  308. package/gsd-core/workflows/list-seeds.md +5 -3
  309. package/gsd-core/workflows/list-workspaces.md +1 -1
  310. package/gsd-core/workflows/manager.md +12 -23
  311. package/gsd-core/workflows/map-codebase.md +1 -1
  312. package/gsd-core/workflows/milestone-summary.md +1 -1
  313. package/gsd-core/workflows/mvp-phase.md +8 -5
  314. package/gsd-core/workflows/new-milestone.md +22 -29
  315. package/gsd-core/workflows/new-project/steps/auto-mode-config.md +1 -1
  316. package/gsd-core/workflows/new-project.md +26 -40
  317. package/gsd-core/workflows/new-workspace.md +1 -1
  318. package/gsd-core/workflows/next.md +14 -2
  319. package/gsd-core/workflows/pause-work.md +1 -1
  320. package/gsd-core/workflows/plan-phase/steps/adr-ingest-express-path.md +1 -1
  321. package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +1 -1
  322. package/gsd-core/workflows/plan-phase/steps/prd-express-path.md +2 -4
  323. package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +3 -3
  324. package/gsd-core/workflows/plan-phase.md +162 -59
  325. package/gsd-core/workflows/plan-review-convergence.md +96 -11
  326. package/gsd-core/workflows/plant-seed.md +2 -2
  327. package/gsd-core/workflows/pr-branch.md +187 -51
  328. package/gsd-core/workflows/profile-user.md +16 -14
  329. package/gsd-core/workflows/progress.md +61 -18
  330. package/gsd-core/workflows/quick/steps/discussion-phase.md +1 -3
  331. package/gsd-core/workflows/quick/steps/plan-checker-loop.md +5 -7
  332. package/gsd-core/workflows/quick/steps/quick-verification.md +28 -9
  333. package/gsd-core/workflows/quick/steps/research-phase.md +4 -6
  334. package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +3 -3
  335. package/gsd-core/workflows/quick.md +55 -44
  336. package/gsd-core/workflows/remove-phase.md +4 -4
  337. package/gsd-core/workflows/remove-workspace.md +2 -2
  338. package/gsd-core/workflows/resume-project.md +8 -12
  339. package/gsd-core/workflows/review.md +219 -20
  340. package/gsd-core/workflows/scan.md +1 -1
  341. package/gsd-core/workflows/secure-phase.md +3 -3
  342. package/gsd-core/workflows/session-report.md +2 -1
  343. package/gsd-core/workflows/settings-advanced.md +7 -9
  344. package/gsd-core/workflows/settings-integrations.md +64 -31
  345. package/gsd-core/workflows/settings.md +69 -7
  346. package/gsd-core/workflows/ship.md +116 -50
  347. package/gsd-core/workflows/sketch-wrap-up.md +11 -17
  348. package/gsd-core/workflows/sketch.md +12 -18
  349. package/gsd-core/workflows/smart-entry.md +3 -5
  350. package/gsd-core/workflows/spec-phase.md +53 -13
  351. package/gsd-core/workflows/spike-wrap-up.md +7 -11
  352. package/gsd-core/workflows/spike.md +20 -31
  353. package/gsd-core/workflows/stats.md +2 -2
  354. package/gsd-core/workflows/sync-skills.md +64 -9
  355. package/gsd-core/workflows/thread.md +11 -7
  356. package/gsd-core/workflows/transition.md +49 -14
  357. package/gsd-core/workflows/ui-phase.md +15 -21
  358. package/gsd-core/workflows/ui-review.md +8 -12
  359. package/gsd-core/workflows/ultraplan-phase.md +5 -13
  360. package/gsd-core/workflows/undo.md +8 -16
  361. package/gsd-core/workflows/update.md +7 -11
  362. package/gsd-core/workflows/validate-phase.md +3 -3
  363. package/gsd-core/workflows/verify-work/steps/automated-ui-verification.md +25 -1
  364. package/gsd-core/workflows/verify-work/steps/mvp-uat-framing.md +1 -1
  365. package/gsd-core/workflows/verify-work.md +66 -25
  366. package/hooks/dist/gsd-agent-isolation-guard.js +158 -30
  367. package/hooks/dist/gsd-check-update-worker.js +56 -13
  368. package/hooks/dist/gsd-check-update.js +19 -1
  369. package/hooks/dist/gsd-config-reload.js +18 -12
  370. package/hooks/dist/gsd-context-monitor.js +19 -10
  371. package/hooks/dist/gsd-cursor-post-tool.js +3 -1
  372. package/hooks/dist/gsd-cursor-pre-tool.js +2 -3
  373. package/hooks/dist/gsd-cursor-session-start.js +2 -1
  374. package/hooks/dist/gsd-cursor-stop.js +2 -1
  375. package/hooks/dist/gsd-cursor-subagent-start.js +83 -3
  376. package/hooks/dist/gsd-cursor-subagent-stop.js +6 -3
  377. package/hooks/dist/gsd-ensure-canonical-path.js +2 -1
  378. package/hooks/dist/gsd-graphify-update.sh +22 -18
  379. package/hooks/dist/gsd-node-runner.sh +76 -0
  380. package/hooks/dist/gsd-phase-boundary.sh +1 -0
  381. package/hooks/dist/gsd-prompt-guard.js +37 -27
  382. package/hooks/dist/gsd-read-guard.js +16 -7
  383. package/hooks/dist/gsd-read-injection-scanner.js +55 -32
  384. package/hooks/dist/gsd-session-state.sh +1 -0
  385. package/hooks/dist/gsd-statusline.js +231 -24
  386. package/hooks/dist/gsd-update-banner.js +22 -1
  387. package/hooks/dist/gsd-validate-commit.sh +80 -6
  388. package/hooks/dist/gsd-windsurf-pre-command.js +16 -11
  389. package/hooks/dist/gsd-windsurf-pre-write.js +22 -13
  390. package/hooks/dist/gsd-workflow-guard.js +162 -46
  391. package/hooks/dist/gsd-worktree-path-guard.js +36 -21
  392. package/hooks/dist/gsd-write-guard.js +35 -25
  393. package/hooks/dist/lib/cli-exit.js +560 -0
  394. package/hooks/dist/lib/exit-code-registry.js +98 -0
  395. package/hooks/dist/lib/git-cmd.js +92 -59
  396. package/hooks/dist/lib/git-probe.js +84 -0
  397. package/hooks/dist/lib/hook-exit.js +81 -0
  398. package/hooks/dist/lib/injection-patterns.js +45 -0
  399. package/hooks/dist/lib/isolation-deny-reason.js +39 -0
  400. package/hooks/dist/lib/isolation-sentinel.js +9 -0
  401. package/hooks/dist/managed-hooks-registry.cjs +3 -0
  402. package/hooks/gsd-agent-isolation-guard.js +158 -30
  403. package/hooks/gsd-check-update-worker.js +56 -13
  404. package/hooks/gsd-check-update.js +19 -1
  405. package/hooks/gsd-config-reload.js +18 -12
  406. package/hooks/gsd-context-monitor.js +19 -10
  407. package/hooks/gsd-cursor-post-tool.js +3 -1
  408. package/hooks/gsd-cursor-pre-tool.js +2 -3
  409. package/hooks/gsd-cursor-session-start.js +2 -1
  410. package/hooks/gsd-cursor-stop.js +2 -1
  411. package/hooks/gsd-cursor-subagent-start.js +83 -3
  412. package/hooks/gsd-cursor-subagent-stop.js +6 -3
  413. package/hooks/gsd-ensure-canonical-path.js +2 -1
  414. package/hooks/gsd-graphify-update.sh +22 -18
  415. package/hooks/gsd-node-runner.sh +76 -0
  416. package/hooks/gsd-phase-boundary.sh +1 -0
  417. package/hooks/gsd-prompt-guard.js +37 -27
  418. package/hooks/gsd-read-guard.js +16 -7
  419. package/hooks/gsd-read-injection-scanner.js +55 -32
  420. package/hooks/gsd-session-state.sh +1 -0
  421. package/hooks/gsd-statusline.js +231 -24
  422. package/hooks/gsd-update-banner.js +22 -1
  423. package/hooks/gsd-validate-commit.sh +80 -6
  424. package/hooks/gsd-windsurf-pre-command.js +16 -11
  425. package/hooks/gsd-windsurf-pre-write.js +22 -13
  426. package/hooks/gsd-workflow-guard.js +162 -46
  427. package/hooks/gsd-worktree-path-guard.js +36 -21
  428. package/hooks/gsd-write-guard.js +35 -25
  429. package/hooks/lib/cli-exit.js +560 -0
  430. package/hooks/lib/exit-code-registry.js +98 -0
  431. package/hooks/lib/git-cmd.js +92 -59
  432. package/hooks/lib/git-probe.js +84 -0
  433. package/hooks/lib/hook-exit.js +81 -0
  434. package/hooks/lib/injection-patterns.js +45 -0
  435. package/hooks/lib/isolation-deny-reason.js +39 -0
  436. package/hooks/lib/isolation-sentinel.js +9 -0
  437. package/hooks/managed-hooks-registry.cjs +3 -0
  438. package/package.json +28 -11
  439. package/pi/gsd.cjs +19 -5
  440. package/scripts/base64-scan.sh +74 -12
  441. package/scripts/baselines/planning-prompt-drift-baseline.json +4 -0
  442. package/scripts/baselines/planning-snapshot-bypass-baseline.json +12 -0
  443. package/scripts/baselines/unreachable-guard-drift-baseline.json +4 -0
  444. package/scripts/build-hooks.js +5 -0
  445. package/scripts/changeset/lint.cjs +60 -5
  446. package/scripts/check-alias-drift.cjs +7 -43
  447. package/scripts/check-contract-drift.cjs +297 -0
  448. package/scripts/check-glossary-refs.cjs +77 -15
  449. package/scripts/check-mutation-score-ratchet.cjs +156 -0
  450. package/scripts/ci-check-job-near-cap.cjs +49 -0
  451. package/scripts/ci-pr-mergeability.cjs +262 -0
  452. package/scripts/ci-test-scope.cjs +64 -14
  453. package/scripts/ci-timeout-report.cjs +230 -0
  454. package/scripts/command-contract-helpers.cjs +903 -1
  455. package/scripts/docs-guard-registry.cjs +396 -0
  456. package/scripts/gen-adr-index.cjs +728 -38
  457. package/scripts/gen-capability-registry.cjs +11 -21
  458. package/scripts/gen-context-index.cjs +2 -11
  459. package/scripts/gen-exit-code-docs.cjs +318 -0
  460. package/scripts/gen-exit-code-registry.cjs +891 -0
  461. package/scripts/gen-features.cjs +836 -0
  462. package/scripts/gen-health-docs.cjs +390 -0
  463. package/scripts/gen-hooks-cli-exit.cjs +239 -0
  464. package/scripts/gen-install-tree-fixtures.cjs +2 -2
  465. package/scripts/gen-inventory-manifest.cjs +50 -4
  466. package/scripts/gen-loop-host-contract.cjs +138 -25
  467. package/scripts/gen-registry.cjs +3 -14
  468. package/scripts/gen-scripts-cli-exit.cjs +185 -0
  469. package/scripts/gen-state-md-docs.cjs +727 -0
  470. package/scripts/{test-failure-reasons.cjs → gsd-test-gate-reasons.cjs} +6 -0
  471. package/scripts/lib/alias-drift-families.cjs +46 -0
  472. package/scripts/lib/ci-job-timing.cjs +72 -0
  473. package/scripts/lib/cli-exit.cjs +546 -44
  474. package/scripts/lib/drift-scan.cjs +308 -0
  475. package/scripts/lib/exit-code-registry.cjs +98 -0
  476. package/scripts/lib/ndjson-reporter.cjs +119 -0
  477. package/scripts/lint-allow-test-rule-refs.allowlist.json +1 -26
  478. package/scripts/lint-allow-test-rule-refs.effective-ceiling.json +4 -0
  479. package/scripts/lint-allow-test-rule-refs.unverified-ceiling.json +3 -0
  480. package/scripts/lint-canary-version-leak.cjs +73 -0
  481. package/scripts/lint-command-contract.cjs +96 -13
  482. package/scripts/lint-completion-predicate-drift.cjs +933 -0
  483. package/scripts/lint-completion-ratio-drift.cjs +214 -0
  484. package/scripts/lint-default-flip-documentation.cjs +193 -0
  485. package/scripts/lint-docs-guard-registration.cjs +495 -0
  486. package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +193 -0
  487. package/scripts/lint-eslint-glob-coverage.allowlist.json +38 -0
  488. package/scripts/lint-eslint-glob-coverage.cjs +340 -0
  489. package/scripts/{lint-fix-has-regression-test.cjs → lint-fix-has-regression-tests.cjs} +12 -6
  490. package/scripts/lint-frontmatter-scalar-broad-grep.cjs +237 -0
  491. package/scripts/lint-health-diagnostic-rule-table.cjs +461 -0
  492. package/scripts/lint-hooks-runtime-build-seam.cjs +262 -0
  493. package/scripts/lint-milestone-window-drift.cjs +468 -0
  494. package/scripts/lint-mutation-test-derivation-drift.cjs +86 -0
  495. package/scripts/lint-phase-enumeration-drift.cjs +492 -0
  496. package/scripts/lint-plan-count-drift.cjs +318 -0
  497. package/scripts/lint-planning-artifact-writer-drift.cjs +398 -0
  498. package/scripts/lint-planning-prompt-drift.cjs +471 -0
  499. package/scripts/lint-planning-snapshot-bypass-drift.cjs +544 -0
  500. package/scripts/lint-regression-test-names.cjs +15 -13
  501. package/scripts/lint-removed-but-needed.cjs +488 -0
  502. package/scripts/lint-seam-enforcement.cjs +182 -0
  503. package/scripts/lint-slug-derivation-drift.cjs +921 -0
  504. package/scripts/lint-source-test-name-collision.cjs +241 -0
  505. package/scripts/lint-state-field-drift.cjs +805 -0
  506. package/scripts/lint-state-write-path-drift.cjs +950 -0
  507. package/scripts/lint-test-file-count.allowlist.json +137 -8
  508. package/scripts/lint-test-file-count.cjs +25 -3
  509. package/scripts/lint-unreachable-guard-drift.cjs +830 -0
  510. package/scripts/lint-vendored-deps.cjs +297 -0
  511. package/scripts/mutation-matrix.cjs +599 -50
  512. package/scripts/pr-changed-files.cjs +63 -0
  513. package/scripts/pr-template-policy.cjs +14 -4
  514. package/scripts/prompt-injection-scan.sh +100 -14
  515. package/scripts/require-issue-link-policy.cjs +192 -0
  516. package/scripts/secret-scan.sh +75 -13
  517. package/scripts/select-docs-guards.cjs +56 -0
  518. package/scripts/sync-runtime-launcher.cjs +24 -7
  519. package/skills/gsd-autonomous/SKILL.md +0 -1
  520. package/skills/gsd-code-review/SKILL.md +1 -1
  521. package/skills/gsd-discuss-phase/SKILL.md +1 -1
  522. package/skills/gsd-execute-phase/SKILL.md +1 -2
  523. package/skills/gsd-import/SKILL.md +1 -1
  524. package/skills/gsd-map-codebase/SKILL.md +1 -1
  525. package/skills/gsd-mempalace-capture/SKILL.md +1 -1
  526. package/skills/gsd-mempalace-recall/SKILL.md +1 -1
  527. package/skills/gsd-new-milestone/SKILL.md +1 -1
  528. package/skills/gsd-next/SKILL.md +0 -1
  529. package/skills/gsd-plan-phase/SKILL.md +0 -1
  530. package/skills/gsd-progress/SKILL.md +0 -1
  531. package/skills/gsd-quick/SKILL.md +9 -5
  532. package/skills/gsd-review-backlog/SKILL.md +2 -1
  533. package/skills/gsd-stats/SKILL.md +0 -1
  534. package/skills/gsd-verify-work/SKILL.md +1 -1
  535. package/vscode/package.json +1 -1
  536. package/bin/lib/ui-safety-gate.cjs +0 -107
  537. package/gsd-core/workflows/discovery-phase.md +0 -298
  538. package/gsd-core/workflows/plan-milestone-gaps.md +0 -281
  539. package/gsd-core/workflows/verify-phase.md +0 -574
  540. package/scripts/affected-tests-lib.cjs +0 -554
  541. package/scripts/lint-allow-test-rule-refs.cjs +0 -162
  542. package/scripts/lint-emitted-drift-ack.cjs +0 -344
  543. package/scripts/run-affected-tests.cjs +0 -7
  544. package/scripts/run-tests.cjs +0 -1051
@@ -0,0 +1,308 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ /**
5
+ * Shared anti-divergence scanner machinery (epic #3180, ADR-3180 Decision 4).
6
+ *
7
+ * Extracted from `scripts/lint-plan-count-drift.cjs` (#3183) so that
8
+ * `scripts/lint-milestone-window-drift.cjs` (#3184) and any future
9
+ * `scripts/lint-<derivation>-drift.cjs` guard consume ONE tree-walk /
10
+ * root-confinement / literal-tokenizer / sanitizer implementation instead of
11
+ * each copying it verbatim — the exact generative-fix-divergence class this
12
+ * epic exists to remove, now applied to the guards themselves (see
13
+ * `.gsd/phase/refactor-3184-milestone-window-single-owner/40-design.md`,
14
+ * "Rejected: let the new drift guard copy Phase 1's tree-walk /
15
+ * root-confinement / sanitizer").
16
+ *
17
+ * `lint-plan-count-drift.cjs` re-exports every symbol it exported before this
18
+ * extraction (`readRegexLiteralAt`, `MAX_REGEX_LITERAL_LEN`, `isInsideRoot`,
19
+ * `sanitizeForReport`), so `tests/plan-count-single-owner.test.cjs` — the
20
+ * ReDoS and root-confinement regression net for this exact machinery —
21
+ * continues to pass unchanged and is the regression net for this move too.
22
+ */
23
+
24
+ const fs = require('node:fs');
25
+ const path = require('node:path');
26
+
27
+ // Longest regex literal this scanner will consider, in characters. Real
28
+ // plan/summary filename filters (and milestone-window regex literals) are far
29
+ // shorter; the bound is what keeps the scan linear. The tokenizer restarts at
30
+ // every `/` on the line (so that a literal preceded by a stray unpaired `/`
31
+ // is still found, matching the previous regex's "find anywhere" behaviour),
32
+ // which without a per-literal bound would be quadratic on a pathological
33
+ // line. With it the whole-line cost is O(n * MAX_REGEX_LITERAL_LEN) with no
34
+ // backtracking at all.
35
+ const MAX_REGEX_LITERAL_LEN = 400;
36
+
37
+ // Directory names this scanner never descends into or reports out of —
38
+ // `.git` (repo internals, e.g. a persisted CI token in `.git/config`),
39
+ // `node_modules` (thousands of third-party files, none of them authored
40
+ // source), `dist` (build output). Named once and used at BOTH skip sites
41
+ // below: the cheap `entry.name` fast path in `walk`, and the resolved-path
42
+ // component check in `isUnderSkippedDir` — a symlink whose OWN name is not
43
+ // in this set but whose target resolves through a directory that IS (e.g.
44
+ // `src/g -> ../.git`, `src/nm -> ../node_modules`) must still be skipped, or
45
+ // the name-only check is a trivial bypass.
46
+ const SKIP_DIR_NAMES = new Set(['node_modules', 'dist', '.git']);
47
+
48
+ /**
49
+ * Read the JS regex literal starting at `line[start]` (which must be `/`).
50
+ * Returns `{ text, end }` — `text` includes the delimiters and any trailing
51
+ * flags, `end` is the index one past the literal — or null if no literal
52
+ * closes within MAX_REGEX_LITERAL_LEN characters.
53
+ *
54
+ * Single left-to-right pass, no backtracking. It models the two constructs a
55
+ * backtracking pattern gets wrong, which is why this is a tokenizer and not a
56
+ * regex:
57
+ * - `\x` escapes consume BOTH characters, so an escaped `\/` never
58
+ * terminates the literal;
59
+ * - inside a `[...]` character class a bare `/` does NOT terminate, so
60
+ * `/PLAN[\\/].*\.md$/` is one literal rather than two fragments. The
61
+ * previous regex silently MISSED every re-derivation using a
62
+ * cross-platform path-separator class for exactly this reason.
63
+ */
64
+ // Deterministic regression seam for the MAJOR-2 bound (issue #3951/#3987): a
65
+ // counter of how many characters this tokenizer has actually examined, so a
66
+ // test can assert the bound HOLDS (total work stays a small linear multiple
67
+ // of the number of scan attempts × MAX_REGEX_LITERAL_LEN) without resorting
68
+ // to a wall-clock elapsed-time assertion, which this repo's test rules ban
69
+ // ("Clock Seams: Do not assert on wall-clock time.") and which is exactly
70
+ // what flaked on a slow shared CI runner. `resetRegexScanStats`/
71
+ // `getRegexScanStats` are read-modify-reset around a single scan under test;
72
+ // they are process-global and NOT safe under concurrent scans, which is fine
73
+ // for this synchronous, single-threaded CLI tool and its tests.
74
+ let regexScanStats = { calls: 0, charsExamined: 0 };
75
+
76
+ function resetRegexScanStats() {
77
+ regexScanStats = { calls: 0, charsExamined: 0 };
78
+ }
79
+
80
+ function getRegexScanStats() {
81
+ return { ...regexScanStats };
82
+ }
83
+
84
+ function readRegexLiteralAt(line, start) {
85
+ if (line[start] !== '/') return null;
86
+ regexScanStats.calls++;
87
+ const limit = Math.min(line.length, start + MAX_REGEX_LITERAL_LEN);
88
+ let inClass = false;
89
+ let i = start + 1;
90
+ for (; i < limit; i++) {
91
+ const ch = line[i];
92
+ if (ch === '\\') {
93
+ i++; // escape consumes the next character, whatever it is
94
+ continue;
95
+ }
96
+ if (ch === '\r' || ch === '\n') {
97
+ // a literal cannot span lines
98
+ regexScanStats.charsExamined += i - start;
99
+ return null;
100
+ }
101
+ if (ch === '[') {
102
+ inClass = true;
103
+ } else if (ch === ']') {
104
+ inClass = false;
105
+ } else if (ch === '/' && !inClass) {
106
+ // Trailing flags are bounded by the SAME `limit` as the literal body
107
+ // itself (not `line.length`) — a literal followed by an unbounded run
108
+ // of lowercase letters must not make `text` grow past
109
+ // MAX_REGEX_LITERAL_LEN either.
110
+ let end = i + 1;
111
+ while (end < limit && line[end] >= 'a' && line[end] <= 'z') end++;
112
+ regexScanStats.charsExamined += end - start;
113
+ return { text: line.slice(start, end), end };
114
+ }
115
+ }
116
+ regexScanStats.charsExamined += limit - start;
117
+ return null;
118
+ }
119
+
120
+ // Symlinks report `isDirectory()`/`isFile()` as false on the Dirent from
121
+ // `readdirSync`, so a symlinked `.cts` (or a symlinked directory containing
122
+ // one) was previously invisible to this scanner — an evasion of a guard
123
+ // whose stated design principle (ADR-3180 Decision 4a) is whole-repo
124
+ // discovery with no allowlist. Resolve each entry with `fs.statSync` (which
125
+ // follows symlinks) to classify it, skipping broken links. `ctx.visitedRealDirs`
126
+ // guards against a symlink cycle sending `walk` into infinite recursion.
127
+ //
128
+ // Every sibling drift guard in `scripts/` that does NOT import this module
129
+ // (`lint-phase-id-drift.cjs`, `lint-package-identity-drift.cjs`,
130
+ // `lint-portable-timeout.cjs`, `lint-test-file-count.cjs`,
131
+ // `lint-allow-test-rule-refs.cjs`) uses the `Dirent` classification straight
132
+ // off `readdirSync` and does NOT follow symlinks at all. This scanner follows
133
+ // them so a symlinked source file cannot evade ADR-3180 Decision 4a's
134
+ // whole-repo discovery — root confinement (`isInsideRoot` below) is the price
135
+ // of doing so: without it, a symlink planted anywhere under a scan directory
136
+ // could walk this scanner out to read and report arbitrary files elsewhere on
137
+ // disk.
138
+ //
139
+ // DIRECTORY vs FILE symlinks are confined to two DIFFERENT roots, tracked as
140
+ // `ctx.scanDirRoot` (the realpath of the current top-level scan-dir entry,
141
+ // e.g. `<realRoot>/src`) vs `ctx.realRoot` (the whole repo):
142
+ // - a DIRECTORY symlink is descended ONLY if its resolved realpath is
143
+ // inside `ctx.scanDirRoot` — NOT merely inside `ctx.realRoot`. Without
144
+ // this, `src/up -> ..` (or `-> <realRoot>`) resolves inside the repo
145
+ // root and `walk` descends the ENTIRE repo, reporting violations under
146
+ // paths like `tests/not-src.cts` or `docs/other.cts` — files the caller's
147
+ // scan-dir list scopes it OUT of. This is a deliberate, fail-CLOSED
148
+ // trade-off: a directory symlink pointing elsewhere INSIDE the repo (but
149
+ // outside the scan directory) is simply not followed. The alternative —
150
+ // descending it — is exactly the whole-repo sweep this rule exists to
151
+ // prevent, and a fork PR could use that sweep to redden `lint:ci` on
152
+ // files this guard was never meant to read. The narrower rule is worth
153
+ // more than the missed edge case.
154
+ // - a FILE symlink is still scanned if its resolved realpath is inside
155
+ // `ctx.realRoot` (the whole repo, not just the scan directory) — this is
156
+ // what keeps `src/alias.cts -> vendor/real.cts` covered (test (f)): an
157
+ // aliased file genuinely is part of the compiled surface even when its
158
+ // real target lives outside `src/`, and it is still reported under its
159
+ // canonical (real) path.
160
+ //
161
+ // A resolved path is inside a root only if it IS that root or begins with
162
+ // root + separator — a plain `startsWith(root)` would also accept a sibling
163
+ // directory whose name merely starts with the root's name (`/repo-evil`).
164
+ function isInsideRoot(realPath, realRoot) {
165
+ return realPath === realRoot || realPath.startsWith(realRoot + path.sep);
166
+ }
167
+
168
+ // True when `realPath` (already confirmed inside `realRoot` by `isInsideRoot`)
169
+ // resolves THROUGH a skip-list directory anywhere along its path relative to
170
+ // the root — not just when `realPath` itself IS one. This is what closes the
171
+ // symlink bypass the `entry.name` fast path alone cannot: `walk` tests
172
+ // `entry.name` (the symlink's OWN name in its parent directory), but a
173
+ // symlink named something innocuous can still RESOLVE into `.git` /
174
+ // `node_modules` / `dist` (`src/g -> ../.git`, `src/leak.cts ->
175
+ // ../.git/config`, `src/nm -> ../node_modules`) — `isInsideRoot` alone admits
176
+ // all three, because every one of those real paths is still under the root.
177
+ function isUnderSkippedDir(realPath, realRoot) {
178
+ const rel = path.relative(realRoot, realPath);
179
+ return rel.split(path.sep).some((segment) => SKIP_DIR_NAMES.has(segment));
180
+ }
181
+
182
+ // `ctx.scanExt` is a `Set` of file extensions (e.g. `.cts`/`.ts`/`.mts`) the
183
+ // caller wants reported — threaded through `ctx` rather than as a positional
184
+ // parameter so recursive `walk(full, acc, ctx)` calls stay unchanged.
185
+ function walk(dir, acc, ctx) {
186
+ let entries;
187
+ try {
188
+ entries = fs.readdirSync(dir, { withFileTypes: true });
189
+ } catch {
190
+ return acc;
191
+ }
192
+ for (const entry of entries) {
193
+ const full = path.join(dir, entry.name);
194
+ if (SKIP_DIR_NAMES.has(entry.name)) continue; // cheap fast path
195
+ let stat;
196
+ try {
197
+ stat = entry.isSymbolicLink() ? fs.statSync(full) : entry;
198
+ } catch {
199
+ continue; // broken symlink target
200
+ }
201
+ let realPath;
202
+ try {
203
+ realPath = fs.realpathSync(full);
204
+ } catch {
205
+ continue; // broken symlink target (race, or a link stat() followed but realpath cannot)
206
+ }
207
+ if (stat.isDirectory()) {
208
+ // Directories (symlinked or real) are confined to the CURRENT scan
209
+ // directory root, not merely the repo root — see the comment above
210
+ // `isInsideRoot` for why (`src/up -> ..` whole-repo sweep).
211
+ if (!isInsideRoot(realPath, ctx.scanDirRoot)) continue;
212
+ if (isUnderSkippedDir(realPath, ctx.realRoot)) continue; // symlink resolves through a skipped dir
213
+ if (ctx.visitedRealDirs.has(realPath)) continue; // symlink cycle guard
214
+ ctx.visitedRealDirs.add(realPath);
215
+ walk(full, acc, ctx);
216
+ } else if (stat.isFile() && ctx.scanExt.has(path.extname(entry.name))) {
217
+ // Files are confined to the whole repo root — a symlinked FILE whose
218
+ // real target lives outside the scan directory but inside the repo
219
+ // (e.g. `src/alias.cts -> vendor/real.cts`) is still part of the
220
+ // compiled surface and must be scanned.
221
+ if (!isInsideRoot(realPath, ctx.realRoot)) continue;
222
+ if (isUnderSkippedDir(realPath, ctx.realRoot)) continue; // symlink resolves through a skipped dir
223
+ if (ctx.visitedRealFiles.has(realPath)) continue; // two symlinks, same real file
224
+ ctx.visitedRealFiles.add(realPath);
225
+ acc.push(realPath);
226
+ }
227
+ }
228
+ return acc;
229
+ }
230
+
231
+ /**
232
+ * Whole-repo tree-walk driver shared by every `lint-<derivation>-drift.cjs`
233
+ * guard. Resolves `root`, walks each of `scanDirs` filtered to `scanExt`
234
+ * (symlink-following, root-confined, cycle-guarded — see `walk` above), reads
235
+ * each discovered file, and calls `onFile(relPath, text)` for it — `relPath`
236
+ * is repo-relative and already the file's canonical (real) path, so a
237
+ * per-file exemption keyed on `relPath` matches consistently regardless of
238
+ * which symlink reached it.
239
+ *
240
+ * `onFile` returns an array of violation objects (or an empty array / null /
241
+ * undefined for "no violations in this file"); `scanTree` flattens them all
242
+ * into one returned array. Pure I/O orchestration — detection logic lives
243
+ * entirely in the caller's `onFile`.
244
+ */
245
+ function scanTree({ root, scanDirs, scanExt, onFile }) {
246
+ const violations = [];
247
+ let realRoot;
248
+ try {
249
+ realRoot = fs.realpathSync(root);
250
+ } catch {
251
+ return violations; // root itself does not exist / is unreadable
252
+ }
253
+ for (const dir of scanDirs) {
254
+ const scanDirPath = path.join(root, dir);
255
+ let scanDirRoot;
256
+ try {
257
+ scanDirRoot = fs.realpathSync(scanDirPath);
258
+ } catch {
259
+ continue; // scan directory itself does not exist / is unreadable
260
+ }
261
+ const ctx = { realRoot, scanDirRoot, scanExt, visitedRealDirs: new Set(), visitedRealFiles: new Set() };
262
+ for (const file of walk(scanDirPath, [], ctx)) {
263
+ const rel = path.relative(realRoot, file);
264
+ let text;
265
+ try {
266
+ text = fs.readFileSync(file, 'utf8');
267
+ } catch {
268
+ continue;
269
+ }
270
+ const found = onFile(rel, text);
271
+ if (found && found.length > 0) violations.push(...found);
272
+ }
273
+ }
274
+ return violations;
275
+ }
276
+
277
+ // A reported fragment AND a reported file path are both attacker-controlled
278
+ // source text on a fork PR (a repo can legally track a filename containing
279
+ // control bytes, so the path is exactly as attacker-controlled as the
280
+ // fragment), and both are written straight to a CI log. Replace C0/C1
281
+ // control bytes (ANSI escapes included) with a visible \xNN, AND the
282
+ // non-Latin-1 formatting/bidi/line-separator codepoints below with \uNNNN, so
283
+ // a crafted literal or filename cannot rewrite the terminal rendering of the
284
+ // report or hide/reorder its own text:
285
+ // - U+200B-U+200F: zero-width space/joiners and directional marks
286
+ // - U+2028/U+2029: Unicode LINE SEPARATOR / PARAGRAPH SEPARATOR (line
287
+ // breaks a `\n`-only log scan would not catch)
288
+ // - U+202A-U+202E: bidi embedding/override controls (RLO etc.)
289
+ // - U+2066-U+2069: bidi isolate controls
290
+ function sanitizeForReport(text) {
291
+ return text
292
+ // eslint-disable-next-line no-control-regex -- the control range IS the target
293
+ .replace(/[\x00-\x1f\x7f-\x9f]/g, (c) => '\\x' + c.charCodeAt(0).toString(16).padStart(2, '0'))
294
+ .replace(/[\u200B-\u200F\u2028\u2029\u202A-\u202E\u2066-\u2069]/g, (c) => '\\u' + c.charCodeAt(0).toString(16).padStart(4, '0'));
295
+ }
296
+
297
+ module.exports = {
298
+ SKIP_DIR_NAMES,
299
+ isInsideRoot,
300
+ isUnderSkippedDir,
301
+ walk,
302
+ readRegexLiteralAt,
303
+ MAX_REGEX_LITERAL_LEN,
304
+ sanitizeForReport,
305
+ scanTree,
306
+ resetRegexScanStats,
307
+ getRegexScanStats,
308
+ };
@@ -0,0 +1,98 @@
1
+ 'use strict';
2
+
3
+ // GENERATED FILE — DO NOT EDIT BY HAND.
4
+ // Source of truth: gsd-core/bin/shared/exit-codes.json. Regenerate with:
5
+ // node scripts/gen-exit-code-registry.cjs --write
6
+ // This exact content is emitted to THREE locations — gsd-core/bin/lib/exit-code-registry.cjs,
7
+ // scripts/lib/exit-code-registry.cjs, and hooks/lib/exit-code-registry.js (the latter two
8
+ // committed so scripts/ and hooks/ consumers work on an unbuilt clone) — all byte-compared by
9
+ // `npm run lint:generated-sync` (#3905 ADR-3889 Phase 1; #3906 Phase 2 added the second copy;
10
+ // #3911 ADR-3889 Phase 7 added the hooks/lib/ copy).
11
+ //
12
+ // exitCodeFor(name) / nameForExitCode(code) are pure and total over this
13
+ // closed table — each throws for anything not registered here.
14
+
15
+ const EXIT_CODES = Object.freeze([
16
+ Object.freeze({
17
+ code: 2,
18
+ name: "HOOK_DENY",
19
+ meaning: "Hook protocol deny — the harness blocks the tool call",
20
+ owner: "hook-adapter",
21
+ authorizedBy: "ADR-3889",
22
+ }),
23
+ Object.freeze({
24
+ code: 64,
25
+ name: "USAGE",
26
+ meaning: "Caller error — bad argv, unknown subcommand, missing argument",
27
+ owner: "generic",
28
+ authorizedBy: "ADR-3889",
29
+ }),
30
+ Object.freeze({
31
+ code: 66,
32
+ name: "NO_INPUT",
33
+ meaning: "Ran; zero units were in scope, and that emptiness is known to be genuine",
34
+ owner: "generic",
35
+ authorizedBy: "ADR-3889",
36
+ }),
37
+ Object.freeze({
38
+ code: 69,
39
+ name: "UNAVAILABLE",
40
+ meaning: "Could not run — prerequisite absent, input unreadable, scope unestablished",
41
+ owner: "generic",
42
+ authorizedBy: "ADR-3889",
43
+ }),
44
+ Object.freeze({
45
+ code: 70,
46
+ name: "INTERNAL",
47
+ meaning: "Self-failure — crash, timeout, killed subprocess",
48
+ owner: "generic",
49
+ authorizedBy: "ADR-3889",
50
+ }),
51
+ Object.freeze({
52
+ code: 80,
53
+ name: "DEGRADED",
54
+ meaning: "Ran to completion and is reporting a condition through its result payload rather than as a process failure",
55
+ owner: "gsd-tools",
56
+ authorizedBy: "ADR-3889 + ADR-2980",
57
+ })
58
+ ]);
59
+
60
+ const NAME_TO_CODE = new Map(EXIT_CODES.map((entry) => [entry.name, entry.code]));
61
+ const CODE_TO_NAME = new Map(EXIT_CODES.map((entry) => [entry.code, entry.name]));
62
+
63
+ /**
64
+ * Resolve the registered exit code for a symbolic name. Pure, total: throws
65
+ * for anything not an exact, registered, exact-case key — including
66
+ * non-strings, the empty string, untrimmed strings, wrong case, and
67
+ * prototype-chain names like `__proto__`/`constructor`/`toString` (a Map
68
+ * lookup never touches the prototype chain, so these are indistinguishable
69
+ * from any other unregistered name).
70
+ *
71
+ * @param {string} name
72
+ * @returns {number}
73
+ */
74
+ function exitCodeFor(name) {
75
+ if (typeof name !== 'string' || name.length === 0) {
76
+ throw new Error(`exitCodeFor: name must be a non-empty string, received ${JSON.stringify(name)}`);
77
+ }
78
+ if (!NAME_TO_CODE.has(name)) {
79
+ throw new Error(`exitCodeFor: unregistered exit code name: ${JSON.stringify(name)}`);
80
+ }
81
+ return NAME_TO_CODE.get(name);
82
+ }
83
+
84
+ /**
85
+ * Reverse of exitCodeFor: resolve the symbolic name for a registered exit
86
+ * code. Pure, total: throws for anything not an exact, registered code.
87
+ *
88
+ * @param {number} code
89
+ * @returns {string}
90
+ */
91
+ function nameForExitCode(code) {
92
+ if (!CODE_TO_NAME.has(code)) {
93
+ throw new Error(`nameForExitCode: unregistered exit code: ${JSON.stringify(code)}`);
94
+ }
95
+ return CODE_TO_NAME.get(code);
96
+ }
97
+
98
+ module.exports = { EXIT_CODES, exitCodeFor, nameForExitCode };
@@ -0,0 +1,119 @@
1
+ 'use strict';
2
+
3
+ // Machine-readable companion reporter for scripts/run-tests.cjs (#3889).
4
+ //
5
+ // node:test's built-in reporters (spec/tap) are human-formatted and
6
+ // scripts/run-tests.cjs spawns the child with `stdio: 'inherit'` — by design,
7
+ // per #3597/#1051, to avoid the maxBuffer and live-output risks of piping —
8
+ // so the parent process has no way to see WHICH file was executing when a
9
+ // per-chunk timeout kills the child. This reporter runs ALONGSIDE the normal
10
+ // human reporter (a second `--test-reporter` on the same invocation, per
11
+ // Node's documented multi-reporter pairing) and appends one JSON object per
12
+ // line to a path supplied via the GSD_RUN_TESTS_EVENTS_FILE env var. On a
13
+ // timeout, run-tests.cjs reads that file back to name the file(s) still
14
+ // in flight (a `test:dequeue` with no matching `test:pass`/`test:fail`).
15
+ //
16
+ // Durability, not `--test-reporter-destination` (#3889 root cause): a
17
+ // reporter that YIELDS strings has them piped by Node into a
18
+ // `fs.WriteStream` targeting the destination path, and that stream buffers.
19
+ // The parent's `execFileSync` timeout SIGKILLs the child on a hang, and
20
+ // SIGKILL is uncatchable and gives the process zero chance to flush — so a
21
+ // yield-based reporter can lose every event still sitting in the stream's
22
+ // buffer, which is exactly the case this feature exists to diagnose (proven
23
+ // live: a chunk killed at 2006ms produced a `killed after 2006ms` line from
24
+ // the TIMER, which lives in the parent, but zero usable events from the
25
+ // reporter, which lives in the child and never flushed). Writing each event
26
+ // with `fs.appendFileSync` — synchronous and unbuffered — makes it durable
27
+ // the instant it happens, before the process can be killed out from under
28
+ // it. The reporter therefore yields NOTHING; it is a pure side-effecting
29
+ // sink. Node still requires a `--test-reporter-destination` to pair with
30
+ // this `--test-reporter` (see run-tests.cjs's reporterArgsFor), but that
31
+ // destination is a throwaway sink that stays empty by design — the durable
32
+ // path is GSD_RUN_TESTS_EVENTS_FILE, not the destination Node manages.
33
+ //
34
+ // Contract targeted: Node's "Custom reporters" contract
35
+ // (https://nodejs.org/api/test.html#custom-reporters) — a reporter module's
36
+ // default export is a function receiving the test runner's event stream (an
37
+ // AsyncIterable of `{ type, data }` objects). Node feeds that function to
38
+ // `stream.compose` as the stream's "body". When the body is an async
39
+ // FUNCTION (not an `async function*` generator), `stream.compose`'s own
40
+ // contract (https://nodejs.org/api/stream.html#streamcomposestreams)
41
+ // requires it to return nully (undefined/null) — returning anything else,
42
+ // including an array, throws `ERR_INVALID_RETURN_VALUE` ("Expected nully to
43
+ // be returned from the 'body' function but got an instance of Array")
44
+ // exactly once the promise resolves. Verified directly against
45
+ // `stream.compose` in this repo's Node: calling it with a body that
46
+ // `return`s `[]` reproduces that same TypeError. A generator form
47
+ // (`async function*`) is the one that yields an iterable; the plain
48
+ // `async function` form used here is the one that must return nully. This
49
+ // repo's `engines.node` requires >=24.0.0 (package.json), where both
50
+ // contracts have been stable since Node 20.
51
+ //
52
+ // Kept intentionally tiny: only the five event types run-tests.cjs needs are
53
+ // handled — `test:enqueue`/`test:dequeue` (emitted by the RUNNER as it queues
54
+ // and begins each spawned test-file child, independent of whether anything
55
+ // inside that file ever completes) plus `test:start`/`test:pass`/`test:fail`
56
+ // (emitted per-subtest, once the child reports it). `test:dequeue` is the
57
+ // event that actually means "in flight": a subtest inside a file that hangs
58
+ // forever never reaches `test:start`/`test:pass`/`test:fail` at all, because
59
+ // node:test only surfaces those to the parent once the child COMPLETES that
60
+ // test — a hang, by definition, never completes. Recording `test:dequeue`
61
+ // closes that gap: it fires the moment the runner begins the file, so a
62
+ // killed hang still leaves a durable "this file was running" record.
63
+ // Everything else (diagnostics, plans, coverage) is ignored so a truncated
64
+ // events file (the process is SIGKILLed mid-`appendFileSync` on timeout — an
65
+ // individual write is unbuffered but not atomic, so the OS can still
66
+ // interleave a partial write with the kill) never leaves more than one
67
+ // dangling unparsable trailing line.
68
+ module.exports = async function ndjsonEventReporter(source) {
69
+ const eventsPath = process.env.GSD_RUN_TESTS_EVENTS_FILE;
70
+ // #3889: an init marker, written as this reporter's FIRST action — before
71
+ // the `for await` loop even begins consuming the event stream — so the
72
+ // events file's mere existence (and its exact contents) can distinguish
73
+ // "the reporter module never loaded in the child at all" (file absent)
74
+ // from "it loaded fine but no test:start reached it before the kill"
75
+ // (file contains only this one line) from "it's working" (file contains
76
+ // more than this line). Same appendFileSync durability rationale as every
77
+ // other write in this file: synchronous and unbuffered, so it survives an
78
+ // uncatchable SIGKILL landing a moment later.
79
+ if (eventsPath) {
80
+ try {
81
+ require('fs').appendFileSync(eventsPath, `${JSON.stringify({ type: 'reporter:init', ts: Date.now() })}\n`);
82
+ } catch {
83
+ // Best-effort, same as every other write below — must never crash the
84
+ // test run this reporter is only observing.
85
+ }
86
+ }
87
+ for await (const event of source) {
88
+ if (!eventsPath) continue; // no destination configured — nothing to record
89
+ if (
90
+ event.type === 'test:enqueue' ||
91
+ event.type === 'test:dequeue' ||
92
+ event.type === 'test:start' ||
93
+ event.type === 'test:pass' ||
94
+ event.type === 'test:fail'
95
+ ) {
96
+ const { file, name, nesting, testNumber } = event.data || {};
97
+ const line = `${JSON.stringify({
98
+ type: event.type,
99
+ file,
100
+ name,
101
+ nesting,
102
+ testNumber,
103
+ ts: Date.now(),
104
+ })}\n`;
105
+ try {
106
+ require('fs').appendFileSync(eventsPath, line);
107
+ } catch {
108
+ // Best-effort: a write failure here (e.g. the events dir vanished)
109
+ // must never crash the test run this reporter is only observing.
110
+ }
111
+ }
112
+ }
113
+ // Falls through to an implicit `return undefined` (nully): this reporter is
114
+ // a pure side-effecting sink (see the durability note above), never a
115
+ // source of reporter OUTPUT, and `stream.compose` requires its async
116
+ // FUNCTION body to return nully — returning an iterable (e.g. `[]`) here
117
+ // raises `ERR_INVALID_RETURN_VALUE` (observed live: this exact `return []`
118
+ // crashed every chunk on the real remote run this regresses).
119
+ };
@@ -2,7 +2,6 @@
2
2
  "tests/agent-classification-parity.test.cjs :: source-text-is-the-product",
3
3
  "tests/agent-frontmatter.test.cjs :: source-text-is-the-product",
4
4
  "tests/agent-required-reading-consistency.test.cjs :: source-text-is-the-product",
5
- "tests/agent-size-budget.test.cjs :: source-text-is-the-product",
6
5
  "tests/agent-skills-awareness.test.cjs :: source-text-is-the-product",
7
6
  "tests/ai-evals.test.cjs :: source-text-is-the-product",
8
7
  "tests/analyze-dependencies.test.cjs :: source-text-is-the-product",
@@ -16,9 +15,7 @@
16
15
  "tests/autonomous-to-flag.test.cjs :: source-text-is-the-product",
17
16
  "tests/chain-flag-plan-phase.test.cjs :: source-text-is-the-product",
18
17
  "tests/changeset-cli.test.cjs :: source-text-is-the-product",
19
- "tests/check-update-config-dir.test.cjs :: structural-regression-guard",
20
18
  "tests/claude-md.test.cjs :: source-text-is-the-product",
21
- "tests/claude-skills-migration.test.cjs :: source-text-is-the-product",
22
19
  "tests/cleanup-branch-pruning.test.cjs :: source-text-is-the-product",
23
20
  "tests/cline-install.test.cjs :: source-text-is-the-product",
24
21
  "tests/cline-support.test.cjs :: source-text-is-the-product",
@@ -30,7 +27,6 @@
30
27
  "tests/codex-config.test.cjs :: source-text-is-the-product",
31
28
  "tests/command-contract.test.cjs :: source-text-is-the-product",
32
29
  "tests/commands.test.cjs :: source-text-is-the-product",
33
- "tests/concurrency-safety.test.cjs :: source-text-is-the-product",
34
30
  "tests/config-field-docs.test.cjs :: docs-parity",
35
31
  "tests/context-enrichment.test.cjs :: source-text-is-the-product",
36
32
  "tests/contributor-standards.test.cjs :: source-text-is-the-product",
@@ -38,9 +34,7 @@
38
34
  "tests/cursor-hooks.test.cjs :: source-text-is-the-product",
39
35
  "tests/cursor-reviewer.test.cjs :: source-text-is-the-product",
40
36
  "tests/debug-session-management.test.cjs :: source-text-is-the-product",
41
- "tests/discuss-all-flag.test.cjs :: source-text-is-the-product",
42
37
  "tests/discuss-checkpoint.test.cjs :: source-text-is-the-product",
43
- "tests/discuss-mode.test.cjs :: structural-implementation-guard",
44
38
  "tests/discuss-phase-power.test.cjs :: source-text-is-the-product",
45
39
  "tests/docs-parity-live-registry.test.cjs :: source-text-is-the-product",
46
40
  "tests/drift-detection.test.cjs :: source-text-is-the-product",
@@ -48,9 +42,6 @@
48
42
  "tests/edge-probe-planner-contract.test.cjs :: source-text-is-the-product",
49
43
  "tests/edge-probe-spec-phase-contract.test.cjs :: source-text-is-the-product",
50
44
  "tests/edit-phase.test.cjs :: source-text-is-the-product",
51
- "tests/eslint-rules.test.cjs :: <source-grep reason> must still error",
52
- "tests/eslint-rules.test.cjs :: pending migration",
53
- "tests/eslint-rules.test.cjs :: source-text-is-the-product",
54
45
  "tests/execute-phase-active-flags.test.cjs :: source-text-is-the-product",
55
46
  "tests/execute-phase-step-5-5-deviation-doc.test.cjs :: source-text-is-the-product",
56
47
  "tests/execute-phase-wave.test.cjs :: source-text-is-the-product",
@@ -65,26 +56,16 @@
65
56
  "tests/gsd-researcher-app-aware.test.cjs :: source-text-is-the-product",
66
57
  "tests/gsd-researcher-flow-diagram.test.cjs :: source-text-is-the-product",
67
58
  "tests/gsd-settings-advanced.test.cjs :: source-text-is-the-product",
68
- "tests/gsd2-import.test.cjs :: source-text-is-the-product",
59
+ "tests/helpers/live-command-registry.cjs :: source-text-is-the-product",
69
60
  "tests/hermes-skills-migration.test.cjs :: source-text-is-the-product",
70
61
  "tests/import-command.test.cjs :: source-text-is-the-product",
71
62
  "tests/ingest-docs.test.cjs :: source-text-is-the-product",
72
63
  "tests/inline-plan-threshold.test.cjs :: source-text-is-the-product",
73
- "tests/install-minimal-hooks.test.cjs :: source-text-is-the-product",
74
64
  "tests/install-nested-layout.test.cjs :: source-text-is-the-product",
75
65
  "tests/install-runtime-artifacts.test.cjs :: source-text-is-the-product",
76
- "tests/install.test.cjs :: source-text-is-the-product",
77
66
  "tests/intel.test.cjs :: source-text-is-the-product",
78
67
  "tests/inventory-headings-countfree.test.cjs :: source-text-is-the-product",
79
68
  "tests/ios-scaffold-safety.test.cjs :: source-text-is-the-product",
80
- "tests/issue-2639-codex-toml-neutralization.test.cjs :: source-text-is-the-product",
81
- "tests/issue-429-comment-text-gate.test.cjs :: source-text-is-the-product",
82
- "tests/issue-498-update-backup-runtime-dir.test.cjs :: source-text-is-the-product",
83
- "tests/issue-57-runtime-install-no-drift.test.cjs :: structural-regression-guard",
84
- "tests/issue-607-installer-dry-run.install.test.cjs :: integration-test-input",
85
- "tests/issue-607-legacy-cleanup.test.cjs :: integration-test-input",
86
- "tests/issue-787-cline-hooks-agents.test.cjs :: source-text-is-the-product",
87
- "tests/issue-815-update-next-channel.test.cjs :: source-text-is-the-product",
88
69
  "tests/locking-bugs-1909-1916-1925-1927.test.cjs :: architectural-invariant",
89
70
  "tests/mcp-tool-inheritance.test.cjs :: source-text-is-the-product",
90
71
  "tests/milestone-summary.test.cjs :: source-text-is-the-product",
@@ -93,13 +74,10 @@
93
74
  "tests/next-safety-gates.test.cjs :: source-text-is-the-product",
94
75
  "tests/next-up-clear-order.test.cjs :: source-text-is-the-product",
95
76
  "tests/no-hardcoded-home-gsd-tools.test.cjs :: source-text-is-the-product",
96
- "tests/opencode-permissions.test.cjs :: architectural-invariant",
97
- "tests/orphan-worktree-detection.test.cjs :: architectural-invariant",
98
77
  "tests/orphaned-hooks.test.cjs :: structural-regression-guard",
99
78
  "tests/package-legitimacy-gate.test.cjs :: source-text-is-the-product",
100
79
  "tests/parallel-dependent-plans.test.cjs :: source-text-is-the-product",
101
80
  "tests/path-replacement.test.cjs :: source-text-is-the-product",
102
- "tests/phase-dependency-levels.test.cjs :: source-text-is-the-product",
103
81
  "tests/phase.test.cjs :: source-text-is-the-product",
104
82
  "tests/phase6-capability-docs.test.cjs :: source-text-is-the-product",
105
83
  "tests/phase6-capstone-conformance.test.cjs :: source-text-is-the-product",
@@ -117,7 +95,6 @@
117
95
  "tests/profile-output.test.cjs :: source-text-is-the-product",
118
96
  "tests/progress-forensic.test.cjs :: source-text-is-the-product",
119
97
  "tests/prompt-thinning.test.cjs :: source-text-is-the-product",
120
- "tests/quick-session-management.test.cjs :: source-text-is-the-product",
121
98
  "tests/qwen-skills-migration.test.cjs :: source-text-is-the-product",
122
99
  "tests/read-guard.test.cjs :: source-text-is-the-product",
123
100
  "tests/reapply-patches.test.cjs :: source-text-is-the-product",
@@ -126,7 +103,6 @@
126
103
  "tests/release-tarball-smoke-workflow.test.cjs :: source-text-is-the-product",
127
104
  "tests/release-tarball-smoke.install.test.cjs :: integration-test-input",
128
105
  "tests/research-agent-profiles.test.cjs :: source-text-is-the-product",
129
- "tests/review-default-reviewers-workflow.test.cjs :: source-text-is-the-product",
130
106
  "tests/roadmap.test.cjs :: source-text-is-the-product",
131
107
  "tests/runtime-launcher-parity.test.cjs :: structural-regression-guard",
132
108
  "tests/runtime-name-policy.test.cjs :: source-text-is-the-product",
@@ -144,7 +120,6 @@
144
120
  "tests/subagent-timeout.test.cjs :: source-text-is-the-product",
145
121
  "tests/template.test.cjs :: source-text-is-the-product",
146
122
  "tests/thinking-partner.test.cjs :: source-text-is-the-product",
147
- "tests/thread-session-management.test.cjs :: source-text-is-the-product",
148
123
  "tests/ultraplan-phase.test.cjs :: source-text-is-the-product",
149
124
  "tests/verify-health.test.cjs :: source-text-is-the-product",
150
125
  "tests/verify-test-quality.test.cjs :: source-text-is-the-product",
@@ -0,0 +1,4 @@
1
+ {
2
+ "maxSites": 10,
3
+ "grace": 2
4
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "maxFiles": 282
3
+ }