forge-workflow 0.0.10 → 0.1.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (454) hide show
  1. package/.claude/rules/{greptile-review-process.md → review-process.md} +56 -41
  2. package/.claude/scripts/{greptile-resolve.sh → review-resolve.sh} +13 -3
  3. package/.cursor/rules/permissions-guidance.mdc +2 -2
  4. package/.forge/hooks/check-tdd.js +3 -0
  5. package/.forge/hooks/forge-native-hook.js +245 -0
  6. package/.forge/protected-paths.yaml +157 -0
  7. package/AGENTS.md +150 -61
  8. package/CHANGELOG.md +681 -0
  9. package/CLAUDE.md +9 -118
  10. package/QUICKSTART.md +171 -0
  11. package/README.md +271 -363
  12. package/bin/forge-cmd.js +120 -9
  13. package/bin/forge-preflight.js +26 -5
  14. package/bin/forge.js +461 -489
  15. package/docs/INDEX.md +93 -0
  16. package/docs/PROJECT_DESIGN.md +685 -0
  17. package/docs/architecture/index.md +66 -0
  18. package/docs/architecture/notes/README.md +35 -0
  19. package/docs/architecture/subsystems/README.md +46 -0
  20. package/docs/forge/TOOLCHAIN.md +670 -0
  21. package/docs/forge/VALIDATION.md +82 -0
  22. package/docs/{AGENT_INSTALL_PROMPT.md → guides/AGENT_INSTALL_PROMPT.md} +3 -3
  23. package/docs/guides/BEADS_GITHUB_SYNC.md +32 -0
  24. package/docs/{ENHANCED_ONBOARDING.md → guides/ENHANCED_ONBOARDING.md} +16 -12
  25. package/docs/guides/GREPTILE_SETUP.md +46 -0
  26. package/docs/guides/MANUAL_REVIEW_GUIDE.md +58 -0
  27. package/docs/guides/MIGRATION.md +56 -0
  28. package/docs/guides/SETUP.md +118 -0
  29. package/docs/guides/SUPPORT.md +185 -0
  30. package/docs/guides/WORKFLOW_TEMPLATES.md +74 -0
  31. package/docs/guides/memory-backends.md +183 -0
  32. package/docs/reference/ADAPTERS.md +128 -0
  33. package/docs/reference/AGENT_SKILL_PARITY.md +175 -0
  34. package/docs/reference/COMMANDS.md +205 -0
  35. package/docs/reference/DECISION_DRIFT_GUARDS.md +97 -0
  36. package/docs/{EXAMPLES.md → reference/EXAMPLES.md} +7 -5
  37. package/docs/reference/FORGE_KERNEL_STORAGE_MODEL.md +135 -0
  38. package/docs/reference/HERMES_INTEGRATION.md +118 -0
  39. package/docs/reference/INSIGHTS_RECAP.md +63 -0
  40. package/docs/reference/INSTALL.md +164 -0
  41. package/docs/reference/KERNEL_TAXONOMY_VALIDATION.md +161 -0
  42. package/docs/reference/PROTECTED_PATH_MANIFEST.md +25 -0
  43. package/docs/reference/RELEASE.md +68 -0
  44. package/docs/reference/RESEARCH_TEMPLATE.md +292 -0
  45. package/docs/{ROADMAP.md → reference/ROADMAP.md} +12 -9
  46. package/docs/reference/SKILLS.md +35 -0
  47. package/docs/reference/STATUS_BOARD.md +80 -0
  48. package/docs/reference/TEMPLATES.md +106 -0
  49. package/docs/{TOOLCHAIN.md → reference/TOOLCHAIN.md} +62 -47
  50. package/docs/reference/VALIDATION.md +82 -0
  51. package/docs/reference/agent-permissions.md +169 -0
  52. package/docs/reference/beads-to-kernel-migration-ux.md +61 -0
  53. package/docs/reference/control-plane-guarantees.md +125 -0
  54. package/docs/reference/dependency-chain.md +331 -0
  55. package/docs/reference/forge-kernel-issue-command-contract.md +161 -0
  56. package/docs/reference/forge-kernel-schema.md +72 -0
  57. package/docs/reference/kernel-conflict-evaluators.md +27 -0
  58. package/docs/reference/patch-md-format.md +77 -0
  59. package/docs/reference/protected-state-surfaces.md +59 -0
  60. package/docs/reference/shepherd.md +115 -0
  61. package/docs/reference/superpowers-analysis.md +320 -0
  62. package/docs/reference/superpowers-integration-options.md +404 -0
  63. package/docs/reference/test-environment.md +519 -0
  64. package/docs/reference/upgrade-safety.md +59 -0
  65. package/lefthook.yml +18 -0
  66. package/lib/adapter-cli.js +307 -0
  67. package/lib/adapters/beads-issue-adapter.js +127 -0
  68. package/lib/adapters/beads-kernel-compat.js +1042 -0
  69. package/lib/adapters/greptile-review-adapter.js +141 -0
  70. package/lib/adapters/kernel-issue-adapter.js +101 -0
  71. package/lib/adapters/pr-state-adapter.js +484 -0
  72. package/lib/adoption-profiles.js +126 -0
  73. package/lib/agents/README.md +2 -6
  74. package/lib/agents/claude.plugin.json +3 -8
  75. package/lib/agents/codex.plugin.json +9 -1
  76. package/lib/agents/cursor.plugin.json +2 -6
  77. package/lib/agents/hermes.plugin.json +22 -0
  78. package/lib/agents-config.js +39 -1236
  79. package/lib/audit-evidence.js +282 -0
  80. package/lib/beads-setup.js +121 -0
  81. package/lib/beads-sync-scaffold.js +25 -101
  82. package/lib/codex-skills.js +51 -1
  83. package/lib/commands/_issue.js +741 -77
  84. package/lib/commands/_manifest.js +91 -0
  85. package/lib/commands/_registry.js +85 -34
  86. package/lib/commands/_resolve-command-opts.js +261 -0
  87. package/lib/commands/_serve-security.js +270 -0
  88. package/lib/commands/adapter.js +12 -0
  89. package/lib/commands/add.js +118 -0
  90. package/lib/commands/audit.js +70 -0
  91. package/lib/commands/blocked.js +5 -0
  92. package/lib/commands/board.js +64 -0
  93. package/lib/commands/claim.js +21 -2
  94. package/lib/commands/claims.js +7 -0
  95. package/lib/commands/clean.js +485 -75
  96. package/lib/commands/close.js +2 -2
  97. package/lib/commands/comment.js +5 -0
  98. package/lib/commands/control.js +148 -0
  99. package/lib/commands/create.js +2 -2
  100. package/lib/commands/dev.js +185 -7
  101. package/lib/commands/doc-gate.js +336 -0
  102. package/lib/commands/doctor.js +156 -0
  103. package/lib/commands/explain.js +15 -0
  104. package/lib/commands/export.js +237 -0
  105. package/lib/commands/gate.js +192 -0
  106. package/lib/commands/hooks.js +242 -0
  107. package/lib/commands/inbox.js +118 -0
  108. package/lib/commands/init.js +598 -0
  109. package/lib/commands/insights.js +79 -0
  110. package/lib/commands/issue.js +12 -1
  111. package/lib/commands/issues.js +17 -0
  112. package/lib/commands/lint.js +5 -0
  113. package/lib/commands/list.js +2 -2
  114. package/lib/commands/merge.js +312 -0
  115. package/lib/commands/migrate.js +523 -0
  116. package/lib/commands/new.js +12 -0
  117. package/lib/commands/options.js +241 -0
  118. package/lib/commands/orient.js +13 -0
  119. package/lib/commands/orphans.js +5 -0
  120. package/lib/commands/patch.js +67 -0
  121. package/lib/commands/plan.js +436 -24
  122. package/lib/commands/preflight.js +211 -0
  123. package/lib/commands/prime.js +13 -0
  124. package/lib/commands/push.js +69 -2
  125. package/lib/commands/ready.js +2 -2
  126. package/lib/commands/recall.js +116 -0
  127. package/lib/commands/recap.js +61 -0
  128. package/lib/commands/recommend.js +0 -1
  129. package/lib/commands/release.js +91 -0
  130. package/lib/commands/remember.js +74 -0
  131. package/lib/commands/role.js +99 -0
  132. package/lib/commands/serve.js +581 -0
  133. package/lib/commands/setup.js +838 -972
  134. package/lib/commands/shepherd.js +436 -0
  135. package/lib/commands/ship.js +23 -1
  136. package/lib/commands/show.js +2 -2
  137. package/lib/commands/stage.js +192 -0
  138. package/lib/commands/stale.js +5 -0
  139. package/lib/commands/status.js +158 -21
  140. package/lib/commands/sync.js +34 -46
  141. package/lib/commands/team.js +4 -1
  142. package/lib/commands/test.js +43 -27
  143. package/lib/commands/update.js +2 -2
  144. package/lib/commands/upgrade.js +47 -0
  145. package/lib/commands/validate.js +43 -18
  146. package/lib/commands/worktree.js +307 -100
  147. package/lib/config-writer.js +202 -0
  148. package/lib/control-plane.js +236 -0
  149. package/lib/core/runtime-graph.js +946 -0
  150. package/lib/dep-guard/keyword-ripple.js +2 -2
  151. package/lib/deprecated-sync-cleanup.js +362 -0
  152. package/lib/detect-agent.js +2 -28
  153. package/lib/detect-worktree.js +35 -9
  154. package/lib/doc-gate/declaration.js +177 -0
  155. package/lib/doc-gate/detect.js +289 -0
  156. package/lib/doc-gate/gate.js +375 -0
  157. package/lib/doc-gate/okf-config.js +128 -0
  158. package/lib/doc-gate/okf.js +429 -0
  159. package/lib/docs-command.js +1161 -6
  160. package/lib/forge-issues.js +382 -11
  161. package/lib/forge-lock.js +262 -0
  162. package/lib/gate-events.js +193 -0
  163. package/lib/global-flags.js +74 -0
  164. package/lib/greptile-match.js +7 -63
  165. package/lib/harness-capability-matrix.js +380 -0
  166. package/lib/hook-global-installer.js +347 -0
  167. package/lib/hook-renderer.js +451 -0
  168. package/lib/inbox.js +391 -0
  169. package/lib/insights.js +397 -0
  170. package/lib/issue-adapter.js +156 -0
  171. package/lib/issue-backend.js +145 -0
  172. package/lib/issue-render.js +220 -0
  173. package/lib/kernel/backing-issue.js +305 -0
  174. package/lib/kernel/broker.js +1218 -0
  175. package/lib/kernel/cli-broker-factory.js +130 -0
  176. package/lib/kernel/conflict-signal.js +82 -0
  177. package/lib/kernel/evaluators.js +195 -0
  178. package/lib/kernel/fs-class.js +495 -0
  179. package/lib/kernel/issue-command-contract.js +559 -0
  180. package/lib/kernel/issue-id-resolver.js +186 -0
  181. package/lib/kernel/lease-enforcer.js +158 -0
  182. package/lib/kernel/migrations.js +333 -0
  183. package/lib/kernel/planning-buckets-schema.js +109 -0
  184. package/lib/kernel/projection-jsonl-writer.js +450 -0
  185. package/lib/kernel/readiness-model.js +329 -0
  186. package/lib/kernel/schema.js +356 -0
  187. package/lib/kernel/sqlite-driver.js +2504 -0
  188. package/lib/kernel/taxonomy-validator.js +394 -0
  189. package/lib/lefthook-check.js +3 -2
  190. package/lib/lefthook-wiring.js +413 -0
  191. package/lib/mcp-config-renderer.js +288 -0
  192. package/lib/memory/graphiti-mcp.js +106 -0
  193. package/lib/memory/router.js +387 -0
  194. package/lib/memory/typed-api.js +102 -0
  195. package/lib/memory-digest.js +195 -0
  196. package/lib/merge-rules.js +395 -0
  197. package/lib/migrate-dry-run.js +466 -0
  198. package/lib/orientation.js +863 -0
  199. package/lib/package-manager-remediation.js +103 -0
  200. package/lib/package-root.js +381 -0
  201. package/lib/patch-intent.js +890 -0
  202. package/lib/plugin-catalog.js +3 -4
  203. package/lib/plugin-manager.js +0 -5
  204. package/lib/pr-bundle.js +186 -0
  205. package/lib/pr-monitor/differ.js +195 -0
  206. package/lib/pr-monitor/events.js +0 -0
  207. package/lib/pr-monitor/gather.js +124 -0
  208. package/lib/pr-monitor/journal.js +299 -0
  209. package/lib/pr-monitor/monitor.js +146 -0
  210. package/lib/pr-monitor/render-sticky.js +157 -0
  211. package/lib/pr-monitor/watch-lifecycle.js +95 -0
  212. package/lib/pr-monitor/watch.js +247 -0
  213. package/lib/pr-pull.js +1273 -0
  214. package/lib/pr-shepherd.js +494 -0
  215. package/lib/pr-state-validator.js +59 -0
  216. package/lib/preflight/gates.js +237 -0
  217. package/lib/preflight/runner.js +116 -0
  218. package/lib/project-discovery.js +0 -53
  219. package/lib/project-memory.js +99 -497
  220. package/lib/protected-path-manifest.js +281 -0
  221. package/lib/protected-state-surfaces.js +387 -0
  222. package/lib/release-readiness.js +2089 -0
  223. package/lib/reset.js +59 -45
  224. package/lib/review-adapter.js +68 -0
  225. package/lib/rules-sync.js +260 -0
  226. package/lib/runtime-health.js +241 -20
  227. package/lib/safety-config-renderer.js +268 -0
  228. package/lib/setup-action-log.js +1 -7
  229. package/lib/setup.js +27 -65
  230. package/lib/shell-utils.js +76 -6
  231. package/lib/skills-sync.js +330 -0
  232. package/lib/smart-status/scoring.js +17 -3
  233. package/lib/status/beads-snapshot.js +45 -2
  234. package/lib/status/presenter.js +169 -18
  235. package/lib/status/snapshot.js +186 -0
  236. package/lib/sync-backend.js +202 -0
  237. package/lib/untrusted-content.js +52 -0
  238. package/lib/upgrade-safety.js +199 -0
  239. package/lib/workflow/enforce-stage.js +296 -47
  240. package/lib/workflow/stage-transition.js +115 -0
  241. package/lib/workflow/stages.js +30 -6
  242. package/lib/workflow/state-manager.js +11 -22
  243. package/lib/workflow/state.js +23 -1
  244. package/lib/workflow-profiles.js +17 -5
  245. package/package.json +37 -35
  246. package/rules/documentation.md +19 -0
  247. package/rules/kernel-tracking.md +26 -0
  248. package/rules/security.md +22 -0
  249. package/rules/tdd.md +20 -0
  250. package/rules/workflow.md +27 -0
  251. package/scripts/auto-backing-issue.js +47 -0
  252. package/scripts/beads-context.sh +81 -57
  253. package/scripts/beads-upgrade-smoke.sh +24 -3
  254. package/scripts/bootstrap-windows-tools.sh +78 -0
  255. package/scripts/branch-protection.js +2 -3
  256. package/scripts/check-agents.js +34 -137
  257. package/scripts/commitlint.js +3 -1
  258. package/scripts/conflict-detect.sh +3 -0
  259. package/scripts/dep-guard.sh +22 -3
  260. package/scripts/file-index.sh +3 -0
  261. package/scripts/forge-team/lib/claim.sh +34 -18
  262. package/scripts/forge-team/lib/dashboard.sh +61 -86
  263. package/scripts/forge-team/lib/epic.sh +99 -263
  264. package/scripts/forge-team/lib/hooks.sh +26 -28
  265. package/scripts/forge-team/lib/identity.sh +4 -4
  266. package/scripts/forge-team/lib/sync-github.sh +49 -84
  267. package/scripts/forge-team/lib/verify.sh +93 -83
  268. package/scripts/forge-team/lib/workload.sh +41 -65
  269. package/scripts/forge-team/tests/claim.test.sh +25 -19
  270. package/scripts/forge-team/tests/dashboard.test.sh +31 -46
  271. package/scripts/forge-team/tests/epic.test.sh +52 -71
  272. package/scripts/forge-team/tests/hooks.test.sh +38 -50
  273. package/scripts/forge-team/tests/identity.test.sh +3 -3
  274. package/scripts/forge-team/tests/integration.test.sh +44 -66
  275. package/scripts/forge-team/tests/sync-github.test.sh +50 -83
  276. package/scripts/forge-team/tests/verify.test.sh +37 -46
  277. package/scripts/forge-team/tests/workflow-integration.test.sh +4 -4
  278. package/scripts/forge-team/tests/workload.test.sh +32 -66
  279. package/scripts/gen-command-manifest.js +153 -0
  280. package/scripts/gen-embedded-assets.mjs +129 -0
  281. package/scripts/install.ps1 +139 -0
  282. package/scripts/install.sh +268 -0
  283. package/scripts/lib/release-asset.mjs +84 -0
  284. package/scripts/parity-check.mjs +145 -0
  285. package/scripts/parity-check.test.mjs +58 -0
  286. package/scripts/pin-agentic-workflow-images.js +112 -0
  287. package/scripts/pr-coordinator.sh +3 -0
  288. package/scripts/preflight-sonar.eslint.config.mjs +44 -0
  289. package/scripts/preflight.sh +21 -94
  290. package/scripts/protected-state-check.js +104 -0
  291. package/scripts/smart-status.sh +60 -57
  292. package/scripts/spikes/config-race-bench.js +111 -0
  293. package/scripts/spikes/harness-capability-matrix.js +13 -0
  294. package/scripts/spikes/patch-anchor-stability-bench.js +125 -0
  295. package/scripts/spikes/protected-path-manifest.js +20 -0
  296. package/scripts/spikes/skill-auto-invoke-parity.js +292 -0
  297. package/scripts/sync-agent-skills.js +62 -0
  298. package/scripts/sync-utils.sh +3 -0
  299. package/scripts/test-ci-shard.js +13 -6
  300. package/scripts/test.js +95 -12
  301. package/skills/claim-safety/SKILL.md +102 -0
  302. package/skills/claim-safety/evals/evals.json +46 -0
  303. package/{.github/prompts/dev.prompt.md → skills/dev/SKILL.md} +44 -50
  304. package/skills/dev/evals/evals.json +50 -0
  305. package/skills/hermes-forge/SKILL.md +185 -0
  306. package/skills/hermes-forge/evals/evals.json +46 -0
  307. package/skills/issue-basics/SKILL.md +111 -0
  308. package/skills/issue-basics/evals/evals.json +46 -0
  309. package/skills/kernel/SKILL.md +166 -0
  310. package/skills/kernel/evals/evals.json +50 -0
  311. package/skills/memory/SKILL.md +102 -0
  312. package/skills/parallel-deep-research/SKILL.md +14 -11
  313. package/skills/parallel-deep-research/evals/evals.json +11 -27
  314. package/{.github/prompts/plan.prompt.md → skills/plan/SKILL.md} +132 -157
  315. package/skills/plan/evals/evals.json +42 -0
  316. package/skills/research/SKILL.md +195 -0
  317. package/skills/research/evals/evals.json +42 -0
  318. package/{.github/prompts/review.prompt.md → skills/review/SKILL.md} +98 -62
  319. package/skills/review/evals/evals.json +42 -0
  320. package/skills/rollback/SKILL.md +110 -0
  321. package/skills/rollback/evals/evals.json +46 -0
  322. package/skills/rollback/references/methods.md +204 -0
  323. package/{.cursor/commands/rollback.md → skills/rollback/references/workflow-integration.md} +10 -284
  324. package/skills/shepherd/SKILL.md +66 -0
  325. package/skills/shepherd/evals/evals.json +42 -0
  326. package/{.github/prompts/ship.prompt.md → skills/ship/SKILL.md} +81 -45
  327. package/skills/ship/evals/evals.json +42 -0
  328. package/skills/smith/SKILL.md +142 -0
  329. package/skills/smith/evals/evals.json +46 -0
  330. package/skills/smith/references/autonomy-and-gates.md +94 -0
  331. package/{.github/prompts/sonarcloud.prompt.md → skills/sonarcloud/SKILL.md} +14 -3
  332. package/skills/sonarcloud/evals/evals.json +46 -0
  333. package/skills/sonarcloud-analysis/SKILL.md +18 -13
  334. package/skills/sonarcloud-analysis/evals/evals.json +11 -15
  335. package/{.github/prompts/status.prompt.md → skills/status/SKILL.md} +20 -10
  336. package/skills/status/evals/evals.json +50 -0
  337. package/skills/triage-ready/SKILL.md +121 -0
  338. package/skills/triage-ready/evals/evals.json +42 -0
  339. package/{.github/prompts/validate.prompt.md → skills/validate/SKILL.md} +52 -29
  340. package/skills/validate/evals/evals.json +42 -0
  341. package/skills/verify/SKILL.md +299 -0
  342. package/skills/verify/evals/evals.json +50 -0
  343. package/.claude/commands/dev.md +0 -345
  344. package/.claude/commands/plan.md +0 -566
  345. package/.claude/commands/premerge.md +0 -186
  346. package/.claude/commands/research.md +0 -42
  347. package/.claude/commands/review.md +0 -451
  348. package/.claude/commands/rollback.md +0 -721
  349. package/.claude/commands/ship.md +0 -213
  350. package/.claude/commands/sonarcloud.md +0 -152
  351. package/.claude/commands/status.md +0 -90
  352. package/.claude/commands/validate.md +0 -288
  353. package/.claude/commands/verify.md +0 -269
  354. package/.claude/rules/workflow.md +0 -121
  355. package/.cline/workflows/dev.md +0 -342
  356. package/.cline/workflows/plan.md +0 -563
  357. package/.cline/workflows/premerge.md +0 -183
  358. package/.cline/workflows/research.md +0 -39
  359. package/.cline/workflows/review.md +0 -448
  360. package/.cline/workflows/rollback.md +0 -718
  361. package/.cline/workflows/ship.md +0 -210
  362. package/.cline/workflows/sonarcloud.md +0 -146
  363. package/.cline/workflows/status.md +0 -87
  364. package/.cline/workflows/validate.md +0 -285
  365. package/.cline/workflows/verify.md +0 -266
  366. package/.codex/config.toml +0 -11
  367. package/.codex/skills/dev/SKILL.md +0 -345
  368. package/.codex/skills/plan/SKILL.md +0 -566
  369. package/.codex/skills/premerge/SKILL.md +0 -186
  370. package/.codex/skills/research/SKILL.md +0 -42
  371. package/.codex/skills/review/SKILL.md +0 -451
  372. package/.codex/skills/rollback/SKILL.md +0 -721
  373. package/.codex/skills/ship/SKILL.md +0 -213
  374. package/.codex/skills/sonarcloud/SKILL.md +0 -149
  375. package/.codex/skills/status/SKILL.md +0 -90
  376. package/.codex/skills/validate/SKILL.md +0 -288
  377. package/.codex/skills/verify/SKILL.md +0 -269
  378. package/.cursor/commands/dev.md +0 -342
  379. package/.cursor/commands/plan.md +0 -563
  380. package/.cursor/commands/premerge.md +0 -183
  381. package/.cursor/commands/research.md +0 -39
  382. package/.cursor/commands/review.md +0 -448
  383. package/.cursor/commands/ship.md +0 -210
  384. package/.cursor/commands/sonarcloud.md +0 -146
  385. package/.cursor/commands/status.md +0 -87
  386. package/.cursor/commands/validate.md +0 -285
  387. package/.cursor/commands/verify.md +0 -266
  388. package/.cursorrules +0 -149
  389. package/.github/prompts/premerge.prompt.md +0 -188
  390. package/.github/prompts/research.prompt.md +0 -44
  391. package/.github/prompts/rollback.prompt.md +0 -723
  392. package/.github/prompts/verify.prompt.md +0 -271
  393. package/.github/workflows/beads-to-github.yml +0 -89
  394. package/.github/workflows/github-to-beads.yml +0 -100
  395. package/.kilocode/workflows/dev.md +0 -346
  396. package/.kilocode/workflows/plan.md +0 -567
  397. package/.kilocode/workflows/premerge.md +0 -187
  398. package/.kilocode/workflows/research.md +0 -43
  399. package/.kilocode/workflows/review.md +0 -452
  400. package/.kilocode/workflows/rollback.md +0 -722
  401. package/.kilocode/workflows/ship.md +0 -214
  402. package/.kilocode/workflows/sonarcloud.md +0 -150
  403. package/.kilocode/workflows/status.md +0 -91
  404. package/.kilocode/workflows/validate.md +0 -289
  405. package/.kilocode/workflows/verify.md +0 -270
  406. package/.opencode/commands/dev.md +0 -345
  407. package/.opencode/commands/plan.md +0 -566
  408. package/.opencode/commands/premerge.md +0 -186
  409. package/.opencode/commands/research.md +0 -42
  410. package/.opencode/commands/review.md +0 -451
  411. package/.opencode/commands/rollback.md +0 -721
  412. package/.opencode/commands/ship.md +0 -213
  413. package/.opencode/commands/sonarcloud.md +0 -149
  414. package/.opencode/commands/status.md +0 -90
  415. package/.opencode/commands/validate.md +0 -288
  416. package/.opencode/commands/verify.md +0 -269
  417. package/.roo/commands/dev.md +0 -346
  418. package/.roo/commands/plan.md +0 -567
  419. package/.roo/commands/premerge.md +0 -187
  420. package/.roo/commands/research.md +0 -43
  421. package/.roo/commands/review.md +0 -452
  422. package/.roo/commands/rollback.md +0 -722
  423. package/.roo/commands/ship.md +0 -214
  424. package/.roo/commands/sonarcloud.md +0 -150
  425. package/.roo/commands/status.md +0 -91
  426. package/.roo/commands/validate.md +0 -289
  427. package/.roo/commands/verify.md +0 -270
  428. package/docs/BEADS_GITHUB_SYNC.md +0 -281
  429. package/docs/GREPTILE_SETUP.md +0 -400
  430. package/docs/MANUAL_REVIEW_GUIDE.md +0 -106
  431. package/docs/SETUP.md +0 -663
  432. package/docs/VALIDATION.md +0 -363
  433. package/lib/agents/cline.plugin.json +0 -29
  434. package/lib/agents/copilot.plugin.json +0 -24
  435. package/lib/agents/kilocode.plugin.json +0 -22
  436. package/lib/agents/opencode.plugin.json +0 -23
  437. package/lib/agents/roo.plugin.json +0 -30
  438. package/lib/beads-bootstrap.js +0 -225
  439. package/lib/beads-health-check.js +0 -188
  440. package/lib/commands/commands-reset.js +0 -147
  441. package/opencode.json +0 -67
  442. package/scripts/beads-context.test.js +0 -584
  443. package/scripts/github-beads-sync/comment.mjs +0 -64
  444. package/scripts/github-beads-sync/config.mjs +0 -148
  445. package/scripts/github-beads-sync/github-api.mjs +0 -131
  446. package/scripts/github-beads-sync/index.mjs +0 -356
  447. package/scripts/github-beads-sync/label-mapper.mjs +0 -54
  448. package/scripts/github-beads-sync/mapping.mjs +0 -132
  449. package/scripts/github-beads-sync/reverse-sync-cli.mjs +0 -31
  450. package/scripts/github-beads-sync/reverse-sync.mjs +0 -162
  451. package/scripts/github-beads-sync/run-bd.mjs +0 -161
  452. package/scripts/github-beads-sync/sanitize.mjs +0 -121
  453. package/scripts/github-beads-sync.config.json +0 -26
  454. package/scripts/sync-commands.js +0 -600
