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
@@ -0,0 +1,282 @@
1
+ const { execFileSync } = require('node:child_process');
2
+ const fs = require('node:fs');
3
+ const path = require('node:path');
4
+
5
+ const VERDICT_LABELS = {
6
+ PASS: 'good',
7
+ FAIL: 'bad',
8
+ };
9
+
10
+ const REVIEWER_ROLES = new Set(['spec_reviewer', 'quality_reviewer']);
11
+ const SECRET_KEY_PATTERN = /(api(?:[_-]|\s)?key|authorization|credential|password|private(?:[_-]|\s)?key|secret|token)/i;
12
+ const SECRET_TEXT_KEY_PATTERN = String.raw`(?:api(?:[_-]|\s)?key|authorization|credential|password|private(?:[_-]|\s)?key|secret|token)`;
13
+ const SECRET_TEXT_PATTERNS = [
14
+ {
15
+ pattern: /\bBearer\s+\S+/gi,
16
+ replace: () => 'Bearer [REDACTED]',
17
+ },
18
+ {
19
+ pattern: new RegExp(`(\\b${SECRET_TEXT_KEY_PATTERN}\\b\\s*=\\s*)([^&,\r\n]+)`, 'gi'),
20
+ replace: (_match, prefix) => `${prefix}[REDACTED]`,
21
+ },
22
+ {
23
+ pattern: new RegExp(`(\\b${SECRET_TEXT_KEY_PATTERN}\\b\\s+is\\s+)([^&,\r\n]+)`, 'gi'),
24
+ replace: (_match, prefix) => `${prefix}[REDACTED]`,
25
+ },
26
+ {
27
+ pattern: new RegExp(
28
+ `(\\b${SECRET_TEXT_KEY_PATTERN}\\b\\s+)(?!is\\b)([^&,\r\n]*?)(?=\\s+\\b${SECRET_TEXT_KEY_PATTERN}\\b\\s+|[&,\r\n]|$)`,
29
+ 'gi'
30
+ ),
31
+ replace: (_match, prefix) => `${prefix}[REDACTED]`,
32
+ },
33
+ {
34
+ pattern: new RegExp(
35
+ `((?:"|')?${SECRET_TEXT_KEY_PATTERN}(?:"|')?\\s*:\\s*)(?:"[^"]*"|'[^']*'|[^,}\\]\r\n]+)`,
36
+ 'gi'
37
+ ),
38
+ replace: (_match, prefix) => `${prefix}"[REDACTED]"`,
39
+ },
40
+ /\bsk-[A-Za-z0-9_-]{8,}\b/g,
41
+ ];
42
+
43
+ function defaultRunCommand(command, args, options = {}) {
44
+ return execFileSync(command, args, {
45
+ cwd: options.cwd || process.cwd(),
46
+ encoding: 'utf8',
47
+ input: options.input,
48
+ timeout: options.timeout || 120000,
49
+ });
50
+ }
51
+
52
+ function redactString(value) {
53
+ return SECRET_TEXT_PATTERNS.reduce(
54
+ (current, entry) => {
55
+ if (entry && typeof entry === 'object' && !(entry instanceof RegExp)) {
56
+ return current.replace(entry.pattern, entry.replace);
57
+ }
58
+ return current.replace(entry, () => '[REDACTED]');
59
+ },
60
+ value,
61
+ );
62
+ }
63
+
64
+ function redact(value, key = '') {
65
+ if (SECRET_KEY_PATTERN.test(key)) {
66
+ return '[REDACTED]';
67
+ }
68
+
69
+ if (typeof value === 'string') {
70
+ return redactString(value);
71
+ }
72
+
73
+ if (Array.isArray(value)) {
74
+ return value.map(item => redact(item));
75
+ }
76
+
77
+ if (value && typeof value === 'object') {
78
+ return Object.fromEntries(
79
+ Object.entries(value).map(([entryKey, entryValue]) => [entryKey, redact(entryValue, entryKey)]),
80
+ );
81
+ }
82
+
83
+ return value;
84
+ }
85
+
86
+ function asJsonString(value) {
87
+ if (typeof value === 'string') return redactString(value);
88
+ return JSON.stringify(redact(value));
89
+ }
90
+
91
+ function buildSubagentAuditPayload(event) {
92
+ if (!event || typeof event !== 'object') {
93
+ throw new TypeError('Audit event must be an object');
94
+ }
95
+ if (!event.command) {
96
+ throw new TypeError('Audit event command is required');
97
+ }
98
+ if (!event.role) {
99
+ throw new TypeError('Audit event role is required');
100
+ }
101
+
102
+ const metadata =
103
+ event.metadata && typeof event.metadata === 'object' && !Array.isArray(event.metadata)
104
+ ? event.metadata
105
+ : {};
106
+
107
+ return {
108
+ kind: 'llm_call',
109
+ command: event.command,
110
+ issueId: event.issueId,
111
+ role: event.role,
112
+ phase: event.phase,
113
+ taskId: event.taskId,
114
+ taskTitle: event.taskTitle,
115
+ model: event.model || 'unknown',
116
+ prompt: asJsonString({
117
+ command: event.command,
118
+ role: event.role,
119
+ phase: event.phase,
120
+ taskId: event.taskId,
121
+ taskTitle: event.taskTitle,
122
+ content: event.prompt || '',
123
+ }),
124
+ response: asJsonString({
125
+ command: event.command,
126
+ role: event.role,
127
+ verdict: event.verdict || 'UNKNOWN',
128
+ content: event.response || '',
129
+ }),
130
+ metadata: redact(metadata),
131
+ verdict: event.verdict,
132
+ };
133
+ }
134
+
135
+ function parseRecordId(output, { requireJson = false } = {}) {
136
+ if (!output) return null;
137
+ try {
138
+ const parsed = JSON.parse(output);
139
+ return typeof parsed.id === 'string' ? parsed.id : null;
140
+ } catch (_error) {
141
+ if (requireJson) return null;
142
+ const match = /\bint-[A-Za-z0-9_-]+\b/.exec(String(output));
143
+ return match ? match[0] : null;
144
+ }
145
+ }
146
+
147
+ function hasAuditMetaJsonSupport(runCommand = defaultRunCommand, options = {}) {
148
+ const output = runCommand('bd', ['audit', 'record', '--help'], options);
149
+ return String(output).includes('--meta-json');
150
+ }
151
+
152
+ function writeFallbackMetadata(payload, entryId, options) {
153
+ if (!entryId || !payload.metadata || Object.keys(payload.metadata).length === 0) {
154
+ return null;
155
+ }
156
+
157
+ const cwd = options.cwd || process.cwd();
158
+ const fsImpl = options.fs || fs;
159
+ const forgeDir = path.join(cwd, '.forge').replace(/\\/g, '/');
160
+ const logPath = path.join(forgeDir, 'log.jsonl').replace(/\\/g, '/');
161
+ const line = {
162
+ kind: 'forge.auditEvidence',
163
+ sourceOfTruth: 'beads',
164
+ beadsEntryId: entryId,
165
+ command: redact(payload.command),
166
+ role: redact(payload.role),
167
+ phase: redact(payload.phase),
168
+ taskId: redact(payload.taskId),
169
+ taskTitle: redact(payload.taskTitle),
170
+ metadata: redact(payload.metadata),
171
+ };
172
+
173
+ try {
174
+ fsImpl.mkdirSync(forgeDir, { recursive: true });
175
+ fsImpl.appendFileSync(logPath, `${JSON.stringify(line)}\n`);
176
+ return { path: logPath, line };
177
+ } catch (error) {
178
+ return { path: logPath, line, skipped: true, error: error.message };
179
+ }
180
+ }
181
+
182
+ function recordSubagentAuditEvent(event, options = {}) {
183
+ const payload = buildSubagentAuditPayload(event);
184
+ const runCommand = options.runCommand || defaultRunCommand;
185
+ const metaJsonSupported =
186
+ typeof options.metaJsonSupported === 'boolean'
187
+ ? options.metaJsonSupported
188
+ : hasAuditMetaJsonSupport(runCommand, { cwd: options.cwd || process.cwd() });
189
+ const args = [
190
+ 'audit',
191
+ 'record',
192
+ '--json',
193
+ '--kind',
194
+ 'llm_call',
195
+ ];
196
+
197
+ if (payload.issueId) {
198
+ args.push('--issue-id', payload.issueId);
199
+ }
200
+
201
+ args.push(
202
+ '--model',
203
+ payload.model,
204
+ '--prompt',
205
+ payload.prompt,
206
+ '--response',
207
+ payload.response,
208
+ );
209
+
210
+ if (metaJsonSupported && Object.keys(payload.metadata).length > 0) {
211
+ args.push('--meta-json', JSON.stringify(payload.metadata));
212
+ }
213
+
214
+ const output = runCommand('bd', args, { cwd: options.cwd || process.cwd() });
215
+ const entryId = parseRecordId(output, { requireJson: true });
216
+ const fallback = metaJsonSupported ? null : writeFallbackMetadata(payload, entryId, options);
217
+
218
+ return {
219
+ success: Boolean(entryId),
220
+ entryId,
221
+ output,
222
+ payload,
223
+ fallback,
224
+ };
225
+ }
226
+
227
+ function labelSubagentAuditEvent(entryId, event, options = {}) {
228
+ const verdict = String(event?.verdict || '').toUpperCase();
229
+ const role = event?.role;
230
+ const label = VERDICT_LABELS[verdict];
231
+
232
+ if (!entryId || !REVIEWER_ROLES.has(role) || !label) {
233
+ return { skipped: true };
234
+ }
235
+
236
+ const runCommand = options.runCommand || defaultRunCommand;
237
+ const reason = `${role} verdict: ${verdict}`;
238
+ let output;
239
+ try {
240
+ output = runCommand('bd', [
241
+ 'audit',
242
+ 'label',
243
+ entryId,
244
+ '--json',
245
+ '--label',
246
+ label,
247
+ '--reason',
248
+ reason,
249
+ ], { cwd: options.cwd || process.cwd() });
250
+ } catch (error) {
251
+ return {
252
+ success: false,
253
+ label,
254
+ error: error.message,
255
+ };
256
+ }
257
+
258
+ const labeledEntryId = parseRecordId(output, { requireJson: true });
259
+
260
+ return {
261
+ success: labeledEntryId === entryId,
262
+ label,
263
+ entryId: labeledEntryId,
264
+ output,
265
+ };
266
+ }
267
+
268
+ function recordAndLabelSubagentAuditEvent(event, options = {}) {
269
+ const record = recordSubagentAuditEvent(event, options);
270
+ const label = labelSubagentAuditEvent(record.entryId, event, options);
271
+ return { record, label };
272
+ }
273
+
274
+ module.exports = {
275
+ VERDICT_LABELS,
276
+ buildSubagentAuditPayload,
277
+ recordSubagentAuditEvent,
278
+ labelSubagentAuditEvent,
279
+ recordAndLabelSubagentAuditEvent,
280
+ hasAuditMetaJsonSupport,
281
+ redact,
282
+ };
@@ -12,6 +12,13 @@ const path = require('node:path');
12
12
  const { spawnSync } = require('node:child_process');
