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
@@ -6,12 +6,16 @@ const path = require('node:path');
6
6
 
7
7
  /**
8
8
  * Forge Worktree Command
9
- * Manage isolated worktrees with Beads integration.
9
+ * Manage isolated worktrees.
10
10
  * Uses execFileSync (not execSync) to prevent command injection (OWASP A03).
11
11
  *
12
+ * The Kernel issue store lives in the git common dir, which every worktree of a
13
+ * repo shares, so no per-worktree issue-store bootstrap is needed — a new
14
+ * worktree already sees the same kernel.
15
+ *
12
16
  * Subcommands:
13
- * create <slug> Create worktree at .worktrees/<slug> with branch + beads + install
14
- * remove <slug> Remove worktree via git worktree remove
17
+ * create <slug> - Create worktree at .worktrees/<slug> with branch + install
18
+ * remove <slug> - Remove worktree via git worktree remove
15
19
  *
16
20
  * @module commands/worktree
17
21
  */
@@ -23,7 +27,10 @@ const path = require('node:path');
23
27
  * @returns {string|null} Package manager command or null
24
28
  */
25
29
  function detectPackageManager(projectRoot, fsApi) {
30
+ // Bun ships two lockfile formats: the legacy binary `bun.lockb` and the current
31
+ // text `bun.lock`. Recognize both so a Bun repo isn't mis-detected as npm.
26
32
  if (fsApi.existsSync(path.join(projectRoot, 'bun.lockb'))) return 'bun';
33
+ if (fsApi.existsSync(path.join(projectRoot, 'bun.lock'))) return 'bun';
27
34
  if (fsApi.existsSync(path.join(projectRoot, 'pnpm-lock.yaml'))) return 'pnpm';
28
35
  if (fsApi.existsSync(path.join(projectRoot, 'yarn.lock'))) return 'yarn';
29
36
  if (fsApi.existsSync(path.join(projectRoot, 'package-lock.json'))) return 'npm';
@@ -31,66 +38,6 @@ function detectPackageManager(projectRoot, fsApi) {
31
38
  return null;
32
39
  }
33
40
 
34
- /**
35
- * Copy .beads/ directory excluding daemon.lock.
36
- * @param {string} source - Source .beads path
37
- * @param {string} dest - Destination .beads path
38
- * @param {object} fsApi - fs module (for DI)
39
- */
40
- function copyBeadsDir(source, dest, fsApi) {
41
- fsApi.mkdirSync(dest, { recursive: true });
42
- const entries = fsApi.readdirSync(source);
43
- for (const entry of entries) {
44
- if (entry === 'daemon.lock') continue;
45
- fsApi.cpSync(path.join(source, entry), path.join(dest, entry), { recursive: true });
46
- }
47
- }
48
-
49
- /**
50
- * Stop a Dolt server running in a worktree to release file locks.
51
- * Tries graceful `bd dolt stop` first, then falls back to PID-based kill
52
- * from lock files. Never kills ALL Dolt processes — only the specific PID.
53
- *
54
- * @param {string} worktreePath - Absolute path to the worktree
55
- * @param {object} [opts] - Options for dependency injection
56
- * @param {Function} [opts._exec] - Override for execFileSync (testing)
57
- * @param {object} [opts._fs] - Override for fs module (testing)
58
- * @param {string} [opts._platform] - Override for process.platform (testing)
59
- * @returns {{ stopped: boolean, method: string, pid?: number }}
60
- */
61
- function stopDolt(worktreePath, opts = {}) {
62
- const exec = opts._exec || execFileSync;
63
- const _fs = opts._fs || fs;
64
- const platform = opts._platform || process.platform;
65
-
66
- // 1. Try graceful: bd dolt stop
67
- try {
68
- exec('bd', ['dolt', 'stop'], { cwd: worktreePath, timeout: 5000, stdio: 'pipe' });
69
- return { stopped: true, method: 'bd-dolt-stop' };
70
- } catch (_e) { /* intentional: bd not available, try PID-based kill */ } // NOSONAR S2486
71
-
72
- // 2. Try PID-based kill from lock file
73
- const lockPaths = [
74
- path.join(worktreePath, '.beads', 'dolt-server.lock'),
75
- path.join(worktreePath, '.beads', 'daemon.lock'),
76
- ];
77
- for (const lockPath of lockPaths) {
78
- try {
79
- const pid = Number.parseInt(_fs.readFileSync(lockPath, 'utf-8').trim(), 10);
80
- if (!Number.isNaN(pid)) {
81
- if (platform === 'win32') {
82
- exec('taskkill', ['/F', '/PID', String(pid)], { stdio: 'pipe' });
83
- } else {
84
- process.kill(pid, 'SIGTERM');
85
- }
86
- return { stopped: true, method: 'pid-kill', pid };
87
- }
88
- } catch (_e) { /* intentional: try next lock file */ } // NOSONAR S2486
89
- }
90
-
91
- return { stopped: false, method: 'none' };
92
- }
93
-
94
41
  /**
95
42
  * Check if a git branch already exists.
96
43
  * @param {string} branchName - Branch name to check
@@ -107,58 +54,189 @@ function branchExists(branchName, runFile) {
107
54
  }
108
55
 
109
56
  /**
110
- * Set up Beads integration for a new worktree (symlink/junction/copy).
57
+ * True when a link failure is a privilege/support problem (Windows without the
58
+ * symlink privilege, restricted FS) rather than a real error. In that case we
59
+ * degrade to a package install instead of hard-failing.
60
+ * @param {Error} error
61
+ * @returns {boolean}
62
+ */
63
+ function isLinkPermissionError(error) {
64
+ return ['EPERM', 'EACCES', 'ENOSYS', 'UV_EPERM'].includes(error && error.code);
65
+ }
66
+
67
+ /**
68
+ * Run package install in the new worktree if a package manager is detected, and
69
+ * SURFACE failures (spawn error or non-zero exit) instead of swallowing them.
111
70
  * @param {string} worktreePath - Absolute path to the new worktree
112
71
  * @param {string} projectRoot - Absolute path to the project root
113
- * @param {string} platform - OS platform string (e.g. 'win32')
72
+ * @param {Function} spawnFn - spawnSync-compatible function
114
73
  * @param {object} fsApi - fs module (for DI)
115
- * @param {Function} exec - execFileSync-compatible function
116
- * @returns {string|null} Warning message if beads setup had issues, null otherwise
74
+ * @returns {{ linked: boolean, installed: boolean }}
75
+ * @throws {Error} when the install cannot be spawned or exits non-zero.
117
76
  */
118
- function setupBeads(worktreePath, projectRoot, platform, fsApi, exec) {
119
- const beadsSource = path.resolve(projectRoot, '.beads');
120
- const beadsDest = path.resolve(worktreePath, '.beads');
77
+ function runInstall(worktreePath, projectRoot, spawnFn, fsApi) {
78
+ const pkgManager = detectPackageManager(projectRoot, fsApi);
79
+ if (!pkgManager) return { linked: false, installed: false };
80
+
81
+ // shell:true on Windows: npm/pnpm/yarn are .cmd shims that cannot be spawned
82
+ // directly (ENOENT / EINVAL). pkgManager comes from lockfile detection (fixed
83
+ // set) and args are hardcoded, so no user input reaches the shell.
84
+ const result = spawnFn(pkgManager, ['install'], {
85
+ cwd: worktreePath,
86
+ stdio: 'pipe',
87
+ shell: process.platform === 'win32',
88
+ });
89
+ if (result && result.error) {
90
+ throw new Error(`Dependency install failed: could not run '${pkgManager} install' in ${worktreePath}: ${result.error.message}`);
91
+ }
92
+ if (result && typeof result.status === 'number' && result.status !== 0) {
93
+ throw new Error(`Dependency install failed: '${pkgManager} install' exited with code ${result.status} in ${worktreePath}`);
94
+ }
95
+ return { linked: false, installed: true };
96
+ }
97
+
98
+ /**
99
+ * Populate the new worktree's node_modules. Fast path: link to the main repo's
100
+ * shared install (a junction on Windows, a directory symlink on POSIX) so a fresh
101
+ * worktree is immediately usable without a full reinstall — this repo's own
102
+ * worktrees follow that pattern. Fallback: run the detected package manager's
103
+ * install when there is no shared install to link. Both paths surface failures.
104
+ * @param {string} worktreePath - Absolute path to the new worktree
105
+ * @param {string} projectRoot - Absolute path to the project root
106
+ * @param {object} deps
107
+ * @param {Function} deps.spawnFn - spawnSync-compatible function
108
+ * @param {object} deps.fsApi - fs module (for DI)
109
+ * @param {string} deps.platform - process.platform value
110
+ * @returns {{ linked: boolean, installed: boolean }}
111
+ * @throws {Error} when linking fails for a non-privilege reason or install fails.
112
+ */
113
+ function setupWorktreeDeps(worktreePath, projectRoot, { spawnFn, fsApi, platform }) {
114
+ const srcModules = path.join(projectRoot, 'node_modules');
115
+ const destModules = path.join(worktreePath, 'node_modules');
116
+
117
+ // Already populated (e.g. git checkout carried it) — nothing to do.
118
+ if (fsApi.existsSync(destModules)) return { linked: false, installed: false };
121
119
 
122
- if (!fsApi.existsSync(beadsSource)) {
123
- return 'Beads not installed — skipping .beads setup';
120
+ // Fast path: link to the shared install when the main repo has one.
121
+ if (fsApi.existsSync(srcModules)) {
122
+ const linkType = platform === 'win32' ? 'junction' : 'dir';
123
+ try {
124
+ fsApi.symlinkSync(srcModules, destModules, linkType);
125
+ return { linked: true, installed: false };
126
+ } catch (error) {
127
+ // Degrade to a real install only when the link was refused for lack of
128
+ // privilege/support; any other failure is surfaced to the caller.
129
+ if (!isLinkPermissionError(error)) throw error;
130
+ }
124
131
  }
125
132
 
126
- // Try symlink first
133
+ return runInstall(worktreePath, projectRoot, spawnFn, fsApi);
134
+ }
135
+
136
+ /**
137
+ * Best-effort: record the issue → worktree → work-folder linkage in the Kernel so
138
+ * `forge worktree list` and orientation READ it instead of guessing the work-folder by
139
+ * a filesystem heuristic. Writes a `kernel_worktrees` row keyed by the absolute worktree
140
+ * path (idempotent upsert) and, when an issue + work-folder are given, drops a
141
+ * machine-readable `.forge-issue` marker so a folder resolves to its issue deterministically.
142
+ *
143
+ * Never throws: a repo without a reachable Kernel (or without the 007 linkage columns)
144
+ * must still get a usable worktree — orientation falls back to the folder heuristic.
145
+ *
146
+ * @param {object} params
147
+ * @param {string} params.projectRoot
148
+ * @param {string} params.worktreePath - Absolute worktree path (the row key).
149
+ * @param {string} params.branch
150
+ * @param {string|null} params.issueId
151
+ * @param {string|null} params.workFolder - Repo-relative work-folder path.
152
+ * @param {object} params.opts - DI options (may inject `_kernelDriver`, `_exec`, `_fs`).
153
+ * @returns {Promise<{registered: boolean, issueId: string|null, workFolder: string|null, reason?: string}>}
154
+ */
155
+ async function registerWorktreeLinkage({ projectRoot, worktreePath, branch, issueId, workFolder, opts }) {
156
+ const runFile = opts._exec || execFileSync;
157
+ const fsApi = opts._fs || fs;
127
158
  try {
128
- if (platform === 'win32') {
129
- fsApi.symlinkSync(beadsSource, beadsDest, 'junction');
130
- } else {
131
- fsApi.symlinkSync(beadsSource, beadsDest);
159
+ // Drop the folder → issue marker first — deterministic even if the DB write fails.
160
+ if (workFolder && issueId) {
161
+ const folderAbs = path.resolve(projectRoot, workFolder);
162
+ fsApi.mkdirSync(folderAbs, { recursive: true });
163
+ fsApi.writeFileSync(path.join(folderAbs, '.forge-issue'), `${issueId}\n`, 'utf8');
132
164
  }
133
- } catch (symlinkErr) {
134
- if (symlinkErr.code === 'EPERM') {
135
- copyBeadsDir(beadsSource, beadsDest, fsApi);
136
- } else {
137
- throw symlinkErr;
165
+
166
+ let driver = opts._kernelDriver;
167
+ if (!driver) {
168
+ // No reachable git repo → no shared Kernel; skip quietly (orientation still works
169
+ // off the folder heuristic). Avoids spawning `git` in a non-repo directory.
170
+ if (!fsApi.existsSync(path.join(projectRoot, '.git'))) {
171
+ return { registered: false, issueId: issueId || null, workFolder: workFolder || null, reason: 'no git repository' };
172
+ }
173
+ // Lazy require: keep the worktree command light and avoid paying kernel setup
174
+ // when linkage is not needed. Migrated deps guarantee the 007 columns exist.
175
+ const { buildMigratedKernelIssueDeps } = require('../kernel/cli-broker-factory');
176
+ driver = (await buildMigratedKernelIssueDeps({ projectRoot })).kernelDriver;
138
177
  }
139
- }
140
178
 
141
- // Verify beads accessible (warn if fails, don't block)
142
- try {
143
- exec('bd', ['--version'], { cwd: worktreePath, timeout: 5000, stdio: 'pipe' });
144
- } catch (_bdErr) { /* intentional: bd may not be on PATH */ // NOSONAR S2486
145
- return 'Beads verification failed — .beads linked but bd may not work';
179
+ const { resolveGitCommonDir } = require('../kernel/broker');
180
+ const gitCommonDir = resolveGitCommonDir(projectRoot, { execFileSync: runFile });
181
+
182
+ driver.registerWorktree({
183
+ git_common_dir: gitCommonDir,
184
+ path: worktreePath,
185
+ branch,
186
+ actor: process.env.FORGE_ACTOR || null,
187
+ issue_id: issueId || null,
188
+ work_folder: workFolder || null,
189
+ registered_at: new Date().toISOString(),
190
+ state: 'active',
191
+ });
192
+
193
+ return { registered: true, issueId: issueId || null, workFolder: workFolder || null };
194
+ } catch (error) {
195
+ // Non-fatal: keep the worktree usable. Only warn when the caller explicitly asked
196
+ // for linkage (--issue/--work-folder); a plain `worktree create` stays quiet.
197
+ if (issueId || workFolder) {
198
+ process.stderr.write(`forge worktree: kernel linkage not recorded (${error.message})\n`);
199
+ }
200
+ return { registered: false, issueId: issueId || null, workFolder: workFolder || null, reason: error.message };
146
201
  }
147
-
148
- return null;
149
202
  }
150
203
 
151
204
  /**
152
- * Run package install in the new worktree if a package manager is detected.
153
- * @param {string} worktreePath - Absolute path to the new worktree
154
- * @param {string} projectRoot - Absolute path to the project root
155
- * @param {Function} spawnFn - spawnSync-compatible function
156
- * @param {object} fsApi - fs module (for DI)
205
+ * Auto-file rail: guarantee the new worktree's branch has a backing Kernel issue,
206
+ * WITHOUT anyone remembering `forge issue create` (kernel issue a4b8f56f). Best-effort
207
+ * and NON-BLOCKING the worktree must stay usable even if tracking fails, so any error
208
+ * degrades to a stderr warning and null. Skipped when `--issue` already links a real
209
+ * issue. Idempotent via ensureBackingIssue (deduped by branch), so re-creating a
210
+ * worktree or later `forge push`/pre-push firing never mints a duplicate.
211
+ *
212
+ * @param {object} params
213
+ * @param {string} params.projectRoot
214
+ * @param {string} params.worktreePath
215
+ * @param {string} params.branch
216
+ * @param {string|null} params.issueId - explicit --issue (skip auto-file when set).
217
+ * @param {object} params.opts - DI (may inject `_ensureBackingIssue`, `_kernelDriver`, `_kernelBroker`, `_fs`).
218
+ * @returns {Promise<object|null>} the backing-issue descriptor, or null when skipped/unavailable.
157
219
  */
158
- function runInstall(worktreePath, projectRoot, spawnFn, fsApi) {
159
- const pkgManager = detectPackageManager(projectRoot, fsApi);
160
- if (pkgManager) {
161
- spawnFn(pkgManager, ['install'], { cwd: worktreePath, stdio: 'pipe' });
220
+ async function autoFileBackingIssue({ projectRoot, worktreePath, branch, issueId, opts }) {
221
+ if (issueId) return null; // explicit --issue already links a real issue.
222
+ const fsApi = opts._fs || fs;
223
+ try {
224
+ // Lazy require INSIDE the try: a module-load failure (missing file / broken
225
+ // sub-dependency) must degrade to null, never crash `forge worktree create`.
226
+ const ensureFn = opts._ensureBackingIssue || require('../kernel/backing-issue').ensureBackingIssue;
227
+ let driver = opts._kernelDriver;
228
+ let broker = opts._kernelBroker;
229
+ if (!driver || !broker) {
230
+ if (!fsApi.existsSync(path.join(projectRoot, '.git'))) return null; // no repo → no kernel
231
+ const { buildMigratedKernelIssueDeps } = require('../kernel/cli-broker-factory');
232
+ const deps = await buildMigratedKernelIssueDeps({ projectRoot });
233
+ driver = driver || deps.kernelDriver;
234
+ broker = broker || deps.kernelBroker;
235
+ }
236
+ return await ensureFn({ branch, projectRoot, worktreePath, driver, broker });
237
+ } catch (error) {
238
+ process.stderr.write(`forge worktree: backing issue not auto-filed (${error.message})\n`);
239
+ return null;
162
240
  }
163
241
  }
164
242
 
@@ -174,18 +252,23 @@ async function handleCreate(slug, flags, projectRoot, opts) {
174
252
  const runFile = opts._exec || execFileSync;
175
253
  const runSpawn = opts._spawn || spawnSync;
176
254
  const fsApi = opts._fs || fs;
177
- const platform = opts._platform || process.platform;
178
255
 
179
256
  const branchName = flags['--branch'] || flags.branch || `feat/${slug}`;
257
+ const issueId = flags['--issue'] || null;
258
+ const workFolder = flags['--work-folder'] || null;
180
259
  const worktreesDir = path.resolve(projectRoot, '.worktrees');
181
260
 
182
- // Guard: Detect bare repo state worktrees created from bare repos produce broken branches
261
+ // Guard: Detect bare repo state - worktrees created from bare repos produce broken branches
183
262
  // git rev-parse --show-toplevel throws in a bare repo (no working tree)
184
263
  try {
185
264
  runFile('git', ['-C', projectRoot, 'rev-parse', '--show-toplevel'], { encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] });
186
- } catch (_e) { // NOSONAR S2486
265
+ } catch (error) {
187
266
  /* intentional: show-toplevel fails in bare repos */
188
- return { success: false, error: 'Main repo is in bare state (no working tree). Clone fresh instead: git clone <url> /tmp/forge-<slug>' };
267
+ const errMsg = String(error?.stderr || error?.message || '').trim();
268
+ if (/must be run in a work tree|this operation must be run in a work tree/i.test(errMsg)) {
269
+ return { success: false, error: 'bare repo detected' };
270
+ }
271
+ return { success: false, error: errMsg || 'git rev-parse --show-toplevel failed' };
189
272
  }
190
273
 
191
274
  // Security: Validate slug doesn't contain path traversal (OWASP A01/A03)
@@ -197,11 +280,23 @@ async function handleCreate(slug, flags, projectRoot, opts) {
197
280
 
198
281
  // Step 0: Check if worktree already exists
199
282
  if (fsApi.existsSync(worktreePath)) {
283
+ // A pre-existing worktree may be checked out on a different branch than the
284
+ // requested branchName — read the actual HEAD so the kernel row is accurate.
285
+ let existingBranch = branchName;
286
+ try {
287
+ const head = runFile('git', ['-C', worktreePath, 'rev-parse', '--abbrev-ref', 'HEAD'], { encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] }).trim();
288
+ // A detached worktree reports the literal "HEAD" — don't persist that; keep branchName.
289
+ if (head && head !== 'HEAD') existingBranch = head;
290
+ } catch (_error) { /* not a resolvable worktree HEAD — fall back to branchName */ }
291
+ const linkage = await registerWorktreeLinkage({ projectRoot, worktreePath, branch: existingBranch, issueId, workFolder, opts });
292
+ const backing = await autoFileBackingIssue({ projectRoot, worktreePath, branch: existingBranch, issueId, opts });
200
293
  return {
201
294
  success: true,
202
295
  reused: true,
203
296
  message: `Worktree already exists at ${worktreePath}`,
204
297
  worktreePath,
298
+ linkage,
299
+ backing,
205
300
  };
206
301
  }
207
302
 
@@ -216,21 +311,52 @@ async function handleCreate(slug, flags, projectRoot, opts) {
216
311
  runFile('git', ['worktree', 'add', worktreePath, '-b', branchName], { stdio: 'pipe' });
217
312
  }
218
313
 
219
- // Step 3: Beads integration
220
- const beadsWarning = setupBeads(worktreePath, projectRoot, platform, fsApi, runFile);
314
+ // Step 3: Populate node_modules (link to the shared install, else install).
315
+ // No per-worktree issue-store bootstrap is needed — the Kernel DB lives in the
316
+ // shared git common dir, so the new worktree already sees the same kernel.
317
+ let deps;
318
+ try {
319
+ deps = setupWorktreeDeps(worktreePath, projectRoot, {
320
+ spawnFn: runSpawn,
321
+ fsApi,
322
+ platform: opts._platform || process.platform,
323
+ });
324
+ } catch (error) {
325
+ // Surface the failure instead of leaving a worktree with no usable deps.
326
+ return { success: false, error: error.message, worktreePath, branch: branchName };
327
+ }
221
328
 
222
- // Step 4: Run package install
223
- runInstall(worktreePath, projectRoot, runSpawn, fsApi);
329
+ const linkage = await registerWorktreeLinkage({ projectRoot, worktreePath, branch: branchName, issueId, workFolder, opts });
330
+ const backing = await autoFileBackingIssue({ projectRoot, worktreePath, branch: branchName, issueId, opts });
224
331
 
225
- const result = {
332
+ return {
226
333
  success: true,
227
334
  worktreePath,
228
335
  branch: branchName,
336
+ depsLinked: deps.linked,
337
+ depsInstalled: deps.installed,
338
+ linkage,
339
+ backing,
229
340
  };
230
- if (beadsWarning) {
231
- result.beadsWarning = beadsWarning;
341
+ }
342
+
343
+ /**
344
+ * Handle the "list" subcommand — read the worktree registry from the Kernel.
345
+ * @param {string} projectRoot - Project root path
346
+ * @param {object} opts - DI options (may inject `_kernelDriver`)
347
+ * @returns {Promise<object>} Result object with a `worktrees` array
348
+ */
349
+ async function handleList(projectRoot, opts) {
350
+ try {
351
+ let driver = opts._kernelDriver;
352
+ if (!driver) {
353
+ const { buildMigratedKernelIssueDeps } = require('../kernel/cli-broker-factory');
354
+ driver = (await buildMigratedKernelIssueDeps({ projectRoot })).kernelDriver;
355
+ }
356
+ return { success: true, worktrees: driver.listWorktrees({}) };
357
+ } catch (error) {
358
+ return { success: false, error: error.message, worktrees: [] };
232
359
  }
233
- return result;
234
360
  }
235
361
 
236
362
  /**
@@ -247,29 +373,65 @@ async function handleRemove(slug, projectRoot, opts) {
247
373
  }
248
374
 
249
375
  const runFile = opts._exec || execFileSync;
250
- const fsModule = opts._fs || fs;
251
376
  const worktreePath = path.resolve(projectRoot, '.worktrees', slug);
252
377
 
253
- // Stop Dolt server to release file locks
254
- const stopResult = stopDolt(worktreePath, { _exec: runFile, _fs: fsModule, _platform: opts._platform });
255
- if (stopResult.stopped) {
256
- // Brief wait for file locks to release (Windows needs this)
257
- await new Promise(r => setTimeout(r, 500));
258
- }
259
-
378
+ // No issue-store server to stop: the Kernel SQLite DB lives in the shared git
379
+ // common dir, so removing a worktree directory never touches it.
260
380
  runFile('git', ['worktree', 'remove', worktreePath], { stdio: 'pipe' });
261
381
 
262
382
  return { success: true, removed: worktreePath };
263
383
  }
264
384
 
385
+ // Long flags that take a value, in both `--flag value` and `--flag=value` forms.
386
+ const WORKTREE_VALUE_FLAGS = ['--branch', '--issue', '--work-folder'];
387
+ const WORKTREE_USAGE_HINT = 'Usage: forge worktree create <slug> [--branch <name>] [--issue <id>] [--work-folder <path>]';
388
+
389
+ function parseWorktreeArgs(args, flags) {
390
+ const positional = [];
391
+ const parsedFlags = { ...flags };
392
+
393
+ for (let i = 0; i < args.length; i++) {
394
+ const arg = args[i];
395
+
396
+ const spaceFlag = WORKTREE_VALUE_FLAGS.find(flag => arg === flag);
397
+ if (spaceFlag) {
398
+ const value = args[i + 1];
399
+ if (!value || value.startsWith('--')) {
400
+ return { error: `Missing value for ${spaceFlag}. ${WORKTREE_USAGE_HINT}` };
401
+ }
402
+ parsedFlags[spaceFlag] = value;
403
+ i++;
404
+ continue;
405
+ }
406
+
407
+ const eqFlag = WORKTREE_VALUE_FLAGS.find(flag => arg.startsWith(`${flag}=`));
408
+ if (eqFlag) {
409
+ const value = arg.slice(`${eqFlag}=`.length);
410
+ if (!value) {
411
+ return { error: `Missing value for ${eqFlag}. ${WORKTREE_USAGE_HINT}` };
412
+ }
413
+ parsedFlags[eqFlag] = value;
414
+ continue;
415
+ }
416
+
417
+ positional.push(arg);
418
+ }
419
+
420
+ // Back-compat alias consumed by handleCreate (flags['--branch'] || flags.branch).
421
+ if (parsedFlags['--branch']) parsedFlags.branch = parsedFlags['--branch'];
422
+
423
+ return { args: positional, flags: parsedFlags };
424
+ }
425
+
265
426
  module.exports = {
266
427
  name: 'worktree',
267
- description: 'Manage isolated worktrees with Beads integration',
268
- usage: 'forge worktree <create|remove> <slug>',
428
+ description: 'Manage isolated worktrees',
429
+ usage: 'forge worktree <create|remove|list> <slug>',
269
430
  flags: {
270
431
  '--branch': 'Custom branch name (default: feat/<slug>)',
432
+ '--issue': 'Kernel issue id to link this worktree to (records issue → worktree)',
433
+ '--work-folder': 'Repo-relative work-folder this issue owns (records worktree → work-folder + drops a .forge-issue marker)',
271
434
  },
272
- stopDolt,
273
435
 
274
436
  /**
275
437
  * Main handler for the worktree command.
@@ -284,27 +446,45 @@ module.exports = {
284
446
  * @returns {Promise<object>}
285
447
  */
286
448
  handler: async (args, flags, projectRoot, opts = {}) => {
287
- const subcommand = args[0];
288
- const slug = args[1];
449
+ const parsed = parseWorktreeArgs(args, flags);
450
+ if (parsed.error) {
451
+ return { success: false, error: parsed.error };
452
+ }
289
453
 
290
- if (!subcommand || !['create', 'remove'].includes(subcommand)) {
454
+ const subcommand = parsed.args[0];
455
+
456
+ if (!subcommand || !['create', 'remove', 'list'].includes(subcommand)) {
291
457
  return {
292
458
  success: false,
293
- error: 'Missing or invalid subcommand. Usage: forge worktree <create|remove> <slug>',
459
+ error: 'Missing or invalid subcommand. Usage: forge worktree <create|remove|list> <slug>',
294
460
  };
295
461
  }
296
462
 
463
+ // `list` reads the Kernel registry and takes no slug.
464
+ if (subcommand === 'list') {
465
+ return handleList(projectRoot, opts);
466
+ }
467
+
468
+ const slug = parsed.args[1];
297
469
  if (!slug) {
298
470
  return {
299
471
  success: false,
300
- error: 'Missing slug. Usage: forge worktree <create|remove> <slug>',
472
+ error: 'Missing slug. Usage: forge worktree <create|remove|list> <slug>',
301
473
  };
302
474
  }
303
475
 
304
476
  if (subcommand === 'create') {
305
- return handleCreate(slug, flags, projectRoot, opts);
477
+ return handleCreate(slug, parsed.flags, projectRoot, opts);
306
478
  }
307
479
 
308
480
  return handleRemove(slug, projectRoot, opts);
309
481
  },
482
+
483
+ // Exposed for unit tests; not part of the CLI surface.
484
+ _internal: {
485
+ detectPackageManager,
486
+ setupWorktreeDeps,
487
+ runInstall,
488
+ autoFileBackingIssue,
489
+ },
310
490
  };