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
@@ -7,7 +7,7 @@
7
7
  # cmd_workload — Main entry point for `forge team workload`
8
8
  #
9
9
  # Env overrides (for testing):
10
- # BD_CMD — Path to bd binary
10
+ # FORGE_CMD — Path to forge binary
11
11
  # GH_CMD — Path to gh binary
12
12
  # WORKLOAD_NOW — Override "now" timestamp for testing (ISO 8601)
13
13
  #
@@ -88,70 +88,46 @@ _json_escape() {
88
88
  }
89
89
 
90
90
  # _collect_issues — Gather all open/in_progress issues with details
91
- # Outputs lines: id|title|status|owner|updated|depends_on
91
+ # Outputs tab-delimited (jq @tsv) lines: id<TAB>title<TAB>status<TAB>owner<TAB>updated<TAB>depends_on
92
+ # @tsv escapes any tab/newline/CR inside fields, so user-controlled titles that
93
+ # contain '|', tabs, or newlines never shift the downstream columns.
94
+ #
95
+ # The Kernel list filter does not accept comma-joined statuses, so query each
96
+ # active status separately and concatenate the JSON issue arrays. Every field
97
+ # the workload view needs (status, assignee, updated_at, dependencies) is
98
+ # present in `issue list --json`, so no per-issue lookup is required.
92
99
  _collect_issues() {
93
- local bd_cmd="${BD_CMD:-bd}"
94
- local list_output
95
- local combined_exit=0
96
-
97
- # beads 0.62 rejects comma-separated status filters, so fall back to
98
- # separate queries when the combined form fails.
99
- list_output="$("$bd_cmd" list --status=open,in_progress 2>/dev/null)"
100
- combined_exit=$?
101
- if [[ "$combined_exit" -ne 0 ]]; then
102
- list_output="$(
103
- {
104
- "$bd_cmd" list --status=open 2>/dev/null || true
105
- "$bd_cmd" list --status=in_progress 2>/dev/null || true
106
- } | awk 'NF && !seen[$0]++'
107
- )"
108
- fi
109
-
110
- # Filter empty lines
111
- if [[ -z "$list_output" ]] || [[ -z "$(printf '%s' "$list_output" | tr -d '[:space:]')" ]]; then
112
- return 0
113
- fi
114
-
115
- while IFS= read -r line; do
116
- # Skip empty lines
117
- [[ -z "$line" ]] && continue
118
-
119
- # Extract issue id: first field like "forge-xxx" after optional icon
120
- local issue_id
121
- issue_id="$(echo "$line" | grep -oE 'forge-[a-zA-Z0-9]+(\.[a-zA-Z0-9]+)*' | head -1)"
122
- [[ -z "$issue_id" ]] && continue
123
-
124
- # Get details via bd show
125
- local show_output
126
- show_output="$("$bd_cmd" show "$issue_id" 2>/dev/null)" || continue
127
-
128
- # Parse owner
129
- local owner
130
- owner="$(echo "$show_output" | grep -E '^Owner:' | sed 's/^Owner:[[:space:]]*//')"
131
- [[ -z "$owner" ]] && owner="unassigned"
132
-
133
- # Parse status from the header line [● Px · STATUS]
134
- local status
135
- status="$(echo "$show_output" | head -1 | grep -oE '(IN_PROGRESS|OPEN|BLOCKED|CLOSED)' | head -1)"
136
- [[ -z "$status" ]] && status="OPEN"
137
-
138
- # Parse title — text after "forge-xxx · " on first line
139
- local title
140
- title="$(echo "$show_output" | head -1 | sed -E 's/^[^·]*·[[:space:]]*//' | sed -E 's/[[:space:]]*\[.*//')"
141
-
142
- # Parse updated timestamp
143
- local updated
144
- updated="$(echo "$show_output" | grep -E '^Updated:' | sed 's/^Updated:[[:space:]]*//')"
145
- [[ -z "$updated" ]] && updated=""
146
-
147
- # Parse dependencies (DEPENDS ON section)
148
- local depends_on=""
149
- if echo "$show_output" | grep -q "DEPENDS ON"; then
150
- depends_on="$(echo "$show_output" | grep -E '^\s*→' | sed -E 's/^\s*→\s*//' | sed -E 's/:.*//' | tr '\n' ',' | sed 's/,$//')"
151
- fi
152
-
153
- echo "${issue_id}|${title}|${status}|${owner}|${updated}|${depends_on}"
154
- done <<< "$list_output"
100
+ local forge_cmd="${FORGE_CMD:-forge}"
101
+ local open_json inprog_json issues_json
102
+
103
+ open_json="$("$forge_cmd" issue list --status=open --json 2>/dev/null)" || open_json=""
104
+ inprog_json="$("$forge_cmd" issue list --status=in_progress --json 2>/dev/null)" || inprog_json=""
105
+
106
+ issues_json="$(jq -n \
107
+ --argjson a "${open_json:-null}" \
108
+ --argjson b "${inprog_json:-null}" \
109
+ '((($a.data.issues) // []) + (($b.data.issues) // []))' 2>/dev/null)" || issues_json="[]"
110
+
111
+ # A Kernel issue's `.dependencies` lists the issues it BLOCKS (outgoing), so
112
+ # depends_on (the issues that block THIS one) is a reverse scan: issues within
113
+ # the active set whose `.dependencies` include this issue.
114
+ printf '%s' "$issues_json" | jq -r '
115
+ . as $all
116
+ | $all[]
117
+ | . as $x
118
+ | [ $x.id,
119
+ ($x.title // ""),
120
+ (($x.status // "open") | ascii_upcase),
121
+ ($x.assignee // $x.claimed_by // "unassigned"),
122
+ (($x.updated_at // "") | sub("\\.[0-9]+Z$"; "Z")),
123
+ ( [ $all[]
124
+ | select( (.dependencies // [])
125
+ | map(if type == "object" then (.id // .to // "") else . end)
126
+ | any(. == $x.id) )
127
+ | .id ]
128
+ | join(",") )
129
+ ]
130
+ | @tsv' | tr -d '\r'
155
131
  }
156
132
 
157
133
  # ── Public API ───────────────────────────────────────────────────────────
@@ -213,7 +189,7 @@ cmd_workload() {
213
189
  local work_dir
214
190
  work_dir="$(mktemp -d)"
215
191
 
216
- while IFS='|' read -r issue_id title status owner updated depends_on; do
192
+ while IFS=$'\t' read -r issue_id title status owner updated depends_on; do
217
193
  [[ -z "$issue_id" ]] && continue
218
194
 
219
195
  # Apply developer filter
@@ -7,7 +7,7 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
7
7
  TEST_TMP="$(mktemp -d)"
8
8
  trap 'rm -rf "$TEST_TMP"' EXIT
9
9
 
10
- # Override TEAM_MAP_ROOT so tests don't touch real .beads/
10
+ # Override TEAM_MAP_ROOT so tests don't touch real .forge/
11
11
  export TEAM_MAP_ROOT="$TEST_TMP"
12
12
 
13
13
  # ── Create mock gh ───────────────────────────────────────────────────────
@@ -52,26 +52,32 @@ exit 1
52
52
  MOCK
53
53
  chmod +x "$mock_dir/gh-fail"
54
54
 
55
- # ── Create mock bd ───────────────────────────────────────────────────────
56
- cat > "$mock_dir/bd" << 'MOCK'
55
+ # ── Create mock forge ─────────────────────────────────────────────────────
56
+ # `issue show --json` carries the github_issue:<n> association as a label.
57
+ cat > "$mock_dir/forge" << 'MOCK'
57
58
  #!/usr/bin/env bash
58
- case "$1" in
59
- show)
60
- case "$2" in
61
- forge-assigned) echo "forge-assigned Assigned Issue [github_issue:42]" ;;
62
- forge-unassigned) echo "forge-unassigned Unassigned Issue [github_issue:43]" ;;
63
- forge-mine) echo "forge-mine My Issue [github_issue:44]" ;;
64
- forge-nogithub) echo "forge-nogithub No GitHub Issue" ;;
65
- *) echo "unknown issue" ;;
66
- esac ;;
67
- update) echo "Updated" ;;
68
- comments) echo "Comment added" ;;
59
+ sub="$1 $2"
60
+ id="$3"
61
+ case "$sub" in
62
+ "issue show")
63
+ case "$id" in
64
+ forge-assigned) labels='["github_issue:42"]' ;;
65
+ forge-unassigned) labels='["github_issue:43"]' ;;
66
+ forge-mine) labels='["github_issue:44"]' ;;
67
+ forge-nogithub) labels='[]' ;;
68
+ *) printf 'unexpected issue id: %s\n' "$id" >&2; exit 64 ;;
69
+ esac
70
+ printf '{"data":{"issue":{"id":"%s","labels":%s}}}\n' "$id" "$labels"
71
+ ;;
72
+ "issue claim") printf '{"data":{"id":"%s"}}\n' "$id" ;;
73
+ "issue comment") printf '{"data":{"id":"%s"}}\n' "$id" ;;
74
+ *) printf 'unexpected forge command: %s\n' "$*" >&2; exit 64 ;;
69
75
  esac
