forge-workflow 0.0.10 → 0.1.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (454) hide show
  1. package/.claude/rules/{greptile-review-process.md → review-process.md} +56 -41
  2. package/.claude/scripts/{greptile-resolve.sh → review-resolve.sh} +13 -3
  3. package/.cursor/rules/permissions-guidance.mdc +2 -2
  4. package/.forge/hooks/check-tdd.js +3 -0
  5. package/.forge/hooks/forge-native-hook.js +245 -0
  6. package/.forge/protected-paths.yaml +157 -0
  7. package/AGENTS.md +150 -61
  8. package/CHANGELOG.md +681 -0
  9. package/CLAUDE.md +9 -118
  10. package/QUICKSTART.md +171 -0
  11. package/README.md +271 -363
  12. package/bin/forge-cmd.js +120 -9
  13. package/bin/forge-preflight.js +26 -5
  14. package/bin/forge.js +461 -489
  15. package/docs/INDEX.md +93 -0
  16. package/docs/PROJECT_DESIGN.md +685 -0
  17. package/docs/architecture/index.md +66 -0
  18. package/docs/architecture/notes/README.md +35 -0
  19. package/docs/architecture/subsystems/README.md +46 -0
  20. package/docs/forge/TOOLCHAIN.md +670 -0
  21. package/docs/forge/VALIDATION.md +82 -0
  22. package/docs/{AGENT_INSTALL_PROMPT.md → guides/AGENT_INSTALL_PROMPT.md} +3 -3
  23. package/docs/guides/BEADS_GITHUB_SYNC.md +32 -0
  24. package/docs/{ENHANCED_ONBOARDING.md → guides/ENHANCED_ONBOARDING.md} +16 -12
  25. package/docs/guides/GREPTILE_SETUP.md +46 -0
  26. package/docs/guides/MANUAL_REVIEW_GUIDE.md +58 -0
  27. package/docs/guides/MIGRATION.md +56 -0
  28. package/docs/guides/SETUP.md +118 -0
  29. package/docs/guides/SUPPORT.md +185 -0
  30. package/docs/guides/WORKFLOW_TEMPLATES.md +74 -0
  31. package/docs/guides/memory-backends.md +183 -0
  32. package/docs/reference/ADAPTERS.md +128 -0
  33. package/docs/reference/AGENT_SKILL_PARITY.md +175 -0
  34. package/docs/reference/COMMANDS.md +205 -0
  35. package/docs/reference/DECISION_DRIFT_GUARDS.md +97 -0
  36. package/docs/{EXAMPLES.md → reference/EXAMPLES.md} +7 -5
  37. package/docs/reference/FORGE_KERNEL_STORAGE_MODEL.md +135 -0
  38. package/docs/reference/HERMES_INTEGRATION.md +118 -0
  39. package/docs/reference/INSIGHTS_RECAP.md +63 -0
  40. package/docs/reference/INSTALL.md +164 -0
  41. package/docs/reference/KERNEL_TAXONOMY_VALIDATION.md +161 -0
  42. package/docs/reference/PROTECTED_PATH_MANIFEST.md +25 -0
  43. package/docs/reference/RELEASE.md +68 -0
  44. package/docs/reference/RESEARCH_TEMPLATE.md +292 -0
  45. package/docs/{ROADMAP.md → reference/ROADMAP.md} +12 -9
  46. package/docs/reference/SKILLS.md +35 -0
  47. package/docs/reference/STATUS_BOARD.md +80 -0
  48. package/docs/reference/TEMPLATES.md +106 -0
  49. package/docs/{TOOLCHAIN.md → reference/TOOLCHAIN.md} +62 -47
  50. package/docs/reference/VALIDATION.md +82 -0
  51. package/docs/reference/agent-permissions.md +169 -0
  52. package/docs/reference/beads-to-kernel-migration-ux.md +61 -0
  53. package/docs/reference/control-plane-guarantees.md +125 -0
  54. package/docs/reference/dependency-chain.md +331 -0
  55. package/docs/reference/forge-kernel-issue-command-contract.md +161 -0
  56. package/docs/reference/forge-kernel-schema.md +72 -0
  57. package/docs/reference/kernel-conflict-evaluators.md +27 -0
  58. package/docs/reference/patch-md-format.md +77 -0
  59. package/docs/reference/protected-state-surfaces.md +59 -0
  60. package/docs/reference/shepherd.md +115 -0
  61. package/docs/reference/superpowers-analysis.md +320 -0
  62. package/docs/reference/superpowers-integration-options.md +404 -0
  63. package/docs/reference/test-environment.md +519 -0
  64. package/docs/reference/upgrade-safety.md +59 -0
  65. package/lefthook.yml +18 -0
  66. package/lib/adapter-cli.js +307 -0
  67. package/lib/adapters/beads-issue-adapter.js +127 -0
  68. package/lib/adapters/beads-kernel-compat.js +1042 -0
  69. package/lib/adapters/greptile-review-adapter.js +141 -0
  70. package/lib/adapters/kernel-issue-adapter.js +101 -0
  71. package/lib/adapters/pr-state-adapter.js +484 -0
  72. package/lib/adoption-profiles.js +126 -0
  73. package/lib/agents/README.md +2 -6
  74. package/lib/agents/claude.plugin.json +3 -8
  75. package/lib/agents/codex.plugin.json +9 -1
  76. package/lib/agents/cursor.plugin.json +2 -6
  77. package/lib/agents/hermes.plugin.json +22 -0
  78. package/lib/agents-config.js +39 -1236
  79. package/lib/audit-evidence.js +282 -0
  80. package/lib/beads-setup.js +121 -0
  81. package/lib/beads-sync-scaffold.js +25 -101
  82. package/lib/codex-skills.js +51 -1
  83. package/lib/commands/_issue.js +741 -77
  84. package/lib/commands/_manifest.js +91 -0
  85. package/lib/commands/_registry.js +85 -34
  86. package/lib/commands/_resolve-command-opts.js +261 -0
  87. package/lib/commands/_serve-security.js +270 -0
  88. package/lib/commands/adapter.js +12 -0
  89. package/lib/commands/add.js +118 -0
  90. package/lib/commands/audit.js +70 -0
  91. package/lib/commands/blocked.js +5 -0
  92. package/lib/commands/board.js +64 -0
  93. package/lib/commands/claim.js +21 -2
  94. package/lib/commands/claims.js +7 -0
  95. package/lib/commands/clean.js +485 -75
  96. package/lib/commands/close.js +2 -2
  97. package/lib/commands/comment.js +5 -0
  98. package/lib/commands/control.js +148 -0
  99. package/lib/commands/create.js +2 -2
  100. package/lib/commands/dev.js +185 -7
  101. package/lib/commands/doc-gate.js +336 -0
  102. package/lib/commands/doctor.js +156 -0
  103. package/lib/commands/explain.js +15 -0
  104. package/lib/commands/export.js +237 -0
  105. package/lib/commands/gate.js +192 -0
  106. package/lib/commands/hooks.js +242 -0
  107. package/lib/commands/inbox.js +118 -0
  108. package/lib/commands/init.js +598 -0
  109. package/lib/commands/insights.js +79 -0
  110. package/lib/commands/issue.js +12 -1
  111. package/lib/commands/issues.js +17 -0
  112. package/lib/commands/lint.js +5 -0
  113. package/lib/commands/list.js +2 -2
  114. package/lib/commands/merge.js +312 -0
  115. package/lib/commands/migrate.js +523 -0
  116. package/lib/commands/new.js +12 -0
  117. package/lib/commands/options.js +241 -0
  118. package/lib/commands/orient.js +13 -0
  119. package/lib/commands/orphans.js +5 -0
  120. package/lib/commands/patch.js +67 -0
  121. package/lib/commands/plan.js +436 -24
  122. package/lib/commands/preflight.js +211 -0
  123. package/lib/commands/prime.js +13 -0
  124. package/lib/commands/push.js +69 -2
  125. package/lib/commands/ready.js +2 -2
  126. package/lib/commands/recall.js +116 -0
  127. package/lib/commands/recap.js +61 -0
  128. package/lib/commands/recommend.js +0 -1
  129. package/lib/commands/release.js +91 -0
  130. package/lib/commands/remember.js +74 -0
  131. package/lib/commands/role.js +99 -0
  132. package/lib/commands/serve.js +581 -0
  133. package/lib/commands/setup.js +838 -972
  134. package/lib/commands/shepherd.js +436 -0
  135. package/lib/commands/ship.js +23 -1
  136. package/lib/commands/show.js +2 -2
  137. package/lib/commands/stage.js +192 -0
  138. package/lib/commands/stale.js +5 -0
  139. package/lib/commands/status.js +158 -21
  140. package/lib/commands/sync.js +34 -46
  141. package/lib/commands/team.js +4 -1
  142. package/lib/commands/test.js +43 -27
  143. package/lib/commands/update.js +2 -2
  144. package/lib/commands/upgrade.js +47 -0
  145. package/lib/commands/validate.js +43 -18
  146. package/lib/commands/worktree.js +307 -100
  147. package/lib/config-writer.js +202 -0
  148. package/lib/control-plane.js +236 -0
  149. package/lib/core/runtime-graph.js +946 -0
  150. package/lib/dep-guard/keyword-ripple.js +2 -2
  151. package/lib/deprecated-sync-cleanup.js +362 -0
  152. package/lib/detect-agent.js +2 -28
  153. package/lib/detect-worktree.js +35 -9
  154. package/lib/doc-gate/declaration.js +177 -0
  155. package/lib/doc-gate/detect.js +289 -0
  156. package/lib/doc-gate/gate.js +375 -0
  157. package/lib/doc-gate/okf-config.js +128 -0
  158. package/lib/doc-gate/okf.js +429 -0
  159. package/lib/docs-command.js +1161 -6
  160. package/lib/forge-issues.js +382 -11
  161. package/lib/forge-lock.js +262 -0
  162. package/lib/gate-events.js +193 -0
  163. package/lib/global-flags.js +74 -0
  164. package/lib/greptile-match.js +7 -63
  165. package/lib/harness-capability-matrix.js +380 -0
  166. package/lib/hook-global-installer.js +347 -0
  167. package/lib/hook-renderer.js +451 -0
  168. package/lib/inbox.js +391 -0
  169. package/lib/insights.js +397 -0
  170. package/lib/issue-adapter.js +156 -0
  171. package/lib/issue-backend.js +145 -0
  172. package/lib/issue-render.js +220 -0
  173. package/lib/kernel/backing-issue.js +305 -0
  174. package/lib/kernel/broker.js +1218 -0
  175. package/lib/kernel/cli-broker-factory.js +130 -0
  176. package/lib/kernel/conflict-signal.js +82 -0
  177. package/lib/kernel/evaluators.js +195 -0
  178. package/lib/kernel/fs-class.js +495 -0
  179. package/lib/kernel/issue-command-contract.js +559 -0
  180. package/lib/kernel/issue-id-resolver.js +186 -0
  181. package/lib/kernel/lease-enforcer.js +158 -0
  182. package/lib/kernel/migrations.js +333 -0
  183. package/lib/kernel/planning-buckets-schema.js +109 -0
  184. package/lib/kernel/projection-jsonl-writer.js +450 -0
  185. package/lib/kernel/readiness-model.js +329 -0
  186. package/lib/kernel/schema.js +356 -0
  187. package/lib/kernel/sqlite-driver.js +2504 -0
  188. package/lib/kernel/taxonomy-validator.js +394 -0
  189. package/lib/lefthook-check.js +3 -2
  190. package/lib/lefthook-wiring.js +413 -0
  191. package/lib/mcp-config-renderer.js +288 -0
  192. package/lib/memory/graphiti-mcp.js +106 -0
  193. package/lib/memory/router.js +387 -0
  194. package/lib/memory/typed-api.js +102 -0
  195. package/lib/memory-digest.js +195 -0
  196. package/lib/merge-rules.js +395 -0
  197. package/lib/migrate-dry-run.js +466 -0
  198. package/lib/orientation.js +863 -0
  199. package/lib/package-manager-remediation.js +103 -0
  200. package/lib/package-root.js +381 -0
  201. package/lib/patch-intent.js +890 -0
  202. package/lib/plugin-catalog.js +3 -4
  203. package/lib/plugin-manager.js +0 -5
  204. package/lib/pr-bundle.js +186 -0
  205. package/lib/pr-monitor/differ.js +195 -0
  206. package/lib/pr-monitor/events.js +0 -0
  207. package/lib/pr-monitor/gather.js +124 -0
  208. package/lib/pr-monitor/journal.js +299 -0
  209. package/lib/pr-monitor/monitor.js +146 -0
  210. package/lib/pr-monitor/render-sticky.js +157 -0
  211. package/lib/pr-monitor/watch-lifecycle.js +95 -0
  212. package/lib/pr-monitor/watch.js +247 -0
  213. package/lib/pr-pull.js +1273 -0
  214. package/lib/pr-shepherd.js +494 -0
  215. package/lib/pr-state-validator.js +59 -0
  216. package/lib/preflight/gates.js +237 -0
  217. package/lib/preflight/runner.js +116 -0
  218. package/lib/project-discovery.js +0 -53
  219. package/lib/project-memory.js +99 -497
  220. package/lib/protected-path-manifest.js +281 -0
  221. package/lib/protected-state-surfaces.js +387 -0
  222. package/lib/release-readiness.js +2089 -0
  223. package/lib/reset.js +59 -45
  224. package/lib/review-adapter.js +68 -0
  225. package/lib/rules-sync.js +260 -0
  226. package/lib/runtime-health.js +241 -20
  227. package/lib/safety-config-renderer.js +268 -0
  228. package/lib/setup-action-log.js +1 -7
  229. package/lib/setup.js +27 -65
  230. package/lib/shell-utils.js +76 -6
  231. package/lib/skills-sync.js +330 -0
  232. package/lib/smart-status/scoring.js +17 -3
  233. package/lib/status/beads-snapshot.js +45 -2
  234. package/lib/status/presenter.js +169 -18
  235. package/lib/status/snapshot.js +186 -0
  236. package/lib/sync-backend.js +202 -0
  237. package/lib/untrusted-content.js +52 -0
  238. package/lib/upgrade-safety.js +199 -0
  239. package/lib/workflow/enforce-stage.js +296 -47
  240. package/lib/workflow/stage-transition.js +115 -0
  241. package/lib/workflow/stages.js +30 -6
  242. package/lib/workflow/state-manager.js +11 -22
  243. package/lib/workflow/state.js +23 -1
  244. package/lib/workflow-profiles.js +17 -5
  245. package/package.json +37 -35
  246. package/rules/documentation.md +19 -0
  247. package/rules/kernel-tracking.md +26 -0
  248. package/rules/security.md +22 -0
  249. package/rules/tdd.md +20 -0
  250. package/rules/workflow.md +27 -0
  251. package/scripts/auto-backing-issue.js +47 -0
  252. package/scripts/beads-context.sh +81 -57
  253. package/scripts/beads-upgrade-smoke.sh +24 -3
  254. package/scripts/bootstrap-windows-tools.sh +78 -0
  255. package/scripts/branch-protection.js +2 -3
  256. package/scripts/check-agents.js +34 -137
  257. package/scripts/commitlint.js +3 -1
  258. package/scripts/conflict-detect.sh +3 -0
  259. package/scripts/dep-guard.sh +22 -3
  260. package/scripts/file-index.sh +3 -0
  261. package/scripts/forge-team/lib/claim.sh +34 -18
  262. package/scripts/forge-team/lib/dashboard.sh +61 -86
  263. package/scripts/forge-team/lib/epic.sh +99 -263
  264. package/scripts/forge-team/lib/hooks.sh +26 -28
  265. package/scripts/forge-team/lib/identity.sh +4 -4
  266. package/scripts/forge-team/lib/sync-github.sh +49 -84
  267. package/scripts/forge-team/lib/verify.sh +93 -83
  268. package/scripts/forge-team/lib/workload.sh +41 -65
  269. package/scripts/forge-team/tests/claim.test.sh +25 -19
  270. package/scripts/forge-team/tests/dashboard.test.sh +31 -46
  271. package/scripts/forge-team/tests/epic.test.sh +52 -71
  272. package/scripts/forge-team/tests/hooks.test.sh +38 -50
  273. package/scripts/forge-team/tests/identity.test.sh +3 -3
  274. package/scripts/forge-team/tests/integration.test.sh +44 -66
  275. package/scripts/forge-team/tests/sync-github.test.sh +50 -83
  276. package/scripts/forge-team/tests/verify.test.sh +37 -46
  277. package/scripts/forge-team/tests/workflow-integration.test.sh +4 -4
  278. package/scripts/forge-team/tests/workload.test.sh +32 -66
  279. package/scripts/gen-command-manifest.js +153 -0
  280. package/scripts/gen-embedded-assets.mjs +129 -0
  281. package/scripts/install.ps1 +139 -0
  282. package/scripts/install.sh +268 -0
  283. package/scripts/lib/release-asset.mjs +84 -0
  284. package/scripts/parity-check.mjs +145 -0
  285. package/scripts/parity-check.test.mjs +58 -0
  286. package/scripts/pin-agentic-workflow-images.js +112 -0
  287. package/scripts/pr-coordinator.sh +3 -0
  288. package/scripts/preflight-sonar.eslint.config.mjs +44 -0
  289. package/scripts/preflight.sh +21 -94
  290. package/scripts/protected-state-check.js +104 -0
  291. package/scripts/smart-status.sh +60 -57
  292. package/scripts/spikes/config-race-bench.js +111 -0
  293. package/scripts/spikes/harness-capability-matrix.js +13 -0
  294. package/scripts/spikes/patch-anchor-stability-bench.js +125 -0
  295. package/scripts/spikes/protected-path-manifest.js +20 -0
  296. package/scripts/spikes/skill-auto-invoke-parity.js +292 -0
  297. package/scripts/sync-agent-skills.js +62 -0
  298. package/scripts/sync-utils.sh +3 -0
  299. package/scripts/test-ci-shard.js +13 -6
  300. package/scripts/test.js +95 -12
  301. package/skills/claim-safety/SKILL.md +102 -0
  302. package/skills/claim-safety/evals/evals.json +46 -0
  303. package/{.github/prompts/dev.prompt.md → skills/dev/SKILL.md} +44 -50
  304. package/skills/dev/evals/evals.json +50 -0
  305. package/skills/hermes-forge/SKILL.md +185 -0
  306. package/skills/hermes-forge/evals/evals.json +46 -0
  307. package/skills/issue-basics/SKILL.md +111 -0
  308. package/skills/issue-basics/evals/evals.json +46 -0
  309. package/skills/kernel/SKILL.md +166 -0
  310. package/skills/kernel/evals/evals.json +50 -0
  311. package/skills/memory/SKILL.md +102 -0
  312. package/skills/parallel-deep-research/SKILL.md +14 -11
  313. package/skills/parallel-deep-research/evals/evals.json +11 -27
  314. package/{.github/prompts/plan.prompt.md → skills/plan/SKILL.md} +132 -157
  315. package/skills/plan/evals/evals.json +42 -0
  316. package/skills/research/SKILL.md +195 -0
  317. package/skills/research/evals/evals.json +42 -0
  318. package/{.github/prompts/review.prompt.md → skills/review/SKILL.md} +98 -62
  319. package/skills/review/evals/evals.json +42 -0
  320. package/skills/rollback/SKILL.md +110 -0
  321. package/skills/rollback/evals/evals.json +46 -0
  322. package/skills/rollback/references/methods.md +204 -0
  323. package/{.cursor/commands/rollback.md → skills/rollback/references/workflow-integration.md} +10 -284
  324. package/skills/shepherd/SKILL.md +66 -0
  325. package/skills/shepherd/evals/evals.json +42 -0
  326. package/{.github/prompts/ship.prompt.md → skills/ship/SKILL.md} +81 -45
  327. package/skills/ship/evals/evals.json +42 -0
  328. package/skills/smith/SKILL.md +142 -0
  329. package/skills/smith/evals/evals.json +46 -0
  330. package/skills/smith/references/autonomy-and-gates.md +94 -0
  331. package/{.github/prompts/sonarcloud.prompt.md → skills/sonarcloud/SKILL.md} +14 -3
  332. package/skills/sonarcloud/evals/evals.json +46 -0
  333. package/skills/sonarcloud-analysis/SKILL.md +18 -13
  334. package/skills/sonarcloud-analysis/evals/evals.json +11 -15
  335. package/{.github/prompts/status.prompt.md → skills/status/SKILL.md} +20 -10
  336. package/skills/status/evals/evals.json +50 -0
  337. package/skills/triage-ready/SKILL.md +121 -0
  338. package/skills/triage-ready/evals/evals.json +42 -0
  339. package/{.github/prompts/validate.prompt.md → skills/validate/SKILL.md} +52 -29
  340. package/skills/validate/evals/evals.json +42 -0
  341. package/skills/verify/SKILL.md +299 -0
  342. package/skills/verify/evals/evals.json +50 -0
  343. package/.claude/commands/dev.md +0 -345
  344. package/.claude/commands/plan.md +0 -566
  345. package/.claude/commands/premerge.md +0 -186
  346. package/.claude/commands/research.md +0 -42
  347. package/.claude/commands/review.md +0 -451
  348. package/.claude/commands/rollback.md +0 -721
  349. package/.claude/commands/ship.md +0 -213
  350. package/.claude/commands/sonarcloud.md +0 -152
  351. package/.claude/commands/status.md +0 -90
  352. package/.claude/commands/validate.md +0 -288
  353. package/.claude/commands/verify.md +0 -269
  354. package/.claude/rules/workflow.md +0 -121
  355. package/.cline/workflows/dev.md +0 -342
  356. package/.cline/workflows/plan.md +0 -563
  357. package/.cline/workflows/premerge.md +0 -183
  358. package/.cline/workflows/research.md +0 -39
  359. package/.cline/workflows/review.md +0 -448
  360. package/.cline/workflows/rollback.md +0 -718
  361. package/.cline/workflows/ship.md +0 -210
  362. package/.cline/workflows/sonarcloud.md +0 -146
  363. package/.cline/workflows/status.md +0 -87
  364. package/.cline/workflows/validate.md +0 -285
  365. package/.cline/workflows/verify.md +0 -266
  366. package/.codex/config.toml +0 -11
  367. package/.codex/skills/dev/SKILL.md +0 -345
  368. package/.codex/skills/plan/SKILL.md +0 -566
  369. package/.codex/skills/premerge/SKILL.md +0 -186
  370. package/.codex/skills/research/SKILL.md +0 -42
  371. package/.codex/skills/review/SKILL.md +0 -451
  372. package/.codex/skills/rollback/SKILL.md +0 -721
  373. package/.codex/skills/ship/SKILL.md +0 -213
  374. package/.codex/skills/sonarcloud/SKILL.md +0 -149
  375. package/.codex/skills/status/SKILL.md +0 -90
  376. package/.codex/skills/validate/SKILL.md +0 -288
  377. package/.codex/skills/verify/SKILL.md +0 -269
  378. package/.cursor/commands/dev.md +0 -342
  379. package/.cursor/commands/plan.md +0 -563
  380. package/.cursor/commands/premerge.md +0 -183
  381. package/.cursor/commands/research.md +0 -39
  382. package/.cursor/commands/review.md +0 -448
  383. package/.cursor/commands/ship.md +0 -210
  384. package/.cursor/commands/sonarcloud.md +0 -146
  385. package/.cursor/commands/status.md +0 -87
  386. package/.cursor/commands/validate.md +0 -285
  387. package/.cursor/commands/verify.md +0 -266
  388. package/.cursorrules +0 -149
  389. package/.github/prompts/premerge.prompt.md +0 -188
  390. package/.github/prompts/research.prompt.md +0 -44
  391. package/.github/prompts/rollback.prompt.md +0 -723
  392. package/.github/prompts/verify.prompt.md +0 -271
  393. package/.github/workflows/beads-to-github.yml +0 -89
  394. package/.github/workflows/github-to-beads.yml +0 -100
  395. package/.kilocode/workflows/dev.md +0 -346
  396. package/.kilocode/workflows/plan.md +0 -567
  397. package/.kilocode/workflows/premerge.md +0 -187
  398. package/.kilocode/workflows/research.md +0 -43
  399. package/.kilocode/workflows/review.md +0 -452
  400. package/.kilocode/workflows/rollback.md +0 -722
  401. package/.kilocode/workflows/ship.md +0 -214
  402. package/.kilocode/workflows/sonarcloud.md +0 -150
  403. package/.kilocode/workflows/status.md +0 -91
  404. package/.kilocode/workflows/validate.md +0 -289
  405. package/.kilocode/workflows/verify.md +0 -270
  406. package/.opencode/commands/dev.md +0 -345
  407. package/.opencode/commands/plan.md +0 -566
  408. package/.opencode/commands/premerge.md +0 -186
  409. package/.opencode/commands/research.md +0 -42
  410. package/.opencode/commands/review.md +0 -451
  411. package/.opencode/commands/rollback.md +0 -721
  412. package/.opencode/commands/ship.md +0 -213
  413. package/.opencode/commands/sonarcloud.md +0 -149
  414. package/.opencode/commands/status.md +0 -90
  415. package/.opencode/commands/validate.md +0 -288
  416. package/.opencode/commands/verify.md +0 -269
  417. package/.roo/commands/dev.md +0 -346
  418. package/.roo/commands/plan.md +0 -567
  419. package/.roo/commands/premerge.md +0 -187
  420. package/.roo/commands/research.md +0 -43
  421. package/.roo/commands/review.md +0 -452
  422. package/.roo/commands/rollback.md +0 -722
  423. package/.roo/commands/ship.md +0 -214
  424. package/.roo/commands/sonarcloud.md +0 -150
  425. package/.roo/commands/status.md +0 -91
  426. package/.roo/commands/validate.md +0 -289
  427. package/.roo/commands/verify.md +0 -270
  428. package/docs/BEADS_GITHUB_SYNC.md +0 -281
  429. package/docs/GREPTILE_SETUP.md +0 -400
  430. package/docs/MANUAL_REVIEW_GUIDE.md +0 -106
  431. package/docs/SETUP.md +0 -663
  432. package/docs/VALIDATION.md +0 -363
  433. package/lib/agents/cline.plugin.json +0 -29
  434. package/lib/agents/copilot.plugin.json +0 -24
  435. package/lib/agents/kilocode.plugin.json +0 -22
  436. package/lib/agents/opencode.plugin.json +0 -23
  437. package/lib/agents/roo.plugin.json +0 -30
  438. package/lib/beads-bootstrap.js +0 -225
  439. package/lib/beads-health-check.js +0 -188
  440. package/lib/commands/commands-reset.js +0 -147
  441. package/opencode.json +0 -67
  442. package/scripts/beads-context.test.js +0 -584
  443. package/scripts/github-beads-sync/comment.mjs +0 -64
  444. package/scripts/github-beads-sync/config.mjs +0 -148
  445. package/scripts/github-beads-sync/github-api.mjs +0 -131
  446. package/scripts/github-beads-sync/index.mjs +0 -356
  447. package/scripts/github-beads-sync/label-mapper.mjs +0 -54
  448. package/scripts/github-beads-sync/mapping.mjs +0 -132
  449. package/scripts/github-beads-sync/reverse-sync-cli.mjs +0 -31
  450. package/scripts/github-beads-sync/reverse-sync.mjs +0 -162
  451. package/scripts/github-beads-sync/run-bd.mjs +0 -161
  452. package/scripts/github-beads-sync/sanitize.mjs +0 -121
  453. package/scripts/github-beads-sync.config.json +0 -26
  454. package/scripts/sync-commands.js +0 -600
