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,282 @@
1
+ const { execFileSync } = require('node:child_process');
2
+ const fs = require('node:fs');
3
+ const path = require('node:path');
4
+
5
+ const VERDICT_LABELS = {
6
+ PASS: 'good',
7
+ FAIL: 'bad',
8
+ };
9
+
10
+ const REVIEWER_ROLES = new Set(['spec_reviewer', 'quality_reviewer']);
11
+ const SECRET_KEY_PATTERN = /(api(?:[_-]|\s)?key|authorization|credential|password|private(?:[_-]|\s)?key|secret|token)/i;
12
+ const SECRET_TEXT_KEY_PATTERN = String.raw`(?:api(?:[_-]|\s)?key|authorization|credential|password|private(?:[_-]|\s)?key|secret|token)`;
13
+ const SECRET_TEXT_PATTERNS = [
14
+ {
15
+ pattern: /\bBearer\s+\S+/gi,
16
+ replace: () => 'Bearer [REDACTED]',
17
+ },
18
+ {
19
+ pattern: new RegExp(`(\\b${SECRET_TEXT_KEY_PATTERN}\\b\\s*=\\s*)([^&,\r\n]+)`, 'gi'),
20
+ replace: (_match, prefix) => `${prefix}[REDACTED]`,
21
+ },
22
+ {
23
+ pattern: new RegExp(`(\\b${SECRET_TEXT_KEY_PATTERN}\\b\\s+is\\s+)([^&,\r\n]+)`, 'gi'),
24
+ replace: (_match, prefix) => `${prefix}[REDACTED]`,
25
+ },
26
+ {
27
+ pattern: new RegExp(
28
+ `(\\b${SECRET_TEXT_KEY_PATTERN}\\b\\s+)(?!is\\b)([^&,\r\n]*?)(?=\\s+\\b${SECRET_TEXT_KEY_PATTERN}\\b\\s+|[&,\r\n]|$)`,
29
+ 'gi'
30
+ ),
31
+ replace: (_match, prefix) => `${prefix}[REDACTED]`,
32
+ },
33
+ {
34
+ pattern: new RegExp(
35
+ `((?:"|')?${SECRET_TEXT_KEY_PATTERN}(?:"|')?\\s*:\\s*)(?:"[^"]*"|'[^']*'|[^,}\\]\r\n]+)`,
36
+ 'gi'
37
+ ),
38
+ replace: (_match, prefix) => `${prefix}"[REDACTED]"`,
39
+ },
40
+ /\bsk-[A-Za-z0-9_-]{8,}\b/g,
41
+ ];
42
+
43
+ function defaultRunCommand(command, args, options = {}) {
44
+ return execFileSync(command, args, {
45
+ cwd: options.cwd || process.cwd(),
46
+ encoding: 'utf8',
47
+ input: options.input,
48
+ timeout: options.timeout || 120000,
49
+ });
50
+ }
51
+
52
+ function redactString(value) {
53
+ return SECRET_TEXT_PATTERNS.reduce(
54
+ (current, entry) => {
55
+ if (entry && typeof entry === 'object' && !(entry instanceof RegExp)) {
56
+ return current.replace(entry.pattern, entry.replace);
57
+ }
58
+ return current.replace(entry, () => '[REDACTED]');
59
+ },
60
+ value,
61
+ );
62
+ }
63
+
64
+ function redact(value, key = '') {
65
+ if (SECRET_KEY_PATTERN.test(key)) {
66
+ return '[REDACTED]';
67
+ }
68
+
69
+ if (typeof value === 'string') {
70
+ return redactString(value);
71
+ }
72
+
73
+ if (Array.isArray(value)) {
74
+ return value.map(item => redact(item));
75
+ }
76
+
77
+ if (value && typeof value === 'object') {
78
+ return Object.fromEntries(
79
+ Object.entries(value).map(([entryKey, entryValue]) => [entryKey, redact(entryValue, entryKey)]),
80
+ );
81
+ }
82
+
83
+ return value;
84
+ }
85
+
86
+ function asJsonString(value) {
87
+ if (typeof value === 'string') return redactString(value);
88
+ return JSON.stringify(redact(value));
89
+ }
90
+
91
+ function buildSubagentAuditPayload(event) {
92
+ if (!event || typeof event !== 'object') {
93
+ throw new TypeError('Audit event must be an object');
94
+ }
95
+ if (!event.command) {
96
+ throw new TypeError('Audit event command is required');
97
+ }
98
+ if (!event.role) {
99
+ throw new TypeError('Audit event role is required');
100
+ }
101
+
102
+ const metadata =
103
+ event.metadata && typeof event.metadata === 'object' && !Array.isArray(event.metadata)
104
+ ? event.metadata
105
+ : {};
106
+
107
+ return {
108
+ kind: 'llm_call',
109
+ command: event.command,
110
+ issueId: event.issueId,
111
+ role: event.role,
112
+ phase: event.phase,
113
+ taskId: event.taskId,
114
+ taskTitle: event.taskTitle,
115
+ model: event.model || 'unknown',
116
+ prompt: asJsonString({
117
+ command: event.command,
118
+ role: event.role,
119
+ phase: event.phase,
120
+ taskId: event.taskId,
121
+ taskTitle: event.taskTitle,
122
+ content: event.prompt || '',
123
+ }),
124
+ response: asJsonString({
125
+ command: event.command,
126
+ role: event.role,
127
+ verdict: event.verdict || 'UNKNOWN',
128
+ content: event.response || '',
129
+ }),
130
+ metadata: redact(metadata),
131
+ verdict: event.verdict,
132
+ };
133
+ }
134
+
135
+ function parseRecordId(output, { requireJson = false } = {}) {
136
+ if (!output) return null;
137
+ try {
138
+ const parsed = JSON.parse(output);
139
+ return typeof parsed.id === 'string' ? parsed.id : null;
140
+ } catch (_error) {
141
+ if (requireJson) return null;
142
+ const match = /\bint-[A-Za-z0-9_-]+\b/.exec(String(output));
143
+ return match ? match[0] : null;
144
+ }
145
+ }
146
+
147
+ function hasAuditMetaJsonSupport(runCommand = defaultRunCommand, options = {}) {
148
+ const output = runCommand('bd', ['audit', 'record', '--help'], options);
149
+ return String(output).includes('--meta-json');
150
+ }
151
+
152
+ function writeFallbackMetadata(payload, entryId, options) {
153
+ if (!entryId || !payload.metadata || Object.keys(payload.metadata).length === 0) {
154
+ return null;
155
+ }
156
+
157
+ const cwd = options.cwd || process.cwd();
158
+ const fsImpl = options.fs || fs;
159
+ const forgeDir = path.join(cwd, '.forge').replace(/\\/g, '/');
160
+ const logPath = path.join(forgeDir, 'log.jsonl').replace(/\\/g, '/');
161
+ const line = {
162
+ kind: 'forge.auditEvidence',
163
+ sourceOfTruth: 'beads',
164
+ beadsEntryId: entryId,
165
+ command: redact(payload.command),
166
+ role: redact(payload.role),
167
+ phase: redact(payload.phase),
168
+ taskId: redact(payload.taskId),
169
+ taskTitle: redact(payload.taskTitle),
170
+ metadata: redact(payload.metadata),
171
+ };
172
+
173
+ try {
174
+ fsImpl.mkdirSync(forgeDir, { recursive: true });
175
+ fsImpl.appendFileSync(logPath, `${JSON.stringify(line)}\n`);
176
+ return { path: logPath, line };
177
+ } catch (error) {
178
+ return { path: logPath, line, skipped: true, error: error.message };
179
+ }
180
+ }
181
+
182
+ function recordSubagentAuditEvent(event, options = {}) {
183
+ const payload = buildSubagentAuditPayload(event);
184
+ const runCommand = options.runCommand || defaultRunCommand;
185
+ const metaJsonSupported =
186
+ typeof options.metaJsonSupported === 'boolean'
187
+ ? options.metaJsonSupported
188
+ : hasAuditMetaJsonSupport(runCommand, { cwd: options.cwd || process.cwd() });
189
+ const args = [
190
+ 'audit',
191
+ 'record',
192
+ '--json',
193
+ '--kind',
194
+ 'llm_call',
195
+ ];
196
+
197
+ if (payload.issueId) {
198
+ args.push('--issue-id', payload.issueId);
199
+ }
200
+
201
+ args.push(
202
+ '--model',
203
+ payload.model,
204
+ '--prompt',
205
+ payload.prompt,
206
+ '--response',
207
+ payload.response,
208
+ );
209
+
210
+ if (metaJsonSupported && Object.keys(payload.metadata).length > 0) {
211
+ args.push('--meta-json', JSON.stringify(payload.metadata));
212
+ }
213
+
214
+ const output = runCommand('bd', args, { cwd: options.cwd || process.cwd() });
215
+ const entryId = parseRecordId(output, { requireJson: true });
216
+ const fallback = metaJsonSupported ? null : writeFallbackMetadata(payload, entryId, options);
217
+
218
+ return {
219
+ success: Boolean(entryId),
220
+ entryId,
221
+ output,
222
+ payload,
223
+ fallback,
224
+ };
225
+ }
226
+
227
+ function labelSubagentAuditEvent(entryId, event, options = {}) {
228
+ const verdict = String(event?.verdict || '').toUpperCase();
229
+ const role = event?.role;
230
+ const label = VERDICT_LABELS[verdict];
231
+
232
+ if (!entryId || !REVIEWER_ROLES.has(role) || !label) {
233
+ return { skipped: true };
234
+ }
235
+
236
+ const runCommand = options.runCommand || defaultRunCommand;
237
+ const reason = `${role} verdict: ${verdict}`;
238
+ let output;
239
+ try {
240
+ output = runCommand('bd', [
241
+ 'audit',
242
+ 'label',
243
+ entryId,
244
+ '--json',
245
+ '--label',
246
+ label,
247
+ '--reason',
248
+ reason,
249
+ ], { cwd: options.cwd || process.cwd() });
250
+ } catch (error) {
251
+ return {
252
+ success: false,
253
+ label,
254
+ error: error.message,
255
+ };
256
+ }
257
+
258
+ const labeledEntryId = parseRecordId(output, { requireJson: true });
259
+
260
+ return {
261
+ success: labeledEntryId === entryId,
262
+ label,
263
+ entryId: labeledEntryId,
264
+ output,
265
+ };
266
+ }
267
+
268
+ function recordAndLabelSubagentAuditEvent(event, options = {}) {
269
+ const record = recordSubagentAuditEvent(event, options);
270
+ const label = labelSubagentAuditEvent(record.entryId, event, options);
271
+ return { record, label };
272
+ }
273
+
274
+ module.exports = {
275
+ VERDICT_LABELS,
276
+ buildSubagentAuditPayload,
277
+ recordSubagentAuditEvent,
278
+ labelSubagentAuditEvent,
279
+ recordAndLabelSubagentAuditEvent,
280
+ hasAuditMetaJsonSupport,
281
+ redact,
282
+ };
@@ -2,7 +2,7 @@
2
2
  * Utilities for configuring Beads during `forge setup`.