70
76
  MOCK
71
- chmod +x "$mock_dir/bd"
77
+ chmod +x "$mock_dir/forge"
72
78
 
73
79
  export GH_CMD="$mock_dir/gh"
74
- export BD_CMD="$mock_dir/bd"
80
+ export FORGE_CMD="$mock_dir/forge"
75
81
 
76
82
  # Source the library under test
77
83
  source "$SCRIPT_DIR/lib/claim.sh"
@@ -109,7 +115,7 @@ assert_exit() {
109
115
  # ── Test 1: Pre-claim on unassigned issue → returns 0 ───────────────────
110
116
  echo "── Test 1: Pre-claim on unassigned issue ──"
111
117
  unset _GITHUB_USER_CACHE
112
- mkdir -p "$TEST_TMP/.beads"
118
+ mkdir -p "$TEST_TMP/.forge"
113
119
  rc=0
114
120
  pre_claim_check "forge-unassigned" 2>/dev/null || rc=$?
115
121
  assert_exit "unassigned issue returns 0" 0 "$rc"
@@ -136,7 +142,7 @@ assert_exit "assigned to self returns 0" 0 "$rc"
136
142
  echo ""
137
143
  echo "── Test 4: --force overrides pre-claim check ──"
138
144
  unset _GITHUB_USER_CACHE
139
- mkdir -p "$TEST_TMP/.beads"
145
+ mkdir -p "$TEST_TMP/.forge"
140
146
  rc=0
141
147
  output="$(forge_team_claim "forge-assigned" "--force" 2>&1)" || rc=$?
142
148
  assert_exit "force claim succeeds" 0 "$rc"
@@ -146,7 +152,7 @@ assert_contains "confirmation output" "claimed" "$output"
146
152
  echo ""
147
153
  echo "── Test 5: Claim with lock succeeds ──"
148
154
  unset _GITHUB_USER_CACHE
149
- mkdir -p "$TEST_TMP/.beads"
155
+ mkdir -p "$TEST_TMP/.forge"
150
156
  # Use the unassigned issue so pre-claim passes
151
157
  rc=0
152
158
  output="$(forge_team_claim "forge-unassigned" 2>&1)" || rc=$?
@@ -7,53 +7,38 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
7
7
  TEST_TMP="$(mktemp -d)"
8
8
  trap 'rm -rf "$TEST_TMP"' EXIT
9
9
 
10
- # ── Create mock bd ───────────────────────────────────────────────────────
10
+ # ── Create mock forge ─────────────────────────────────────────────────────
11
+ # Emits Kernel-shaped JSON ({"data":{"issues":[...]}}) for `issue list`.
11
12
  mock_dir="$(mktemp -d)"
12
13
 
13
- cat > "$mock_dir/bd" << 'MOCK'
14
+ cat > "$mock_dir/forge" << 'MOCK'
14
15
  #!/usr/bin/env bash
15
- case "$1" in
16
- list)
17
- if echo "$*" | grep -q -- "--status=open,in_progress"; then
18
- if [[ -n "${BD_MOCK_EMPTY:-}" ]]; then
19
- # No output for empty test
20
- :
21
- elif [[ -n "${BD_MOCK_SINGLE:-}" ]]; then
22
- echo "forge-aaa · Feature A"
23
- else
24
- echo " forge-aaa · Feature A"
25
- echo "○ forge-bbb · Feature B"
26
- echo "◐ forge-ccc · Feature C"
27
- fi
28
- fi
29
- ;;
30
- show)
31
- case "$2" in
32
- forge-aaa)
33
- echo "◐ forge-aaa · Feature A [● P2 · IN_PROGRESS]"
34
- echo "Owner: devone"
35
- echo "Updated: 2026-03-27T10:00:00Z"
36
- ;;
37
- forge-bbb)
38
- echo "○ forge-bbb · Feature B [● P2 · OPEN]"
39
- echo "Owner: devtwo"
40
- echo "Updated: 2026-03-24T10:00:00Z"
41
- ;;
42
- forge-ccc)
43
- echo "◐ forge-ccc · Feature C [● P1 · IN_PROGRESS]"
44
- echo "Owner: devone"
45
- echo "Updated: 2026-03-27T09:00:00Z"
46
- echo ""
47
- echo "DEPENDS ON"
48
- echo " → ◐ forge-aaa: Feature A"
49
- ;;
50
- esac
51
- ;;
52
- esac
16
+ args="$*"
17
+ emit() { printf '{"data":{"issues":%s}}\n' "$1"; }
18
+
19
+ # forge-aaa BLOCKS forge-ccc (kernel: blocker carries the dependency edge), so
20
+ # forge-ccc is the blocked one — its blocked_by resolves to forge-aaa via reverse scan.
21
+ aaa='{"id":"forge-aaa","title":"Feature A","status":"in_progress","assignee":"devone","updated_at":"2026-03-27T10:00:00Z","dependencies":["forge-ccc"]}'
22
+ bbb='{"id":"forge-bbb","title":"Feature B","status":"open","assignee":"devtwo","updated_at":"2026-03-24T10:00:00Z","dependencies":[]}'
23
+ ccc='{"id":"forge-ccc","title":"Feature C","status":"in_progress","assignee":"devone","updated_at":"2026-03-27T09:00:00Z","dependencies":[]}'
24
+
25
+ if [[ "$args" == *"issue list"* ]]; then
26
+ if [[ -n "${FORGE_MOCK_EMPTY:-}" ]]; then
27
+ emit "[]"
28
+ elif [[ -n "${FORGE_MOCK_SINGLE:-}" ]]; then
29
+ if [[ "$args" == *"--status=in_progress"* ]]; then emit "[$aaa]"; else emit "[]"; fi
30
+ else
31
+ if [[ "$args" == *"--status=open"* ]]; then emit "[$bbb]"
32
+ elif [[ "$args" == *"--status=in_progress"* ]]; then emit "[$aaa,$ccc]"
33
+ else emit "[]"; fi
34
+ fi
35
+ exit 0
36
+ fi
37
+ exit 0
53
38
  MOCK
