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,78 @@
1
+ #!/usr/bin/env bash
2
+ # Shared Windows/WSL command bootstrap for bash entrypoints.
3
+
4
+ if [[ -n "${_FORGE_BOOTSTRAP_WINDOWS_TOOLS_LOADED:-}" ]]; then
5
+ return 0 2>/dev/null || exit 0
6
+ fi
7
+ _FORGE_BOOTSTRAP_WINDOWS_TOOLS_LOADED=1
8
+
9
+ _forge_to_unix_path() {
10
+ local raw="$1"
11
+ if command -v wslpath >/dev/null 2>&1; then
12
+ wslpath -u "$raw" 2>/dev/null && return 0
13
+ fi
14
+ if command -v cygpath >/dev/null 2>&1; then
15
+ cygpath -u "$raw" 2>/dev/null && return 0
16
+ fi
17
+ printf '%s\n' "$raw"
18
+ }
19
+
20
+ _forge_resolve_tool() {
21
+ local name="$1"
22
+ local found=""
23
+
24
+ found="$(command -v "$name" 2>/dev/null || true)"
25
+ if [[ -n "$found" ]]; then
26
+ printf '%s\n' "$found"
27
+ return 0
28
+ fi
29
+
30
+ if command -v where.exe >/dev/null 2>&1; then
31
+ found="$(where.exe "$name" 2>/dev/null | tr -d '\r' | head -n 1 || true)"
32
+ if [[ -n "$found" ]]; then
33
+ _forge_to_unix_path "$found"
34
+ return 0
35
+ fi
36
+ fi
37
+
38
+ return 1
39
+ }
40
+
41
+ if [[ -z "${BD_CMD:-}" ]]; then
42
+ BD_CMD="$(_forge_resolve_tool bd || true)"
43
+ fi
44
+ if [[ -n "${BD_CMD:-}" ]]; then
45
+ export BD_CMD
46
+ fi
47
+
48
+ if [[ -z "${JQ_CMD:-}" ]]; then
49
+ JQ_CMD="$(_forge_resolve_tool jq || true)"
50
+ fi
51
+ if [[ -n "${JQ_CMD:-}" ]]; then
52
+ export JQ_CMD
53
+ fi
54
+
55
+ if [[ -z "${GH_CMD:-}" ]]; then
56
+ GH_CMD="$(_forge_resolve_tool gh || true)"
57
+ fi
58
+ if [[ -n "${GH_CMD:-}" ]]; then
59
+ export GH_CMD
60
+ fi
61
+
62
+ if [[ -n "${BD_CMD:-}" ]]; then
63
+ bd() {
64
+ command "$BD_CMD" "$@"
65
+ }
66
+ fi
67
+
68
+ if [[ -n "${JQ_CMD:-}" ]]; then
69
+ jq() {
70
+ command "$JQ_CMD" "$@"
71
+ }
72
+ fi
73
+
74
+ if [[ -n "${GH_CMD:-}" ]]; then
75
+ gh() {
76
+ command "$GH_CMD" "$@"
77
+ }
78
+ fi
@@ -131,7 +131,7 @@ function main() {
131
131
  const currentBranch = getCurrentBranch();
132
132
 
133
133
  if (isProtectedBranch(currentBranch)) {
134
- // Allow beads-only commits (issue tracking metadata) to push directly
134
+ // Beads runtime metadata is local state. Do not bypass protected branches for it.
135
135
  try {
136
136
  let upstream;
137
137
  try {
@@ -150,8 +150,7 @@ function main() {
150
150
  if (changedFiles.length === 0) {
151
151
  console.error(`${YELLOW}Note: no changed files detected — nothing to bypass${RESET}`);
152
152
  } else if (changedFiles.every(f => f.startsWith('.beads/'))) {
153
- console.error(`${YELLOW}Beads-only push to '${currentBranch}' allowed${RESET}`);
154
- process.exit(0);
153
+ console.error(`${YELLOW}Beads metadata is local runtime state; protected branches do not accept .beads-only pushes.${RESET}`);
155
154
  }
156
155
  } catch (_e) {
157
156
  console.error(`${YELLOW}Note: could not detect beads-only push (upstream ref missing?) — blocking by default${RESET}`);
@@ -5,11 +5,12 @@
5
5
  *
6
6
  * CLI command that validates all agent configs are complete and in sync.
7
7
  *
8
- * 1. Runs syncCommands({ check: true }) to verify agent command files match canonical source
9
- * 2. Reads lib/agents/*.plugin.json to verify each agent with capabilities.commands: true
10
- * has its command directory populated with expected files
11
- * 3. Reports: missing files, out-of-sync files, stale files
12
- * 4. Exits 0 if all clean, exits non-zero if issues found
8
+ * 1. Runs the skills drift check (lib/skills-sync) to verify generated agent
9
+ * skill mirrors (e.g. .codex/skills) match the canonical root skills/ source.
10
+ * 2. Reads lib/agents/*.plugin.json to validate each plugin's schema/parity
11
+ * (support metadata, rules/skills scaffold paths, deprecated-tier consistency).
12
+ * 3. Reports: skill drift, missing/stale skills, plugin parity errors.
13
+ * 4. Exits 0 if all clean, exits non-zero if issues found.
13
14
  *
14
15
  * Usage:
15
16
  * node scripts/check-agents.js
@@ -18,51 +19,22 @@
18
19
  * checkAgents(repoRoot) -> { errors: string[], warnings: string[] }
19
20
  */
20
21
 
21
- const { syncCommands } = require('./sync-commands');
22
- const { AGENT_ADAPTERS } = require('./sync-commands');
23
22
  const path = require('path');
24
23
  const fs = require('fs');
24
+ const { checkSkillsSync } = require('../lib/skills-sync');
25
25
  const { validatePluginSchema } = require('../lib/plugin-manager');
26
26
 
27
- const SYNC_ADAPTER_BY_PLUGIN_ID = Object.freeze({
28
- claude: 'claude-code',
29
- cline: 'cline',
30
- codex: 'codex',
31
- copilot: 'github-copilot',
32
- cursor: 'cursor',
33
- kilocode: 'kilo-code',
34
- opencode: 'opencode',
35
- roo: 'roo-code',
36
- });
37
-
38
- function normalizeRelativeDir(dir) {
39
- if (!dir) return null;
40
- return String(dir).replace(/\\/g, '/').replace(/\/+$/, '');
41
- }
42
-
43
- function getDeclaredCommandDir(plugin) {
44
- const dirs = plugin.directories || {};
45
- return dirs.commands || dirs.workflows || dirs.prompts || dirs.skills || null;
46
- }
47
-
48
- function getExpectedCommandDir(plugin) {
49
- const adapterId = SYNC_ADAPTER_BY_PLUGIN_ID[plugin.id];
50
- if (!adapterId) {
51
- return null;
52
- }
53
-
54
- const adapter = AGENT_ADAPTERS[adapterId];
55
- if (!adapter) {
56
- return null;
57
- }
58
-
59
- if (plugin.id === 'codex') {
60
- return normalizeRelativeDir(plugin.directories?.skills || adapter.baseDir);
61
- }
62
-
63
- return normalizeRelativeDir(adapter.baseDir);
64
- }
65
-
27
+ /**
28
+ * Validate a single plugin's schema + capability/scaffold parity.
29
+ *
30
+ * Command-surface parity is intentionally NOT validated: Forge is skills-only
31
+ * (the .claude/commands/.cursor/commands/.codex/skills command surface was
32
+ * removed in PR-A0). The surviving checks cover support metadata, the rules and
33
+ * skills scaffold paths, and deprecated-tier consistency.
34
+ *
35
+ * @param {object} plugin
36
+ * @param {string[]} errors - mutated with any parity errors
37
+ */
66
38
  function validatePluginParity(plugin, errors) {
67
39
  const validation = validatePluginSchema(plugin);
68
40
  if (!validation.valid) {
@@ -78,25 +50,6 @@ function validatePluginParity(plugin, errors) {
78
50
  const dirs = plugin.directories || {};
79
51
  const supportStatus = plugin.support?.status;
80
52
 
81
- if (capabilities.commands) {
82
- const expectedDir = getExpectedCommandDir(plugin);
83
- const declaredDir = normalizeRelativeDir(getDeclaredCommandDir(plugin));
84
-
85
- if (!expectedDir) {
86
- errors.push(
87
- `Plugin "${plugin.name}" (${plugin.id}) declares commands support but has no Forge sync adapter.`
88
- );
89
- } else if (!declaredDir) {
90
- errors.push(
91
- `Plugin "${plugin.name}" (${plugin.id}) declares commands support but has no command directory configured.`
92
- );
93
- } else if (declaredDir !== expectedDir) {
94
- errors.push(
95
- `Plugin "${plugin.name}" (${plugin.id}) command directory "${declaredDir}" does not match sync output "${expectedDir}".`
96
- );
97
- }
98
- }
99
-
100
53
  if (capabilities.rules && !dirs.rules) {
101
54
  errors.push(
102
55
  `Plugin "${plugin.name}" (${plugin.id}) declares rules capability but has no scaffold path configured.`
@@ -136,47 +89,34 @@ function checkAgents(repoRoot) {
136
89
  /** @type {string[]} */
137
90
  const warnings = [];
138
91
 
139
- // ---- 1. Run sync check ----
140
- let syncResult;
92
+ // ---- 1. Skills drift check ----
93
+ let driftResult;
141
94
  try {
142
- syncResult = syncCommands({ check: true, dryRun: false, repoRoot });
95
+ driftResult = checkSkillsSync({ repoRoot });
143
96
  } catch (err) {
144
- errors.push(`Sync check failed: ${err.message}`);
97
+ errors.push(`Skills sync check failed: ${err.message}`);
145
98
  return { errors, warnings };
146
99
  }
147
100
 
148
- if (syncResult.empty) {
149
- errors.push('No command files found in .claude/commands/ — cannot verify sync.');
101
+ const canonicalSkillsDir = path.join(repoRoot, 'skills');
102
+ if (!fs.existsSync(canonicalSkillsDir)) {
103
+ errors.push('No canonical skills found in skills/ — cannot verify skill sync.');
150
104
  return { errors, warnings };
151
- } else {
152
- if (syncResult.manifestMissing) {
153
- warnings.push(
154
- 'Sync manifest (.forge/sync-manifest.json) not found — stale file detection skipped. ' +
155
- 'Run "node scripts/sync-commands.js" to generate it.'
156
- );
157
- }
105
+ }
158
106
 
159
- if (syncResult.outOfSync && syncResult.outOfSync.length > 0) {
160
- for (const entry of syncResult.outOfSync) {
161
- const relPath = path.join(entry.dir, entry.filename);
162
- const exists = fs.existsSync(entry.filePath);
163
- const status = exists ? 'modified' : 'missing';
164
- errors.push(`Out of sync [${entry.agent}]: ${relPath} (${status})`);
165
- }
166
- }
107
+ if (driftResult.checkedAgents.length === 0) {
108
+ warnings.push(
109
+ 'No generated agent skill directories found (e.g. .codex/skills) — skill drift check skipped. ' +
110
+ 'Run "forge setup" or "skills sync" to populate them.'
111
+ );
112
+ }
167
113
 
168
- if (syncResult.staleFiles && syncResult.staleFiles.length > 0) {
169
- for (const filePath of syncResult.staleFiles) {
170
- const relPath = path.relative(repoRoot, filePath);
171
- errors.push(`Stale file (no longer generated, should be removed): ${relPath}`);
172
- }
173
- }
114
+ for (const d of driftResult.drift) {
115
+ errors.push(`Out of sync [${d.agent}]: ${d.skill}/${d.file} (${d.status})`);
174
116
  }
175
117
 
176
118
  // ---- 2. Validate plugin catalog ----
177
119
  const pluginDir = path.join(repoRoot, 'lib', 'agents');
178
- /** @type {object[]} */
179
- const plugins = [];
180
120
 
181
121
  if (!fs.existsSync(pluginDir)) {
182
122
  warnings.push('No plugin directory found at lib/agents/ — plugin catalog validation skipped.');
@@ -190,54 +130,11 @@ function checkAgents(repoRoot) {
190
130
  for (const file of pluginFiles) {
191
131
  try {
192
132
  const plugin = JSON.parse(fs.readFileSync(path.join(pluginDir, file), 'utf8'));
193
- plugins.push(plugin);
194
133
  validatePluginParity(plugin, errors);
195
134
  } catch (_err) {
196
135
  errors.push(`Failed to parse plugin file: lib/agents/${file}`);
197
136
  }
198
137
  }
199
-
200
- // For each plugin with commands: true, verify its command directory has files
201
- for (const plugin of plugins) {
202
- if (!plugin.capabilities || !plugin.capabilities.commands) {
203
- continue;
204
- }
205
-
206
- // Find the command directory from the plugin's directories config
207
- const dirs = plugin.directories || {};
208
- // Plugins use different keys: commands, workflows, prompts, skills
209
- const commandDir = dirs.commands || dirs.workflows || dirs.prompts;
210
-
211
- if (!commandDir) {
212
- // Plugin declares commands: true but has no command directory configured
213
- // Codex is the only agent that uses skills as its command mechanism
214
- if (plugin.id === 'codex' && dirs.skills) {
215
- // Codex CLI: commands live in .codex/skills/<name>/SKILL.md — skip standard check
216
- continue;
217
- }
218
- warnings.push(
219
- `Plugin "${plugin.name}" (${plugin.id}) has commands: true but no command directory configured.`
220
- );
221
- continue;
222
- }
223
-
224
- const absCmdDir = path.join(repoRoot, commandDir);
225
-
226
- if (!fs.existsSync(absCmdDir)) {
227
- errors.push(
228
- `Plugin "${plugin.name}" (${plugin.id}) has commands: true but directory "${commandDir}" does not exist.`
229
- );
230
- continue;
231
- }
232
-
233
- // Check the directory has at least one file
234
- const files = fs.readdirSync(absCmdDir).filter((f) => !f.startsWith('.'));
235
- if (files.length === 0) {
236
- errors.push(
237
- `Plugin "${plugin.name}" (${plugin.id}) has commands: true but directory "${commandDir}" is empty.`
238
- );
239
- }
240
- }
241
138
  }
242
139
 
243
140
  return { errors, warnings };
@@ -12,7 +12,9 @@ const isWindows = process.platform === 'win32';
12
12
 
13
13
  const commitMsgFile = process.argv[2];
14
14
  if (!commitMsgFile) {
15
- console.error('❌ No commit message file provided');
15
+ // Write synchronously so the message is flushed before exit: on Windows the
16
+ // stderr pipe is async and process.exit() can otherwise truncate it.
17
+ require('node:fs').writeSync(2, '❌ No commit message file provided\n');
16
18
  process.exit(1);
17
19
  }
18
20
 
@@ -17,6 +17,9 @@
17
17
  set -euo pipefail
18
18
 
19
19
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
20
+ if [[ -f "$SCRIPT_DIR/bootstrap-windows-tools.sh" ]]; then
21
+ source "$SCRIPT_DIR/bootstrap-windows-tools.sh"
22
+ fi
20
23
 
21
24
  # Source file-index helpers (file_index_read, file_index_get)
22
25
  source "$SCRIPT_DIR/file-index.sh" || { echo "FATAL: failed to source file-index.sh" >&2; exit 2; }
@@ -32,26 +32,61 @@ function normalizeSingleIssuePayload(payload) {
32
32
  return {};
33
33
  }
34
34
 
35
+ function readStdinPayload() {
36
+ const raw = fs.readFileSync(0, 'utf8');
37
+ if (!raw.trim()) {
38
+ throw new Error('Expected JSON payload on stdin');
39
+ }
40
+
41
+ const payload = JSON.parse(raw);
42
+ return {
43
+ currentIssue: normalizeSingleIssuePayload(payload.currentIssue),
44
+ openIssues: normalizeListPayload(payload.openIssues),
45
+ inProgressIssues: normalizeListPayload(payload.inProgressIssues),
46
+ taskFile: payload.taskFile,
47
+ repositoryRoot: payload.repositoryRoot || process.cwd(),
48
+ };
49
+ }
50
+
35
51
  function main() {
36
- const [
37
- currentIssueFile,
38
- openIssuesFile,
39
- inProgressIssuesFile,
40
- taskFile,
41
- repositoryRoot = process.cwd(),
42
- ] = process.argv.slice(2);
52
+ const args = process.argv.slice(2);
53
+ let currentIssue;
54
+ let openIssues;
55
+ let taskFile;
56
+ let repositoryRoot;
43
57
 
44
- if (!currentIssueFile || !openIssuesFile || !inProgressIssuesFile || !taskFile) {
45
- throw new Error(
46
- 'Usage: dep-guard-analyze.js <current-issue.json> <open-issues.json> <in-progress-issues.json> <task-file> [repository-root]',
47
- );
48
- }
58
+ if (args[0] === '--stdin') {
59
+ const payload = readStdinPayload();
60
+ currentIssue = payload.currentIssue;
61
+ openIssues = [
62
+ ...payload.openIssues,
63
+ ...payload.inProgressIssues,
64
+ ].filter((issue) => issue && issue.id && issue.id !== currentIssue.id);
65
+ taskFile = payload.taskFile;
66
+ repositoryRoot = payload.repositoryRoot;
67
+ } else {
68
+ const [
69
+ currentIssueFile,
70
+ openIssuesFile,
71
+ inProgressIssuesFile,
72
+ taskFileArg,
73
+ repositoryRootArg = process.cwd(),
74
+ ] = args;
49
75
 
50
- const currentIssue = normalizeSingleIssuePayload(readJsonFile(currentIssueFile));
51
- const openIssues = [
52
- ...normalizeListPayload(readJsonFile(openIssuesFile)),
53
- ...normalizeListPayload(readJsonFile(inProgressIssuesFile)),
54
- ].filter((issue) => issue && issue.id && issue.id !== currentIssue.id);
76
+ if (!currentIssueFile || !openIssuesFile || !inProgressIssuesFile || !taskFileArg) {
77
+ throw new Error(
78
+ 'Usage: dep-guard-analyze.js <current-issue.json> <open-issues.json> <in-progress-issues.json> <task-file> [repository-root]',
79
+ );
80
+ }
81
+
82
+ currentIssue = normalizeSingleIssuePayload(readJsonFile(currentIssueFile));
83
+ openIssues = [
84
+ ...normalizeListPayload(readJsonFile(openIssuesFile)),
85
+ ...normalizeListPayload(readJsonFile(inProgressIssuesFile)),
86
+ ].filter((issue) => issue && issue.id && issue.id !== currentIssue.id);
87
+ taskFile = taskFileArg;
88
+ repositoryRoot = repositoryRootArg;
89
+ }
55
90
 
56
91
  const result = analyzePhase3Dependencies({
57
92
  currentIssue,
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const {
5
+ parseActiveIssueLines,
6
+ renderKeywordRippleReport,
7
+ } = require('../lib/dep-guard/keyword-ripple.js');
8
+
9
+ function main() {
10
+ try {
11
+ const report = renderKeywordRippleReport({
12
+ issueId: process.env.ISSUE_ID || '',
13
+ sourceTitle: process.env.SOURCE_TITLE || '',
14
+ activeIssues: parseActiveIssueLines(process.env.LIST_OUTPUT || ''),
15
+ });
16
+
17
+ if (report.overlapCount > 0) {
18
+ process.stdout.write(`⚠️ ${report.output}\n`);
19
+ return;
20
+ }
21
+
22
+ process.stdout.write(`✅ ${report.output}\n`);
23
+ } catch (error) {
24
+ console.error(`dep-guard-keyword-ripple: ${error.message}`);
25
+ process.exit(1);
26
+ }
27
+ }
28
+
29
+ main();
@@ -0,0 +1,86 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const fs = require('node:fs');
5
+
6
+ function readAnalysis() {
7
+ const raw = fs.readFileSync(0, 'utf8');
8
+ if (!raw.trim()) {
9
+ throw new Error('Expected JSON analysis payload on stdin');
10
+ }
11
+ return JSON.parse(raw);
12
+ }
13
+
14
+ function renderPhase3Review(analysis) {
15
+ const detectorCategories = Object.entries(analysis.scores ?? {})
16
+ .filter(([name, score]) => name !== 'rubric' && Number(score) > 0)
17
+ .map(([name]) => name);
18
+
19
+ const lines = [
20
+ '',
21
+ `Structured dependency review for ${analysis.currentIssue.id}...`,
22
+ '',
23
+ ];
24
+
25
+ if (!Array.isArray(analysis.issues) || analysis.issues.length === 0) {
26
+ lines.push('No conflicts detected');
27
+ return `${lines.join('\n')}\n`;
28
+ }
29
+
30
+ const seenPairs = new Set();
31
+ for (const finding of analysis.issues) {
32
+ const key = `${analysis.currentIssue.id}->${finding.targetIssueId}`;
33
+ if (seenPairs.has(key)) {
34
+ continue;
35
+ }
36
+ seenPairs.add(key);
37
+ lines.push(`Issue pair: ${analysis.currentIssue.id} -> ${finding.targetIssueId}`);
38
+ }
39
+
40
+ lines.push(`Rubric score: ${analysis.scores?.rubric ?? 0}`);
41
+ lines.push(
42
+ `Confidence: ${(analysis.confidence?.score ?? 0).toFixed(2)}${
43
+ analysis.confidence?.belowThreshold ? ' (below 70% threshold)' : ''
44
+ }`,
45
+ );
46
+ lines.push(`Detector categories: ${detectorCategories.join(', ') || 'none'}`);
47
+ lines.push(`Needs user decision: ${analysis.needsUserDecision ? 'yes' : 'no'}`);
48
+
49
+ if (Array.isArray(analysis.detectorConflicts) && analysis.detectorConflicts.length > 0) {
50
+ lines.push('Conflicts:');
51
+ for (const conflict of analysis.detectorConflicts) {
52
+ lines.push(` - ${conflict}`);
53
+ }
54
+ }
55
+
56
+ if (Array.isArray(analysis.proposals) && analysis.proposals.length > 0) {
57
+ lines.push('');
58
+ lines.push('Proposed dependency updates:');
59
+ for (const proposal of analysis.proposals) {
60
+ lines.push(` - ${proposal.dependentIssueId} depends on ${proposal.dependsOnIssueId}`);
61
+ if (Array.isArray(proposal.pros) && proposal.pros.length > 0) {
62
+ lines.push(` Pros: ${proposal.pros.join('; ')}`);
63
+ }
64
+ if (Array.isArray(proposal.cons) && proposal.cons.length > 0) {
65
+ lines.push(` Cons: ${proposal.cons.join('; ')}`);
66
+ }
67
+ }
68
+ }
69
+
70
+ return `${lines.join('\n')}\n`;
71
+ }
72
+
73
+ function main() {
74
+ process.stdout.write(renderPhase3Review(readAnalysis()));
75
+ }
76
+
77
+ try {
78
+ main();
79
+ } catch (error) {
80
+ process.stderr.write(`${error.message}\n`);
81
+ process.exit(1);
82
+ }
83
+
84
+ module.exports = {
85
+ renderPhase3Review,
86
+ };