forge-workflow 0.0.9 → 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 (479) 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 +151 -61
  8. package/CHANGELOG.md +681 -0
  9. package/CLAUDE.md +9 -106
  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 +466 -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/{TOOLCHAIN.md → forge/TOOLCHAIN.md} +56 -47
  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/reference/TOOLCHAIN.md +658 -0
  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 +225 -28
  81. package/lib/beads-sync-scaffold.js +36 -107
  82. package/lib/codex-skills.js +51 -1
  83. package/lib/commands/_issue.js +744 -70
  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 +66 -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 +22 -2
  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 +851 -979
  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 +329 -11
  140. package/lib/commands/sync.js +34 -46
  141. package/lib/commands/team.js +15 -2
  142. package/lib/commands/test.js +58 -7
  143. package/lib/commands/update.js +2 -2
  144. package/lib/commands/upgrade.js +47 -0
  145. package/lib/commands/validate.js +56 -25
  146. package/lib/commands/worktree.js +308 -128
  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 +184 -0
  151. package/lib/deprecated-sync-cleanup.js +362 -0
  152. package/lib/detect-agent.js +2 -28
  153. package/lib/detect-worktree.js +42 -17
  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 +697 -0
  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/issue-sync/authority.js +100 -0
  174. package/lib/issue-sync/github-pull.js +184 -0
  175. package/lib/issue-sync/import-primitives.js +98 -0
  176. package/lib/issue-sync/legacy-link-bridge.js +436 -0
  177. package/lib/issue-sync/link-store.js +292 -0
  178. package/lib/issue-sync/project-github.js +123 -0
  179. package/lib/issue-sync/reconcile.js +195 -0
  180. package/lib/issue-sync/schema.js +126 -0
  181. package/lib/kernel/backing-issue.js +305 -0
  182. package/lib/kernel/broker.js +1218 -0
  183. package/lib/kernel/cli-broker-factory.js +130 -0
  184. package/lib/kernel/conflict-signal.js +82 -0
  185. package/lib/kernel/evaluators.js +195 -0
  186. package/lib/kernel/fs-class.js +495 -0
  187. package/lib/kernel/issue-command-contract.js +559 -0
  188. package/lib/kernel/issue-id-resolver.js +186 -0
  189. package/lib/kernel/lease-enforcer.js +158 -0
  190. package/lib/kernel/migrations.js +333 -0
  191. package/lib/kernel/planning-buckets-schema.js +109 -0
  192. package/lib/kernel/projection-jsonl-writer.js +450 -0
  193. package/lib/kernel/readiness-model.js +329 -0
  194. package/lib/kernel/schema.js +356 -0
  195. package/lib/kernel/sqlite-driver.js +2504 -0
  196. package/lib/kernel/taxonomy-validator.js +394 -0
  197. package/lib/lefthook-check.js +8 -4
  198. package/lib/lefthook-wiring.js +413 -0
  199. package/lib/mcp-config-renderer.js +288 -0
  200. package/lib/memory/graphiti-mcp.js +106 -0
  201. package/lib/memory/router.js +387 -0
  202. package/lib/memory/typed-api.js +102 -0
  203. package/lib/memory-digest.js +195 -0
  204. package/lib/merge-rules.js +395 -0
  205. package/lib/migrate-dry-run.js +466 -0
  206. package/lib/orientation.js +863 -0
  207. package/lib/package-manager-remediation.js +103 -0
  208. package/lib/package-root.js +381 -0
  209. package/lib/patch-intent.js +890 -0
  210. package/lib/plugin-catalog.js +3 -4
  211. package/lib/plugin-manager.js +0 -5
  212. package/lib/pr-bundle.js +186 -0
  213. package/lib/pr-monitor/differ.js +195 -0
  214. package/lib/pr-monitor/events.js +0 -0
  215. package/lib/pr-monitor/gather.js +124 -0
  216. package/lib/pr-monitor/journal.js +299 -0
  217. package/lib/pr-monitor/monitor.js +146 -0
  218. package/lib/pr-monitor/render-sticky.js +157 -0
  219. package/lib/pr-monitor/watch-lifecycle.js +95 -0
  220. package/lib/pr-monitor/watch.js +247 -0
  221. package/lib/pr-pull.js +1273 -0
  222. package/lib/pr-shepherd.js +494 -0
  223. package/lib/pr-state-validator.js +59 -0
  224. package/lib/preflight/gates.js +237 -0
  225. package/lib/preflight/runner.js +116 -0
  226. package/lib/project-discovery.js +0 -53
  227. package/lib/project-memory.js +166 -0
  228. package/lib/protected-path-manifest.js +281 -0
  229. package/lib/protected-state-surfaces.js +387 -0
  230. package/lib/release-readiness.js +2089 -0
  231. package/lib/reset.js +59 -45
  232. package/lib/review-adapter.js +68 -0
  233. package/lib/rules-sync.js +260 -0
  234. package/lib/runtime-health.js +332 -23
  235. package/lib/safety-config-renderer.js +268 -0
  236. package/lib/setup-action-log.js +1 -7
  237. package/lib/setup.js +27 -65
  238. package/lib/shell-utils.js +76 -6
  239. package/lib/skills-sync.js +330 -0
  240. package/lib/smart-status/conflicts.js +205 -0
  241. package/lib/smart-status/scoring.js +191 -0
  242. package/lib/status/beads-snapshot.js +145 -0
  243. package/lib/status/presenter.js +216 -0
  244. package/lib/status/snapshot.js +186 -0
  245. package/lib/sync-backend.js +202 -0
  246. package/lib/untrusted-content.js +52 -0
  247. package/lib/upgrade-safety.js +199 -0
  248. package/lib/workflow/enforce-stage.js +298 -47
  249. package/lib/workflow/stage-transition.js +115 -0
  250. package/lib/workflow/stages.js +30 -6
  251. package/lib/workflow/state-manager.js +159 -14
  252. package/lib/workflow/state.js +23 -1
  253. package/lib/workflow-profiles.js +17 -5
  254. package/package.json +46 -36
  255. package/rules/documentation.md +19 -0
  256. package/rules/kernel-tracking.md +26 -0
  257. package/rules/security.md +22 -0
  258. package/rules/tdd.md +20 -0
  259. package/rules/workflow.md +27 -0
  260. package/scripts/auto-backing-issue.js +47 -0
  261. package/scripts/beads-context.sh +165 -22
  262. package/scripts/beads-migrate-to-dolt.sh +7 -0
  263. package/scripts/beads-upgrade-smoke.sh +284 -0
  264. package/scripts/behavioral-judge.sh +115 -11
  265. package/scripts/benchmark.js +349 -63
  266. package/scripts/bootstrap-windows-tools.sh +78 -0
  267. package/scripts/branch-protection.js +2 -3
  268. package/scripts/check-agents.js +34 -137
  269. package/scripts/commitlint.js +3 -1
  270. package/scripts/conflict-detect.sh +3 -0
  271. package/scripts/dep-guard-analyze.js +52 -17
  272. package/scripts/dep-guard-keyword-ripple.js +29 -0
  273. package/scripts/dep-guard-render-review.js +86 -0
  274. package/scripts/dep-guard.sh +64 -232
  275. package/scripts/file-index.sh +3 -0
  276. package/scripts/forge-team/lib/claim.sh +34 -18
  277. package/scripts/forge-team/lib/dashboard.sh +61 -86
  278. package/scripts/forge-team/lib/epic.sh +99 -263
  279. package/scripts/forge-team/lib/hooks.sh +26 -28
  280. package/scripts/forge-team/lib/identity.sh +4 -4
  281. package/scripts/forge-team/lib/sync-github.sh +144 -47
  282. package/scripts/forge-team/lib/verify.sh +93 -83
  283. package/scripts/forge-team/lib/workload.sh +41 -65
  284. package/scripts/forge-team/tests/claim.test.sh +25 -19
  285. package/scripts/forge-team/tests/dashboard.test.sh +31 -46
  286. package/scripts/forge-team/tests/epic.test.sh +52 -71
  287. package/scripts/forge-team/tests/hooks.test.sh +38 -50
  288. package/scripts/forge-team/tests/identity.test.sh +3 -3
  289. package/scripts/forge-team/tests/integration.test.sh +44 -66
  290. package/scripts/forge-team/tests/sync-github.test.sh +183 -79
  291. package/scripts/forge-team/tests/verify.test.sh +37 -46
  292. package/scripts/forge-team/tests/workflow-integration.test.sh +4 -4
  293. package/scripts/forge-team/tests/workload.test.sh +32 -66
  294. package/scripts/gen-command-manifest.js +153 -0
  295. package/scripts/gen-embedded-assets.mjs +129 -0
  296. package/scripts/install.ps1 +139 -0
  297. package/scripts/install.sh +268 -0
  298. package/scripts/lib/beads-migrate-to-dolt.mjs +503 -0
  299. package/scripts/lib/release-asset.mjs +84 -0
  300. package/scripts/parity-check.mjs +145 -0
  301. package/scripts/parity-check.test.mjs +58 -0
  302. package/scripts/pin-agentic-workflow-images.js +112 -0
  303. package/scripts/pr-coordinator.sh +3 -0
  304. package/scripts/preflight-sonar.eslint.config.mjs +44 -0
  305. package/scripts/preflight.sh +108 -0
  306. package/scripts/protected-state-check.js +104 -0
  307. package/scripts/smart-status-score.js +31 -0
  308. package/scripts/smart-status-sessions.js +51 -0
  309. package/scripts/smart-status.sh +117 -369
  310. package/scripts/spikes/config-race-bench.js +111 -0
  311. package/scripts/spikes/harness-capability-matrix.js +13 -0
  312. package/scripts/spikes/patch-anchor-stability-bench.js +125 -0
  313. package/scripts/spikes/protected-path-manifest.js +20 -0
  314. package/scripts/spikes/skill-auto-invoke-parity.js +292 -0
  315. package/scripts/sync-agent-skills.js +62 -0
  316. package/scripts/sync-agentic-workflow.js +48 -0
  317. package/scripts/sync-utils.sh +3 -0
  318. package/scripts/test-ci-shard.js +251 -0
  319. package/scripts/test-dashboard.js +188 -52
  320. package/scripts/test-full-suite.js +186 -0
  321. package/scripts/test-profile.js +278 -0
  322. package/scripts/test.js +302 -28
  323. package/scripts/validate.js +143 -0
  324. package/scripts/validate.sh +18 -1
  325. package/skills/claim-safety/SKILL.md +102 -0
  326. package/skills/claim-safety/evals/evals.json +46 -0
  327. package/{.github/prompts/dev.prompt.md → skills/dev/SKILL.md} +46 -52
  328. package/skills/dev/evals/evals.json +50 -0
  329. package/skills/hermes-forge/SKILL.md +185 -0
  330. package/skills/hermes-forge/evals/evals.json +46 -0
  331. package/skills/issue-basics/SKILL.md +111 -0
  332. package/skills/issue-basics/evals/evals.json +46 -0
  333. package/skills/kernel/SKILL.md +166 -0
  334. package/skills/kernel/evals/evals.json +50 -0
  335. package/skills/memory/SKILL.md +102 -0
  336. package/skills/parallel-deep-research/SKILL.md +14 -11
  337. package/skills/parallel-deep-research/evals/evals.json +11 -27
  338. package/{.github/prompts/plan.prompt.md → skills/plan/SKILL.md} +134 -159
  339. package/skills/plan/evals/evals.json +42 -0
  340. package/skills/research/SKILL.md +195 -0
  341. package/skills/research/evals/evals.json +42 -0
  342. package/{.github/prompts/review.prompt.md → skills/review/SKILL.md} +98 -62
  343. package/skills/review/evals/evals.json +42 -0
  344. package/skills/rollback/SKILL.md +110 -0
  345. package/skills/rollback/evals/evals.json +46 -0
  346. package/skills/rollback/references/methods.md +204 -0
  347. package/{.cursor/commands/rollback.md → skills/rollback/references/workflow-integration.md} +10 -284
  348. package/skills/shepherd/SKILL.md +66 -0
  349. package/skills/shepherd/evals/evals.json +42 -0
  350. package/skills/ship/SKILL.md +251 -0
  351. package/skills/ship/evals/evals.json +42 -0
  352. package/skills/smith/SKILL.md +142 -0
  353. package/skills/smith/evals/evals.json +46 -0
  354. package/skills/smith/references/autonomy-and-gates.md +94 -0
  355. package/{.github/prompts/sonarcloud.prompt.md → skills/sonarcloud/SKILL.md} +14 -3
  356. package/skills/sonarcloud/evals/evals.json +46 -0
  357. package/skills/sonarcloud-analysis/SKILL.md +18 -13
  358. package/skills/sonarcloud-analysis/evals/evals.json +11 -15
  359. package/skills/status/SKILL.md +102 -0
  360. package/skills/status/evals/evals.json +50 -0
  361. package/skills/triage-ready/SKILL.md +121 -0
  362. package/skills/triage-ready/evals/evals.json +42 -0
  363. package/{.github/prompts/validate.prompt.md → skills/validate/SKILL.md} +52 -29
  364. package/skills/validate/evals/evals.json +42 -0
  365. package/skills/verify/SKILL.md +299 -0
  366. package/skills/verify/evals/evals.json +50 -0
  367. package/.claude/commands/dev.md +0 -345
  368. package/.claude/commands/plan.md +0 -566
  369. package/.claude/commands/premerge.md +0 -186
  370. package/.claude/commands/research.md +0 -42
  371. package/.claude/commands/review.md +0 -451
  372. package/.claude/commands/rollback.md +0 -721
  373. package/.claude/commands/ship.md +0 -213
  374. package/.claude/commands/sonarcloud.md +0 -152
  375. package/.claude/commands/status.md +0 -90
  376. package/.claude/commands/validate.md +0 -288
  377. package/.claude/commands/verify.md +0 -269
  378. package/.claude/rules/workflow.md +0 -121
  379. package/.cline/workflows/dev.md +0 -342
  380. package/.cline/workflows/plan.md +0 -563
  381. package/.cline/workflows/premerge.md +0 -183
  382. package/.cline/workflows/research.md +0 -39
  383. package/.cline/workflows/review.md +0 -448
  384. package/.cline/workflows/rollback.md +0 -718
  385. package/.cline/workflows/ship.md +0 -210
  386. package/.cline/workflows/sonarcloud.md +0 -146
  387. package/.cline/workflows/status.md +0 -87
  388. package/.cline/workflows/validate.md +0 -285
  389. package/.cline/workflows/verify.md +0 -266
  390. package/.codex/config.toml +0 -11
  391. package/.codex/skills/dev/SKILL.md +0 -345
  392. package/.codex/skills/plan/SKILL.md +0 -566
  393. package/.codex/skills/premerge/SKILL.md +0 -186
  394. package/.codex/skills/research/SKILL.md +0 -42
  395. package/.codex/skills/review/SKILL.md +0 -451
  396. package/.codex/skills/rollback/SKILL.md +0 -721
  397. package/.codex/skills/ship/SKILL.md +0 -213
  398. package/.codex/skills/sonarcloud/SKILL.md +0 -149
  399. package/.codex/skills/status/SKILL.md +0 -90
  400. package/.codex/skills/validate/SKILL.md +0 -288
  401. package/.codex/skills/verify/SKILL.md +0 -269
  402. package/.cursor/commands/dev.md +0 -342
  403. package/.cursor/commands/plan.md +0 -563
  404. package/.cursor/commands/premerge.md +0 -183
  405. package/.cursor/commands/research.md +0 -39
  406. package/.cursor/commands/review.md +0 -448
  407. package/.cursor/commands/ship.md +0 -210
  408. package/.cursor/commands/sonarcloud.md +0 -146
  409. package/.cursor/commands/status.md +0 -87
  410. package/.cursor/commands/validate.md +0 -285
  411. package/.cursor/commands/verify.md +0 -266
  412. package/.cursorrules +0 -149
  413. package/.github/prompts/premerge.prompt.md +0 -188
  414. package/.github/prompts/research.prompt.md +0 -44
  415. package/.github/prompts/rollback.prompt.md +0 -723
  416. package/.github/prompts/ship.prompt.md +0 -215
  417. package/.github/prompts/status.prompt.md +0 -92
  418. package/.github/prompts/verify.prompt.md +0 -271
  419. package/.github/workflows/beads-to-github.yml +0 -56
  420. package/.github/workflows/github-to-beads.yml +0 -97
  421. package/.kilocode/workflows/dev.md +0 -346
  422. package/.kilocode/workflows/plan.md +0 -567
  423. package/.kilocode/workflows/premerge.md +0 -187
  424. package/.kilocode/workflows/research.md +0 -43
  425. package/.kilocode/workflows/review.md +0 -452
  426. package/.kilocode/workflows/rollback.md +0 -722
  427. package/.kilocode/workflows/ship.md +0 -214
  428. package/.kilocode/workflows/sonarcloud.md +0 -150
  429. package/.kilocode/workflows/status.md +0 -91
  430. package/.kilocode/workflows/validate.md +0 -289
  431. package/.kilocode/workflows/verify.md +0 -270
  432. package/.opencode/commands/dev.md +0 -345
  433. package/.opencode/commands/plan.md +0 -566
  434. package/.opencode/commands/premerge.md +0 -186
  435. package/.opencode/commands/research.md +0 -42
  436. package/.opencode/commands/review.md +0 -451
  437. package/.opencode/commands/rollback.md +0 -721
  438. package/.opencode/commands/ship.md +0 -213
  439. package/.opencode/commands/sonarcloud.md +0 -149
  440. package/.opencode/commands/status.md +0 -90
  441. package/.opencode/commands/validate.md +0 -288
  442. package/.opencode/commands/verify.md +0 -269
  443. package/.roo/commands/dev.md +0 -346
  444. package/.roo/commands/plan.md +0 -567
  445. package/.roo/commands/premerge.md +0 -187
  446. package/.roo/commands/research.md +0 -43
  447. package/.roo/commands/review.md +0 -452
  448. package/.roo/commands/rollback.md +0 -722
  449. package/.roo/commands/ship.md +0 -214
  450. package/.roo/commands/sonarcloud.md +0 -150
  451. package/.roo/commands/status.md +0 -91
  452. package/.roo/commands/validate.md +0 -289
  453. package/.roo/commands/verify.md +0 -270
  454. package/docs/BEADS_GITHUB_SYNC.md +0 -255
  455. package/docs/GREPTILE_SETUP.md +0 -400
  456. package/docs/MANUAL_REVIEW_GUIDE.md +0 -106
  457. package/docs/SETUP.md +0 -663
  458. package/docs/VALIDATION.md +0 -363
  459. package/lib/agents/cline.plugin.json +0 -29
  460. package/lib/agents/copilot.plugin.json +0 -24
  461. package/lib/agents/kilocode.plugin.json +0 -22
  462. package/lib/agents/opencode.plugin.json +0 -23
  463. package/lib/agents/roo.plugin.json +0 -30
  464. package/lib/beads-health-check.js +0 -143
  465. package/lib/commands/commands-reset.js +0 -147
  466. package/opencode.json +0 -67
  467. package/scripts/beads-context.test.js +0 -567
  468. package/scripts/github-beads-sync/comment.mjs +0 -64
  469. package/scripts/github-beads-sync/config.mjs +0 -148
  470. package/scripts/github-beads-sync/github-api.mjs +0 -131
  471. package/scripts/github-beads-sync/index.mjs +0 -332
  472. package/scripts/github-beads-sync/label-mapper.mjs +0 -54
  473. package/scripts/github-beads-sync/mapping.mjs +0 -78
  474. package/scripts/github-beads-sync/reverse-sync-cli.mjs +0 -31
  475. package/scripts/github-beads-sync/reverse-sync.mjs +0 -138
  476. package/scripts/github-beads-sync/run-bd.mjs +0 -161
  477. package/scripts/github-beads-sync/sanitize.mjs +0 -121
  478. package/scripts/github-beads-sync.config.json +0 -26
  479. package/scripts/sync-commands.js +0 -600