54
- chmod +x "$mock_dir/bd"
39
+ chmod +x "$mock_dir/forge"
55
40
 
56
- export BD_CMD="$mock_dir/bd"
41
+ export FORGE_CMD="$mock_dir/forge"
57
42
 
58
43
  # Source the library under test
59
44
  source "$SCRIPT_DIR/lib/dashboard.sh"
@@ -132,24 +117,24 @@ assert_contains "blocked shows dependency" "forge-aaa" "$output"
132
117
  echo ""
133
118
  echo "── Test 4: No issues → clear message ──"
134
119
 
135
- export BD_MOCK_EMPTY=1
120
+ export FORGE_MOCK_EMPTY=1
136
121
  rc=0
137
122
  output_empty="$(cmd_dashboard 2>&1)" || rc=$?
138
123
  assert_exit "empty dashboard exits 0" 0 "$rc"
139
124
  assert_contains "shows no active issues" "No active issues" "$output_empty"
140
- unset BD_MOCK_EMPTY
125
+ unset FORGE_MOCK_EMPTY
141
126
 
142
127
  # ── Test 5: Single developer → works correctly ──────────────────────────
143
128
  echo ""
144
129
  echo "── Test 5: Single developer ──"
145
130
 
146
- export BD_MOCK_SINGLE=1
131
+ export FORGE_MOCK_SINGLE=1
147
132
  rc=0
