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,184 @@
1
+ 'use strict';
2
+
3
+ const STOP_WORDS = new Set([
4
+ 'the',
5
+ 'a',
6
+ 'an',
7
+ 'and',
8
+ 'or',
9
+ 'is',
10
+ 'in',
11
+ 'to',
12
+ 'for',
13
+ 'of',
14
+ 'with',
15
+ 'on',
16
+ 'at',
17
+ 'by',
18
+ 'from',
19
+ 'add',
20
+ 'fix',
21
+ 'update',
22
+ 'implement',
23
+ 'create',
24
+ 'remove',
25
+ 'delete',
26
+ 'make',
27
+ 'use',
28
+ 'get',
29
+ 'set',
30
+ 'run',
31
+ 'test',
32
+ 'check',
33
+ 'all',
34
+ 'this',
35
+ 'that',
36
+ 'it',
37
+ 'be',
38
+ 'as',
39
+ 'not',
40
+ 'no',
41
+ 'but',
42
+ 'if',
43
+ 'do',
44
+ 'we',
45
+ 'they',
46
+ 'are',
47
+ 'was',
48
+ 'were',
49
+ 'been',
50
+ 'have',
51
+ 'has',
52
+ 'had',
53
+ 'will',
54
+ 'would',
55
+ 'could',
56
+ 'should',
57
+ 'may',
58
+ 'can',
59
+ 'each',
60
+ 'every',
61
+ 'both',
62
+ 'also',
63
+ 'into',
64
+ 'than',
65
+ 'then',
66
+ 'when',
67
+ 'where',
68
+ 'which',
69
+ 'what',
70
+ 'how',
71
+ 'why',
72
+ 'who',
73
+ 'its',
74
+ 'new',
75
+ 'first',
76
+ 'last',
77
+ 'same',
78
+ 'other',
79
+ ]);
80
+
81
+ function tokenizeMeaningfulTerms(title) {
82
+ return [...new Set(
83
+ String(title ?? '')
84
+ .toLowerCase()
85
+ .split(/[^a-z]+/u)
86
+ .filter((term) => term.length >= 3)
87
+ .filter((term) => !STOP_WORDS.has(term)),
88
+ )].sort((left, right) => left.localeCompare(right));
89
+ }
90
+
91
+ function collectSharedTerms(sourceTerms, candidateTerms) {
92
+ const candidateSet = new Set(candidateTerms);
93
+ return sourceTerms.filter((term) => candidateSet.has(term));
94
+ }
95
+
96
+ function isInProgressLine(line) {
97
+ return line.includes('◐') || line.includes('◐');
98
+ }
99
+
100
+ function parseActiveIssueLines(listOutput) {
101
+ return String(listOutput ?? '')
102
+ .split(/\r?\n/u)
103
+ .map((line) => line.trim())
104
+ .filter(Boolean)
105
+ .map((line) => {
106
+ const idMatch = /forge-[a-zA-Z0-9]+(?:\.[a-zA-Z0-9]+)*/u.exec(line);
107
+ if (!idMatch) {
108
+ return null;
109
+ }
110
+
111
+ const titleIndex = line.indexOf(' - ');
112
+ const priorityMatch = /P\d+/u.exec(line);
113
+ return {
114
+ id: idMatch[0],
115
+ priority: priorityMatch ? priorityMatch[0] : 'P2',
116
+ status: isInProgressLine(line) ? 'in_progress' : 'open',
117
+ title: titleIndex >= 0 ? line.slice(titleIndex + 3).trim() : '',
118
+ };
119
+ })
120
+ .filter(Boolean);
121
+ }
122
+
123
+ function renderKeywordRippleReport({ issueId, sourceTitle, activeIssues }) {
124
+ const sourceTerms = tokenizeMeaningfulTerms(sourceTitle);
125
+ const overlaps = [];
126
+
127
+ for (const candidate of activeIssues ?? []) {
128
+ if (!candidate || candidate.id === issueId) {
129
+ continue;
130
+ }
131
+
132
+ const sharedTerms = collectSharedTerms(sourceTerms, tokenizeMeaningfulTerms(candidate.title));
133
+ if (sharedTerms.length < 2) {
134
+ continue;
135
+ }
136
+
137
+ overlaps.push({
138
+ id: candidate.id,
139
+ priority: candidate.priority || 'P2',
140
+ status: candidate.status || 'open',
141
+ title: candidate.title || '',
142
+ sharedTerms,
143
+ });
144
+ }
145
+
146
+ if (overlaps.length === 0) {
147
+ return {
148
+ overlapCount: 0,
149
+ overlaps,
150
+ output: 'No conflicts detected',
151
+ };
152
+ }
153
+
154
+ const lines = [`Potential overlap with ${overlaps.length} issue(s):`, ''];
155
+ for (const overlap of overlaps) {
156
+ const renderedSharedTerms = overlap.sharedTerms.map((term) => `"${term}"`).join(', ');
157
+ lines.push(
158
+ ` ${overlap.id} (${overlap.status}, ${overlap.priority}): "${overlap.title}"`,
159
+ ` Overlap: keyword match - ${renderedSharedTerms}`,
160
+ ' Confidence: LOW (keyword only, no contract data)',
161
+ '',
162
+ ' Options:',
163
+ ` (a) Add dependency: forge issue dep add ${issueId} ${overlap.id}`,
164
+ ' (b) Proceed - no real conflict',
165
+ ` (c) Investigate: forge issue show ${overlap.id}`,
166
+ '',
167
+ );
168
+ }
169
+
170
+ return {
171
+ overlapCount: overlaps.length,
172
+ overlaps,
173
+ output: lines.join('\n').trimEnd(),
174
+ };
175
+ }
176
+
177
+ module.exports = {
178
+ STOP_WORDS,
179
+ collectSharedTerms,
180
+ isInProgressLine,
181
+ parseActiveIssueLines,
182
+ renderKeywordRippleReport,
183
+ tokenizeMeaningfulTerms,
184
+ };
@@ -0,0 +1,362 @@
1
+ 'use strict';
2
+
3
+ const crypto = require('node:crypto');
4
+ const fs = require('node:fs');
5
+ const path = require('node:path');
6
+
7
+ const DEPRECATED_SYNC_FILES = [
8
+ '.github/workflows/github-to-beads.yml',
9
+ '.github/workflows/beads-to-github.yml',
10
+ '.github/beads-mapping.json',
11
+ '.github/beads-sync-config.json',
12
+ '.github/scripts/beads-sync/comment.mjs',
13
+ '.github/scripts/beads-sync/config.mjs',
14
+ '.github/scripts/beads-sync/github-api.mjs',
15
+ '.github/scripts/beads-sync/index.mjs',
16
+ '.github/scripts/beads-sync/label-mapper.mjs',
17
+ '.github/scripts/beads-sync/mapping.mjs',
18
+ '.github/scripts/beads-sync/reverse-sync.mjs',
19
+ '.github/scripts/beads-sync/reverse-sync-cli.mjs',
20
+ '.github/scripts/beads-sync/run-bd.mjs',
21
+ '.github/scripts/beads-sync/sanitize.mjs',
22
+ 'scripts/github-beads-sync.config.json',
23
+ 'scripts/github-beads-sync/comment.mjs',
24
+ 'scripts/github-beads-sync/config.mjs',
25
+ 'scripts/github-beads-sync/github-api.mjs',
26
+ 'scripts/github-beads-sync/index.mjs',
27
+ 'scripts/github-beads-sync/label-mapper.mjs',
28
+ 'scripts/github-beads-sync/mapping.mjs',
29
+ 'scripts/github-beads-sync/reverse-sync.mjs',
30
+ 'scripts/github-beads-sync/reverse-sync-cli.mjs',
31
+ 'scripts/github-beads-sync/run-bd.mjs',
32
+ 'scripts/github-beads-sync/sanitize.mjs'
33
+ ];
34
+
35
+ const DEPRECATED_SYNC_FILE_SET = new Set(DEPRECATED_SYNC_FILES);
36
+
37
+ const DEPRECATED_SYNC_DIRS = [
38
+ 'scripts/github-beads-sync',
39
+ '.github/scripts/beads-sync',
40
+ '.github/scripts',
41
+ '.github/workflows'
42
+ ];
43
+
44
+ const LEGACY_SYNC_SCAN_DIRS = [
45
+ 'scripts/github-beads-sync',
46
+ '.github/scripts/beads-sync'
47
+ ];
48
+
49
+ const NON_BLOCKING_CUSTOM_SYNC_FILES = new Set([
50
+ '.github/beads-mapping.json',
51
+ '.github/beads-sync-config.json',
52
+ 'scripts/github-beads-sync.config.json'
53
+ ]);
54
+
55
+ const KNOWN_GENERATED_HASHES = new Map([
56
+ ['.github/workflows/github-to-beads.yml', [
57
+ 'f3f18b300f0faada51087b33c1be83fcc80cba75432645707a10188d824558f6',
58
+ 'fa475e7ba914b9e2b95eea0f170e396f9e6e6df87c0ea143f2cfcee18c016ff5',
59
+ '46bc8d78a39641e90b901fa0af10dfd35f28c1eaf14bb5ced504ea915faacd35',
60
+ '074f70345de076acb4b8c2c3e40633b2158ebe0851aaf88b8890b0fc42686585',
61
+ '8345c0875c19887a49472fb3cf03a7ae83348c03c3a05756a92be1f096b6d6ee',
62
+ '5ce4e4229db7d94d6d6fdb5d473a7278f9f0f72c3eb80fc334ea97800aa59b0a',
63
+ '50a0385f6094187ab2978d1442dd269ccbdbbd3818b9aebc1000ac059eb714f6',
64
+ '1d8d1637b75e582b257a0640b8e7efcc747223b55cde249adccd42f65a502839',
65
+ 'e9d14f24f6316369d623dcbcea98695e6ff169929e1b024076a9c6cc071b5fb0',
66
+ '31db1e5aa0947026e9a1ac7a0990a191224580c906a17175196cd2fca40edafa',
67
+ '152a5b54745eb01e9bf51993bdd8885fea429a0e62b13f6319d6f6805a8aba15',
68
+ '17ec1a14f387fdfc2ce4c492b12f0148b0149a1ba5fd7ac123fc2dcd2eba0a68',
69
+ '4f8831c5dd066b45e8aa7b5ed62eaf1d5f8c2ac5be0df97624a5db20668e2973',
70
+ 'dc33a595a08db419daf062f9b0499fb51d44f6d96d8da8123ff6ec65c2ee407c',
71
+ 'f60ed0c74013fa2f4dc29ab67bc506dea9605aee938f6a2b69ea0d117d28a47b',
72
+ 'c9370c43bcfdc97ffb56d8a0e8a20abe24edce12f9939eb3353a561fa3bf1972'
73
+ ]],
74
+ ['.github/workflows/beads-to-github.yml', [
75
+ '62f801b12ddcf4a7e5343ec4e7a4f244f612ebba2f4bf46ba3cc1e7c92374693',
76
+ '0739867fb1e28b3d8d31587f2e7659af493dad1363544332973e5ac38c5c5073',
77
+ '83e9fb3de96cd04ffee1232e6fd91a8322d6231a1a42877993afa78be071656e'
78
+ ]],
79
+ ['.github/beads-mapping.json', [
80
+ 'ca3d163bab055381827226140568f3bef7eaac187cebd76878e0b63e9e442356',
81
+ '44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a'
82
+ ]],
83
+ ['.github/beads-sync-config.json', '737be9ca940b3f6c059a229ffed84d3dedd2c871682c4923f780e59ba6be45ea'],
84
+ ['.github/scripts/beads-sync/comment.mjs', 'af03fe24e7a7c302b73ccfe400e456dae61f6729369ff15ca64b429f8eb59816'],
85
+ ['.github/scripts/beads-sync/config.mjs', '9c7537d1f93f4fafdb6370b0c03c3f77c6daa20dd302b12a2de89af941a71464'],
86
+ ['.github/scripts/beads-sync/github-api.mjs', 'a730e6be6b51efffb486ee61ca555714d3e3ba5fc829ef567a92ff4a2d3dba17'],
87
+ ['.github/scripts/beads-sync/index.mjs', 'ba655a7d0b4cea9ff3c1f8f81cb54a60a32212e187679990438dec02b42f8262'],
88
+ ['.github/scripts/beads-sync/label-mapper.mjs', 'c9427ceecd8a2d35c0ec2b6e8eb0491a368ff4a15c30db9d9f7a1f7283d6aceb'],
89
+ ['.github/scripts/beads-sync/mapping.mjs', '716ec16887ae632dd834ea3b8a0397ef14231128f5b398e66d148d5e2135a7f8'],
90
+ ['.github/scripts/beads-sync/reverse-sync-cli.mjs', 'b9dd3b88555893f46a7a47e1e31ec883822ee7e73dc4e1eaad14fc33a1080e3b'],
91
+ ['.github/scripts/beads-sync/reverse-sync.mjs', '70df756f23db182e8e21cff6f492e4c262e9b0475ca1fcf1c1938888b3b9c611'],
92
+ ['.github/scripts/beads-sync/run-bd.mjs', '4154636d43be89a0cea9e00b4e587acd9c9caf3e17b6d0aac305d5f6a34ec96d'],
93
+ ['.github/scripts/beads-sync/sanitize.mjs', 'c3f227d18e7cb1d0ab1dd7c622b1c7dd5e05c0c180e6603a1e3ac524bbf2e47b'],
94
+ ['scripts/github-beads-sync.config.json', '737be9ca940b3f6c059a229ffed84d3dedd2c871682c4923f780e59ba6be45ea'],
95
+ ['scripts/github-beads-sync/comment.mjs', 'af03fe24e7a7c302b73ccfe400e456dae61f6729369ff15ca64b429f8eb59816'],
96
+ ['scripts/github-beads-sync/config.mjs', '9c7537d1f93f4fafdb6370b0c03c3f77c6daa20dd302b12a2de89af941a71464'],
97
+ ['scripts/github-beads-sync/github-api.mjs', 'a730e6be6b51efffb486ee61ca555714d3e3ba5fc829ef567a92ff4a2d3dba17'],
98
+ ['scripts/github-beads-sync/index.mjs', [
99
+ 'a4df5082f0cf7f93e46299e04aaa29ba5846379ab389d68551e26ca710c90ed3',
100
+ '0ae43e46c9552a907c3efc619724ada95e2345046750309e23d680d7f8b5781d',
101
+ '6cb8c5d2b7831d2d994df4c540e5f2ec02244bfb994b59af1424cbee387ec837',
102
+ 'ba655a7d0b4cea9ff3c1f8f81cb54a60a32212e187679990438dec02b42f8262'
103
+ ]],
104
+ ['scripts/github-beads-sync/label-mapper.mjs', 'c9427ceecd8a2d35c0ec2b6e8eb0491a368ff4a15c30db9d9f7a1f7283d6aceb'],
105
+ ['scripts/github-beads-sync/mapping.mjs', [
106
+ '098f79f78929dfba7bb4a9c5b76c51e37e71e2c0d6bcb1016afaaaf6df789b94',
107
+ '716ec16887ae632dd834ea3b8a0397ef14231128f5b398e66d148d5e2135a7f8'
108
+ ]],
109
+ ['scripts/github-beads-sync/reverse-sync-cli.mjs', [
110
+ '1b88004657678ae2ac7908edd18a7b971928aa9830fd5525842d0b0ddf158d20',
111
+ 'b9dd3b88555893f46a7a47e1e31ec883822ee7e73dc4e1eaad14fc33a1080e3b'
112
+ ]],
113
+ ['scripts/github-beads-sync/reverse-sync.mjs', [
114
+ '4da1bf5f5d5253dee4c77cbfea4e9dd86d9e0a267d46197e5eecab5a3f9b5687',
115
+ 'f33adf1a2d6a7a7437e0efd6cb7f223843d522e82d7061ac355ea2909dbb7624',
116
+ '70df756f23db182e8e21cff6f492e4c262e9b0475ca1fcf1c1938888b3b9c611'
117
+ ]],
118
+ ['scripts/github-beads-sync/run-bd.mjs', [
119
+ '6d9117b1f7e4d0628941a30773da183dc2ff8e5e5357e4ae897c381dba854c38',
120
+ '1af7367645ff03102b2c3253718e360fd829ea4cad95fd50b973ec68b21a0cc1',
121
+ '4154636d43be89a0cea9e00b4e587acd9c9caf3e17b6d0aac305d5f6a34ec96d'
122
+ ]],
123
+ ['scripts/github-beads-sync/sanitize.mjs', 'c3f227d18e7cb1d0ab1dd7c622b1c7dd5e05c0c180e6603a1e3ac524bbf2e47b']
124
+ ]);
125
+
126
+ const GENERATED_MARKERS = [
127
+ 'Generated by Forge GitHub-Beads sync',
128
+ 'forge:deprecated-github-beads-sync'
129
+ ];
130
+
131
+ const BRANCH_TEMPLATED_WORKFLOWS = new Set([
132
+ '.github/workflows/beads-to-github.yml'
133
+ ]);
134
+
135
+ const GENERATED_DEFAULT_BRANCH_VALUES = new Set([
136
+ 'master',
137
+ 'main'
138
+ ]);
139
+
140
+ const BEADS_VERSION_TEMPLATED_WORKFLOWS = new Set([
141
+ '.github/workflows/github-to-beads.yml',
142
+ '.github/workflows/beads-to-github.yml'
143
+ ]);
144
+
145
+ const GENERATED_BEADS_VERSION_VALUES = [
146
+ '0.49.1',
147
+ '1.0.0',
148
+ '__FORGE_BEADS_VERSION__'
149
+ ];
150
+
151
+ function normalizeContent(content) {
152
+ return content.replaceAll(/\r\n/g, '\n');
153
+ }
154
+
155
+ function sha256(content) {
156
+ return crypto.createHash('sha256').update(normalizeContent(content), 'utf8').digest('hex');
157
+ }
158
+
159
+ function generatedDefaultBranchValues(options = {}) {
160
+ const values = new Set(GENERATED_DEFAULT_BRANCH_VALUES);
161
+ const defaultBranch = typeof options.defaultBranch === 'string' ? options.defaultBranch.trim() : '';
162
+ if (defaultBranch) {
163
+ values.add(defaultBranch);
164
+ }
165
+
166
+ return values;
167
+ }
168
+
169
+ function toPortablePath(filePath) {
170
+ return filePath.split(path.sep).join('/');
171
+ }
172
+
173
+ function listFilesRecursively(rootDir) {
174
+ const files = [];
175
+
176
+ if (!fs.existsSync(rootDir)) {
177
+ return files;
178
+ }
179
+
180
+ for (const entry of fs.readdirSync(rootDir, { withFileTypes: true })) {
181
+ const entryPath = path.join(rootDir, entry.name);
182
+ if (entry.isDirectory()) {
183
+ files.push(...listFilesRecursively(entryPath));
184
+ } else if (entry.isFile()) {
185
+ files.push(entryPath);
186
+ }
187
+ }
188
+
189
+ return files;
190
+ }
191
+
192
+ function collectDeprecatedSyncFiles(projectRoot) {
193
+ const files = new Set(DEPRECATED_SYNC_FILES);
194
+
195
+ for (const dir of LEGACY_SYNC_SCAN_DIRS) {
196
+ const scanDir = path.join(projectRoot, dir);
197
+ for (const filePath of listFilesRecursively(scanDir)) {
198
+ files.add(toPortablePath(path.relative(projectRoot, filePath)));
199
+ }
200
+ }
201
+
202
+ return [...files].sort((a, b) => a.localeCompare(b));
203
+ }
204
+
205
+ function generatedHashKeyFor(file) {
206
+ const githubScriptsPrefix = '.github/scripts/beads-sync/';
207
+ if (file.startsWith(githubScriptsPrefix)) {
208
+ return `scripts/github-beads-sync/${file.slice(githubScriptsPrefix.length)}`;
209
+ }
210
+
211
+ if (file === '.github/beads-sync-config.json') {
212
+ return 'scripts/github-beads-sync.config.json';
213
+ }
214
+
215
+ return file;
216
+ }
217
+
218
+ function packageSourceFor(file, packageDir) {
219
+ if (!packageDir) {
220
+ return null;
221
+ }
222
+
223
+ const githubScriptsPrefix = '.github/scripts/beads-sync/';
224
+ if (file.startsWith(githubScriptsPrefix)) {
225
+ return path.join(packageDir, 'scripts', 'github-beads-sync', file.slice(githubScriptsPrefix.length));
226
+ }
227
+
228
+ if (file === '.github/beads-sync-config.json') {
229
+ return path.join(packageDir, 'scripts', 'github-beads-sync.config.json');
230
+ }
231
+
232
+ return path.join(packageDir, file);
233
+ }
234
+
235
+ function normalizedLegacyWorkflowTemplates(file, content, options = {}) {
236
+ const candidates = new Set();
237
+ const addCandidate = (candidate) => {
238
+ if (candidate !== content) {
239
+ candidates.add(candidate);
240
+ }
241
+ };
242
+
243
+ let branchNormalized = content;
244
+ if (BRANCH_TEMPLATED_WORKFLOWS.has(file)) {
245
+ const branchList = content.match(/branches:\s*\[([^\]\r\n]+)\]/);
246
+ const branchName = branchList?.[1]?.trim();
247
+ if (branchName && !branchName.includes(',') && generatedDefaultBranchValues(options).has(branchName)) {
248
+ branchNormalized = content.replace(branchList[0], 'branches: [master]');
249
+ addCandidate(branchNormalized);
250
+ }
251
+ }
252
+
253
+ if (BEADS_VERSION_TEMPLATED_WORKFLOWS.has(file) && /BD_VERSION="[^"\r\n]+"/.test(content)) {
254
+ const bases = new Set([content, branchNormalized]);
255
+ for (const base of bases) {
256
+ for (const version of GENERATED_BEADS_VERSION_VALUES) {
257
+ addCandidate(base
258
+ .replaceAll(/BD_VERSION="[^"\r\n]+"/g, `BD_VERSION="${version}"`)
259
+ .replaceAll(/(- name:\s+Install Beads CLI)(?: \(pinned to v[^)\r\n]+\))?/g, `$1 (pinned to v${version})`));
260
+ }
261
+ }
262
+ }
263
+
264
+ return [...candidates];
265
+ }
266
+
267
+ function isGeneratedLegacySyncFile(projectRoot, file, options = {}) {
268
+ const fullPath = path.join(projectRoot, file);
269
+ if (!fs.existsSync(fullPath) || !fs.statSync(fullPath).isFile()) {
270
+ return false;
271
+ }
272
+
273
+ const content = fs.readFileSync(fullPath, 'utf8');
274
+ const contentHash = sha256(content);
275
+
276
+ const knownHashes = KNOWN_GENERATED_HASHES.get(generatedHashKeyFor(file));
277
+ if (knownHashes === contentHash || (Array.isArray(knownHashes) && knownHashes.includes(contentHash))) {
278
+ return true;
279
+ }
280
+
281
+ for (const templateContent of normalizedLegacyWorkflowTemplates(file, content, options)) {
282
+ const templateHash = sha256(templateContent);
283
+ if (knownHashes === templateHash || (Array.isArray(knownHashes) && knownHashes.includes(templateHash))) {
284
+ return true;
285
+ }
286
+ }
287
+
288
+ const packageSource = packageSourceFor(file, options.packageDir);
289
+ if (packageSource && fs.existsSync(packageSource) && fs.statSync(packageSource).isFile()) {
290
+ const packageContent = fs.readFileSync(packageSource, 'utf8');
291
+ if (sha256(packageContent) === contentHash) {
292
+ return true;
293
+ }
294
+ }
295
+
296
+ return GENERATED_MARKERS.some((marker) => content.includes(marker));
297
+ }
298
+
299
+ function removeDirIfEmpty(projectRoot, dir) {
300
+ const dirPath = path.join(projectRoot, dir);
301
+ try {
302
+ if (fs.existsSync(dirPath) && fs.readdirSync(dirPath).length === 0) {
303
+ fs.rmdirSync(dirPath);
304
+ }
305
+ } catch (error) {
306
+ if (!['ENOENT', 'ENOTEMPTY'].includes(error?.code)) {
307
+ throw error;
308
+ }
309
+ }
310
+ }
311
+
312
+ function cleanupDeprecatedSyncFiles(projectRoot, options = {}) {
313
+ const removed = [];
314
+ const skipped = [];
315
+ const files = collectDeprecatedSyncFiles(projectRoot);
316
+ const entries = files.map((file) => {
317
+ const fullPath = path.join(projectRoot, file);
318
+ const exists = fs.existsSync(fullPath);
319
+ return {
320
+ file,
321
+ fullPath,
322
+ exists,
323
+ generated: exists ? isGeneratedLegacySyncFile(projectRoot, file, options) : false
324
+ };
325
+ });
326
+
327
+ if (entries.some((entry) => (
328
+ entry.exists
329
+ && !entry.generated
330
+ && DEPRECATED_SYNC_FILE_SET.has(entry.file)
331
+ && !NON_BLOCKING_CUSTOM_SYNC_FILES.has(entry.file)
332
+ ))) {
333
+ return { removed, skipped: files };
334
+ }
335
+
336
+ for (const entry of entries) {
337
+ if (!entry.exists) {
338
+ skipped.push(entry.file);
339
+ continue;
340
+ }
341
+
342
+ if (!entry.generated) {
343
+ skipped.push(entry.file);
344
+ continue;
345
+ }
346
+
347
+ fs.rmSync(entry.fullPath, { force: true });
348
+ removed.push(entry.file);
349
+ }
350
+
351
+ for (const dir of DEPRECATED_SYNC_DIRS) {
352
+ removeDirIfEmpty(projectRoot, dir);
353
+ }
354
+
355
+ return { removed, skipped };
356
+ }
357
+
358
+ module.exports = {
359
+ DEPRECATED_SYNC_FILES,
360
+ cleanupDeprecatedSyncFiles,
361
+ isGeneratedLegacySyncFile
362
+ };
@@ -15,21 +15,12 @@ const path = require('node:path');
15
15
 