@@ -2,12 +2,15 @@
2
2
  # scripts/forge-team/lib/epic.sh — Epic rollup view
3
3
  #
4
4
  # Shows epic progress with per-developer breakdown and blocked issue tracking.
5
+ # All data comes from a SINGLE `forge issue children <id> --json` call: the kernel
6
+ # computes the rollup (done-only percentage, per-status counts) and emits each child
7
+ # with its assignee + blocked_by, so this layer only renders.
5
8
  #
6
9
  # Functions:
7
10
  # cmd_epic — Top-level dispatcher entry point
8
11
  #
9
12
  # Env overrides (for testing):
10
- # BD_CMD — Path to bd binary
13
+ # FORGE_CMD — Path to forge binary (default: forge)
11
14
  #
12
15
  # This file does NOT set errexit/pipefail — callers manage their own shell options.
13
16
 
@@ -19,85 +22,10 @@ _EPIC_LIB_LOADED=1
19
22
 
20
23
  # ── Internal helpers ─────────────────────────────────────────────────────
21
24
 
22
- # _epic_get_bd Returns the bd command path
23
- _epic_get_bd() {
24
- printf '%s' "${BD_CMD:-bd}"
25
- }
26
-
27
- # _epic_parse_blocks <bd-show-output>
28
- # Extracts child issue IDs from the BLOCKS section.
29
- # Each line in BLOCKS looks like: ← ✓ forge-child1: Child 1 (closed)
30
- # Returns one ID per line.
31
- _epic_parse_blocks() {
32
- local bd_output="$1"
33
- local in_blocks=0
34
-
35
- while IFS= read -r line; do
36
- if [[ "$line" == "BLOCKS" ]]; then
37
- in_blocks=1
38
- continue
39
- fi
40
- # Stop at next section header (non-indented, non-empty line after BLOCKS)
41
- if [[ $in_blocks -eq 1 ]]; then
42
- if [[ -z "$line" ]]; then
43
- continue
44
- fi
45
- if [[ "$line" =~ ^[A-Z] ]]; then
46
- break
47
- fi
48
- # Extract issue ID: matches forge-XXXX pattern after the arrow+status marker
49
- local child_id
50
- child_id="$(printf '%s' "$line" | sed -n 's/.*← [^ ]* \([a-z0-9-]*\):.*/\1/p')"
51
- if [[ -n "$child_id" ]]; then
52
- printf '%s\n' "$child_id"
53
- fi
54
- fi
55
- done <<< "$bd_output"
56
- }
57
-
58
- # _epic_get_child_info <child-id>
59
- # Returns: id|status|owner|title|blocked_by
60
- _epic_get_child_info() {
61
- local child_id="$1"
62
- local bd_cmd
63
- bd_cmd="$(_epic_get_bd)"
64
-
65
- local child_output
66
- child_output="$("$bd_cmd" show "$child_id" 2>/dev/null)" || return 1
67
-
68
- local first_line
69
- first_line="$(printf '%s' "$child_output" | head -1)"
70
-
71
- # Parse status from the first character/marker
72
- local status="open"
73
- if [[ "$first_line" == *"CLOSED"* ]] || [[ "$first_line" == *"✓"* ]]; then
74
- status="closed"
75
- elif [[ "$first_line" == *"IN_PROGRESS"* ]] || [[ "$first_line" == *"◐"* ]]; then
76
- status="in_progress"
77
- fi
78
-
79
- # Parse title — between · and [
80
- local title
81
- title="$(printf '%s' "$first_line" | sed -n 's/^[^ ]* [^ ]* · \(.*\) \[.*/\1/p')"
82
- if [[ -z "$title" ]]; then
83
- title="$child_id"
84
- fi
85
-
86
- # Parse owner from "Owner: xxx" line
87
- local owner=""
88
- owner="$(printf '%s' "$child_output" | sed -n 's/^Owner: *//p' | head -1)"
89
-
90
- # Check for BLOCKED_BY section
91
- local blocked_by=""
92
- blocked_by="$(printf '%s' "$child_output" | sed -n '/^BLOCKED_BY$/,/^[A-Z]/{ /^ /{ s/.*→ \([a-z0-9-]*\):.*/\1/p; }; }')"
93
-
94
- printf '%s|%s|%s|%s|%s' "$child_id" "$status" "$owner" "$title" "$blocked_by"
95
- }
96
-
97
- # _epic_status_icon <status>
25
+ # _epic_status_icon <status> (kernel status vocabulary: open|in_progress|review|done|cancelled)
98
26
  _epic_status_icon() {
99
27
  case "$1" in
100
- closed) printf '%s' "✓" ;;
28
+ done) printf '%s' "✓" ;;
101
29
  in_progress) printf '%s' "◐" ;;