148
133
  output_single="$(cmd_dashboard 2>&1)" || rc=$?
149
134
  assert_exit "single dev dashboard exits 0" 0 "$rc"
150
135
  assert_contains "shows devone" "devone" "$output_single"
151
136
  assert_not_contains "no devtwo in single mode" "devtwo" "$output_single"
152
- unset BD_MOCK_SINGLE
137
+ unset FORGE_MOCK_SINGLE
153
138
 
154
139
  # ── Test 6: --format=json → valid JSON ──────────────────────────────────
155
140
  echo ""
@@ -7,74 +7,45 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
7
7
  TEST_TMP="$(mktemp -d)"
8
8
  trap 'rm -rf "$TEST_TMP"' EXIT
9
9
 
10
- # ── Create mock bd ───────────────────────────────────────────────────────
10
+ # ── Create mock forge ────────────────────────────────────────────────────
11
+ # Only handles `forge issue children <id> --json`, emitting the kernel
12
+ # issue-command-contract envelope ({schema_version,command,data:{epic,children,
13
+ # rollup,count},next_commands}). An unknown id mirrors the kernel not-found path:
14
+ # error on stderr, empty stdout, non-zero exit.
11
15
  mock_dir="$(mktemp -d)"
12
16
 
13
- cat > "$mock_dir/bd" << 'MOCK'
17
+ cat > "$mock_dir/forge" << 'MOCK'
14
18
  #!/usr/bin/env bash
