forge-workflow 0.0.10 → 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 (454) 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 +150 -61
  8. package/CHANGELOG.md +681 -0
  9. package/CLAUDE.md +9 -118
  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 +461 -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 +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/{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 +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 +121 -0
  81. package/lib/beads-sync-scaffold.js +25 -101
  82. package/lib/codex-skills.js +51 -1
  83. package/lib/commands/_issue.js +741 -77
  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 +17 -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 +0 -1
  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 +838 -972
  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 +158 -21
  140. package/lib/commands/sync.js +34 -46
  141. package/lib/commands/team.js +4 -1
  142. package/lib/commands/test.js +43 -27
  143. package/lib/commands/update.js +2 -2
  144. package/lib/commands/upgrade.js +47 -0
  145. package/lib/commands/validate.js +43 -18
  146. package/lib/commands/worktree.js +307 -100
  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 +2 -2
  151. package/lib/deprecated-sync-cleanup.js +362 -0
  152. package/lib/detect-agent.js +2 -28
  153. package/lib/detect-worktree.js +35 -9
  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 +382 -11
  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/kernel/backing-issue.js +305 -0
  174. package/lib/kernel/broker.js +1218 -0
  175. package/lib/kernel/cli-broker-factory.js +130 -0
  176. package/lib/kernel/conflict-signal.js +82 -0
  177. package/lib/kernel/evaluators.js +195 -0
  178. package/lib/kernel/fs-class.js +495 -0
  179. package/lib/kernel/issue-command-contract.js +559 -0
  180. package/lib/kernel/issue-id-resolver.js +186 -0
  181. package/lib/kernel/lease-enforcer.js +158 -0
  182. package/lib/kernel/migrations.js +333 -0
  183. package/lib/kernel/planning-buckets-schema.js +109 -0
  184. package/lib/kernel/projection-jsonl-writer.js +450 -0
  185. package/lib/kernel/readiness-model.js +329 -0
  186. package/lib/kernel/schema.js +356 -0
  187. package/lib/kernel/sqlite-driver.js +2504 -0
  188. package/lib/kernel/taxonomy-validator.js +394 -0
  189. package/lib/lefthook-check.js +3 -2
  190. package/lib/lefthook-wiring.js +413 -0
  191. package/lib/mcp-config-renderer.js +288 -0
  192. package/lib/memory/graphiti-mcp.js +106 -0
  193. package/lib/memory/router.js +387 -0
  194. package/lib/memory/typed-api.js +102 -0
  195. package/lib/memory-digest.js +195 -0
  196. package/lib/merge-rules.js +395 -0
  197. package/lib/migrate-dry-run.js +466 -0
  198. package/lib/orientation.js +863 -0
  199. package/lib/package-manager-remediation.js +103 -0
  200. package/lib/package-root.js +381 -0
  201. package/lib/patch-intent.js +890 -0
  202. package/lib/plugin-catalog.js +3 -4
  203. package/lib/plugin-manager.js +0 -5
  204. package/lib/pr-bundle.js +186 -0
  205. package/lib/pr-monitor/differ.js +195 -0
  206. package/lib/pr-monitor/events.js +0 -0
  207. package/lib/pr-monitor/gather.js +124 -0
  208. package/lib/pr-monitor/journal.js +299 -0
  209. package/lib/pr-monitor/monitor.js +146 -0
  210. package/lib/pr-monitor/render-sticky.js +157 -0
  211. package/lib/pr-monitor/watch-lifecycle.js +95 -0
  212. package/lib/pr-monitor/watch.js +247 -0
  213. package/lib/pr-pull.js +1273 -0
  214. package/lib/pr-shepherd.js +494 -0
  215. package/lib/pr-state-validator.js +59 -0
  216. package/lib/preflight/gates.js +237 -0
  217. package/lib/preflight/runner.js +116 -0
  218. package/lib/project-discovery.js +0 -53
  219. package/lib/project-memory.js +99 -497
  220. package/lib/protected-path-manifest.js +281 -0
  221. package/lib/protected-state-surfaces.js +387 -0
  222. package/lib/release-readiness.js +2089 -0
  223. package/lib/reset.js +59 -45
  224. package/lib/review-adapter.js +68 -0
  225. package/lib/rules-sync.js +260 -0
  226. package/lib/runtime-health.js +241 -20
  227. package/lib/safety-config-renderer.js +268 -0
  228. package/lib/setup-action-log.js +1 -7
  229. package/lib/setup.js +27 -65
  230. package/lib/shell-utils.js +76 -6
  231. package/lib/skills-sync.js +330 -0
  232. package/lib/smart-status/scoring.js +17 -3
  233. package/lib/status/beads-snapshot.js +45 -2
  234. package/lib/status/presenter.js +169 -18
  235. package/lib/status/snapshot.js +186 -0
  236. package/lib/sync-backend.js +202 -0
  237. package/lib/untrusted-content.js +52 -0
  238. package/lib/upgrade-safety.js +199 -0
  239. package/lib/workflow/enforce-stage.js +296 -47
  240. package/lib/workflow/stage-transition.js +115 -0
  241. package/lib/workflow/stages.js +30 -6
  242. package/lib/workflow/state-manager.js +11 -22
  243. package/lib/workflow/state.js +23 -1
  244. package/lib/workflow-profiles.js +17 -5
  245. package/package.json +37 -35
  246. package/rules/documentation.md +19 -0
  247. package/rules/kernel-tracking.md +26 -0
  248. package/rules/security.md +22 -0
  249. package/rules/tdd.md +20 -0
  250. package/rules/workflow.md +27 -0
  251. package/scripts/auto-backing-issue.js +47 -0
  252. package/scripts/beads-context.sh +81 -57
  253. package/scripts/beads-upgrade-smoke.sh +24 -3
  254. package/scripts/bootstrap-windows-tools.sh +78 -0
  255. package/scripts/branch-protection.js +2 -3
  256. package/scripts/check-agents.js +34 -137
  257. package/scripts/commitlint.js +3 -1
  258. package/scripts/conflict-detect.sh +3 -0
  259. package/scripts/dep-guard.sh +22 -3
  260. package/scripts/file-index.sh +3 -0
  261. package/scripts/forge-team/lib/claim.sh +34 -18
  262. package/scripts/forge-team/lib/dashboard.sh +61 -86
  263. package/scripts/forge-team/lib/epic.sh +99 -263
  264. package/scripts/forge-team/lib/hooks.sh +26 -28
  265. package/scripts/forge-team/lib/identity.sh +4 -4
  266. package/scripts/forge-team/lib/sync-github.sh +49 -84
  267. package/scripts/forge-team/lib/verify.sh +93 -83
  268. package/scripts/forge-team/lib/workload.sh +41 -65
  269. package/scripts/forge-team/tests/claim.test.sh +25 -19
  270. package/scripts/forge-team/tests/dashboard.test.sh +31 -46
  271. package/scripts/forge-team/tests/epic.test.sh +52 -71
  272. package/scripts/forge-team/tests/hooks.test.sh +38 -50
  273. package/scripts/forge-team/tests/identity.test.sh +3 -3
  274. package/scripts/forge-team/tests/integration.test.sh +44 -66
  275. package/scripts/forge-team/tests/sync-github.test.sh +50 -83
  276. package/scripts/forge-team/tests/verify.test.sh +37 -46
  277. package/scripts/forge-team/tests/workflow-integration.test.sh +4 -4
  278. package/scripts/forge-team/tests/workload.test.sh +32 -66
  279. package/scripts/gen-command-manifest.js +153 -0
  280. package/scripts/gen-embedded-assets.mjs +129 -0
  281. package/scripts/install.ps1 +139 -0
  282. package/scripts/install.sh +268 -0
  283. package/scripts/lib/release-asset.mjs +84 -0
  284. package/scripts/parity-check.mjs +145 -0
  285. package/scripts/parity-check.test.mjs +58 -0
  286. package/scripts/pin-agentic-workflow-images.js +112 -0
  287. package/scripts/pr-coordinator.sh +3 -0
  288. package/scripts/preflight-sonar.eslint.config.mjs +44 -0
  289. package/scripts/preflight.sh +21 -94
  290. package/scripts/protected-state-check.js +104 -0
  291. package/scripts/smart-status.sh +60 -57
  292. package/scripts/spikes/config-race-bench.js +111 -0
  293. package/scripts/spikes/harness-capability-matrix.js +13 -0
  294. package/scripts/spikes/patch-anchor-stability-bench.js +125 -0
  295. package/scripts/spikes/protected-path-manifest.js +20 -0
  296. package/scripts/spikes/skill-auto-invoke-parity.js +292 -0
  297. package/scripts/sync-agent-skills.js +62 -0
  298. package/scripts/sync-utils.sh +3 -0
  299. package/scripts/test-ci-shard.js +13 -6
  300. package/scripts/test.js +95 -12
  301. package/skills/claim-safety/SKILL.md +102 -0
  302. package/skills/claim-safety/evals/evals.json +46 -0
  303. package/{.github/prompts/dev.prompt.md → skills/dev/SKILL.md} +44 -50
  304. package/skills/dev/evals/evals.json +50 -0
  305. package/skills/hermes-forge/SKILL.md +185 -0
  306. package/skills/hermes-forge/evals/evals.json +46 -0
  307. package/skills/issue-basics/SKILL.md +111 -0
  308. package/skills/issue-basics/evals/evals.json +46 -0
  309. package/skills/kernel/SKILL.md +166 -0
  310. package/skills/kernel/evals/evals.json +50 -0
  311. package/skills/memory/SKILL.md +102 -0
  312. package/skills/parallel-deep-research/SKILL.md +14 -11
  313. package/skills/parallel-deep-research/evals/evals.json +11 -27
  314. package/{.github/prompts/plan.prompt.md → skills/plan/SKILL.md} +132 -157
  315. package/skills/plan/evals/evals.json +42 -0
  316. package/skills/research/SKILL.md +195 -0
  317. package/skills/research/evals/evals.json +42 -0
  318. package/{.github/prompts/review.prompt.md → skills/review/SKILL.md} +98 -62
  319. package/skills/review/evals/evals.json +42 -0
  320. package/skills/rollback/SKILL.md +110 -0
  321. package/skills/rollback/evals/evals.json +46 -0
  322. package/skills/rollback/references/methods.md +204 -0
  323. package/{.cursor/commands/rollback.md → skills/rollback/references/workflow-integration.md} +10 -284
  324. package/skills/shepherd/SKILL.md +66 -0
  325. package/skills/shepherd/evals/evals.json +42 -0
  326. package/{.github/prompts/ship.prompt.md → skills/ship/SKILL.md} +81 -45
  327. package/skills/ship/evals/evals.json +42 -0
  328. package/skills/smith/SKILL.md +142 -0
  329. package/skills/smith/evals/evals.json +46 -0
  330. package/skills/smith/references/autonomy-and-gates.md +94 -0
  331. package/{.github/prompts/sonarcloud.prompt.md → skills/sonarcloud/SKILL.md} +14 -3
  332. package/skills/sonarcloud/evals/evals.json +46 -0
  333. package/skills/sonarcloud-analysis/SKILL.md +18 -13
  334. package/skills/sonarcloud-analysis/evals/evals.json +11 -15
  335. package/{.github/prompts/status.prompt.md → skills/status/SKILL.md} +20 -10
  336. package/skills/status/evals/evals.json +50 -0
  337. package/skills/triage-ready/SKILL.md +121 -0
  338. package/skills/triage-ready/evals/evals.json +42 -0
  339. package/{.github/prompts/validate.prompt.md → skills/validate/SKILL.md} +52 -29
  340. package/skills/validate/evals/evals.json +42 -0
  341. package/skills/verify/SKILL.md +299 -0
  342. package/skills/verify/evals/evals.json +50 -0
  343. package/.claude/commands/dev.md +0 -345
  344. package/.claude/commands/plan.md +0 -566
  345. package/.claude/commands/premerge.md +0 -186
  346. package/.claude/commands/research.md +0 -42
  347. package/.claude/commands/review.md +0 -451
  348. package/.claude/commands/rollback.md +0 -721
  349. package/.claude/commands/ship.md +0 -213
  350. package/.claude/commands/sonarcloud.md +0 -152
  351. package/.claude/commands/status.md +0 -90
  352. package/.claude/commands/validate.md +0 -288
  353. package/.claude/commands/verify.md +0 -269
  354. package/.claude/rules/workflow.md +0 -121
  355. package/.cline/workflows/dev.md +0 -342
  356. package/.cline/workflows/plan.md +0 -563
  357. package/.cline/workflows/premerge.md +0 -183
  358. package/.cline/workflows/research.md +0 -39
  359. package/.cline/workflows/review.md +0 -448
  360. package/.cline/workflows/rollback.md +0 -718
  361. package/.cline/workflows/ship.md +0 -210
  362. package/.cline/workflows/sonarcloud.md +0 -146
  363. package/.cline/workflows/status.md +0 -87
  364. package/.cline/workflows/validate.md +0 -285
  365. package/.cline/workflows/verify.md +0 -266
  366. package/.codex/config.toml +0 -11
  367. package/.codex/skills/dev/SKILL.md +0 -345
  368. package/.codex/skills/plan/SKILL.md +0 -566
  369. package/.codex/skills/premerge/SKILL.md +0 -186
  370. package/.codex/skills/research/SKILL.md +0 -42
  371. package/.codex/skills/review/SKILL.md +0 -451
  372. package/.codex/skills/rollback/SKILL.md +0 -721
  373. package/.codex/skills/ship/SKILL.md +0 -213
  374. package/.codex/skills/sonarcloud/SKILL.md +0 -149
  375. package/.codex/skills/status/SKILL.md +0 -90
  376. package/.codex/skills/validate/SKILL.md +0 -288
  377. package/.codex/skills/verify/SKILL.md +0 -269
  378. package/.cursor/commands/dev.md +0 -342
  379. package/.cursor/commands/plan.md +0 -563
  380. package/.cursor/commands/premerge.md +0 -183
  381. package/.cursor/commands/research.md +0 -39
  382. package/.cursor/commands/review.md +0 -448
  383. package/.cursor/commands/ship.md +0 -210
  384. package/.cursor/commands/sonarcloud.md +0 -146
  385. package/.cursor/commands/status.md +0 -87
  386. package/.cursor/commands/validate.md +0 -285
  387. package/.cursor/commands/verify.md +0 -266
  388. package/.cursorrules +0 -149
  389. package/.github/prompts/premerge.prompt.md +0 -188
  390. package/.github/prompts/research.prompt.md +0 -44
  391. package/.github/prompts/rollback.prompt.md +0 -723
  392. package/.github/prompts/verify.prompt.md +0 -271
  393. package/.github/workflows/beads-to-github.yml +0 -89
  394. package/.github/workflows/github-to-beads.yml +0 -100
  395. package/.kilocode/workflows/dev.md +0 -346
  396. package/.kilocode/workflows/plan.md +0 -567
  397. package/.kilocode/workflows/premerge.md +0 -187
  398. package/.kilocode/workflows/research.md +0 -43
  399. package/.kilocode/workflows/review.md +0 -452
  400. package/.kilocode/workflows/rollback.md +0 -722
  401. package/.kilocode/workflows/ship.md +0 -214
  402. package/.kilocode/workflows/sonarcloud.md +0 -150
  403. package/.kilocode/workflows/status.md +0 -91
  404. package/.kilocode/workflows/validate.md +0 -289
  405. package/.kilocode/workflows/verify.md +0 -270
  406. package/.opencode/commands/dev.md +0 -345
  407. package/.opencode/commands/plan.md +0 -566
  408. package/.opencode/commands/premerge.md +0 -186
  409. package/.opencode/commands/research.md +0 -42
  410. package/.opencode/commands/review.md +0 -451
  411. package/.opencode/commands/rollback.md +0 -721
  412. package/.opencode/commands/ship.md +0 -213
  413. package/.opencode/commands/sonarcloud.md +0 -149
  414. package/.opencode/commands/status.md +0 -90
  415. package/.opencode/commands/validate.md +0 -288
  416. package/.opencode/commands/verify.md +0 -269
  417. package/.roo/commands/dev.md +0 -346
  418. package/.roo/commands/plan.md +0 -567
  419. package/.roo/commands/premerge.md +0 -187
  420. package/.roo/commands/research.md +0 -43
  421. package/.roo/commands/review.md +0 -452
  422. package/.roo/commands/rollback.md +0 -722
  423. package/.roo/commands/ship.md +0 -214
  424. package/.roo/commands/sonarcloud.md +0 -150
  425. package/.roo/commands/status.md +0 -91
  426. package/.roo/commands/validate.md +0 -289
  427. package/.roo/commands/verify.md +0 -270
  428. package/docs/BEADS_GITHUB_SYNC.md +0 -281
  429. package/docs/GREPTILE_SETUP.md +0 -400
  430. package/docs/MANUAL_REVIEW_GUIDE.md +0 -106
  431. package/docs/SETUP.md +0 -663
  432. package/docs/VALIDATION.md +0 -363
  433. package/lib/agents/cline.plugin.json +0 -29
  434. package/lib/agents/copilot.plugin.json +0 -24
  435. package/lib/agents/kilocode.plugin.json +0 -22
  436. package/lib/agents/opencode.plugin.json +0 -23
  437. package/lib/agents/roo.plugin.json +0 -30
  438. package/lib/beads-bootstrap.js +0 -225
  439. package/lib/beads-health-check.js +0 -188
  440. package/lib/commands/commands-reset.js +0 -147
  441. package/opencode.json +0 -67
  442. package/scripts/beads-context.test.js +0 -584
  443. package/scripts/github-beads-sync/comment.mjs +0 -64
  444. package/scripts/github-beads-sync/config.mjs +0 -148
  445. package/scripts/github-beads-sync/github-api.mjs +0 -131
  446. package/scripts/github-beads-sync/index.mjs +0 -356
  447. package/scripts/github-beads-sync/label-mapper.mjs +0 -54
  448. package/scripts/github-beads-sync/mapping.mjs +0 -132
  449. package/scripts/github-beads-sync/reverse-sync-cli.mjs +0 -31
  450. package/scripts/github-beads-sync/reverse-sync.mjs +0 -162
  451. package/scripts/github-beads-sync/run-bd.mjs +0 -161
  452. package/scripts/github-beads-sync/sanitize.mjs +0 -121
  453. package/scripts/github-beads-sync.config.json +0 -26
  454. package/scripts/sync-commands.js +0 -600
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  const { runIssueOperation } = require('../forge-issues');
4
+ const { SUBCOMMANDS } = require('./_issue');
4
5
 
5
6
  const SUPPORTED_SUBCOMMANDS = ['create', 'list', 'show', 'close', 'update'];
6
7
 
@@ -25,6 +26,10 @@ module.exports = {
25
26
  name: 'issues',
26
27
  description: 'Manage issues through the Forge authority layer',
27
28
  usage: 'forge issues <subcommand> [...]',
29
+ // Undocumented back-compat alias for the canonical `forge issue` surface. It stays
30
+ // registered and executable, but `hidden: true` omits it from `forge --help` so the
31
+ // singular `issue` reads as the one canonical issue surface (kernel issue 450c6e34).
32
+ hidden: true,
28
33
  flags: {},
29
34
  handler: async (args, _flags, projectRoot, opts = {}) => {
30
35
  const [subcommand, ...rest] = normalizeArgs(args);
@@ -43,6 +48,18 @@ module.exports = {
43
48
  };
44
49
  }
45
50
 
51
+ // --help for a specific subcommand: print its usage and return BEFORE dispatching
52
+ // to any backend. Otherwise --help is forwarded as an operation arg, which is
53
+ // absorbed by Beads but fails with a bare "Command failed" on the Kernel default
54
+ // (mirrors the short-circuit in lib/commands/_issue.js runIssueSubcommand).
55
+ if (rest.some(arg => arg === '--help' || arg === '-h')) {
56
+ const spec = SUBCOMMANDS[subcommand];
57
+ return {
58
+ success: true,
59
+ output: spec ? `${spec.usage}\n\n${spec.description}` : formatHelp(),
60
+ };
61
+ }
62
+
46
63
  const runner = opts.runIssueOperation || runIssueOperation;
47
64
  return runner(subcommand, rest, projectRoot, opts);
48
65
  },
@@ -0,0 +1,5 @@
1
+ 'use strict';
2
+
3
+ const { createIssueSubcommand } = require('./_issue');
4
+
5
+ module.exports = createIssueSubcommand('lint');
@@ -1,5 +1,5 @@
1
1
  'use strict';
2
2
 
3
- const { makeAliasCommand } = require('./_issue');
3
+ const { createIssueSubcommand } = require('./_issue');
4
4
 
5
- module.exports = makeAliasCommand('list');
5
+ module.exports = createIssueSubcommand('list');
@@ -0,0 +1,312 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * merge command — opt-in conditional auto-merge.
5
+ *
6
+ * `forge merge --auto <pr>` is the ONLY path by which Forge will merge a PR on
7
+ * its own, and it stays OFF unless the user has explicitly opted in. It reads
8
+ * the `merge.auto` section of `.forge/config.yaml`:
9
+ *
10
+ * merge:
11
+ * auto:
12
+ * enabled: true # default false / absent → strict NO-OP
13
+ * rules: # ALL must pass (see lib/merge-rules.js)
14
+ * - checks_green # or scope it, e.g. for a docs-only task that
15
+ * # may take a coverage dip:
16
+ * # - checks_green: { ignore: ["Coverage"] }
17
+ * - threads_resolved
18
+ * - no_conflicts # recommended: never merge a conflicting branch
19
+ * - not_behind
20
+ * - settle_min: 10
21
+ *
22
+ * Flow: with no config (or `enabled` not true) the command is a strict NO-OP —
23
+ * it prints why and merges nothing, preserving the test-enforced
24
+ * never-auto-merge-by-default invariant. When enabled, it fetches the PR
25
+ * context via `gh`, evaluates the rules with the pure `evaluateMergeRules`, and
26
+ * merges ONLY when every rule passes. Two extra safety layers wrap that decision:
27
+ * a pre-flight guard that no-ops on an already merged/closed PR (idempotent
28
+ * re-runs), and a TOCTOU live re-check that re-fetches and re-evaluates right
29
+ * before merging so a stale snapshot can never merge a since-changed PR. The
30
+ * gh-fetch and the merge action are isolated behind injectable `fetchPrContext`
31
+ * / `mergePr` seams so the decision path is unit-testable without the network.
32
+ *
33
+ * A bring-your-own custom-predicate seam (registered via `forge add`) is a
34
+ * documented follow-up and intentionally NOT wired here. Further follow-ups
35
+ * documented in lib/merge-rules.js: opt-in `auto_update`, required-checks
36
+ * scoping for `checks_green`, a configurable merge `method`, and post-merge
37
+ * branch deletion.
38
+ *
39
+ * @module commands/merge
40
+ */
41
+
42
+ const { execFileSync } = require('node:child_process');
43
+
44
+ const { loadRawConfig } = require('../config-writer');
45
+ const { evaluateMergeRules } = require('../merge-rules');
46
+
47
+ /** Default `gh` runner. Only reached by the default fetch/merge seams (never in unit tests). */
48
+ function defaultGh(args, options = {}) {
49
+ return execFileSync('gh', args, { encoding: 'utf8', ...options }); // NOSONAR S4036 - hardcoded CLI (gh), args array (no shell), developer-tool context
50
+ }
51
+
52
+ /** Parse `gh ... --json` output, returning `null` on any failure (callers fail closed). */
53
+ function ghJson(gh, args) {
54
+ try {
55
+ return JSON.parse(gh(args) || '{}');
56
+ } catch (_err) {
57
+ return null;
58
+ }
59
+ }
60
+
61
+ /**
62
+ * Read the unresolved review-thread count via the GraphQL API. `reviewThreads`
63
+ * is not a valid `gh pr view --json` field, so this needs a dedicated query.
64
+ * Returns `undefined` on any failure so `threads_resolved` fails closed.
65
+ */
66
+ function fetchUnresolvedThreadCount(gh, pr) {
67
+ try {
68
+ const repo = ghJson(gh, ['repo', 'view', '--json', 'owner,name']);
69
+ const owner = repo && repo.owner && repo.owner.login;
70
+ const name = repo && repo.name;
71
+ if (!owner || !name) return undefined;
72
+ // Paginate through ALL review threads — a PR can have >100, and the ones on
73
+ // later pages could be the unresolved/newest ones. Stopping at page 1 would
74
+ // both miss them and make a large PR un-mergeable. Loop on the GraphQL cursor
75
+ // until hasNextPage is false; any unreadable page → undefined (fail closed).
76
+ const query = 'query($o:String!,$n:String!,$pr:Int!,$after:String){repository(owner:$o,name:$n)'
77
+ + '{pullRequest(number:$pr){reviewThreads(first:100,after:$after){pageInfo{hasNextPage endCursor}nodes{isResolved isOutdated}}}}}';
78
+ let after = '';
79
+ let count = 0;
80
+ for (let page = 0; page < 100; page += 1) { // 100-page cap = 10k threads backstop
81
+ const args = ['api', 'graphql', '-f', `query=${query}`,
82
+ '-F', `o=${owner}`, '-F', `n=${name}`, '-F', `pr=${Number(pr)}`];
83
+ if (after) args.push('-F', `after=${after}`);
84
+ const data = JSON.parse(gh(args) || '{}');
85
+ const threads = (((data.data || {}).repository || {}).pullRequest || {}).reviewThreads;
86
+ if (!threads) return undefined; // unreadable page → fail closed
87
+ count += (threads.nodes || []).filter((t) => t && t.isResolved === false && t.isOutdated === false).length;
88
+ if (!threads.pageInfo || !threads.pageInfo.hasNextPage) return count;
89
+ after = threads.pageInfo.endCursor;
90
+ if (!after) return undefined; // hasNextPage but no cursor → fail closed
91
+ }
92
+ return undefined; // exceeded the page cap → fail closed rather than undercount
93
+ } catch (_err) {
94
+ return undefined;
95
+ }
96
+ }
97
+
98
+ /**
99
+ * Default PR-context fetcher (the network seam). Assembles the shape consumed
100
+ * by `evaluateMergeRules` from `gh`. Anything it cannot read is left absent so
101
+ * the dependent rule fails closed rather than guessing. Fully replaced by
102
+ * `deps.fetchPrContext` in tests.
103
+ *
104
+ * @returns {object} prContext
105
+ */
106
+ function defaultFetchPrContext({ pr, gh = defaultGh, now = Date.now() }) {
107
+ const view = ghJson(gh, ['pr', 'view', String(pr), '--json',
108
+ 'number,state,isDraft,mergeable,mergeStateStatus,statusCheckRollup,reviews,comments,updatedAt']) || {};
109
+
110
+ const rollup = Array.isArray(view.statusCheckRollup) ? view.statusCheckRollup : null;
111
+ const checks = (rollup || []).map((c) => ({
112
+ name: c.name || c.context || '?',
113
+ conclusion: String(c.conclusion || c.state || c.status || ''),
114
+ }));
115
+
116
+ const comments = Array.isArray(view.comments)
117
+ ? view.comments.map((c) => ({
118
+ author: (c.author && c.author.login) || '',
119
+ at: c.createdAt || c.submittedAt || '',
120
+ }))
121
+ : [];
122
+
123
+ const reviews = Array.isArray(view.reviews) ? view.reviews : [];
124
+ const approvals = reviews
125
+ .filter((r) => String(r.state).toUpperCase() === 'APPROVED')
126
+ .map((r) => ({ author: (r.author && r.author.login) || '' }));
127
+
128
+ // Derive from GitHub's mergeStateStatus / mergeable. Only a known set maps to
129
+ // a definite answer; anything else stays undefined so the dependent rule fails
130
+ // closed rather than guessing.
131
+ const mergeStateStatus = String(view.mergeStateStatus || '').toUpperCase();
132
+ const mergeable = String(view.mergeable || '').toUpperCase();
133
+
134
+ let behindBase;
135
+ if (mergeStateStatus === 'BEHIND') behindBase = true;
136
+ else if (['CLEAN', 'UNSTABLE', 'HAS_HOOKS', 'BLOCKED', 'DIRTY'].includes(mergeStateStatus)) behindBase = false;
137
+
138
+ // Conflict status: DIRTY (or mergeable=CONFLICTING) → conflicting; a clean set
139
+ // of states → not conflicting; UNKNOWN / missing / still-computing → undefined.
140
+ let conflicting;
141
+ if (mergeStateStatus === 'DIRTY' || mergeable === 'CONFLICTING') conflicting = true;
142
+ else if (['CLEAN', 'UNSTABLE', 'HAS_HOOKS', 'BLOCKED'].includes(mergeStateStatus)) conflicting = false;
143
+
144
+ const isDraft = typeof view.isDraft === 'boolean' ? view.isDraft : undefined;
145
+ const state = view.state ? String(view.state).toUpperCase() : undefined;
146
+
147
+ const stamps = [
148
+ ...comments.map((c) => c.at),
149
+ ...reviews.map((r) => r.submittedAt || r.createdAt || ''),
150
+ view.updatedAt || '',
151
+ ].map((s) => Date.parse(s)).filter((n) => !Number.isNaN(n));
152
+ const lastActivityAt = stamps.length ? Math.max(...stamps) : undefined;
153
+
154
+ return {
155
+ checks,
156
+ requiredChecksKnown: rollup !== null,
157
+ unresolvedThreads: fetchUnresolvedThreadCount(gh, pr),
158
+ behindBase,
159
+ conflicting,
160
+ isDraft,
161
+ state,
162
+ approvals,
163
+ comments,
164
+ lastActivityAt,
165
+ now,
166
+ };
167
+ }
168
+
169
+ /** Default merge action (squash). Fully replaced by `deps.mergePr` in tests. */
170
+ function defaultMergePr({ pr, gh = defaultGh }) {
171
+ gh(['pr', 'merge', String(pr), '--squash']);
172
+ return { merged: true, method: 'squash' };
173
+ }
174
+
175
+ /**
176
+ * Command handler.
177
+ *
178
+ * @param {string[]} args - Positional + flag args (first positional is the PR).
179
+ * @param {object} _flags - Parsed flags (unused; flags are read from args).
180
+ * @param {string} projectRoot - Project root.
181
+ * @param {object} [deps] - Injected seams for testing: loadConfig, fetchPrContext, mergePr, gh, now.
182
+ * @returns {Promise<object>} result envelope.
183
+ */
184
+ async function handler(args, _flags, projectRoot, deps = {}) {
185
+ const argv = Array.isArray(args) ? args : [];
186
+ const positional = argv.filter((a) => !String(a).startsWith('--'));
187
+ const flags = new Set(argv.filter((a) => String(a).startsWith('--')));
188
+ const pr = positional[0];
189
+ const root = projectRoot || process.cwd();
190
+
191
+ if (!flags.has('--auto')) {
192
+ return { success: false, error: 'Usage: forge merge --auto <pr> (opt-in conditional auto-merge; OFF by default)' };
193
+ }
194
+ if (!pr) {
195
+ return { success: false, error: 'Usage: forge merge --auto <pr>' };
196
+ }
197
+
198
+ const loadConfig = deps.loadConfig || loadRawConfig;
199
+ let config;
200
+ try {
201
+ config = loadConfig(root) || {};
202
+ } catch (err) {
203
+ // A malformed .forge/config.yaml must NOT crash the command — fail closed:
204
+ // refuse to auto-merge and report, rather than throwing past the contract.
205
+ const reason = `Could not read merge config (${err.message}) — refusing to auto-merge (fail-closed).`;
206
+ process.stdout.write(`${reason}\n`);
207
+ return { success: false, merged: false, error: reason };
208
+ }
209
+ const auto = (config.merge && config.merge.auto) || {};
210
+ const enabled = auto.enabled === true;
211
+ const rules = Array.isArray(auto.rules) ? auto.rules : [];
212
+
213
+ // Invariant: absent config or `enabled` not true → strict NO-OP. Forge never
214
+ // auto-merges unless the user has explicitly opted in via .forge/config.yaml.
215
+ if (!enabled) {
216
+ const reason = 'Auto-merge is OPT-IN and OFF by default (merge.auto.enabled is not true in .forge/config.yaml). No action taken.';
217
+ process.stdout.write(`${reason}\n`);
218
+ return { success: true, merged: false, enabled: false, reason };
219
+ }
220
+
221
+ // Opted in but no rules → refuse (fail-closed): an empty ruleset is vacuously
222
+ // "allowed", which would merge unconditionally. Treat that as misconfiguration.
223
+ if (rules.length === 0) {
224
+ const reason = 'merge.auto.enabled is true but no rules are configured — refusing to auto-merge (fail-closed). Add rules under merge.auto.rules.';
225
+ process.stdout.write(`${reason}\n`);
226
+ return { success: false, merged: false, enabled: true, reason };
227
+ }
228
+
229
+ const fetchPrContext = deps.fetchPrContext || defaultFetchPrContext;
230
+ const mergePr = deps.mergePr || defaultMergePr;
231
+ const gh = deps.gh || defaultGh;
232
+
233
+ let prContext;
234
+ try {
235
+ prContext = await fetchPrContext({ pr, projectRoot: root, gh, now: deps.now || Date.now() });
236
+ } catch (err) {
237
+ return { success: false, merged: false, error: `Failed to fetch PR context: ${err.message}` };
238
+ }
239
+
240
+ // Pre-flight: a PR that is already merged or closed is terminal. Re-running the
241
+ // command must be an idempotent NO-OP — never an error and never a second merge
242
+ // attempt. (An absent/unknown state falls through to the fail-closed rules.)
243
+ const prState = prContext && prContext.state ? String(prContext.state).toUpperCase() : '';
244
+ if (prState && prState !== 'OPEN') {
245
+ const reason = `PR #${pr} is ${prState} (not OPEN) — nothing to merge. No action taken.`;
246
+ process.stdout.write(`${reason}\n`);
247
+ return { success: true, merged: false, enabled: true, state: prState, reason };
248
+ }
249
+
250
+ const { allowed, unmet } = evaluateMergeRules(prContext, rules);
251
+
252
+ if (!allowed) {
253
+ process.stdout.write(`Auto-merge conditions NOT met for PR #${pr} — ${unmet.length} unmet rule(s):\n`);
254
+ for (const item of unmet) {
255
+ process.stdout.write(` x ${item.rule} — ${item.reason}\n`);
256
+ }
257
+ return { success: true, merged: false, enabled: true, allowed: false, unmet, reason: 'auto-merge conditions not met' };
258
+ }
259
+
260
+ // TOCTOU guard: PR state can change between the first fetch and the merge — a
261
+ // new comment resets settle_min, a required check regresses, a thread opens.
262
+ // Re-pull LIVE data and re-evaluate immediately before merging so our custom
263
+ // rules (which GitHub's server-side branch protection does NOT enforce) are
264
+ // honored against the freshest possible state, never a stale snapshot.
265
+ let freshContext;
266
+ try {
267
+ freshContext = await fetchPrContext({ pr, projectRoot: root, gh, now: deps.now || Date.now() });
268
+ } catch (err) {
269
+ return { success: false, merged: false, error: `Failed to re-fetch PR context before merge: ${err.message}` };
270
+ }
271
+ // Re-apply the terminal-state guard on the FRESH context: the PR may have been
272
+ // merged or closed between the first fetch and now. Never merge a terminal PR.
273
+ const freshState = freshContext && freshContext.state ? String(freshContext.state).toUpperCase() : '';
274
+ if (freshState && freshState !== 'OPEN') {
275
+ const reason = `PR #${pr} became ${freshState} (not OPEN) before merge — nothing to merge. No action taken.`;
276
+ process.stdout.write(`${reason}\n`);
277
+ return { success: true, merged: false, enabled: true, state: freshState, reason };
278
+ }
279
+ const recheck = evaluateMergeRules(freshContext, rules);
280
+ if (!recheck.allowed) {
281
+ process.stdout.write(`Auto-merge ABORTED for PR #${pr} — state changed since first check; ${recheck.unmet.length} rule(s) now unmet:\n`);
282
+ for (const item of recheck.unmet) {
283
+ process.stdout.write(` x ${item.rule} — ${item.reason}\n`);
284
+ }
285
+ return { success: true, merged: false, enabled: true, allowed: false, unmet: recheck.unmet, reason: 'PR state changed before merge (live re-check failed)' };
286
+ }
287
+
288
+ try {
289
+ const mergeResult = await mergePr({ pr, projectRoot: root, gh });
290
+ process.stdout.write(`All ${rules.length} merge rule(s) passed — merged PR #${pr}.\n`);
291
+ return {
292
+ success: true,
293
+ merged: true,
294
+ enabled: true,
295
+ allowed: true,
296
+ reason: 'all merge rules passed',
297
+ ...(mergeResult && typeof mergeResult === 'object' ? mergeResult : {}),
298
+ };
299
+ } catch (err) {
300
+ return { success: false, merged: false, error: `Merge failed: ${err.message}` };
301
+ }
302
+ }
303
+
304
+ module.exports = {
305
+ name: 'merge',
306
+ description: 'Opt-in conditional auto-merge: merge a PR only when all user-configured rules pass (OFF by default)',
307
+ usage: 'Usage: forge merge --auto <pr>',
308
+ handler,
309
+ // Exported seams for testing / reuse.
310
+ defaultFetchPrContext,
311
+ defaultMergePr,
312
+ };