forge-workflow 0.0.10 → 0.1.0-beta.2

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 (454) hide show
  1. package/.claude/rules/{greptile-review-process.md → review-process.md} +56 -41
  2. package/.claude/scripts/{greptile-resolve.sh → review-resolve.sh} +13 -3
  3. package/.cursor/rules/permissions-guidance.mdc +2 -2
  4. package/.forge/hooks/check-tdd.js +3 -0
  5. package/.forge/hooks/forge-native-hook.js +245 -0
  6. package/.forge/protected-paths.yaml +157 -0
  7. package/AGENTS.md +150 -61
  8. package/CHANGELOG.md +681 -0
  9. package/CLAUDE.md +9 -118
  10. package/QUICKSTART.md +171 -0
  11. package/README.md +271 -363
  12. package/bin/forge-cmd.js +120 -9
  13. package/bin/forge-preflight.js +26 -5
  14. package/bin/forge.js +461 -489
  15. package/docs/INDEX.md +93 -0
  16. package/docs/PROJECT_DESIGN.md +685 -0
  17. package/docs/architecture/index.md +66 -0
  18. package/docs/architecture/notes/README.md +35 -0
  19. package/docs/architecture/subsystems/README.md +46 -0
  20. package/docs/forge/TOOLCHAIN.md +670 -0
  21. package/docs/forge/VALIDATION.md +82 -0
  22. package/docs/{AGENT_INSTALL_PROMPT.md → guides/AGENT_INSTALL_PROMPT.md} +3 -3
  23. package/docs/guides/BEADS_GITHUB_SYNC.md +32 -0
  24. package/docs/{ENHANCED_ONBOARDING.md → guides/ENHANCED_ONBOARDING.md} +16 -12
  25. package/docs/guides/GREPTILE_SETUP.md +46 -0
  26. package/docs/guides/MANUAL_REVIEW_GUIDE.md +58 -0
  27. package/docs/guides/MIGRATION.md +56 -0
  28. package/docs/guides/SETUP.md +118 -0
  29. package/docs/guides/SUPPORT.md +185 -0
  30. package/docs/guides/WORKFLOW_TEMPLATES.md +74 -0
  31. package/docs/guides/memory-backends.md +183 -0
  32. package/docs/reference/ADAPTERS.md +128 -0
  33. package/docs/reference/AGENT_SKILL_PARITY.md +175 -0
  34. package/docs/reference/COMMANDS.md +205 -0
  35. package/docs/reference/DECISION_DRIFT_GUARDS.md +97 -0
  36. package/docs/{EXAMPLES.md → reference/EXAMPLES.md} +7 -5
  37. package/docs/reference/FORGE_KERNEL_STORAGE_MODEL.md +135 -0
  38. package/docs/reference/HERMES_INTEGRATION.md +118 -0
  39. package/docs/reference/INSIGHTS_RECAP.md +63 -0
  40. package/docs/reference/INSTALL.md +164 -0
  41. package/docs/reference/KERNEL_TAXONOMY_VALIDATION.md +161 -0
  42. package/docs/reference/PROTECTED_PATH_MANIFEST.md +25 -0
  43. package/docs/reference/RELEASE.md +68 -0
  44. package/docs/reference/RESEARCH_TEMPLATE.md +292 -0
  45. package/docs/{ROADMAP.md → reference/ROADMAP.md} +12 -9
  46. package/docs/reference/SKILLS.md +35 -0
  47. package/docs/reference/STATUS_BOARD.md +80 -0
  48. package/docs/reference/TEMPLATES.md +106 -0
  49. package/docs/{TOOLCHAIN.md → reference/TOOLCHAIN.md} +62 -47
  50. package/docs/reference/VALIDATION.md +82 -0
  51. package/docs/reference/agent-permissions.md +169 -0
  52. package/docs/reference/beads-to-kernel-migration-ux.md +61 -0
  53. package/docs/reference/control-plane-guarantees.md +125 -0
  54. package/docs/reference/dependency-chain.md +331 -0
  55. package/docs/reference/forge-kernel-issue-command-contract.md +161 -0
  56. package/docs/reference/forge-kernel-schema.md +72 -0
  57. package/docs/reference/kernel-conflict-evaluators.md +27 -0
  58. package/docs/reference/patch-md-format.md +77 -0
  59. package/docs/reference/protected-state-surfaces.md +59 -0
  60. package/docs/reference/shepherd.md +115 -0
  61. package/docs/reference/superpowers-analysis.md +320 -0
  62. package/docs/reference/superpowers-integration-options.md +404 -0
  63. package/docs/reference/test-environment.md +519 -0
  64. package/docs/reference/upgrade-safety.md +59 -0
  65. package/lefthook.yml +18 -0
  66. package/lib/adapter-cli.js +307 -0
  67. package/lib/adapters/beads-issue-adapter.js +127 -0
  68. package/lib/adapters/beads-kernel-compat.js +1042 -0
  69. package/lib/adapters/greptile-review-adapter.js +141 -0
  70. package/lib/adapters/kernel-issue-adapter.js +101 -0
  71. package/lib/adapters/pr-state-adapter.js +484 -0
  72. package/lib/adoption-profiles.js +126 -0
  73. package/lib/agents/README.md +2 -6
  74. package/lib/agents/claude.plugin.json +3 -8
  75. package/lib/agents/codex.plugin.json +9 -1
  76. package/lib/agents/cursor.plugin.json +2 -6
  77. package/lib/agents/hermes.plugin.json +22 -0
  78. package/lib/agents-config.js +39 -1236
  79. package/lib/audit-evidence.js +282 -0
  80. package/lib/beads-setup.js +121 -0
  81. package/lib/beads-sync-scaffold.js +25 -101
  82. package/lib/codex-skills.js +51 -1
  83. package/lib/commands/_issue.js +741 -77
  84. package/lib/commands/_manifest.js +91 -0
  85. package/lib/commands/_registry.js +85 -34
  86. package/lib/commands/_resolve-command-opts.js +261 -0
  87. package/lib/commands/_serve-security.js +270 -0
  88. package/lib/commands/adapter.js +12 -0
  89. package/lib/commands/add.js +118 -0
  90. package/lib/commands/audit.js +70 -0
  91. package/lib/commands/blocked.js +5 -0
  92. package/lib/commands/board.js +64 -0
  93. package/lib/commands/claim.js +21 -2
  94. package/lib/commands/claims.js +7 -0
  95. package/lib/commands/clean.js +485 -75
  96. package/lib/commands/close.js +2 -2
  97. package/lib/commands/comment.js +5 -0
  98. package/lib/commands/control.js +148 -0
  99. package/lib/commands/create.js +2 -2
  100. package/lib/commands/dev.js +185 -7
  101. package/lib/commands/doc-gate.js +336 -0
  102. package/lib/commands/doctor.js +156 -0
  103. package/lib/commands/explain.js +15 -0
  104. package/lib/commands/export.js +237 -0
  105. package/lib/commands/gate.js +192 -0
  106. package/lib/commands/hooks.js +242 -0
  107. package/lib/commands/inbox.js +118 -0
  108. package/lib/commands/init.js +598 -0
  109. package/lib/commands/insights.js +79 -0
  110. package/lib/commands/issue.js +12 -1
  111. package/lib/commands/issues.js +17 -0
  112. package/lib/commands/lint.js +5 -0
  113. package/lib/commands/list.js +2 -2
  114. package/lib/commands/merge.js +312 -0
  115. package/lib/commands/migrate.js +523 -0
  116. package/lib/commands/new.js +12 -0
  117. package/lib/commands/options.js +241 -0
  118. package/lib/commands/orient.js +13 -0
  119. package/lib/commands/orphans.js +5 -0
  120. package/lib/commands/patch.js +67 -0
  121. package/lib/commands/plan.js +436 -24
  122. package/lib/commands/preflight.js +211 -0
  123. package/lib/commands/prime.js +13 -0
  124. package/lib/commands/push.js +69 -2
  125. package/lib/commands/ready.js +2 -2
  126. package/lib/commands/recall.js +116 -0
  127. package/lib/commands/recap.js +61 -0
  128. package/lib/commands/recommend.js +0 -1
  129. package/lib/commands/release.js +91 -0
  130. package/lib/commands/remember.js +74 -0
  131. package/lib/commands/role.js +99 -0
  132. package/lib/commands/serve.js +581 -0
  133. package/lib/commands/setup.js +838 -972
  134. package/lib/commands/shepherd.js +436 -0
  135. package/lib/commands/ship.js +23 -1
  136. package/lib/commands/show.js +2 -2
  137. package/lib/commands/stage.js +192 -0
  138. package/lib/commands/stale.js +5 -0
  139. package/lib/commands/status.js +158 -21
  140. package/lib/commands/sync.js +34 -46
  141. package/lib/commands/team.js +4 -1
  142. package/lib/commands/test.js +43 -27
  143. package/lib/commands/update.js +2 -2
  144. package/lib/commands/upgrade.js +47 -0
  145. package/lib/commands/validate.js +43 -18
  146. package/lib/commands/worktree.js +307 -100
  147. package/lib/config-writer.js +202 -0
  148. package/lib/control-plane.js +236 -0
  149. package/lib/core/runtime-graph.js +946 -0
  150. package/lib/dep-guard/keyword-ripple.js +2 -2
  151. package/lib/deprecated-sync-cleanup.js +362 -0
  152. package/lib/detect-agent.js +2 -28
  153. package/lib/detect-worktree.js +35 -9
  154. package/lib/doc-gate/declaration.js +177 -0
  155. package/lib/doc-gate/detect.js +289 -0
  156. package/lib/doc-gate/gate.js +375 -0
  157. package/lib/doc-gate/okf-config.js +128 -0
  158. package/lib/doc-gate/okf.js +429 -0
  159. package/lib/docs-command.js +1161 -6
  160. package/lib/forge-issues.js +382 -11
  161. package/lib/forge-lock.js +262 -0
  162. package/lib/gate-events.js +193 -0
  163. package/lib/global-flags.js +74 -0
  164. package/lib/greptile-match.js +7 -63
  165. package/lib/harness-capability-matrix.js +380 -0
  166. package/lib/hook-global-installer.js +347 -0
  167. package/lib/hook-renderer.js +451 -0
  168. package/lib/inbox.js +391 -0
  169. package/lib/insights.js +397 -0
  170. package/lib/issue-adapter.js +156 -0
  171. package/lib/issue-backend.js +145 -0
  172. package/lib/issue-render.js +220 -0
  173. package/lib/kernel/backing-issue.js +305 -0
  174. package/lib/kernel/broker.js +1218 -0
  175. package/lib/kernel/cli-broker-factory.js +130 -0
  176. package/lib/kernel/conflict-signal.js +82 -0
  177. package/lib/kernel/evaluators.js +195 -0
  178. package/lib/kernel/fs-class.js +495 -0
  179. package/lib/kernel/issue-command-contract.js +559 -0
  180. package/lib/kernel/issue-id-resolver.js +186 -0
  181. package/lib/kernel/lease-enforcer.js +158 -0
  182. package/lib/kernel/migrations.js +333 -0
  183. package/lib/kernel/planning-buckets-schema.js +109 -0
  184. package/lib/kernel/projection-jsonl-writer.js +450 -0
  185. package/lib/kernel/readiness-model.js +329 -0
  186. package/lib/kernel/schema.js +356 -0
  187. package/lib/kernel/sqlite-driver.js +2504 -0
  188. package/lib/kernel/taxonomy-validator.js +394 -0
  189. package/lib/lefthook-check.js +3 -2
  190. package/lib/lefthook-wiring.js +413 -0
  191. package/lib/mcp-config-renderer.js +288 -0
  192. package/lib/memory/graphiti-mcp.js +106 -0
  193. package/lib/memory/router.js +387 -0
  194. package/lib/memory/typed-api.js +102 -0
  195. package/lib/memory-digest.js +195 -0
  196. package/lib/merge-rules.js +395 -0
  197. package/lib/migrate-dry-run.js +466 -0
  198. package/lib/orientation.js +863 -0
  199. package/lib/package-manager-remediation.js +103 -0
  200. package/lib/package-root.js +381 -0
  201. package/lib/patch-intent.js +890 -0
  202. package/lib/plugin-catalog.js +3 -4
  203. package/lib/plugin-manager.js +0 -5
  204. package/lib/pr-bundle.js +186 -0
  205. package/lib/pr-monitor/differ.js +195 -0
  206. package/lib/pr-monitor/events.js +0 -0
  207. package/lib/pr-monitor/gather.js +124 -0
  208. package/lib/pr-monitor/journal.js +299 -0
  209. package/lib/pr-monitor/monitor.js +146 -0
  210. package/lib/pr-monitor/render-sticky.js +157 -0
  211. package/lib/pr-monitor/watch-lifecycle.js +95 -0
  212. package/lib/pr-monitor/watch.js +247 -0
  213. package/lib/pr-pull.js +1273 -0
  214. package/lib/pr-shepherd.js +494 -0
  215. package/lib/pr-state-validator.js +59 -0
  216. package/lib/preflight/gates.js +237 -0
  217. package/lib/preflight/runner.js +116 -0
  218. package/lib/project-discovery.js +0 -53
  219. package/lib/project-memory.js +99 -497
  220. package/lib/protected-path-manifest.js +281 -0
  221. package/lib/protected-state-surfaces.js +387 -0
  222. package/lib/release-readiness.js +2089 -0
  223. package/lib/reset.js +59 -45
  224. package/lib/review-adapter.js +68 -0
  225. package/lib/rules-sync.js +260 -0
  226. package/lib/runtime-health.js +241 -20
  227. package/lib/safety-config-renderer.js +268 -0
  228. package/lib/setup-action-log.js +1 -7
  229. package/lib/setup.js +27 -65
  230. package/lib/shell-utils.js +76 -6
  231. package/lib/skills-sync.js +330 -0
  232. package/lib/smart-status/scoring.js +17 -3
  233. package/lib/status/beads-snapshot.js +45 -2
  234. package/lib/status/presenter.js +169 -18
  235. package/lib/status/snapshot.js +186 -0
  236. package/lib/sync-backend.js +202 -0
  237. package/lib/untrusted-content.js +52 -0
  238. package/lib/upgrade-safety.js +199 -0
  239. package/lib/workflow/enforce-stage.js +296 -47
  240. package/lib/workflow/stage-transition.js +115 -0
  241. package/lib/workflow/stages.js +30 -6
  242. package/lib/workflow/state-manager.js +11 -22
  243. package/lib/workflow/state.js +23 -1
  244. package/lib/workflow-profiles.js +17 -5
  245. package/package.json +37 -35
  246. package/rules/documentation.md +19 -0
  247. package/rules/kernel-tracking.md +26 -0
  248. package/rules/security.md +22 -0
  249. package/rules/tdd.md +20 -0
  250. package/rules/workflow.md +27 -0
  251. package/scripts/auto-backing-issue.js +47 -0
  252. package/scripts/beads-context.sh +81 -57
  253. package/scripts/beads-upgrade-smoke.sh +24 -3
  254. package/scripts/bootstrap-windows-tools.sh +78 -0
  255. package/scripts/branch-protection.js +2 -3
  256. package/scripts/check-agents.js +34 -137
  257. package/scripts/commitlint.js +3 -1
  258. package/scripts/conflict-detect.sh +3 -0
  259. package/scripts/dep-guard.sh +22 -3
  260. package/scripts/file-index.sh +3 -0
  261. package/scripts/forge-team/lib/claim.sh +34 -18
  262. package/scripts/forge-team/lib/dashboard.sh +61 -86
  263. package/scripts/forge-team/lib/epic.sh +99 -263
  264. package/scripts/forge-team/lib/hooks.sh +26 -28
  265. package/scripts/forge-team/lib/identity.sh +4 -4
  266. package/scripts/forge-team/lib/sync-github.sh +49 -84
  267. package/scripts/forge-team/lib/verify.sh +93 -83
  268. package/scripts/forge-team/lib/workload.sh +41 -65
  269. package/scripts/forge-team/tests/claim.test.sh +25 -19
  270. package/scripts/forge-team/tests/dashboard.test.sh +31 -46
  271. package/scripts/forge-team/tests/epic.test.sh +52 -71
  272. package/scripts/forge-team/tests/hooks.test.sh +38 -50
  273. package/scripts/forge-team/tests/identity.test.sh +3 -3
  274. package/scripts/forge-team/tests/integration.test.sh +44 -66
  275. package/scripts/forge-team/tests/sync-github.test.sh +50 -83
  276. package/scripts/forge-team/tests/verify.test.sh +37 -46
  277. package/scripts/forge-team/tests/workflow-integration.test.sh +4 -4
  278. package/scripts/forge-team/tests/workload.test.sh +32 -66
  279. package/scripts/gen-command-manifest.js +153 -0
  280. package/scripts/gen-embedded-assets.mjs +129 -0
  281. package/scripts/install.ps1 +139 -0
  282. package/scripts/install.sh +268 -0
  283. package/scripts/lib/release-asset.mjs +84 -0
  284. package/scripts/parity-check.mjs +145 -0
  285. package/scripts/parity-check.test.mjs +58 -0
  286. package/scripts/pin-agentic-workflow-images.js +112 -0
  287. package/scripts/pr-coordinator.sh +3 -0
  288. package/scripts/preflight-sonar.eslint.config.mjs +44 -0
  289. package/scripts/preflight.sh +21 -94
  290. package/scripts/protected-state-check.js +104 -0
  291. package/scripts/smart-status.sh +60 -57
  292. package/scripts/spikes/config-race-bench.js +111 -0
  293. package/scripts/spikes/harness-capability-matrix.js +13 -0
  294. package/scripts/spikes/patch-anchor-stability-bench.js +125 -0
  295. package/scripts/spikes/protected-path-manifest.js +20 -0
  296. package/scripts/spikes/skill-auto-invoke-parity.js +292 -0
  297. package/scripts/sync-agent-skills.js +62 -0
  298. package/scripts/sync-utils.sh +3 -0
  299. package/scripts/test-ci-shard.js +13 -6
  300. package/scripts/test.js +95 -12
  301. package/skills/claim-safety/SKILL.md +102 -0
  302. package/skills/claim-safety/evals/evals.json +46 -0
  303. package/{.github/prompts/dev.prompt.md → skills/dev/SKILL.md} +44 -50
  304. package/skills/dev/evals/evals.json +50 -0
  305. package/skills/hermes-forge/SKILL.md +185 -0
  306. package/skills/hermes-forge/evals/evals.json +46 -0
  307. package/skills/issue-basics/SKILL.md +111 -0
  308. package/skills/issue-basics/evals/evals.json +46 -0
  309. package/skills/kernel/SKILL.md +166 -0
  310. package/skills/kernel/evals/evals.json +50 -0
  311. package/skills/memory/SKILL.md +102 -0
  312. package/skills/parallel-deep-research/SKILL.md +14 -11
  313. package/skills/parallel-deep-research/evals/evals.json +11 -27
  314. package/{.github/prompts/plan.prompt.md → skills/plan/SKILL.md} +132 -157
  315. package/skills/plan/evals/evals.json +42 -0
  316. package/skills/research/SKILL.md +195 -0
  317. package/skills/research/evals/evals.json +42 -0
  318. package/{.github/prompts/review.prompt.md → skills/review/SKILL.md} +98 -62
  319. package/skills/review/evals/evals.json +42 -0
  320. package/skills/rollback/SKILL.md +110 -0
  321. package/skills/rollback/evals/evals.json +46 -0
  322. package/skills/rollback/references/methods.md +204 -0
  323. package/{.cursor/commands/rollback.md → skills/rollback/references/workflow-integration.md} +10 -284
  324. package/skills/shepherd/SKILL.md +66 -0
  325. package/skills/shepherd/evals/evals.json +42 -0
  326. package/{.github/prompts/ship.prompt.md → skills/ship/SKILL.md} +81 -45
  327. package/skills/ship/evals/evals.json +42 -0
  328. package/skills/smith/SKILL.md +142 -0
  329. package/skills/smith/evals/evals.json +46 -0
  330. package/skills/smith/references/autonomy-and-gates.md +94 -0
  331. package/{.github/prompts/sonarcloud.prompt.md → skills/sonarcloud/SKILL.md} +14 -3
  332. package/skills/sonarcloud/evals/evals.json +46 -0
  333. package/skills/sonarcloud-analysis/SKILL.md +18 -13
  334. package/skills/sonarcloud-analysis/evals/evals.json +11 -15
  335. package/{.github/prompts/status.prompt.md → skills/status/SKILL.md} +20 -10
  336. package/skills/status/evals/evals.json +50 -0
  337. package/skills/triage-ready/SKILL.md +121 -0
  338. package/skills/triage-ready/evals/evals.json +42 -0
  339. package/{.github/prompts/validate.prompt.md → skills/validate/SKILL.md} +52 -29
  340. package/skills/validate/evals/evals.json +42 -0
  341. package/skills/verify/SKILL.md +299 -0
  342. package/skills/verify/evals/evals.json +50 -0
  343. package/.claude/commands/dev.md +0 -345
  344. package/.claude/commands/plan.md +0 -566
  345. package/.claude/commands/premerge.md +0 -186
  346. package/.claude/commands/research.md +0 -42
  347. package/.claude/commands/review.md +0 -451
  348. package/.claude/commands/rollback.md +0 -721
  349. package/.claude/commands/ship.md +0 -213
  350. package/.claude/commands/sonarcloud.md +0 -152
  351. package/.claude/commands/status.md +0 -90
  352. package/.claude/commands/validate.md +0 -288
  353. package/.claude/commands/verify.md +0 -269
  354. package/.claude/rules/workflow.md +0 -121
  355. package/.cline/workflows/dev.md +0 -342
  356. package/.cline/workflows/plan.md +0 -563
  357. package/.cline/workflows/premerge.md +0 -183
  358. package/.cline/workflows/research.md +0 -39
  359. package/.cline/workflows/review.md +0 -448
  360. package/.cline/workflows/rollback.md +0 -718
  361. package/.cline/workflows/ship.md +0 -210
  362. package/.cline/workflows/sonarcloud.md +0 -146
  363. package/.cline/workflows/status.md +0 -87
  364. package/.cline/workflows/validate.md +0 -285
  365. package/.cline/workflows/verify.md +0 -266
  366. package/.codex/config.toml +0 -11
  367. package/.codex/skills/dev/SKILL.md +0 -345
  368. package/.codex/skills/plan/SKILL.md +0 -566
  369. package/.codex/skills/premerge/SKILL.md +0 -186
  370. package/.codex/skills/research/SKILL.md +0 -42
  371. package/.codex/skills/review/SKILL.md +0 -451
  372. package/.codex/skills/rollback/SKILL.md +0 -721
  373. package/.codex/skills/ship/SKILL.md +0 -213
  374. package/.codex/skills/sonarcloud/SKILL.md +0 -149
  375. package/.codex/skills/status/SKILL.md +0 -90
  376. package/.codex/skills/validate/SKILL.md +0 -288
  377. package/.codex/skills/verify/SKILL.md +0 -269
  378. package/.cursor/commands/dev.md +0 -342
  379. package/.cursor/commands/plan.md +0 -563
  380. package/.cursor/commands/premerge.md +0 -183
  381. package/.cursor/commands/research.md +0 -39
  382. package/.cursor/commands/review.md +0 -448
  383. package/.cursor/commands/ship.md +0 -210
  384. package/.cursor/commands/sonarcloud.md +0 -146
  385. package/.cursor/commands/status.md +0 -87
  386. package/.cursor/commands/validate.md +0 -285
  387. package/.cursor/commands/verify.md +0 -266
  388. package/.cursorrules +0 -149
  389. package/.github/prompts/premerge.prompt.md +0 -188
  390. package/.github/prompts/research.prompt.md +0 -44
  391. package/.github/prompts/rollback.prompt.md +0 -723
  392. package/.github/prompts/verify.prompt.md +0 -271
  393. package/.github/workflows/beads-to-github.yml +0 -89
  394. package/.github/workflows/github-to-beads.yml +0 -100
  395. package/.kilocode/workflows/dev.md +0 -346
  396. package/.kilocode/workflows/plan.md +0 -567
  397. package/.kilocode/workflows/premerge.md +0 -187
  398. package/.kilocode/workflows/research.md +0 -43
  399. package/.kilocode/workflows/review.md +0 -452
  400. package/.kilocode/workflows/rollback.md +0 -722
  401. package/.kilocode/workflows/ship.md +0 -214
  402. package/.kilocode/workflows/sonarcloud.md +0 -150
  403. package/.kilocode/workflows/status.md +0 -91
  404. package/.kilocode/workflows/validate.md +0 -289
  405. package/.kilocode/workflows/verify.md +0 -270
  406. package/.opencode/commands/dev.md +0 -345
  407. package/.opencode/commands/plan.md +0 -566
  408. package/.opencode/commands/premerge.md +0 -186
  409. package/.opencode/commands/research.md +0 -42
  410. package/.opencode/commands/review.md +0 -451
  411. package/.opencode/commands/rollback.md +0 -721
  412. package/.opencode/commands/ship.md +0 -213
  413. package/.opencode/commands/sonarcloud.md +0 -149
  414. package/.opencode/commands/status.md +0 -90
  415. package/.opencode/commands/validate.md +0 -288
  416. package/.opencode/commands/verify.md +0 -269
  417. package/.roo/commands/dev.md +0 -346
  418. package/.roo/commands/plan.md +0 -567
  419. package/.roo/commands/premerge.md +0 -187
  420. package/.roo/commands/research.md +0 -43
  421. package/.roo/commands/review.md +0 -452
  422. package/.roo/commands/rollback.md +0 -722
  423. package/.roo/commands/ship.md +0 -214
  424. package/.roo/commands/sonarcloud.md +0 -150
  425. package/.roo/commands/status.md +0 -91
  426. package/.roo/commands/validate.md +0 -289
  427. package/.roo/commands/verify.md +0 -270
  428. package/docs/BEADS_GITHUB_SYNC.md +0 -281
  429. package/docs/GREPTILE_SETUP.md +0 -400
  430. package/docs/MANUAL_REVIEW_GUIDE.md +0 -106
  431. package/docs/SETUP.md +0 -663
  432. package/docs/VALIDATION.md +0 -363
  433. package/lib/agents/cline.plugin.json +0 -29
  434. package/lib/agents/copilot.plugin.json +0 -24
  435. package/lib/agents/kilocode.plugin.json +0 -22
  436. package/lib/agents/opencode.plugin.json +0 -23
  437. package/lib/agents/roo.plugin.json +0 -30
  438. package/lib/beads-bootstrap.js +0 -225
  439. package/lib/beads-health-check.js +0 -188
  440. package/lib/commands/commands-reset.js +0 -147
  441. package/opencode.json +0 -67
  442. package/scripts/beads-context.test.js +0 -584
  443. package/scripts/github-beads-sync/comment.mjs +0 -64
  444. package/scripts/github-beads-sync/config.mjs +0 -148
  445. package/scripts/github-beads-sync/github-api.mjs +0 -131
  446. package/scripts/github-beads-sync/index.mjs +0 -356
  447. package/scripts/github-beads-sync/label-mapper.mjs +0 -54
  448. package/scripts/github-beads-sync/mapping.mjs +0 -132
  449. package/scripts/github-beads-sync/reverse-sync-cli.mjs +0 -31
  450. package/scripts/github-beads-sync/reverse-sync.mjs +0 -162
  451. package/scripts/github-beads-sync/run-bd.mjs +0 -161
  452. package/scripts/github-beads-sync/sanitize.mjs +0 -121
  453. package/scripts/github-beads-sync.config.json +0 -26
  454. package/scripts/sync-commands.js +0 -600
