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,523 @@
1
+ 'use strict';
2
+
3
+ const fs = require('node:fs');
4
+ const os = require('node:os');
5
+ const path = require('node:path');
6
+ const { execFileSync } = require('node:child_process');
7
+
8
+ const {
9
+ buildMigrationDryRunReport,
10
+ renderMigrationDryRunReport,
11
+ } = require('../migrate-dry-run');
12
+ const {
13
+ loadBeadsSnapshotFromDirectory,
14
+ importBeadsSnapshot,
15
+ } = require('../adapters/beads-kernel-compat');
16
+ const { buildMigratedKernelIssueDeps } = require('../kernel/cli-broker-factory');
17
+
18
+ function hasArg(args, name) {
19
+ return Array.isArray(args) && args.includes(name);
20
+ }
21
+
22
+ /**
23
+ * Parse `forge migrate` options from positional args (with a parsed flags object
24
+ * as a fallback). Supported: --from <source>, --source <dir>, --dry-run, --json.
25
+ * Unknown tokens are ignored so the legacy v2→v3 PoC flags pass through untouched.
26
+ */
27
+ function parseMigrateOptions(args = [], flags = {}) {
28
+ const options = {
29
+ from: flags.from,
30
+ source: flags.source,
31
+ dryRun: Boolean(flags.dryRun || flags['dry-run']),
32
+ json: Boolean(flags.json),
33
+ errors: [],
34
+ };
35
+
36
+ const takeValue = (arg, prefix, current, index) => {
37
+ if (arg.startsWith(`${prefix}=`)) {
38
+ const value = arg.slice(prefix.length + 1);
39
+ if (!value) options.errors.push(`${prefix} requires a value`);
40
+ return { value: value || current, next: index };
41
+ }
42
+ const candidate = args[index + 1];
43
+ if (candidate && !candidate.startsWith('--')) {
44
+ return { value: candidate, next: index + 1 };
45
+ }
46
+ options.errors.push(`${prefix} requires a value`);
47
+ return { value: current, next: index };
48
+ };
49
+
50
+ let i = 0;
51
+ while (i < args.length) {
52
+ const arg = args[i];
53
+ if (arg === '--dry-run') options.dryRun = true;
54
+ else if (arg === '--json') options.json = true;
55
+ else if (arg === '--from' || arg.startsWith('--from=')) {
56
+ const parsed = takeValue(arg, '--from', options.from, i);
57
+ options.from = parsed.value;
58
+ i = parsed.next;
59
+ } else if (arg === '--source' || arg.startsWith('--source=')) {
60
+ const parsed = takeValue(arg, '--source', options.source, i);
61
+ options.source = parsed.value;
62
+ i = parsed.next;
63
+ }
64
+ i += 1;
65
+ }
66
+
67
+ return options;
68
+ }
69
+
70
+ function directoryHasJsonl(dir, fsImpl) {
71
+ try {
72
+ return fsImpl.readdirSync(dir).some(entry => entry.endsWith('.jsonl'));
73
+ } catch (_err) {
74
+ /* intentional: unreadable directory has no usable jsonl */ // NOSONAR S2486
75
+ return false;
76
+ }
77
+ }
78
+
79
+ /**
80
+ * Export a Dolt-only Beads store to JSONL in a temp dir via `bd export --all`,
81
+ * then return that dir for the loader. Defensive: a missing `bd` on PATH yields a
82
+ * clear, actionable error instead of a stack trace.
83
+ *
84
+ * NOTE (flagged ambiguity): the exact on-disk shape `bd export --all` emits is not
85
+ * pinned in this repo. We capture stdout into `<temp>/issues.jsonl`, which the
86
+ * loader reads. Operators with a different layout should prefer `--source <dir>`.
87
+ */
88
+ function exportDoltStoreToJsonl(beadsDir, projectRoot, deps) {
89
+ const exec = deps.execFileSync || execFileSync;
90
+ const fsImpl = deps.fs || fs;
91
+ const tempDir = fsImpl.mkdtempSync(path.join(os.tmpdir(), 'forge-migrate-bd-'));
92
+ try {
93
+ const stdout = exec('bd', ['export', '--all'], {
94
+ cwd: projectRoot || process.cwd(),
95
+ encoding: 'utf8',
96
+ });
97
+ fsImpl.writeFileSync(path.join(tempDir, 'issues.jsonl'), stdout || '');
98
+ return { dir: tempDir, kind: 'dolt-export', temp: tempDir };
99
+ } catch (err) {
100
+ fsImpl.rmSync(tempDir, { recursive: true, force: true });
101
+ const message = err && err.message ? err.message : String(err);
102
+ if (/ENOENT|not found|not recognized|no such file/i.test(message)) {
103
+ return {
104
+ error:
105
+ "Beads CLI 'bd' is not on PATH — cannot export the Dolt store at " +
106
+ `${beadsDir}. Install bd, or pass --source <dir> with exported *.jsonl files.`,
107
+ };
108
+ }
109
+ return { error: `bd export --all failed: ${message}` };
110
+ }
111
+ }
112
+
113
+ /**
114
+ * Resolve the directory holding Beads JSONL the loader will read.
115
+ * 1. --source wins (used as given).
116
+ * 2. else auto-detect a `.beads/` dir containing *.jsonl.
117
+ * 3. else a Dolt-only `.beads/` (no jsonl) → `bd export --all` into a temp dir.
118
+ * 4. else nothing found.
119
+ */
120
+ function resolveBeadsSource(options, projectRoot, deps) {
121
+ const fsImpl = deps.fs || fs;
122
+ const root = projectRoot || process.cwd();
123
+
124
+ if (options.source) {
125
+ const dir = path.resolve(root, options.source);
126
+ if (!fsImpl.existsSync(dir)) {
127
+ return { error: `No beads data found at --source ${dir} (directory does not exist)` };
128
+ }
129
+ return { dir, kind: 'source' };
130
+ }
131
+
132
+ const beadsDir = path.join(root, '.beads');
133
+ if (fsImpl.existsSync(beadsDir)) {
134
+ if (directoryHasJsonl(beadsDir, fsImpl)) {
135
+ return { dir: beadsDir, kind: 'jsonl-autodetect' };
136
+ }
137
+ return exportDoltStoreToJsonl(beadsDir, root, deps);
138
+ }
139
+
140
+ return {
141
+ error:
142
+ 'No beads data found. Looked for a .beads/ directory with *.jsonl under ' +
143
+ `${root}. Pass --source <dir> to point at an exported Beads store.`,
144
+ };
145
+ }
146
+
147
+ function cleanupResolved(resolved, deps) {
148
+ if (resolved && resolved.temp) {
149
+ const fsImpl = deps.fs || fs;
150
+ fsImpl.rmSync(resolved.temp, { recursive: true, force: true });
151
+ }
152
+ }
153
+
154
+ function summarizeGaps(gaps) {
155
+ const items = Array.isArray(gaps) ? gaps : [];
156
+ return {
157
+ count: items.length,
158
+ items: items.map(gap => ({ field: gap.field, reason: gap.reason })),
159
+ };
160
+ }
161
+
162
+ function renderHuman(payload) {
163
+ if (payload.error) {
164
+ return `forge migrate failed: ${payload.error}`;
165
+ }
166
+
167
+ const gaps = payload.gaps || { count: 0, items: [] };
168
+ const gapBrief = gaps.count > 0
169
+ ? ` (${gaps.items.map(item => item.field).join(', ')})`
170
+ : '';
171
+
172
+ if (payload.dryRun) {
173
+ return [
174
+ `Dry run — would import beads → kernel from ${payload.source}:`,
175
+ ` issues: ${payload.planned.issues}, comments: ${payload.planned.comments}, ` +
176
+ `dependencies: ${payload.planned.dependencies}, events: ${payload.planned.events ?? 0}`,
177
+ ` gaps: ${gaps.count}${gapBrief}`,
178
+ ' (nothing written to the kernel)',
179
+ ].join('\n');
180
+ }
181
+
182
+ const imported = payload.imported;
183
+ const importedEvents = imported.events || { inserted: 0, skipped: 0 };
184
+ return [
185
+ `Migrated beads → kernel from ${payload.source}:`,
186
+ ` issues: ${imported.issues.inserted} imported, ${imported.issues.skipped} skipped`,
187
+ ` comments: ${imported.comments.inserted} imported, ${imported.comments.skipped || 0} skipped`,
188
+ ` dependencies: ${imported.dependencies.inserted} imported, ` +
189
+ `${imported.dependencies.skipped} skipped`,
190
+ ` events: ${importedEvents.inserted} imported, ${importedEvents.skipped || 0} skipped`,
191
+ ` gaps: ${gaps.count}${gapBrief}`,
192
+ ].join('\n');
193
+ }
194
+
195
+ function finalize(options, payload, exitCode) {
196
+ const output = options.json ? JSON.stringify(payload, null, 2) : renderHuman(payload);
197
+ const result = { ...payload, output, json: Boolean(options.json) };
198
+ if (payload.success === false && Number.isInteger(exitCode)) {
199
+ result.exitCode = exitCode;
200
+ }
201
+ return result;
202
+ }
203
+
204
+ /**
205
+ * Beads → Forge Kernel transport. Reuses the faithful-import spine end-to-end:
206
+ * loadBeadsSnapshotFromDirectory → importBeadsSnapshot → broker.importIssues.
207
+ */
208
+ async function runBeadsMigration(options, projectRoot, opts) {
209
+ const now = opts._now || new Date().toISOString();
210
+ const deps = { execFileSync: opts._execFileSync, fs: opts._fs };
211
+
212
+ const resolved = resolveBeadsSource(options, projectRoot, deps);
213
+ if (resolved.error) {
214
+ return finalize(options, { success: false, from: 'beads', error: resolved.error }, 1);
215
+ }
216
+
217
+ let snapshot;
218
+ try {
219
+ snapshot = loadBeadsSnapshotFromDirectory(resolved.dir);
220
+ } catch (err) {
221
+ cleanupResolved(resolved, deps);
222
+ return finalize(
223
+ options,
224
+ { success: false, from: 'beads', source: resolved.dir, error: `Failed to read beads data: ${err.message}` },
225
+ 1,
226
+ );
227
+ }
228
+
229
+ if (snapshot.issues.length === 0 && snapshot.comments.length === 0 && snapshot.dependencies.length === 0) {
230
+ cleanupResolved(resolved, deps);
231
+ return finalize(
232
+ options,
233
+ { success: false, from: 'beads', source: resolved.dir, error: `No beads data found in ${resolved.dir}` },
234
+ 1,
235
+ );
236
+ }
237
+
238
+ let kernel;
239
+ let report;
240
+ try {
241
+ ({ kernel, report } = importBeadsSnapshot(snapshot, { importedAt: now }));
242
+ } catch (err) {
243
+ cleanupResolved(resolved, deps);
244
+ return finalize(
245
+ options,
246
+ { success: false, from: 'beads', source: resolved.dir, error: `Failed to map beads data: ${err.message}` },
247
+ 1,
248
+ );
249
+ }
250
+ const gaps = summarizeGaps(report?.gaps);
251
+ const planned = {
252
+ issues: kernel.issues.length,
253
+ comments: kernel.comments.length,
254
+ dependencies: kernel.dependencies.length,
255
+ events: Array.isArray(kernel.activityEvents) ? kernel.activityEvents.length : 0,
256
+ };
257
+
258
+ if (options.dryRun) {
259
+ cleanupResolved(resolved, deps);
260
+ return finalize(options, {
261
+ success: true,
262
+ from: 'beads',
263
+ dryRun: true,
264
+ source: resolved.dir,
265
+ sourceKind: resolved.kind,
266
+ planned,
267
+ gaps,
268
+ });
269
+ }
270
+
271
+ try {
272
+ let broker = opts._broker;
273
+ if (!broker) {
274
+ const built = await buildMigratedKernelIssueDeps({ projectRoot });
275
+ broker = built.kernelBroker;
276
+ }
277
+ const summary = await broker.importIssues(kernel, { now });
278
+ cleanupResolved(resolved, deps);
279
+ return finalize(options, {
280
+ success: true,
281
+ from: 'beads',
282
+ dryRun: false,
283
+ source: resolved.dir,
284
+ sourceKind: resolved.kind,
285
+ planned,
286
+ imported: {
287
+ issues: summary.issues,
288
+ comments: summary.comments,
289
+ dependencies: summary.dependencies,
290
+ events: summary.events,
291
+ },
292
+ gaps,
293
+ });
294
+ } catch (err) {
295
+ cleanupResolved(resolved, deps);
296
+ return finalize(
297
+ options,
298
+ { success: false, from: 'beads', source: resolved.dir, error: `Kernel import failed: ${err.message}` },
299
+ 1,
300
+ );
301
+ }
302
+ }
303
+
304
+ /**
305
+ * Detect a jsonl-backed Beads store under `<projectRoot>/.beads`. Returns the
306
+ * directory path when it holds *.jsonl sidecars, else null.
307
+ *
308
+ * Onboarding (forge setup/init) uses this to decide whether to auto-migrate.
309
+ * It deliberately never falls back to `bd export` (a Dolt-only store with no
310
+ * jsonl returns null), so setup stays bd-free even when Dolt is down.
311
+ */
312
+ function detectBeadsJsonlSource(projectRoot, deps = {}) {
313
+ const fsImpl = deps.fs || fs;
314
+ const beadsDir = path.join(projectRoot || process.cwd(), '.beads');
315
+ return fsImpl.existsSync(beadsDir) && directoryHasJsonl(beadsDir, fsImpl)
316
+ ? beadsDir
317
+ : null;
318
+ }
319
+
320
+ /**
321
+ * Idempotently import an existing jsonl-backed Beads store into the Kernel as
322
+ * part of onboarding. Reuses the exact `forge migrate --from beads` spine, so
323
+ * gaps are surfaced honestly and a second run inserts nothing.
324
+ *
325
+ * No-op (`{ migrated: false, reason: 'no-beads-jsonl' }`) when there is no jsonl
326
+ * `.beads/` present. Never requires the `bd` binary.
327
+ *
328
+ * @param {string} projectRoot
329
+ * @param {object} [opts] - Passed through to runBeadsMigration (_broker/_now/_fs seams).
330
+ * @returns {Promise<{ migrated: boolean, reason?: string, result?: object }>}
331
+ */
332
+ async function autoMigrateBeadsIfPresent(projectRoot, opts = {}) {
333
+ if (!detectBeadsJsonlSource(projectRoot, { fs: opts._fs })) {
334
+ return { migrated: false, reason: 'no-beads-jsonl' };
335
+ }
336
+ const result = await runBeadsMigration({ from: 'beads' }, projectRoot, opts);
337
+ return { migrated: result.success === true, result };
338
+ }
339
+
340
+ const BEADS_MIGRATE_NUDGE =
341
+ 'Forge could not import your Beads issues into the Kernel automatically. '
342
+ + 'Run `forge migrate --from beads` to import them.';
343
+
344
+ // The "already imported" marker lives as a row in the broker's kernel_migrations
345
+ // ledger (created unconditionally by broker.initialize()), NOT as a file beside the
346
+ // DB. Keeping it INSIDE the kernel DB means a DB reset drops the marker and the import
347
+ // self-heals; a file sentinel would survive the reset and leave issues dark forever.
348
+ // The id uses underscores so it passes the ledger charset /^[0-9a-z_]+$/i and stays
349
+ // clear of the tokens the D20 retirement audit counts (see release-readiness.js).
350
+ const IMPORT_MARKER_TABLE = 'kernel_migrations';
351
+ const IMPORT_MARKER_ID = 'data_import_beads_jsonl';
352
+
353
+ // Read/record the import marker via the DRIVER (the broker exposes no raw SQL). Both
354
+ // calls are param-less (raw SQL + config); the id is a hardcoded constant and appliedAt
355
+ // is an ISO string, so interpolation is injection-safe — mirrors broker.recordMigrationSql.
356
+ async function importMarkerPresent(driver, config) {
357
+ if (!driver || typeof driver.queryAll !== 'function') {
358
+ return false;
359
+ }
360
+ try {
361
+ const rows = await driver.queryAll(
362
+ `SELECT 1 FROM ${IMPORT_MARKER_TABLE} WHERE id = '${IMPORT_MARKER_ID}' LIMIT 1;`,
363
+ config,
364
+ );
365
+ return Array.isArray(rows) && rows.length > 0;
366
+ } catch {
367
+ // Ledger table absent / driver unavailable → treat as not-yet-imported.
368
+ return false;
369
+ }
370
+ }
371
+
372
+ async function recordImportMarker(driver, config, appliedAt) {
373
+ if (!driver || typeof driver.exec !== 'function') {
374
+ return;
375
+ }
376
+ try {
377
+ await driver.exec(
378
+ `INSERT OR IGNORE INTO ${IMPORT_MARKER_TABLE} (id, applied_at) VALUES ('${IMPORT_MARKER_ID}', '${appliedAt}');`,
379
+ config,
380
+ );
381
+ } catch {
382
+ // Best-effort marker; never break the command we ride on.
383
+ }
384
+ }
385
+
386
+ /**
387
+ * First-use safety net for the kernel default backend. Onboarding auto-migrate runs
388
+ * only from `forge setup`/`init`; an existing repo whose user merely upgrades forge
389
+ * reads an EMPTY kernel on the first issue command, so their existing Beads issues
390
+ * appear to vanish. This imports them ONCE — gated by an in-DB marker row in the
391
+ * kernel_migrations ledger, so the gate shares the DB lifecycle and a DB reset
392
+ * self-heals — idempotently, announcing on stderr only so `--json` stdout stays a pure
393
+ * contract. NEVER throws: the safety net must never break the command it rides on.
394
+ *
395
+ * Only a jsonl-backed store is auto-imported (the migration binary is never shelled).
396
+ * A store with no jsonl export is skipped silently. The marker is SUCCESS-ONLY: a
397
+ * failed import records nothing and is retried (with a nudge) on the next kernel
398
+ * command, so transient failures and DB resets self-heal. Imported issues land in the
399
+ * read model directly and arrive UNCLAIMED — they surface via `forge issue ready`.
400
+ *
401
+ * @param {object} params
402
+ * @param {string} params.projectRoot
403
+ * @param {string} params.databasePath - kernel DB path (used for the driver config).
404
+ * @param {object} params.broker - an initialized kernel broker to import through.
405
+ * @param {object} params.driver - kernel driver, for the ledger marker read/write.
406
+ * @param {object} [deps] - { fs, warn, now, driver, _fs } seams for tests.
407
+ * @returns {Promise<{action:'migrated'|'nudge'|'skip', reason?:string, inserted?:number}>}
408
+ */
409
+ async function autoMigrateBeadsAtRuntime({ projectRoot, databasePath, broker, driver } = {}, deps = {}) {
410
+ const fsImpl = deps.fs || fs;
411
+ const warn = deps.warn || ((msg) => process.stderr.write(`${msg}\n`));
412
+ const appliedAt = deps.now || new Date().toISOString();
413
+ const markerDriver = deps.driver || driver;
414
+ const markerConfig = databasePath ? { databasePath } : {};
415
+ try {
416
+ if (!databasePath) {
417
+ return { action: 'skip', reason: 'no-db-path' };
418
+ }
419
+
420
+ // One-time gate: the import already ran on THIS kernel DB (the marker dies with the
421
+ // DB, so deleting kernel.sqlite to reset correctly re-triggers the import).
422
+ if (await importMarkerPresent(markerDriver, markerConfig)) {
423
+ return { action: 'skip', reason: 'already-imported' };
424
+ }
425
+
426
+ // Only a jsonl export can be imported automatically; anything else is skipped
427
+ // silently (an empty or export-less store must never trigger a false nudge).
428
+ if (!detectBeadsJsonlSource(projectRoot, { fs: fsImpl })) {
429
+ return { action: 'skip', reason: 'no-jsonl' };
430
+ }
431
+
432
+ // Import (idempotent) through the already-initialized broker.
433
+ let outcome;
434
+ try {
435
+ outcome = await autoMigrateBeadsIfPresent(projectRoot, { _broker: broker, _now: deps.now, _fs: deps._fs });
436
+ } catch (err) {
437
+ outcome = { migrated: false, result: { success: false, error: err.message } };
438
+ }
439
+
440
+ if (outcome.migrated) {
441
+ const inserted = outcome.result?.imported?.issues?.inserted ?? 0;
442
+ const skipped = outcome.result?.imported?.issues?.skipped ?? 0;
443
+ // Record the marker LAST so a concurrent first run is a benign idempotent skip.
444
+ await recordImportMarker(markerDriver, markerConfig, appliedAt);
445
+ if (inserted > 0) {
446
+ warn(`Forge: imported ${inserted} Beads issue(s) into the Kernel — your issues are here, not lost.`);
447
+ }
448
+ return { action: 'migrated', inserted, skipped };
449
+ }
450
+
451
+ // Success-only marker: a failed import records nothing and re-nudges next run,
452
+ // so a transient failure self-heals once the underlying problem is resolved.
453
+ const error = outcome.result?.error || outcome.reason || 'unknown error';
454
+ warn(BEADS_MIGRATE_NUDGE);
455
+ return { action: 'nudge', reason: 'migrate-failed', error };
456
+ } catch (err) {
457
+ // Absolutely never break the command we ride on.
458
+ return { action: 'skip', reason: 'error', error: err.message };
459
+ }
460
+ }
461
+
462
+ module.exports = {
463
+ name: 'migrate',
464
+ description: 'Migrate a Beads issue store into the Forge Kernel with --from beads, '
465
+ + 'or preview the v2→v3 migration (preview only — --dry-run required; applying it is not yet available)',
466
+ detectBeadsJsonlSource,
467
+ autoMigrateBeadsIfPresent,
468
+ autoMigrateBeadsAtRuntime,
469
+ usage: 'forge migrate --from beads [--dry-run] [--source <dir>] [--json]',
470
+ flags: {
471
+ '--from <source>': 'Migration source. Use "beads" to import a Beads issue store into the Kernel.',
472
+ '--source <dir>': 'Directory of exported beads *.jsonl files (defaults to auto-detecting .beads/). '
473
+ + 'A split .beads layout is tolerated: files missing from the given dir are also read from a '
474
+ + 'backup/ subdir and the parent dir, so events (under .beads/backup/) and interactions '
475
+ + '(at .beads/interactions.jsonl) are both picked up regardless of which you point at.',
476
+ '--dry-run': 'Read + map only; print what WOULD be imported without writing to the Kernel. '
477
+ + 'Without --from, this is the only supported mode (preview only).',
478
+ '--json': 'Emit a structured JSON result (counts + gaps + dryRun flag).',
479
+ '--fixture-corpus': 'v2→v3 preview only: also dry-run the source-tree v2 fixture corpus when available.',
480
+ },
481
+
482
+ async handler(args, flags, projectRoot, opts = {}) {
483
+ const options = parseMigrateOptions(args, flags);
484
+ if (options.errors.length > 0) {
485
+ return finalize(options, { success: false, error: options.errors.join('; ') }, 1);
486
+ }
487
+
488
+ // New beads → kernel transport, gated on `--from beads`. Any other (or absent)
489
+ // `--from` falls through to the pre-existing v2→v3 dry-run PoC so its contract
490
+ // (and tests) stay intact.
491
+ if (options.from) {
492
+ if (options.from === 'beads') {
493
+ return runBeadsMigration(options, projectRoot, opts);
494
+ }
495
+ return finalize(
496
+ options,
497
+ { success: false, error: `Unsupported migration source '${options.from}'. Supported sources: beads.` },
498
+ 1,
499
+ );
500
+ }
501
+
502
+ // --- legacy v2 → v3 dry-run PoC (unchanged) ---
503
+ const dryRun = flags?.dryRun === true || hasArg(args, '--dry-run');
504
+ if (!dryRun) {
505
+ return {
506
+ success: false,
507
+ error: "forge migrate currently supports preview only. Run 'forge migrate --dry-run' "
508
+ + 'to see what would change; applying migrations is not yet available.',
509
+ };
510
+ }
511
+
512
+ const report = buildMigrationDryRunReport(projectRoot, {
513
+ fixtureCorpus: hasArg(args, '--fixture-corpus'),
514
+ });
515
+ const output = renderMigrationDryRunReport(report);
516
+
517
+ return {
518
+ success: report.ok,
519
+ output,
520
+ error: report.ok ? undefined : output,
521
+ };
522
+ },
523
+ };
@@ -0,0 +1,12 @@
1
+ 'use strict';
2
+
3
+ const { scaffoldAdapter } = require('../adapter-cli');
4
+
5
+ module.exports = {
6
+ name: 'new',
7
+ description: 'Create Forge extension scaffolds',
8
+ usage: 'forge new adapter <name> --kind=review --template=greptile',
9
+ async handler(args, _flags, projectRoot) {
10
+ return scaffoldAdapter(args, projectRoot);
11
+ },
12
+ };