102
30
  *) printf '%s' "○" ;;
103
31
  esac
@@ -115,35 +43,43 @@ cmd_epic() {
115
43
  return 1
116
44
  fi
117
45
 
118
- local bd_cmd
119
- bd_cmd="$(_epic_get_bd)"
46
+ local forge_cmd
47
+ forge_cmd="${FORGE_CMD:-forge}"
120
48
 
121
- # 1. Get epic details
122
- local epic_output
123
- epic_output="$("$bd_cmd" show "$issue_id" 2>/dev/null)" || {
49
+ # 1. Single query: epic header + direct children + kernel-computed rollup. A missing
50
+ # or invalid id makes `forge issue children` fail (empty stdout) — treat as not found.
51
+ local response
52
+ response="$("$forge_cmd" issue children "$issue_id" --json 2>/dev/null)" || {
124
53
  echo "ERROR: Could not fetch epic $issue_id" >&2
125
54
  return 1
126
55
  }
127
-
128
- # Parse epic title from first line
129
- local epic_first_line
130
- epic_first_line="$(printf '%s' "$epic_output" | head -1)"
131
- local epic_title
132
- epic_title="$(printf '%s' "$epic_first_line" | sed -n 's/^[^ ]* [^ ]* · \(.*\) \[.*/\1/p')"
133
- if [[ -z "$epic_title" ]]; then
134
- epic_title="$issue_id"
56
+ if [[ -z "$response" ]]; then
57
+ echo "ERROR: Could not fetch epic $issue_id" >&2
58
+ return 1
135
59
  fi
136
60
 
137
- # 2. Parse BLOCKS section to find child issues
138
- local children_ids
139
- children_ids="$(_epic_parse_blocks "$epic_output")"
140
-
141
- # Handle empty epic
142
- if [[ -z "$children_ids" ]]; then
61
+ # 2. Epic title (fall back to the id when the header carries no title).
62
+ local epic_title
63
+ epic_title="$(printf '%s' "$response" | jq -r '.data.epic.title // empty' | tr -d '\r')"
64
+ [[ -z "$epic_title" ]] && epic_title="$issue_id"
65
+
66
+ # 3. Rollup counts (kernel-computed). open_count keeps the historical invariant
67
+ # total = done + in_progress + open_count (the catch-all bucket also absorbs the
68
+ # kernel review/cancelled statuses), so downstream consumers see a stable shape.
69
+ local total done_count in_progress_count open_count percentage
70
+ total="$(printf '%s' "$response" | jq -r '.data.rollup.total // 0' | tr -d '\r')"
71
+ done_count="$(printf '%s' "$response" | jq -r '.data.rollup.done // 0' | tr -d '\r')"
72
+ in_progress_count="$(printf '%s' "$response" | jq -r '.data.rollup.in_progress // 0' | tr -d '\r')"
73
+ percentage="$(printf '%s' "$response" | jq -r '.data.rollup.percentage // 0' | tr -d '\r')"
74
+ open_count=$((total - done_count - in_progress_count))
75
+
76
+ # 4. Empty epic → no children.
77
+ if [[ "$total" -eq 0 ]]; then
143
78
  if [[ "$format_flag" == "--format=json" ]]; then
144
- cat <<ENDJSON
145
- {"epic_id":"$issue_id","title":"$epic_title","total":0,"done":0,"in_progress":0,"open_count":0,"percentage":0,"children":[],"by_developer":{},"blocked":[]}
146
- ENDJSON
79
+ # Build via jq --arg so a title containing quotes/backslashes stays valid
80
+ # JSON (parity with the non-empty path below).
81
+ jq -cn --arg epic_id "$issue_id" --arg title "$epic_title" \
82
+ '{epic_id:$epic_id,title:$title,total:0,done:0,in_progress:0,open_count:0,percentage:0,children:[],by_developer:{},blocked:[]}'
147
83
  return 0
148
84
  fi
149
85
  echo "Epic: $issue_id — $epic_title"
@@ -151,181 +87,81 @@ ENDJSON
151
87
  return 0
152
88
  fi
153
89
 
154
- # 3. For each child: get status, assignee
155
- local total=0
156
- local done_count=0
157
- local in_progress_count=0
158
- local open_count=0
159
- local blocked_list=""
160
-
161
- # Arrays for child data (using indexed approach for bash 3 compat)
162
- local child_lines=""
163
- # Developer tracking: accumulate "dev:status" pairs
164
- local dev_entries=""
165
-
166
- while IFS= read -r child_id; do
167
- [[ -z "$child_id" ]] && continue
168
-
169
- local info
170
- info="$(_epic_get_child_info "$child_id")" || continue
171
-
172
- local c_id c_status c_owner c_title c_blocked
173
- IFS='|' read -r c_id c_status c_owner c_title c_blocked <<< "$info"
174
-
175
- total=$((total + 1))
176
-
177
- case "$c_status" in
178
- closed) done_count=$((done_count + 1)) ;;
179
- in_progress) in_progress_count=$((in_progress_count + 1)) ;;
180
- *) open_count=$((open_count + 1)) ;;
181
- esac
182
-
183
- # Track blocked children
184
- if [[ -n "$c_blocked" ]]; then
185
- if [[ -n "$blocked_list" ]]; then
186
- blocked_list="$blocked_list"$'\n'"$c_id blocked by $c_blocked"
187
- else
188
- blocked_list="$c_id blocked by $c_blocked"
189
- fi
190
- fi
191
-
192
- # Build child line for display
193
- local icon
194
- icon="$(_epic_status_icon "$c_status")"
195
- local display_owner="${c_owner:-unassigned}"
196
- child_lines="${child_lines} $icon $c_id [$display_owner] $c_title ($c_status)"$'\n'
197
-
198
- # Track developer entries
199
- if [[ -n "$c_owner" ]]; then
200
- dev_entries="${dev_entries}${c_owner}:${c_status}"$'\n'
201
- fi
202
- done <<< "$children_ids"
203
-
204
- # 4. Calculate completion percentage
205
- local percentage=0
206
- if [[ $total -gt 0 ]]; then
207
- percentage=$(( (done_count * 100) / total ))
208
- fi
209
-
210
- # 5. Build per-developer breakdown
211
- # Collect unique developers
212
- local devs=""
213
- while IFS= read -r entry; do
214
- [[ -z "$entry" ]] && continue
215
- local dev="${entry%%:*}"
216
- if [[ -z "$devs" ]] || ! printf '%s' "$devs" | grep -qxF "$dev"; then
217
- if [[ -n "$devs" ]]; then
218
- devs="$devs"$'\n'"$dev"
219
- else
220
- devs="$dev"
221
- fi
222
- fi
223
- done <<< "$dev_entries"
224
-
225
- # JSON output
90
+ # 5. JSON output one jq transform from the kernel response. Preserves the historical
91
+ # cmd_epic shape (epic_id,title,total,done,in_progress,open_count,percentage,
92
+ # children,by_developer,blocked). Unassigned children are excluded from by_developer
93
+ # (matches the prior behavior), and per-dev open is the same total-done-in_progress
94
+ # catch-all.
226
95
  if [[ "$format_flag" == "--format=json" ]]; then