@@ -0,0 +1,125 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const { performance } = require('node:perf_hooks');
5
+
6
+ function readNumberFlag(args, name, fallback) {
7
+ const index = args.indexOf(name);
8
+ if (index === -1) return fallback;
9
+ const value = Number(args[index + 1]);
10
+ if (!Number.isFinite(value) || value < 0) {
11
+ throw new Error(`${name} must be a non-negative number`);
12
+ }
13
+ return value;
14
+ }
15
+
16
+ function assertPositiveInteger(name, value) {
17
+ if (!Number.isInteger(value) || value <= 0) {
18
+ throw new Error(`${name} must be a positive integer`);
19
+ }
20
+ }
21
+
22
+ function assertNonNegativeInteger(name, value) {
23
+ if (!Number.isInteger(value) || value < 0) {
24
+ throw new Error(`${name} must be a non-negative integer`);
25
+ }
26
+ }
27
+
28
+ function runBench(options = {}) {
29
+ const anchorCount = options.anchorCount ?? 500;
30
+ const patchCount = options.patchCount ?? 50;
31
+ const renameCount = options.renameCount ?? patchCount;
32
+ const unmappedCount = options.unmappedCount ?? 2;
33
+ const threshold = options.threshold ?? 0.10;
34
+
35
+ assertPositiveInteger('anchorCount', anchorCount);
36
+ assertPositiveInteger('patchCount', patchCount);
37
+ assertNonNegativeInteger('renameCount', renameCount);
38
+ assertNonNegativeInteger('unmappedCount', unmappedCount);
39
+ if (patchCount > anchorCount) {
40
+ throw new Error('patchCount must be <= anchorCount');
41
+ }
42
+ if (renameCount > patchCount) {
43
+ throw new Error('renameCount must be <= patchCount');
44
+ }
45
+ if (unmappedCount > renameCount) {
46
+ throw new Error('unmappedCount must be <= renameCount');
47
+ }
48
+
49
+ const start = performance.now();
50
+ const oldAnchors = Array.from({ length: anchorCount }, (_, i) => `stage.${i}.body`);
51
+ const patches = oldAnchors.slice(0, patchCount).map((anchor, i) => ({
52
+ id: `patch-${String(i + 1).padStart(3, '0')}`,
53
+ anchor,
54
+ }));
55
+
56
+ const currentAnchors = new Set(oldAnchors);
57
+ const aliases = new Map();
58
+ for (let i = 0; i < renameCount; i += 1) {
59
+ const oldAnchor = oldAnchors[i];
60
+ const newAnchor = `${oldAnchor}.v2`;
61
+ currentAnchors.delete(oldAnchor);
62
+ currentAnchors.add(newAnchor);
63
+ if (i >= unmappedCount) {
64
+ aliases.set(oldAnchor, newAnchor);
65
+ }
66
+ }
67
+
68
+ let resolved = 0;
69
+ let orphaned = 0;
70
+ const orphanIds = [];
71
+ for (const patch of patches) {
72
+ if (currentAnchors.has(patch.anchor)) {
73
+ resolved += 1;
74
+ continue;
75
+ }
76
+ const alias = aliases.get(patch.anchor);
77
+ if (alias && currentAnchors.has(alias)) {
78
+ resolved += 1;
79
+ continue;
80
+ }
81
+ orphaned += 1;
82
+ orphanIds.push(patch.id);
83
+ }
84
+
85
+ const elapsedMs = performance.now() - start;
86
+ const orphanRate = orphaned / patchCount;
87
+ return {
88
+ spike: 'patch-anchor-stability',
89
+ patchCount,
90
+ anchorCount,
91
+ renamedAnchors: renameCount,
92
+ aliasEntries: aliases.size,
93
+ orphaned,
94
+ resolved,
95
+ orphanRate,
96
+ threshold,
97
+ passed: orphanRate < threshold,
98
+ elapsedMs: Number(elapsedMs.toFixed(3)),
99
+ complexity: 'O(patches + anchors + aliases) with Map/Set lookups',
100
+ orphanIds,
101
+ };
102
+ }
103
+
104
+ function main() {
105
+ const args = process.argv.slice(2);
106
+ const patchCount = readNumberFlag(args, '--patches', 50);
107
+ const result = runBench({
108
+ anchorCount: readNumberFlag(args, '--anchors', 500),
109
+ patchCount,
110
+ renameCount: readNumberFlag(args, '--renames', patchCount),
111
+ unmappedCount: readNumberFlag(args, '--unmapped', 2),
112
+ threshold: readNumberFlag(args, '--threshold', 0.10),
113
+ });
114
+
115
+ console.log(JSON.stringify(result, null, args.includes('--json') ? 0 : 2));
116
+ if (!result.passed) {
117
+ process.exitCode = 1;
118
+ }
119
+ }
120
+
121
+ if (require.main === module) {
122
+ main();
123
+ }
124
+
125
+ module.exports = { runBench };
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const path = require('node:path');
5
+ const {
6
+ buildProtectedPathManifestEvidence,
7
+ loadProtectedPathManifest,
8
+ } = require('../../lib/protected-path-manifest');
9
+
10
+ const root = path.resolve(__dirname, '..', '..');
11
+ const manifestPath = path.join(root, '.forge', 'protected-paths.yaml');
12
+
13
+ try {
14
+ const manifest = loadProtectedPathManifest(manifestPath);
15
+ process.stdout.write(`${JSON.stringify(buildProtectedPathManifestEvidence(manifest), null, 2)}\n`);
16
+ } catch (error) {
17
+ const message = error instanceof Error ? error.message : String(error);
18
+ process.stderr.write(`Failed to build protected path manifest evidence from ${manifestPath}: ${message}\n`);
19
+ process.exit(1);
20
+ }
@@ -0,0 +1,292 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const fs = require('node:fs');
5
+ const os = require('node:os');
6
+ const path = require('node:path');
7
+ const YAML = require('yaml');
8
+
9
+ const CANONICAL_SKILL = {
10
+ name: 'guard-rails-audit',
11
+ description: 'Use when asked to inspect Forge L1 rail enforcement, audit events, or protected path policy.',
12
+ body: [
13
+ '# Guard Rails Audit',
14
+ '',
15
+ 'Check Forge L1 rails, audit-event coverage, and protected path policy before recommending changes.',
16
+ ].join('\n'),
17
+ };
18
+
19
+ const MATCHING_PROMPT = 'Inspect Forge L1 rail enforcement and audit events for protected path policy.';
20
+ const NON_MATCHING_PROMPT = 'Draft release notes for a minor README copy edit.';
21
+ const FIXTURE_FILE = 'src/index.js';
22
+
23
+ const SOURCES = [
24
+ {
25
+ label: 'S1',
26
+ harness: 'claude-code',
27
+ url: 'https://code.claude.com/docs/en/skills',
28
+ summary: 'Claude Code project skills live under .claude/skills/<skill>/SKILL.md and use description metadata for automatic invocation.',
29
+ },
30
+ {
31
+ label: 'S2',
32
+ harness: 'cursor',
33
+ url: 'https://docs.cursor.com/en/context',
34
+ summary: 'Cursor Project Rules live under .cursor/rules as .mdc files; Agent Requested rules are description-driven.',
35
+ },
36
+ {
37
+ label: 'S3',
38
+ harness: 'codex-cli',
39
+ url: 'https://github.com/openai/codex/blob/main/codex-rs/skills/src/assets/samples/skill-creator/SKILL.md',
40
+ summary: 'Codex skills use SKILL.md frontmatter name and description to determine when the skill gets used.',
41
+ },
42
+ {
43
+ label: 'S4',
44
+ harness: 'forge',
45
+ url: 'lib/codex-skills.js',
46
+ summary: 'Forge packages repository Codex skills from .codex/skills for installation into $CODEX_HOME/skills.',
47
+ },
48
+ ];
49
+
50
+ const HARNESS_TARGETS = [
51
+ {
52
+ harness: 'claude-code',
53
+ target: '.claude/skills/guard-rails-audit/SKILL.md',
54
+ explicitInvocation: '/guard-rails-audit',
55
+ sourceLabel: 'S1',
56
+ source: 'Claude Code skill directory target',
57
+ buildFrontmatter: () => ({
58
+ name: CANONICAL_SKILL.name,
59
+ description: CANONICAL_SKILL.description,
60
+ }),
61
+ },
62
+ {
63
+ harness: 'cursor',
64
+ target: '.cursor/rules/guard-rails-audit.mdc',
65
+ explicitInvocation: '/guard-rails-audit',
66
+ sourceLabel: 'S2',
67
+ source: 'Cursor project rule with documented description/globs/alwaysApply metadata',
68
+ buildFrontmatter: () => ({
69
+ description: CANONICAL_SKILL.description,
70
+ globs: null,
71
+ alwaysApply: false,
72
+ }),
73
+ },
74
+ {
75
+ harness: 'codex-cli',
76
+ target: '.codex/skills/guard-rails-audit/SKILL.md',
77
+ explicitInvocation: '/guard-rails-audit',
78
+ sourceLabel: 'S4',
79
+ source: 'Forge repository Codex skills package surface; custom slash prompt files are intentionally not used',
80
+ buildFrontmatter: () => ({
81
+ name: CANONICAL_SKILL.name,
82
+ description: CANONICAL_SKILL.description,
83
+ }),
84
+ },
85
+ ];
86
+
87
+ function buildMarkdown(frontmatter, body) {
88
+ return `---\n${YAML.stringify(frontmatter, {
89
+ lineWidth: 0,
90
+ defaultKeyType: 'PLAIN',
91
+ defaultStringType: 'PLAIN',
92
+ }).trimEnd()}\n---\n\n${body}\n`;
93
+ }
94
+
95
+ function parseFrontmatter(content) {
96
+ const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?/);
97
+ if (!match) return {};
98
+ const parsed = YAML.parse(match[1]);
99
+ return parsed && typeof parsed === 'object' ? parsed : {};
100
+ }
101
+
102
+ function writeFile(root, relativePath, content) {
103
+ const absolutePath = path.join(root, relativePath);
104
+ fs.mkdirSync(path.dirname(absolutePath), { recursive: true });
105
+ fs.writeFileSync(absolutePath, content);
106
+ }
107
+
108
+ function isDirectoryEmpty(directory) {
109
+ return !fs.existsSync(directory) || fs.readdirSync(directory).length === 0;
110
+ }
111
+
112
+ function materializeFixture(root) {
113
+ if (!isDirectoryEmpty(root)) {
114
+ throw new Error(`fixture directory must be empty: ${root}`);
115
+ }
116
+
117
+ fs.mkdirSync(root, { recursive: true });
118
+ writeFile(root, FIXTURE_FILE, 'export function fixture() { return true; }\n');
119
+
120
+ for (const target of HARNESS_TARGETS) {
121
+ writeFile(
122
+ root,
123
+ target.target,
124
+ buildMarkdown(target.buildFrontmatter(), CANONICAL_SKILL.body),
125
+ );
126
+ }
127
+
128
+ return { root, skill: CANONICAL_SKILL, targets: HARNESS_TARGETS };
129
+ }
130
+
131
+ function tokens(value) {
132
+ return String(value)
133
+ .toLowerCase()
134
+ .match(/[a-z0-9]+/g)
135
+ ?.filter((token) => token.length >= 4) || [];
136
+ }
137
+
138
+ function descriptionMatches(description, prompt) {
139
+ const promptTokens = new Set(tokens(prompt));
140
+ const triggerTokens = tokens(description)
141
+ .filter((token) => !['when', 'asked', 'inspect'].includes(token));
142
+
143
+ return triggerTokens.some((token) => promptTokens.has(token));
144
+ }
145
+
146
+ function cursorGlobMatches(globs, filePath) {
147
+ void filePath;
148
+ if (!Array.isArray(globs) || globs.length === 0) return true;
149
+ return globs.includes('**/*') || globs.includes(filePath);
150
+ }
151
+
152
+ function validateHarness(root, target) {
153
+ const absolutePath = path.join(root, target.target);
154
+ const failures = [];
155
+
156
+ if (!fs.existsSync(absolutePath)) {
157
+ failures.push(`missing ${target.target}`);
158
+ return { ...target, passed: false, failures };
159
+ }
160
+
161
+ const frontmatter = parseFrontmatter(fs.readFileSync(absolutePath, 'utf8'));
162
+ const description = frontmatter.description;
163
+ const positiveMatch = descriptionMatches(description, MATCHING_PROMPT);
164
+ const negativeMatch = descriptionMatches(description, NON_MATCHING_PROMPT);
165
+
166
+ if (description !== CANONICAL_SKILL.description) {
167
+ failures.push('description does not match canonical skill description');
168
+ }
169
+ if (!positiveMatch) {
170
+ failures.push('matching prompt did not select the skill by description');
171
+ }
172
+ if (negativeMatch) {
173
+ failures.push('unrelated prompt selected the skill');
174
+ }
175
+ if (target.explicitInvocation !== `/${CANONICAL_SKILL.name}`) {
176
+ failures.push('explicit slash invocation does not match canonical skill name');
177
+ }
178
+
179
+ if (target.harness === 'claude-code') {
180
+ if (frontmatter.name !== CANONICAL_SKILL.name) failures.push('Claude skill name is missing or incorrect');
181
+ }
182
+
183
+ if (target.harness === 'cursor') {
184
+ if (frontmatter.alwaysApply !== false) failures.push('Cursor rule must keep alwaysApply: false for request-time selection');
185
+ if (!cursorGlobMatches(frontmatter.globs, FIXTURE_FILE)) failures.push(`Cursor globs do not include ${FIXTURE_FILE}`);
186
+ }
187
+
188
+ if (target.harness === 'codex-cli') {
189
+ if (!target.target.startsWith('.codex/skills/') || target.target.includes('/prompts/')) {
190
+ failures.push('Codex target must use .codex/skills, not undocumented prompt/slash files');
191
+ }
192
+ }
193
+
194
+ return {
195
+ ...target,
196
+ passed: failures.length === 0,
197
+ descriptionMatched: positiveMatch,
198
+ negativePromptIgnored: !negativeMatch,
199
+ frontmatter,
200
+ failures,
201
+ };
202
+ }
203
+
204
+ function runParity(options = {}) {
205
+ const root = options.fixtureDir || fs.mkdtempSync(path.join(os.tmpdir(), 'forge-w0-harness-parity-'));
206
+ const cleanup = options.fixtureDir ? false : options.cleanup !== false;
207
+
208
+ try {
209
+ materializeFixture(root);
210
+ const harnesses = HARNESS_TARGETS.map((target) => validateHarness(root, target));
211
+ const passed = harnesses.every((result) => result.passed);
212
+ const feasibleCount = harnesses.filter((result) => result.passed).length;
213
+ const knownIssues = passed ? [] : [{
214
+ issue: 'Cross-harness skill render parity did not pass for all three target harnesses.',
215
+ d38: 'D38 kills v3 if two of Claude/Cursor/Codex cannot render a single skill correctly by the W3 checkpoint.',
216
+ feasibleCount,
217
+ }];
218
+
219
+ return {
220
+ fixture: 'w0-skill-auto-invoke-parity',
221
+ fixtureRoot: root,
222
+ matchingPrompt: MATCHING_PROMPT,
223
+ nonMatchingPrompt: NON_MATCHING_PROMPT,
224
+ canonicalSkill: CANONICAL_SKILL,
225
+ harnesses,
226
+ sources: SOURCES,
227
+ proofBoundary: {
228
+ level: 'metadata-surface',
229
+ liveAgentInvocation: 'not-run',
230
+ codexRuntimeDiscovery: 'not-run',
231
+ reason: 'closed-source harness model invocation is outside this deterministic fixture; .codex/skills is the Forge repository packaging surface, not proof of direct Codex runtime discovery',
232
+ },
233
+ passed,
234
+ knownIssues,
235
+ };
236
+ } finally {
237
+ if (cleanup) fs.rmSync(root, { recursive: true, force: true });
238
+ }
239
+ }
240
+
241
+ function printText(result) {
242
+ console.log(`W0 skill auto-invoke parity: ${result.passed ? 'PASS' : 'FAIL'}`);
243
+ for (const harness of result.harnesses) {
244
+ const status = harness.passed ? 'PASS' : 'FAIL';
245
+ console.log(`${status} ${harness.harness} ${harness.target}`);
246
+ for (const failure of harness.failures) {
247
+ console.log(` - ${failure}`);
248
+ }
249
+ }
250
+ if (result.knownIssues.length > 0) {
251
+ for (const issue of result.knownIssues) {
252
+ console.log(`Known issue: ${issue.issue} ${issue.d38}`);
253
+ }
254
+ }
255
+ }
256
+
257
+ function readStringFlag(args, name) {
258
+ const index = args.indexOf(name);
259
+ if (index === -1) return undefined;
260
+ const value = args[index + 1];
261
+ if (!value || value.startsWith('-')) return undefined;
262
+ return value;
263
+ }
264
+
265
+ function main() {
266
+ const args = process.argv.slice(2);
267
+ const result = runParity({ fixtureDir: readStringFlag(args, '--fixture-dir') });
268
+
269
+ if (args.includes('--json')) {
270
+ console.log(JSON.stringify(result));
271
+ } else {
272
+ printText(result);
273
+ }
274
+
275
+ if (!result.passed) process.exitCode = 1;
276
+ }
277
+
278
+ if (require.main === module) {
279
+ main();
280
+ }
281
+
282
+ module.exports = {
283
+ CANONICAL_SKILL,
284
+ HARNESS_TARGETS,
285
+ MATCHING_PROMPT,
286
+ NON_MATCHING_PROMPT,
287
+ SOURCES,
288
+ descriptionMatches,
289
+ materializeFixture,
290
+ parseFrontmatter,
291
+ runParity,
292
+ };
@@ -0,0 +1,62 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ /**
5
+ * Pre-commit auto-sync for the committed `.agents/skills` mirror.
6
+ *
7
+ * `.agents/skills` is Codex's repo-local discovery path and the ONE skill mirror
8
+ * committed to the repo (so a teammate who clones WITHOUT running `forge setup`
9
+ * still gets Forge skills/stages auto-discovered). It must stay byte-identical to
10
+ * the canonical `skills/` source, which the structural drift gate enforces.
11
+ *
12
+ * This hook removes the regen friction: whenever `skills/**` is staged, it
13
+ * regenerates `.agents/skills` from `skills/` (reusing the same
14
+ * `populateCodexRepoSkills` / `populateAgentSkills` sync the drift gate checks
15
+ * against) and re-stages it, so the committed mirror never drifts from canonical.
16
+ *
17
+ * It is intentionally scoped to `skills/**` via lefthook's `glob`, so it only runs
18
+ * when the canonical source actually changes.
19
+ */
20
+
21
+ const path = require('node:path');
22
+ const { execFileSync } = require('node:child_process');
23
+ const { populateCodexRepoSkills, resolveCodexRepoSkillsDir } = require('../lib/codex-skills');
24
+
25
+ function repoRoot() {
26
+ try {
27
+ return execFileSync('git', ['rev-parse', '--show-toplevel'], {
28
+ encoding: 'utf8',
29
+ stdio: ['ignore', 'pipe', 'ignore'],
30
+ }).trim();
31
+ } catch {
32
+ return path.resolve(__dirname, '..');
33
+ }
34
+ }
35
+
36
+ function main() {
37
+ const root = repoRoot();
38
+ let written = [];
39
+ try {
40
+ // clean: true so skills removed from canonical are dropped from the mirror too.
41
+ ({ written } = populateCodexRepoSkills({ sourceRoot: root, projectRoot: root, clean: true }));
42
+ } catch (error) {
43
+ console.error(`sync-agent-skills: failed to regenerate .agents/skills — ${error.message}`);
44
+ process.exit(1);
45
+ }
46
+
47
+ const mirror = resolveCodexRepoSkillsDir(root);
48
+ try {
49
+ // Stage the regenerated mirror (and any deletions within it).
50
+ execFileSync('git', ['add', '--all', '--', mirror], {
51
+ cwd: root,
52
+ stdio: ['ignore', 'ignore', 'inherit'],
53
+ });
54
+ } catch (error) {
55
+ console.error(`sync-agent-skills: failed to stage .agents/skills — ${error.message}`);
56
+ process.exit(1);
57
+ }
58
+
59
+ console.log(`sync-agent-skills: .agents/skills in sync with skills/ (${written.length} skills)`);
60
+ }
61
+
62
+ main();
@@ -13,6 +13,9 @@ fi
13
13
 
