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,559 @@
1
+ 'use strict';
2
+
3
+ const ISSUE_COMMAND_SCHEMA_VERSION = 'forge.issue.v1';
4
+ const ISSUE_COMMAND_ERROR_SCHEMA_VERSION = 'forge.issue.error.v1';
5
+
6
+ const ISSUE_COMMAND_EXIT_CODES = Object.freeze({
7
+ success: 0,
8
+ internal: 1,
9
+ usage: 2,
10
+ notFound: 3,
11
+ conflict: 4,
12
+ unavailable: 5,
13
+ validation: 6,
14
+ });
15
+
16
+ // Canonical D18 taxonomy. Types and statuses are enforced at the validation layer
17
+ // (see taxonomy-validator), not as DB constraints, so label-based extensibility and
18
+ // derived readiness (ready/blocked) stay outside the stored status set.
19
+ const ISSUE_TYPES = Object.freeze(['epic', 'task', 'bug', 'decision']);
20
+ // `backlog` is a parked lifecycle state (ideas discussed but not yet scheduled): a real
21
+ // stored status, distinct from the derived readiness `backlog` state. Parked issues are
22
+ // NOT workable (excluded from WORKABLE_STATUSES) and NOT stale, but ARE counted in rollups.
23
+ const ISSUE_STATUSES = Object.freeze(['open', 'in_progress', 'review', 'done', 'cancelled', 'backlog']);
24
+ // Canonical priority labels P0..P4. The bare integers 0..4 are also accepted on input
25
+ // (the CLI documents `--priority 1`; normalizePriority maps ranks 0..4) — see
26
+ // isValidIssuePriority. P5+ / non-numeric labels are rejected at the validation layer,
27
+ // matching MAX_DISPLAY_PRIORITY_RANK in taxonomy-validator.
28
+ const ISSUE_PRIORITIES = Object.freeze(['P0', 'P1', 'P2', 'P3', 'P4']);
29
+
30
+ // True when `priority` is a canonical P0..P4 label (case-insensitive) or a bare
31
+ // integer 0..4. Used by the create/update validation gate to reject junk priorities
32
+ // (P9, BOGUS, -1) instead of persisting them verbatim — Beads rejected them too.
33
+ function isValidIssuePriority(priority) {
34
+ if (typeof priority === 'number') {
35
+ return Number.isInteger(priority) && priority >= 0 && priority <= 4;
36
+ }
37
+ if (typeof priority !== 'string') return false;
38
+ const raw = priority.trim().toUpperCase();
39
+ const match = /^P?([0-9]+)$/.exec(raw);
40
+ if (!match) return false;
41
+ const rank = Number(match[1]);
42
+ return rank >= 0 && rank <= 4;
43
+ }
44
+
45
+ // Canonicalize a priority input to its P0..P4 label. Accepts the canonical labels
46
+ // (case-insensitive) and the bare ranks 0..4 the CLI documents (`--priority 1`), and
47
+ // maps BOTH forms to the SAME label ('1' and 'P1' -> 'P1'). Out-of-range / non-priority
48
+ // input is returned UNCHANGED so the create/update validation gate (isValidIssuePriority)
49
+ // still REJECTS it rather than silently clamping (P9 must error, not become P4). The
50
+ // stored canonical form is this label; priority_rank is its numeric rank.
51
+ function normalizePriority(priority) {
52
+ if (!isValidIssuePriority(priority)) return priority;
53
+ const raw = typeof priority === 'number' ? String(priority) : priority.trim().toUpperCase();
54
+ const rank = Number(/^P?([0-9]+)$/.exec(raw)[1]);
55
+ return `P${rank}`;
56
+ }
57
+
58
+ function deepFreeze(value) {
59
+ if (!value || typeof value !== 'object') return value;
60
+ Object.freeze(value);
61
+ for (const nestedValue of Object.values(value)) {
62
+ deepFreeze(nestedValue);
63
+ }
64
+ return value;
65
+ }
66
+
67
+ const ISSUE_SUMMARY_SCHEMA = {
68
+ type: 'object',
69
+ required: ['id', 'title', 'type', 'status', 'revision'],
70
+ properties: {
71
+ id: { type: 'string' },
72
+ title: { type: 'string' },
73
+ body: { type: ['string', 'null'] },
74
+ type: { enum: [...ISSUE_TYPES] },
75
+ status: { enum: [...ISSUE_STATUSES] },
76
+ priority: { type: 'string' },
77
+ rank: { type: 'number' },
78
+ revision: { type: 'integer', minimum: 0 },
79
+ blocked: { type: 'boolean' },
80
+ claimed_by: { type: ['string', 'null'] },
81
+ // KAP-2: stored-but-previously-unprojected fields, surfaced for agents.
82
+ parent_id: { type: ['string', 'null'] },
83
+ labels: { type: 'array', items: { type: 'string' } },
84
+ dependencies: { type: 'array', items: { type: 'string' } },
85
+ // Epic/reverse-dependency exposure: `dependents` are the ids that depend on this
86
+ // issue (inverse of `dependencies`); `blocked_by` is the readiness model's live
87
+ // blocker subset. Additive superset on every read op (schema is permissive —
88
+ // no additionalProperties:false — so older consumers still validate).
89
+ dependents: { type: 'array', items: { type: 'string' } },
90
+ blocked_by: { type: 'array', items: { type: 'string' } },
91
+ created_at: { type: 'string' },
92
+ updated_at: { type: 'string' },
93
+ // KAP-10 (acceptance_criteria/design/notes) + KAP-11 (assignee): nullable
94
+ // content fields and a persistent assignee. Optional (NOT required) so summaries
95
+ // that omit them still validate.
96
+ acceptance_criteria: { type: ['string', 'null'] },
97
+ design: { type: ['string', 'null'] },
98
+ notes: { type: ['string', 'null'] },
99
+ assignee: { type: ['string', 'null'] },
100
+ // Beads full-fidelity import: author, close timestamp, raw close reason and a
101
+ // verbatim metadata JSON blob. Optional (NOT required) and nullable so summaries
102
+ // that omit them still validate.
103
+ created_by: { type: ['string', 'null'] },
104
+ closed_at: { type: ['string', 'null'] },
105
+ close_reason: { type: ['string', 'null'] },
106
+ metadata: { type: ['string', 'null'] },
107
+ // KAP-3: `show` attaches the issue's comments; other reads (list/ready/search/
108
+ // stats) omit the key. Optional (NOT in required) so comment-less summaries still
109
+ // validate. Each item carries id/body/actor/created_at (body may be null).
110
+ comments: {
111
+ type: 'array',
112
+ items: {
113
+ type: 'object',
114
+ required: ['id', 'body', 'actor', 'created_at'],
115
+ properties: {
116
+ id: { type: 'string' },
117
+ body: { type: ['string', 'null'] },
118
+ actor: { type: 'string' },
119
+ created_at: { type: 'string' },
120
+ },
121
+ },
122
+ },
123
+ // KAP-12: `lint` attaches a content-validation result to each FAILING issue;
124
+ // other reads (list/ready/search/...) omit the key. Optional (NOT in required)
125
+ // so validation-less summaries still validate. rules_failed names the broken
126
+ // content rules (e.g. 'missing_acceptance_criteria').
127
+ validation: {
128
+ type: 'object',
129
+ required: ['rules_failed'],
130
+ properties: {
131
+ rules_failed: { type: 'array', items: { type: 'string' } },
132
+ },
133
+ },
134
+ },
135
+ };
136
+
137
+ const NEXT_COMMANDS_SCHEMA = {
138
+ type: 'array',
139
+ items: { type: 'string' },
140
+ };
141
+
142
+ const ISSUE_COMMAND_RESPONSE_SCHEMAS = deepFreeze({
143
+ issue: {
144
+ type: 'object',
145
+ required: ['ok', 'schema_version', 'command', 'data', 'next_commands'],
146
+ properties: {
147
+ ok: { const: true },
148
+ schema_version: { const: ISSUE_COMMAND_SCHEMA_VERSION },
149
+ command: { type: 'string' },
150
+ data: ISSUE_SUMMARY_SCHEMA,
151
+ next_commands: NEXT_COMMANDS_SCHEMA,
152
+ },
153
+ },
154
+ issueList: {
155
+ type: 'object',
156
+ required: ['ok', 'schema_version', 'command', 'data', 'next_commands'],
157
+ properties: {
158
+ ok: { const: true },
159
+ schema_version: { const: ISSUE_COMMAND_SCHEMA_VERSION },
160
+ command: { type: 'string' },
161
+ data: {
162
+ type: 'object',
163
+ required: ['issues'],
164
+ properties: {
165
+ issues: {
166
+ type: 'array',
167
+ items: ISSUE_SUMMARY_SCHEMA,
168
+ },
169
+ count: { type: 'integer', minimum: 0 },
170
+ truncated: { type: 'boolean' },
171
+ },
172
+ },
173
+ next_commands: NEXT_COMMANDS_SCHEMA,
174
+ },
175
+ },
176
+ stats: {
177
+ type: 'object',
178
+ required: ['ok', 'schema_version', 'command', 'data', 'next_commands'],
179
+ properties: {
180
+ ok: { const: true },
181
+ schema_version: { const: ISSUE_COMMAND_SCHEMA_VERSION },
182
+ command: { type: 'string' },
183
+ data: {
184
+ type: 'object',
185
+ required: ['counts'],
186
+ properties: {
187
+ counts: { type: 'object' },
188
+ ready_count: { type: 'integer', minimum: 0 },
189
+ blocked_count: { type: 'integer', minimum: 0 },
190
+ active_claims: { type: 'integer', minimum: 0 },
191
+ },
192
+ },
193
+ next_commands: NEXT_COMMANDS_SCHEMA,
194
+ },
195
+ },
196
+ // KAP-7: derived read responses. `blocked` and `orphans` reuse the issueList
197
+ // shape above (an array of ISSUE_SUMMARY_SCHEMA + count). `stale` reuses that
198
+ // shape and additionally carries the threshold_days (in days) the staleness
199
+ // window was computed against.
200
+ staleList: {
201
+ type: 'object',
202
+ required: ['ok', 'schema_version', 'command', 'data', 'next_commands'],
203
+ properties: {
204
+ ok: { const: true },
205
+ schema_version: { const: ISSUE_COMMAND_SCHEMA_VERSION },
206
+ command: { type: 'string' },
207
+ data: {
208
+ type: 'object',
209
+ required: ['issues', 'count', 'threshold_days'],
210
+ properties: {
211
+ issues: {
212
+ type: 'array',
213
+ items: ISSUE_SUMMARY_SCHEMA,
214
+ },
215
+ count: { type: 'integer', minimum: 0 },
216
+ threshold_days: { type: 'integer' },
217
+ },
218
+ },
219
+ next_commands: NEXT_COMMANDS_SCHEMA,
220
+ },
221
+ },
222
+ // Epic support: `children` returns the epic header, its DIRECT children (each a full
223
+ // ISSUE_SUMMARY_SCHEMA), and a kernel-computed rollup. The rollup owns the status
224
+ // vocabulary so consumers never hard-code status names; `percentage` is done-only.
225
+ children: {
226
+ type: 'object',
227
+ required: ['ok', 'schema_version', 'command', 'data', 'next_commands'],
228
+ properties: {
229
+ ok: { const: true },
230
+ schema_version: { const: ISSUE_COMMAND_SCHEMA_VERSION },
231
+ command: { type: 'string' },
232
+ data: {
233
+ type: 'object',
234
+ required: ['epic', 'children', 'rollup', 'count'],
235
+ properties: {
236
+ epic: {
237
+ type: 'object',
238
+ required: ['id', 'title', 'type', 'status'],
239
+ properties: {
240
+ id: { type: 'string' },
241
+ title: { type: 'string' },
242
+ type: { enum: [...ISSUE_TYPES] },
243
+ status: { enum: [...ISSUE_STATUSES] },
244
+ },
245
+ },
246
+ children: {
247
+ type: 'array',
248
+ items: ISSUE_SUMMARY_SCHEMA,
249
+ },
250
+ rollup: {
251
+ type: 'object',
252
+ required: ['total', 'done', 'percentage', 'by_status'],
253
+ properties: {
254
+ total: { type: 'integer', minimum: 0 },
255
+ done: { type: 'integer', minimum: 0 },
256
+ in_progress: { type: 'integer', minimum: 0 },
257
+ open: { type: 'integer', minimum: 0 },
258
+ review: { type: 'integer', minimum: 0 },
259
+ cancelled: { type: 'integer', minimum: 0 },
260
+ backlog: { type: 'integer', minimum: 0 },
261
+ blocked: { type: 'integer', minimum: 0 },
262
+ percentage: { type: 'integer', minimum: 0 },
263
+ by_status: { type: 'object' },
264
+ },
265
+ },
266
+ count: { type: 'integer', minimum: 0 },
267
+ },
268
+ },
269
+ next_commands: NEXT_COMMANDS_SCHEMA,
270
+ },
271
+ },
272
+ // Issue 7dc229d4: the active-lease/claims read. `claims` is an array of live
273
+ // lease rows (state='active' AND not expired at read time). Each row carries the
274
+ // full who/what/where the dashboard live layer needs: actor + session_id +
275
+ // worktree_id + expires_at + issue_id (plus the lease id and claimed_at). The
276
+ // kernel_claims schema has no `agent` column, so none is surfaced. session_id /
277
+ // worktree_id / expires_at are nullable (a claim may carry none / never expire).
278
+ claimsList: {
279
+ type: 'object',
280
+ required: ['ok', 'schema_version', 'command', 'data', 'next_commands'],
281
+ properties: {
282
+ ok: { const: true },
283
+ schema_version: { const: ISSUE_COMMAND_SCHEMA_VERSION },
284
+ command: { type: 'string' },
285
+ data: {
286
+ type: 'object',
287
+ required: ['claims', 'count'],
288
+ properties: {
289
+ claims: {
290
+ type: 'array',
291
+ items: {
292
+ type: 'object',
293
+ required: ['id', 'issue_id', 'actor', 'session_id', 'worktree_id', 'claimed_at', 'expires_at'],
294
+ properties: {
295
+ id: { type: 'string' },
296
+ issue_id: { type: 'string' },
297
+ actor: { type: ['string', 'null'] },
298
+ session_id: { type: ['string', 'null'] },
299
+ worktree_id: { type: ['string', 'null'] },
300
+ claimed_at: { type: ['string', 'null'] },
301
+ expires_at: { type: ['string', 'null'] },
302
+ },
303
+ },
304
+ },
305
+ count: { type: 'integer', minimum: 0 },
306
+ },
307
+ },
308
+ next_commands: NEXT_COMMANDS_SCHEMA,
309
+ },
310
+ },
311
+ mutation: {
312
+ type: 'object',
313
+ required: ['ok', 'schema_version', 'command', 'data', 'next_commands'],
314
+ properties: {
315
+ ok: { const: true },
316
+ schema_version: { const: ISSUE_COMMAND_SCHEMA_VERSION },
317
+ command: { type: 'string' },
318
+ data: {
319
+ type: 'object',
320
+ required: ['id', 'revision'],
321
+ properties: {
322
+ id: { type: 'string' },
323
+ revision: { type: 'integer', minimum: 0 },
324
+ issue: ISSUE_SUMMARY_SCHEMA,
325
+ comment_id: { type: 'string' },
326
+ dependency_id: { type: 'string' },
327
+ claim_id: { type: 'string' },
328
+ // KAP-8: close only — ids that became ready now the issue is done.
329
+ // OPTIONAL (not in `required`) so every other mutation still validates.
330
+ newly_unblocked: { type: 'array', items: { type: 'string' } },
331
+ projection: {
332
+ type: 'object',
333
+ properties: {
334
+ status: { type: 'string' },
335
+ targets: { type: 'array', items: { type: 'string' } },
336
+ },
337
+ },
338
+ },
339
+ },
340
+ next_commands: NEXT_COMMANDS_SCHEMA,
341
+ },
342
+ },
343
+ // Multi-id close (`forge issue close <a> <b> ...`). The kernel close op closes a
344
+ // SINGLE id, so the CLI fans out one mutation per id and aggregates the outcomes
345
+ // into ONE envelope (never a bare array — that broke envelope parity). `ok` is a
346
+ // plain boolean here (true only when EVERY id closed); per-id outcomes live in
347
+ // `data.results`, and `data.closed` lists the ids that reached terminal state.
348
+ // Each result echoes the single-close mutation fields (revision/newly_unblocked)
349
+ // on success or the forge.issue.error.v1 `error` object on failure.
350
+ mutationBatch: {
351
+ type: 'object',
352
+ required: ['ok', 'schema_version', 'command', 'data', 'next_commands'],
353
+ properties: {
354
+ ok: { type: 'boolean' },
355
+ schema_version: { const: ISSUE_COMMAND_SCHEMA_VERSION },
356
+ command: { type: 'string' },
357
+ data: {
358
+ type: 'object',
359
+ required: ['results', 'count', 'closed'],
360
+ properties: {
361
+ results: {
362
+ type: 'array',
363
+ items: {
364
+ type: 'object',
365
+ required: ['id', 'ok'],
366
+ properties: {
367
+ id: { type: 'string' },
368
+ ok: { type: 'boolean' },
369
+ revision: { type: 'integer', minimum: 0 },
370
+ newly_unblocked: { type: 'array', items: { type: 'string' } },
371
+ error: { type: 'object' },
372
+ },
373
+ },
374
+ },
375
+ count: { type: 'integer', minimum: 0 },
376
+ closed: { type: 'array', items: { type: 'string' } },
377
+ },
378
+ },
379
+ next_commands: NEXT_COMMANDS_SCHEMA,
380
+ },
381
+ },
382
+ });
383
+
384
+ const ISSUE_COMMAND_ERROR_SCHEMA = deepFreeze({
385
+ type: 'object',
386
+ required: ['ok', 'schema_version', 'command', 'error', 'next_commands'],
387
+ properties: {
388
+ ok: { const: false },
389
+ schema_version: { const: ISSUE_COMMAND_ERROR_SCHEMA_VERSION },
390
+ command: { type: 'string' },
391
+ error: {
392
+ type: 'object',
393
+ required: ['code', 'message', 'exit_code', 'retryable'],
394
+ properties: {
395
+ code: { type: 'string' },
396
+ message: { type: 'string' },
397
+ exit_code: { type: 'integer' },
398
+ retryable: { type: 'boolean' },
399
+ details: { type: 'object' },
400
+ },
401
+ },
402
+ next_commands: NEXT_COMMANDS_SCHEMA,
403
+ },
404
+ });
405
+
406
+ function command(id, invocation, operation, mode, outputSchema, nextCommands) {
407
+ return {
408
+ id,
409
+ invocation,
410
+ operation,
411
+ mode,
412
+ schemaVersion: ISSUE_COMMAND_SCHEMA_VERSION,
413
+ outputSchema,
414
+ errorShape: ISSUE_COMMAND_ERROR_SCHEMA_VERSION,
415
+ exitCodes: ISSUE_COMMAND_EXIT_CODES,
416
+ nextCommands,
417
+ };
418
+ }
419
+
420
+ const COMMANDS = [
421
+ command('issue.ready', 'forge issue ready --json', 'ready', 'read', ISSUE_COMMAND_RESPONSE_SCHEMAS.issueList, [
422
+ 'forge claim <id>',
423
+ 'forge issue show <id> --json',
424
+ ]),
425
+ command('issue.list', 'forge issue list --json', 'list', 'read', ISSUE_COMMAND_RESPONSE_SCHEMAS.issueList, [
426
+ 'forge issue show <id> --json',
427
+ 'forge issue search <query> --json',
428
+ ]),
429
+ command('issue.show', 'forge issue show <id> --json', 'show', 'read', ISSUE_COMMAND_RESPONSE_SCHEMAS.issue, [
430
+ 'forge claim <id>',
431
+ 'forge issue comment <id> "<note>"',
432
+ ]),
433
+ command('issue.search', 'forge issue search <query> --json', 'search', 'read', ISSUE_COMMAND_RESPONSE_SCHEMAS.issueList, [
434
+ 'forge issue show <id> --json',
435
+ 'forge claim <id>',
436
+ ]),
437
+ command('issue.stats', 'forge issue stats --json', 'stats', 'read', ISSUE_COMMAND_RESPONSE_SCHEMAS.stats, [
438
+ 'forge issue ready --json',
439
+ 'forge issue list --json',
440
+ ]),
441
+ command('issue.blocked', 'forge blocked --json', 'blocked', 'read', ISSUE_COMMAND_RESPONSE_SCHEMAS.issueList, [
442
+ 'forge issue show <id> --json',
443
+ 'forge issue ready --json',
444
+ ]),
445
+ command('issue.stale', 'forge stale --json', 'stale', 'read', ISSUE_COMMAND_RESPONSE_SCHEMAS.staleList, [
446
+ 'forge issue show <id> --json',
447
+ 'forge issue update <id>',
448
+ ]),
449
+ command('issue.orphans', 'forge orphans --json', 'orphans', 'read', ISSUE_COMMAND_RESPONSE_SCHEMAS.issueList, [
450
+ 'forge issue show <id> --json',
451
+ 'forge issue dep add <issue-id> <blocks-issue-id>',
452
+ ]),
453
+ command('issue.lint', 'forge lint --json', 'lint', 'read', ISSUE_COMMAND_RESPONSE_SCHEMAS.issueList, [
454
+ 'forge issue show <id> --json',
455
+ 'forge issue update <id> --acceptance "<criteria>"',
456
+ ]),
457
+ command('issue.children', 'forge issue children <id> --json', 'children', 'read', ISSUE_COMMAND_RESPONSE_SCHEMAS.children, [
458
+ 'forge issue show <id> --json',
459
+ 'forge claim <id>',
460
+ ]),
461
+ command('issue.claims', 'forge claims --json', 'claims', 'read', ISSUE_COMMAND_RESPONSE_SCHEMAS.claimsList, [
462
+ 'forge issue show <id> --json',
463
+ 'forge claim <id>',
464
+ ]),
465
+ command('issue.create', 'forge issue create', 'create', 'mutation', ISSUE_COMMAND_RESPONSE_SCHEMAS.mutation, [
466
+ 'forge issue show <id> --json',
467
+ 'forge claim <id>',
468
+ ]),
469
+ command('issue.update', 'forge issue update', 'update', 'mutation', ISSUE_COMMAND_RESPONSE_SCHEMAS.mutation, [
470
+ 'forge issue show <id> --json',
471
+ ]),
472
+ command('issue.close', 'forge issue close', 'close', 'mutation', ISSUE_COMMAND_RESPONSE_SCHEMAS.mutation, [
473
+ 'forge issue ready --json',
474
+ ]),
475
+ command('issue.comment', 'forge issue comment', 'comment', 'mutation', ISSUE_COMMAND_RESPONSE_SCHEMAS.mutation, [
476
+ 'forge issue show <id> --json',
477
+ ]),
478
+ command('issue.dep.add', 'forge issue dep add', 'dep.add', 'mutation', ISSUE_COMMAND_RESPONSE_SCHEMAS.mutation, [
479
+ 'forge issue show <id> --json',
480
+ 'forge issue ready --json',
481
+ ]),
482
+ command('issue.dep.remove', 'forge issue dep remove', 'dep.remove', 'mutation', ISSUE_COMMAND_RESPONSE_SCHEMAS.mutation, [
483
+ 'forge issue ready --json',
484
+ ]),
485
+ command('claim', 'forge claim <id>', 'claim', 'mutation', ISSUE_COMMAND_RESPONSE_SCHEMAS.mutation, [
486
+ 'forge issue show <id> --json',
487
+ 'forge release <id>',
488
+ ]),
489
+ command('release', 'forge release <id>', 'release', 'mutation', ISSUE_COMMAND_RESPONSE_SCHEMAS.mutation, [
490
+ 'forge issue ready --json',
491
+ ]),
492
+ ];
493
+
494
+ const ISSUE_COMMAND_CONTRACT = deepFreeze({
495
+ version: ISSUE_COMMAND_SCHEMA_VERSION,
496
+ errorSchemaVersion: ISSUE_COMMAND_ERROR_SCHEMA_VERSION,
497
+ commands: COMMANDS,
498
+ exitCodes: ISSUE_COMMAND_EXIT_CODES,
499
+ });
500
+
501
+ const COMMAND_BY_ID = new Map(ISSUE_COMMAND_CONTRACT.commands.map(candidate => [candidate.id, candidate]));
502
+
503
+ function getIssueCommandContract(id) {
504
+ return COMMAND_BY_ID.get(id) || null;
505
+ }
506
+
507
+ // Resolve the catalog next_commands for a command, substituting the concrete issue
508
+ // id into the `<id>` placeholder when the response carries a single id (show and the
509
+ // mutation responses). Multi-issue responses (list/ready/blocked/...) keep the
510
+ // `<id>` template since there is no single id to bind. Unknown commands → [].
511
+ function resolveNextCommands(commandId, data = {}) {
512
+ const contract = COMMAND_BY_ID.get(commandId);
513
+ const templates = contract ? contract.nextCommands : [];
514
+ // Most single-id responses store the id at `data.id`; `issue.children` instead
515
+ // anchors on the epic, so fall back to `data.epic.id` — otherwise its
516
+ // next_commands would emit literal `<id>` placeholders.
517
+ const id = data && typeof data.id === 'string'
518
+ ? data.id
519
+ : (data && data.epic && typeof data.epic.id === 'string' ? data.epic.id : null);
520
+ return id ? templates.map(entry => entry.replace(/<id>/g, id)) : [...templates];
521
+ }
522
+
523
+ function formatIssueCommandError(options = {}) {
524
+ const error = {
525
+ code: options.code || 'FORGE_ISSUE_ERROR',
526
+ message: options.message || 'Forge issue command failed',
527
+ exit_code: Number.isInteger(options.exitCode) ? options.exitCode : ISSUE_COMMAND_EXIT_CODES.internal,
528
+ retryable: Boolean(options.retryable),
529
+ };
530
+
531
+ if (options.details && typeof options.details === 'object') {
532
+ error.details = options.details;
533
+ }
534
+
535
+ return {
536
+ ok: false,
537
+ schema_version: ISSUE_COMMAND_ERROR_SCHEMA_VERSION,
538
+ command: options.command || 'forge issue',
539
+ error,
540
+ next_commands: Array.isArray(options.nextCommands) ? options.nextCommands : [],
541
+ };
542
+ }
543
+
544
+ module.exports = {
545
+ ISSUE_COMMAND_CONTRACT,
546
+ ISSUE_COMMAND_ERROR_SCHEMA,
547
+ ISSUE_COMMAND_ERROR_SCHEMA_VERSION,
548
+ ISSUE_COMMAND_EXIT_CODES,
549
+ ISSUE_COMMAND_RESPONSE_SCHEMAS,
550
+ ISSUE_COMMAND_SCHEMA_VERSION,
551
+ ISSUE_PRIORITIES,
552
+ ISSUE_STATUSES,
553
+ ISSUE_TYPES,
554
+ formatIssueCommandError,
555
+ getIssueCommandContract,
556
+ isValidIssuePriority,
557
+ normalizePriority,
558
+ resolveNextCommands,
559
+ };