13
13
  const { secureExecFileSync } = require('./shell-utils');
14
14
 
15
+ const BEADS_LOCAL_EXCLUDE_LINES = [
16
+ '# Forge local Beads state',
17
+ '.beads/',
18
+ '.dolt/',
19
+ '.beads-credential-key'
20
+ ];
21
+
15
22
  function isIgnorableFsError(error) {
16
23
  return ['EACCES', 'ENOENT', 'ENOTDIR', 'EPERM'].includes(error?.code);
17
24
  }
@@ -103,6 +110,10 @@ function writeBeadsGitignore(projectRoot) {
103
110
  fs.mkdirSync(beadsDir, { recursive: true });
104
111
 
105
112
  const gitignoreContent = [
113
+ '# Beads runtime, export, and backup state is local',
114
+ '*',
115
+ '!.gitignore',
116
+ '',
106
117
  '# Dolt database files (binary, not suitable for git)',
107
118
  'dolt/',
108
119
  '*.db',
@@ -117,6 +128,108 @@ function writeBeadsGitignore(projectRoot) {
117
128
  );
118
129
  }
119
130
 
131
+ function resolveGitInfoExcludePath(projectRoot) {
132
+ try {
133
+ const gitExcludePath = secureExecFileSync(resolveCommand('git'), ['rev-parse', '--git-path', 'info/exclude'], {
134
+ cwd: projectRoot,
135
+ encoding: 'utf8',
136
+ stdio: 'pipe'
137
+ }).trim();
138
+
139
+ if (gitExcludePath) {
140
+ return path.isAbsolute(gitExcludePath)
141
+ ? gitExcludePath
142
+ : path.resolve(projectRoot, gitExcludePath);
143
+ }
144
+ } catch (error) {
145
+ if (!isRecoverableCommandError(error)) {
146
+ throw error;
147
+ }
148
+ }
149
+
150
+ return path.join(projectRoot, '.git', 'info', 'exclude');
151
+ }
152
+
153
+ function untrackExistingBeadsState(projectRoot) {
154
+ let tracked;
155
+ try {
156
+ tracked = secureExecFileSync(resolveCommand('git'), [
157
+ 'ls-files',
158
+ '-z',
159
+ '--',
160
+ '.beads',
161
+ '.dolt',
162
+ '.beads-credential-key'
163
+ ], {
164
+ cwd: projectRoot,
165
+ encoding: 'utf8',
166
+ stdio: 'pipe'
167
+ });
168
+ } catch (error) {
169
+ if (!isRecoverableCommandError(error)) {
170
+ throw error;
171
+ }
172
+ return;
173
+ }
174
+
175
+ if (!tracked) {
176
+ return;
177
+ }
178
+
179
+ try {
180
+ secureExecFileSync(resolveCommand('git'), [
181
+ 'rm',
182
+ '--cached',
183
+ '-r',
184
+ '-f',
185
+ '--ignore-unmatch',
186
+ '--',
187
+ '.beads',
188
+ '.dolt',
189
+ '.beads-credential-key'
190
+ ], {
191
+ cwd: projectRoot,
192
+ encoding: 'utf8',
193
+ stdio: 'pipe'
194
+ });
195
+ } catch (error) {
196
+ if (!isRecoverableCommandError(error)) {
197
+ throw error;
198
+ }
199
+ }
200
+ }
201
+
202
+ /**
203
+ * Add local-only Git exclude rules for Beads state.
204
+ *
205
+ * Uses `.git/info/exclude` instead of the tracked `.gitignore` so `forge setup`
206
+ * does not dirty downstream repositories just to keep Beads runtime files local.
207
+ * Existing tracked Beads state is removed from the Git index only, leaving local
208
+ * files in place for the Beads runtime.
209
+ *
210
+ * @param {string} projectRoot - Absolute path to the project root
211
+ */
212
+ function ensureBeadsGitExclude(projectRoot) {
213
+ const excludePath = resolveGitInfoExcludePath(projectRoot);
214
+ fs.mkdirSync(path.dirname(excludePath), { recursive: true });
215
+
216
+ const existing = fs.existsSync(excludePath)
217
+ ? fs.readFileSync(excludePath, 'utf8')
218
+ : '';
219
+ const existingLines = new Set(existing.split(/\r?\n/));
220
+ const missingLines = BEADS_LOCAL_EXCLUDE_LINES.filter((line) => !existingLines.has(line));
221
+
222
+ if (missingLines.length === 0) {
223
+ untrackExistingBeadsState(projectRoot);
224
+ return;
225
+ }
226
+
227
+ const prefix = existing && !existing.endsWith('\n') ? '\n' : '';
228
+ const spacer = existing.trim() ? '\n' : '';
229
+ fs.appendFileSync(excludePath, `${prefix}${spacer}${missingLines.join('\n')}\n`, 'utf8');
230
+ untrackExistingBeadsState(projectRoot);
231
+ }
232
+
120
233
  /**
121
234
  * Check whether Beads is properly initialized in a project.
122
235
  *
@@ -334,6 +447,13 @@ function safeBeadsInit(projectRoot, options = {}) {
334
447
  const warnings = [];
335
448
  const errors = [];
336
449
 
450
+ // Keep Beads runtime/export state local even when the tracker already exists.
451
+ try {
452
+ ensureBeadsGitExclude(projectRoot);
453
+ } catch (err) {
454
+ warnings.push(`Failed to write local Beads git exclude rules: ${err.message}`);
455
+ }
456
+
337
457
  // (a) Check if already initialized — idempotent skip
338
458
  if (isBeadsInitialized(projectRoot)) {
339
459
  return {
@@ -410,6 +530,7 @@ module.exports = {
410
530
  sanitizePrefix,
411
531
  writeBeadsConfig,
412
532
  writeBeadsGitignore,
533
+ ensureBeadsGitExclude,
413
534
  isBeadsInitialized,
414
535
  readBeadsDatabaseName,
415
536
  preSeedJsonl,
@@ -3,6 +3,7 @@
3
3
  const fs = require('node:fs');
4
4
  const path = require('node:path');
5
5
  const { execFileSync } = require('node:child_process');
6
+ const { cleanupDeprecatedSyncFiles } = require('./deprecated-sync-cleanup');
6
7
 
7
8
  const DEFAULT_BEADS_VERSION = '1.0.0';
8
9
 
@@ -141,119 +142,41 @@ function templateWorkflows(workflowDir, branch, beadsVersion, createdFiles = [])
141
142
  }
142
143
  }
143
144
 
144
- /**
145
- * @typedef {Object} ScaffoldResult
146
- * @property {string[]} filesCreated - Relative paths of files written (new or overwritten)
147
- * @property {string[]} filesSkipped - Relative paths of files that already existed and were preserved
148
- */
145
+ function cleanupDeprecatedBeadsSync(projectRoot, options = {}) {
146
+ return cleanupDeprecatedSyncFiles(projectRoot, options);
147
+ }
149
148
 
150
149
  /**
151
- * Copy a single file from src to dest, creating parent directories as needed.
152
- *
153
- * @param {string} src - Absolute source path
154
- * @param {string} dest - Absolute destination path
155
- * @returns {void}
150
+ * @typedef {Object} ScaffoldResult
151
+ * @property {string[]} filesCreated - Always empty; retained for deprecated API compatibility.
152
+ * @property {string[]} filesSkipped - Always empty; retained for deprecated API compatibility.
153
+ * @property {string[]} filesRemoved - Relative paths of deprecated generated sync files removed.
154
+ * @property {boolean} deprecated - Indicates the legacy scaffold path is deprecated.
155
+ * @property {string} message - Deprecation guidance for future sync direction.
156
156
  */
157
- function copyFileWithDirs(src, dest) {
158
- fs.mkdirSync(path.dirname(dest), { recursive: true });
159
- fs.copyFileSync(src, dest);
160
- }
161
157
 
162
158
  /**
163
- * Scaffold Beads sync workflows and scripts to the user's project.
159
+ * Deprecated compatibility shim for removed Beads/GitHub sync scaffolding.
164
160
  *
165
- * Copies workflow templates, sync modules, config, and mapping stub into
166
- * the project's `.github/` tree from the forge package source.
161
+ * Performs cleanup of generated legacy sync artifacts only. User-owned files
162
+ * at matching paths are preserved unless their content matches known generated
163
+ * templates.
167
164
  *
168
165
  * @param {string} projectRoot - Absolute path to the user's project root
169
166
  * @param {string} packageDir - Absolute path to the forge package install location
170
167
  * @param {Object} [_options={}] - Reserved for future options
171
- * @returns {ScaffoldResult}
168
+ * @returns {ScaffoldResult} Deprecated cleanup result.
172
169
  */
173
170
  function scaffoldBeadsSync(projectRoot, packageDir, _options = {}) {
174
- /** @type {string[]} */
175
- const filesCreated = [];
176
- /** @type {string[]} */
177
- const filesSkipped = [];
178
-
179
- const githubDir = path.join(projectRoot, '.github');
180
-
181
- // --- Step a: Copy workflow templates ---
182
- const workflowNames = ['github-to-beads.yml', 'beads-to-github.yml'];
183
- const srcWorkflowsDir = path.join(packageDir, '.github', 'workflows');
184
-
185
- for (const name of workflowNames) {
186
- const src = path.join(srcWorkflowsDir, name);
187
- const relPath = `.github/workflows/${name}`;
188
- const dest = path.join(projectRoot, '.github', 'workflows', name);
189
-
190
- if (!fs.existsSync(src)) continue;
191
- if (fs.existsSync(dest)) {
192
- filesSkipped.push(relPath);
193
- } else {
194
- copyFileWithDirs(src, dest);
195
- filesCreated.push(relPath);
196
- }
197
- }
198
-
199
- // --- Step b: Copy sync modules ---
200
- const srcSyncDir = path.join(packageDir, 'scripts', 'github-beads-sync');
201
- const destSyncDir = path.join(githubDir, 'scripts', 'beads-sync');
202
-
203
- if (fs.existsSync(srcSyncDir)) {
204
- const entries = fs.readdirSync(srcSyncDir);
205
- for (const entry of entries) {
206
- const srcFile = path.join(srcSyncDir, entry);
207
- const stat = fs.statSync(srcFile);
208
- if (stat.isFile()) {
209
- const relPath = `.github/scripts/beads-sync/${entry}`;
210
- const dest = path.join(destSyncDir, entry);
211
- if (fs.existsSync(dest)) {
212
- filesSkipped.push(relPath);
213
- } else {
214
- copyFileWithDirs(srcFile, dest);
215
- filesCreated.push(relPath);
216
- }
217
- }
218
- }
219
- }
220
-
221
- // --- Step c: Create beads-sync-config.json ---
222
- const configRelPath = '.github/beads-sync-config.json';
223
- const configDest = path.join(githubDir, 'beads-sync-config.json');
224
- const srcConfig = path.join(packageDir, 'scripts', 'github-beads-sync.config.json');
225
-
226
- if (fs.existsSync(configDest)) {
227
- filesSkipped.push(configRelPath);
228
- } else if (fs.existsSync(srcConfig)) {
229
- copyFileWithDirs(srcConfig, configDest);
230
- filesCreated.push(configRelPath);
231
- } else {
232
- // Create a sensible default config
233
- const defaultConfig = {
234
- defaultType: 'task',
235
- defaultPriority: 2,
236
- mapAssignee: true,
237
- publicRepoGate: 'none'
238
- };
239
- fs.mkdirSync(path.dirname(configDest), { recursive: true });
240
- fs.writeFileSync(configDest, JSON.stringify(defaultConfig, null, 2) + '\n');
241
- filesCreated.push(configRelPath);
242
- }
243
-
244
- // --- Step d: Create beads-mapping.json if not exists ---
245
- const mappingRelPath = '.github/beads-mapping.json';
246
- const mappingDest = path.join(githubDir, 'beads-mapping.json');
247
-
248
- if (fs.existsSync(mappingDest)) {
249
- filesSkipped.push(mappingRelPath);
250
- } else {
251
- fs.mkdirSync(path.dirname(mappingDest), { recursive: true });
252
- fs.writeFileSync(mappingDest, '{}');
253
- filesCreated.push(mappingRelPath);
254
- }
255
-
256
- return { filesCreated, filesSkipped };
171
+ const cleanup = cleanupDeprecatedBeadsSync(projectRoot, { packageDir });
172
+
173
+ return {
174
+ filesCreated: [],
175
+ filesSkipped: [],
176
+ filesRemoved: cleanup.removed,
177
+ deprecated: true,
178
+ message: 'Beads GitHub sync scaffolding is deprecated; future GitHub issue sync must use Forge Kernel/server authority.'
179
+ };
257
180
  }
258
181
 
259
182
  module.exports = {
@@ -261,5 +184,6 @@ module.exports = {
261
184
  detectDefaultBranch,
262
185
  detectBeadsVersion,
263
186
  templateWorkflows,
187
+ cleanupDeprecatedBeadsSync,
264
188
  scaffoldBeadsSync,
265
189
  };
@@ -2,6 +2,19 @@ const fs = require('node:fs');
2
2
  const os = require('node:os');
3
3
  const path = require('node:path');
4
4
 
5
+ const { populateAgentSkills } = require('./skills-sync');
6
+
7
+ /**
8
+ * Codex's documented repo-local skill discovery directory, relative to a project
9
+ * root. Codex scans `.agents/skills/<name>/SKILL.md` from the current working
10
+ * directory up to the repo root (developers.openai.com/codex/skills). Unlike the
11
+ * GLOBAL `$CODEX_HOME/skills` install, this surface is COMMITTED to the repo (kept
12
+ * byte-identical to the canonical `skills/` source by a pre-commit sync hook and
13
+ * the drift gate), so a teammate who clones the repo WITHOUT running `forge setup`
14
+ * still gets the Forge skills/stages auto-discovered.
15
+ */
16
+ const CODEX_REPO_SKILLS_DIR = '.agents/skills';
17
+
5
18
  function injectForgeAdapter(content, commandName) {
6
19
  const adapter = [
7
20
  '> Forge stage adapter',
@@ -20,7 +33,10 @@ function injectForgeAdapter(content, commandName) {
20
33
  }
21
34
 
22
35
  function listCodexSkillEntries(sourceRoot) {
23
- const skillsDir = path.join(sourceRoot, '.codex', 'skills');
36
+ // Read from the canonical `skills/` source (single source of truth) rather than
37
+ // a committed `.codex/skills` mirror. The GLOBAL `$CODEX_HOME/skills` install is
38
+ // generated from these entries with the stage adapter injected below.
39
+ const skillsDir = path.join(sourceRoot, 'skills');
24
40
 
25
41
  if (!fs.existsSync(skillsDir)) {
26
42
  return [];
@@ -94,10 +110,44 @@ function buildCodexSkillInstallPlan(sourceRoot, options = {}) {
94
110
  }));
95
111
  }
96
112
 
113
+ /**
114
+ * Absolute path to a project's repo-local Codex skill discovery dir.
115
+ *
116
+ * @param {string} projectRoot - The project/repo root.
117
+ * @returns {string} `<projectRoot>/.agents/skills`.
118
+ */
119
+ function resolveCodexRepoSkillsDir(projectRoot) {
120
+ return path.join(projectRoot, '.agents', 'skills');
121
+ }
122
+
123
+ /**
124
+ * Generate the repo-local Codex skill discovery mirror (`.agents/skills`) from
125
+ * the canonical `skills/` source.
126
+ *
127
+ * Content matches the other harness mirrors byte-for-byte (raw canonical — the
128
+ * `$CODEX_HOME` stage adapter is NOT injected here) so the skills-sync drift gate
129
+ * can enforce it, and so repo-local discovery reaches parity with the
130
+ * `.claude/skills` / `.cursor/skills` discovery surfaces.
131
+ *
132
+ * @param {object} params
133
+ * @param {string} params.sourceRoot - Root containing the canonical `skills/` dir.
134
+ * @param {string} params.projectRoot - Target project/repo root.
135
+ * @param {boolean} [params.clean=false] - Remove stale canonical-managed dirs first.
136
+ * @returns {{targetSkillsDir: string, written: string[]}}
137
+ */
138
+ function populateCodexRepoSkills({ sourceRoot, projectRoot, clean = false }) {
139
+ const targetSkillsDir = resolveCodexRepoSkillsDir(projectRoot);
140
+ const { written } = populateAgentSkills({ sourceRoot, targetSkillsDir, clean });
141
+ return { targetSkillsDir, written };
142
+ }
143
+
97
144
  module.exports = {
145
+ CODEX_REPO_SKILLS_DIR,
98
146
  buildCodexSkillInstallPlan,
99
147
  formatCodexSkillsInstallDir,
100
148
  listCodexSkillEntries,
149
+ populateCodexRepoSkills,
101
150
  resolveCodexHome,
151
+ resolveCodexRepoSkillsDir,
102
152
  resolveCodexSkillsInstallDir,
103
153
  };