3
3
  *
4
4
  * Handles prefix sanitization, config/gitignore generation,
5
- * initialization detection, and issues.jsonl pre-seeding.
5
+ * initialization detection, and legacy JSONL compatibility shims.
6
6
  *
7
7
  * @module beads-setup
8
8
  */
@@ -10,6 +10,22 @@
10
10
  const fs = require('node:fs');
11
11
  const path = require('node:path');
12
12
  const { spawnSync } = require('node:child_process');
13
+ const { secureExecFileSync } = require('./shell-utils');
14
+
15
+ const BEADS_LOCAL_EXCLUDE_LINES = [
16
+ '# Forge local Beads state',
17
+ '.beads/',
18
+ '.dolt/',
19
+ '.beads-credential-key'
20
+ ];
21
+
22
+ function isIgnorableFsError(error) {
23
+ return ['EACCES', 'ENOENT', 'ENOTDIR', 'EPERM'].includes(error?.code);
24
+ }
25
+
26
+ function isRecoverableCommandError(error) {
27
+ return error?.code === 'ENOENT' || typeof error?.status === 'number';
28
+ }
13
29
 
14
30
  /**
15
31
  * Resolve a command to its full path to avoid relying on inherited PATH.
@@ -24,7 +40,10 @@ function resolveCommand(command) {
24
40
  if (result.status === 0 && result.stdout) {
25
41
  return result.stdout.trim().split(/\r?\n/)[0].trim();
26
42
  }
27
- } catch (_e) {
43
+ } catch (error) {
44
+ if (!isRecoverableCommandError(error)) {
45
+ throw error;
46
+ }
28
47
  // Expected: command resolution may fail if 'which'/'where.exe' is unavailable — fall back to bare command name
29
48
  }
30
49
  return command;
@@ -91,6 +110,10 @@ function writeBeadsGitignore(projectRoot) {
91
110
  fs.mkdirSync(beadsDir, { recursive: true });
92
111
 
93
112
  const gitignoreContent = [
113
+ '# Beads runtime, export, and backup state is local',
114
+ '*',
115
+ '!.gitignore',
116
+ '',
94
117
  '# Dolt database files (binary, not suitable for git)',
95
118
  'dolt/',
96
119
  '*.db',
@@ -105,13 +128,120 @@ function writeBeadsGitignore(projectRoot) {
105
128
  );
106
129
  }
107
130
 
131
+ function resolveGitInfoExcludePath(projectRoot) {
132
+ try {
133
+ const gitExcludePath = secureExecFileSync(resolveCommand('git'), ['rev-parse', '--git-path', 'info/exclude'], {
134
+ cwd: projectRoot,
135
+ encoding: 'utf8',
136
+ stdio: 'pipe'
137
+ }).trim();
138
+
139
+ if (gitExcludePath) {
140
+ return path.isAbsolute(gitExcludePath)
141
+ ? gitExcludePath
142
+ : path.resolve(projectRoot, gitExcludePath);
143
+ }
144
+ } catch (error) {
145
+ if (!isRecoverableCommandError(error)) {
146
+ throw error;
147
+ }
148
+ }
149
+
150
+ return path.join(projectRoot, '.git', 'info', 'exclude');
151
+ }
152
+
153
+ function untrackExistingBeadsState(projectRoot) {
154
+ let tracked;
155
+ try {
156
+ tracked = secureExecFileSync(resolveCommand('git'), [
157
+ 'ls-files',
158
+ '-z',
159
+ '--',
160
+ '.beads',
161
+ '.dolt',
162
+ '.beads-credential-key'
163
+ ], {
164
+ cwd: projectRoot,
165
+ encoding: 'utf8',
166
+ stdio: 'pipe'
167
+ });
168
+ } catch (error) {
169
+ if (!isRecoverableCommandError(error)) {
170
+ throw error;
171
+ }
172
+ return;
173
+ }
174
+
175
+ if (!tracked) {
176
+ return;
177
+ }
178
+
179
+ try {
180
+ secureExecFileSync(resolveCommand('git'), [
181
+ 'rm',
182
+ '--cached',
183
+ '-r',
184
+ '-f',
185
+ '--ignore-unmatch',
186
+ '--',
187
+ '.beads',
188
+ '.dolt',
189
+ '.beads-credential-key'
190
+ ], {
191
+ cwd: projectRoot,
192
+ encoding: 'utf8',
193
+ stdio: 'pipe'
194
+ });
195
+ } catch (error) {
196
+ if (!isRecoverableCommandError(error)) {
197
+ throw error;
198
+ }
199
+ }
200
+ }
201
+
202
+ /**
203
+ * Add local-only Git exclude rules for Beads state.
204
+ *
205
+ * Uses `.git/info/exclude` instead of the tracked `.gitignore` so `forge setup`
206
+ * does not dirty downstream repositories just to keep Beads runtime files local.
207
+ * Existing tracked Beads state is removed from the Git index only, leaving local
208
+ * files in place for the Beads runtime.
209
+ *
210
+ * @param {string} projectRoot - Absolute path to the project root
211
+ */
212
+ function ensureBeadsGitExclude(projectRoot) {
213
+ const excludePath = resolveGitInfoExcludePath(projectRoot);
214
+ fs.mkdirSync(path.dirname(excludePath), { recursive: true });
215
+
216
+ const existing = fs.existsSync(excludePath)
217
+ ? fs.readFileSync(excludePath, 'utf8')
218
+ : '';
219
+ const existingLines = new Set(existing.split(/\r?\n/));
220
+ const missingLines = BEADS_LOCAL_EXCLUDE_LINES.filter((line) => !existingLines.has(line));
221
+
222
+ if (missingLines.length === 0) {
223
+ untrackExistingBeadsState(projectRoot);
224
+ return;
225
+ }
226
+
227
+ const prefix = existing && !existing.endsWith('\n') ? '\n' : '';
228
+ const spacer = existing.trim() ? '\n' : '';
229
+ fs.appendFileSync(excludePath, `${prefix}${spacer}${missingLines.join('\n')}\n`, 'utf8');
230
+ untrackExistingBeadsState(projectRoot);
231
+ }
232
+
108
233
  /**
109
234
  * Check whether Beads is properly initialized in a project.
110
235
  *
111
- * Returns `true` only when all of the following are present:
236
+ * Returns `true` when all of the following are present:
112
237
  * - `.beads/` directory exists
113
238
  * - `.beads/config.yaml` exists and contains an `issue-prefix` key
114
- * - `.beads/issues.jsonl` exists
239
+ * - the config points to either:
240
+ * - a legacy SQLite tracker with legacy data markers present, or
241
+ * - a Dolt-backed tracker with at least one post-`bd init` marker present
242
+ *
243
+ * Legacy SQLite-backed Beads installs also count as initialized so `forge setup`
244
+ * does not run `bd init` over an existing tracker before migration.
115
245
  *
116
246
  * @param {string} projectRoot - Absolute path to the project root
117
247
  * @returns {boolean} `true` if Beads is fully initialized
@@ -119,34 +249,74 @@ function writeBeadsGitignore(projectRoot) {
119
249
  function isBeadsInitialized(projectRoot) {
120
250
  const beadsDir = path.join(projectRoot, '.beads');
121
251
  const configPath = path.join(beadsDir, 'config.yaml');
122
- const jsonlPath = path.join(beadsDir, 'issues.jsonl');
123
252
 
124
253
  if (!fs.existsSync(beadsDir)) return false;
125
254
  if (!fs.existsSync(configPath)) return false;
126
- if (!fs.existsSync(jsonlPath)) return false;
127
255
 
128
256
  const configContent = fs.readFileSync(configPath, 'utf8');
129
257
  if (!configContent.includes('issue-prefix:')) return false;
130
258
 
131
- return true;
259
+ const hasLegacyState = [
260
+ 'issues.jsonl',
261
+ 'backup',
262
+ 'bd.db',
263
+ 'beads.db',
264
+ 'db.sqlite'
265
+ ].some((entry) => fs.existsSync(path.join(beadsDir, entry)));
266
+ const hasDoltMetadata = fs.existsSync(path.join(beadsDir, 'metadata.json'));
267
+ const hasDoltCompanionState = [
268
+ 'README.md',
269
+ 'hooks',
270
+ 'redirect'
271
+ ].some((entry) => fs.existsSync(path.join(beadsDir, entry)));
272
+ const hasDoltState = hasDoltMetadata && hasDoltCompanionState;
273
+
274
+ if (configContent.includes('backend: sqlite')) {
275
+ return hasLegacyState;
276
+ }
277
+
278
+ if (configContent.includes('backend: dolt')) {
279
+ return hasDoltState;
280
+ }
281
+
282
+ return hasLegacyState || hasDoltState;
283
+ }
284
+
285
+ function readBeadsDatabaseName(projectRoot) {
286
+ const metadataPath = path.join(projectRoot, '.beads', 'metadata.json');
287
+ if (!fs.existsSync(metadataPath)) {
288
+ return null;
289
+ }
290
+
291
+ try {
292
+ const metadata = JSON.parse(fs.readFileSync(metadataPath, 'utf8'));
293
+ if (typeof metadata.dolt_database === 'string' && metadata.dolt_database.trim()) {
294
+ return metadata.dolt_database.trim();
295
+ }
296
+ if (typeof metadata.database === 'string' && metadata.database.trim()) {
297
+ return metadata.database.trim();
298
+ }
299
+ } catch (error) {
300
+ if (error instanceof SyntaxError || isIgnorableFsError(error)) {
301
+ return null;
302
+ }
303
+ throw error;
304
+ }
305
+
306
+ return null;
132
307
  }
133
308
 
134
309
  /**
135
- * Ensure `issues.jsonl` exists inside `.beads/`.
310
+ * Legacy compatibility shim for the removed JSONL pre-seed workaround.
136
311
  *
137
- * Creates the `.beads/` directory and an empty `issues.jsonl` if either
138
- * is missing. Leaves an existing `issues.jsonl` untouched.
312
+ * Beads latest no longer requires `.beads/issues.jsonl` during init, so
313
+ * this helper intentionally does nothing. It remains exported because some
314
+ * older tests and setup paths still import it.
139
315
  *
140
- * @param {string} projectRoot - Absolute path to the project root
316
+ * @param {string} _projectRoot - Absolute path to the project root
141
317
  */
