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,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
+ };