14
14
  # Source shared sanitize library
15
15
  _SU_SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
16
+ if [[ -f "$_SU_SCRIPT_DIR/bootstrap-windows-tools.sh" ]]; then
17
+ source "$_SU_SCRIPT_DIR/bootstrap-windows-tools.sh"
18
+ fi
16
19
  source "$_SU_SCRIPT_DIR/lib/sanitize.sh"
17
20
 
18
21
  # ── Session Identity ───────────────────────────────────────────────────
@@ -177,17 +177,23 @@ function getShardPlan(args, { allUnitTests, durationMap }) {
177
177
  };
178
178
  }
179
179
 
180
- function runTests(label, files) {
181
- fs.mkdirSync(reportDir, { recursive: true });
182
- const junitPath = path.join(reportDir, `${label}.xml`);
183
- const bunCommand = process.env.BUN_EXE || 'bun';
184
- const result = spawnSync(bunCommand, [
180
+ function buildBunTestArgs({ junitPath, files }) {
181
+ return [
185
182
  'test',
183
+ '--timeout',
184
+ '15000',
186
185
  '--reporter=junit',
187
186
  '--reporter-outfile',
188
187
  junitPath,
189
188
  ...files,
190
- ], {
189
+ ];
190
+ }
191
+
192
+ function runTests(label, files) {
193
+ fs.mkdirSync(reportDir, { recursive: true });
194
+ const junitPath = path.join(reportDir, `${label}.xml`);
195
+ const bunCommand = process.env.BUN_EXE || 'bun';
196
+ const result = spawnSync(bunCommand, buildBunTestArgs({ junitPath, files }), {
191
197
  cwd: rootDir,
192
198
  stdio: 'inherit',
193
199
  shell: process.platform === 'win32',
@@ -226,6 +232,7 @@ if (require.main === module) {
226
232
  module.exports = {
227
233
  DEFAULT_SMOKE_FILES,
228
234
  PROFILE_MAX_AGE_MS,
235
+ buildBunTestArgs,
229
236
  createDurationMap,
230
237
  ensureFilesExist,
231
238
  getShardPlan,