15
- case "$1 $2" in
16
- "show forge-epic1")
17
- cat << 'SHOW'
18
- forge-epic1 · Test Epic [● P2 · IN_PROGRESS]
19
- Owner: devone
20
-
21
- BLOCKS
22
- ← ✓ forge-child1: Child 1 (closed)
23
- ← ◐ forge-child2: Child 2 (in_progress)
24
- forge-child3: Child 3 (open)
25
- SHOW
26
- ;;
27
- "show forge-child1")
28
- echo "✓ forge-child1 · Child 1 [● P2 · CLOSED]"
29
- echo "Owner: devone"
30
- ;;
31
- "show forge-child2")
32
- echo "◐ forge-child2 · Child 2 [● P2 · IN_PROGRESS]"
33
- echo "Owner: devtwo"
34
- ;;
35
- "show forge-child3")
36
- echo "○ forge-child3 · Child 3 [● P3 · OPEN]"
37
- echo "Owner: devone"
38
- ;;
39
- "show forge-empty")
40
- cat << 'SHOW'
41
- ○ forge-empty · Empty Epic [● P2 · OPEN]
42
- Owner: devone
43
- SHOW
44
- ;;
45
- "show forge-blocked")
46
- cat << 'SHOW'
47
- ◐ forge-blocked · Blocked Epic [● P2 · IN_PROGRESS]
48
- Owner: devone
49
-
50
- BLOCKS
51
- ← ✓ forge-bchild1: Bchild 1 (closed)
52
- ← ◐ forge-bchild2: Bchild 2 (in_progress)
53
- ← ○ forge-bchild3: Bchild 3 (open)
54
- SHOW
55
- ;;
56
- "show forge-bchild1")
57
- echo "✓ forge-bchild1 · Bchild 1 [● P2 · CLOSED]"
58
- echo "Owner: devone"
59
- ;;
60
- "show forge-bchild2")
61
- cat << 'SHOW'
62
- ◐ forge-bchild2 · Bchild 2 [● P2 · IN_PROGRESS]
63
- Owner: devtwo
64
-
65
- BLOCKED_BY
66
- → forge-bchild1: Bchild 1
67
- SHOW
68
- ;;
69
- "show forge-bchild3")
70
- echo "○ forge-bchild3 · Bchild 3 [● P3 · OPEN]"
71
- echo "Owner: devone"
72
- ;;
73
- esac
19
+ if [[ "$1" == "issue" && "$2" == "children" ]]; then
20
+ id="$3"
21
+ case "$id" in
22
+ forge-epic1)
23
+ cat << 'JSON'
24
+ {"schema_version":"forge.issue.v1","command":"issue.children","data":{"epic":{"id":"forge-epic1","title":"Test Epic","type":"epic","status":"in_progress"},"children":[{"id":"forge-child1","title":"Child 1","status":"done","assignee":"devone","blocked":false,"blocked_by":[],"dependencies":[],"dependents":[]},{"id":"forge-child2","title":"Child 2","status":"in_progress","assignee":"devtwo","blocked":false,"blocked_by":[],"dependencies":[],"dependents":[]},{"id":"forge-child3","title":"Child 3","status":"open","assignee":"devone","blocked":false,"blocked_by":[],"dependencies":[],"dependents":[]}],"rollup":{"total":3,"done":1,"in_progress":1,"open":1,"review":0,"cancelled":0,"blocked":0,"percentage":33,"by_status":{"open":1,"in_progress":1,"review":0,"done":1,"cancelled":0}},"count":3},"next_commands":[]}
25
+ JSON
26
+ ;;
27
+ forge-empty)
28
+ cat << 'JSON'
29
+ {"schema_version":"forge.issue.v1","command":"issue.children","data":{"epic":{"id":"forge-empty","title":"Empty Epic","type":"epic","status":"open"},"children":[],"rollup":{"total":0,"done":0,"in_progress":0,"open":0,"review":0,"cancelled":0,"blocked":0,"percentage":0,"by_status":{"open":0,"in_progress":0,"review":0,"done":0,"cancelled":0}},"count":0},"next_commands":[]}
30
+ JSON
31
+ ;;
32
+ forge-blocked)
33
+ cat << 'JSON'
34
+ {"schema_version":"forge.issue.v1","command":"issue.children","data":{"epic":{"id":"forge-blocked","title":"Blocked Epic","type":"epic","status":"in_progress"},"children":[{"id":"forge-bchild1","title":"Bchild 1","status":"done","assignee":"devone","blocked":false,"blocked_by":[],"dependencies":[],"dependents":["forge-bchild2"]},{"id":"forge-bchild2","title":"Bchild 2","status":"in_progress","assignee":"devtwo","blocked":true,"blocked_by":["forge-bchild1"],"dependencies":["forge-bchild1"],"dependents":[]},{"id":"forge-bchild3","title":"Bchild 3","status":"open","assignee":"devone","blocked":false,"blocked_by":[],"dependencies":[],"dependents":[]}],"rollup":{"total":3,"done":1,"in_progress":1,"open":1,"review":0,"cancelled":0,"blocked":1,"percentage":33,"by_status":{"open":1,"in_progress":1,"review":0,"done":1,"cancelled":0}},"count":3},"next_commands":[]}
35
+ JSON
36
+ ;;
37
+ *)
38
+ echo "Issue $id not found" >&2
39
+ exit 1
40
+ ;;
41
+ esac
42
+ exit 0
43
+ fi
44
+ exit 1
74
45
  MOCK
