forge-workflow 0.0.10 → 0.1.0-beta.3

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 (468) 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 +82 -5
  5. package/.forge/hooks/forge-native-hook.js +431 -0
  6. package/.forge/protected-paths.yaml +157 -0
  7. package/AGENTS.md +151 -61
  8. package/CHANGELOG.md +709 -0
  9. package/CLAUDE.md +9 -118
  10. package/QUICKSTART.md +175 -0
  11. package/README.md +275 -365
  12. package/bin/forge-cmd.js +120 -9
  13. package/bin/forge-preflight.js +26 -5
  14. package/bin/forge.js +532 -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 +121 -0
  29. package/docs/guides/SUPPORT.md +190 -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 +214 -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 +155 -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/activation/ensure-forge-home.js +135 -0
  67. package/lib/adapter-cli.js +307 -0
  68. package/lib/adapters/beads-issue-adapter.js +127 -0
  69. package/lib/adapters/beads-kernel-compat.js +1109 -0
  70. package/lib/adapters/greptile-review-adapter.js +141 -0
  71. package/lib/adapters/kernel-issue-adapter.js +101 -0
  72. package/lib/adapters/pr-state-adapter.js +484 -0
  73. package/lib/adoption-profiles.js +139 -0
  74. package/lib/agents/README.md +2 -6
  75. package/lib/agents/claude.plugin.json +3 -8
  76. package/lib/agents/codex.plugin.json +9 -1
  77. package/lib/agents/cursor.plugin.json +2 -6
  78. package/lib/agents/hermes.plugin.json +22 -0
  79. package/lib/agents-config.js +39 -1236
  80. package/lib/audit-evidence.js +282 -0
  81. package/lib/beads-detect.js +60 -0
  82. package/lib/beads-nudge.js +91 -0
  83. package/lib/beads-setup.js +121 -0
  84. package/lib/beads-sync-scaffold.js +25 -101
  85. package/lib/codex-skills.js +51 -1
  86. package/lib/commands/_aliases.js +248 -0
  87. package/lib/commands/_issue.js +780 -77
  88. package/lib/commands/_manifest.js +93 -0
  89. package/lib/commands/_registry.js +99 -34
  90. package/lib/commands/_resolve-command-opts.js +230 -0
  91. package/lib/commands/_serve-security.js +270 -0
  92. package/lib/commands/adapter.js +12 -0
  93. package/lib/commands/add.js +118 -0
  94. package/lib/commands/audit.js +70 -0
  95. package/lib/commands/blocked.js +5 -0
  96. package/lib/commands/board.js +64 -0
  97. package/lib/commands/claim.js +21 -2
  98. package/lib/commands/claims.js +7 -0
  99. package/lib/commands/clean.js +485 -75
  100. package/lib/commands/close.js +2 -2
  101. package/lib/commands/comment.js +5 -0
  102. package/lib/commands/control.js +148 -0
  103. package/lib/commands/create.js +2 -2
  104. package/lib/commands/dev.js +185 -7
  105. package/lib/commands/doc-gate.js +336 -0
  106. package/lib/commands/doctor.js +156 -0
  107. package/lib/commands/explain.js +15 -0
  108. package/lib/commands/export.js +237 -0
  109. package/lib/commands/gate.js +209 -0
  110. package/lib/commands/hooks.js +377 -0
  111. package/lib/commands/inbox.js +118 -0
  112. package/lib/commands/init.js +604 -0
  113. package/lib/commands/insights.js +79 -0
  114. package/lib/commands/issue.js +12 -1
  115. package/lib/commands/issues.js +17 -0
  116. package/lib/commands/lint.js +5 -0
  117. package/lib/commands/list.js +2 -2
  118. package/lib/commands/memory.js +81 -0
  119. package/lib/commands/merge.js +312 -0
  120. package/lib/commands/migrate.js +362 -0
  121. package/lib/commands/new.js +12 -0
  122. package/lib/commands/options.js +241 -0
  123. package/lib/commands/orient.js +13 -0
  124. package/lib/commands/orphans.js +5 -0
  125. package/lib/commands/patch.js +67 -0
  126. package/lib/commands/plan.js +481 -29
  127. package/lib/commands/pr.js +88 -0
  128. package/lib/commands/preflight.js +211 -0
  129. package/lib/commands/prime.js +13 -0
  130. package/lib/commands/push.js +135 -2
  131. package/lib/commands/ready.js +2 -2
  132. package/lib/commands/recall.js +171 -0
  133. package/lib/commands/recap.js +75 -0
  134. package/lib/commands/recommend.js +0 -1
  135. package/lib/commands/release.js +104 -0
  136. package/lib/commands/remember.js +140 -0
  137. package/lib/commands/role.js +99 -0
  138. package/lib/commands/serve.js +581 -0
  139. package/lib/commands/setup.js +900 -971
  140. package/lib/commands/shepherd.js +501 -0
  141. package/lib/commands/ship.js +59 -1
  142. package/lib/commands/show.js +2 -2
  143. package/lib/commands/stage.js +192 -0
  144. package/lib/commands/stale.js +5 -0
  145. package/lib/commands/status.js +158 -21
  146. package/lib/commands/sync.js +34 -46
  147. package/lib/commands/team.js +4 -1
  148. package/lib/commands/test.js +43 -27
  149. package/lib/commands/update.js +2 -2
  150. package/lib/commands/upgrade.js +47 -0
  151. package/lib/commands/validate.js +43 -18
  152. package/lib/commands/worktree.js +362 -99
  153. package/lib/config-writer.js +202 -0
  154. package/lib/control-plane.js +236 -0
  155. package/lib/core/runtime-graph.js +977 -0
  156. package/lib/dep-guard/keyword-ripple.js +2 -2
  157. package/lib/deprecated-sync-cleanup.js +362 -0
  158. package/lib/detect-agent.js +2 -28
  159. package/lib/detect-worktree.js +35 -9
  160. package/lib/doc-gate/declaration.js +177 -0
  161. package/lib/doc-gate/detect.js +289 -0
  162. package/lib/doc-gate/gate.js +375 -0
  163. package/lib/doc-gate/okf-config.js +128 -0
  164. package/lib/doc-gate/okf.js +429 -0
  165. package/lib/docs-command.js +1161 -6
  166. package/lib/forge-issues.js +382 -11
  167. package/lib/forge-lock.js +262 -0
  168. package/lib/gate-events.js +192 -0
  169. package/lib/global-flags.js +104 -0
  170. package/lib/greptile-match.js +7 -63
  171. package/lib/grounding/context-events.js +230 -0
  172. package/lib/grounding/read-first.js +112 -0
  173. package/lib/harness-capability-matrix.js +380 -0
  174. package/lib/hook-global-installer.js +347 -0
  175. package/lib/hook-renderer.js +541 -0
  176. package/lib/inbox.js +391 -0
  177. package/lib/insights.js +397 -0
  178. package/lib/issue-adapter.js +156 -0
  179. package/lib/issue-backend.js +145 -0
  180. package/lib/issue-render.js +220 -0
  181. package/lib/kernel/backing-issue.js +311 -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/owned-kernel.js +43 -0
  192. package/lib/kernel/planning-buckets-schema.js +109 -0
  193. package/lib/kernel/projection-jsonl-writer.js +450 -0
  194. package/lib/kernel/readiness-model.js +329 -0
  195. package/lib/kernel/schema.js +356 -0
  196. package/lib/kernel/sqlite-driver.js +2540 -0
  197. package/lib/kernel/taxonomy-validator.js +394 -0
  198. package/lib/lefthook-check.js +3 -2
  199. package/lib/lefthook-wiring.js +413 -0
  200. package/lib/mcp-config-renderer.js +288 -0
  201. package/lib/memory/graphiti-mcp.js +106 -0
  202. package/lib/memory/router.js +387 -0
  203. package/lib/memory/typed-api.js +102 -0
  204. package/lib/memory-digest.js +195 -0
  205. package/lib/merge-rules.js +395 -0
  206. package/lib/migrate-dry-run.js +466 -0
  207. package/lib/orientation.js +863 -0
  208. package/lib/package-manager-remediation.js +103 -0
  209. package/lib/package-root.js +381 -0
  210. package/lib/patch-intent.js +890 -0
  211. package/lib/plugin-catalog.js +3 -4
  212. package/lib/plugin-manager.js +0 -5
  213. package/lib/pr-bundle.js +186 -0
  214. package/lib/pr-monitor/auto-actions.js +175 -0
  215. package/lib/pr-monitor/differ.js +195 -0
  216. package/lib/pr-monitor/digest.js +206 -0
  217. package/lib/pr-monitor/events.js +0 -0
  218. package/lib/pr-monitor/gather.js +124 -0
  219. package/lib/pr-monitor/journal.js +299 -0
  220. package/lib/pr-monitor/monitor.js +146 -0
  221. package/lib/pr-monitor/render-sticky.js +192 -0
  222. package/lib/pr-monitor/upsert-sticky.js +169 -0
  223. package/lib/pr-monitor/watch-lifecycle.js +95 -0
  224. package/lib/pr-monitor/watch.js +247 -0
  225. package/lib/pr-pull.js +1314 -0
  226. package/lib/pr-shepherd.js +494 -0
  227. package/lib/pr-state-validator.js +59 -0
  228. package/lib/preflight/gates.js +237 -0
  229. package/lib/preflight/runner.js +116 -0
  230. package/lib/project-discovery.js +0 -53
  231. package/lib/project-memory.js +99 -497
  232. package/lib/protected-path-manifest.js +281 -0
  233. package/lib/protected-state-surfaces.js +387 -0
  234. package/lib/release-readiness.js +2105 -0
  235. package/lib/reset.js +59 -45
  236. package/lib/review-adapter.js +68 -0
  237. package/lib/rules-sync.js +260 -0
  238. package/lib/runtime-health.js +241 -20
  239. package/lib/safety-config-renderer.js +268 -0
  240. package/lib/setup-action-log.js +1 -7
  241. package/lib/setup.js +27 -65
  242. package/lib/shell-utils.js +76 -6
  243. package/lib/skills-sync.js +330 -0
  244. package/lib/smart-status/scoring.js +17 -3
  245. package/lib/status/beads-snapshot.js +45 -2
  246. package/lib/status/presenter.js +169 -18
  247. package/lib/status/snapshot.js +186 -0
  248. package/lib/sync-backend.js +202 -0
  249. package/lib/untrusted-content.js +52 -0
  250. package/lib/upgrade-safety.js +251 -0
  251. package/lib/workflow/enforce-stage.js +351 -45
  252. package/lib/workflow/stage-transition.js +115 -0
  253. package/lib/workflow/stages.js +30 -6
  254. package/lib/workflow/state-manager.js +11 -22
  255. package/lib/workflow/state.js +23 -1
  256. package/lib/workflow-profiles.js +17 -5
  257. package/package.json +37 -35
  258. package/rules/documentation.md +19 -0
  259. package/rules/kernel-tracking.md +26 -0
  260. package/rules/security.md +22 -0
  261. package/rules/tdd.md +20 -0
  262. package/rules/workflow.md +27 -0
  263. package/scripts/auto-backing-issue.js +47 -0
  264. package/scripts/beads-context.sh +81 -57
  265. package/scripts/beads-upgrade-smoke.sh +24 -3
  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.sh +22 -3
  272. package/scripts/file-index.sh +3 -0
  273. package/scripts/forge-team/lib/claim.sh +34 -18
  274. package/scripts/forge-team/lib/dashboard.sh +61 -86
  275. package/scripts/forge-team/lib/epic.sh +99 -263
  276. package/scripts/forge-team/lib/hooks.sh +26 -28
  277. package/scripts/forge-team/lib/identity.sh +4 -4
  278. package/scripts/forge-team/lib/sync-github.sh +49 -84
  279. package/scripts/forge-team/lib/verify.sh +93 -83
  280. package/scripts/forge-team/lib/workload.sh +41 -65
  281. package/scripts/forge-team/tests/claim.test.sh +25 -19
  282. package/scripts/forge-team/tests/dashboard.test.sh +31 -46
  283. package/scripts/forge-team/tests/epic.test.sh +52 -71
  284. package/scripts/forge-team/tests/hooks.test.sh +38 -50
  285. package/scripts/forge-team/tests/identity.test.sh +3 -3
  286. package/scripts/forge-team/tests/integration.test.sh +44 -66
  287. package/scripts/forge-team/tests/sync-github.test.sh +50 -83
  288. package/scripts/forge-team/tests/verify.test.sh +37 -46
  289. package/scripts/forge-team/tests/workflow-integration.test.sh +4 -4
  290. package/scripts/forge-team/tests/workload.test.sh +32 -66
  291. package/scripts/gen-command-manifest.js +153 -0
  292. package/scripts/gen-embedded-assets.mjs +129 -0
  293. package/scripts/install.ps1 +139 -0
  294. package/scripts/install.sh +268 -0
  295. package/scripts/lib/release-asset.mjs +84 -0
  296. package/scripts/parity-check.mjs +145 -0
  297. package/scripts/parity-check.test.mjs +58 -0
  298. package/scripts/pin-agentic-workflow-images.js +112 -0
  299. package/scripts/pr-auto-actions.js +93 -0
  300. package/scripts/pr-coordinator.sh +3 -0
  301. package/scripts/pr-verdict-label.js +50 -0
  302. package/scripts/preflight-sonar.eslint.config.mjs +44 -0
  303. package/scripts/preflight.sh +21 -94
  304. package/scripts/protected-state-check.js +104 -0
  305. package/scripts/smart-status.sh +60 -57
  306. package/scripts/spikes/config-race-bench.js +111 -0
  307. package/scripts/spikes/harness-capability-matrix.js +13 -0
  308. package/scripts/spikes/patch-anchor-stability-bench.js +125 -0
  309. package/scripts/spikes/protected-path-manifest.js +20 -0
  310. package/scripts/spikes/skill-auto-invoke-parity.js +292 -0
  311. package/scripts/sync-agent-skills.js +62 -0
  312. package/scripts/sync-utils.sh +3 -0
  313. package/scripts/test-ci-shard.js +13 -6
  314. package/scripts/test.js +95 -12
  315. package/skills/claim-safety/SKILL.md +102 -0
  316. package/skills/claim-safety/evals/evals.json +46 -0
  317. package/{.github/prompts/dev.prompt.md → skills/dev/SKILL.md} +44 -50
  318. package/skills/dev/evals/evals.json +50 -0
  319. package/skills/hermes-forge/SKILL.md +185 -0
  320. package/skills/hermes-forge/evals/evals.json +46 -0
  321. package/skills/issue-basics/SKILL.md +111 -0
  322. package/skills/issue-basics/evals/evals.json +46 -0
  323. package/skills/kernel/SKILL.md +166 -0
  324. package/skills/kernel/evals/evals.json +50 -0
  325. package/skills/memory/SKILL.md +102 -0
  326. package/skills/parallel-deep-research/SKILL.md +14 -11
  327. package/skills/parallel-deep-research/evals/evals.json +11 -27
  328. package/{.github/prompts/plan.prompt.md → skills/plan/SKILL.md} +132 -157
  329. package/skills/plan/evals/evals.json +42 -0
  330. package/skills/research/SKILL.md +195 -0
  331. package/skills/research/evals/evals.json +42 -0
  332. package/{.github/prompts/review.prompt.md → skills/review/SKILL.md} +98 -62
  333. package/skills/review/evals/evals.json +42 -0
  334. package/skills/rollback/SKILL.md +110 -0
  335. package/skills/rollback/evals/evals.json +46 -0
  336. package/skills/rollback/references/methods.md +204 -0
  337. package/{.cursor/commands/rollback.md → skills/rollback/references/workflow-integration.md} +10 -284
  338. package/skills/shepherd/SKILL.md +66 -0
  339. package/skills/shepherd/evals/evals.json +42 -0
  340. package/{.github/prompts/ship.prompt.md → skills/ship/SKILL.md} +81 -45
  341. package/skills/ship/evals/evals.json +42 -0
  342. package/skills/smith/SKILL.md +142 -0
  343. package/skills/smith/evals/evals.json +46 -0
  344. package/skills/smith/references/autonomy-and-gates.md +94 -0
  345. package/{.github/prompts/sonarcloud.prompt.md → skills/sonarcloud/SKILL.md} +14 -3
  346. package/skills/sonarcloud/evals/evals.json +46 -0
  347. package/skills/sonarcloud-analysis/SKILL.md +18 -13
  348. package/skills/sonarcloud-analysis/evals/evals.json +11 -15
  349. package/{.github/prompts/status.prompt.md → skills/status/SKILL.md} +20 -10
  350. package/skills/status/evals/evals.json +50 -0
  351. package/skills/triage-ready/SKILL.md +121 -0
  352. package/skills/triage-ready/evals/evals.json +42 -0
  353. package/{.github/prompts/validate.prompt.md → skills/validate/SKILL.md} +52 -29
  354. package/skills/validate/evals/evals.json +42 -0
  355. package/skills/verify/SKILL.md +299 -0
  356. package/skills/verify/evals/evals.json +50 -0
  357. package/.claude/commands/dev.md +0 -345
  358. package/.claude/commands/plan.md +0 -566
  359. package/.claude/commands/premerge.md +0 -186
  360. package/.claude/commands/research.md +0 -42
  361. package/.claude/commands/review.md +0 -451
  362. package/.claude/commands/rollback.md +0 -721
  363. package/.claude/commands/ship.md +0 -213
  364. package/.claude/commands/sonarcloud.md +0 -152
  365. package/.claude/commands/status.md +0 -90
  366. package/.claude/commands/validate.md +0 -288
  367. package/.claude/commands/verify.md +0 -269
  368. package/.claude/rules/workflow.md +0 -121
  369. package/.cline/workflows/dev.md +0 -342
  370. package/.cline/workflows/plan.md +0 -563
  371. package/.cline/workflows/premerge.md +0 -183
  372. package/.cline/workflows/research.md +0 -39
  373. package/.cline/workflows/review.md +0 -448
  374. package/.cline/workflows/rollback.md +0 -718
  375. package/.cline/workflows/ship.md +0 -210
  376. package/.cline/workflows/sonarcloud.md +0 -146
  377. package/.cline/workflows/status.md +0 -87
  378. package/.cline/workflows/validate.md +0 -285
  379. package/.cline/workflows/verify.md +0 -266
  380. package/.codex/config.toml +0 -11
  381. package/.codex/skills/dev/SKILL.md +0 -345
  382. package/.codex/skills/plan/SKILL.md +0 -566
  383. package/.codex/skills/premerge/SKILL.md +0 -186
  384. package/.codex/skills/research/SKILL.md +0 -42
  385. package/.codex/skills/review/SKILL.md +0 -451
  386. package/.codex/skills/rollback/SKILL.md +0 -721
  387. package/.codex/skills/ship/SKILL.md +0 -213
  388. package/.codex/skills/sonarcloud/SKILL.md +0 -149
  389. package/.codex/skills/status/SKILL.md +0 -90
  390. package/.codex/skills/validate/SKILL.md +0 -288
  391. package/.codex/skills/verify/SKILL.md +0 -269
  392. package/.cursor/commands/dev.md +0 -342
  393. package/.cursor/commands/plan.md +0 -563
  394. package/.cursor/commands/premerge.md +0 -183
  395. package/.cursor/commands/research.md +0 -39
  396. package/.cursor/commands/review.md +0 -448
  397. package/.cursor/commands/ship.md +0 -210
  398. package/.cursor/commands/sonarcloud.md +0 -146
  399. package/.cursor/commands/status.md +0 -87
  400. package/.cursor/commands/validate.md +0 -285
  401. package/.cursor/commands/verify.md +0 -266
  402. package/.cursorrules +0 -149
  403. package/.github/prompts/premerge.prompt.md +0 -188
  404. package/.github/prompts/research.prompt.md +0 -44
  405. package/.github/prompts/rollback.prompt.md +0 -723
  406. package/.github/prompts/verify.prompt.md +0 -271
  407. package/.github/workflows/beads-to-github.yml +0 -89
  408. package/.github/workflows/github-to-beads.yml +0 -100
  409. package/.kilocode/workflows/dev.md +0 -346
  410. package/.kilocode/workflows/plan.md +0 -567
  411. package/.kilocode/workflows/premerge.md +0 -187
  412. package/.kilocode/workflows/research.md +0 -43
  413. package/.kilocode/workflows/review.md +0 -452
  414. package/.kilocode/workflows/rollback.md +0 -722
  415. package/.kilocode/workflows/ship.md +0 -214
  416. package/.kilocode/workflows/sonarcloud.md +0 -150
  417. package/.kilocode/workflows/status.md +0 -91
  418. package/.kilocode/workflows/validate.md +0 -289
  419. package/.kilocode/workflows/verify.md +0 -270
  420. package/.opencode/commands/dev.md +0 -345
  421. package/.opencode/commands/plan.md +0 -566
  422. package/.opencode/commands/premerge.md +0 -186
  423. package/.opencode/commands/research.md +0 -42
  424. package/.opencode/commands/review.md +0 -451
  425. package/.opencode/commands/rollback.md +0 -721
  426. package/.opencode/commands/ship.md +0 -213
  427. package/.opencode/commands/sonarcloud.md +0 -149
  428. package/.opencode/commands/status.md +0 -90
  429. package/.opencode/commands/validate.md +0 -288
  430. package/.opencode/commands/verify.md +0 -269
  431. package/.roo/commands/dev.md +0 -346
  432. package/.roo/commands/plan.md +0 -567
  433. package/.roo/commands/premerge.md +0 -187
  434. package/.roo/commands/research.md +0 -43
  435. package/.roo/commands/review.md +0 -452
  436. package/.roo/commands/rollback.md +0 -722
  437. package/.roo/commands/ship.md +0 -214
  438. package/.roo/commands/sonarcloud.md +0 -150
  439. package/.roo/commands/status.md +0 -91
  440. package/.roo/commands/validate.md +0 -289
  441. package/.roo/commands/verify.md +0 -270
  442. package/docs/BEADS_GITHUB_SYNC.md +0 -281
  443. package/docs/GREPTILE_SETUP.md +0 -400
  444. package/docs/MANUAL_REVIEW_GUIDE.md +0 -106
  445. package/docs/SETUP.md +0 -663
  446. package/docs/VALIDATION.md +0 -363
  447. package/lib/agents/cline.plugin.json +0 -29
  448. package/lib/agents/copilot.plugin.json +0 -24
  449. package/lib/agents/kilocode.plugin.json +0 -22
  450. package/lib/agents/opencode.plugin.json +0 -23
  451. package/lib/agents/roo.plugin.json +0 -30
  452. package/lib/beads-bootstrap.js +0 -225
  453. package/lib/beads-health-check.js +0 -188
  454. package/lib/commands/commands-reset.js +0 -147
  455. package/opencode.json +0 -67
  456. package/scripts/beads-context.test.js +0 -584
  457. package/scripts/github-beads-sync/comment.mjs +0 -64
  458. package/scripts/github-beads-sync/config.mjs +0 -148
  459. package/scripts/github-beads-sync/github-api.mjs +0 -131
  460. package/scripts/github-beads-sync/index.mjs +0 -356
  461. package/scripts/github-beads-sync/label-mapper.mjs +0 -54
  462. package/scripts/github-beads-sync/mapping.mjs +0 -132
  463. package/scripts/github-beads-sync/reverse-sync-cli.mjs +0 -31
  464. package/scripts/github-beads-sync/reverse-sync.mjs +0 -162
  465. package/scripts/github-beads-sync/run-bd.mjs +0 -161
  466. package/scripts/github-beads-sync/sanitize.mjs +0 -121
  467. package/scripts/github-beads-sync.config.json +0 -26
  468. 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
- }