@opengsd/gsd-core 1.14.0 → 1.16.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 (551) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/.opencode/plugins/gsd-core.js +85 -5
  4. package/README.ja-JP.md +3 -3
  5. package/README.ko-KR.md +3 -3
  6. package/README.pt-BR.md +3 -3
  7. package/README.zh-CN.md +3 -3
  8. package/agents/gsd-code-fixer.compact.md +7 -6
  9. package/agents/gsd-code-fixer.md +9 -8
  10. package/agents/gsd-code-reviewer.compact.md +5 -3
  11. package/agents/gsd-code-reviewer.md +8 -6
  12. package/agents/gsd-debug-session-manager.compact.md +17 -2
  13. package/agents/gsd-debug-session-manager.md +17 -2
  14. package/agents/gsd-debugger.md +3 -3
  15. package/agents/gsd-eval-auditor.compact.md +1 -1
  16. package/agents/gsd-eval-auditor.md +1 -1
  17. package/agents/gsd-executor.md +17 -12
  18. package/agents/gsd-intel-updater.compact.md +1 -1
  19. package/agents/gsd-intel-updater.md +1 -1
  20. package/agents/gsd-mempalace-curator.md +2 -2
  21. package/agents/gsd-phase-researcher.md +19 -11
  22. package/agents/gsd-plan-checker.md +15 -9
  23. package/agents/gsd-planner.md +15 -11
  24. package/agents/gsd-project-researcher.compact.md +1 -1
  25. package/agents/gsd-project-researcher.md +1 -1
  26. package/agents/gsd-research-synthesizer.compact.md +1 -1
  27. package/agents/gsd-research-synthesizer.md +1 -1
  28. package/agents/gsd-ui-auditor.compact.md +21 -30
  29. package/agents/gsd-ui-auditor.md +166 -37
  30. package/agents/gsd-ui-researcher.compact.md +1 -1
  31. package/agents/gsd-ui-researcher.md +1 -1
  32. package/agents/gsd-verifier.md +37 -14
  33. package/bin/install.js +764 -287
  34. package/commands/gsd/add-tests.md +6 -1
  35. package/commands/gsd/ai-integration-phase.md +6 -1
  36. package/commands/gsd/audit-fix.md +5 -0
  37. package/commands/gsd/audit-milestone.md +6 -1
  38. package/commands/gsd/autonomous.md +7 -2
  39. package/commands/gsd/capture.md +9 -5
  40. package/commands/gsd/code-review.md +7 -2
  41. package/commands/gsd/complete-milestone.md +4 -0
  42. package/commands/gsd/config.md +7 -3
  43. package/commands/gsd/debug.md +11 -7
  44. package/commands/gsd/discuss-phase.md +7 -3
  45. package/commands/gsd/docs-update.md +12 -7
  46. package/commands/gsd/eval-review.md +6 -1
  47. package/commands/gsd/execute-phase.md +12 -7
  48. package/commands/gsd/extract-learnings.md +5 -0
  49. package/commands/gsd/fast.md +4 -0
  50. package/commands/gsd/forensics.md +5 -1
  51. package/commands/gsd/graphify.md +10 -6
  52. package/commands/gsd/health.md +5 -0
  53. package/commands/gsd/help.md +7 -2
  54. package/commands/gsd/import.md +7 -3
  55. package/commands/gsd/inbox.md +5 -0
  56. package/commands/gsd/ingest-docs.md +5 -1
  57. package/commands/gsd/manager.md +6 -1
  58. package/commands/gsd/map-codebase.md +7 -3
  59. package/commands/gsd/mempalace-capture.md +12 -4
  60. package/commands/gsd/mempalace-recall.md +5 -1
  61. package/commands/gsd/milestone-summary.md +5 -1
  62. package/commands/gsd/mvp-phase.md +8 -3
  63. package/commands/gsd/new-milestone.md +6 -1
  64. package/commands/gsd/new-project.md +5 -0
  65. package/commands/gsd/next.md +6 -1
  66. package/commands/gsd/ns-context.md +4 -0
  67. package/commands/gsd/ns-ideate.md +4 -0
  68. package/commands/gsd/ns-manage.md +4 -0
  69. package/commands/gsd/ns-project.md +4 -0
  70. package/commands/gsd/ns-review.md +4 -0
  71. package/commands/gsd/ns-workflow.md +4 -0
  72. package/commands/gsd/onboard.md +6 -1
  73. package/commands/gsd/pause-work.md +5 -1
  74. package/commands/gsd/phase.md +8 -4
  75. package/commands/gsd/plan-phase.md +6 -1
  76. package/commands/gsd/plan-review-convergence.md +11 -7
  77. package/commands/gsd/pr-branch.md +4 -0
  78. package/commands/gsd/profile-user.md +5 -1
  79. package/commands/gsd/progress.md +7 -2
  80. package/commands/gsd/quick-batch.md +21 -9
  81. package/commands/gsd/quick.md +12 -7
  82. package/commands/gsd/review.md +7 -4
  83. package/commands/gsd/secure-phase.md +6 -1
  84. package/commands/gsd/ship.md +5 -0
  85. package/commands/gsd/sketch.md +7 -2
  86. package/commands/gsd/spec-phase.md +5 -1
  87. package/commands/gsd/spike.md +8 -3
  88. package/commands/gsd/surface.md +5 -1
  89. package/commands/gsd/thread.md +4 -0
  90. package/commands/gsd/ui-phase.md +6 -1
  91. package/commands/gsd/ui-review.md +6 -1
  92. package/commands/gsd/ultraplan-phase.md +5 -1
  93. package/commands/gsd/undo.md +5 -1
  94. package/commands/gsd/update.md +6 -2
  95. package/commands/gsd/validate-phase.md +6 -1
  96. package/commands/gsd/verify-work.md +6 -1
  97. package/commands/gsd/workspace.md +7 -3
  98. package/gsd-core/bin/gsd-tools.cjs +477 -78
  99. package/gsd-core/bin/lib/active-workstream-store.cjs +15 -0
  100. package/gsd-core/bin/lib/adr-parser.cjs +3 -1
  101. package/gsd-core/bin/lib/agent-install-check.cjs +4 -1
  102. package/gsd-core/bin/lib/audit.cjs +144 -42
  103. package/gsd-core/bin/lib/broken-windows.cjs +13 -13
  104. package/gsd-core/bin/lib/capability-activation.cjs +9 -4
  105. package/gsd-core/bin/lib/capability-registry.cjs +197 -222
  106. package/gsd-core/bin/lib/capability-validator.cjs +16 -1
  107. package/gsd-core/bin/lib/check-auto-mode.cjs +35 -0
  108. package/gsd-core/bin/lib/check-command-router.cjs +164 -1625
  109. package/gsd-core/bin/lib/cjs-command-router-adapter.cjs +13 -2
  110. package/gsd-core/bin/lib/cli-exit.cjs +12 -0
  111. package/gsd-core/bin/lib/codex-agent-toml.cjs +32 -33
  112. package/gsd-core/bin/lib/command-aliases.cjs +7 -0
  113. package/gsd-core/bin/lib/command-routing-hub.cjs +48 -1
  114. package/gsd-core/bin/lib/commands.cjs +343 -207
  115. package/gsd-core/bin/lib/complexity-trigger.cjs +8 -7
  116. package/gsd-core/bin/lib/config-loader.cjs +65 -4
  117. package/gsd-core/bin/lib/config.cjs +76 -19
  118. package/gsd-core/bin/lib/core-utils.cjs +6 -1
  119. package/gsd-core/bin/lib/coverage.cjs +4 -8
  120. package/gsd-core/bin/lib/decision-coverage-support.cjs +259 -0
  121. package/gsd-core/bin/lib/decisions.cjs +30 -14
  122. package/gsd-core/bin/lib/drift.cjs +177 -42
  123. package/gsd-core/bin/lib/frontmatter-fence.cjs +90 -0
  124. package/gsd-core/bin/lib/frontmatter-splice.cjs +494 -0
  125. package/gsd-core/bin/lib/frontmatter.cjs +426 -234
  126. package/gsd-core/bin/lib/gap-checker.cjs +72 -29
  127. package/gsd-core/bin/lib/gate-api-coverage-verify-pre.cjs +381 -0
  128. package/gsd-core/bin/lib/gate-args.cjs +53 -0
  129. package/gsd-core/bin/lib/gate-codebase-drift.cjs +285 -0
  130. package/gsd-core/bin/lib/gate-config.cjs +46 -0
  131. package/gsd-core/bin/lib/gate-context-drift.cjs +141 -0
  132. package/gsd-core/bin/lib/gate-decision-coverage-plan.cjs +169 -0
  133. package/gsd-core/bin/lib/gate-decision-coverage-verify.cjs +126 -0
  134. package/gsd-core/bin/lib/gate-evaluation-scope.cjs +555 -0
  135. package/gsd-core/bin/lib/gate-evidence.cjs +138 -0
  136. package/gsd-core/bin/lib/gate-exit.cjs +27 -0
  137. package/gsd-core/bin/lib/gate-gap-analysis-plan-post.cjs +61 -0
  138. package/gsd-core/bin/lib/gate-phase-context.cjs +170 -0
  139. package/gsd-core/bin/lib/gate-predicate-evaluator.cjs +1 -1
  140. package/gsd-core/bin/lib/gate-predicate.cjs +165 -0
  141. package/gsd-core/bin/lib/gate-prohibition-enforcement.cjs +94 -0
  142. package/gsd-core/bin/lib/gate-schema-drift.cjs +165 -0
  143. package/gsd-core/bin/lib/gate-tdd-red-evidence.cjs +100 -0
  144. package/gsd-core/bin/lib/gate-tdd-review-checkpoint.cjs +182 -0
  145. package/gsd-core/bin/lib/gate-ui-plan.cjs +86 -0
  146. package/gsd-core/bin/lib/gate-ui-safety.cjs +80 -0
  147. package/gsd-core/bin/lib/gate-verdict.cjs +64 -0
  148. package/gsd-core/bin/lib/gate-verify-command-paths.cjs +78 -0
  149. package/gsd-core/bin/lib/gate-verify-failure-directions.cjs +41 -0
  150. package/gsd-core/bin/lib/graphify.cjs +10 -2
  151. package/gsd-core/bin/lib/health-diagnostic-rules/phase-structure.cjs +43 -47
  152. package/gsd-core/bin/lib/health-diagnostic.cjs +45 -8
  153. package/gsd-core/bin/lib/host-runtime-detection.cjs +9 -0
  154. package/gsd-core/bin/lib/init.cjs +364 -132
  155. package/gsd-core/bin/lib/install-engine.cjs +30 -33
  156. package/gsd-core/bin/lib/install-profiles.cjs +7 -4
  157. package/gsd-core/bin/lib/installer-migrations.cjs +8 -1
  158. package/gsd-core/bin/lib/io.cjs +122 -3
  159. package/gsd-core/bin/lib/loop-resolver.cjs +95 -0
  160. package/gsd-core/bin/lib/markdown-sectionizer.cjs +75 -1
  161. package/gsd-core/bin/lib/milestone.cjs +37 -6
  162. package/gsd-core/bin/lib/model-resolver.cjs +171 -62
  163. package/gsd-core/bin/lib/observability/event.cjs +1 -1
  164. package/gsd-core/bin/lib/observability/logger.cjs +46 -1
  165. package/gsd-core/bin/lib/pattern.cjs +10 -0
  166. package/gsd-core/bin/lib/phase-command-router.cjs +20 -5
  167. package/gsd-core/bin/lib/phase-estimation.cjs +5 -4
  168. package/gsd-core/bin/lib/phase-id-card.cjs +32 -0
  169. package/gsd-core/bin/lib/phase-id-display.cjs +78 -0
  170. package/gsd-core/bin/lib/phase-id.cjs +110 -8
  171. package/gsd-core/bin/lib/phase-lifecycle.cjs +9 -2
  172. package/gsd-core/bin/lib/phase-locator.cjs +29 -10
  173. package/gsd-core/bin/lib/phase-status.cjs +360 -0
  174. package/gsd-core/bin/lib/phase.cjs +489 -88
  175. package/gsd-core/bin/lib/plan-document.cjs +142 -20
  176. package/gsd-core/bin/lib/plan-drift-guard.cjs +5 -0
  177. package/gsd-core/bin/lib/planning-document.cjs +692 -0
  178. package/gsd-core/bin/lib/planning-inspect.cjs +60 -9
  179. package/gsd-core/bin/lib/planning-snapshot.cjs +18 -0
  180. package/gsd-core/bin/lib/planning-workspace.cjs +83 -55
  181. package/gsd-core/bin/lib/pr-branch-patterns.cjs +57 -0
  182. package/gsd-core/bin/lib/pristine-baseline.cjs +10 -0
  183. package/gsd-core/bin/lib/probe-core.cjs +7 -1
  184. package/gsd-core/bin/lib/profile-output.cjs +6 -3
  185. package/gsd-core/bin/lib/prohibition-enforcement.cjs +0 -55
  186. package/gsd-core/bin/lib/project-root.cjs +41 -2
  187. package/gsd-core/bin/lib/quick-batch-command-router.cjs +35 -9
  188. package/gsd-core/bin/lib/quick-batch-dispatch.cjs +11 -8
  189. package/gsd-core/bin/lib/real-home-guard.cjs +9 -1
  190. package/gsd-core/bin/lib/report-parser.cjs +269 -0
  191. package/gsd-core/bin/lib/review-lane-descriptor.cjs +10 -30
  192. package/gsd-core/bin/lib/review-reviewer-selection.cjs +2 -2
  193. package/gsd-core/bin/lib/roadmap-command-router.cjs +25 -19
  194. package/gsd-core/bin/lib/roadmap-parser.cjs +242 -15
  195. package/gsd-core/bin/lib/roadmap-upgrade.cjs +1653 -65
  196. package/gsd-core/bin/lib/roadmap.cjs +405 -88
  197. package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +373 -187
  198. package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +5 -2
  199. package/gsd-core/bin/lib/runtime-artifact-layout.cjs +57 -1
  200. package/gsd-core/bin/lib/runtime-homes.cjs +14 -7
  201. package/gsd-core/bin/lib/runtime-hooks-surface.cjs +522 -624
  202. package/gsd-core/bin/lib/runtime-name-policy.cjs +246 -21
  203. package/gsd-core/bin/lib/runtime-slash.cjs +47 -30
  204. package/gsd-core/bin/lib/shell-command-projection.cjs +47 -8
  205. package/gsd-core/bin/lib/smart-entry.cjs +19 -3
  206. package/gsd-core/bin/lib/stale-bake-guard.cjs +32 -48
  207. package/gsd-core/bin/lib/state-contract.cjs +15 -18
  208. package/gsd-core/bin/lib/state-document.cjs +100 -22
  209. package/gsd-core/bin/lib/state-transition.cjs +39 -2
  210. package/gsd-core/bin/lib/state.cjs +256 -105
  211. package/gsd-core/bin/lib/surface.cjs +19 -2
  212. package/gsd-core/bin/lib/tdd-red-evidence.cjs +48 -79
  213. package/gsd-core/bin/lib/uat-predicate.cjs +359 -38
  214. package/gsd-core/bin/lib/uat.cjs +432 -7
  215. package/gsd-core/bin/lib/ui-consideration-probe.cjs +15 -2
  216. package/gsd-core/bin/lib/ui-frontend-evidence.cjs +167 -40
  217. package/gsd-core/bin/lib/undo-commit-selection.cjs +131 -0
  218. package/gsd-core/bin/lib/vendor/README.md +31 -9
  219. package/gsd-core/bin/lib/vendor/saxes.cjs +1934 -0
  220. package/gsd-core/bin/lib/vendor/saxes.cjs.LICENSE.txt +92 -0
  221. package/gsd-core/bin/lib/vendor/tap-parser.cjs +8927 -0
  222. package/gsd-core/bin/lib/vendor/tap-parser.cjs.LICENSE.txt +152 -0
  223. package/gsd-core/bin/lib/verification-command-router.cjs +2 -1
  224. package/gsd-core/bin/lib/verification.cjs +1378 -274
  225. package/gsd-core/bin/lib/verify-command-grounding.cjs +46 -2
  226. package/gsd-core/bin/lib/verify-command-router.cjs +18 -7
  227. package/gsd-core/bin/lib/verify.cjs +357 -531
  228. package/gsd-core/bin/lib/workstream-inventory-builder.cjs +14 -6
  229. package/gsd-core/bin/lib/workstream-inventory.cjs +31 -21
  230. package/gsd-core/bin/lib/workstream-name-policy.cjs +31 -1
  231. package/gsd-core/bin/lib/workstream.cjs +11 -2
  232. package/gsd-core/bin/lib/worktree-base-ref.cjs +482 -73
  233. package/gsd-core/bin/lib/worktree-safety.cjs +784 -51
  234. package/gsd-core/bin/shared/config-defaults.manifest.json +8 -0
  235. package/gsd-core/bin/shared/config-schema.manifest.json +5 -0
  236. package/gsd-core/references/autonomous-smart-discuss.md +2 -1
  237. package/gsd-core/references/autonomous-ui-design-contract.md +3 -3
  238. package/gsd-core/references/checkpoints.md +5 -3
  239. package/gsd-core/references/edge-probe-fixtures/01-round-half-even/expected-coverage.json +28 -3
  240. package/gsd-core/references/edge-probe-fixtures/02-merge-intervals/expected-coverage.json +37 -4
  241. package/gsd-core/references/edge-probe-fixtures/03-truncate-graphemes/expected-coverage.json +28 -3
  242. package/gsd-core/references/edge-probe-fixtures/04-money-rounding/expected-coverage.json +28 -3
  243. package/gsd-core/references/edge-probe-fixtures/05-list-dedupe/expected-coverage.json +37 -4
  244. package/gsd-core/references/edge-probe-fixtures/06-resolved-mixed/expected-coverage.json +37 -4
  245. package/gsd-core/references/edge-probe.md +195 -21
  246. package/gsd-core/references/execute-mvp-tdd.md +5 -10
  247. package/gsd-core/references/execute-phase-between-wave-reset.md +10 -6
  248. package/gsd-core/references/execute-phase-response-language.md +1 -1
  249. package/gsd-core/references/execute-phase-wave-guard.md +22 -11
  250. package/gsd-core/references/gsd-run-resolver.md +1 -1
  251. package/gsd-core/references/loop-hook-dispatch.md +7 -1
  252. package/gsd-core/references/model-profiles.md +1 -1
  253. package/gsd-core/references/offer-next.md +1 -1
  254. package/gsd-core/references/phase-argument-parsing.md +9 -7
  255. package/gsd-core/references/phase-id-convention.md +28 -0
  256. package/gsd-core/references/planner-gap-closure.md +2 -0
  257. package/gsd-core/references/planner-load-graph-context.md +24 -13
  258. package/gsd-core/references/planner-verify-command-grounding.md +14 -0
  259. package/gsd-core/references/planning-config.md +12 -3
  260. package/gsd-core/references/spidr-splitting.md +1 -1
  261. package/gsd-core/references/tdd.md +37 -8
  262. package/gsd-core/references/ui-consideration-probe.md +10 -5
  263. package/gsd-core/references/verifier-phase-gates.md +5 -2
  264. package/gsd-core/references/verify-command-path-resolvability.md +10 -2
  265. package/gsd-core/references/verify-mvp-mode.md +2 -2
  266. package/gsd-core/references/workstream-flag.md +33 -3
  267. package/gsd-core/references/worktree-path-safety.md +321 -0
  268. package/gsd-core/templates/README.md +1 -1
  269. package/gsd-core/templates/UAT.md +17 -1
  270. package/gsd-core/templates/config.json +2 -11
  271. package/gsd-core/templates/verification-report.md +1 -1
  272. package/gsd-core/workflows/_runtime-launcher.snippet.sh +1 -1
  273. package/gsd-core/workflows/add-backlog.md +1 -1
  274. package/gsd-core/workflows/add-phase.md +8 -7
  275. package/gsd-core/workflows/add-tests.md +4 -3
  276. package/gsd-core/workflows/add-todo.md +6 -5
  277. package/gsd-core/workflows/ai-integration-phase.md +13 -4
  278. package/gsd-core/workflows/audit-fix.md +1 -1
  279. package/gsd-core/workflows/audit-milestone.md +4 -3
  280. package/gsd-core/workflows/audit-uat.md +1 -1
  281. package/gsd-core/workflows/autonomous/steps/converge-fail-fast.md +9 -18
  282. package/gsd-core/workflows/autonomous.md +43 -23
  283. package/gsd-core/workflows/check-todos.md +7 -6
  284. package/gsd-core/workflows/cleanup.md +2 -2
  285. package/gsd-core/workflows/code-review/steps/dispatch-fix.md +4 -3
  286. package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +20 -13
  287. package/gsd-core/workflows/code-review-fix.md +112 -25
  288. package/gsd-core/workflows/code-review.md +146 -135
  289. package/gsd-core/workflows/complete-milestone/detail/elaboration.md +4 -3
  290. package/gsd-core/workflows/complete-milestone.md +13 -8
  291. package/gsd-core/workflows/debug.md +32 -7
  292. package/gsd-core/workflows/diagnose-issues.md +3 -2
  293. package/gsd-core/workflows/discuss-phase/modes/advisor.md +1 -1
  294. package/gsd-core/workflows/discuss-phase/modes/chain.md +1 -1
  295. package/gsd-core/workflows/discuss-phase-assumptions.md +4 -3
  296. package/gsd-core/workflows/discuss-phase.md +4 -3
  297. package/gsd-core/workflows/do.md +2 -2
  298. package/gsd-core/workflows/docs-update.md +6 -5
  299. package/gsd-core/workflows/edit-phase.md +4 -3
  300. package/gsd-core/workflows/eval-review.md +14 -5
  301. package/gsd-core/workflows/execute-phase/detail/elaboration.md +2 -2
  302. package/gsd-core/workflows/execute-phase/steps/code-review-disposition.md +1019 -0
  303. package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +15 -4
  304. package/gsd-core/workflows/execute-phase/steps/completion-reconciliation.md +10 -7
  305. package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +37 -3
  306. package/gsd-core/workflows/execute-phase/steps/gap-closure-artifacts.md +3 -1
  307. package/gsd-core/workflows/execute-phase/steps/partial-wave.md +2 -2
  308. package/gsd-core/workflows/execute-phase/steps/per-plan-executor-routing.md +1 -1
  309. package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +1 -1
  310. package/gsd-core/workflows/execute-phase/steps/post-merge-gate.md +46 -9
  311. package/gsd-core/workflows/execute-phase/steps/protected-branch.md +1 -1
  312. package/gsd-core/workflows/execute-phase/steps/ready-wave-gate.md +37 -0
  313. package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +1 -1
  314. package/gsd-core/workflows/execute-phase/steps/regression-gate.md +2 -0
  315. package/gsd-core/workflows/execute-phase/steps/tdd-applicability-resolution.md +1 -1
  316. package/gsd-core/workflows/execute-phase/steps/threat-id-gate.md +28 -0
  317. package/gsd-core/workflows/execute-phase/steps/verify-phase-goal.md +187 -0
  318. package/gsd-core/workflows/execute-phase/steps/wave-post-gate-hooks.md +2 -3
  319. package/gsd-core/workflows/execute-phase/steps/worktree-base-check.md +25 -0
  320. package/gsd-core/workflows/execute-phase.md +96 -178
  321. package/gsd-core/workflows/execute-plan.md +18 -23
  322. package/gsd-core/workflows/explore.md +4 -4
  323. package/gsd-core/workflows/extract-learnings.md +4 -2
  324. package/gsd-core/workflows/fast.md +1 -1
  325. package/gsd-core/workflows/forensics.md +1 -1
  326. package/gsd-core/workflows/graduation.md +1 -1
  327. package/gsd-core/workflows/health.md +3 -2
  328. package/gsd-core/workflows/help/modes/full.compact.md +3 -3
  329. package/gsd-core/workflows/help/modes/full.md +5 -5
  330. package/gsd-core/workflows/help/modes/topic.md +15 -5
  331. package/gsd-core/workflows/import.md +4 -3
  332. package/gsd-core/workflows/inbox.md +2 -2
  333. package/gsd-core/workflows/ingest-docs.md +3 -3
  334. package/gsd-core/workflows/insert-phase.md +4 -3
  335. package/gsd-core/workflows/list-seeds.md +1 -1
  336. package/gsd-core/workflows/list-workspaces.md +1 -1
  337. package/gsd-core/workflows/manager.md +6 -4
  338. package/gsd-core/workflows/map-codebase.md +5 -4
  339. package/gsd-core/workflows/milestone-summary.md +3 -2
  340. package/gsd-core/workflows/mvp-phase.md +14 -14
  341. package/gsd-core/workflows/new-milestone.md +11 -11
  342. package/gsd-core/workflows/new-project/steps/auto-mode-config.md +3 -3
  343. package/gsd-core/workflows/new-project/steps/codebase-map-offer.md +1 -1
  344. package/gsd-core/workflows/new-project.md +7 -7
  345. package/gsd-core/workflows/new-workspace.md +2 -2
  346. package/gsd-core/workflows/next.md +1 -1
  347. package/gsd-core/workflows/note.md +1 -1
  348. package/gsd-core/workflows/onboard.md +1 -1
  349. package/gsd-core/workflows/pause-work.md +2 -2
  350. package/gsd-core/workflows/plan-phase/detail/elaboration.md +1 -1
  351. package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +17 -5
  352. package/gsd-core/workflows/plan-phase/steps/closed-phase-gate.md +1 -1
  353. package/gsd-core/workflows/plan-phase/steps/prd-express-path.md +1 -1
  354. package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +23 -5
  355. package/gsd-core/workflows/plan-phase.md +50 -24
  356. package/gsd-core/workflows/plan-review-convergence.md +21 -5
  357. package/gsd-core/workflows/plant-seed.md +62 -20
  358. package/gsd-core/workflows/pr-branch.md +113 -13
  359. package/gsd-core/workflows/profile-user.md +2 -2
  360. package/gsd-core/workflows/progress.md +19 -49
  361. package/gsd-core/workflows/quick/steps/plan-checker-loop.md +27 -0
  362. package/gsd-core/workflows/quick/steps/quick-verification.md +4 -4
  363. package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +30 -11
  364. package/gsd-core/workflows/quick-batch/steps/batch-init.md +1 -1
  365. package/gsd-core/workflows/quick-batch/steps/completion.md +1 -1
  366. package/gsd-core/workflows/quick-batch/steps/merge-wave.md +1 -1
  367. package/gsd-core/workflows/quick-batch/steps/planner-wave.md +1 -1
  368. package/gsd-core/workflows/quick-batch/steps/research-phase.md +1 -1
  369. package/gsd-core/workflows/quick-batch/steps/resume-mode.md +1 -1
  370. package/gsd-core/workflows/quick-batch/steps/verification-wave.md +9 -3
  371. package/gsd-core/workflows/quick-batch/steps/worktree-dispatch.md +1 -1
  372. package/gsd-core/workflows/quick-batch.md +15 -10
  373. package/gsd-core/workflows/quick.md +62 -39
  374. package/gsd-core/workflows/reapply-patches.md +9 -3
  375. package/gsd-core/workflows/remove-phase.md +3 -2
  376. package/gsd-core/workflows/remove-workspace.md +2 -2
  377. package/gsd-core/workflows/resume-project.md +3 -2
  378. package/gsd-core/workflows/review.md +33 -17
  379. package/gsd-core/workflows/scan.md +3 -2
  380. package/gsd-core/workflows/secure-phase.md +13 -13
  381. package/gsd-core/workflows/settings-advanced.md +30 -10
  382. package/gsd-core/workflows/settings-integrations.md +2 -3
  383. package/gsd-core/workflows/settings.md +4 -4
  384. package/gsd-core/workflows/ship.md +14 -13
  385. package/gsd-core/workflows/sketch-wrap-up.md +1 -1
  386. package/gsd-core/workflows/sketch.md +1 -1
  387. package/gsd-core/workflows/smart-entry.md +2 -2
  388. package/gsd-core/workflows/spec-phase.md +15 -5
  389. package/gsd-core/workflows/spike-wrap-up.md +1 -1
  390. package/gsd-core/workflows/spike.md +1 -1
  391. package/gsd-core/workflows/stats.md +1 -1
  392. package/gsd-core/workflows/sync-skills.md +5 -5
  393. package/gsd-core/workflows/thread.md +2 -2
  394. package/gsd-core/workflows/transition.md +13 -23
  395. package/gsd-core/workflows/ui-phase.md +48 -11
  396. package/gsd-core/workflows/ui-review.md +21 -6
  397. package/gsd-core/workflows/ultraplan-phase.md +3 -2
  398. package/gsd-core/workflows/undo.md +339 -20
  399. package/gsd-core/workflows/update.md +7 -7
  400. package/gsd-core/workflows/validate-phase.md +12 -13
  401. package/gsd-core/workflows/verify-work/detail/elaboration.md +43 -3
  402. package/gsd-core/workflows/verify-work/steps/automated-ui-verification.md +1 -1
  403. package/gsd-core/workflows/verify-work/steps/mvp-uat-framing.md +5 -3
  404. package/gsd-core/workflows/verify-work.md +129 -55
  405. package/hooks/dist/gsd-agent-isolation-guard.js +32 -0
  406. package/hooks/dist/gsd-check-update-worker.js +8 -0
  407. package/hooks/dist/gsd-check-update.js +8 -0
  408. package/hooks/dist/gsd-context-monitor.js +31 -8
  409. package/hooks/dist/gsd-cursor-subagent-start.js +8 -0
  410. package/hooks/dist/gsd-secret-read-guard.js +161 -4
  411. package/hooks/dist/gsd-statusline.js +85 -20
  412. package/hooks/dist/gsd-update-banner.js +8 -0
  413. package/hooks/dist/gsd-validate-commit.sh +63 -4
  414. package/hooks/dist/gsd-windsurf-pre-write.js +11 -2
  415. package/hooks/dist/gsd-workflow-guard.js +5 -4
  416. package/hooks/dist/gsd-worktree-path-guard.js +6 -2
  417. package/hooks/dist/lib/cli-exit.js +12 -0
  418. package/hooks/dist/lib/git-probe.js +17 -1
  419. package/hooks/dist/lib/isolation-sentinel.js +2 -2
  420. package/hooks/gsd-agent-isolation-guard.js +32 -0
  421. package/hooks/gsd-check-update-worker.js +8 -0
  422. package/hooks/gsd-check-update.js +8 -0
  423. package/hooks/gsd-context-monitor.js +31 -8
  424. package/hooks/gsd-cursor-subagent-start.js +8 -0
  425. package/hooks/gsd-secret-read-guard.js +161 -4
  426. package/hooks/gsd-statusline.js +85 -20
  427. package/hooks/gsd-update-banner.js +8 -0
  428. package/hooks/gsd-validate-commit.sh +63 -4
  429. package/hooks/gsd-windsurf-pre-write.js +11 -2
  430. package/hooks/gsd-workflow-guard.js +5 -4
  431. package/hooks/gsd-worktree-path-guard.js +6 -2
  432. package/hooks/hooks.json +5 -5
  433. package/hooks/lib/cli-exit.js +12 -0
  434. package/hooks/lib/git-probe.js +17 -1
  435. package/hooks/lib/isolation-sentinel.js +2 -2
  436. package/package.json +22 -4
  437. package/scripts/build-hooks.js +15 -6
  438. package/scripts/changeset/parse.cjs +52 -4
  439. package/scripts/check-contract-drift.cjs +127 -11
  440. package/scripts/ci-timeout-report.cjs +770 -4
  441. package/scripts/command-contract-helpers.cjs +15 -8
  442. package/scripts/docs-guard-registry.cjs +34 -0
  443. package/scripts/gen-features.cjs +13 -8
  444. package/scripts/gen-hooks-cli-exit.cjs +12 -28
  445. package/scripts/gen-loop-host-contract.cjs +79 -1
  446. package/scripts/gen-platform-conformance-tier.cjs +187 -1
  447. package/scripts/gen-plugin-skills.cjs +87 -1
  448. package/scripts/gen-research-agents.cjs +24 -31
  449. package/scripts/gen-scripts-cli-exit.cjs +30 -3
  450. package/scripts/gen-test-timings.cjs +32 -7
  451. package/scripts/lib/cli-exit.cjs +12 -0
  452. package/scripts/lib/macos-conformance-tier.generated.cjs +34 -2
  453. package/scripts/lib/ndjson-reporter.cjs +31 -5
  454. package/scripts/lib/platform-conformance-tier.generated.cjs +45 -5
  455. package/scripts/lib/registration-ledger-preload.cjs +155 -0
  456. package/scripts/lib/vendor-bundle.cjs +59 -0
  457. package/scripts/lib/vendor-licenses/saxes-6.0.0.txt +64 -0
  458. package/scripts/lint-allow-test-rule-refs.effective-ceiling.json +1 -1
  459. package/scripts/lint-allow-test-rule-refs.unverified-ceiling.json +1 -1
  460. package/scripts/lint-completion-predicate-drift.cjs +18 -19
  461. package/scripts/lint-descriptions.cjs +7 -3
  462. package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +38 -1
  463. package/scripts/lint-eslint-glob-coverage.allowlist.json +20 -0
  464. package/scripts/lint-frontmatter-fence-drift.cjs +313 -0
  465. package/scripts/lint-frontmatter-scalar-broad-grep.cjs +122 -16
  466. package/scripts/lint-phase-arg-assignment.cjs +257 -0
  467. package/scripts/lint-phase-enumeration-drift.cjs +12 -8
  468. package/scripts/lint-phase-id-drift.cjs +319 -5
  469. package/scripts/lint-planning-document-positive-control.cjs +329 -0
  470. package/scripts/lint-pr-branch-pattern-drift.cjs +148 -0
  471. package/scripts/lint-response-language-coverage.cjs +3 -0
  472. package/scripts/lint-retired-runtime-name.cjs +619 -0
  473. package/scripts/lint-skill-deps.cjs +7 -3
  474. package/scripts/lint-state-write-path-drift.cjs +93 -0
  475. package/scripts/lint-test-file-count.allowlist.json +38 -9
  476. package/scripts/lint-test-file-count.cjs +34 -1
  477. package/scripts/lint-vendored-deps.cjs +41 -5
  478. package/scripts/lint-workflow-shellcheck-baseline.json +25 -10
  479. package/scripts/mutation-matrix.cjs +50 -5
  480. package/scripts/prompt-injection-scan.sh +4 -0
  481. package/scripts/release-tarball-smoke.cjs +194 -1
  482. package/scripts/require-issue-link-policy.cjs +6 -2
  483. package/scripts/sync-runtime-launcher.cjs +184 -2
  484. package/scripts/verify-npm-publish.cjs +76 -20
  485. package/skills/gsd-add-tests/SKILL.md +6 -1
  486. package/skills/gsd-ai-integration-phase/SKILL.md +6 -1
  487. package/skills/gsd-audit-fix/SKILL.md +5 -0
  488. package/skills/gsd-audit-milestone/SKILL.md +6 -1
  489. package/skills/gsd-autonomous/SKILL.md +7 -2
  490. package/skills/gsd-capture/SKILL.md +9 -5
  491. package/skills/gsd-code-review/SKILL.md +7 -2
  492. package/skills/gsd-complete-milestone/SKILL.md +4 -0
  493. package/skills/gsd-config/SKILL.md +8 -4
  494. package/skills/gsd-debug/SKILL.md +11 -7
  495. package/skills/gsd-discuss-phase/SKILL.md +7 -3
  496. package/skills/gsd-docs-update/SKILL.md +12 -7
  497. package/skills/gsd-eval-review/SKILL.md +6 -1
  498. package/skills/gsd-execute-phase/SKILL.md +12 -7
  499. package/skills/gsd-extract-learnings/SKILL.md +5 -0
  500. package/skills/gsd-fast/SKILL.md +4 -0
  501. package/skills/gsd-forensics/SKILL.md +5 -1
  502. package/skills/gsd-graphify/SKILL.md +10 -6
  503. package/skills/gsd-health/SKILL.md +5 -0
  504. package/skills/gsd-help/SKILL.md +7 -2
  505. package/skills/gsd-import/SKILL.md +7 -3
  506. package/skills/gsd-inbox/SKILL.md +5 -0
  507. package/skills/gsd-ingest-docs/SKILL.md +5 -1
  508. package/skills/gsd-manager/SKILL.md +6 -1
  509. package/skills/gsd-map-codebase/SKILL.md +7 -3
  510. package/skills/gsd-mempalace-capture/SKILL.md +12 -4
  511. package/skills/gsd-mempalace-recall/SKILL.md +5 -1
  512. package/skills/gsd-milestone-summary/SKILL.md +5 -1
  513. package/skills/gsd-mvp-phase/SKILL.md +8 -3
  514. package/skills/gsd-new-milestone/SKILL.md +6 -1
  515. package/skills/gsd-new-project/SKILL.md +5 -0
  516. package/skills/gsd-next/SKILL.md +6 -1
  517. package/skills/gsd-ns-context/SKILL.md +4 -0
  518. package/skills/gsd-ns-ideate/SKILL.md +4 -0
  519. package/skills/gsd-ns-manage/SKILL.md +4 -0
  520. package/skills/gsd-ns-project/SKILL.md +4 -0
  521. package/skills/gsd-ns-review/SKILL.md +4 -0
  522. package/skills/gsd-ns-workflow/SKILL.md +4 -0
  523. package/skills/gsd-onboard/SKILL.md +6 -1
  524. package/skills/gsd-pause-work/SKILL.md +5 -1
  525. package/skills/gsd-phase/SKILL.md +8 -4
  526. package/skills/gsd-plan-phase/SKILL.md +6 -1
  527. package/skills/gsd-plan-review-convergence/SKILL.md +10 -6
  528. package/skills/gsd-pr-branch/SKILL.md +4 -0
  529. package/skills/gsd-profile-user/SKILL.md +5 -1
  530. package/skills/gsd-progress/SKILL.md +7 -2
  531. package/skills/gsd-quick/SKILL.md +16 -10
  532. package/skills/gsd-quick-batch/SKILL.md +21 -9
  533. package/skills/gsd-review/SKILL.md +7 -4
  534. package/skills/gsd-review-backlog/SKILL.md +3 -2
  535. package/skills/gsd-secure-phase/SKILL.md +6 -1
  536. package/skills/gsd-ship/SKILL.md +5 -0
  537. package/skills/gsd-sketch/SKILL.md +7 -2
  538. package/skills/gsd-spec-phase/SKILL.md +5 -1
  539. package/skills/gsd-spike/SKILL.md +8 -3
  540. package/skills/gsd-surface/SKILL.md +5 -1
  541. package/skills/gsd-thread/SKILL.md +4 -0
  542. package/skills/gsd-ui-phase/SKILL.md +6 -1
  543. package/skills/gsd-ui-review/SKILL.md +6 -1
  544. package/skills/gsd-ultraplan-phase/SKILL.md +5 -1
  545. package/skills/gsd-undo/SKILL.md +5 -1
  546. package/skills/gsd-update/SKILL.md +6 -2
  547. package/skills/gsd-validate-phase/SKILL.md +6 -1
  548. package/skills/gsd-verify-work/SKILL.md +6 -1
  549. package/skills/gsd-workspace/SKILL.md +7 -3
  550. package/skills/gsd-workstreams/SKILL.md +6 -6
  551. package/vscode/package.json +1 -1
