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
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env bash
2
- # beads-context.sh — Helper script to manage Beads issue context
2
+ # beads-context.sh — Helper script to manage issue context
3
3
  # for the Forge 7-stage workflow.
4
4
  #
5
5
  # Subcommands:
@@ -17,6 +17,9 @@ set -euo pipefail
17
17
 
18
18
  # Source shared sanitize library
19
19
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
20
+ if [[ -f "$SCRIPT_DIR/bootstrap-windows-tools.sh" ]]; then
21
+ source "$SCRIPT_DIR/bootstrap-windows-tools.sh"
22
+ fi
20
23
  source "$SCRIPT_DIR/lib/sanitize.sh"
21
24
 
22
25
  # ── Helpers ──────────────────────────────────────────────────────────────
@@ -41,11 +44,124 @@ die() {
41
44
  exit 1
42
45
  }
43
46
 
44
- # Run bd update and check for errors in both exit code and output.
45
- # bd update exits 0 even for non-existent issues, so we check stdout too.
46
- bd_update() {
47
+ # Resolve a Windows forge.exe installation for bash-based helper flows.
48
+ # This covers WSL/Git Bash cases where PowerShell can run forge.exe but bash PATH
49
+ # does not include the Windows install directory.
50
+ convert_windows_path() {
51
+ local raw="${1%$'\r'}"
52
+
53
+ if [[ -z "$raw" ]]; then
54
+ return 1
55
+ fi
56
+
57
+ if [[ ! "$raw" =~ ^[A-Za-z]:\\ ]]; then
58
+ printf '%s' "$raw"
59
+ return 0
60
+ fi
61
+
62
+ if command -v wslpath >/dev/null 2>&1; then
63
+ wslpath -u "$raw" 2>/dev/null && return 0
64
+ fi
65
+
66
+ if command -v cygpath >/dev/null 2>&1; then
67
+ cygpath -u "$raw" 2>/dev/null && return 0
68
+ fi
69
+
70
+ local drive rest
71
+ drive="$(printf '%s' "$raw" | cut -c1 | tr '[:upper:]' '[:lower:]')"
72
+ rest="${raw:2}"
73
+ rest="${rest//\\//}"
74
+ printf '/mnt/%s%s' "$drive" "$rest"
75
+ }
76
+
77
+ is_runnable_forge_candidate() {
78
+ local candidate="${1:-}"
79
+
80
+ if [[ -z "$candidate" || ! -f "$candidate" ]]; then
81
+ return 1
82
+ fi
83
+
84
+ [[ -x "$candidate" || "$candidate" == *.exe ]]
85
+ }
86
+
87
+ resolve_forge_cmd() {
88
+ local candidate=""
89
+ local converted=""
90
+
91
+ if [[ -n "${FORGE_CMD:-}" ]]; then
92
+ if [[ "${FORGE_CMD}" == *"/"* || "${FORGE_CMD}" == *"\\"* ]]; then
93
+ converted="$(convert_windows_path "$FORGE_CMD")"
94
+ if is_runnable_forge_candidate "$converted"; then
95
+ printf '%s' "$converted"
96
+ return 0
97
+ fi
98
+
99
+ is_runnable_forge_candidate "$FORGE_CMD" || return 1
100
+ fi
101
+ printf '%s' "$FORGE_CMD"
102
+ return 0
103
+ fi
104
+
105
+ if command -v forge >/dev/null 2>&1; then
106
+ printf '%s' "forge"
107
+ return 0
108
+ fi
109
+
110
+ if command -v forge.exe >/dev/null 2>&1; then
111
+ printf '%s' "forge.exe"
112
+ return 0
113
+ fi
114
+
115
+ for candidate in \
116
+ "$HOME/.local/bin/forge" \
117
+ "$HOME/.local/bin/forge.exe" \
118
+ "$HOME/.bun/bin/forge" \
119
+ "$HOME/.bun/bin/forge.exe"
120
+ do
121
+ if is_runnable_forge_candidate "$candidate"; then
122
+ printf '%s' "$candidate"
123
+ return 0
124
+ fi
125
+ done
126
+
127
+ if command -v where.exe >/dev/null 2>&1; then
128
+ while IFS= read -r candidate; do
129
+ candidate="${candidate%$'\r'}"
130
+ [[ -z "$candidate" ]] && continue
131
+
132
+ converted="$(convert_windows_path "$candidate")"
133
+ if is_runnable_forge_candidate "$converted"; then
134
+ printf '%s' "$converted"
135
+ return 0
136
+ fi
137
+
138
+ if is_runnable_forge_candidate "$candidate"; then
139
+ printf '%s' "$candidate"
140
+ return 0
141
+ fi
142
+ done < <(where.exe forge 2>/dev/null || true)
143
+ fi
144
+
145
+ return 1
146
+ }
147
+
148
+ FORGE=""
149
+
150
+ get_forge_cmd() {
151
+ if [[ -z "$FORGE" ]]; then
152
+ FORGE="$(resolve_forge_cmd)" || die "forge is required but not found"
153
+ fi
154
+
155
+ printf '%s' "$FORGE"
156
+ }
157
+
158
+ # Run forge issue update and check for errors in both exit code and output.
159
+ # The update operation exits 0 even for non-existent issues, so we check stdout too.
160
+ forge_update() {
161
+ local forge_cmd
162
+ forge_cmd="$(get_forge_cmd)"
47
163
  local output
48
- output="$(bd update "$@" 2>&1)"
164
+ output="$("$forge_cmd" issue update "$@" 2>&1)"
49
165
  local rc=$?
50
166
 
51
167
  if [[ $rc -ne 0 ]]; then
@@ -53,7 +169,7 @@ bd_update() {
53
169
  return 1
54
170
  fi
55
171
 
56
- # bd prints "Error resolving/updating ..." to stdout for non-existent issues
172
+ # Forge prints "Error resolving/updating ..." to stdout for non-existent issues
57
173
  # Use specific patterns to avoid false positives from data containing "error"
58
174
  if printf '%s' "$output" | grep -Eqi '^Error|Error resolving|Error updating'; then
59
175
  echo "$output" >&2
@@ -64,10 +180,12 @@ bd_update() {
64
180
  return 0
65
181
  }
66
182
 
67
- # Run bd comments add and check for errors similarly.
68
- bd_comment() {
183
+ # Run forge issue comment and check for errors similarly.
184
+ forge_comment() {
185
+ local forge_cmd
186
+ forge_cmd="$(get_forge_cmd)"
69
187
  local output
70
- output="$(bd comments add "$@" 2>&1)"
188
+ output="$("$forge_cmd" issue comment "$@" 2>&1)"
71
189
  local rc=$?
72
190
 
73
191
  if [[ $rc -ne 0 ]]; then
@@ -85,6 +203,25 @@ bd_comment() {
85
203
  return 0
86
204
  }
87
205
 
206
+ # Extract concatenated comment text from a `forge issue show --json` payload.
207
+ # Forge/issue show returns comments as an array of objects ({text:...}) — matching
208
+ # the issue-state contract in lib/workflow/state-manager.js — or, defensively, a
209
+ # raw string. jq is preferred; a grep/sed fallback captures "text" fields.
210
+ extract_comments_text() {
211
+ local json="$1"
212
+
213
+ if command -v jq &>/dev/null; then
214
+ printf '%s' "$json" | jq -r '
215
+ ((if type == "array" then .[0] else . end).comments // [])
216
+ | if type == "array" then (map(.text? // tostring) | join("\n"))
217
+ else tostring end
218
+ ' 2>/dev/null || true
219
+ return 0
220
+ fi
221
+
222
+ printf '%s' "$json" | grep -o '"text": *"[^"]*"' | sed 's/^"text": *"//;s/"$//' || true
223
+ }
224
+
88
225
  # ── Subcommands ──────────────────────────────────────────────────────────
89
226
 
90
227
  cmd_set_design() {
@@ -101,7 +238,7 @@ cmd_set_design() {
101
238
 
102
239
  local design_text="${task_count} tasks | ${task_file}"
103
240
 
104
- if ! bd_update "$issue_id" --design "$design_text" > /dev/null; then
241
+ if ! forge_update "$issue_id" --design "$design_text" > /dev/null; then
105
242
  die "Failed to set design on issue ${issue_id}"
106
243
  fi
107
244
 
@@ -118,7 +255,7 @@ cmd_set_acceptance() {
118
255
  local criteria
119
256
  criteria="$(sanitize "$2")"
120
257
 
121
- if ! bd_update "$issue_id" --acceptance "$criteria" > /dev/null; then
258
+ if ! forge_update "$issue_id" --acceptance "$criteria" > /dev/null; then
122
259
  die "Failed to set acceptance on issue ${issue_id}"
123
260
  fi
124
261
 
@@ -158,7 +295,7 @@ cmd_update_progress() {
158
295
 
159
296
  local note="Task ${task_num}/${total} done: ${title} | ${test_count} tests | ${commit_sha} | ${gate_count} gates"
160
297
 
161
- if ! bd_update "$issue_id" --append-notes "$note" > /dev/null; then
298
+ if ! forge_update "$issue_id" --append-notes "$note" > /dev/null; then
162
299
  die "Failed to update progress on issue ${issue_id}"
163
300
  fi
164
301
 
@@ -172,18 +309,20 @@ cmd_parse_progress() {
172
309
  fi
173
310
 
174
311
  local issue_id="$1"
312
+ local forge_cmd
313
+ forge_cmd="$(get_forge_cmd)"
175
314
 
176
315
  # Get the issue JSON — detect non-existent issues
177
316
  local json
178
- json="$(bd show "$issue_id" --json 2>&1)" || die "Failed to show issue ${issue_id}"
317
+ json="$("$forge_cmd" issue show "$issue_id" --json 2>&1)" || die "Failed to show issue ${issue_id}"
179
318
 
180
- # bd show may exit 0 but print an error for non-existent issues
181
- # Match specific bd error patterns, not the word "error" in data fields
319
+ # show may exit 0 but print an error for non-existent issues
320
+ # Match specific error patterns, not the word "error" in data fields
182
321
  if printf '%s' "$json" | grep -Eqi '^Error (fetching|resolving)'; then
183
322
  die "Issue not found: ${issue_id}"
184
323
  fi
185
324
 
186
- # bd show returns "[]" or empty for non-existent issues
325
+ # show returns "[]" or empty for non-existent issues
187
326
  if [[ -z "$json" || "$json" == "[]" || "$json" == "null" ]]; then
188
327
  die "Issue not found: ${issue_id}"
189
328
  fi
@@ -191,7 +330,7 @@ cmd_parse_progress() {
191
330
  # Extract notes field from JSON — prefer jq if available, fall back to grep/sed
192
331
  local notes
193
332
  if command -v jq &>/dev/null; then
194
- # Handle both array ([{...}]) and object ({...}) responses from bd show
333
+ # Handle both array ([{...}]) and object ({...}) show responses
195
334
  notes="$(printf '%s' "$json" | jq -r 'if type == "array" then .[0].notes else .notes end // empty' 2>/dev/null || true)"
196
335
  else
197
336
  notes="$(printf '%s' "$json" | grep -o '"notes": *"[^"]*"' | head -1 | sed 's/^"notes": *"//;s/"$//' || true)"
@@ -305,7 +444,7 @@ Next: ${flag_next}"
305
444
  WorkflowState: ${flag_workflow_state}"
306
445
  fi
307
446
 
308
- if ! bd_comment "$issue_id" "$comment" > /dev/null; then
447
+ if ! forge_comment "$issue_id" "$comment" > /dev/null; then
309
448
  die "Failed to record stage transition on issue ${issue_id}"
310
449
  fi
311
450
 
@@ -320,15 +459,17 @@ cmd_validate() {
320
459
 
321
460
  local issue_id="$1"
322
461
  local warnings=0
462
+ local forge_cmd
463
+ forge_cmd="$(get_forge_cmd)"
323
464
 
324
465
  # Get issue JSON
325
466
  local json
326
- json="$(bd show "$issue_id" --json 2>&1)" || {
467
+ json="$("$forge_cmd" issue show "$issue_id" --json 2>&1)" || {
327
468
  echo "Error: Failed to retrieve issue ${issue_id}" >&2
328
469
  exit 1
329
470
  }
330
471
 
331
- # Check for bd error patterns
472
+ # Check for error patterns
332
473
  if printf '%s' "$json" | grep -Eqi '^Error|Error resolving|Error fetching'; then
333
474
  echo "Error: Issue not found: ${issue_id}" >&2
334
475
  exit 1
@@ -355,9 +496,11 @@ cmd_validate() {
355
496
  warnings=$((warnings + 1))
356
497
  fi
357
498
 
358
- # Get comments to check for stage transitions
499
+ # The issue payload returned by `forge issue show --json` already includes its
500
+ # comment history, so the stage-transition checks read comments from that single
501
+ # response rather than issuing a separate comment-list query.
359
502
  local comments
360
- comments="$(bd comments list "$issue_id" 2>/dev/null || true)"
503
+ comments="$(extract_comments_text "$json")"
361
504
 
362
505
  # Check 2: At least one stage transition exists
363
506
  local has_transition=false
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
5
+ NODE_CMD="${NODE_CMD:-node}"
6
+
7
+ exec "$NODE_CMD" "$SCRIPT_DIR/lib/beads-migrate-to-dolt.mjs" "$@"
@@ -0,0 +1,284 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ _BEADS_UPGRADE_SMOKE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
5
+ if [[ -f "$_BEADS_UPGRADE_SMOKE_DIR/bootstrap-windows-tools.sh" ]]; then
6
+ source "$_BEADS_UPGRADE_SMOKE_DIR/bootstrap-windows-tools.sh"
7
+ fi
8
+
9
+ BD_CMD="${BD_CMD:-bd}"
10
+ NODE_CMD="${NODE_CMD:-node}"
11
+ PROJECT_ROOT="${PROJECT_ROOT:-$(pwd)}"
12
+ ARTIFACT_DIR="${BEADS_UPGRADE_SMOKE_ARTIFACT_DIR:-${PROJECT_ROOT}/.artifacts/beads-upgrade-smoke}"
13
+ COMMAND_LOG_PATH="${ARTIFACT_DIR}/commands.jsonl"
14
+ SUMMARY_PATH="${ARTIFACT_DIR}/summary.json"
15
+ CLEANUP_REASON="Beads upgrade smoke cleanup"
16
+ SMOKE_RUN_ID="${BEADS_UPGRADE_SMOKE_RUN_ID:-$(date +%s)-$$}"
17
+ PRIMARY_ISSUE_TITLE="Beads upgrade smoke primary (${SMOKE_RUN_ID})"
18
+ DEPENDENT_ISSUE_TITLE="Beads upgrade smoke dependent (${SMOKE_RUN_ID})"
19
+
20
+ node_fs_path() {
21
+ case "$1" in
22
+ /[A-Za-z]/*)
23
+ _drive="$(printf '%s' "${1:1:1}" | tr '[:lower:]' '[:upper:]')"
24
+ printf '%s:/%s\n' "$_drive" "${1:3}"
25
+ ;;
26
+ *)
27
+ if command -v cygpath >/dev/null 2>&1; then
28
+ cygpath -m "$1"
29
+ else
30
+ printf '%s\n' "$1"
31
+ fi
32
+ ;;
33
+ esac
34
+ }
35
+
36
+ mkdir -p "${ARTIFACT_DIR}"
37
+ : > "${COMMAND_LOG_PATH}"
38
+
39
+ created_issue_ids=()
40
+ closed_issue_ids=()
41
+ failed_step=""
42
+ failure_message=""
43
+
44
+ parse_issue_id() {
45
+ local output="$1"
46
+ if [[ "${output}" =~ Created[[:space:]]+issue:[[:space:]]*([[:alnum:]-]+) ]]; then
47
+ printf '%s' "${BASH_REMATCH[1]}"
48
+ return 0
49
+ fi
50
+ if [[ "${output}" =~ \"id\"[[:space:]]*:[[:space:]]*\"([[:alnum:]-]+)\" ]]; then
51
+ printf '%s' "${BASH_REMATCH[1]}"
52
+ return 0
53
+ fi
54
+ return 1
55
+ }
56
+
57
+ find_issue_id_by_title() {
58
+ local issue_title="$1"
59
+ local list_output
60
+ list_output="$("${BD_CMD}" list --json --limit=50 2>/dev/null)" || return 1
61
+
62
+ "${NODE_CMD}" -e '
63
+ const fs = require("node:fs");
64
+ const [issueTitle] = process.argv.slice(1);
65
+ try {
66
+ const rows = JSON.parse(fs.readFileSync(0, "utf8"));
67
+ if (!Array.isArray(rows)) {
68
+ process.exit(1);
69
+ }
70
+ const match = rows.find((row) => row && row.title === issueTitle && typeof row.id === "string");
71
+ if (!match) {
72
+ process.exit(1);
73
+ }
74
+ process.stdout.write(match.id);
75
+ } catch {
76
+ process.exit(1);
77
+ }
78
+ ' "${issue_title}" <<< "${list_output}"
79
+ }
80
+
81
+ append_command() {
82
+ local step="$1"
83
+ local command_name="$2"
84
+ local command_text="$3"
85
+ local exit_code="$4"
86
+ local stdout_path="$5"
87
+ local stderr_path="$6"
88
+
89
+ "${NODE_CMD}" -e '
90
+ const fs = require("node:fs");
91
+ const [logPath, step, commandName, commandText, exitCode, stdoutPath, stderrPath] = process.argv.slice(1);
92
+ const entry = {
93
+ step,
94
+ commandName,
95
+ commandText,
96
+ exitCode: Number(exitCode),
97
+ stdoutPath,
98
+ stderrPath,
99
+ };
100
+ fs.appendFileSync(logPath, JSON.stringify(entry) + "\n");
101
+ ' "$(node_fs_path "${COMMAND_LOG_PATH}")" "${step}" "${command_name}" "${command_text}" "${exit_code}" "$(node_fs_path "${stdout_path}")" "$(node_fs_path "${stderr_path}")"
102
+ }
103
+
104
+ read_output_snippet() {
105
+ local file_path="$1"
106
+ if [[ ! -f "${file_path}" ]]; then
107
+ return 0
108
+ fi
109
+
110
+ "${NODE_CMD}" -e '
111
+ const fs = require("node:fs");
112
+ const [filePath] = process.argv.slice(1);
113
+ const text = fs.readFileSync(filePath, "utf8");
114
+ process.stdout.write(text.slice(0, 4096));
115
+ ' "$(node_fs_path "${file_path}")"
116
+ }
117
+
118
+ write_summary() {
119
+ local ok="$1"
120
+
121
+ "${NODE_CMD}" -e '
122
+ const fs = require("node:fs");
123
+ const [
124
+ commandLogPath,
125
+ summaryPath,
126
+ okValue,
127
+ failedStep,
128
+ failureMessage,
129
+ artifactDir,
130
+ createdJson,
131
+ closedJson,
132
+ ] = process.argv.slice(1);
133
+ const commands = fs.readFileSync(commandLogPath, "utf8")
134
+ .split(/\r?\n/)
135
+ .filter(Boolean)
136
+ .map((line) => JSON.parse(line));
137
+ const summary = {
138
+ ok: okValue === "true",
139
+ failedStep: failedStep || null,
140
+ failureMessage: failureMessage || null,
141
+ commands,
142
+ cleanup: {
143
+ createdIssueIds: JSON.parse(createdJson),
144
+ closedIssueIds: JSON.parse(closedJson),
145
+ },
146
+ failureArtifact: summaryPath,
147
+ artifactDir,
148
+ };
149
+ fs.writeFileSync(summaryPath, JSON.stringify(summary, null, 2) + "\n");
150
+ ' "$(node_fs_path "${COMMAND_LOG_PATH}")" "$(node_fs_path "${SUMMARY_PATH}")" "${ok}" "${failed_step}" "${failure_message}" "$(node_fs_path "${ARTIFACT_DIR}")" "$(printf '%s\n' "${created_issue_ids[@]:-}" | "${NODE_CMD}" -e 'const fs=require("node:fs"); const lines=fs.readFileSync(0,"utf8").split(/\r?\n/).filter(Boolean); process.stdout.write(JSON.stringify(lines));')" "$(printf '%s\n' "${closed_issue_ids[@]:-}" | "${NODE_CMD}" -e 'const fs=require("node:fs"); const lines=fs.readFileSync(0,"utf8").split(/\r?\n/).filter(Boolean); process.stdout.write(JSON.stringify(lines));')"
151
+ }
152
+
153
+ run_bd_step() {
154
+ local step="$1"
155
+ local command_name="$2"
156
+ shift 2
157
+
158
+ local stdout_file stderr_file exit_code command_text
159
+ stdout_file="${ARTIFACT_DIR}/$(printf '%s' "${step}" | tr '[:upper:]' '[:lower:]').stdout"
160
+ stderr_file="${ARTIFACT_DIR}/$(printf '%s' "${step}" | tr '[:upper:]' '[:lower:]').stderr"
161
+ command_text="$*"
162
+
163
+ if "${BD_CMD}" "$@" >"${stdout_file}" 2>"${stderr_file}"; then
164
+ exit_code=0
165
+ else
166
+ exit_code=$?
167
+ fi
168
+
169
+ append_command "${step}" "${command_name}" "${command_text}" "${exit_code}" "${stdout_file}" "${stderr_file}"
170
+
171
+ if [[ "${exit_code}" -ne 0 ]]; then
172
+ failed_step="${command_name}"
173
+ local stderr_text stdout_text
174
+ stderr_text="$(read_output_snippet "${stderr_file}")"
175
+ stdout_text="$(read_output_snippet "${stdout_file}")"
176
+ failure_message="${stderr_text:-${stdout_text:-${command_text}}}"
177
+ return "${exit_code}"
178
+ fi
179
+
180
+ cat "${stdout_file}"
181
+ }
182
+
183
+ is_closed_issue() {
184
+ local issue_id="$1"
185
+ local existing
186
+ for existing in "${closed_issue_ids[@]:-}"; do
187
+ if [[ "${existing}" == "${issue_id}" ]]; then
188
+ return 0
189
+ fi
190
+ done
191
+ return 1
192
+ }
193
+
194
+ rollback_unclosed_issues() {
195
+ local idx issue_id
196
+ for (( idx=${#created_issue_ids[@]} - 1; idx>=0; idx-- )); do
197
+ issue_id="${created_issue_ids[idx]}"
198
+ if is_closed_issue "${issue_id}"; then
199
+ continue
200
+ fi
201
+ if run_bd_step "rollback-close-${issue_id}" "close" close "${issue_id}" "--reason=${CLEANUP_REASON}" >/dev/null; then
202
+ closed_issue_ids+=("${issue_id}")
203
+ fi
204
+ done
205
+ }
206
+
207
+ handle_issue_id_parse_failure() {
208
+ local issue_title="$1"
209
+ local message="$2"
210
+ local recovered_issue_id=""
211
+
212
+ failed_step="create"
213
+ failure_message="${message}"
214
+
215
+ recovered_issue_id="$(find_issue_id_by_title "${issue_title}" || true)"
216
+ if [[ -n "${recovered_issue_id}" ]]; then
217
+ created_issue_ids+=("${recovered_issue_id}")
218
+ fi
219
+
220
+ rollback_unclosed_issues
221
+ write_summary "false"
222
+ exit 1
223
+ }
224
+
225
+ primary_output="$(run_bd_step "create-primary" "create" create --title="${PRIMARY_ISSUE_TITLE}" --type=task --priority=4)" || {
226
+ rollback_unclosed_issues
227
+ write_summary "false"
228
+ exit 1
229
+ }
230
+ primary_issue_id="$(parse_issue_id "${primary_output}")" || {
231
+ handle_issue_id_parse_failure "${PRIMARY_ISSUE_TITLE}" "Could not parse primary smoke issue ID"
232
+ }
233
+ created_issue_ids+=("${primary_issue_id}")
234
+
235
+ dependent_output="$(run_bd_step "create-dependent" "create" create --title="${DEPENDENT_ISSUE_TITLE}" --type=task --priority=4)" || {
236
+ rollback_unclosed_issues
237
+ write_summary "false"
238
+ exit 1
239
+ }
240
+ dependent_issue_id="$(parse_issue_id "${dependent_output}")" || {
241
+ handle_issue_id_parse_failure "${DEPENDENT_ISSUE_TITLE}" "Could not parse dependent smoke issue ID"
242
+ }
243
+ created_issue_ids+=("${dependent_issue_id}")
244
+
245
+ run_bd_step "list" "list" list --json --limit=50 >/dev/null || {
246
+ rollback_unclosed_issues
247
+ write_summary "false"
248
+ exit 1
249
+ }
250
+
251
+ run_bd_step "show-primary" "show" show "${primary_issue_id}" --json >/dev/null || {
252
+ rollback_unclosed_issues
253
+ write_summary "false"
254
+ exit 1
255
+ }
256
+
257
+ run_bd_step "dep-add" "dep" dep add "${primary_issue_id}" "${dependent_issue_id}" >/dev/null || {
258
+ rollback_unclosed_issues
259
+ write_summary "false"
260
+ exit 1
261
+ }
262
+
263
+ run_bd_step "close-dependent" "close" close "${dependent_issue_id}" "--reason=${CLEANUP_REASON}" >/dev/null || {
264
+ rollback_unclosed_issues
265
+ write_summary "false"
266
+ exit 1
267
+ }
268
+ closed_issue_ids+=("${dependent_issue_id}")
269
+
270
+ run_bd_step "close-primary" "close" close "${primary_issue_id}" "--reason=${CLEANUP_REASON}" >/dev/null || {
271
+ rollback_unclosed_issues
272
+ write_summary "false"
273
+ exit 1
274
+ }
275
+ closed_issue_ids+=("${primary_issue_id}")
276
+
277
+ run_bd_step "sync" "sync" sync >/dev/null || {
278
+ rollback_unclosed_issues
279
+ write_summary "false"
280
+ exit 1
281
+ }
282
+
283
+ write_summary "true"
284
+ printf '%s\n' "${SUMMARY_PATH}"