75
- chmod +x "$mock_dir/bd"
46
+ chmod +x "$mock_dir/forge"
76
47
 
77
- export BD_CMD="$mock_dir/bd"
48
+ export FORGE_CMD="$mock_dir/forge"
78
49
 
79
50
  # Source the library under test
80
51
  source "$SCRIPT_DIR/lib/epic.sh"
@@ -116,7 +87,7 @@ output="$(cmd_epic "forge-epic1" 2>&1)" || rc=$?
116
87
  assert_exit "exits 0" 0 "$rc"
117
88
  assert_contains "shows epic id" "forge-epic1" "$output"
118
89
  assert_contains "progress shows 1/3" "1/3" "$output"
119
- assert_contains "shows closed child marker" "forge-child1" "$output"
90
+ assert_contains "shows done child marker" "forge-child1" "$output"
120
91
  assert_contains "shows in_progress child" "forge-child2" "$output"
121
92
  assert_contains "shows open child" "forge-child3" "$output"
122
93
 
@@ -145,13 +116,14 @@ echo "── Test 5: --format=json ──"
145
116
  rc=0
146
117
  output_json="$(cmd_epic "forge-epic1" "--format=json" 2>&1)" || rc=$?
147
118
  assert_exit "json exits 0" 0 "$rc"
