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,148 +0,0 @@
1
- /**
2
- * Config loader for GitHub-Beads issue sync.
3
- * @module scripts/github-beads-sync/config
4
- */
5
-
6
- import { readFileSync } from 'node:fs';
7
-
8
- /**
9
- * Default configuration for GitHub-Beads sync.
10
- * @type {Readonly<SyncConfig>}
11
- */
12
- export const DEFAULT_CONFIG = Object.freeze({
13
- labelToType: Object.freeze({
14
- bug: 'bug',
15
- enhancement: 'feature',
16
- documentation: 'task',
17
- question: 'task',
18
- }),
19
- labelToPriority: Object.freeze({
20
- P0: 0, critical: 0,
21
- P1: 1, high: 1,
22
- P2: 2, medium: 2,
23
- P3: 3, low: 3,
24
- P4: 4, backlog: 4,
25
- }),
26
- defaultType: 'task',
27
- defaultPriority: 2,
28
- mapAssignee: true,
29
- publicRepoGate: 'none',
30
- gateLabelName: 'beads-track',
31
- gateAssociations: Object.freeze(['MEMBER', 'COLLABORATOR', 'OWNER']),
32
- });
33
-
34
- /**
35
- * Deep-merge source into target (one level of nesting).
36
- * Arrays and scalars from source overwrite target.
37
- * Plain objects are merged key-by-key.
38
- * @param {object} target
39
- * @param {object} source
40
- * @returns {object} Merged result (new object)
41
- */
42
- function deepMerge(target, source) {
43
- const result = { ...target };
44
- for (const key of Object.keys(source)) {
45
- const srcVal = source[key];
46
- const tgtVal = target[key];
47
- if (
48
- srcVal !== null &&
49
- typeof srcVal === 'object' &&
50
- !Array.isArray(srcVal) &&
51
- tgtVal !== null &&
52
- typeof tgtVal === 'object' &&
53
- !Array.isArray(tgtVal)
54
- ) {
55
- result[key] = { ...tgtVal, ...srcVal };
56
- } else {
57
- result[key] = srcVal;
58
- }
59
- }
60
- return result;
61
- }
62
-
63
- /**
64
- * Clone DEFAULT_CONFIG into a mutable plain object.
65
- * @returns {object}
66
- */
67
- function cloneDefaults() {
68
- return {
69
- ...DEFAULT_CONFIG,
70
- labelToType: { ...DEFAULT_CONFIG.labelToType },
71
- labelToPriority: { ...DEFAULT_CONFIG.labelToPriority },
72
- gateAssociations: [...DEFAULT_CONFIG.gateAssociations],
73
- };
74
- }
75
-
76
- /**
77
- * Load and validate sync configuration.
78
- * - No arguments: returns a copy of DEFAULT_CONFIG.
79
- * - With path: reads JSON file and deep-merges with defaults (user overrides win).
80
- * - Missing file: returns defaults (no throw).
81
- * - Invalid JSON: throws with helpful message.
82
- *
83
- * @param {string} [configPath] - Path to a JSON config file.
84
- * @returns {object} Merged configuration object.
85
- */
86
- export function loadConfig(configPath) {
87
- if (!configPath) {
88
- return cloneDefaults();
89
- }
90
-
91
- let raw;
92
- try {
93
- raw = readFileSync(configPath, 'utf-8');
94
- } catch {
95
- // File not found or unreadable — return defaults
96
- return cloneDefaults();
97
- }
98
-
99
- let userConfig;
100
- try {
101
- userConfig = JSON.parse(raw);
102
- } catch (parseErr) {
103
- throw new Error(
104
- `Invalid JSON in config file: ${configPath}\n` +
105
- `Parse error: ${parseErr.message}`,
106
- { cause: parseErr }
107
- );
108
- }
109
-
110
- const merged = deepMerge(cloneDefaults(), userConfig);
111
- return validateConfig(merged);
112
- }
113
-
114
- /**
115
- * Validate and normalize config values.
116
- * Replaces invalid types with defaults rather than throwing.
117
- * @param {object} cfg
118
- * @returns {object} Validated config
119
- */
120
- function validateConfig(cfg) {
121
- const defaults = cloneDefaults();
122
- if (!cfg.labelToType || typeof cfg.labelToType !== 'object' || Array.isArray(cfg.labelToType)) {
123
- cfg.labelToType = defaults.labelToType;
124
- }
125
- if (!cfg.labelToPriority || typeof cfg.labelToPriority !== 'object' || Array.isArray(cfg.labelToPriority)) {
126
- cfg.labelToPriority = defaults.labelToPriority;
127
- }
128
- if (typeof cfg.defaultPriority !== 'number') {
129
- cfg.defaultPriority = defaults.defaultPriority;
130
- }
131
- if (typeof cfg.mapAssignee !== 'boolean') {
132
- cfg.mapAssignee = defaults.mapAssignee;
133
- }
134
- if (!Array.isArray(cfg.gateAssociations)) {
135
- cfg.gateAssociations = defaults.gateAssociations;
136
- }
137
- const VALID_GATE_VALUES = ['none', 'author_association', 'label'];
138
- if (!VALID_GATE_VALUES.includes(cfg.publicRepoGate)) {
139
- cfg.publicRepoGate = defaults.publicRepoGate;
140
- }
141
- if (typeof cfg.defaultType !== 'string' || !cfg.defaultType) {
142
- cfg.defaultType = defaults.defaultType;
143
- }
144
- if (typeof cfg.gateLabelName !== 'string' || !cfg.gateLabelName) {
145
- cfg.gateLabelName = defaults.gateLabelName;
146
- }
147
- return cfg;
148
- }
@@ -1,131 +0,0 @@
1
- /**
2
- * GitHub API caller module using `gh api` CLI.
3
- * Builds argument arrays for execFileSync('gh', args) — no shell invocation.
4
- * @module github-api
5
- */
6
-
7
- import { execFileSync } from 'node:child_process';
8
-
9
- const SYNC_MARKER = '<!-- beads-sync:';
10
-
11
- /**
12
- * Builds args for listing all comments on a GitHub issue.
13
- * @param {string} owner - Repository owner
14
- * @param {string} repo - Repository name
15
- * @param {number|string} issueNumber - Issue number
16
- * @returns {string[]} Args array for execFileSync('gh', args)
17
- */
18
- export function buildFindCommentsArgs(owner, repo, issueNumber) {
19
- return [
20
- 'api',
21
- `repos/${owner}/${repo}/issues/${issueNumber}/comments`,
22
- ];
23
- }
24
-
25
- /**
26
- * Finds the beads-sync comment in a list of comment objects.
27
- * @param {Array<{id: number, body: string}>} comments - Array of GitHub comment objects
28
- * @returns {{id: number, body: string}|null} The sync comment or null
29
- */
30
- export function parseFindSyncComment(comments) {
31
- const match = comments.find((c) => c.body && c.body.includes(SYNC_MARKER));
32
- if (!match) return null;
33
- return { id: match.id, body: match.body };
34
- }
35
-
36
- /**
37
- * Builds args for creating a comment on a GitHub issue.
38
- * @param {string} owner - Repository owner
39
- * @param {string} repo - Repository name
40
- * @param {number|string} issueNumber - Issue number
41
- * @param {string} body - Comment body
42
- * @returns {string[]} Args array for execFileSync('gh', args)
43
- */
44
- export function buildCreateCommentArgs(owner, repo, issueNumber, body) {
45
- return [
46
- 'api',
47
- `repos/${owner}/${repo}/issues/${issueNumber}/comments`,
48
- '-f',
49
- `body=${body}`,
50
- ];
51
- }
52
-
53
- /**
54
- * Builds args for editing an existing comment.
55
- * @param {string} owner - Repository owner
56
- * @param {string} repo - Repository name
57
- * @param {number|string} commentId - Comment ID
58
- * @param {string} body - Updated comment body
59
- * @returns {string[]} Args array for execFileSync('gh', args)
60
- */
61
- export function buildEditCommentArgs(owner, repo, commentId, body) {
62
- return [
63
- 'api',
64
- `repos/${owner}/${repo}/issues/comments/${commentId}`,
65
- '-X',
66
- 'PATCH',
67
- '-f',
68
- `body=${body}`,
69
- ];
70
- }
71
-
72
- /**
73
- * Builds args for closing a GitHub issue.
74
- * @param {string} owner - Repository owner
75
- * @param {string} repo - Repository name
76
- * @param {number|string} issueNumber - Issue number
77
- * @returns {string[]} Args array for execFileSync('gh', args)
78
- */
79
- export function buildCloseIssueArgs(owner, repo, issueNumber) {
80
- return [
81
- 'api',
82
- `repos/${owner}/${repo}/issues/${issueNumber}`,
83
- '-X',
84
- 'PATCH',
85
- '-f',
86
- 'state=closed',
87
- ];
88
- }
89
-
90
- /**
91
- * Finds the existing beads-sync comment on an issue, or returns null.
92
- * @param {string} owner - Repository owner
93
- * @param {string} repo - Repository name
94
- * @param {number|string} issueNumber - Issue number
95
- * @returns {{id: number, body: string}|null}
96
- */
97
- export function findSyncComment(owner, repo, issueNumber) {
98
- const args = buildFindCommentsArgs(owner, repo, issueNumber);
99
- const raw = execFileSync('gh', args, { encoding: 'utf-8' });
100
- const comments = JSON.parse(raw);
101
- return parseFindSyncComment(comments);
102
- }
103
-
104
- /**
105
- * Creates or edits the beads-sync comment on an issue.
106
- * If a sync comment already exists, edits it; otherwise creates a new one.
107
- * @param {string} owner - Repository owner
108
- * @param {string} repo - Repository name
109
- * @param {number|string} issueNumber - Issue number
110
- * @param {string} body - Comment body (should contain the beads-sync marker)
111
- * @returns {void}
112
- */
113
- export function createOrEditComment(owner, repo, issueNumber, body) {
114
- const existing = findSyncComment(owner, repo, issueNumber);
115
- const args = existing
116
- ? buildEditCommentArgs(owner, repo, existing.id, body)
117
- : buildCreateCommentArgs(owner, repo, issueNumber, body);
118
- execFileSync('gh', args, { encoding: 'utf-8' });
119
- }
120
-
121
- /**
122
- * Closes a GitHub issue.
123
- * @param {string} owner - Repository owner
124
- * @param {string} repo - Repository name
125
- * @param {number|string} issueNumber - Issue number
126
- * @returns {void}
127
- */
128
- export function closeIssue(owner, repo, issueNumber) {
129
- const args = buildCloseIssueArgs(owner, repo, issueNumber);
130
- execFileSync('gh', args, { encoding: 'utf-8' });
131
- }
@@ -1,332 +0,0 @@
1
- /**
2
- * Main entry point for GitHub-Beads issue sync.
3
- * Orchestrates all Wave 1 modules to handle GitHub webhook events.
4
- *
5
- * @module scripts/github-beads-sync/index
6
- */
7
-
8
- import { readFileSync, appendFileSync } from 'node:fs';
9
- import { fileURLToPath } from 'node:url';
10
- import { loadConfig } from './config.mjs';
11
- import { sanitizeTitle } from './sanitize.mjs';
12
- import { mapLabels } from './label-mapper.mjs';
13
- import { bdCreate as realBdCreate, bdClose as realBdClose, bdShow as realBdShow } from './run-bd.mjs';
14
- import { getBeadsId as realGetBeadsId, setBeadsId as realSetBeadsId } from './mapping.mjs';
15
- import { buildComment, parseComment } from './comment.mjs';
16
- import {
17
- findSyncComment as realFindSyncComment,
18
- createOrEditComment as realCreateOrEditComment,
19
- } from './github-api.mjs';
20
-
21
- /**
22
- * Check if a sender login matches known bot patterns.
23
- * @param {string} login - GitHub sender login
24
- * @returns {boolean}
25
- */
26
- function isBot(login) {
27
- if (!login) return false;
28
- return login.includes('[bot]') || login === 'github-actions';
29
- }
30
-
31
- /**
32
- * Check if an issue has the skip-beads-sync label.
33
- * @param {Array<{name: string}|string>} labels
34
- * @returns {boolean}
35
- */
36
- function hasSkipLabel(labels) {
37
- if (!labels) return false;
38
- return labels.some((l) => {
39
- const name = typeof l === 'string' ? l : l.name;
40
- return name === 'skip-beads-sync';
41
- });
42
- }
43
-
44
- /**
45
- * Handle a GitHub issue "opened" event.
46
- *
47
- * @param {object} event - Parsed GitHub webhook payload
48
- * @param {object} options
49
- * @param {string} [options.configPath] - Path to config JSON
50
- * @param {string} options.mappingPath - Path to mapping JSON
51
- * @param {string} options.owner - Repository owner
52
- * @param {string} options.repo - Repository name
53
- * @param {object} [options.bd] - Dependency injection for bd functions
54
- * @param {object} [options.github] - Dependency injection for github-api functions
55
- * @param {object} [options.mapping] - Dependency injection for mapping functions
56
- * @param {object} [options.configOverride] - Merge into loaded config (for testing)
57
- * @returns {object} Result object
58
- */
59
- export function handleOpened(event, options = {}) {
60
- const {
61
- configPath,
62
- mappingPath,
63
- owner,
64
- repo,
65
- bd = {},
66
- github = {},
67
- mapping = {},
68
- configOverride,
69
- } = options;
70
-
71
- const bdCreate = bd.bdCreate ?? realBdCreate;
72
- const findSyncComment = github.findSyncComment ?? realFindSyncComment;
73
- const createOrEditComment = github.createOrEditComment ?? realCreateOrEditComment;
74
- const getBeadsId = mapping.getBeadsId ?? realGetBeadsId;
75
- const setBeadsId = mapping.setBeadsId ?? realSetBeadsId;
76
-
77
- // 1. Load config
78
- let config = loadConfig(configPath);
79
- if (configOverride) {
80
- config = { ...config, ...configOverride };
81
- }
82
-
83
- // 2. Extract event data
84
- const issue = event.issue;
85
- const issueNumber = issue.number;
86
- const rawTitle = issue.title;
87
- const labels = issue.labels || [];
88
- const assignee = config.mapAssignee ? issue.assignee?.login : undefined;
89
- const htmlUrl = issue.html_url;
90
- const body = issue.body ?? '';
91
- const authorAssociation = issue.author_association;
92
-
93
- // 3. Guard: bot actor
94
- if (isBot(event.sender?.login)) {
95
- return { skipped: true, reason: 'bot actor' };
96
- }
97
-
98
- // 4. Guard: skip label
99
- if (hasSkipLabel(labels)) {
100
- return { skipped: true, reason: 'skip label' };
101
- }
102
-
103
- // 5. Guard: no-beads body
104
- if (body.includes('no-beads')) {
105
- return { skipped: true, reason: 'no-beads in body' };
106
- }
107
-
108
- // 6. Guard: public repo gate
109
- if (config.publicRepoGate === 'author_association') {
110
- const allowed = config.gateAssociations || [];
111
- if (!allowed.includes(authorAssociation)) {
112
- return { skipped: true, reason: 'author not authorized' };
113
- }
114
- } else if (config.publicRepoGate === 'label') {
115
- const gateLabelName = config.gateLabelName || 'beads-track';
116
- const hasGateLabel = labels.some((l) => {
117
- const name = typeof l === 'string' ? l : l.name;
118
- return name === gateLabelName;
119
- });
120
- if (!hasGateLabel) {
121
- return { skipped: true, reason: `missing required label: ${gateLabelName}` };
122
- }
123
- }
124
-
125
- // 7. Idempotency — check mapping file first (fast, survives comment deletion)
126
- const existingBeadsId = getBeadsId(mappingPath, issueNumber);
127
- if (existingBeadsId) {
128
- // Mapping exists — ensure the GitHub comment is present (repair if deleted)
129
- const existingComment = findSyncComment(owner, repo, issueNumber);
130
- if (!existingComment) {
131
- const externalRef = `gh-${issueNumber}`;
132
- const commentBody = buildComment(existingBeadsId, issueNumber, { externalRef });
133
- createOrEditComment(owner, repo, issueNumber, commentBody);
134
- }
135
- return {
136
- skipped: true,
137
- reason: 'already synced (mapping file)',
138
- beadsId: existingBeadsId,
139
- };
140
- }
141
-
142
- // 7b. Fallback idempotency — check for existing sync comment
143
- const existingComment = findSyncComment(owner, repo, issueNumber);
144
- if (existingComment) {
145
- const parsed = parseComment(existingComment.body);
146
- // Repair mapping file from comment
147
- if (parsed?.beadsId) {
148
- setBeadsId(mappingPath, issueNumber, parsed.beadsId);
149
- }
150
- return {
151
- skipped: true,
152
- reason: 'already synced (comment)',
153
- beadsId: parsed?.beadsId ?? null,
154
- };
155
- }
156
-
157
- // 8. Sanitize title (labels mapped from raw names — sanitization only needed for CLI args)
158
- const { sanitized: sanitizedTitle, warnings: titleWarnings } = sanitizeTitle(rawTitle);
159
- if (titleWarnings.length) console.warn('sanitize:', titleWarnings);
160
-
161
- // 9. Map labels using raw names (case-insensitive matching in mapLabels handles normalization)
162
- const rawLabelNames = labels.map((l) => (typeof l === 'string' ? l : l.name));
163
- const { type, priority } = mapLabels(rawLabelNames, config);
164
-
165
- // 10. Create beads issue
166
- const externalRef = `gh-${issueNumber}`;
167
- const beadsId = bdCreate({
168
- title: sanitizedTitle,
169
- type,
170
- priority,
171
- assignee,
172
- description: htmlUrl,
173
- externalRef,
174
- });
175
-
176
- if (!beadsId) {
177
- return { success: false, reason: 'bd create failed — no beads ID returned', issueNumber };
178
- }
179
-
180
- // 11. Update mapping
181
- setBeadsId(mappingPath, issueNumber, beadsId);
182
-
183
- // 12. Build and post comment
184
- const commentBody = buildComment(beadsId, issueNumber, { type, priority, externalRef });
185
- createOrEditComment(owner, repo, issueNumber, commentBody);
186
-
187
- // 13. Return success
188
- return { success: true, beadsId, issueNumber };
189
- }
190
-
191
- /**
192
- * Handle a GitHub issue "closed" event.
193
- *
194
- * @param {object} event - Parsed GitHub webhook payload
195
- * @param {object} options
196
- * @param {string} options.mappingPath - Path to mapping JSON
197
- * @param {string} options.owner - Repository owner
198
- * @param {string} options.repo - Repository name
199
- * @param {object} [options.bd] - Dependency injection for bd functions
200
- * @param {object} [options.github] - Dependency injection for github-api functions
201
- * @param {object} [options.mapping] - Dependency injection for mapping functions
202
- * @returns {object} Result object
203
- */
204
- export function handleClosed(event, options = {}) {
205
- const {
206
- mappingPath,
207
- owner,
208
- repo,
209
- bd = {},
210
- github = {},
211
- mapping = {},
212
- } = options;
213
-
214
- const bdClose = bd.bdClose ?? realBdClose;
215
- const bdShow = bd.bdShow ?? realBdShow;
216
- const getBeadsId = mapping.getBeadsId ?? realGetBeadsId;
217
- const findSyncComment = github.findSyncComment ?? realFindSyncComment;
218
-
219
- // 1. Extract issue number, labels, and state reason
220
- const issueNumber = event.issue.number;
221
- const labels = event.issue.labels || [];
222
- const stateReason = event.issue.state_reason;
223
-
224
- // 2. Guard: bot actor
225
- if (isBot(event.sender?.login)) {
226
- return { skipped: true, reason: 'bot actor' };
227
- }
228
-
229
- // 3. Guard: skip label
230
- if (hasSkipLabel(labels)) {
231
- return { skipped: true, reason: 'skip label' };
232
- }
233
-
234
- // 4. Guard: skip "not planned" closures (only close on "completed")
235
- if (stateReason && stateReason !== 'completed') {
236
- return { skipped: true, reason: `closed as ${stateReason}` };
237
- }
238
-
239
- // 5. Read mapping
240
- let beadsId = getBeadsId(mappingPath, issueNumber);
241
-
242
- // 6. Fallback: find via sync comment
243
- if (!beadsId) {
244
- const comment = findSyncComment(owner, repo, issueNumber);
245
- if (comment) {
246
- const parsed = parseComment(comment.body);
247
- // Verify the comment's tagged issue number matches current issue (prevents cross-issue close)
248
- if (parsed && parsed.issueNumber === issueNumber) {
249
- beadsId = parsed.beadsId;
250
- }
251
- }
252
- }
253
-
254
- // 7. No beads link found
255
- if (!beadsId) {
256
- return { skipped: true, reason: 'no beads link found' };
257
- }
258
-
259
- // 8. Check if already closed
260
- const status = bdShow(beadsId);
261
- if (status === null) {
262
- return { skipped: true, reason: 'could not determine beads status' };
263
- }
264
- if (status === 'closed') {
265
- return { skipped: true, reason: 'already closed' };
266
- }
267
-
268
- // 9. Close beads issue
269
- bdClose(beadsId, `Closed via GitHub issue #${issueNumber}`);
270
-
271
- // 10. Return success
272
- return { success: true, beadsId, issueNumber };
273
- }
274
-
275
- // ---------------------------------------------------------------------------
276
- // CLI entry point
277
- // ---------------------------------------------------------------------------
278
- const __filename = fileURLToPath(import.meta.url);
279
- if (process.argv[1] === __filename) {
280
- const action = process.argv[2];
281
- const eventPath = process.env.GITHUB_EVENT_PATH || process.argv[3];
282
-
283
- if (!action || !eventPath) {
284
- console.error('Usage: node index.mjs <opened|closed> [event-path]');
285
- console.error(' GITHUB_EVENT_PATH env var is used if event-path arg is omitted.');
286
- process.exit(1);
287
- }
288
-
289
- const event = JSON.parse(readFileSync(eventPath, 'utf-8'));
290
- const [owner, repo] = (process.env.GITHUB_REPOSITORY || 'unknown/unknown').split('/');
291
-
292
- const options = {
293
- configPath: process.env.BEADS_SYNC_CONFIG || undefined,
294
- mappingPath: process.env.BEADS_SYNC_MAPPING || '.github/beads-mapping.json',
295
- owner,
296
- repo,
297
- };
298
-
299
- // Validate action explicitly — only allow known actions
300
- const VALID_ACTIONS = ['opened', 'closed'];
301
- if (!VALID_ACTIONS.includes(action)) {
302
- console.error(`Unknown action: "${action}". Expected one of: ${VALID_ACTIONS.join(', ')}`);
303
- process.exit(1);
304
- }
305
-
306
- const handler = action === 'opened' ? handleOpened : handleClosed;
307
-
308
- Promise.resolve(handler(event, options))
309
- .then((result) => {
310
- console.log(JSON.stringify(result, null, 2));
311
-
312
- // Exit non-zero on logical failure (e.g., bdCreate returned null)
313
- if (result.success === false) {
314
- console.error(`Sync failed: ${result.reason || 'unknown'}`);
315
- process.exit(1);
316
- }
317
-
318
- // Write to GITHUB_OUTPUT if available
319
- const outputPath = process.env.GITHUB_OUTPUT;
320
- if (outputPath) {
321
- for (const [key, value] of Object.entries(result)) {
322
- if (value != null) {
323
- appendFileSync(outputPath, `${key}=${value}\n`);
324
- }
325
- }
326
- }
327
- })
328
- .catch((err) => {
329
- console.error('Fatal:', err.message);
330
- process.exit(1);
331
- });
332
- }
@@ -1,54 +0,0 @@
1
- /**
2
- * Maps GitHub issue labels to Beads type and priority.
3
- *
4
- * @param {Array<string|{name: string}>} labels - GitHub labels (strings or objects)
5
- * @param {object} config - Mapping configuration
6
- * @param {Record<string, string>} config.labelToType - Label name to Beads type
7
- * @param {Record<string, number>} config.labelToPriority - Label name to priority number
8
- * @param {string} [config.defaultType="task"] - Fallback type
9
- * @param {number} [config.defaultPriority=2] - Fallback priority
10
- * @returns {{ type: string, priority: number }}
11
- */
12
- export function mapLabels(labels, config) {
13
- const {
14
- defaultType = 'task',
15
- defaultPriority = 2,
16
- } = config;
17
- const labelToType = (config.labelToType && typeof config.labelToType === 'object' && !Array.isArray(config.labelToType)) ? config.labelToType : {};
18
- const labelToPriority = (config.labelToPriority && typeof config.labelToPriority === 'object' && !Array.isArray(config.labelToPriority)) ? config.labelToPriority : {};
19
-
20
- // Normalize labels to lowercase strings
21
- const names = labels.map((l) =>
22
- (typeof l === 'string' ? l : l.name).toLowerCase()
23
- );
24
-
25
- // Build lowercase lookup maps
26
- const typeLookup = Object.create(null);
27
- for (const [key, value] of Object.entries(labelToType)) {
28
- typeLookup[key.toLowerCase()] = value;
29
- }
30
-
31
- const priorityLookup = Object.create(null);
32
- for (const [key, value] of Object.entries(labelToPriority)) {
33
- priorityLookup[key.toLowerCase()] = value;
34
- }
35
-
36
- // First match wins
37
- let type = defaultType;
38
- for (const name of names) {
39
- if (name in typeLookup) {
40
- type = typeLookup[name];
41
- break;
42
- }
43
- }
44
-
45
- let priority = defaultPriority;
46
- for (const name of names) {
47
- if (name in priorityLookup) {
48
- priority = priorityLookup[name];
49
- break;
50
- }
51
- }
52
-
53
- return { type, priority };
54
- }