@@ -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,356 +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 { resolveCanonicalBeadsLink, upsertCanonicalBeadsLink } from './mapping.mjs';
14
- import { bdCreate as realBdCreate, bdClose as realBdClose, bdShow as realBdShow } from './run-bd.mjs';
15
- import { buildComment, parseComment } from './comment.mjs';
16
- import { createOrEditComment as realCreateOrEditComment, findSyncComment as realFindSyncComment } from './github-api.mjs';
17
-
18
- const DEFAULT_MAPPING_PATH = '.github/beads-mapping.json';
19
-
20
- function isBot(login) {
21
- if (!login) return false;
22
- return login.includes('[bot]') || login === 'github-actions';
23
- }
24
-
25
- function hasSkipLabel(labels) {
26
- if (!labels) return false;
27
- return labels.some((l) => {
28
- const name = typeof l === 'string' ? l : l.name;
29
- return name === 'skip-beads-sync';
30
- });
31
- }
32
-
33
- function getGitHubLink(issue = {}) {
34
- return {
35
- nodeId: issue.node_id ?? issue.nodeId ?? null,
36
- number: issue.number ?? null,
37
- url: issue.html_url ?? null,
38
- };
39
- }
40
-
41
- function createCanonicalLinkStore(mappingPath) {
42
- return {
43
- resolveCanonicalLink(lookup) {
44
- return resolveCanonicalBeadsLink(mappingPath, lookup);
45
- },
46
- upsertCanonicalLink(link) {
47
- return upsertCanonicalBeadsLink(mappingPath, link);
48
- },
49
- };
50
- }
51
-
52
- function getCanonicalLinkStore(options = {}) {
53
- const defaultStore = createCanonicalLinkStore(options.mappingPath ?? DEFAULT_MAPPING_PATH);
54
-
55
- if (
56
- options.linkStore &&
57
- typeof options.linkStore.resolveCanonicalLink === 'function' &&
58
- typeof options.linkStore.upsertCanonicalLink === 'function'
59
- ) {
60
- return options.linkStore;
61
- }
62
-
63
- return defaultStore;
64
- }
65
-
66
- /**
67
- * Handle a GitHub issue "opened" event.
68
- *
69
- * @param {object} event - Parsed GitHub webhook payload
70
- * @param {object} options
71
- * @param {string} [options.configPath] - Path to config JSON
72
- * @param {string} options.mappingPath - Path to mapping JSON
73
- * @param {string} options.owner - Repository owner
74
- * @param {string} options.repo - Repository name
75
- * @param {object} [options.bd] - Dependency injection for bd functions
76
- * @param {object} [options.github] - Dependency injection for github-api functions
77
- * @param {object} [options.linkStore] - Dependency injection for canonical link store
78
- * @param {object} [options.configOverride] - Merge into loaded config (for testing)
79
- * @returns {object} Result object
80
- */
81
- export function handleOpened(event, options = {}) {
82
- const {
83
- configPath,
84
- owner,
85
- repo,
86
- bd = {},
87
- github = {},
88
- configOverride,
89
- } = options;
90
-
91
- const bdCreate = bd.bdCreate ?? realBdCreate;
92
- const createOrEditComment = github.createOrEditComment ?? realCreateOrEditComment;
93
- const findSyncComment = github.findSyncComment ?? realFindSyncComment;
94
- const canonicalLinkStore = getCanonicalLinkStore(options);
95
-
96
- let config = loadConfig(configPath);
97
- if (configOverride) {
98
- config = { ...config, ...configOverride };
99
- }
100
-
101
- const issue = event.issue;
102
- const issueNumber = issue.number;
103
- const rawTitle = issue.title;
104
- const labels = issue.labels || [];
105
- const assignee = config.mapAssignee ? issue.assignee?.login : undefined;
106
- const htmlUrl = issue.html_url;
107
- const body = issue.body ?? '';
108
- const authorAssociation = issue.author_association;
109
- const rawLabelNames = labels.map((l) => (typeof l === 'string' ? l : l.name));
110
- const { type, priority } = mapLabels(rawLabelNames, config);
111
- const externalRef = `gh-${issueNumber}`;
112
-
113
- if (isBot(event.sender?.login)) {
114
- return { skipped: true, reason: 'bot actor' };
115
- }
116
-
117
- if (hasSkipLabel(labels)) {
118
- return { skipped: true, reason: 'skip label' };
119
- }
120
-
121
- if (body.includes('no-beads')) {
122
- return { skipped: true, reason: 'no-beads in body' };
123
- }
124
-
125
- if (config.publicRepoGate === 'author_association') {
126
- const allowed = config.gateAssociations || [];
127
- if (!allowed.includes(authorAssociation)) {
128
- return { skipped: true, reason: 'author not authorized' };
129
- }
130
- } else if (config.publicRepoGate === 'label') {
131
- const gateLabelName = config.gateLabelName || 'beads-track';
132
- const hasGateLabel = labels.some((l) => {
133
- const name = typeof l === 'string' ? l : l.name;
134
- return name === gateLabelName;
135
- });
136
- if (!hasGateLabel) {
137
- return { skipped: true, reason: `missing required label: ${gateLabelName}` };
138
- }
139
- }
140
-
141
- const canonicalLink = canonicalLinkStore.resolveCanonicalLink({
142
- githubNodeId: issue.node_id ?? issue.nodeId ?? null,
143
- githubNumber: issue.number,
144
- });
145
- if (canonicalLink) {
146
- const commentBody = buildComment(canonicalLink.forgeIssueId, issueNumber, {
147
- type,
148
- priority,
149
- externalRef,
150
- });
151
- createOrEditComment(owner, repo, issueNumber, commentBody);
152
- return {
153
- skipped: true,
154
- reason: 'already synced (canonical link)',
155
- beadsId: canonicalLink.forgeIssueId,
156
- };
157
- }
158
-
159
- const existingSyncComment = parseComment(findSyncComment(owner, repo, issueNumber)?.body);
160
- if (existingSyncComment?.beadsId) {
161
- canonicalLinkStore.upsertCanonicalLink({
162
- forgeIssueId: existingSyncComment.beadsId,
163
- github: getGitHubLink(issue),
164
- sources: [
165
- {
166
- source: 'syncComment',
167
- forgeIssueId: existingSyncComment.beadsId,
168
- githubNumber: issueNumber,
169
- url: htmlUrl,
170
- },
171
- ],
172
- diagnostics: [],
173
- });
174
- const commentBody = buildComment(existingSyncComment.beadsId, issueNumber, {
175
- type,
176
- priority,
177
- externalRef,
178
- });
179
- createOrEditComment(owner, repo, issueNumber, commentBody);
180
- return {
181
- skipped: true,
182
- reason: 'already synced (sync comment)',
183
- beadsId: existingSyncComment.beadsId,
184
- };
185
- }
186
-
187
- const { sanitized: sanitizedTitle, warnings: titleWarnings } = sanitizeTitle(rawTitle);
188
- if (titleWarnings.length) console.warn('sanitize:', titleWarnings);
189
- const beadsId = bdCreate({
190
- title: sanitizedTitle,
191
- type,
192
- priority,
193
- assignee,
194
- description: htmlUrl,
195
- externalRef,
196
- });
197
-
198
- if (!beadsId) {
199
- return { success: false, reason: 'bd create failed - no beads ID returned', issueNumber };
200
- }
201
-
202
- canonicalLinkStore.upsertCanonicalLink({
203
- forgeIssueId: beadsId,
204
- github: getGitHubLink(issue),
205
- sources: [
206
- {
207
- source: 'externalRef',
208
- forgeIssueId: beadsId,
209
- githubNumber: issueNumber,
210
- url: htmlUrl,
211
- },
212
- ],
213
- diagnostics: [],
214
- });
215
-
216
- const commentBody = buildComment(beadsId, issueNumber, { type, priority, externalRef });
217
- createOrEditComment(owner, repo, issueNumber, commentBody);
218
-
219
- return { success: true, beadsId, issueNumber };
220
- }
221
-
222
- /**
223
- * Handle a GitHub issue "closed" event.
224
- *
225
- * @param {object} event - Parsed GitHub webhook payload
226
- * @param {object} options
227
- * @param {string} options.mappingPath - Path to mapping JSON
228
- * @param {string} options.owner - Repository owner
229
- * @param {string} options.repo - Repository name
230
- * @param {object} [options.bd] - Dependency injection for bd functions
231
- * @param {object} [options.github] - Dependency injection for github-api functions
232
- * @param {object} [options.linkStore] - Dependency injection for canonical link store
233
- * @returns {object} Result object
234
- */
235
- export function handleClosed(event, options = {}) {
236
- const {
237
- bd = {},
238
- } = options;
239
-
240
- const bdClose = bd.bdClose ?? realBdClose;
241
- const bdShow = bd.bdShow ?? realBdShow;
242
- const findSyncComment = options.github?.findSyncComment ?? realFindSyncComment;
243
- const canonicalLinkStore = getCanonicalLinkStore(options);
244
-
245
- const issue = event.issue;
246
- const issueNumber = issue.number;
247
- const labels = issue.labels || [];
248
- const stateReason = issue.state_reason;
249
-
250
- if (isBot(event.sender?.login)) {
251
- return { skipped: true, reason: 'bot actor' };
252
- }
253
-
254
- if (hasSkipLabel(labels)) {
255
- return { skipped: true, reason: 'skip label' };
256
- }
257
-
258
- if (stateReason && stateReason !== 'completed') {
259
- return { skipped: true, reason: `closed as ${stateReason}` };
260
- }
261
-
262
- const canonicalLink = canonicalLinkStore.resolveCanonicalLink({
263
- githubNodeId: issue.node_id ?? issue.nodeId ?? null,
264
- githubNumber: issue.number,
265
- });
266
- let beadsId = canonicalLink?.forgeIssueId ?? null;
267
-
268
- if (!beadsId) {
269
- const syncCommentLink = parseComment(findSyncComment(options.owner, options.repo, issueNumber)?.body);
270
- if (syncCommentLink?.beadsId && syncCommentLink.issueNumber === issueNumber) {
271
- canonicalLinkStore.upsertCanonicalLink({
272
- forgeIssueId: syncCommentLink.beadsId,
273
- github: getGitHubLink(issue),
274
- sources: [
275
- {
276
- source: 'syncComment',
277
- forgeIssueId: syncCommentLink.beadsId,
278
- githubNumber: issueNumber,
279
- url: issue.html_url ?? null,
280
- },
281
- ],
282
- diagnostics: [],
283
- });
284
- beadsId = syncCommentLink.beadsId;
285
- }
286
- }
287
-
288
- if (!beadsId) {
289
- return { skipped: true, reason: 'no beads link found' };
290
- }
291
-
292
- const status = bdShow(beadsId);
293
- if (status === null) {
294
- return { skipped: true, reason: 'could not determine beads status' };
295
- }
296
- if (status === 'closed') {
297
- return { skipped: true, reason: 'already closed' };
298
- }
299
-
300
- bdClose(beadsId, `Closed via GitHub issue #${issueNumber}`);
301
-
302
- return { success: true, beadsId, issueNumber };
303
- }
304
-
305
- const __filename = fileURLToPath(import.meta.url);
306
- if (process.argv[1] === __filename) {
307
- const action = process.argv[2];
308
- const eventPath = process.env.GITHUB_EVENT_PATH || process.argv[3];
309
-
310
- if (!action || !eventPath) {
311
- console.error('Usage: node index.mjs <opened|closed> [event-path]');
312
- console.error(' GITHUB_EVENT_PATH env var is used if event-path arg is omitted.');
313
- process.exit(1);
314
- }
315
-
316
- const event = JSON.parse(readFileSync(eventPath, 'utf-8'));
317
- const [owner, repo] = (process.env.GITHUB_REPOSITORY || 'unknown/unknown').split('/');
318
-
319
- const options = {
320
- configPath: process.env.BEADS_SYNC_CONFIG || undefined,
321
- mappingPath: process.env.BEADS_SYNC_MAPPING || DEFAULT_MAPPING_PATH,
322
- owner,
323
- repo,
324
- };
325
-
326
- const VALID_ACTIONS = ['opened', 'closed'];
327
- if (!VALID_ACTIONS.includes(action)) {
328
- console.error(`Unknown action: "${action}". Expected one of: ${VALID_ACTIONS.join(', ')}`);
329
- process.exit(1);
330
- }
331
-
332
- const handler = action === 'opened' ? handleOpened : handleClosed;
333
-
334
- Promise.resolve(handler(event, options))
335
- .then((result) => {
336
- console.log(JSON.stringify(result, null, 2));
337
-
338
- if (result.success === false) {
339
- console.error(`Sync failed: ${result.reason || 'unknown'}`);
340
- process.exit(1);
341
- }
342
-
343
- const outputPath = process.env.GITHUB_OUTPUT;
344
- if (outputPath) {
345
- for (const [key, value] of Object.entries(result)) {
346
- if (value != null) {
347
- appendFileSync(outputPath, `${key}=${value}\n`);
348
- }
349
- }
350
- }
351
- })
352
- .catch((err) => {
353
- console.error('Fatal:', err.message);
354
- process.exit(1);
355
- });
356
- }
@@ -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
- }