148
- # Validate it's actual JSON (check for opening brace and key fields)
149
- assert_contains "json has epic_id" "epic_id" "$output_json"
150
- assert_contains "json has total" "total" "$output_json"
151
- assert_contains "json has done" "done" "$output_json"
152
- assert_contains "json has percentage" "percentage" "$output_json"
153
- assert_contains "json has children" "children" "$output_json"
154
- assert_contains "json has by_developer" "by_developer" "$output_json"
119
+ # Validate it parses as JSON and carries the expected fields/values.
120
+ assert_eq "json total is 3" "3" "$(printf '%s' "$output_json" | jq -r '.total')"
121
+ assert_eq "json done is 1" "1" "$(printf '%s' "$output_json" | jq -r '.done')"
122
+ assert_eq "json percentage is 33" "33" "$(printf '%s' "$output_json" | jq -r '.percentage')"
123
+ assert_eq "json has 3 children" "3" "$(printf '%s' "$output_json" | jq -r '.children | length')"
124
+ assert_eq "json by_developer devone total 2" "2" "$(printf '%s' "$output_json" | jq -r '.by_developer.devone.total')"
125
+ assert_eq "json by_developer devone done 1" "1" "$(printf '%s' "$output_json" | jq -r '.by_developer.devone.done')"
126
+ assert_eq "json epic_id" "forge-epic1" "$(printf '%s' "$output_json" | jq -r '.epic_id')"
155
127
 
156
128
  # ── Test 6: Missing issue-id → error ────────────────────────────────────
157
129
  echo ""
@@ -169,6 +141,15 @@ output_blocked="$(cmd_epic "forge-blocked" 2>&1)" || rc=$?
169
141
  assert_exit "blocked epic exits 0" 0 "$rc"
170
142
  assert_contains "blocked section present" "Blocked" "$output_blocked"
171
143
  assert_contains "blocked child mentioned" "forge-bchild2" "$output_blocked"
144
+ assert_contains "blocked-by id mentioned" "forge-bchild1" "$output_blocked"
145
+
146
+ # ── Test 8: Unknown epic id → not-found error ────────────────────────────
147
+ echo ""
148
+ echo "── Test 8: Unknown epic id ──"
149
+ rc=0
150
+ output_unknown="$(cmd_epic "forge-nope" 2>&1)" || rc=$?
151
+ assert_exit "unknown id returns 1" 1 "$rc"
152
+ assert_contains "error about fetch" "Could not fetch" "$output_unknown"
172
153
 
173
154
  # ── Results ──────────────────────────────────────────────────────────────
174
155
  echo ""