142
- function preSeedJsonl(projectRoot) {
143
- const beadsDir = path.join(projectRoot, '.beads');
144
- fs.mkdirSync(beadsDir, { recursive: true });
145
-
146
- const jsonlPath = path.join(beadsDir, 'issues.jsonl');
147
- if (!fs.existsSync(jsonlPath)) {
148
- fs.writeFileSync(jsonlPath, '', 'utf8');
149
- }
318
+ function preSeedJsonl(_projectRoot) {
319
+ // Legacy no-op: Dolt-backed Beads no longer requires JSONL pre-seeding.
150
320
  }
151
321
 
152
322
  // ---------------------------------------------------------------------------
@@ -212,6 +382,31 @@ function restoreDirectory(dirPath, snapshot) {
212
382
  }
213
383
  }
214
384
 
385
+ function resolveHooksDir(projectRoot) {
386
+ const fallbackHooksDir = path.join(projectRoot, '.git', 'hooks');
387
+
388
+ try {
389
+ const gitHooksPath = secureExecFileSync(resolveCommand('git'), ['rev-parse', '--git-path', 'hooks'], {
390
+ cwd: projectRoot,
391
+ encoding: 'utf8',
392
+ stdio: 'pipe'
393
+ }).trim();
394
+
395
+ if (!gitHooksPath) {
396
+ return fallbackHooksDir;
397
+ }
398
+
399
+ return path.isAbsolute(gitHooksPath)
400
+ ? gitHooksPath
401
+ : path.resolve(projectRoot, gitHooksPath);
402
+ } catch (error) {
403
+ if (isRecoverableCommandError(error)) {
404
+ return fallbackHooksDir;
405
+ }
406
+ throw error;
407
+ }
408
+ }
409
+
215
410
  /**
216
411
  * Default bd init executor — calls `execFileSync('bd', ['init'])`.
217
412
  *
@@ -237,7 +432,7 @@ function defaultExecBdInit(projectRoot) {
237
432
  * e. Run bd init (via execBdInit callback or default execFileSync)
238
433
  * f. Restore .git/hooks/ from snapshot
239
434
  * g. Restore lefthook hooks if callback provided
240
- * h. Pre-seed issues.jsonl
435
+ * h. Skip the removed issues.jsonl pre-seed workaround
241
436
  *
242
437
  * @param {string} projectRoot - Absolute path to the project root
243
438
  * @param {Object} [options={}] - Configuration options
@@ -252,6 +447,13 @@ function safeBeadsInit(projectRoot, options = {}) {
252
447
  const warnings = [];
253
448
  const errors = [];
254
449
 
450
+ // Keep Beads runtime/export state local even when the tracker already exists.
451
+ try {
452
+ ensureBeadsGitExclude(projectRoot);
453
+ } catch (err) {
454
+ warnings.push(`Failed to write local Beads git exclude rules: ${err.message}`);
455
+ }
456
+
255
457
  // (a) Check if already initialized — idempotent skip
256
458
  if (isBeadsInitialized(projectRoot)) {
257
459
  return {
@@ -279,7 +481,7 @@ function safeBeadsInit(projectRoot, options = {}) {
279
481
  }
280
482
 
281
483
  // (d) Snapshot current .git/hooks/ directory
282
- const hooksDir = path.join(projectRoot, '.git', 'hooks');
484
+ const hooksDir = resolveHooksDir(projectRoot);
283
485
  const hooksSnapshot = snapshotDirectory(hooksDir);
284
486
 
285
487
  // (e) Run bd init — wrapped in try/catch
@@ -316,13 +518,6 @@ function safeBeadsInit(projectRoot, options = {}) {
316
518
  }
317
519
  }
318
520
 
319
- // (h) Pre-seed JSONL if empty
320
- try {
321
- preSeedJsonl(projectRoot);
322
- } catch (err) {
323
- warnings.push(`Failed to pre-seed issues.jsonl: ${err.message}`);
324
- }
325
-
326
521
  return {
327
522
  success: true,
328
523
  skipped: false,
@@ -335,7 +530,9 @@ module.exports = {
335
530
  sanitizePrefix,
336
531
  writeBeadsConfig,
337
532
  writeBeadsGitignore,
533
+ ensureBeadsGitExclude,
338
534
  isBeadsInitialized,
535
+ readBeadsDatabaseName,
339
536
  preSeedJsonl,
340
537
  safeBeadsInit
341
538
  };