@@ -0,0 +1,503 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { execFileSync } from 'node:child_process';
4
+ import fs from 'node:fs';
5
+ import path from 'node:path';
6
+ import process from 'node:process';
7
+ import { pathToFileURL } from 'node:url';
8
+
9
+ const BACKUP_FILES = [
10
+ 'issues.jsonl',
11
+ 'labels.jsonl',
12
+ 'dependencies.jsonl',
13
+ 'comments.jsonl',
14
+ 'events.jsonl',
15
+ 'config.jsonl',
16
+ ];
17
+
18
+ function sanitizePrefix(value) {
19
+ return value
20
+ .trim()
21
+ .toLowerCase()
22
+ .replaceAll(/[^a-z0-9-]/g, '-')
23
+ .replaceAll(/-{2,}/g, '-')
24
+ .replace(/^-/, '')
25
+ .replace(/-$/, '');
26
+ }
27
+
28
+ function readJsonl(filePath) {
29
+ return fs
30
+ .readFileSync(filePath, 'utf8')
31
+ .split(/\r?\n/)
32
+ .filter(Boolean)
33
+ .map((line) => JSON.parse(line));
34
+ }
35
+
36
+ function ensureBackupShape(legacyBackupDir) {
37
+ if (!fs.existsSync(legacyBackupDir) || !fs.statSync(legacyBackupDir).isDirectory()) {
38
+ throw new Error(`Legacy backup directory not found: ${legacyBackupDir}`);
39
+ }
40
+
41
+ for (const file of BACKUP_FILES) {
42
+ const filePath = path.join(legacyBackupDir, file);
43
+ if (!fs.existsSync(filePath)) {
44
+ throw new Error(`Missing backup file: ${filePath}`);
45
+ }
46
+ }
47
+ }
48
+
49
+ function loadBackupData(backupDir) {
50
+ ensureBackupShape(backupDir);
51
+ return {
52
+ issues: readJsonl(path.join(backupDir, 'issues.jsonl')),
53
+ labels: readJsonl(path.join(backupDir, 'labels.jsonl')),
54
+ dependencies: readJsonl(path.join(backupDir, 'dependencies.jsonl')),
55
+ comments: readJsonl(path.join(backupDir, 'comments.jsonl')),
56
+ events: readJsonl(path.join(backupDir, 'events.jsonl')),
57
+ config: readJsonl(path.join(backupDir, 'config.jsonl')),
58
+ };
59
+ }
60
+
61
+ function setDifference(left, right) {
62
+ const rightSet = new Set(right);
63
+ return left.filter((item) => !rightSet.has(item));
64
+ }
65
+
66
+ function normalizeRecord(value) {
67
+ if (Array.isArray(value)) {
68
+ return value.map((entry) => normalizeRecord(entry));
69
+ }
70
+ if (value && typeof value === 'object') {
71
+ return Object.fromEntries(
72
+ Object.keys(value)
73
+ .sort()
74
+ .map((key) => [key, normalizeRecord(value[key])]),
75
+ );
76
+ }
77
+ return value;
78
+ }
79
+
80
+ function stableSerializeRecord(record) {
81
+ return JSON.stringify(normalizeRecord(record));
82
+ }
83
+
84
+ function arraysEqual(left, right) {
85
+ return JSON.stringify(left) === JSON.stringify(right);
86
+ }
87
+
88
+ function collectParity(data) {
89
+ return {
90
+ counts: {
91
+ issues: data.issues.length,
92
+ labels: data.labels.length,
93
+ dependencies: data.dependencies.length,
94
+ comments: data.comments.length,
95
+ events: data.events.length,
96
+ config: data.config.length,
97
+ },
98
+ issueIds: data.issues.map((issue) => issue.id).sort(),
99
+ dependencyEdges: data.dependencies
100
+ .map((dep) => `${dep.issue_id} ${dep.type} ${dep.depends_on_id}`)
101
+ .sort(),
102
+ commentIds: data.comments.map((comment) => comment.id).sort(),
103
+ configKeys: data.config.map((entry) => entry.key).sort(),
104
+ issueRecords: data.issues.map((issue) => stableSerializeRecord(issue)).sort(),
105
+ labelRecords: data.labels.map((label) => stableSerializeRecord(label)).sort(),
106
+ dependencyRecords: data.dependencies
107
+ .map((dependency) => stableSerializeRecord(dependency))
108
+ .sort(),
109
+ commentRecords: data.comments.map((comment) => stableSerializeRecord(comment)).sort(),
110
+ eventRecords: data.events.map((event) => stableSerializeRecord(event)).sort(),
111
+ configRecords: data.config.map((entry) => stableSerializeRecord(entry)).sort(),
112
+ };
113
+ }
114
+
115
+ function summarizeParityMismatch(parity) {
116
+ const parts = [];
117
+ if (parity.missingIssueIds.length > 0 || parity.extraIssueIds.length > 0) {
118
+ parts.push('issue ids differ');
119
+ }
120
+ if (
121
+ parity.missingDependencyEdges.length > 0 ||
122
+ parity.extraDependencyEdges.length > 0
123
+ ) {
124
+ parts.push('dependency edges differ');
125
+ }
126
+ if (parity.missingCommentIds.length > 0 || parity.extraCommentIds.length > 0) {
127
+ parts.push('comment ids differ');
128
+ }
129
+ if (parity.missingConfigKeys.length > 0 || parity.extraConfigKeys.length > 0) {
130
+ parts.push('config keys differ');
131
+ }
132
+ const recordMismatchMessages = {
133
+ issues: 'issue records differ',
134
+ labels: 'label records differ',
135
+ dependencies: 'dependency records differ',
136
+ comments: 'comment records differ',
137
+ events: 'event records differ',
138
+ config: 'config records differ',
139
+ };
140
+ for (const kind of parity.recordMismatches || []) {
141
+ const message = recordMismatchMessages[kind];
142
+ if (message && !parts.includes(message)) {
143
+ parts.push(message);
144
+ }
145
+ }
146
+ if (parts.length === 0) {
147
+ parts.push('record counts differ');
148
+ }
149
+ return parts.join('; ');
150
+ }
151
+
152
+ export async function verifyMigrationParity({ legacyBackupDir, exportDir }) {
153
+ const source = collectParity(loadBackupData(legacyBackupDir));
154
+ const exported = collectParity(loadBackupData(exportDir));
155
+ const recordMismatches = Object.entries({
156
+ issues: arraysEqual(source.issueRecords, exported.issueRecords),
157
+ labels: arraysEqual(source.labelRecords, exported.labelRecords),
158
+ dependencies: arraysEqual(source.dependencyRecords, exported.dependencyRecords),
159
+ comments: arraysEqual(source.commentRecords, exported.commentRecords),
160
+ events: arraysEqual(source.eventRecords, exported.eventRecords),
161
+ config: arraysEqual(source.configRecords, exported.configRecords),
162
+ })
163
+ .filter(([, match]) => !match)
164
+ .map(([kind]) => kind);
165
+
166
+ const parity = {
167
+ ok:
168
+ arraysEqual(source.counts, exported.counts) &&
169
+ arraysEqual(source.issueIds, exported.issueIds) &&
170
+ arraysEqual(source.dependencyEdges, exported.dependencyEdges) &&
171
+ arraysEqual(source.commentIds, exported.commentIds) &&
172
+ arraysEqual(source.configKeys, exported.configKeys) &&
173
+ recordMismatches.length === 0,
174
+ counts: source.counts,
175
+ issueIds: source.issueIds,
176
+ dependencyEdges: source.dependencyEdges,
177
+ commentIds: source.commentIds,
178
+ configKeys: source.configKeys,
179
+ recordMismatches,
180
+ missingIssueIds: setDifference(source.issueIds, exported.issueIds),
181
+ extraIssueIds: setDifference(exported.issueIds, source.issueIds),
182
+ missingDependencyEdges: setDifference(
183
+ source.dependencyEdges,
184
+ exported.dependencyEdges,
185
+ ),
186
+ extraDependencyEdges: setDifference(
187
+ exported.dependencyEdges,
188
+ source.dependencyEdges,
189
+ ),
190
+ missingCommentIds: setDifference(source.commentIds, exported.commentIds),
191
+ extraCommentIds: setDifference(exported.commentIds, source.commentIds),
192
+ missingConfigKeys: setDifference(source.configKeys, exported.configKeys),
193
+ extraConfigKeys: setDifference(exported.configKeys, source.configKeys),
194
+ };
195
+
196
+ return parity;
197
+ }
198
+
199
+ function snapshotCurrentBeads(projectRoot, snapshotRoot, now = new Date()) {
200
+ const liveBeadsDir = path.join(projectRoot, '.beads');
201
+ if (!fs.existsSync(liveBeadsDir)) {
202
+ throw new Error(`Beads directory not found: ${liveBeadsDir}`);
203
+ }
204
+
205
+ const timestamp = now.toISOString().replaceAll(':', '-');
206
+ const snapshotDir = path.join(snapshotRoot, timestamp);
207
+ const snapshotBeadsDir = path.join(snapshotDir, 'current-beads');
208
+ fs.mkdirSync(snapshotDir, { recursive: true });
209
+ fs.cpSync(liveBeadsDir, snapshotBeadsDir, { recursive: true });
210
+ return snapshotDir;
211
+ }
212
+
213
+ function materializeLegacyBackupDir({ legacyBackupDir, snapshotDir }) {
214
+ const snapshotBeadsDir = path.join(snapshotDir, 'current-beads');
215
+ const synthesizedBackupDir = path.join(snapshotDir, 'legacy-backup');
216
+ fs.mkdirSync(synthesizedBackupDir, { recursive: true });
217
+
218
+ for (const file of BACKUP_FILES) {
219
+ const backupCandidate = path.join(legacyBackupDir, file);
220
+ const liveCandidate = path.join(snapshotBeadsDir, file);
221
+ const sourcePath = fs.existsSync(liveCandidate) ? liveCandidate : backupCandidate;
222
+ if (!fs.existsSync(sourcePath)) {
223
+ throw new Error(`Missing legacy backup file: ${file}`);
224
+ }
225
+ fs.copyFileSync(sourcePath, path.join(synthesizedBackupDir, file));
226
+ }
227
+
228
+ return synthesizedBackupDir;
229
+ }
230
+
231
+ function applyMigratedBeadsState({ projectRoot, migratedDir }) {
232
+ const liveBeadsDir = path.join(projectRoot, '.beads');
233
+ const migratedBeadsDir = path.join(migratedDir, '.beads');
234
+ const stagedBeadsDir = path.join(projectRoot, `.beads.next-${Date.now()}`);
235
+
236
+ if (!fs.existsSync(migratedBeadsDir) || !fs.statSync(migratedBeadsDir).isDirectory()) {
237
+ throw new Error(`Migrated Beads directory not found: ${migratedBeadsDir}`);
238
+ }
239
+
240
+ fs.rmSync(stagedBeadsDir, { recursive: true, force: true });
241
+ fs.cpSync(migratedBeadsDir, stagedBeadsDir, { recursive: true });
242
+ fs.rmSync(liveBeadsDir, { recursive: true, force: true });
243
+ fs.renameSync(stagedBeadsDir, liveBeadsDir);
244
+
245
+ return {
246
+ liveBeadsDir,
247
+ migratedBeadsDir,
248
+ };
249
+ }
250
+
251
+ function defaultCliPaths(projectRoot) {
252
+ return {
253
+ legacyBackupDir: path.join(projectRoot, '.beads', 'backup'),
254
+ snapshotRoot: path.join(projectRoot, '.beads-migration-snapshots'),
255
+ migratedDir: path.join(projectRoot, '.beads-migrated'),
256
+ exportDir: path.join(projectRoot, '.beads-migrated-export'),
257
+ };
258
+ }
259
+
260
+ export async function rollbackLegacyBeadsMigration({ projectRoot, snapshotDir }) {
261
+ const liveBeadsDir = path.join(projectRoot, '.beads');
262
+ const snapshotBeadsDir = path.join(snapshotDir, 'current-beads');
263
+
264
+ if (!fs.existsSync(snapshotBeadsDir)) {
265
+ throw new Error(`Snapshot payload not found: ${snapshotBeadsDir}`);
266
+ }
267
+
268
+ fs.rmSync(liveBeadsDir, { recursive: true, force: true });
269
+ fs.cpSync(snapshotBeadsDir, liveBeadsDir, { recursive: true });
270
+
271
+ return {
272
+ restored: true,
273
+ snapshotDir,
274
+ liveBeadsDir,
275
+ };
276
+ }
277
+
278
+ function resolveBdCommand() {
279
+ return process.env.BD_CMD || 'bd';
280
+ }
281
+
282
+ function inferPrefix(projectRoot) {
283
+ const configPath = path.join(projectRoot, '.beads', 'config.yaml');
284
+ if (fs.existsSync(configPath)) {
285
+ const match = /^issue-prefix:\s*(.+)$/m.exec(fs.readFileSync(configPath, 'utf8'));
286
+ if (match?.[1]) {
287
+ return sanitizePrefix(match[1]);
288
+ }
289
+ }
290
+ return sanitizePrefix(path.basename(projectRoot) || 'beads');
291
+ }
292
+
293
+ export function defaultImportBackup({
294
+ projectRoot,
295
+ sourceDir,
296
+ migratedDir,
297
+ exportDir,
298
+ }) {
299
+ const bd = resolveBdCommand();
300
+ fs.mkdirSync(migratedDir, { recursive: true });
301
+ fs.rmSync(exportDir, { recursive: true, force: true });
302
+
303
+ const prefix = inferPrefix(projectRoot);
304
+ const execOpts = {
305
+ cwd: migratedDir,
306
+ encoding: 'utf8',
307
+ env: {
308
+ ...process.env,
309
+ BEADS_DIR: path.join(migratedDir, '.beads'),
310
+ },
311
+ };
312
+
313
+ execFileSync(
314
+ bd,
315
+ ['init', '--force', '--prefix', prefix, '--skip-hooks', '--skip-agents'],
316
+ execOpts,
317
+ );
318
+ execFileSync(bd, ['backup', 'restore', sourceDir], execOpts);
319
+ execFileSync(bd, ['backup', '--force'], execOpts);
320
+
321
+ const exportedBackupDir = path.join(migratedDir, '.beads', 'backup');
322
+ ensureBackupShape(exportedBackupDir);
323
+ fs.cpSync(exportedBackupDir, exportDir, { recursive: true });
324
+
325
+ return {
326
+ strategy: 'bd-backup-restore',
327
+ prefix,
328
+ };
329
+ }
330
+
331
+ function writeManifest(manifestPath, payload) {
332
+ fs.mkdirSync(path.dirname(manifestPath), { recursive: true });
333
+ fs.writeFileSync(manifestPath, `${JSON.stringify(payload, null, 2)}\n`, 'utf8');
334
+ }
335
+
336
+ export async function runLegacyBeadsMigration(options) {
337
+ const {
338
+ projectRoot,
339
+ legacyBackupDir,
340
+ snapshotRoot,
341
+ migratedDir,
342
+ exportDir,
343
+ importBackup = defaultImportBackup,
344
+ now = new Date(),
345
+ } = options;
346
+
347
+ if (!projectRoot || !legacyBackupDir || !snapshotRoot || !migratedDir || !exportDir) {
348
+ throw new Error('projectRoot, legacyBackupDir, snapshotRoot, migratedDir, and exportDir are required');
349
+ }
350
+
351
+ const manifestPath = path.join(migratedDir, 'migration-manifest.json');
352
+ if (fs.existsSync(manifestPath)) {
353
+ return {
354
+ status: 'skipped',
355
+ reason: 'already migrated',
356
+ migratedDir,
357
+ };
358
+ }
359
+
360
+ const snapshotDir = snapshotCurrentBeads(projectRoot, snapshotRoot, now);
361
+ const resolvedLegacyBackupDir = materializeLegacyBackupDir({
362
+ legacyBackupDir,
363
+ snapshotDir,
364
+ });
365
+ let rolledBack = false;
366
+
367
+ try {
368
+ const importResult = await importBackup({
369
+ projectRoot,
370
+ sourceDir: resolvedLegacyBackupDir,
371
+ migratedDir,
372
+ exportDir,
373
+ snapshotDir,
374
+ });
375
+
376
+ const parity = await verifyMigrationParity({
377
+ legacyBackupDir: resolvedLegacyBackupDir,
378
+ exportDir,
379
+ });
380
+
381
+ if (!parity.ok) {
382
+ await rollbackLegacyBeadsMigration({ projectRoot, snapshotDir });
383
+ rolledBack = true;
384
+
385
+ const error = new Error(
386
+ `Parity verification failed: ${summarizeParityMismatch(parity)}`,
387
+ );
388
+ error.parity = parity;
389
+ throw error;
390
+ }
391
+
392
+ const appliedState = applyMigratedBeadsState({
393
+ projectRoot,
394
+ migratedDir,
395
+ });
396
+
397
+ writeManifest(manifestPath, {
398
+ status: 'migrated',
399
+ createdAt: now.toISOString(),
400
+ snapshotDir,
401
+ legacyBackupDir: resolvedLegacyBackupDir,
402
+ parity,
403
+ appliedState,
404
+ importResult: importResult || null,
405
+ });
406
+
407
+ return {
408
+ status: 'migrated',
409
+ snapshotDir,
410
+ migratedDir,
411
+ exportDir,
412
+ legacyBackupDir: resolvedLegacyBackupDir,
413
+ appliedState,
414
+ parity,
415
+ importResult: importResult || null,
416
+ };
417
+ } catch (error) {
418
+ if (!rolledBack) {
419
+ await rollbackLegacyBeadsMigration({ projectRoot, snapshotDir });
420
+ }
421
+ throw error;
422
+ }
423
+ }
424
+
425
+ export function parseCliArgs(argv, cwd = process.cwd()) {
426
+ const options = {
427
+ projectRoot: cwd,
428
+ ...defaultCliPaths(cwd),
429
+ };
430
+ const explicitPathFlags = new Set();
431
+
432
+ for (let i = 0; i < argv.length; i += 1) {
433
+ const arg = argv[i];
434
+ switch (arg) {
435
+ case '--project-root':
436
+ options.projectRoot = path.resolve(argv[++i]);
437
+ for (const [key, value] of Object.entries(defaultCliPaths(options.projectRoot))) {
438
+ if (!explicitPathFlags.has(key)) {
439
+ options[key] = value;
440
+ }
441
+ }
442
+ break;
443
+ case '--legacy-backup-dir':
444
+ options.legacyBackupDir = path.resolve(argv[++i]);
445
+ explicitPathFlags.add('legacyBackupDir');
446
+ break;
447
+ case '--snapshot-root':
448
+ options.snapshotRoot = path.resolve(argv[++i]);
449
+ explicitPathFlags.add('snapshotRoot');
450
+ break;
451
+ case '--migrated-dir':
452
+ options.migratedDir = path.resolve(argv[++i]);
453
+ explicitPathFlags.add('migratedDir');
454
+ break;
455
+ case '--export-dir':
456
+ options.exportDir = path.resolve(argv[++i]);
457
+ explicitPathFlags.add('exportDir');
458
+ break;
459
+ case '-h':
460
+ case '--help':
461
+ options.help = true;
462
+ break;
463
+ default:
464
+ throw new Error(`Unknown argument: ${arg}`);
465
+ }
466
+ }
467
+
468
+ return options;
469
+ }
470
+
471
+ function printUsage() {
472
+ console.log(`Usage: beads-migrate-to-dolt [options]
473
+
474
+ Options:
475
+ --project-root <path> Project root containing .beads/
476
+ --legacy-backup-dir <path> Legacy JSONL backup directory
477
+ --snapshot-root <path> Where rollback snapshots are stored
478
+ --migrated-dir <path> Working directory for migrated Beads state
479
+ --export-dir <path> Export directory used for parity verification
480
+ -h, --help Show this help message
481
+ `);
482
+ }
483
+
484
+ async function main() {
485
+ const options = parseCliArgs(process.argv.slice(2));
486
+ if (options.help) {
487
+ printUsage();
488
+ return;
489
+ }
490
+
491
+ const result = await runLegacyBeadsMigration(options);
492
+ console.log(JSON.stringify(result, null, 2));
493
+ }
494
+
495
+ if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
496
+ main().catch((error) => {
497
+ console.error(error.message);
498
+ if (error.parity) {
499
+ console.error(JSON.stringify(error.parity, null, 2));
500
+ }
501
+ process.exitCode = 1;
502
+ });
503
+ }
@@ -0,0 +1,84 @@
1
+ // Canonical GitHub Release asset-name mapping for the single-binary distribution
2
+ // (epic 6f11d483, Step 4 / issue 50afbc47). This is the SINGLE SOURCE OF TRUTH
3
+ // for how a detected platform (os / arch / libc) maps to the release asset that
4
+ // `scripts/install.sh` and `scripts/install.ps1` download.
5
+ //
6
+ // The CI workflow `.github/workflows/build-binary.yml` compiles seven canonical
7
+ // bun targets and publishes each to the GitHub Release under the names produced
8
+ // here. The install scripts re-derive the same name from the host platform, so
9
+ // this table is exercised by `scripts/release-asset.test.js` (which also
10
+ // cross-checks the shell script's own detection against it) to guarantee the two
11
+ // sides never drift.
12
+ //
13
+ // bun target -> release asset
14
+ // bun-windows-x64 -> forge-windows-x64.exe
15
+ // bun-darwin-arm64 -> forge-darwin-arm64
16
+ // bun-darwin-x64 -> forge-darwin-x64
17
+ // bun-linux-x64 -> forge-linux-x64
18
+ // bun-linux-arm64 -> forge-linux-arm64
19
+ // bun-linux-x64-musl -> forge-linux-x64-musl
20
+ // bun-linux-arm64-musl -> forge-linux-arm64-musl
21
+
22
+ /** Operating systems we publish binaries for. */
23
+ export const SUPPORTED_OS = ['windows', 'darwin', 'linux'];
24
+ /** CPU architectures we publish binaries for. */
25
+ export const SUPPORTED_ARCH = ['x64', 'arm64'];
26
+
27
+ /**
28
+ * Map a detected platform to its GitHub Release asset filename.
29
+ *
30
+ * @param {object} p
31
+ * @param {string} p.os - 'windows' | 'darwin' | 'linux'
32
+ * @param {string} p.arch - 'x64' | 'arm64'
33
+ * @param {string} [p.libc] - 'glibc' | 'musl' (linux only; ignored elsewhere)
34
+ * @returns {string} asset filename, e.g. 'forge-linux-x64-musl' or 'forge-windows-x64.exe'
35
+ * @throws {Error} on an unsupported os/arch combination
36
+ */
37
+ export function releaseAssetName({ os, arch, libc } = {}) {
38
+ if (!SUPPORTED_OS.includes(os)) {
39
+ throw new Error(`Unsupported OS: ${os} (supported: ${SUPPORTED_OS.join(', ')})`);
40
+ }
41
+ if (!SUPPORTED_ARCH.includes(arch)) {
42
+ throw new Error(`Unsupported arch: ${arch} (supported: ${SUPPORTED_ARCH.join(', ')})`);
43
+ }
44
+ // Reject os/arch pairs that are not actually published. The independent
45
+ // allowlists above would otherwise accept e.g. windows/arm64 and invent a
46
+ // `forge-windows-arm64.exe` asset that no release contains. Validate the
47
+ // tuple against the canonical matrix (windows is x64-only) so JS, install.sh
48
+ // and install.ps1 all agree on the same supported set.
49
+ if (!PUBLISHED_OS_ARCH.has(`${os}/${arch}`)) {
50
+ throw new Error(
51
+ `Unsupported platform: ${os}/${arch} is not a published target ` +
52
+ `(supported: ${[...PUBLISHED_OS_ARCH].join(', ')})`,
53
+ );
54
+ }
55
+ let name = `forge-${os}-${arch}`;
56
+ if (os === 'linux' && libc === 'musl') {
57
+ name += '-musl';
58
+ }
59
+ if (os === 'windows') {
60
+ name += '.exe';
61
+ }
62
+ return name;
63
+ }
64
+
65
+ /**
66
+ * The full set of seven canonical assets, in the same order as the CI matrix.
67
+ * Exported for tests and for anyone enumerating the published release.
68
+ */
69
+ export const CANONICAL_ASSETS = [
70
+ { os: 'windows', arch: 'x64', libc: undefined, asset: 'forge-windows-x64.exe' },
71
+ { os: 'darwin', arch: 'arm64', libc: undefined, asset: 'forge-darwin-arm64' },
72
+ { os: 'darwin', arch: 'x64', libc: undefined, asset: 'forge-darwin-x64' },
73
+ { os: 'linux', arch: 'x64', libc: 'glibc', asset: 'forge-linux-x64' },
74
+ { os: 'linux', arch: 'arm64', libc: 'glibc', asset: 'forge-linux-arm64' },
75
+ { os: 'linux', arch: 'x64', libc: 'musl', asset: 'forge-linux-x64-musl' },
76
+ { os: 'linux', arch: 'arm64', libc: 'musl', asset: 'forge-linux-arm64-musl' },
77
+ ];
78
+
79
+ /**
80
+ * The set of published `os/arch` tuples, derived from CANONICAL_ASSETS so it can
81
+ * never drift from the actual release matrix. Used by releaseAssetName() to
82
+ * reject unsupported combinations (e.g. windows/arm64).
83
+ */
84
+ export const PUBLISHED_OS_ARCH = new Set(CANONICAL_ASSETS.map((a) => `${a.os}/${a.arch}`));