@@ -17,6 +17,21 @@
17
17
  * installer uses, producing a build-generated skills/ dir that ships in the
18
18
  * npm package and serves plugin-only installs.
19
19
  *
20
+ * #4995: commands/gsd/*.md still instruct bare command-position `gsd-tools
21
+ * <verb>` calls in 4 files (workstreams.md, quick.md, review-backlog.md,
22
+ * config.md), which fail with "command not found" on a shim-only install.
23
+ * That source can't be normalized to `gsd_run` directly the way #2751 did for
24
+ * agents/*.md and gsd-core/workflows/*.md: tests/gsd-tools-path-refs.test.cjs
25
+ * (#1766) pins commands/gsd/workstreams.md to the literal string
26
+ * `gsd-tools query workstream.list`, and bringing commands/ under the #2751
27
+ * guard was tried and reverted for unrelated load-bearing reasons (11ad7881ed
28
+ * / d286e54163). So this generator rewrites bare gsd-tools -> gsd_run in its
29
+ * OWN output — the same shape of fix #725 already established for the Codex
30
+ * conversion pipeline (rewrite the generated artifact, not the shared
31
+ * source) — reusing the exact `gsd_run` resolver preamble #2751 established
32
+ * (scripts/sync-runtime-launcher.cjs's transformFile) rather than inventing a
33
+ * new resolution mechanism.
34
+ *
20
35
  * Depends on: gsd-core/bin/lib/runtime-artifact-conversion.cjs (compiled from
21
36
  * src/runtime-artifact-conversion.cts by `npm run build:lib`). Must run AFTER
22
37
  * build:lib in the build chain.
@@ -25,6 +40,7 @@
25
40
  const fs = require('node:fs');
26
41
  const path = require('node:path');
27
42
  const { ExitError, runMain } = require('./lib/cli-exit.cjs');
43
+ const { transformFile, loadPreamble } = require('./sync-runtime-launcher.cjs');
28
44
 
29
45
  const ROOT = path.resolve(__dirname, '..');
30
46
  const COMMANDS_DIR = path.join(ROOT, 'commands', 'gsd');
@@ -33,6 +49,73 @@ const CONVERSION_MODULE = path.join(ROOT, 'gsd-core', 'bin', 'lib', 'runtime-art
33
49
  const PREFIX = 'gsd-';
34
50
  const RUNTIME = 'claude';
35
51
 
52
+ // #4995: the 4 commands/gsd/*.md stems (census taken by the issue) that carry
53
+ // command-position bare `gsd-tools <verb>` calls. Deliberately an explicit
54
+ // allowlist, NOT a blanket regex applied to every generated skill: several
55
+ // other skills (e.g. gsd-graphify) merely NAME `gsd-tools`/`gsd_run`
56
+ // descriptively (prose, "DO NOT use ..." warnings) in ways a command-position
57
+ // regex cannot safely tell apart from a real instruction without per-site
58
+ // human review -- exactly the ambiguity tests/no-bare-gsd-tools-command-
59
+ // position.test.cjs's PROSE_ALLOWLIST exists to resolve by hand for #2751/
60
+ // #3809. gsd-graphify also carries 5 deliberately-separate per-block
61
+ // preambles (tests/graphify-visualization.test.cjs extracts and runs each
62
+ // fenced Step-3 block standalone); running every skill through
63
+ // transformFile's "collapse to one preamble per file" behavior would
64
+ // reproduce the exact regression d286e54163 already found and reverted for
65
+ // commands/gsd/graphify.md. Restricting the rewrite to the 4 files the
66
+ // census in #4995 actually names avoids all of that.
67
+ const BARE_GSD_TOOLS_STEMS = new Set(['workstreams', 'quick', 'review-backlog', 'config']);
68
+
69
+ // #4995: command-position bare `gsd-tools` -> `gsd_run` token swap. Mirrors 3
70
+ // of the 4 command-position shapes rewriteBareGsdToolsCommandsForCodex
71
+ // (src/runtime-artifact-conversion.cts) already covers for the Codex
72
+ // pipeline: start-of-line, inside `$( ... )`, and immediately after a
73
+ // backtick (inline "Run: `gsd-tools verb args`" prose). Deliberately DROPS
74
+ // that function's 4th shape -- a bare, unescaped `|` counted as a shell
75
+ // pipe separator -- because a Markdown table row (`| col | gsd-tools verb
76
+ // arg |`) also starts a cell with `| gsd-tools`, and none of the 11 sites in
77
+ // #4995's census need it: config.md's own routing TABLE names `gsd-tools
78
+ // query config-set-model-profile` descriptively in a `|`-delimited cell one
79
+ // row above the real operative site, and rewriting that cell too would be a
80
+ // change nobody asked for. (`&&`/`;` are kept: two-character or dedicated
81
+ // separators, not also a Markdown table delimiter.) Only applied to
82
+ // BARE_GSD_TOOLS_STEMS files (see above). Within those 4 files this narrower
83
+ // pattern still matches one site beyond the issue's 11-site census --
84
+ // gsd-quick/SKILL.md's <security_notes> line ("Status fields read via
85
+ // `gsd-tools query frontmatter.get`") is a backtick-wrapped DESCRIPTIVE
86
+ // mention, not a `Run:` instruction, but it has the identical command-
87
+ // position shape and gets swapped too. That's harmless (the sentence reads
88
+ // the same with `gsd_run` in it) and left as-is rather than special-cased,
89
+ // but the true count this generator fixes is 12 operative-shaped sites, not
90
+ // 11 -- the 12th just wasn't literal-command "operative" in the issue's own
91
+ // sense.
92
+ function rewriteBareGsdToolsCommandsToGsdRun(content) {
93
+ return content
94
+ .replace(/(^[ \t]*)gsd-tools(?=\s)/gm, '$1gsd_run')
95
+ .replace(/(\$\(\s*)gsd-tools(?=\s)/g, '$1gsd_run')
96
+ .replace(/(`\s*)gsd-tools(?=\s)/g, '$1gsd_run')
97
+ .replace(/((?:&&|;)\s*)gsd-tools(?=\s)/g, '$1gsd_run');
98
+ }
99
+
100
+ // #4995: after the token swap, any fenced bash/sh/shell block that now calls
101
+ // `gsd_run` needs the resolver preamble that defines it -- reuse
102
+ // sync-runtime-launcher.cjs's transformFile verbatim (the same mechanism
103
+ // applied to agents/*.md and gsd-core/workflows/*.md) rather than
104
+ // reimplementing preamble placement here. Inline (non-fenced) "Run: `gsd_run
105
+ // verb args`" prose has no fenced block to anchor a preamble to; per the
106
+ // precedent already set for this exact shape (commands/gsd/workstreams.md
107
+ // and config.md in 11ad7881ed), it is left as a bare `gsd_run` token --
108
+ // `gsd_run` is itself a shipped npm bin name, so it resolves identically to
109
+ // how the pre-fix `gsd-tools` form resolved once PATH carries it (e.g. via
110
+ // the CLAUDE_ENV_FILE export in an earlier-run preamble in the same
111
+ // session), without regressing anything that worked before.
112
+ function rewriteSkillContent(content) {
113
+ const swapped = rewriteBareGsdToolsCommandsToGsdRun(content);
114
+ const preamble = loadPreamble();
115
+ const withPreamble = transformFile(swapped, preamble);
116
+ return withPreamble === null ? swapped : withPreamble;
117
+ }
118
+
36
119
  function generateSkills(conversion) {
37
120
  const cmdNames = conversion.readGsdCommandNames();
38
121
  const files = fs.readdirSync(COMMANDS_DIR).filter(f => f.endsWith('.md'));
@@ -41,7 +124,10 @@ function generateSkills(conversion) {
41
124
  const stem = file.slice(0, -3);
42
125
  const skillName = PREFIX + stem;
43
126
  const src = fs.readFileSync(path.join(COMMANDS_DIR, file), 'utf8');
44
- const converted = conversion.convertClaudeCommandToClaudeSkill(src, skillName, RUNTIME, cmdNames, true);
127
+ let converted = conversion.convertClaudeCommandToClaudeSkill(src, skillName, RUNTIME, cmdNames, true);
128
+ if (BARE_GSD_TOOLS_STEMS.has(stem)) {
129
+ converted = rewriteSkillContent(converted);
130
+ }
45
131
  results.push({ skillName, content: converted });
46
132
  }
47
133
  return results;
@@ -25,6 +25,9 @@ const path = require('node:path');
25
25
 
26
26
  const { PROFILES } = require('./research-profiles.cjs');
27
27
  const { ExitError, runMain } = require('./lib/cli-exit.cjs');
28
+ // The one frontmatter fence owner (src/frontmatter-fence.cts, built by build:lib).
29
+ // This dev-time script runs after the build (manually, and from the tests).
30
+ const { locateFrontmatterFence } = require('../gsd-core/bin/lib/frontmatter-fence.cjs');
28
31
 
29
32
  const ROOT = path.resolve(__dirname, '..');
30
33
  const AGENTS_DIR = path.join(ROOT, 'agents');
@@ -41,12 +44,13 @@ const AGENTS_DIR = path.join(ROOT, 'agents');
41
44
  * We read the CURRENT commented-hooks block from the agent file and preserve it
42
45
  * byte-for-byte; only name/description/tools/color are regenerated.
43
46
  */
44
- function buildFrontmatter(profile, existingFrontmatter) {
45
- // Extract the commented hooks section from the existing frontmatter, if any.
46
- // The hooks block starts at `# hooks:` and runs to (but not including) the
47
- // closing `---`. In the committed files there is NO blank line between
48
- // `color:` and `# hooks:`, so we append it directly after the color line's `\n`.
49
- const hooksMatch = existingFrontmatter.match(/(# hooks:[\s\S]*?)(?=\n---)/);
47
+ function buildFrontmatter(profile, existingRegion) {
48
+ // Extract the commented hooks section from the existing frontmatter region
49
+ // (the YAML text between the fences), if any. The hooks block starts at
50
+ // `# hooks:` and runs to the end of the region — the closing `---` follows it.
51
+ // In the committed files there is NO blank line between `color:` and
52
+ // `# hooks:`, so we append it directly after the color line's `\n`.
53
+ const hooksMatch = existingRegion.match(/(# hooks:[\s\S]*)$/);
50
54
  // hooksSuffix: if present, the block followed by a newline so `---` is on its own line;
51
55
  // if absent, empty string (the closing `---` follows directly after color's `\n`).
52
56
  const hooksSuffix = hooksMatch ? hooksMatch[1] + '\n' : '';
@@ -67,37 +71,26 @@ function buildFrontmatter(profile, existingFrontmatter) {
67
71
  /**
68
72
  * Parse a .md file and return { frontmatterRaw, body, frontmatterFields }.
69
73
  *
70
- * frontmatterRaw: the raw text between the first and second `---` delimiters (exclusive)
71
- * body: everything after the closing `---\n`
74
+ * frontmatterRaw: the YAML text between the opening and closing fences (exclusive)
75
+ * fullFrontmatter: the block from the opening fence through the closing fence line
76
+ * body: everything after the closing fence line's line ending
72
77
  * frontmatterFields: { name, description, color, tools }
78
+ *
79
+ * The block is the one the one fence owner finds (found while implementing #5105):
80
+ * it opens at byte 0 (after a BOM), exactly as the runtime that loads the agent reads it.
73
81
  */
74
82
  function parseAgentFile(filePath) {
75
83
  const raw = fs.readFileSync(filePath, 'utf8');
76
84
 
77
- // The frontmatter is between the first `---` line and the next `---` line.
78
- const lines = raw.split('\n');
79
- let start = -1;
80
- let end = -1;
81
- for (let i = 0; i < lines.length; i++) {
82
- if (lines[i].trim() === '---') {
83
- if (start === -1) {
84
- start = i;
85
- } else {
86
- end = i;
87
- break;
88
- }
89
- }
90
- }
91
-
92
- if (start === -1 || end === -1) {
85
+ const fence = locateFrontmatterFence(raw);
86
+ if (!fence || !fence.closed) {
93
87
  throw new Error('No valid frontmatter delimiters found in ' + filePath);
94
88
  }
95
89
 
96
- const frontmatterLines = lines.slice(start + 1, end);
97
- const frontmatterRaw = frontmatterLines.join('\n');
98
- // body includes the closing `---` line and everything after
99
- const fullFrontmatter = lines.slice(start, end + 1).join('\n');
100
- const body = lines.slice(end + 1).join('\n');
90
+ const frontmatterRaw = raw.slice(fence.openEnd, fence.bodyEnd);
91
+ const frontmatterLines = frontmatterRaw.split(/\r?\n/);
92
+ const fullFrontmatter = raw.slice(fence.bom.length, fence.closingFenceEnd);
93
+ const body = raw.slice(fence.closingFenceEnd).replace(/^\r?\n/, '');
101
94
 
102
95
  const fields = {};
103
96
  // Parse simple key: value pairs (not nested YAML, no multi-line values here)
@@ -214,9 +207,9 @@ function runCheck() {
214
207
  */
215
208
  function writeAgent(profile) {
216
209
  const agentPath = path.join(AGENTS_DIR, profile.name + '.md');
217
- const { fullFrontmatter, body } = parseAgentFile(agentPath);
210
+ const { frontmatterRaw, body } = parseAgentFile(agentPath);
218
211
 
219
- const newFrontmatter = buildFrontmatter(profile, fullFrontmatter);
212
+ const newFrontmatter = buildFrontmatter(profile, frontmatterRaw);
220
213
  const newContent = newFrontmatter + '\n' + body;
221
214
 
222
215
  fs.writeFileSync(agentPath, newContent, 'utf8');
@@ -65,15 +65,40 @@ const BANNER = [
65
65
  '',
66
66
  ].join('\n');
67
67
 
68
- /** Compile the whole project to a throwaway outDir so the work tree is untouched. */
68
+ /**
69
+ * Compile ONLY src/cli-exit.cts (and whatever it imports — tsc follows
70
+ * `./exit-code-registry.cjs` on its own) to a throwaway outDir, so the work
71
+ * tree is untouched. A whole-project `-p tsconfig.build.json` type-checks and
72
+ * emits every .cts file in src/ under a fixed COMPILE_TIMEOUT_MS ceiling; on a
73
+ * CPU-contended shared bench that whole-project compile can exceed the
74
+ * ceiling and get killed even though the one file this script actually needs
75
+ * compiles in a fraction of the time. A throwaway tsconfig that `extends`
76
+ * tsconfig.build.json but overrides `files`/`include` to name only
77
+ * cli-exit.cts keeps every compiler option (target, strict, rootDir, etc.)
78
+ * while scoping the type-check + emit to that file's own import closure.
79
+ */
69
80
  function compileToTemp() {
70
81
  const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-scripts-cli-exit-'));
82
+ const scopedTsconfigPath = path.join(tmp, 'tsconfig.scoped.json');
71
83
  try {
84
+ const scopedTsconfig = {
85
+ extends: path.join(REPO_ROOT, 'tsconfig.build.json'),
86
+ // typeRoots must be pinned to the real repo's node_modules/@types: tsc
87
+ // resolves a bare "types": ["node"] by walking up from the config
88
+ // file's own directory, and our scoped tsconfig lives outside the repo
89
+ // tree (in the throwaway tmp dir), so without this it cannot find
90
+ // @types/node at all.
91
+ compilerOptions: { typeRoots: [path.join(REPO_ROOT, 'node_modules', '@types')] },
92
+ files: [path.join(REPO_ROOT, 'src', 'cli-exit.cts')],
93
+ include: [],
94
+ };
95
+ fs.writeFileSync(scopedTsconfigPath, JSON.stringify(scopedTsconfig, null, 2), 'utf8');
96
+
72
97
  execFileSync(
73
98
  process.execPath,
74
99
  [
75
100
  path.join(REPO_ROOT, 'node_modules', 'typescript', 'bin', 'tsc'),
76
- '-p', path.join(REPO_ROOT, 'tsconfig.build.json'),
101
+ '-p', scopedTsconfigPath,
77
102
  '--outDir', tmp,
78
103
  // A throwaway outDir must not reuse the in-tree incremental state, or
79
104
  // tsc skips emit for files it believes are already current.
@@ -87,6 +112,8 @@ function compileToTemp() {
87
112
  fs.rmSync(tmp, { recursive: true, force: true });
88
113
  const detail = [err.stdout, err.stderr].filter(Boolean).join('\n').trim();
89
114
  return { ok: false, detail };
115
+ } finally {
116
+ fs.rmSync(scopedTsconfigPath, { force: true });
90
117
  }
91
118
  }
92
119
 
@@ -182,4 +209,4 @@ function main() {
182
209
 
183
210
  if (require.main === module) process.exitCode = main();
184
211
 
185
- module.exports = { REASON, buildExpectedContent, OUTPUT_PATH, BANNER };
212
+ module.exports = { REASON, buildExpectedContent, compileToTemp, OUTPUT_PATH, BANNER };
@@ -19,6 +19,9 @@
19
19
  // node scripts/gen-test-timings.cjs <events.jsonl> [<events.jsonl> ...]
20
20
  // node scripts/gen-test-timings.cjs ~/.local/state/gsd-test/runs/*/test-events-*.jsonl
21
21
  // node scripts/gen-test-timings.cjs events.jsonl --out tests/test-timings.json
22
+ // node scripts/gen-test-timings.cjs --platform win32 test-timings-windows-shard*.jsonl
23
+ // (#5071: the per-shard exports CI uploads from its Windows conformance
24
+ // jobs -> tests/test-timings.win32.json, preferred by run-tests.cjs on win32)
22
25
  //
23
26
  // When several streams are supplied (multiple lanes, e.g. node22 + node24), a
24
27
  // file's recorded time is the MAX across them, not the mean: the packer exists
@@ -28,9 +31,9 @@
28
31
  // The table is ADVISORY and deliberately un-gated — there is no `--check` mode
29
32
  // and no CI lint that fails on staleness, because timing data legitimately
30
33
  // varies run to run. A file missing from the table falls back to the table's
31
- // median weight, so a stale table degrades chunk BALANCE gracefully instead of
32
- // failing the build. Regenerate it when the suite's cost profile has visibly
33
- // drifted, not on a schedule.
34
+ // mean weight (see makeFileWeigher in run-tests.cjs), so a stale table
35
+ // degrades chunk BALANCE gracefully instead of failing the build. Regenerate
36
+ // it when the suite's cost profile has visibly drifted, not on a schedule.
34
37
  'use strict';
35
38
 
36
39
  const fs = require('fs');
@@ -40,12 +43,32 @@ const { ExitError, runMain } = require('./lib/cli-exit.cjs');
40
43
  const DEFAULT_OUT = join(__dirname, '..', 'tests', 'test-timings.json');
41
44
  const SCHEMA_VERSION = 1;
42
45
 
46
+ // #5071: `--platform <p>` writes the table measured ON that platform, which
47
+ // scripts/run-tests.cjs prefers there (see its makeFileWeigher). The default
48
+ // path must match run-tests.cjs's platformTimingsPath() —
49
+ // tests/run-tests-harness.test.cjs pins the two together. A closed set, in
50
+ // exactly Node's own `process.platform` spelling, because the value becomes
51
+ // part of a filename the runner looks up by that spelling.
52
+ const PLATFORMS = ['win32', 'darwin', 'linux'];
53
+ function platformOut(platform) {
54
+ return join(__dirname, '..', 'tests', `test-timings.${platform}.json`);
55
+ }
56
+
43
57
  function parseArgs(argv) {
44
58
  const inputs = [];
45
- let out = DEFAULT_OUT;
59
+ let out = null;
60
+ let platform = null;
46
61
  for (let i = 0; i < argv.length; i++) {
47
62
  const arg = argv[i];
48
- if (arg === '--out') {
63
+ if (arg === '--platform' || arg.startsWith('--platform=')) {
64
+ if (platform !== null) return { error: 'duplicate --platform flag' };
65
+ const value = arg === '--platform' ? argv[++i] : arg.slice('--platform='.length);
66
+ if (!value || value.startsWith('-')) return { error: `--platform requires one of: ${PLATFORMS.join(', ')}` };
67
+ if (!PLATFORMS.includes(value)) {
68
+ return { error: `unknown --platform "${value}" (expected one of: ${PLATFORMS.join(', ')})` };
69
+ }
70
+ platform = value;
71
+ } else if (arg === '--out') {
49
72
  const value = argv[++i];
50
73
  if (!value) return { error: '--out requires a path' };
51
74
  out = value;
@@ -60,9 +83,10 @@ function parseArgs(argv) {
60
83
  }
61
84
  }
62
85
  if (inputs.length === 0) {
63
- return { error: 'usage: gen-test-timings.cjs <reporter-events.jsonl> [...] [--out <path>]' };
86
+ return { error: 'usage: gen-test-timings.cjs <reporter-events.jsonl> [...] [--platform <win32|darwin|linux>] [--out <path>]' };
64
87
  }
65
- return { inputs, out };
88
+ if (out === null) out = platform ? platformOut(platform) : DEFAULT_OUT;
89
+ return { inputs, out, platform };
66
90
  }
67
91
 
68
92
  // Fold one reporter event stream into `acc`, keeping the MAX duration seen for
@@ -180,6 +204,7 @@ function main() {
180
204
  const payload = {
181
205
  schema_version: SCHEMA_VERSION,
182
206
  generated_by: 'scripts/gen-test-timings.cjs',
207
+ ...(parsed.platform ? { platform: parsed.platform } : {}),
183
208
  unit: 'ms',
184
209
  sources: sources.sort(),
185
210
  file_count: acc.size,
@@ -183,6 +183,17 @@ function setPendingOutcome(v) {
183
183
  function getPendingOutcome() {
184
184
  return globalThis[PENDING_OUTCOME_KEY];
185
185
  }
186
+ /**
187
+ * Declare the outcome a void-returning `main()` ends with (#5170, ADR-5057 §4): writes the
188
+ * pending-outcome cell that `runMain` projects. Validates `name` is an outcome
189
+ * `projectOutcome` accepts (PASS, FAIL or a registered name) and THROWS otherwise, so a typo'd
190
+ * name fails at the declaration rather than at process exit. Call it AFTER `output()`, which
191
+ * rewrites the cell on every call. `output()` and this are the only writers of the cell.
192
+ */
193
+ function declareOutcome(name) {
194
+ projectOutcome(name, 'v1');
195
+ setPendingOutcome(name);
196
+ }
186
197
  const EXIT_CONTRACT_FLAG_PREFIX = '--exit-contract=';
187
198
  /** Scan argv for the FIRST `--exit-contract=<value>` token; undefined if absent. */
188
199
  function findExitContractFlag(argv) {
@@ -555,4 +566,5 @@ module.exports = {
555
566
  terminateNow,
556
567
  setPendingOutcome,
557
568
  getPendingOutcome,
569
+ declareOutcome,
558
570
  };
@@ -6,6 +6,7 @@
6
6
 
7
7
  module.exports = {
8
8
  MACOS_CONFORMANCE_TIER_FILES: [
9
+ "tests/active-workstream-store.unit.test.cjs",
9
10
  "tests/adr-612-bracket-phase-counting.test.cjs",
10
11
  "tests/adr-index-gate.test.cjs",
11
12
  "tests/adr-parser.property.test.cjs",
@@ -32,6 +33,8 @@ module.exports = {
32
33
  "tests/changeset-parse.test.cjs",
33
34
  "tests/check-contract-drift.test.cjs",
34
35
  "tests/check-predicate.test.cjs",
36
+ "tests/check-router-cutover-equivalence.test.cjs",
37
+ "tests/check-ui-plan-gate.test.cjs",
35
38
  "tests/check-ui-safety-gate.test.cjs",
36
39
  "tests/check-update-config-dir.test.cjs",
37
40
  "tests/chunked-planning-parallel.test.cjs",
@@ -43,7 +46,7 @@ module.exports = {
43
46
  "tests/codex-config-hooks.test.cjs",
44
47
  "tests/codex-config-install.test.cjs",
45
48
  "tests/codex-config.test.cjs",
46
- "tests/commands.test.cjs",
49
+ "tests/commands.platform.test.cjs",
47
50
  "tests/commit-docs-bypass.test.cjs",
48
51
  "tests/commit-files-deletion.test.cjs",
49
52
  "tests/commit-files-pathspec.test.cjs",
@@ -52,6 +55,7 @@ module.exports = {
52
55
  "tests/config-loader.test.cjs",
53
56
  "tests/config-schema.property.test.cjs",
54
57
  "tests/config.test.cjs",
58
+ "tests/configured-entrypoint-validation.test.cjs",
55
59
  "tests/contributor-standards.test.cjs",
56
60
  "tests/core-utils.test.cjs",
57
61
  "tests/cursor-subagent-isolation.test.cjs",
@@ -59,6 +63,7 @@ module.exports = {
59
63
  "tests/default-flip-documentation-lint.test.cjs",
60
64
  "tests/discuss-phase-power.test.cjs",
61
65
  "tests/docs-parity-live-registry.test.cjs",
66
+ "tests/drift-whole-change-set.test.cjs",
62
67
  "tests/effort-surface-axis.test.cjs",
63
68
  "tests/effort-sync-installed-runtime.test.cjs",
64
69
  "tests/emitted-attribution.test.cjs",
@@ -73,16 +78,24 @@ module.exports = {
73
78
  "tests/features-index-gate.test.cjs",
74
79
  "tests/frontmatter.unit.test.cjs",
75
80
  "tests/gap-checker.property.test.cjs",
81
+ "tests/gate-api-coverage-verify-pre-escape.test.cjs",
82
+ "tests/gate-codebase-drift.unit.test.cjs",
83
+ "tests/gate-tdd-red-evidence-containment.test.cjs",
84
+ "tests/gate-ui-plan.unit.test.cjs",
85
+ "tests/gate-verify-command-paths.unit.test.cjs",
86
+ "tests/gemini-runtime-removed.test.cjs",
76
87
  "tests/gen-context-index.test.cjs",
77
88
  "tests/gen-section-manifest.test.cjs",
78
89
  "tests/git-base-branch.test.cjs",
79
90
  "tests/graphify-query.test.cjs",
80
91
  "tests/graphify-visualization.test.cjs",
92
+ "tests/gsd-agent-isolation-guard.test.cjs",
81
93
  "tests/gsd-secret-read-guard.test.cjs",
82
94
  "tests/gsd-settings-advanced.test.cjs",
83
95
  "tests/gsd-statusline.test.cjs",
84
96
  "tests/gsd-tools-path-refs.test.cjs",
85
97
  "tests/gsd-validate-commit-crash-policy.test.cjs",
98
+ "tests/gsd-validate-commit-sigpipe.test.cjs",
86
99
  "tests/gsd-write-guard.test.cjs",
87
100
  "tests/health-diagnostic-rules/worktree-health.test.cjs",
88
101
  "tests/health-diagnostic.test.cjs",
@@ -92,7 +105,6 @@ module.exports = {
92
105
  "tests/hooks-opt-in.test.cjs",
93
106
  "tests/host-integration.test.cjs",
94
107
  "tests/init-manager.test.cjs",
95
- "tests/init.test.cjs",
96
108
  "tests/install-minimal-hooks.test.cjs",
97
109
  "tests/install-path-detection.test.cjs",
98
110
  "tests/install-regressions.test.cjs",
@@ -111,8 +123,11 @@ module.exports = {
111
123
  "tests/issue-version-gate.test.cjs",
112
124
  "tests/kimi-upgrades.test.cjs",
113
125
  "tests/lint-docs-command-form.test.cjs",
126
+ "tests/lint-frontmatter-scalar-broad-grep.test.cjs",
127
+ "tests/lint-retired-runtime-name.test.cjs",
114
128
  "tests/lint-workflow-shellcheck-fetch.test.cjs",
115
129
  "tests/list-seeds.test.cjs",
130
+ "tests/markdown-sectionizer-xml-tags.property.test.cjs",
116
131
  "tests/markdown-sectionizer.test.cjs",
117
132
  "tests/mcp-catalog.test.cjs",
118
133
  "tests/milestone-archive.test.cjs",
@@ -125,6 +140,7 @@ module.exports = {
125
140
  "tests/no-posix-mode-bit-assert.rule.test.cjs",
126
141
  "tests/no-private-binary-resolution.rule.test.cjs",
127
142
  "tests/no-unguarded-nonportable-exec.rule.test.cjs",
143
+ "tests/nsegment-phase-grammar.test.cjs",
128
144
  "tests/observability/event.test.cjs",
129
145
  "tests/onboard-command.test.cjs",
130
146
  "tests/opencode-plugin-adapter.test.cjs",
@@ -136,8 +152,11 @@ module.exports = {
136
152
  "tests/phase-id-drift-guard.test.cjs",
137
153
  "tests/phase-id.test.cjs",
138
154
  "tests/phase-locator.test.cjs",
155
+ "tests/phase-status.test.cjs",
156
+ "tests/phase.platform.test.cjs",
139
157
  "tests/phase.test.cjs",
140
158
  "tests/plan-count-single-owner.test.cjs",
159
+ "tests/plan-document.test.cjs",
141
160
  "tests/plan-phase-stall-detection.test.cjs",
142
161
  "tests/plan-review-convergence.test.cjs",
143
162
  "tests/planning-inspect.test.cjs",
@@ -154,6 +173,8 @@ module.exports = {
154
173
  "tests/process-seam.test.cjs",
155
174
  "tests/profile-output.test.cjs",
156
175
  "tests/profile-pipeline.test.cjs",
176
+ "tests/project-root.test.cjs",
177
+ "tests/quick-batch-command-router.stdin.test.cjs",
157
178
  "tests/quick-batch.test.cjs",
158
179
  "tests/quick-branching.test.cjs",
159
180
  "tests/quick-research.test.cjs",
@@ -173,21 +194,31 @@ module.exports = {
173
194
  "tests/roadmap-mode-field.test.cjs",
174
195
  "tests/roadmap-parser.test.cjs",
175
196
  "tests/roadmap-phase-fallback.test.cjs",
197
+ "tests/roadmap-upgrade-bracket.test.cjs",
176
198
  "tests/roadmap.test.cjs",
199
+ "tests/run-tests-accounting.test.cjs",
200
+ "tests/run-tests-harness.test.cjs",
177
201
  "tests/runtime-artifact-layout.test.cjs",
178
202
  "tests/runtime-identity.test.cjs",
179
203
  "tests/runtime-launcher-parity.test.cjs",
204
+ "tests/runtime-name-policy.test.cjs",
180
205
  "tests/security.test.cjs",
181
206
  "tests/settings-jsonc.test.cjs",
182
207
  "tests/shared-hooks-dir-resolution.test.cjs",
183
208
  "tests/shell-command-projection-dispatch.test.cjs",
209
+ "tests/shipped-reference-cites.test.cjs",
184
210
  "tests/spawn-liveness-banner.test.cjs",
185
211
  "tests/state-document.test.cjs",
186
212
  "tests/state-transition.test.cjs",
213
+ "tests/state.platform.test.cjs",
187
214
  "tests/state.test.cjs",
188
215
  "tests/todos-workstream-scope.test.cjs",
189
216
  "tests/tracer-bullet.test.cjs",
217
+ "tests/uat-complete-session.test.cjs",
218
+ "tests/uat-predicate.test.cjs",
190
219
  "tests/uat.test.cjs",
220
+ "tests/ui-auditor-screenshot-block.test.cjs",
221
+ "tests/ui-interaction-capture.test.cjs",
191
222
  "tests/ui-safety-gate.test.cjs",
192
223
  "tests/ui-spec-inventory-provenance.test.cjs",
193
224
  "tests/unreachable-guard-drift.test.cjs",
@@ -195,6 +226,7 @@ module.exports = {
195
226
  "tests/unusable-input.test.cjs",
196
227
  "tests/update-custom-backup.test.cjs",
197
228
  "tests/user-artifact-staging.test.cjs",
229
+ "tests/verification-append-audit.test.cjs",
198
230
  "tests/verification-overrides.test.cjs",
199
231
  "tests/verification-status.test.cjs",
200
232
  "tests/verify-archive-dirs-live-path.test.cjs",
@@ -16,8 +16,9 @@
16
16
  // Durability, not `--test-reporter-destination` (#3889 root cause): a
17
17
  // reporter that YIELDS strings has them piped by Node into a
18
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
19
+ // The parent's per-chunk timeout (run-tests.cjs's runChunk) kills the child
20
+ // on a hang, and a hard kill (TerminateProcess on Windows, SIGKILL on POSIX)
21
+ // is uncatchable and gives the process zero chance to flush — so a
21
22
  // yield-based reporter can lose every event still sitting in the stream's
22
23
  // buffer, which is exactly the case this feature exists to diagnose (proven
23
24
  // live: a chunk killed at 2006ms produced a `killed after 2006ms` line from
@@ -49,8 +50,9 @@
49
50
  // repo's `engines.node` requires >=24.0.0 (package.json), where both
50
51
  // contracts have been stable since Node 20.
51
52
  //
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
53
+ // Kept intentionally tiny: only the event types run-tests.cjs needs are
54
+ // handled — per-file `test:summary` (#5071, see the loop) plus these five:
55
+ // `test:enqueue`/`test:dequeue` (emitted by the RUNNER as it queues
54
56
  // and begins each spawned test-file child, independent of whether anything
55
57
  // inside that file ever completes) plus `test:start`/`test:pass`/`test:fail`
56
58
  // (emitted per-subtest, once the child reports it). `test:dequeue` is the
@@ -93,13 +95,19 @@ module.exports = async function ndjsonEventReporter(source) {
93
95
  event.type === 'test:pass' ||
94
96
  event.type === 'test:fail'
95
97
  ) {
96
- const { file, name, nesting, testNumber } = event.data || {};
98
+ const { file, name, nesting, testNumber, details } = event.data || {};
99
+ // #4031: `kind` is node:test's `details.type` ('suite' for a suite,
100
+ // otherwise a test). run-tests.cjs's per-chunk accounting counts the
101
+ // pass/fail events that are NOT suites and compares them with the
102
+ // registration ledger (scripts/lib/registration-ledger-preload.cjs).
103
+ const kind = details && typeof details.type === 'string' ? details.type : undefined;
97
104
  const line = `${JSON.stringify({
98
105
  type: event.type,
99
106
  file,
100
107
  name,
101
108
  nesting,
102
109
  testNumber,
110
+ kind,
103
111
  ts: Date.now(),
104
112
  })}\n`;
105
113
  try {
@@ -108,6 +116,24 @@ module.exports = async function ndjsonEventReporter(source) {
108
116
  // Best-effort: a write failure here (e.g. the events dir vanished)
109
117
  // must never crash the test run this reporter is only observing.
110
118
  }
119
+ } else if (event.type === 'test:summary' && typeof (event.data || {}).file === 'string') {
120
+ // #5071: node:test emits one `test:summary` per test FILE (its
121
+ // `duration_ms` is that file's wall-clock) plus a run-level one with no
122
+ // `file`. Only the per-file ones are recorded: run-tests.cjs exports
123
+ // them, when asked, as the raw input for a per-platform timing table
124
+ // (scripts/gen-test-timings.cjs --platform). The run-level summary is
125
+ // not a file measurement and is skipped here.
126
+ const line = `${JSON.stringify({
127
+ type: event.type,
128
+ file: event.data.file,
129
+ duration_ms: event.data.duration_ms,
130
+ ts: Date.now(),
131
+ })}\n`;
132
+ try {
133
+ require('fs').appendFileSync(eventsPath, line);
134
+ } catch {
135
+ // Best-effort, as above.
136
+ }
111
137
  }
112
138
  }
113
139
  // Falls through to an implicit `return undefined` (nully): this reporter is