forge-workflow 0.0.10 → 0.1.0-beta.3

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 (468) 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 +82 -5
  5. package/.forge/hooks/forge-native-hook.js +431 -0
  6. package/.forge/protected-paths.yaml +157 -0
  7. package/AGENTS.md +151 -61
  8. package/CHANGELOG.md +709 -0
  9. package/CLAUDE.md +9 -118
  10. package/QUICKSTART.md +175 -0
  11. package/README.md +275 -365
  12. package/bin/forge-cmd.js +120 -9
  13. package/bin/forge-preflight.js +26 -5
  14. package/bin/forge.js +532 -489
  15. package/docs/INDEX.md +93 -0
  16. package/docs/PROJECT_DESIGN.md +685 -0
  17. package/docs/architecture/index.md +66 -0
  18. package/docs/architecture/notes/README.md +35 -0
  19. package/docs/architecture/subsystems/README.md +46 -0
  20. package/docs/forge/TOOLCHAIN.md +670 -0
  21. package/docs/forge/VALIDATION.md +82 -0
  22. package/docs/{AGENT_INSTALL_PROMPT.md → guides/AGENT_INSTALL_PROMPT.md} +3 -3
  23. package/docs/guides/BEADS_GITHUB_SYNC.md +32 -0
  24. package/docs/{ENHANCED_ONBOARDING.md → guides/ENHANCED_ONBOARDING.md} +16 -12
  25. package/docs/guides/GREPTILE_SETUP.md +46 -0
  26. package/docs/guides/MANUAL_REVIEW_GUIDE.md +58 -0
  27. package/docs/guides/MIGRATION.md +56 -0
  28. package/docs/guides/SETUP.md +121 -0
  29. package/docs/guides/SUPPORT.md +190 -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 +214 -0
  35. package/docs/reference/DECISION_DRIFT_GUARDS.md +97 -0
  36. package/docs/{EXAMPLES.md → reference/EXAMPLES.md} +7 -5
  37. package/docs/reference/FORGE_KERNEL_STORAGE_MODEL.md +135 -0
  38. package/docs/reference/HERMES_INTEGRATION.md +118 -0
  39. package/docs/reference/INSIGHTS_RECAP.md +63 -0
  40. package/docs/reference/INSTALL.md +164 -0
  41. package/docs/reference/KERNEL_TAXONOMY_VALIDATION.md +161 -0
  42. package/docs/reference/PROTECTED_PATH_MANIFEST.md +25 -0
  43. package/docs/reference/RELEASE.md +68 -0
  44. package/docs/reference/RESEARCH_TEMPLATE.md +292 -0
  45. package/docs/{ROADMAP.md → reference/ROADMAP.md} +12 -9
  46. package/docs/reference/SKILLS.md +35 -0
  47. package/docs/reference/STATUS_BOARD.md +80 -0
  48. package/docs/reference/TEMPLATES.md +106 -0
  49. package/docs/{TOOLCHAIN.md → reference/TOOLCHAIN.md} +62 -47
  50. package/docs/reference/VALIDATION.md +82 -0
  51. package/docs/reference/agent-permissions.md +169 -0
  52. package/docs/reference/beads-to-kernel-migration-ux.md +61 -0
  53. package/docs/reference/control-plane-guarantees.md +125 -0
  54. package/docs/reference/dependency-chain.md +331 -0
  55. package/docs/reference/forge-kernel-issue-command-contract.md +161 -0
  56. package/docs/reference/forge-kernel-schema.md +72 -0
  57. package/docs/reference/kernel-conflict-evaluators.md +27 -0
  58. package/docs/reference/patch-md-format.md +77 -0
  59. package/docs/reference/protected-state-surfaces.md +59 -0
  60. package/docs/reference/shepherd.md +155 -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/activation/ensure-forge-home.js +135 -0
  67. package/lib/adapter-cli.js +307 -0
  68. package/lib/adapters/beads-issue-adapter.js +127 -0
  69. package/lib/adapters/beads-kernel-compat.js +1109 -0
  70. package/lib/adapters/greptile-review-adapter.js +141 -0
  71. package/lib/adapters/kernel-issue-adapter.js +101 -0
  72. package/lib/adapters/pr-state-adapter.js +484 -0
  73. package/lib/adoption-profiles.js +139 -0
  74. package/lib/agents/README.md +2 -6
  75. package/lib/agents/claude.plugin.json +3 -8
  76. package/lib/agents/codex.plugin.json +9 -1
  77. package/lib/agents/cursor.plugin.json +2 -6
  78. package/lib/agents/hermes.plugin.json +22 -0
  79. package/lib/agents-config.js +39 -1236
  80. package/lib/audit-evidence.js +282 -0
  81. package/lib/beads-detect.js +60 -0
  82. package/lib/beads-nudge.js +91 -0
  83. package/lib/beads-setup.js +121 -0
  84. package/lib/beads-sync-scaffold.js +25 -101
  85. package/lib/codex-skills.js +51 -1
  86. package/lib/commands/_aliases.js +248 -0
  87. package/lib/commands/_issue.js +780 -77
  88. package/lib/commands/_manifest.js +93 -0
  89. package/lib/commands/_registry.js +99 -34
  90. package/lib/commands/_resolve-command-opts.js +230 -0
  91. package/lib/commands/_serve-security.js +270 -0
  92. package/lib/commands/adapter.js +12 -0
  93. package/lib/commands/add.js +118 -0
  94. package/lib/commands/audit.js +70 -0
  95. package/lib/commands/blocked.js +5 -0
  96. package/lib/commands/board.js +64 -0
  97. package/lib/commands/claim.js +21 -2
  98. package/lib/commands/claims.js +7 -0
  99. package/lib/commands/clean.js +485 -75
  100. package/lib/commands/close.js +2 -2
  101. package/lib/commands/comment.js +5 -0
  102. package/lib/commands/control.js +148 -0
  103. package/lib/commands/create.js +2 -2
  104. package/lib/commands/dev.js +185 -7
  105. package/lib/commands/doc-gate.js +336 -0
  106. package/lib/commands/doctor.js +156 -0
  107. package/lib/commands/explain.js +15 -0
  108. package/lib/commands/export.js +237 -0
  109. package/lib/commands/gate.js +209 -0
  110. package/lib/commands/hooks.js +377 -0
  111. package/lib/commands/inbox.js +118 -0
  112. package/lib/commands/init.js +604 -0
  113. package/lib/commands/insights.js +79 -0
  114. package/lib/commands/issue.js +12 -1
  115. package/lib/commands/issues.js +17 -0
  116. package/lib/commands/lint.js +5 -0
  117. package/lib/commands/list.js +2 -2
  118. package/lib/commands/memory.js +81 -0
  119. package/lib/commands/merge.js +312 -0
  120. package/lib/commands/migrate.js +362 -0
  121. package/lib/commands/new.js +12 -0
  122. package/lib/commands/options.js +241 -0
  123. package/lib/commands/orient.js +13 -0
  124. package/lib/commands/orphans.js +5 -0
  125. package/lib/commands/patch.js +67 -0
  126. package/lib/commands/plan.js +481 -29
  127. package/lib/commands/pr.js +88 -0
  128. package/lib/commands/preflight.js +211 -0
  129. package/lib/commands/prime.js +13 -0
  130. package/lib/commands/push.js +135 -2
  131. package/lib/commands/ready.js +2 -2
  132. package/lib/commands/recall.js +171 -0
  133. package/lib/commands/recap.js +75 -0
  134. package/lib/commands/recommend.js +0 -1
  135. package/lib/commands/release.js +104 -0
  136. package/lib/commands/remember.js +140 -0
  137. package/lib/commands/role.js +99 -0
  138. package/lib/commands/serve.js +581 -0
  139. package/lib/commands/setup.js +900 -971
  140. package/lib/commands/shepherd.js +501 -0
  141. package/lib/commands/ship.js +59 -1
  142. package/lib/commands/show.js +2 -2
  143. package/lib/commands/stage.js +192 -0
  144. package/lib/commands/stale.js +5 -0
  145. package/lib/commands/status.js +158 -21
  146. package/lib/commands/sync.js +34 -46
  147. package/lib/commands/team.js +4 -1
  148. package/lib/commands/test.js +43 -27
  149. package/lib/commands/update.js +2 -2
  150. package/lib/commands/upgrade.js +47 -0
  151. package/lib/commands/validate.js +43 -18
  152. package/lib/commands/worktree.js +362 -99
  153. package/lib/config-writer.js +202 -0
  154. package/lib/control-plane.js +236 -0
  155. package/lib/core/runtime-graph.js +977 -0
  156. package/lib/dep-guard/keyword-ripple.js +2 -2
  157. package/lib/deprecated-sync-cleanup.js +362 -0
  158. package/lib/detect-agent.js +2 -28
  159. package/lib/detect-worktree.js +35 -9
  160. package/lib/doc-gate/declaration.js +177 -0
  161. package/lib/doc-gate/detect.js +289 -0
  162. package/lib/doc-gate/gate.js +375 -0
  163. package/lib/doc-gate/okf-config.js +128 -0
  164. package/lib/doc-gate/okf.js +429 -0
  165. package/lib/docs-command.js +1161 -6
  166. package/lib/forge-issues.js +382 -11
  167. package/lib/forge-lock.js +262 -0
  168. package/lib/gate-events.js +192 -0
  169. package/lib/global-flags.js +104 -0
  170. package/lib/greptile-match.js +7 -63
  171. package/lib/grounding/context-events.js +230 -0
  172. package/lib/grounding/read-first.js +112 -0
  173. package/lib/harness-capability-matrix.js +380 -0
  174. package/lib/hook-global-installer.js +347 -0
  175. package/lib/hook-renderer.js +541 -0
  176. package/lib/inbox.js +391 -0
  177. package/lib/insights.js +397 -0
  178. package/lib/issue-adapter.js +156 -0
  179. package/lib/issue-backend.js +145 -0
  180. package/lib/issue-render.js +220 -0
  181. package/lib/kernel/backing-issue.js +311 -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/owned-kernel.js +43 -0
  192. package/lib/kernel/planning-buckets-schema.js +109 -0
  193. package/lib/kernel/projection-jsonl-writer.js +450 -0
  194. package/lib/kernel/readiness-model.js +329 -0
  195. package/lib/kernel/schema.js +356 -0
  196. package/lib/kernel/sqlite-driver.js +2540 -0
  197. package/lib/kernel/taxonomy-validator.js +394 -0
  198. package/lib/lefthook-check.js +3 -2
  199. package/lib/lefthook-wiring.js +413 -0
  200. package/lib/mcp-config-renderer.js +288 -0
  201. package/lib/memory/graphiti-mcp.js +106 -0
  202. package/lib/memory/router.js +387 -0
  203. package/lib/memory/typed-api.js +102 -0
  204. package/lib/memory-digest.js +195 -0
  205. package/lib/merge-rules.js +395 -0
  206. package/lib/migrate-dry-run.js +466 -0
  207. package/lib/orientation.js +863 -0
  208. package/lib/package-manager-remediation.js +103 -0
  209. package/lib/package-root.js +381 -0
  210. package/lib/patch-intent.js +890 -0
  211. package/lib/plugin-catalog.js +3 -4
  212. package/lib/plugin-manager.js +0 -5
  213. package/lib/pr-bundle.js +186 -0
  214. package/lib/pr-monitor/auto-actions.js +175 -0
  215. package/lib/pr-monitor/differ.js +195 -0
  216. package/lib/pr-monitor/digest.js +206 -0
  217. package/lib/pr-monitor/events.js +0 -0
  218. package/lib/pr-monitor/gather.js +124 -0
  219. package/lib/pr-monitor/journal.js +299 -0
  220. package/lib/pr-monitor/monitor.js +146 -0
  221. package/lib/pr-monitor/render-sticky.js +192 -0
  222. package/lib/pr-monitor/upsert-sticky.js +169 -0
  223. package/lib/pr-monitor/watch-lifecycle.js +95 -0
  224. package/lib/pr-monitor/watch.js +247 -0
  225. package/lib/pr-pull.js +1314 -0
  226. package/lib/pr-shepherd.js +494 -0
  227. package/lib/pr-state-validator.js +59 -0
  228. package/lib/preflight/gates.js +237 -0
  229. package/lib/preflight/runner.js +116 -0
  230. package/lib/project-discovery.js +0 -53
  231. package/lib/project-memory.js +99 -497
  232. package/lib/protected-path-manifest.js +281 -0
  233. package/lib/protected-state-surfaces.js +387 -0
  234. package/lib/release-readiness.js +2105 -0
  235. package/lib/reset.js +59 -45
  236. package/lib/review-adapter.js +68 -0
  237. package/lib/rules-sync.js +260 -0
  238. package/lib/runtime-health.js +241 -20
  239. package/lib/safety-config-renderer.js +268 -0
  240. package/lib/setup-action-log.js +1 -7
  241. package/lib/setup.js +27 -65
  242. package/lib/shell-utils.js +76 -6
  243. package/lib/skills-sync.js +330 -0
  244. package/lib/smart-status/scoring.js +17 -3
  245. package/lib/status/beads-snapshot.js +45 -2
  246. package/lib/status/presenter.js +169 -18
  247. package/lib/status/snapshot.js +186 -0
  248. package/lib/sync-backend.js +202 -0
  249. package/lib/untrusted-content.js +52 -0
  250. package/lib/upgrade-safety.js +251 -0
  251. package/lib/workflow/enforce-stage.js +351 -45
  252. package/lib/workflow/stage-transition.js +115 -0
  253. package/lib/workflow/stages.js +30 -6
  254. package/lib/workflow/state-manager.js +11 -22
  255. package/lib/workflow/state.js +23 -1
  256. package/lib/workflow-profiles.js +17 -5
  257. package/package.json +37 -35
  258. package/rules/documentation.md +19 -0
  259. package/rules/kernel-tracking.md +26 -0
  260. package/rules/security.md +22 -0
  261. package/rules/tdd.md +20 -0
  262. package/rules/workflow.md +27 -0
  263. package/scripts/auto-backing-issue.js +47 -0
  264. package/scripts/beads-context.sh +81 -57
  265. package/scripts/beads-upgrade-smoke.sh +24 -3
  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.sh +22 -3
  272. package/scripts/file-index.sh +3 -0
  273. package/scripts/forge-team/lib/claim.sh +34 -18
  274. package/scripts/forge-team/lib/dashboard.sh +61 -86
  275. package/scripts/forge-team/lib/epic.sh +99 -263
  276. package/scripts/forge-team/lib/hooks.sh +26 -28
  277. package/scripts/forge-team/lib/identity.sh +4 -4
  278. package/scripts/forge-team/lib/sync-github.sh +49 -84
  279. package/scripts/forge-team/lib/verify.sh +93 -83
  280. package/scripts/forge-team/lib/workload.sh +41 -65
  281. package/scripts/forge-team/tests/claim.test.sh +25 -19
  282. package/scripts/forge-team/tests/dashboard.test.sh +31 -46
  283. package/scripts/forge-team/tests/epic.test.sh +52 -71
  284. package/scripts/forge-team/tests/hooks.test.sh +38 -50
  285. package/scripts/forge-team/tests/identity.test.sh +3 -3
  286. package/scripts/forge-team/tests/integration.test.sh +44 -66
  287. package/scripts/forge-team/tests/sync-github.test.sh +50 -83
  288. package/scripts/forge-team/tests/verify.test.sh +37 -46
  289. package/scripts/forge-team/tests/workflow-integration.test.sh +4 -4
  290. package/scripts/forge-team/tests/workload.test.sh +32 -66
  291. package/scripts/gen-command-manifest.js +153 -0
  292. package/scripts/gen-embedded-assets.mjs +129 -0
  293. package/scripts/install.ps1 +139 -0
  294. package/scripts/install.sh +268 -0
  295. package/scripts/lib/release-asset.mjs +84 -0
  296. package/scripts/parity-check.mjs +145 -0
  297. package/scripts/parity-check.test.mjs +58 -0
  298. package/scripts/pin-agentic-workflow-images.js +112 -0
  299. package/scripts/pr-auto-actions.js +93 -0
  300. package/scripts/pr-coordinator.sh +3 -0
  301. package/scripts/pr-verdict-label.js +50 -0
  302. package/scripts/preflight-sonar.eslint.config.mjs +44 -0
  303. package/scripts/preflight.sh +21 -94
  304. package/scripts/protected-state-check.js +104 -0
  305. package/scripts/smart-status.sh +60 -57
  306. package/scripts/spikes/config-race-bench.js +111 -0
  307. package/scripts/spikes/harness-capability-matrix.js +13 -0
  308. package/scripts/spikes/patch-anchor-stability-bench.js +125 -0
  309. package/scripts/spikes/protected-path-manifest.js +20 -0
  310. package/scripts/spikes/skill-auto-invoke-parity.js +292 -0
  311. package/scripts/sync-agent-skills.js +62 -0
  312. package/scripts/sync-utils.sh +3 -0
  313. package/scripts/test-ci-shard.js +13 -6
  314. package/scripts/test.js +95 -12
  315. package/skills/claim-safety/SKILL.md +102 -0
  316. package/skills/claim-safety/evals/evals.json +46 -0
  317. package/{.github/prompts/dev.prompt.md → skills/dev/SKILL.md} +44 -50
  318. package/skills/dev/evals/evals.json +50 -0
  319. package/skills/hermes-forge/SKILL.md +185 -0
  320. package/skills/hermes-forge/evals/evals.json +46 -0
  321. package/skills/issue-basics/SKILL.md +111 -0
  322. package/skills/issue-basics/evals/evals.json +46 -0
  323. package/skills/kernel/SKILL.md +166 -0
  324. package/skills/kernel/evals/evals.json +50 -0
  325. package/skills/memory/SKILL.md +102 -0
  326. package/skills/parallel-deep-research/SKILL.md +14 -11
  327. package/skills/parallel-deep-research/evals/evals.json +11 -27
  328. package/{.github/prompts/plan.prompt.md → skills/plan/SKILL.md} +132 -157
  329. package/skills/plan/evals/evals.json +42 -0
  330. package/skills/research/SKILL.md +195 -0
  331. package/skills/research/evals/evals.json +42 -0
  332. package/{.github/prompts/review.prompt.md → skills/review/SKILL.md} +98 -62
  333. package/skills/review/evals/evals.json +42 -0
  334. package/skills/rollback/SKILL.md +110 -0
  335. package/skills/rollback/evals/evals.json +46 -0
  336. package/skills/rollback/references/methods.md +204 -0
  337. package/{.cursor/commands/rollback.md → skills/rollback/references/workflow-integration.md} +10 -284
  338. package/skills/shepherd/SKILL.md +66 -0
  339. package/skills/shepherd/evals/evals.json +42 -0
  340. package/{.github/prompts/ship.prompt.md → skills/ship/SKILL.md} +81 -45
  341. package/skills/ship/evals/evals.json +42 -0
  342. package/skills/smith/SKILL.md +142 -0
  343. package/skills/smith/evals/evals.json +46 -0
  344. package/skills/smith/references/autonomy-and-gates.md +94 -0
  345. package/{.github/prompts/sonarcloud.prompt.md → skills/sonarcloud/SKILL.md} +14 -3
  346. package/skills/sonarcloud/evals/evals.json +46 -0
  347. package/skills/sonarcloud-analysis/SKILL.md +18 -13
  348. package/skills/sonarcloud-analysis/evals/evals.json +11 -15
  349. package/{.github/prompts/status.prompt.md → skills/status/SKILL.md} +20 -10
  350. package/skills/status/evals/evals.json +50 -0
  351. package/skills/triage-ready/SKILL.md +121 -0
  352. package/skills/triage-ready/evals/evals.json +42 -0
  353. package/{.github/prompts/validate.prompt.md → skills/validate/SKILL.md} +52 -29
  354. package/skills/validate/evals/evals.json +42 -0
  355. package/skills/verify/SKILL.md +299 -0
  356. package/skills/verify/evals/evals.json +50 -0
  357. package/.claude/commands/dev.md +0 -345
  358. package/.claude/commands/plan.md +0 -566
  359. package/.claude/commands/premerge.md +0 -186
  360. package/.claude/commands/research.md +0 -42
  361. package/.claude/commands/review.md +0 -451
  362. package/.claude/commands/rollback.md +0 -721
  363. package/.claude/commands/ship.md +0 -213
  364. package/.claude/commands/sonarcloud.md +0 -152
  365. package/.claude/commands/status.md +0 -90
  366. package/.claude/commands/validate.md +0 -288
  367. package/.claude/commands/verify.md +0 -269
  368. package/.claude/rules/workflow.md +0 -121
  369. package/.cline/workflows/dev.md +0 -342
  370. package/.cline/workflows/plan.md +0 -563
  371. package/.cline/workflows/premerge.md +0 -183
  372. package/.cline/workflows/research.md +0 -39
  373. package/.cline/workflows/review.md +0 -448
  374. package/.cline/workflows/rollback.md +0 -718
  375. package/.cline/workflows/ship.md +0 -210
  376. package/.cline/workflows/sonarcloud.md +0 -146
  377. package/.cline/workflows/status.md +0 -87
  378. package/.cline/workflows/validate.md +0 -285
  379. package/.cline/workflows/verify.md +0 -266
  380. package/.codex/config.toml +0 -11
  381. package/.codex/skills/dev/SKILL.md +0 -345
  382. package/.codex/skills/plan/SKILL.md +0 -566
  383. package/.codex/skills/premerge/SKILL.md +0 -186
  384. package/.codex/skills/research/SKILL.md +0 -42
  385. package/.codex/skills/review/SKILL.md +0 -451
  386. package/.codex/skills/rollback/SKILL.md +0 -721
  387. package/.codex/skills/ship/SKILL.md +0 -213
  388. package/.codex/skills/sonarcloud/SKILL.md +0 -149
  389. package/.codex/skills/status/SKILL.md +0 -90
  390. package/.codex/skills/validate/SKILL.md +0 -288
  391. package/.codex/skills/verify/SKILL.md +0 -269
  392. package/.cursor/commands/dev.md +0 -342
  393. package/.cursor/commands/plan.md +0 -563
  394. package/.cursor/commands/premerge.md +0 -183
  395. package/.cursor/commands/research.md +0 -39
  396. package/.cursor/commands/review.md +0 -448
  397. package/.cursor/commands/ship.md +0 -210
  398. package/.cursor/commands/sonarcloud.md +0 -146
  399. package/.cursor/commands/status.md +0 -87
  400. package/.cursor/commands/validate.md +0 -285
  401. package/.cursor/commands/verify.md +0 -266
  402. package/.cursorrules +0 -149
  403. package/.github/prompts/premerge.prompt.md +0 -188
  404. package/.github/prompts/research.prompt.md +0 -44
  405. package/.github/prompts/rollback.prompt.md +0 -723
  406. package/.github/prompts/verify.prompt.md +0 -271
  407. package/.github/workflows/beads-to-github.yml +0 -89
  408. package/.github/workflows/github-to-beads.yml +0 -100
  409. package/.kilocode/workflows/dev.md +0 -346
  410. package/.kilocode/workflows/plan.md +0 -567
  411. package/.kilocode/workflows/premerge.md +0 -187
  412. package/.kilocode/workflows/research.md +0 -43
  413. package/.kilocode/workflows/review.md +0 -452
  414. package/.kilocode/workflows/rollback.md +0 -722
  415. package/.kilocode/workflows/ship.md +0 -214
  416. package/.kilocode/workflows/sonarcloud.md +0 -150
  417. package/.kilocode/workflows/status.md +0 -91
  418. package/.kilocode/workflows/validate.md +0 -289
  419. package/.kilocode/workflows/verify.md +0 -270
  420. package/.opencode/commands/dev.md +0 -345
  421. package/.opencode/commands/plan.md +0 -566
  422. package/.opencode/commands/premerge.md +0 -186
  423. package/.opencode/commands/research.md +0 -42
  424. package/.opencode/commands/review.md +0 -451
  425. package/.opencode/commands/rollback.md +0 -721
  426. package/.opencode/commands/ship.md +0 -213
  427. package/.opencode/commands/sonarcloud.md +0 -149
  428. package/.opencode/commands/status.md +0 -90
  429. package/.opencode/commands/validate.md +0 -288
  430. package/.opencode/commands/verify.md +0 -269
  431. package/.roo/commands/dev.md +0 -346
  432. package/.roo/commands/plan.md +0 -567
  433. package/.roo/commands/premerge.md +0 -187
  434. package/.roo/commands/research.md +0 -43
  435. package/.roo/commands/review.md +0 -452
  436. package/.roo/commands/rollback.md +0 -722
  437. package/.roo/commands/ship.md +0 -214
  438. package/.roo/commands/sonarcloud.md +0 -150
  439. package/.roo/commands/status.md +0 -91
  440. package/.roo/commands/validate.md +0 -289
  441. package/.roo/commands/verify.md +0 -270
  442. package/docs/BEADS_GITHUB_SYNC.md +0 -281
  443. package/docs/GREPTILE_SETUP.md +0 -400
  444. package/docs/MANUAL_REVIEW_GUIDE.md +0 -106
  445. package/docs/SETUP.md +0 -663
  446. package/docs/VALIDATION.md +0 -363
  447. package/lib/agents/cline.plugin.json +0 -29
  448. package/lib/agents/copilot.plugin.json +0 -24
  449. package/lib/agents/kilocode.plugin.json +0 -22
  450. package/lib/agents/opencode.plugin.json +0 -23
  451. package/lib/agents/roo.plugin.json +0 -30
  452. package/lib/beads-bootstrap.js +0 -225
  453. package/lib/beads-health-check.js +0 -188
  454. package/lib/commands/commands-reset.js +0 -147
  455. package/opencode.json +0 -67
  456. package/scripts/beads-context.test.js +0 -584
  457. package/scripts/github-beads-sync/comment.mjs +0 -64
  458. package/scripts/github-beads-sync/config.mjs +0 -148
  459. package/scripts/github-beads-sync/github-api.mjs +0 -131
  460. package/scripts/github-beads-sync/index.mjs +0 -356
  461. package/scripts/github-beads-sync/label-mapper.mjs +0 -54
  462. package/scripts/github-beads-sync/mapping.mjs +0 -132
  463. package/scripts/github-beads-sync/reverse-sync-cli.mjs +0 -31
  464. package/scripts/github-beads-sync/reverse-sync.mjs +0 -162
  465. package/scripts/github-beads-sync/run-bd.mjs +0 -161
  466. package/scripts/github-beads-sync/sanitize.mjs +0 -121
  467. package/scripts/github-beads-sync.config.json +0 -26
  468. package/scripts/sync-commands.js +0 -600