16
16
  const CANONICAL_AGENT_IDS = new Set([
17
17
  'claude',
18
- 'cline',
19
18
  'codex',
20
- 'copilot',
21
19
  'cursor',
22
- 'kilocode',
23
- 'opencode',
24
- 'roo',
25
20
  ]);
26
21
 
27
22
  const LEGACY_AGENT_ALIASES = Object.freeze({
28
23
  'claude-code': 'claude',
29
- 'github-copilot': 'copilot',
30
- kilo: 'kilocode',
31
- 'kilo-code': 'kilocode',
32
- 'roo-code': 'roo',
33
24
  });
34
25
 
35
26
  /**
@@ -39,7 +30,7 @@ const LEGACY_AGENT_ALIASES = Object.freeze({
39
30
  * @type {Array<[string, string]>}
40
31
  */
41
32
  const AGENT_ENV_VARS = [
42
- // Forge-supported agents only (7 agents)
33
+ // Forge-supported agents only (claude, codex, cursor)
43
34
  // Claude Code (with cowork sub-check handled separately)
44
35
  ['CLAUDECODE', 'claude'],
45
36
  ['CLAUDE_CODE', 'claude'],
@@ -50,13 +41,6 @@ const AGENT_ENV_VARS = [
50
41
  ['CODEX_SANDBOX', 'codex'],
51
42
  ['CODEX_CI', 'codex'],
52
43
  ['CODEX_THREAD_ID', 'codex'],
53
- // OpenCode
54
- ['OPENCODE_CLIENT', 'opencode'],
55
- // GitHub Copilot
56
- ['COPILOT_MODEL', 'copilot'],
57
- ['COPILOT_ALLOW_ALL', 'copilot'],
58
- ['COPILOT_GITHUB_TOKEN', 'copilot'],
59
- // Cline, Roo Code, Kilocode — no env vars (VSCode extensions, config-file-only)
60
44
  ];
61
45
 
62
46
  /**
@@ -65,22 +49,12 @@ const AGENT_ENV_VARS = [
65
49
  * @type {Array<[string, string]>}
66
50
  */
67
51
  const CONFIG_SIGNATURES = [
68
- // Forge-supported agents only (7 agents)
52
+ // Forge-supported agents only (claude, codex, cursor)
69
53
  [path.join('.claude', 'settings.json'), 'claude'],
70
54
  ['.cursorrules', 'cursor'],
71
55
  [path.join('.cursor', 'rules'), 'cursor'],
72
- ['.clinerules', 'cline'],
73
- ['.cline', 'cline'],
74
- [path.join('.roo', 'rules'), 'roo'],
75
- ['.roo', 'roo'],
76
- ['.roorules', 'roo'],
77
- ['.kilo.md', 'kilocode'],
78
- ['.kilocode', 'kilocode'],
79
56
  ['codex.md', 'codex'],
80
57
  ['.codex', 'codex'],
81
- [path.join('.opencode', 'commands'), 'opencode'],
82
- ['.opencode', 'opencode'],
83
- [path.join('.github', 'copilot-instructions.md'), 'copilot'],
84
58
  ];
85
59
 
86
60
  function normalizeAgentId(agentId) {
@@ -3,43 +3,68 @@
3
3
  const { execFileSync } = require('child_process');
4
4
  const path = require('path');
5
5
 
6
+ // This synchronous git spawn can hang on Windows/Node (same class of issue as
7
+ // ba388d01 / #356's Kernel broker fix). A bounded `timeout` makes each spawn
8
+ // fail fast (ETIMEDOUT) instead of hanging forever; git normally answers these
9
+ // in milliseconds, so 30s only guards against a pathological wedge.
10
+ const GIT_SPAWN_TIMEOUT_MS = 30000;
11
+
6
12
  /**
7
13
  * Detect if the current directory is inside a git worktree.
8
14
  * Uses git rev-parse --git-dir vs --git-common-dir — they differ in worktrees.
9
15
  *
10
16
  * @param {string} [cwd=process.cwd()] - Directory to check
11
- * @returns {{ inWorktree: boolean, branch?: string, mainWorktree?: string }}
17
+ * @param {object} [deps] - Injectable dependencies for testing (execFileSync, warn)
18
+ * @returns {{ inWorktree: boolean, branch?: string, mainWorktree?: string, currentWorktree?: string }}
12
19
  */
13
- function detectWorktree(cwd = process.cwd()) {
20
+ function detectWorktree(cwd = process.cwd(), deps = {}) {
21
+ const exec = deps.execFileSync || execFileSync;
22
+ const warn = deps.warn || ((message) => console.warn(message));
23
+
14
24
  try {
15
- const gitDir = execFileSync('git', ['rev-parse', '--git-dir'], {
16
- encoding: 'utf8', cwd, stdio: ['pipe', 'pipe', 'pipe']
25
+ const gitDir = exec('git', ['rev-parse', '--git-dir'], {
26
+ encoding: 'utf8', cwd, stdio: ['pipe', 'pipe', 'pipe'], timeout: GIT_SPAWN_TIMEOUT_MS
17
27
  }).trim();
18
28
 
19
- const gitCommonDir = execFileSync('git', ['rev-parse', '--git-common-dir'], {
20
- encoding: 'utf8', cwd, stdio: ['pipe', 'pipe', 'pipe']
29
+ const gitCommonDir = exec('git', ['rev-parse', '--git-common-dir'], {
30
+ encoding: 'utf8', cwd, stdio: ['pipe', 'pipe', 'pipe'], timeout: GIT_SPAWN_TIMEOUT_MS
21
31
  }).trim();
22
32
 
33
+ // Empty output from either probe is not a valid git dir. Do NOT feed it to
34
+ // path.resolve — an empty string resolves to `cwd`, which would make an
35
+ // empty gitDir compare equal-or-unequal by accident (falsely reporting
36
+ // inWorktree, or returning extra non-fallback fields). Degrade to the
37
+ // documented { inWorktree: false } fallback with a warning instead.
38
+ if (!gitDir || !gitCommonDir) {
39
+ warn('[forge] git worktree detection got empty git dir output '
40
+ + `(gitDir=${JSON.stringify(gitDir)}, gitCommonDir=${JSON.stringify(gitCommonDir)}); `
41
+ + 'falling back to { inWorktree: false }');
42
+ return { inWorktree: false };
43
+ }
44
+
23
45
  // Resolve to absolute paths for reliable comparison
24
46
  const absGitDir = path.resolve(cwd, gitDir);
25
47
  const absCommonDir = path.resolve(cwd, gitCommonDir);
26
48
 
49
+ const branch = exec('git', ['branch', '--show-current'], {
50
+ encoding: 'utf8', cwd, stdio: ['pipe', 'pipe', 'pipe'], timeout: GIT_SPAWN_TIMEOUT_MS
51
+ }).trim();
52
+ const mainWorktree = path.resolve(absCommonDir, '..');
53
+ const currentWorktree = path.resolve(cwd);
54
+
27
55
  // In a worktree, git-dir is like .git/worktrees/<name>
28
56
  // while git-common-dir is the main .git directory
29
57
  if (absGitDir !== absCommonDir) {
30
- const branch = execFileSync('git', ['branch', '--show-current'], {
31
- encoding: 'utf8', cwd, stdio: ['pipe', 'pipe', 'pipe']
32
- }).trim();
33
-
34
- // Main worktree is one level above the common .git dir
35
- const mainWorktree = path.resolve(absCommonDir, '..');
36
-
37
- return { inWorktree: true, branch, mainWorktree };
58
+ return { inWorktree: true, branch, mainWorktree, currentWorktree };
38
59
  }
39
60
 
40
- return { inWorktree: false };
41
- } catch (_err) {
42
- // Not in a git repo or git not available
61
+ return { inWorktree: false, branch, mainWorktree, currentWorktree };
62
+ } catch (err) {
63
+ // Not in a git repo, git not available, or a spawn that hung past the
64
+ // bound (ETIMEDOUT) — none of these should crash the caller. Degrade
65
+ // gracefully to the same shape callers already handle.
66
+ warn(`[forge] git worktree detection failed (${err.code || err.message}); `
67
+ + 'falling back to { inWorktree: false }');
43
68
  return { inWorktree: false };
44
69
  }
45
70
  }