227
- local children_json="["
228
- local first_child=1
229
- while IFS= read -r child_id; do
230
- [[ -z "$child_id" ]] && continue
231
- local info
232
- info="$(_epic_get_child_info "$child_id")" || continue
233
- local c_id c_status c_owner c_title c_blocked
234
- IFS='|' read -r c_id c_status c_owner c_title c_blocked <<< "$info"
235
-
236
- if [[ $first_child -eq 0 ]]; then
237
- children_json="$children_json,"
238
- fi
239
- first_child=0
240
- children_json="$children_json{\"id\":\"$c_id\",\"status\":\"$c_status\",\"owner\":\"$c_owner\",\"title\":\"$c_title\",\"blocked_by\":\"$c_blocked\"}"
241
- done <<< "$children_ids"
242
- children_json="$children_json]"
243
-
244
- local dev_json="{"
245
- local first_dev=1
246
- while IFS= read -r dev; do
247
- [[ -z "$dev" ]] && continue
248
- local d_done=0 d_in_progress=0 d_open=0 d_total=0
249
- while IFS= read -r entry; do
250
- [[ -z "$entry" ]] && continue
251
- local e_dev="${entry%%:*}"
252
- local e_status="${entry#*:}"
253
- if [[ "$e_dev" == "$dev" ]]; then
254
- d_total=$((d_total + 1))
255
- case "$e_status" in
256
- closed) d_done=$((d_done + 1)) ;;
257
- in_progress) d_in_progress=$((d_in_progress + 1)) ;;
258
- *) d_open=$((d_open + 1)) ;;
259
- esac
260
- fi
261
- done <<< "$dev_entries"
262
-
263
- if [[ $first_dev -eq 0 ]]; then
264
- dev_json="$dev_json,"
265
- fi
266
- first_dev=0
267
- dev_json="$dev_json\"$dev\":{\"total\":$d_total,\"done\":$d_done,\"in_progress\":$d_in_progress,\"open\":$d_open}"
268
- done <<< "$devs"
269
- dev_json="$dev_json}"
270
-
271
- local blocked_json="["
272
- if [[ -n "$blocked_list" ]]; then
273
- local first_blocked=1
274
- while IFS= read -r bline; do
275
- [[ -z "$bline" ]] && continue
276
- if [[ $first_blocked -eq 0 ]]; then
277
- blocked_json="$blocked_json,"
278
- fi
279
- first_blocked=0
280
- blocked_json="$blocked_json\"$bline\""
281
- done <<< "$blocked_list"
282
- fi
283
- blocked_json="$blocked_json]"
284
-
285
- printf '{"epic_id":"%s","title":"%s","total":%d,"done":%d,"in_progress":%d,"open_count":%d,"percentage":%d,"children":%s,"by_developer":%s,"blocked":%s}\n' \
286
- "$issue_id" "$epic_title" "$total" "$done_count" "$in_progress_count" "$open_count" "$percentage" \
287
- "$children_json" "$dev_json" "$blocked_json"
96
+ printf '%s' "$response" | jq -c \
97
+ --arg epic_id "$issue_id" \
98
+ --arg title "$epic_title" '
99
+ (.data.children // []) as $children
100
+ | {
101
+ epic_id: $epic_id,
102
+ title: $title,
103
+ total: (.data.rollup.total // 0),
104
+ done: (.data.rollup.done // 0),
105
+ in_progress: (.data.rollup.in_progress // 0),
106
+ open_count: ((.data.rollup.total // 0) - (.data.rollup.done // 0) - (.data.rollup.in_progress // 0)),
107
+ percentage: (.data.rollup.percentage // 0),
108
+ children: [ $children[] | {
109
+ id: .id,
110
+ status: .status,
111
+ owner: (.assignee // ""),
112
+ title: (.title // .id),
113
+ blocked_by: ((.blocked_by // []) | join(","))
114
+ } ],
115
+ by_developer: (
116
+ [ $children[] | select((.assignee // "") != "") ]
117
+ | group_by(.assignee)
118
+ | map(
119
+ (.[0].assignee) as $dev
120
+ | length as $t
121
+ | ([.[] | select(.status == "done")] | length) as $d
122
+ | ([.[] | select(.status == "in_progress")] | length) as $ip
123
+ | { key: $dev, value: { total: $t, done: $d, in_progress: $ip, open: ($t - $d - $ip) } }
124
+ )
125
+ | from_entries
126
+ ),
127
+ blocked: [ $children[] | select(.blocked == true) | "\(.id) blocked by \((.blocked_by // []) | join(","))" ]
128
+ }' | tr -d '\r'
288
129
  return 0
289
130
  fi
290
131
 
291
- # Text output
132
+ # 6. Text output.
292
133
  echo "Epic: $issue_id — $epic_title"
293
134
  echo "Progress: $done_count/$total ($percentage%)"
294
- printf '%s' "$child_lines"
135
+ while IFS=$'\t' read -r c_id c_status c_owner c_title; do
136
+ [[ -z "$c_id" ]] && continue
137
+ local icon
138
+ icon="$(_epic_status_icon "$c_status")"
139
+ echo " $icon $c_id [${c_owner:-unassigned}] $c_title ($c_status)"
140
+ done < <(printf '%s' "$response" | jq -r '.data.children[] | [.id, .status, (.assignee // ""), (.title // .id)] | @tsv' | tr -d '\r')
295
141
 
296
142
  echo ""
297
143
  echo "By developer:"
298
- while IFS= read -r dev; do
299
- [[ -z "$dev" ]] && continue
300
- local d_done=0 d_in_progress=0 d_open=0 d_total=0
301
- while IFS= read -r entry; do
302
- [[ -z "$entry" ]] && continue
303
- local e_dev="${entry%%:*}"
304
- local e_status="${entry#*:}"
305
- if [[ "$e_dev" == "$dev" ]]; then
306
- d_total=$((d_total + 1))
307
- case "$e_status" in
308
- closed) d_done=$((d_done + 1)) ;;
309
- in_progress) d_in_progress=$((d_in_progress + 1)) ;;
310
- *) d_open=$((d_open + 1)) ;;
311
- esac
312
- fi
313
- done <<< "$dev_entries"
314
-
315
- local dev_parts=""
316
- dev_parts="$d_done/$d_total done"
317
- [[ $d_in_progress -gt 0 ]] && dev_parts="$dev_parts, $d_in_progress in progress"
318
- [[ $d_open -gt 0 ]] && dev_parts="$dev_parts, $d_open open"
319
- echo " $dev: $dev_parts"
320
- done <<< "$devs"
144
+ printf '%s' "$response" | jq -r '
145
+ [ (.data.children // [])[] | select((.assignee // "") != "") ]
146
+ | group_by(.assignee)
147
+ | map(
148
+ (.[0].assignee) as $dev
149
+ | length as $t
150
+ | ([.[] | select(.status == "done")] | length) as $d
151
+ | ([.[] | select(.status == "in_progress")] | length) as $ip
152
+ | ($t - $d - $ip) as $op
153
+ | " \($dev): \($d)/\($t) done"
154
+ + (if $ip > 0 then ", \($ip) in progress" else "" end)
155
+ + (if $op > 0 then ", \($op) open" else "" end)
156
+ )
157
+ | .[]' | tr -d '\r'
321
158
 
322
159
  echo ""
323
- if [[ -n "$blocked_list" ]]; then
160
+ local blocked_lines
161
+ blocked_lines="$(printf '%s' "$response" | jq -r '.data.children[] | select(.blocked == true) | " \(.id) blocked by \((.blocked_by // []) | join(","))"' | tr -d '\r')"
162
+ if [[ -n "$blocked_lines" ]]; then
324
163
  echo "Blocked:"
325
- while IFS= read -r bline; do
326
- [[ -z "$bline" ]] && continue
327
- echo " $bline"
328
- done <<< "$blocked_list"
164
+ printf '%s\n' "$blocked_lines"
329
165
  else
330
166
  echo "Blocked: none"
331
167
  fi
@@ -8,8 +8,8 @@
8
8
  #
9
9
  # Env overrides (for testing):
10
10
  # GH_CMD — Path to gh binary (default: gh)
11
- # BD_CMD — Path to bd binary (default: bd)
12
- # BEADS_ROOT — Path to .beads/ parent directory (default: .)
11
+ # FORGE_CMD — Path to forge binary (default: forge)
12
+ # FORGE_ROOT — Path to .forge/ parent directory (default: .)
13
13
  #
14
14
  # This file does NOT set errexit/pipefail — callers manage their own shell options.
15
15
 
@@ -56,11 +56,11 @@ _hooks_warn() {
56
56
  }
57
57
 
58
58
  # ── _check_auto_sync_enabled ─────────────────────────────────────────────
59
- # Reads .beads/config.yaml for team.auto-sync setting.
59
+ # Reads .forge/config.yaml for the team.auto-sync setting.
60
60
  # Returns 0 if enabled (default), 1 if disabled.
61
61
  _check_auto_sync_enabled() {
62
- local beads_root="${BEADS_ROOT:-.}"
63
- local config_file="$beads_root/.beads/config.yaml"
62
+ local forge_root="${FORGE_ROOT:-.}"
63
+ local config_file="$forge_root/.forge/config.yaml"
64
64
 
65
65
  if [[ ! -f "$config_file" ]]; then
66
66
  # Default: enabled
@@ -108,7 +108,7 @@ forge_team_sync() {
108
108
  done
109
109
 
110
110
  local gh_cmd="${GH_CMD:-gh}"
111
- local bd_cmd="${BD_CMD:-bd}"
111
+ local forge_cmd="${FORGE_CMD:-forge}"
112
112
 
113
113
  # 1. Check gh auth status
114
114
  if ! "$gh_cmd" auth status >/dev/null 2>&1; then
@@ -122,44 +122,42 @@ forge_team_sync() {
122
122
  return 0
123
123
  fi
124
124
 
125
- # 3. Get all in_progress issues
126
- local list_output
127
- list_output="$("$bd_cmd" list --status=in_progress 2>/dev/null)" || {
125
+ # 3. Get all in_progress issues as JSON
126
+ local list_json
127
+ list_json="$("$forge_cmd" issue list --status=in_progress --json 2>/dev/null)" || {
128
128
  if [[ "$quiet" == "false" ]]; then
129
129
  _hooks_warn "Failed to list issues, sync skipped"
130
130
  fi
131
131
  return 0
132
132
  }
133
133
 
134
- # Filter empty lines
135
- if [[ -z "$list_output" ]] || [[ -z "$(echo "$list_output" | tr -d '[:space:]')" ]]; then
134
+ # Build "id<TAB>has_github" lines (has_github is true when a github_issue:<n>
135
+ # label is present on the issue).
136
+ local issue_lines
137
+ issue_lines="$(printf '%s' "$list_json" | jq -r '
138
+ (.data.issues // [])[]
139
+ | [ .id, (((.labels // []) | any(test("^github_issue:"))) | tostring) ]
140
+ | join("\t")' 2>/dev/null | tr -d '\r')"
141
+
142
+ if [[ -z "$issue_lines" ]] || [[ -z "$(printf '%s' "$issue_lines" | tr -d '[:space:]')" ]]; then
136
143
  if [[ "$quiet" == "false" ]]; then
137
144
  _hooks_info "Nothing to sync"
138
145
  fi
139
146
  return 0
140
147
  fi
141
148
 
142
- # 4. For each issue, check for github_issue state and sync
149
+ # 4. For each issue with a github_issue label, sync its status to GitHub
143
150
  local synced=0
144
151
  local warnings=0
145
152
 
146
- while IFS= read -r line; do
147
- [[ -z "$line" ]] && continue
148
-
149
- # Extract issue id
150
- local issue_id
151
- issue_id="$(echo "$line" | grep -oE 'forge-[a-zA-Z0-9]+(\.[a-zA-Z0-9]+)*' | head -1)"
153
+ while IFS=$'\t' read -r issue_id has_github; do
152
154
  [[ -z "$issue_id" ]] && continue
153
155
 
154
- # Get details to check for github_issue state
155
- local show_output
156
- show_output="$("$bd_cmd" show "$issue_id" 2>/dev/null)" || continue
157
-
158
- # Check if it has github_issue:N state
159
- local gh_issue_num
160
- gh_issue_num="$(printf '%s' "$show_output" | grep -oP 'github_issue:\K[0-9]+' | head -1 || true)"
161
-
162
- if [[ -z "$gh_issue_num" ]]; then
156
+ # Skip only when there is neither a github_issue:<n> label nor a legacy
157
+ # mapping-file association. _get_github_issue_number (from sync-github.sh)
158
+ # checks the label first, then the mapping-file fallback, so mapping-only
159
+ # linked issues are still synced instead of being skipped here.
160
+ if [[ "$has_github" != "true" ]] && ! _get_github_issue_number "$issue_id" >/dev/null 2>&1; then
163
161
  # No GitHub issue linked, skip but warn
164
162
  warnings=$((warnings + 1))
165
163
  if [[ "$quiet" == "false" ]]; then
@@ -177,7 +175,7 @@ forge_team_sync() {
177
175
  _hooks_warn "Failed to sync $issue_id to GitHub"
178
176
  fi
179
177
  fi
180
- done <<< "$list_output"
178
+ done <<< "$issue_lines"
181
179
 
182
180
  # 5. Report
183
181
  if [[ "$quiet" == "false" ]]; then
@@ -2,7 +2,7 @@
2
2
  # scripts/forge-team/lib/identity.sh — GitHub-username-only identity mapping
3
3
  #
4
4
  # Auto-detects developer via `gh api user`. Stores identity in
5
- # .beads/team-map.jsonl (append-only, LWW per GitHub username).
5
+ # .forge/team-map.jsonl (append-only, LWW per GitHub username).
6
6
  #
7
7
  # Functions:
8
8
  # get_github_user — Current dev's GitHub username (cached)
@@ -14,7 +14,7 @@
14
14
  #
15
15
  # Env overrides:
16
16
  # GH_CMD — Path to gh binary (for testing)
17
- # TEAM_MAP_ROOT — Root dir for .beads/team-map.jsonl (default: .)
17
+ # TEAM_MAP_ROOT — Root dir for .forge/team-map.jsonl (default: .)
18
18
  #
19
19
  # This file does NOT set errexit/pipefail — callers manage their own shell options.
20
20
 
@@ -69,7 +69,7 @@ _identity_prompt() {
69
69
  # _team_map_file — Returns the path to team-map.jsonl
70
70
  _team_map_file() {
71
71
  local root="${TEAM_MAP_ROOT:-.}"
72
- printf '%s' "$root/.beads/team-map.jsonl"
72
+ printf '%s' "$root/.forge/team-map.jsonl"
73
73
  }
74
74
 
75
75
  # _validate_github_username <username>
@@ -124,7 +124,7 @@ get_github_user() {
124
124
  }
125
125
 
126
126
  # team_map_add <github-user> [display-name]
127
- # Adds/updates entry in .beads/team-map.jsonl.
127
+ # Adds/updates entry in .forge/team-map.jsonl.
128
128
  # Schema: {"github":"<user>","display_name":"<name>","updated_at":"<ts>","is_bot":false}
129
129
  team_map_add() {
130
130
  local github_user="${1:-}"