@@ -160,9 +160,9 @@ function renderKeywordRippleReport({ issueId, sourceTitle, activeIssues }) {
160
160
  ' Confidence: LOW (keyword only, no contract data)',
161
161
  '',
162
162
  ' Options:',
163
- ` (a) Add dependency: bd dep add ${issueId} ${overlap.id}`,
163
+ ` (a) Add dependency: forge issue dep add ${issueId} ${overlap.id}`,
164
164
  ' (b) Proceed - no real conflict',
165
- ` (c) Investigate: bd show ${overlap.id}`,
165
+ ` (c) Investigate: forge issue show ${overlap.id}`,
166
166
  '',
167
167
  );
168
168
  }
@@ -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,29 +3,51 @@
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
17
+ * @param {object} [deps] - Injectable dependencies for testing (execFileSync, warn)
11
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
 
27
- const branch = execFileSync('git', ['branch', '--show-current'], {
28
- encoding: 'utf8', cwd, stdio: ['pipe', 'pipe', 'pipe']
49
+ const branch = exec('git', ['branch', '--show-current'], {
50
+ encoding: 'utf8', cwd, stdio: ['pipe', 'pipe', 'pipe'], timeout: GIT_SPAWN_TIMEOUT_MS
29
51
  }).trim();
30
52
  const mainWorktree = path.resolve(absCommonDir, '..');
31
53
  const currentWorktree = path.resolve(cwd);
@@ -37,8 +59,12 @@ function detectWorktree(cwd = process.cwd()) {
37
59
  }
38
60
 
39
61
  return { inWorktree: false, branch, mainWorktree, currentWorktree };
40
- } catch (_err) {
41
- // Not in a git repo or git not available
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 }');
42
68
  return { inWorktree: false };
43
69
  }
44
70
  }