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,330 @@
1
+ /**
2
+ * @module skills-sync
3
+ *
4
+ * Skills-only surface population + drift detection for Forge.
5
+ *
6
+ * Canonical source of truth is the committed root `skills/` directory — each
7
+ * `skills/<name>/SKILL.md` (plus any sibling files) is an auto-surfacing skill.
8
+ * Agent harness skill directories (`.agents/skills/`, `.claude/skills/`,
9
+ * `.codex/skills/`, `.cursor/skills/`, `.hermes/skills/`) are GENERATED from that
10
+ * canonical source. `.agents/skills` is Codex's documented repo-local discovery
11
+ * path (scanned from cwd up to the repo root) and is the ONE mirror committed to
12
+ * the repo (kept byte-identical by a pre-commit sync hook + the drift gate), so a
13
+ * teammate who clones the repo WITHOUT running `forge setup` still gets the Forge
14
+ * skills/stages auto-discovered. The other mirrors (including `.codex/skills`) are
15
+ * gitignored and populated at setup only.
16
+ *
17
+ * This module is the Forge-internal port of the `@forge/skills` CLI sync step.
18
+ * Forge cannot depend on `@forge/skills` at runtime (the `packages/` workspace is
19
+ * excluded from the published npm package), so the minimal population + check
20
+ * logic lives here. It mirrors the CLI's whole-directory copy semantics so that
21
+ * `skills sync --check` and this module agree on what "in sync" means.
22
+ *
23
+ * Design constraints (locked in kernel-skill-surface-design.md §6):
24
+ * - Registry-independent: never requires `.skills/.registry.json` (the registry
25
+ * is gitignored and absent on a fresh checkout).
26
+ * - AGENTS.md-safe: never writes AGENTS.md (it is the protected workflow contract).
27
+ * - Existing-mirror scoped: `checkSkillsSync` only validates agent skill dirs
28
+ * that already exist on disk. The gitignored, setup-populated mirrors
29
+ * (`.claude/skills`, `.codex/skills`, `.cursor/skills`, `.hermes/skills`) are
30
+ * absent on a clean checkout and are correctly skipped; `.agents/skills` is the
31
+ * committed mirror that is always present and thus always enforced against the
32
+ * canonical source, which is what the gate guarantees.
33
+ */
34
+
35
+ const fs = require('node:fs');
36
+ const path = require('node:path');
37
+
38
+ /** Canonical skills live under this directory at the repo/package root. */
39
+ const CANONICAL_SKILLS_DIR = 'skills';
40
+
41
+ /**
42
+ * Standard agent harness skill directories, relative to a project root.
43
+ * Order is stable for deterministic reporting.
44
+ */
45
+ const AGENT_SKILL_DIRS = [
46
+ '.agents/skills',
47
+ '.claude/skills',
48
+ '.codex/skills',
49
+ '.cursor/skills',
50
+ '.hermes/skills',
51
+ ];
52
+
53
+ /** Skill name must be a safe single path segment (no traversal). */
54
+ function isValidSkillName(name) {
55
+ return (
56
+ typeof name === 'string' &&
57
+ name.length > 0 &&
58
+ name !== '.' &&
59
+ name !== '..' &&
60
+ !name.includes('/') &&
61
+ !name.includes('\\') &&
62
+ !name.includes('\0')
63
+ );
64
+ }
65
+
66
+ /**
67
+ * List canonical skills under `<sourceRoot>/skills`.
68
+ *
69
+ * A skill is any direct subdirectory that contains a `SKILL.md` file.
70
+ *
71
+ * @param {string} sourceRoot - Directory containing the canonical `skills/` dir.
72
+ * @param {object} [options]
73
+ * @param {Set<string>|string[]} [options.only] - Restrict to these skill names.
74
+ * @returns {{name: string, sourcePath: string}[]} Sorted list of skills.
75
+ */
76
+ function listCanonicalSkills(sourceRoot, options = {}) {
77
+ const skillsDir = path.join(sourceRoot, CANONICAL_SKILLS_DIR);
78
+ if (!fs.existsSync(skillsDir)) {
79
+ return [];
80
+ }
81
+
82
+ const only = options.only ? new Set(options.only) : null;
83
+ const skills = [];
84
+
85
+ for (const entry of fs.readdirSync(skillsDir, { withFileTypes: true })) {
86
+ if (!entry.isDirectory()) continue;
87
+ if (!isValidSkillName(entry.name)) continue;
88
+ if (only && !only.has(entry.name)) continue;
89
+
90
+ const sourcePath = path.join(skillsDir, entry.name);
91
+ if (!fs.existsSync(path.join(sourcePath, 'SKILL.md'))) continue;
92
+
93
+ skills.push({ name: entry.name, sourcePath });
94
+ }
95
+
96
+ skills.sort((a, b) => a.name.localeCompare(b.name));
97
+ return skills;
98
+ }
99
+
100
+ /**
101
+ * List all files under a directory as paths relative to that directory,
102
+ * using forward slashes for stable cross-platform comparison.
103
+ *
104
+ * @param {string} dir - Directory to walk.
105
+ * @returns {string[]} Sorted relative file paths.
106
+ */
107
+ function listFilesRecursive(dir) {
108
+ const out = [];
109
+
110
+ function walk(current, prefix) {
111
+ for (const entry of fs.readdirSync(current, { withFileTypes: true })) {
112
+ const abs = path.join(current, entry.name);
113
+ const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
114
+ if (entry.isDirectory()) {
115
+ walk(abs, rel);
116
+ } else if (entry.isFile()) {
117
+ out.push(rel);
118
+ }
119
+ }
120
+ }
121
+
122
+ if (fs.existsSync(dir)) {
123
+ walk(dir, '');
124
+ }
125
+ out.sort((a, b) => a.localeCompare(b));
126
+ return out;
127
+ }
128
+
129
+ /** Normalize line endings so Windows CRLF working-tree state is not false drift. */
130
+ function normalizeContent(buffer) {
131
+ return buffer.toString('utf8').replace(/\r\n/g, '\n');
132
+ }
133
+
134
+ /**
135
+ * Remove a symlink sitting at a target path so a real directory can be written
136
+ * in its place. Only ever removes the link entry itself — never a real
137
+ * directory (with content) and never the symlink's target.
138
+ *
139
+ * Guards against the exact cruft that broke local skill-sync: a pre-existing
140
+ * DANGLING symlink at a skill dir path, which makes `mkdirSync`/copy fail.
141
+ *
142
+ * @param {string} targetPath - Path that may hold a (possibly dangling) symlink.
143
+ * @returns {boolean} True if a symlink was cleared, false otherwise.
144
+ */
145
+ function clearSymlinkAtPath(targetPath) {
146
+ let linkStat;
147
+ try {
148
+ // lstat does NOT follow the link, so a dangling symlink is still detected.
149
+ linkStat = fs.lstatSync(targetPath);
150
+ } catch {
151
+ return false; // nothing at this path
152
+ }
153
+
154
+ if (!linkStat.isSymbolicLink()) {
155
+ return false; // a real file/dir — leave it for the normal copy path
156
+ }
157
+
158
+ // Remove ONLY the link. Neither unlink nor rm follow a symlink's target, so
159
+ // the (possibly dangling) target's contents are never touched.
160
+ try {
161
+ fs.unlinkSync(targetPath);
162
+ } catch {
163
+ // Windows directory symlinks/junctions can reject unlink; rmSync removes the
164
+ // link entry itself without recursing into the target.
165
+ fs.rmSync(targetPath, { recursive: true, force: true });
166
+ }
167
+ return true;
168
+ }
169
+
170
+ /**
171
+ * Copy a single skill directory (recursively) from source to target,
172
+ * overwriting existing files. Byte-for-byte copy (matches CLI cpSync).
173
+ *
174
+ * @param {string} sourcePath - Source skill directory.
175
+ * @param {string} targetPath - Target skill directory.
176
+ */
177
+ function copySkillDir(sourcePath, targetPath) {
178
+ fs.mkdirSync(targetPath, { recursive: true });
179
+ for (const entry of fs.readdirSync(sourcePath, { withFileTypes: true })) {
180
+ const src = path.join(sourcePath, entry.name);
181
+ const dest = path.join(targetPath, entry.name);
182
+ if (entry.isDirectory()) {
183
+ copySkillDir(src, dest);
184
+ } else if (entry.isFile()) {
185
+ fs.copyFileSync(src, dest);
186
+ }
187
+ }
188
+ }
189
+
190
+ /**
191
+ * Populate an agent harness skills directory from the canonical source.
192
+ *
193
+ * Writes `<targetSkillsDir>/<name>/...` for every canonical skill. Existing
194
+ * skills are overwritten; pre-existing unrelated skill dirs are left untouched
195
+ * unless `clean` is set.
196
+ *
197
+ * @param {object} params
198
+ * @param {string} params.sourceRoot - Root containing the canonical `skills/` dir.
199
+ * @param {string} params.targetSkillsDir - Absolute path to the agent skills dir.
200
+ * @param {Set<string>|string[]} [params.only] - Restrict to these skill names.
201
+ * @param {boolean} [params.clean=false] - Remove canonical-managed stale dirs first.
202
+ * @returns {{written: string[]}} Names of skills written.
203
+ */
204
+ function populateAgentSkills({ sourceRoot, targetSkillsDir, only, clean = false }) {
205
+ const skills = listCanonicalSkills(sourceRoot, { only });
206
+ fs.mkdirSync(targetSkillsDir, { recursive: true });
207
+
208
+ if (clean) {
209
+ // Keep-set is the FULL canonical set, not the `only`-filtered subset, so a
210
+ // partial sync (only: [...]) never deletes other canonical skills' dirs.
211
+ const canonicalNames = new Set(listCanonicalSkills(sourceRoot).map((s) => s.name));
212
+ for (const entry of fs.readdirSync(targetSkillsDir, { withFileTypes: true })) {
213
+ if (entry.isDirectory() && !canonicalNames.has(entry.name)) {
214
+ fs.rmSync(path.join(targetSkillsDir, entry.name), { recursive: true, force: true });
215
+ }
216
+ }
217
+ }
218
+
219
+ const written = [];
220
+ for (const skill of skills) {
221
+ const targetPath = path.join(targetSkillsDir, skill.name);
222
+ // Defensive: clear a pre-existing (possibly dangling) symlink so the copy
223
+ // doesn't fail. Only symlinks are removed — real dirs are overwritten in place.
224
+ clearSymlinkAtPath(targetPath);
225
+ copySkillDir(skill.sourcePath, targetPath);
226
+ written.push(skill.name);
227
+ }
228
+ return { written };
229
+ }
230
+
231
+ /**
232
+ * Compare a canonical skill directory against a target copy.
233
+ *
234
+ * @param {string} sourcePath - Canonical skill dir.
235
+ * @param {string} targetPath - Target (generated) skill dir.
236
+ * @returns {{file: string, status: 'missing'|'changed'|'extra'}[]} Drift entries.
237
+ */
238
+ function diffSkillDir(sourcePath, targetPath) {
239
+ const drift = [];
240
+ const sourceFiles = new Set(listFilesRecursive(sourcePath));
241
+ const targetFiles = new Set(listFilesRecursive(targetPath));
242
+
243
+ for (const rel of sourceFiles) {
244
+ if (!targetFiles.has(rel)) {
245
+ drift.push({ file: rel, status: 'missing' });
246
+ continue;
247
+ }
248
+ const a = normalizeContent(fs.readFileSync(path.join(sourcePath, rel)));
249
+ const b = normalizeContent(fs.readFileSync(path.join(targetPath, rel)));
250
+ if (a !== b) {
251
+ drift.push({ file: rel, status: 'changed' });
252
+ }
253
+ }
254
+
255
+ for (const rel of targetFiles) {
256
+ if (!sourceFiles.has(rel)) {
257
+ drift.push({ file: rel, status: 'extra' });
258
+ }
259
+ }
260
+
261
+ return drift;
262
+ }
263
+
264
+ /**
265
+ * Check that existing agent skill mirrors match the canonical source.
266
+ *
267
+ * Only agent skill dirs that already EXIST under `repoRoot` are validated. The
268
+ * gitignored, setup-populated mirrors (`.claude/skills`, `.codex/skills`, etc.)
269
+ * are absent on a clean checkout and correctly skipped; the committed
270
+ * `.agents/skills` mirror is always present and always enforced against the
271
+ * canonical source. Any mirror present locally must match canonical.
272
+ *
273
+ * @param {object} params
274
+ * @param {string} params.repoRoot - Repo root (contains `skills/` + agent dirs).
275
+ * @param {Set<string>|string[]} [params.only] - Restrict canonical set.
276
+ * @param {string[]} [params.agentSkillDirs] - Override the agent dirs to scan.
277
+ * @returns {{inSync: boolean, checkedAgents: string[], drift: object[]}}
278
+ */
279
+ function checkSkillsSync({ repoRoot, only, agentSkillDirs = AGENT_SKILL_DIRS }) {
280
+ const skills = listCanonicalSkills(repoRoot, { only });
281
+ const canonicalByName = new Map(skills.map((s) => [s.name, s]));
282
+ const drift = [];
283
+ const checkedAgents = [];
284
+
285
+ for (const rel of agentSkillDirs) {
286
+ const agentDir = path.join(repoRoot, rel);
287
+ if (!fs.existsSync(agentDir)) continue; // populated at setup time; absence ≠ drift
288
+ checkedAgents.push(rel);
289
+
290
+ const targetNames = fs
291
+ .readdirSync(agentDir, { withFileTypes: true })
292
+ .filter((e) => e.isDirectory())
293
+ .map((e) => e.name);
294
+
295
+ // Skills present canonically but missing/changed in the mirror.
296
+ for (const skill of skills) {
297
+ const targetPath = path.join(agentDir, skill.name);
298
+ // A regular file at the skill path is corruption, not a valid mirror:
299
+ // treat it as drift instead of letting diffSkillDir() throw ENOTDIR.
300
+ if (!fs.existsSync(targetPath) || !fs.statSync(targetPath).isDirectory()) {
301
+ drift.push({ agent: rel, skill: skill.name, file: 'SKILL.md', status: 'missing' });
302
+ continue;
303
+ }
304
+ for (const entry of diffSkillDir(skill.sourcePath, targetPath)) {
305
+ drift.push({ agent: rel, skill: skill.name, ...entry });
306
+ }
307
+ }
308
+
309
+ // Skill dirs in the mirror with no canonical source = stale.
310
+ for (const name of targetNames) {
311
+ if (!canonicalByName.has(name)) {
312
+ drift.push({ agent: rel, skill: name, file: '*', status: 'stale' });
313
+ }
314
+ }
315
+ }
316
+
317
+ return { inSync: drift.length === 0, checkedAgents, drift };
318
+ }
319
+
320
+ module.exports = {
321
+ CANONICAL_SKILLS_DIR,
322
+ AGENT_SKILL_DIRS,
323
+ isValidSkillName,
324
+ listCanonicalSkills,
325
+ listFilesRecursive,
326
+ clearSymlinkAtPath,
327
+ populateAgentSkills,
328
+ diffSkillDir,
329
+ checkSkillsSync,
330
+ };
@@ -0,0 +1,205 @@
1
+ 'use strict';
2
+
3
+ function splitLines(value) {
4
+ if (!value) {
5
+ return [];
6
+ }
7
+
8
+ return String(value)
9
+ .replaceAll('\r', '')
10
+ .split('\n');
11
+ }
12
+
13
+ function uniqueStrings(values) {
14
+ const result = [];
15
+ const seen = new Set();
16
+
17
+ for (const value of values || []) {
18
+ if (typeof value !== 'string') {
19
+ continue;
20
+ }
21
+ const normalized = value.trim();
22
+ if (!normalized || seen.has(normalized)) {
23
+ continue;
24
+ }
25
+ seen.add(normalized);
26
+ result.push(normalized);
27
+ }
28
+
29
+ return result;
30
+ }
31
+
32
+ function parseWorktreePorcelain(porcelainText, baseBranch) {
33
+ const worktrees = [];
34
+ let currentPath = '';
35
+ let currentBranch = '';
36
+
37
+ for (const line of splitLines(porcelainText)) {
38
+ if (line.startsWith('worktree ')) {
39
+ currentPath = line.slice('worktree '.length);
40
+ continue;
41
+ }
42
+
43
+ if (line.startsWith('branch refs/heads/')) {
44
+ currentBranch = line.slice('branch refs/heads/'.length);
45
+ continue;
46
+ }
47
+
48
+ if (line !== '') {
49
+ continue;
50
+ }
51
+
52
+ if (currentBranch && currentBranch !== baseBranch) {
53
+ worktrees.push({ branch: currentBranch, path: currentPath });
54
+ }
55
+ currentPath = '';
56
+ currentBranch = '';
57
+ }
58
+
59
+ if (currentBranch && currentBranch !== baseBranch) {
60
+ worktrees.push({ branch: currentBranch, path: currentPath });
61
+ }
62
+
63
+ return worktrees;
64
+ }
65
+
66
+ function branchSlugToSearch(branch) {
67
+ const slug = String(branch || '').includes('/')
68
+ ? String(branch).slice(String(branch).lastIndexOf('/') + 1)
69
+ : String(branch || '');
70
+ return slug.replaceAll('-', ' ').toLowerCase();
71
+ }
72
+
73
+ function matchInProgressIssues(worktrees, inProgressIssues) {
74
+ const issues = Array.isArray(inProgressIssues) ? inProgressIssues : [];
75
+
76
+ return (Array.isArray(worktrees) ? worktrees : []).map((worktree) => {
77
+ const slug = branchSlugToSearch(worktree.branch);
78
+ if (!slug) {
79
+ return {
80
+ branch: worktree.branch,
81
+ path: worktree.path,
82
+ issue_ids: [],
83
+ issue_count: 0,
84
+ };
85
+ }
86
+ const issueIds = issues
87
+ .filter((issue) => typeof issue?.title === 'string' && issue.title.toLowerCase().includes(slug))
88
+ .map((issue) => issue?.id)
89
+ .filter((issueId) => typeof issueId === 'string' && issueId);
90
+
91
+ return {
92
+ branch: worktree.branch,
93
+ path: worktree.path,
94
+ issue_ids: issueIds,
95
+ issue_count: issueIds.length,
96
+ };
97
+ });
98
+ }
99
+
100
+ function normalizeBranchFiles(branchFiles) {
101
+ if (Array.isArray(branchFiles)) {
102
+ return branchFiles
103
+ .filter((entry) => entry && typeof entry.branch === 'string')
104
+ .map((entry) => ({
105
+ branch: entry.branch,
106
+ files: Array.isArray(entry.files) ? uniqueStrings(entry.files) : [],
107
+ }));
108
+ }
109
+
110
+ if (branchFiles && typeof branchFiles === 'object') {
111
+ return Object.entries(branchFiles).map(([branch, files]) => ({
112
+ branch,
113
+ files: Array.isArray(files) ? uniqueStrings(files) : [],
114
+ }));
115
+ }
116
+
117
+ return [];
118
+ }
119
+
120
+ function computeFileConflicts(sessions, branchFiles) {
121
+ const branchFileEntries = normalizeBranchFiles(branchFiles);
122
+ const filesByBranch = new Map(branchFileEntries.map((entry) => [entry.branch, entry.files]));
123
+
124
+ return (Array.isArray(sessions) ? sessions : []).map((session) => {
125
+ const changedFiles = filesByBranch.get(session.branch) || [];
126
+ const conflicts = [];
127
+
128
+ for (const other of branchFileEntries) {
129
+ if (other.branch === session.branch || other.files.length === 0 || changedFiles.length === 0) {
130
+ continue;
131
+ }
132
+
133
+ const otherSet = new Set(other.files);
134
+ const overlap = uniqueStrings(changedFiles.filter((file) => otherSet.has(file)));
135
+ if (overlap.length > 0) {
136
+ conflicts.push({ branch: other.branch, files: overlap });
137
+ }
138
+ }
139
+
140
+ return {
141
+ ...session,
142
+ changed_files: changedFiles,
143
+ conflicts,
144
+ };
145
+ });
146
+ }
147
+
148
+ function parseMergeTreeNameOnly(stdout) {
149
+ const lines = splitLines(stdout).filter((line, index) => index > 0 && line.trim().length > 0);
150
+ return uniqueStrings(lines);
151
+ }
152
+
153
+ function applyMergeTreeConflicts(sessions, mergeTreeResults) {
154
+ const nextSessions = (Array.isArray(sessions) ? sessions : []).map((session) => ({
155
+ ...session,
156
+ merge_conflicts: Array.isArray(session.merge_conflicts) ? [...session.merge_conflicts] : [],
157
+ }));
158
+ const sessionIndexes = new Map(nextSessions.map((session, index) => [session.branch, index]));
159
+
160
+ for (const result of Array.isArray(mergeTreeResults) ? mergeTreeResults : []) {
161
+ if (!result || typeof result.left !== 'string' || typeof result.right !== 'string') {
162
+ continue;
163
+ }
164
+
165
+ const exitCode = Number(result.exitCode);
166
+ if (exitCode !== 1) {
167
+ continue;
168
+ }
169
+
170
+ const files = parseMergeTreeNameOnly(result.output);
171
+ if (files.length === 0) {
172
+ continue;
173
+ }
174
+
175
+ for (const [targetBranch, otherBranch] of [[result.left, result.right], [result.right, result.left]]) {
176
+ const index = sessionIndexes.get(targetBranch);
177
+ if (index === undefined) {
178
+ continue;
179
+ }
180
+
181
+ nextSessions[index].merge_conflicts.push({
182
+ branch: otherBranch,
183
+ files,
184
+ });
185
+ }
186
+ }
187
+
188
+ return nextSessions.map((session) => {
189
+ if (session.merge_conflicts.length === 0) {
190
+ const nextSession = { ...session };
191
+ delete nextSession.merge_conflicts;
192
+ return nextSession;
193
+ }
194
+
195
+ return session;
196
+ });
197
+ }
198
+
199
+ module.exports = {
200
+ applyMergeTreeConflicts,
201
+ computeFileConflicts,
202
+ matchInProgressIssues,
203
+ parseMergeTreeNameOnly,
204
+ parseWorktreePorcelain,
205
+ };