forge-workflow 0.0.9 → 0.1.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (479) hide show
  1. package/.claude/rules/{greptile-review-process.md → review-process.md} +56 -41
  2. package/.claude/scripts/{greptile-resolve.sh → review-resolve.sh} +13 -3
  3. package/.cursor/rules/permissions-guidance.mdc +2 -2
  4. package/.forge/hooks/check-tdd.js +3 -0
  5. package/.forge/hooks/forge-native-hook.js +245 -0
  6. package/.forge/protected-paths.yaml +157 -0
  7. package/AGENTS.md +151 -61
  8. package/CHANGELOG.md +681 -0
  9. package/CLAUDE.md +9 -106
  10. package/QUICKSTART.md +171 -0
  11. package/README.md +271 -363
  12. package/bin/forge-cmd.js +120 -9
  13. package/bin/forge-preflight.js +26 -5
  14. package/bin/forge.js +466 -489
  15. package/docs/INDEX.md +93 -0
  16. package/docs/PROJECT_DESIGN.md +685 -0
  17. package/docs/architecture/index.md +66 -0
  18. package/docs/architecture/notes/README.md +35 -0
  19. package/docs/architecture/subsystems/README.md +46 -0
  20. package/docs/{TOOLCHAIN.md → forge/TOOLCHAIN.md} +56 -47
  21. package/docs/forge/VALIDATION.md +82 -0
  22. package/docs/{AGENT_INSTALL_PROMPT.md → guides/AGENT_INSTALL_PROMPT.md} +3 -3
  23. package/docs/guides/BEADS_GITHUB_SYNC.md +32 -0
  24. package/docs/{ENHANCED_ONBOARDING.md → guides/ENHANCED_ONBOARDING.md} +16 -12
  25. package/docs/guides/GREPTILE_SETUP.md +46 -0
  26. package/docs/guides/MANUAL_REVIEW_GUIDE.md +58 -0
  27. package/docs/guides/MIGRATION.md +56 -0
  28. package/docs/guides/SETUP.md +118 -0
  29. package/docs/guides/SUPPORT.md +185 -0
  30. package/docs/guides/WORKFLOW_TEMPLATES.md +74 -0
  31. package/docs/guides/memory-backends.md +183 -0
  32. package/docs/reference/ADAPTERS.md +128 -0
  33. package/docs/reference/AGENT_SKILL_PARITY.md +175 -0
  34. package/docs/reference/COMMANDS.md +205 -0
  35. package/docs/reference/DECISION_DRIFT_GUARDS.md +97 -0
  36. package/docs/{EXAMPLES.md → reference/EXAMPLES.md} +7 -5
  37. package/docs/reference/FORGE_KERNEL_STORAGE_MODEL.md +135 -0
  38. package/docs/reference/HERMES_INTEGRATION.md +118 -0
  39. package/docs/reference/INSIGHTS_RECAP.md +63 -0
  40. package/docs/reference/INSTALL.md +164 -0
  41. package/docs/reference/KERNEL_TAXONOMY_VALIDATION.md +161 -0
  42. package/docs/reference/PROTECTED_PATH_MANIFEST.md +25 -0
  43. package/docs/reference/RELEASE.md +68 -0
  44. package/docs/reference/RESEARCH_TEMPLATE.md +292 -0
  45. package/docs/{ROADMAP.md → reference/ROADMAP.md} +12 -9
  46. package/docs/reference/SKILLS.md +35 -0
  47. package/docs/reference/STATUS_BOARD.md +80 -0
  48. package/docs/reference/TEMPLATES.md +106 -0
  49. package/docs/reference/TOOLCHAIN.md +658 -0
  50. package/docs/reference/VALIDATION.md +82 -0
  51. package/docs/reference/agent-permissions.md +169 -0
  52. package/docs/reference/beads-to-kernel-migration-ux.md +61 -0
  53. package/docs/reference/control-plane-guarantees.md +125 -0
  54. package/docs/reference/dependency-chain.md +331 -0
  55. package/docs/reference/forge-kernel-issue-command-contract.md +161 -0
  56. package/docs/reference/forge-kernel-schema.md +72 -0
  57. package/docs/reference/kernel-conflict-evaluators.md +27 -0
  58. package/docs/reference/patch-md-format.md +77 -0
  59. package/docs/reference/protected-state-surfaces.md +59 -0
  60. package/docs/reference/shepherd.md +115 -0
  61. package/docs/reference/superpowers-analysis.md +320 -0
  62. package/docs/reference/superpowers-integration-options.md +404 -0
  63. package/docs/reference/test-environment.md +519 -0
  64. package/docs/reference/upgrade-safety.md +59 -0
  65. package/lefthook.yml +18 -0
  66. package/lib/adapter-cli.js +307 -0
  67. package/lib/adapters/beads-issue-adapter.js +127 -0
  68. package/lib/adapters/beads-kernel-compat.js +1042 -0
  69. package/lib/adapters/greptile-review-adapter.js +141 -0
  70. package/lib/adapters/kernel-issue-adapter.js +101 -0
  71. package/lib/adapters/pr-state-adapter.js +484 -0
  72. package/lib/adoption-profiles.js +126 -0
  73. package/lib/agents/README.md +2 -6
  74. package/lib/agents/claude.plugin.json +3 -8
  75. package/lib/agents/codex.plugin.json +9 -1
  76. package/lib/agents/cursor.plugin.json +2 -6
  77. package/lib/agents/hermes.plugin.json +22 -0
  78. package/lib/agents-config.js +39 -1236
  79. package/lib/audit-evidence.js +282 -0
  80. package/lib/beads-setup.js +225 -28
  81. package/lib/beads-sync-scaffold.js +36 -107
  82. package/lib/codex-skills.js +51 -1
  83. package/lib/commands/_issue.js +744 -70
  84. package/lib/commands/_manifest.js +91 -0
  85. package/lib/commands/_registry.js +85 -34
  86. package/lib/commands/_resolve-command-opts.js +261 -0
  87. package/lib/commands/_serve-security.js +270 -0
  88. package/lib/commands/adapter.js +12 -0
  89. package/lib/commands/add.js +118 -0
  90. package/lib/commands/audit.js +70 -0
  91. package/lib/commands/blocked.js +5 -0
  92. package/lib/commands/board.js +64 -0
  93. package/lib/commands/claim.js +21 -2
  94. package/lib/commands/claims.js +7 -0
  95. package/lib/commands/clean.js +485 -75
  96. package/lib/commands/close.js +2 -2
  97. package/lib/commands/comment.js +5 -0
  98. package/lib/commands/control.js +148 -0
  99. package/lib/commands/create.js +2 -2
  100. package/lib/commands/dev.js +185 -7
  101. package/lib/commands/doc-gate.js +336 -0
  102. package/lib/commands/doctor.js +156 -0
  103. package/lib/commands/explain.js +15 -0
  104. package/lib/commands/export.js +237 -0
  105. package/lib/commands/gate.js +192 -0
  106. package/lib/commands/hooks.js +242 -0
  107. package/lib/commands/inbox.js +118 -0
  108. package/lib/commands/init.js +598 -0
  109. package/lib/commands/insights.js +79 -0
  110. package/lib/commands/issue.js +12 -1
  111. package/lib/commands/issues.js +66 -0
  112. package/lib/commands/lint.js +5 -0
  113. package/lib/commands/list.js +2 -2
  114. package/lib/commands/merge.js +312 -0
  115. package/lib/commands/migrate.js +523 -0
  116. package/lib/commands/new.js +12 -0
  117. package/lib/commands/options.js +241 -0
  118. package/lib/commands/orient.js +13 -0
  119. package/lib/commands/orphans.js +5 -0
  120. package/lib/commands/patch.js +67 -0
  121. package/lib/commands/plan.js +436 -24
  122. package/lib/commands/preflight.js +211 -0
  123. package/lib/commands/prime.js +13 -0
  124. package/lib/commands/push.js +69 -2
  125. package/lib/commands/ready.js +2 -2
  126. package/lib/commands/recall.js +116 -0
  127. package/lib/commands/recap.js +61 -0
  128. package/lib/commands/recommend.js +22 -2
  129. package/lib/commands/release.js +91 -0
  130. package/lib/commands/remember.js +74 -0
  131. package/lib/commands/role.js +99 -0
  132. package/lib/commands/serve.js +581 -0
  133. package/lib/commands/setup.js +851 -979
  134. package/lib/commands/shepherd.js +436 -0
  135. package/lib/commands/ship.js +23 -1
  136. package/lib/commands/show.js +2 -2
  137. package/lib/commands/stage.js +192 -0
  138. package/lib/commands/stale.js +5 -0
  139. package/lib/commands/status.js +329 -11
  140. package/lib/commands/sync.js +34 -46
  141. package/lib/commands/team.js +15 -2
  142. package/lib/commands/test.js +58 -7
  143. package/lib/commands/update.js +2 -2
  144. package/lib/commands/upgrade.js +47 -0
  145. package/lib/commands/validate.js +56 -25
  146. package/lib/commands/worktree.js +308 -128
  147. package/lib/config-writer.js +202 -0
  148. package/lib/control-plane.js +236 -0
  149. package/lib/core/runtime-graph.js +946 -0
  150. package/lib/dep-guard/keyword-ripple.js +184 -0
  151. package/lib/deprecated-sync-cleanup.js +362 -0
  152. package/lib/detect-agent.js +2 -28
  153. package/lib/detect-worktree.js +42 -17
  154. package/lib/doc-gate/declaration.js +177 -0
  155. package/lib/doc-gate/detect.js +289 -0
  156. package/lib/doc-gate/gate.js +375 -0
  157. package/lib/doc-gate/okf-config.js +128 -0
  158. package/lib/doc-gate/okf.js +429 -0
  159. package/lib/docs-command.js +1161 -6
  160. package/lib/forge-issues.js +697 -0
  161. package/lib/forge-lock.js +262 -0
  162. package/lib/gate-events.js +193 -0
  163. package/lib/global-flags.js +74 -0
  164. package/lib/greptile-match.js +7 -63
  165. package/lib/harness-capability-matrix.js +380 -0
  166. package/lib/hook-global-installer.js +347 -0
  167. package/lib/hook-renderer.js +451 -0
  168. package/lib/inbox.js +391 -0
  169. package/lib/insights.js +397 -0
  170. package/lib/issue-adapter.js +156 -0
  171. package/lib/issue-backend.js +145 -0
  172. package/lib/issue-render.js +220 -0
  173. package/lib/issue-sync/authority.js +100 -0
  174. package/lib/issue-sync/github-pull.js +184 -0
  175. package/lib/issue-sync/import-primitives.js +98 -0
  176. package/lib/issue-sync/legacy-link-bridge.js +436 -0
  177. package/lib/issue-sync/link-store.js +292 -0
  178. package/lib/issue-sync/project-github.js +123 -0
  179. package/lib/issue-sync/reconcile.js +195 -0
  180. package/lib/issue-sync/schema.js +126 -0
  181. package/lib/kernel/backing-issue.js +305 -0
  182. package/lib/kernel/broker.js +1218 -0
  183. package/lib/kernel/cli-broker-factory.js +130 -0
  184. package/lib/kernel/conflict-signal.js +82 -0
  185. package/lib/kernel/evaluators.js +195 -0
  186. package/lib/kernel/fs-class.js +495 -0
  187. package/lib/kernel/issue-command-contract.js +559 -0
  188. package/lib/kernel/issue-id-resolver.js +186 -0
  189. package/lib/kernel/lease-enforcer.js +158 -0
  190. package/lib/kernel/migrations.js +333 -0
  191. package/lib/kernel/planning-buckets-schema.js +109 -0
  192. package/lib/kernel/projection-jsonl-writer.js +450 -0
  193. package/lib/kernel/readiness-model.js +329 -0
  194. package/lib/kernel/schema.js +356 -0
  195. package/lib/kernel/sqlite-driver.js +2504 -0
  196. package/lib/kernel/taxonomy-validator.js +394 -0
  197. package/lib/lefthook-check.js +8 -4
  198. package/lib/lefthook-wiring.js +413 -0
  199. package/lib/mcp-config-renderer.js +288 -0
  200. package/lib/memory/graphiti-mcp.js +106 -0
  201. package/lib/memory/router.js +387 -0
  202. package/lib/memory/typed-api.js +102 -0
  203. package/lib/memory-digest.js +195 -0
  204. package/lib/merge-rules.js +395 -0
  205. package/lib/migrate-dry-run.js +466 -0
  206. package/lib/orientation.js +863 -0
  207. package/lib/package-manager-remediation.js +103 -0
  208. package/lib/package-root.js +381 -0
  209. package/lib/patch-intent.js +890 -0
  210. package/lib/plugin-catalog.js +3 -4
  211. package/lib/plugin-manager.js +0 -5
  212. package/lib/pr-bundle.js +186 -0
  213. package/lib/pr-monitor/differ.js +195 -0
  214. package/lib/pr-monitor/events.js +0 -0
  215. package/lib/pr-monitor/gather.js +124 -0
  216. package/lib/pr-monitor/journal.js +299 -0
  217. package/lib/pr-monitor/monitor.js +146 -0
  218. package/lib/pr-monitor/render-sticky.js +157 -0
  219. package/lib/pr-monitor/watch-lifecycle.js +95 -0
  220. package/lib/pr-monitor/watch.js +247 -0
  221. package/lib/pr-pull.js +1273 -0
  222. package/lib/pr-shepherd.js +494 -0
  223. package/lib/pr-state-validator.js +59 -0
  224. package/lib/preflight/gates.js +237 -0
  225. package/lib/preflight/runner.js +116 -0
  226. package/lib/project-discovery.js +0 -53
  227. package/lib/project-memory.js +166 -0
  228. package/lib/protected-path-manifest.js +281 -0
  229. package/lib/protected-state-surfaces.js +387 -0
  230. package/lib/release-readiness.js +2089 -0
  231. package/lib/reset.js +59 -45
  232. package/lib/review-adapter.js +68 -0
  233. package/lib/rules-sync.js +260 -0
  234. package/lib/runtime-health.js +332 -23
  235. package/lib/safety-config-renderer.js +268 -0
  236. package/lib/setup-action-log.js +1 -7
  237. package/lib/setup.js +27 -65
  238. package/lib/shell-utils.js +76 -6
  239. package/lib/skills-sync.js +330 -0
  240. package/lib/smart-status/conflicts.js +205 -0
  241. package/lib/smart-status/scoring.js +191 -0
  242. package/lib/status/beads-snapshot.js +145 -0
  243. package/lib/status/presenter.js +216 -0
  244. package/lib/status/snapshot.js +186 -0
  245. package/lib/sync-backend.js +202 -0
  246. package/lib/untrusted-content.js +52 -0
  247. package/lib/upgrade-safety.js +199 -0
  248. package/lib/workflow/enforce-stage.js +298 -47
  249. package/lib/workflow/stage-transition.js +115 -0
  250. package/lib/workflow/stages.js +30 -6
  251. package/lib/workflow/state-manager.js +159 -14
  252. package/lib/workflow/state.js +23 -1
  253. package/lib/workflow-profiles.js +17 -5
  254. package/package.json +46 -36
  255. package/rules/documentation.md +19 -0
  256. package/rules/kernel-tracking.md +26 -0
  257. package/rules/security.md +22 -0
  258. package/rules/tdd.md +20 -0
  259. package/rules/workflow.md +27 -0
  260. package/scripts/auto-backing-issue.js +47 -0
  261. package/scripts/beads-context.sh +165 -22
  262. package/scripts/beads-migrate-to-dolt.sh +7 -0
  263. package/scripts/beads-upgrade-smoke.sh +284 -0
  264. package/scripts/behavioral-judge.sh +115 -11
  265. package/scripts/benchmark.js +349 -63
  266. package/scripts/bootstrap-windows-tools.sh +78 -0
  267. package/scripts/branch-protection.js +2 -3
  268. package/scripts/check-agents.js +34 -137
  269. package/scripts/commitlint.js +3 -1
  270. package/scripts/conflict-detect.sh +3 -0
  271. package/scripts/dep-guard-analyze.js +52 -17
  272. package/scripts/dep-guard-keyword-ripple.js +29 -0
  273. package/scripts/dep-guard-render-review.js +86 -0
  274. package/scripts/dep-guard.sh +64 -232
  275. package/scripts/file-index.sh +3 -0
  276. package/scripts/forge-team/lib/claim.sh +34 -18
  277. package/scripts/forge-team/lib/dashboard.sh +61 -86
  278. package/scripts/forge-team/lib/epic.sh +99 -263
  279. package/scripts/forge-team/lib/hooks.sh +26 -28
  280. package/scripts/forge-team/lib/identity.sh +4 -4
  281. package/scripts/forge-team/lib/sync-github.sh +144 -47
  282. package/scripts/forge-team/lib/verify.sh +93 -83
  283. package/scripts/forge-team/lib/workload.sh +41 -65
  284. package/scripts/forge-team/tests/claim.test.sh +25 -19
  285. package/scripts/forge-team/tests/dashboard.test.sh +31 -46
  286. package/scripts/forge-team/tests/epic.test.sh +52 -71
  287. package/scripts/forge-team/tests/hooks.test.sh +38 -50
  288. package/scripts/forge-team/tests/identity.test.sh +3 -3
  289. package/scripts/forge-team/tests/integration.test.sh +44 -66
  290. package/scripts/forge-team/tests/sync-github.test.sh +183 -79
  291. package/scripts/forge-team/tests/verify.test.sh +37 -46
  292. package/scripts/forge-team/tests/workflow-integration.test.sh +4 -4
  293. package/scripts/forge-team/tests/workload.test.sh +32 -66
  294. package/scripts/gen-command-manifest.js +153 -0
  295. package/scripts/gen-embedded-assets.mjs +129 -0
  296. package/scripts/install.ps1 +139 -0
  297. package/scripts/install.sh +268 -0
  298. package/scripts/lib/beads-migrate-to-dolt.mjs +503 -0
  299. package/scripts/lib/release-asset.mjs +84 -0
  300. package/scripts/parity-check.mjs +145 -0
  301. package/scripts/parity-check.test.mjs +58 -0
  302. package/scripts/pin-agentic-workflow-images.js +112 -0
  303. package/scripts/pr-coordinator.sh +3 -0
  304. package/scripts/preflight-sonar.eslint.config.mjs +44 -0
  305. package/scripts/preflight.sh +108 -0
  306. package/scripts/protected-state-check.js +104 -0
  307. package/scripts/smart-status-score.js +31 -0
  308. package/scripts/smart-status-sessions.js +51 -0
  309. package/scripts/smart-status.sh +117 -369
  310. package/scripts/spikes/config-race-bench.js +111 -0
  311. package/scripts/spikes/harness-capability-matrix.js +13 -0
  312. package/scripts/spikes/patch-anchor-stability-bench.js +125 -0
  313. package/scripts/spikes/protected-path-manifest.js +20 -0
  314. package/scripts/spikes/skill-auto-invoke-parity.js +292 -0
  315. package/scripts/sync-agent-skills.js +62 -0
  316. package/scripts/sync-agentic-workflow.js +48 -0
  317. package/scripts/sync-utils.sh +3 -0
  318. package/scripts/test-ci-shard.js +251 -0
  319. package/scripts/test-dashboard.js +188 -52
  320. package/scripts/test-full-suite.js +186 -0
  321. package/scripts/test-profile.js +278 -0
  322. package/scripts/test.js +302 -28
  323. package/scripts/validate.js +143 -0
  324. package/scripts/validate.sh +18 -1
  325. package/skills/claim-safety/SKILL.md +102 -0
  326. package/skills/claim-safety/evals/evals.json +46 -0
  327. package/{.github/prompts/dev.prompt.md → skills/dev/SKILL.md} +46 -52
  328. package/skills/dev/evals/evals.json +50 -0
  329. package/skills/hermes-forge/SKILL.md +185 -0
  330. package/skills/hermes-forge/evals/evals.json +46 -0
  331. package/skills/issue-basics/SKILL.md +111 -0
  332. package/skills/issue-basics/evals/evals.json +46 -0
  333. package/skills/kernel/SKILL.md +166 -0
  334. package/skills/kernel/evals/evals.json +50 -0
  335. package/skills/memory/SKILL.md +102 -0
  336. package/skills/parallel-deep-research/SKILL.md +14 -11
  337. package/skills/parallel-deep-research/evals/evals.json +11 -27
  338. package/{.github/prompts/plan.prompt.md → skills/plan/SKILL.md} +134 -159
  339. package/skills/plan/evals/evals.json +42 -0
  340. package/skills/research/SKILL.md +195 -0
  341. package/skills/research/evals/evals.json +42 -0
  342. package/{.github/prompts/review.prompt.md → skills/review/SKILL.md} +98 -62
  343. package/skills/review/evals/evals.json +42 -0
  344. package/skills/rollback/SKILL.md +110 -0
  345. package/skills/rollback/evals/evals.json +46 -0
  346. package/skills/rollback/references/methods.md +204 -0
  347. package/{.cursor/commands/rollback.md → skills/rollback/references/workflow-integration.md} +10 -284
  348. package/skills/shepherd/SKILL.md +66 -0
  349. package/skills/shepherd/evals/evals.json +42 -0
  350. package/skills/ship/SKILL.md +251 -0
  351. package/skills/ship/evals/evals.json +42 -0
  352. package/skills/smith/SKILL.md +142 -0
  353. package/skills/smith/evals/evals.json +46 -0
  354. package/skills/smith/references/autonomy-and-gates.md +94 -0
  355. package/{.github/prompts/sonarcloud.prompt.md → skills/sonarcloud/SKILL.md} +14 -3
  356. package/skills/sonarcloud/evals/evals.json +46 -0
  357. package/skills/sonarcloud-analysis/SKILL.md +18 -13
  358. package/skills/sonarcloud-analysis/evals/evals.json +11 -15
  359. package/skills/status/SKILL.md +102 -0
  360. package/skills/status/evals/evals.json +50 -0
  361. package/skills/triage-ready/SKILL.md +121 -0
  362. package/skills/triage-ready/evals/evals.json +42 -0
  363. package/{.github/prompts/validate.prompt.md → skills/validate/SKILL.md} +52 -29
  364. package/skills/validate/evals/evals.json +42 -0
  365. package/skills/verify/SKILL.md +299 -0
  366. package/skills/verify/evals/evals.json +50 -0
  367. package/.claude/commands/dev.md +0 -345
  368. package/.claude/commands/plan.md +0 -566
  369. package/.claude/commands/premerge.md +0 -186
  370. package/.claude/commands/research.md +0 -42
  371. package/.claude/commands/review.md +0 -451
  372. package/.claude/commands/rollback.md +0 -721
  373. package/.claude/commands/ship.md +0 -213
  374. package/.claude/commands/sonarcloud.md +0 -152
  375. package/.claude/commands/status.md +0 -90
  376. package/.claude/commands/validate.md +0 -288
  377. package/.claude/commands/verify.md +0 -269
  378. package/.claude/rules/workflow.md +0 -121
  379. package/.cline/workflows/dev.md +0 -342
  380. package/.cline/workflows/plan.md +0 -563
  381. package/.cline/workflows/premerge.md +0 -183
  382. package/.cline/workflows/research.md +0 -39
  383. package/.cline/workflows/review.md +0 -448
  384. package/.cline/workflows/rollback.md +0 -718
  385. package/.cline/workflows/ship.md +0 -210
  386. package/.cline/workflows/sonarcloud.md +0 -146
  387. package/.cline/workflows/status.md +0 -87
  388. package/.cline/workflows/validate.md +0 -285
  389. package/.cline/workflows/verify.md +0 -266
  390. package/.codex/config.toml +0 -11
  391. package/.codex/skills/dev/SKILL.md +0 -345
  392. package/.codex/skills/plan/SKILL.md +0 -566
  393. package/.codex/skills/premerge/SKILL.md +0 -186
  394. package/.codex/skills/research/SKILL.md +0 -42
  395. package/.codex/skills/review/SKILL.md +0 -451
  396. package/.codex/skills/rollback/SKILL.md +0 -721
  397. package/.codex/skills/ship/SKILL.md +0 -213
  398. package/.codex/skills/sonarcloud/SKILL.md +0 -149
  399. package/.codex/skills/status/SKILL.md +0 -90
  400. package/.codex/skills/validate/SKILL.md +0 -288
  401. package/.codex/skills/verify/SKILL.md +0 -269
  402. package/.cursor/commands/dev.md +0 -342
  403. package/.cursor/commands/plan.md +0 -563
  404. package/.cursor/commands/premerge.md +0 -183
  405. package/.cursor/commands/research.md +0 -39
  406. package/.cursor/commands/review.md +0 -448
  407. package/.cursor/commands/ship.md +0 -210
  408. package/.cursor/commands/sonarcloud.md +0 -146
  409. package/.cursor/commands/status.md +0 -87
  410. package/.cursor/commands/validate.md +0 -285
  411. package/.cursor/commands/verify.md +0 -266
  412. package/.cursorrules +0 -149
  413. package/.github/prompts/premerge.prompt.md +0 -188
  414. package/.github/prompts/research.prompt.md +0 -44
  415. package/.github/prompts/rollback.prompt.md +0 -723
  416. package/.github/prompts/ship.prompt.md +0 -215
  417. package/.github/prompts/status.prompt.md +0 -92
  418. package/.github/prompts/verify.prompt.md +0 -271
  419. package/.github/workflows/beads-to-github.yml +0 -56
  420. package/.github/workflows/github-to-beads.yml +0 -97
  421. package/.kilocode/workflows/dev.md +0 -346
  422. package/.kilocode/workflows/plan.md +0 -567
  423. package/.kilocode/workflows/premerge.md +0 -187
  424. package/.kilocode/workflows/research.md +0 -43
  425. package/.kilocode/workflows/review.md +0 -452
  426. package/.kilocode/workflows/rollback.md +0 -722
  427. package/.kilocode/workflows/ship.md +0 -214
  428. package/.kilocode/workflows/sonarcloud.md +0 -150
  429. package/.kilocode/workflows/status.md +0 -91
  430. package/.kilocode/workflows/validate.md +0 -289
  431. package/.kilocode/workflows/verify.md +0 -270
  432. package/.opencode/commands/dev.md +0 -345
  433. package/.opencode/commands/plan.md +0 -566
  434. package/.opencode/commands/premerge.md +0 -186
  435. package/.opencode/commands/research.md +0 -42
  436. package/.opencode/commands/review.md +0 -451
  437. package/.opencode/commands/rollback.md +0 -721
  438. package/.opencode/commands/ship.md +0 -213
  439. package/.opencode/commands/sonarcloud.md +0 -149
  440. package/.opencode/commands/status.md +0 -90
  441. package/.opencode/commands/validate.md +0 -288
  442. package/.opencode/commands/verify.md +0 -269
  443. package/.roo/commands/dev.md +0 -346
  444. package/.roo/commands/plan.md +0 -567
  445. package/.roo/commands/premerge.md +0 -187
  446. package/.roo/commands/research.md +0 -43
  447. package/.roo/commands/review.md +0 -452
  448. package/.roo/commands/rollback.md +0 -722
  449. package/.roo/commands/ship.md +0 -214
  450. package/.roo/commands/sonarcloud.md +0 -150
  451. package/.roo/commands/status.md +0 -91
  452. package/.roo/commands/validate.md +0 -289
  453. package/.roo/commands/verify.md +0 -270
  454. package/docs/BEADS_GITHUB_SYNC.md +0 -255
  455. package/docs/GREPTILE_SETUP.md +0 -400
  456. package/docs/MANUAL_REVIEW_GUIDE.md +0 -106
  457. package/docs/SETUP.md +0 -663
  458. package/docs/VALIDATION.md +0 -363
  459. package/lib/agents/cline.plugin.json +0 -29
  460. package/lib/agents/copilot.plugin.json +0 -24
  461. package/lib/agents/kilocode.plugin.json +0 -22
  462. package/lib/agents/opencode.plugin.json +0 -23
  463. package/lib/agents/roo.plugin.json +0 -30
  464. package/lib/beads-health-check.js +0 -143
  465. package/lib/commands/commands-reset.js +0 -147
  466. package/opencode.json +0 -67
  467. package/scripts/beads-context.test.js +0 -567
  468. package/scripts/github-beads-sync/comment.mjs +0 -64
  469. package/scripts/github-beads-sync/config.mjs +0 -148
  470. package/scripts/github-beads-sync/github-api.mjs +0 -131
  471. package/scripts/github-beads-sync/index.mjs +0 -332
  472. package/scripts/github-beads-sync/label-mapper.mjs +0 -54
  473. package/scripts/github-beads-sync/mapping.mjs +0 -78
  474. package/scripts/github-beads-sync/reverse-sync-cli.mjs +0 -31
  475. package/scripts/github-beads-sync/reverse-sync.mjs +0 -138
  476. package/scripts/github-beads-sync/run-bd.mjs +0 -161
  477. package/scripts/github-beads-sync/sanitize.mjs +0 -121
  478. package/scripts/github-beads-sync.config.json +0 -26
  479. package/scripts/sync-commands.js +0 -600
@@ -0,0 +1,598 @@
1
+ const fs = require('node:fs');
2
+ const path = require('node:path');
3
+ const readline = require('node:readline');
4
+ const YAML = require('yaml');
5
+
6
+ const {
7
+ ADOPTION_PROFILE_NAMES,
8
+ buildAdoptionConfig,
9
+ renderAdoptionConfigYaml,
10
+ } = require('../adoption-profiles');
11
+
12
+ const PROFILE_REQUIRED_ERROR = '--profile requires a non-empty value: minimal, standard, or full.';
13
+ const CLASSIFICATION_REQUIRED_ERROR = '--classification requires a non-empty value: critical, standard, or refactor.';
14
+ const PROFILE_SHORTCUTS = Object.freeze({
15
+ '--minimal': 'minimal',
16
+ '--standard': 'standard',
17
+ '--full': 'full',
18
+ });
19
+ const CLASSIFICATIONS = Object.freeze(['critical', 'standard', 'refactor']);
20
+ const DETECTABLE_HARNESS_TARGETS = Object.freeze(['claude', 'cursor', 'codex']);
21
+ const HARNESS_TARGETS = Object.freeze(['claude', 'cursor', 'codex']);
22
+ const HARNESS_REQUIRED_ERROR = `--harness requires a non-empty value: ${HARNESS_TARGETS.join(', ')}.`;
23
+
24
+ /** Return the command help text shown by the registry. */
25
+ function usage() {
26
+ return [
27
+ 'Usage: forge init [--profile minimal|standard|full] [--classification critical|standard|refactor] [--harness claude,cursor,codex] [--yes] [--force] [--dry-run]',
28
+ '',
29
+ 'Initialize the day-one .forge skeleton for a fresh repository.',
30
+ ].join('\n');
31
+ }
32
+
33
+ /** Normalize a profile flag value while preserving empty-string validation. */
34
+ function normalizeProfile(value) {
35
+ if (typeof value !== 'string') return value ?? null;
36
+ const trimmed = value.trim();
37
+ return trimmed.length > 0 ? trimmed : '';
38
+ }
39
+
40
+ /** Apply a parsed adoption profile value to the mutable parse result. */
41
+ function setProfile(parsed, value) {
42
+ const profile = normalizeProfile(value);
43
+ if (profile === '') {
44
+ parsed.error = PROFILE_REQUIRED_ERROR;
45
+ parsed.profile = null;
46
+ return;
47
+ }
48
+ parsed.profile = profile;
49
+ }
50
+
51
+ /** Normalize a classification flag or wizard answer. */
52
+ function normalizeClassification(value) {
53
+ if (typeof value !== 'string') return value ?? null;
54
+ const trimmed = value.trim().toLowerCase();
55
+ return trimmed.length > 0 ? trimmed : '';
56
+ }
57
+
58
+ /** Validate and apply a default workflow classification. */
59
+ function setClassification(parsed, value) {
60
+ const classification = normalizeClassification(value);
61
+ if (classification === '') {
62
+ parsed.error = CLASSIFICATION_REQUIRED_ERROR;
63
+ parsed.classification = null;
64
+ return;
65
+ }
66
+ if (!CLASSIFICATIONS.includes(classification)) {
67
+ parsed.error = `Unknown classification '${classification}'. Choose one of: ${CLASSIFICATIONS.join(', ')}.`;
68
+ parsed.classification = null;
69
+ return;
70
+ }
71
+ parsed.classification = classification;
72
+ }
73
+
74
+ /** Convert comma-separated or array harness input into normalized target names. */
75
+ function normalizeHarnessTargets(value) {
76
+ if (Array.isArray(value)) {
77
+ return value.flatMap(item => normalizeHarnessTargets(item));
78
+ }
79
+ if (typeof value !== 'string') return [];
80
+ return value
81
+ .split(',')
82
+ .map(item => item.trim().toLowerCase())
83
+ .filter(Boolean);
84
+ }
85
+
86
+ /** Validate and apply selected harness targets. */
87
+ function setHarnessTargets(parsed, value) {
88
+ const targets = [...new Set(normalizeHarnessTargets(value))];
89
+ if (targets.length === 0) {
90
+ parsed.error = HARNESS_REQUIRED_ERROR;
91
+ parsed.harnessTargets = null;
92
+ return;
93
+ }
94
+ const unknown = targets.find(target => !HARNESS_TARGETS.includes(target));
95
+ if (unknown) {
96
+ parsed.error = `Unknown harness target '${unknown}'. Choose from: ${HARNESS_TARGETS.join(', ')}.`;
97
+ parsed.harnessTargets = null;
98
+ return;
99
+ }
100
+ parsed.harnessTargets = targets;
101
+ }
102
+
103
+ /** Consume --profile syntax from argv and return the consumed index. */
104
+ function consumeProfileArg(args, index, parsed) {
105
+ const arg = args[index];
106
+ if (arg === '--profile') {
107
+ const value = args[index + 1];
108
+ if (typeof value === 'string' && !value.startsWith('--')) {
109
+ setProfile(parsed, value);
110
+ return index + 1;
111
+ }
112
+ parsed.error = PROFILE_REQUIRED_ERROR;
113
+ return index;
114
+ }
115
+
116
+ setProfile(parsed, arg.slice('--profile='.length));
117
+ return index;
118
+ }
119
+
120
+ /** Consume --classification syntax from argv and return the consumed index. */
121
+ function consumeClassificationArg(args, index, parsed) {
122
+ const arg = args[index];
123
+ if (arg === '--classification') {
124
+ const value = args[index + 1];
125
+ if (typeof value === 'string' && !value.startsWith('--')) {
126
+ setClassification(parsed, value);
127
+ return index + 1;
128
+ }
129
+ parsed.error = CLASSIFICATION_REQUIRED_ERROR;
130
+ return index;
131
+ }
132
+
133
+ setClassification(parsed, arg.slice('--classification='.length));
134
+ return index;
135
+ }
136
+
137
+ /** Consume --harness syntax from argv and return the consumed index. */
138
+ function consumeHarnessArg(args, index, parsed) {
139
+ const arg = args[index];
140
+ if (arg === '--harness') {
141
+ const value = args[index + 1];
142
+ if (typeof value === 'string' && !value.startsWith('--')) {
143
+ setHarnessTargets(parsed, value);
144
+ return index + 1;
145
+ }
146
+ parsed.error = HARNESS_REQUIRED_ERROR;
147
+ return index;
148
+ }
149
+
150
+ setHarnessTargets(parsed, arg.slice('--harness='.length));
151
+ return index;
152
+ }
153
+
154
+ /** Apply profile shortcut flags such as --minimal and --full. */
155
+ function applyProfileShortcut(arg, parsed) {
156
+ const profile = PROFILE_SHORTCUTS[arg];
157
+ if (profile) {
158
+ parsed.profile = profile;
159
+ parsed.yes = true;
160
+ }
161
+ return Boolean(profile);
162
+ }
163
+
164
+ /** Parse init-specific flags after global CLI flag handling. */
165
+ function parseInitFlags(args = [], flags = {}) {
166
+ const parsed = {
167
+ profile: null,
168
+ error: null,
169
+ yes: Boolean(flags.yes || flags.nonInteractive),
170
+ force: Boolean(flags.force),
171
+ dryRun: Boolean(flags.dryRun),
172
+ classification: null,
173
+ harnessTargets: null,
174
+ railsConfirmed: Boolean(flags.yes || flags.nonInteractive),
175
+ };
176
+
177
+ if (Object.hasOwn(flags, 'profile')) {
178
+ setProfile(parsed, flags.profile);
179
+ }
180
+ if (Object.hasOwn(flags, 'classification')) {
181
+ setClassification(parsed, flags.classification);
182
+ }
183
+ if (Object.hasOwn(flags, 'harness')) {
184
+ setHarnessTargets(parsed, flags.harness);
185
+ }
186
+
187
+ let index = 0;
188
+ while (index < args.length) {
189
+ const arg = args[index];
190
+ if (arg === '--profile' || arg.startsWith('--profile=')) {
191
+ index = consumeProfileArg(args, index, parsed) + 1;
192
+ continue;
193
+ } else if (arg === '--classification' || arg.startsWith('--classification=')) {
194
+ index = consumeClassificationArg(args, index, parsed) + 1;
195
+ continue;
196
+ } else if (arg === '--harness' || arg.startsWith('--harness=')) {
197
+ index = consumeHarnessArg(args, index, parsed) + 1;
198
+ continue;
199
+ } else if (applyProfileShortcut(arg, parsed)) {
200
+ index += 1;
201
+ continue;
202
+ } else if (arg === '--yes' || arg === '-y') {
203
+ parsed.yes = true;
204
+ parsed.railsConfirmed = true;
205
+ } else if (arg === '--force') {
206
+ parsed.force = true;
207
+ } else if (arg === '--dry-run') {
208
+ parsed.dryRun = true;
209
+ }
210
+ index += 1;
211
+ }
212
+
213
+ return parsed;
214
+ }
215
+
216
+ /** Create one readline prompt interface for a multi-question wizard. */
217
+ function makePromptInterface() {
218
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
219
+ return {
220
+ ask(question) {
221
+ return new Promise((resolve) => {
222
+ rl.question(question, (answer) => {
223
+ resolve(answer);
224
+ });
225
+ });
226
+ },
227
+ close() {
228
+ rl.close();
229
+ },
230
+ };
231
+ }
232
+
233
+ /** Resolve the adoption profile while preserving non-interactive defaults. */
234
+ async function resolveProfile(parsed) {
235
+ if (parsed.profile) {
236
+ return parsed.profile;
237
+ }
238
+ return 'standard';
239
+ }
240
+
241
+ /** Validate a resolved adoption profile name before prompting the user. */
242
+ function validateProfile(profile) {
243
+ if (ADOPTION_PROFILE_NAMES.includes(profile)) {
244
+ return null;
245
+ }
246
+ return `Unknown adoption profile '${profile}'. Available profiles: ${ADOPTION_PROFILE_NAMES.join(', ')}`;
247
+ }
248
+
249
+ /** Return true only when a path exists and is a directory. */
250
+ function isDirectory(filePath) {
251
+ try {
252
+ return fs.statSync(filePath).isDirectory();
253
+ } catch (_err) {
254
+ return false;
255
+ }
256
+ }
257
+
258
+ /** Detect active harnesses from day-one filesystem marker directories. */
259
+ function detectHarnessTargets(projectRoot = process.cwd()) {
260
+ return DETECTABLE_HARNESS_TARGETS.filter(target => isDirectory(path.join(projectRoot, `.${target}`)));
261
+ }
262
+
263
+ /** Read profile-defined harness targets for explicit profile selections. */
264
+ function getProfileHarnessTargets(profile) {
265
+ const targets = buildAdoptionConfig(profile).adapters?.harness?.targets;
266
+ return Array.isArray(targets) ? targets : [];
267
+ }
268
+
269
+ /** Render the empty patch intent scaffold. */
270
+ function renderPatchMd() {
271
+ return [
272
+ '# Forge Patch Intent',
273
+ '',
274
+ '<!--',
275
+ 'This file is intentionally empty for day-one setup.',
276
+ 'Use it later to document local Forge overrides before applying them.',
277
+ '-->',
278
+ '',
279
+ ].join('\n');
280
+ }
281
+
282
+ /** Append an existing file or directory glob to the protected-path manifest. */
283
+ function addExistingPath(entries, projectRoot, protectedPath, reason) {
284
+ const absolutePath = projectRoot ? path.join(projectRoot, protectedPath) : null;
285
+ if (!absolutePath || !fs.existsSync(absolutePath)) {
286
+ return;
287
+ }
288
+ const manifestPath = isDirectory(absolutePath) ? `${protectedPath}/**` : protectedPath;
289
+ entries.push({ path: manifestPath.replace(/\\/g, '/'), reason });
290
+ }
291
+
292
+ /** Add only selected and existing harness paths to the manifest. */
293
+ function addSelectedHarnessPaths(entries, { projectRoot, harnessTargets }) {
294
+ if (!projectRoot) return;
295
+ if (fs.existsSync(path.join(projectRoot, 'AGENTS.md'))) {
296
+ entries.push({ path: 'AGENTS.md', reason: 'Agent workflow instructions' });
297
+ }
298
+
299
+ if (harnessTargets.includes('claude')) {
300
+ addExistingPath(entries, projectRoot, 'CLAUDE.md', 'Claude harness instructions');
301
+ addExistingPath(entries, projectRoot, '.claude', 'Claude harness directory');
302
+ }
303
+ if (harnessTargets.includes('cursor')) {
304
+ addExistingPath(entries, projectRoot, '.cursor', 'Cursor harness directory');
305
+ }
306
+ if (harnessTargets.includes('codex')) {
307
+ addExistingPath(entries, projectRoot, '.codex', 'Codex harness directory');
308
+ }
309
+ }
310
+
311
+ /** Render the protected-path manifest scaffold without enforcing it. */
312
+ function renderProtectedPathsYaml({ classification, harnessTargets, projectRoot = null }) {
313
+ const paths = [
314
+ { path: '.forge/config.yaml', reason: 'Forge runtime configuration' },
315
+ { path: '.forge/patch.md', reason: 'Local patch intent scaffold' },
316
+ { path: '.forge/protected-paths.yaml', reason: 'Protected path manifest scaffold' },
317
+ ];
318
+ addSelectedHarnessPaths(paths, { projectRoot, harnessTargets });
319
+
320
+ return YAML.stringify({
321
+ kind: 'forge.protectedPaths',
322
+ version: 1,
323
+ classification,
324
+ harness: {
325
+ targets: harnessTargets,
326
+ },
327
+ paths,
328
+ });
329
+ }
330
+
331
+ /** Render config.yaml by layering day-one choices over an adoption profile. */
332
+ function renderDayOneConfigYaml({ profile, classification, harnessTargets, railsConfirmed }) {
333
+ const config = YAML.parse(renderAdoptionConfigYaml(profile));
334
+ config.workflow = config.workflow || {};
335
+ config.workflow.classification = { default: classification };
336
+ config.layer1Rails = {
337
+ confirmed: railsConfirmed,
338
+ rails: [
339
+ 'tdd_intent',
340
+ 'secret_scan',
341
+ 'branch_protection',
342
+ 'signed_commits',
343
+ 'schema_integrity',
344
+ ],
345
+ };
346
+ config.adapters = config.adapters || {};
347
+ config.adapters.harness = {
348
+ enabled: harnessTargets.length > 0,
349
+ targets: harnessTargets,
350
+ };
351
+ config.protectedPaths = [
352
+ ...new Set([
353
+ ...(Array.isArray(config.protectedPaths) ? config.protectedPaths : []),
354
+ '.forge/config.yaml',
355
+ '.forge/patch.md',
356
+ '.forge/protected-paths.yaml',
357
+ ]),
358
+ ];
359
+ return YAML.stringify(config);
360
+ }
361
+
362
+ /** Format generated file paths relative to the target project root. */
363
+ function relativeForgePath(projectRoot, filePath) {
364
+ return path.relative(projectRoot, filePath).replace(/\\/g, '/');
365
+ }
366
+
367
+ /** Build the complete set of day-one generated files. */
368
+ function buildGeneratedFiles(projectRoot, choices) {
369
+ const forgeDir = path.join(projectRoot, '.forge');
370
+ return [
371
+ {
372
+ path: path.join(forgeDir, 'config.yaml'),
373
+ content: renderDayOneConfigYaml(choices),
374
+ },
375
+ {
376
+ path: path.join(forgeDir, 'patch.md'),
377
+ content: renderPatchMd(),
378
+ },
379
+ {
380
+ path: path.join(forgeDir, 'protected-paths.yaml'),
381
+ content: renderProtectedPathsYaml({ ...choices, projectRoot }),
382
+ },
383
+ ];
384
+ }
385
+
386
+ /** Filter generated files down to paths that already exist. */
387
+ function existingGeneratedFiles(files) {
388
+ return files.filter(file => fs.existsSync(file.path));
389
+ }
390
+
391
+ /** Build a no-clobber repair message for existing generated files. */
392
+ function formatNoClobberError(projectRoot, files) {
393
+ const names = files.map(file => relativeForgePath(projectRoot, file.path)).join(', ');
394
+ const plural = files.length !== 1;
395
+ return `${names} already ${plural ? 'exist' : 'exists'}. Re-run with --force to overwrite ${plural ? 'them' : 'it'}, or move the existing ${plural ? 'files' : 'file'} and run forge init again.`;
396
+ }
397
+
398
+ /** Resolve the workflow classification from flags, wizard input, or defaults. */
399
+ async function resolveClassificationChoice(parsed, interactive, prompt) {
400
+ if (parsed.classification) {
401
+ return { classification: parsed.classification };
402
+ }
403
+ if (!interactive) {
404
+ return { classification: 'standard' };
405
+ }
406
+
407
+ const answer = await prompt(`Select default classification (${CLASSIFICATIONS.join('/')}), default standard: `);
408
+ setClassification(parsed, answer.trim() || 'standard');
409
+ if (parsed.error) {
410
+ return { error: parsed.error };
411
+ }
412
+ return { classification: parsed.classification };
413
+ }
414
+
415
+ /** Resolve Layer 1 rail confirmation from flags, wizard input, or defaults. */
416
+ async function resolveRailsConfirmation(parsed, interactive, prompt) {
417
+ if (parsed.railsConfirmed) {
418
+ return { railsConfirmed: true };
419
+ }
420
+ if (!interactive) {
421
+ return { railsConfirmed: true };
422
+ }
423
+
424
+ const answer = await prompt('Confirm Layer 1 rails are required for this repo? (Y/n): ');
425
+ const normalized = answer.trim().toLowerCase();
426
+ const railsConfirmed = normalized === '' || normalized === 'y' || normalized === 'yes';
427
+ if (railsConfirmed) {
428
+ return { railsConfirmed: true };
429
+ }
430
+ return {
431
+ error: 'Layer 1 rails must be confirmed before initialization. Re-run forge init and answer yes to continue.',
432
+ };
433
+ }
434
+
435
+ /** Resolve harness targets from flags, filesystem detection, wizard input, or defaults. */
436
+ async function resolveHarnessTargetChoice(parsed, interactive, prompt, projectRoot, profile) {
437
+ if (parsed.harnessTargets) {
438
+ return { harnessTargets: parsed.harnessTargets };
439
+ }
440
+
441
+ const detectedHarnessTargets = detectHarnessTargets(projectRoot);
442
+ const profileHarnessTargets = parsed.profile ? getProfileHarnessTargets(profile) : [];
443
+ const fallbackHarnessTargets = profileHarnessTargets.length > 0 || parsed.profile ? profileHarnessTargets : ['codex'];
444
+ const defaultHarnessTargets = detectedHarnessTargets.length > 0
445
+ ? detectedHarnessTargets
446
+ : fallbackHarnessTargets;
447
+ if (!interactive) {
448
+ return { harnessTargets: defaultHarnessTargets };
449
+ }
450
+
451
+ const defaultValue = defaultHarnessTargets.join(',');
452
+ const answer = await prompt(`Select harness targets (${HARNESS_TARGETS.join(',')}), default ${defaultValue}: `);
453
+ if (answer.trim().length === 0) {
454
+ return { harnessTargets: defaultHarnessTargets };
455
+ }
456
+
457
+ setHarnessTargets(parsed, answer.trim());
458
+ if (parsed.error) {
459
+ return { error: parsed.error };
460
+ }
461
+ return { harnessTargets: parsed.harnessTargets };
462
+ }
463
+
464
+ /** Resolve profile, classification, L1 confirmation, and harness targets. */
465
+ async function resolveChoices(parsed, projectRoot, deps = {}, profile = null) {
466
+ const stdinIsTTY = deps.stdinIsTTY ?? process.stdin.isTTY;
467
+ const interactive = !parsed.yes && stdinIsTTY;
468
+ const promptInterface = !deps.prompt && interactive ? makePromptInterface() : null;
469
+ const prompt = deps.prompt || (promptInterface ? promptInterface.ask : null);
470
+ const resolvedProfile = profile || await resolveProfile(parsed);
471
+
472
+ try {
473
+ const classificationChoice = await resolveClassificationChoice(parsed, interactive, prompt);
474
+ if (classificationChoice.error) {
475
+ return { error: classificationChoice.error };
476
+ }
477
+
478
+ const railsChoice = await resolveRailsConfirmation(parsed, interactive, prompt);
479
+ if (railsChoice.error) {
480
+ return { error: railsChoice.error };
481
+ }
482
+
483
+ const harnessChoice = await resolveHarnessTargetChoice(parsed, interactive, prompt, projectRoot, resolvedProfile);
484
+ if (harnessChoice.error) {
485
+ return { error: harnessChoice.error };
486
+ }
487
+
488
+ return {
489
+ profile: resolvedProfile,
490
+ classification: classificationChoice.classification,
491
+ railsConfirmed: railsChoice.railsConfirmed,
492
+ harnessTargets: harnessChoice.harnessTargets,
493
+ };
494
+ } finally {
495
+ if (promptInterface) {
496
+ promptInterface.close();
497
+ }
498
+ }
499
+ }
500
+
501
+ /** Execute forge init for the target project root. */
502
+ async function handler(args, flags, projectRoot = process.cwd(), deps = {}) {
503
+ const parsed = parseInitFlags(args, flags);
504
+ if (parsed.error) {
505
+ return { success: false, error: parsed.error };
506
+ }
507
+ const profile = await resolveProfile(parsed);
508
+ const profileError = validateProfile(profile);
509
+ if (profileError) {
510
+ return {
511
+ success: false,
512
+ error: profileError,
513
+ };
514
+ }
515
+ const choices = await resolveChoices(parsed, projectRoot, deps, profile);
516
+ if (choices.error) {
517
+ return { success: false, error: choices.error };
518
+ }
519
+ const forgeDir = path.join(projectRoot, '.forge');
520
+ const files = buildGeneratedFiles(projectRoot, choices);
521
+
522
+ if (parsed.dryRun) {
523
+ const previewFile = files[0];
524
+ return {
525
+ success: true,
526
+ ...choices,
527
+ files: [relativeForgePath(projectRoot, previewFile.path)],
528
+ output: previewFile.content,
529
+ };
530
+ }
531
+
532
+ const existingFiles = existingGeneratedFiles(files);
533
+ if (existingFiles.length > 0 && !parsed.force) {
534
+ return {
535
+ success: false,
536
+ error: formatNoClobberError(projectRoot, existingFiles),
537
+ };
538
+ }
539
+
540
+ fs.mkdirSync(forgeDir, { recursive: true });
541
+ for (const file of files) {
542
+ fs.writeFileSync(file.path, file.content, 'utf8');
543
+ }
544
+
545
+ // Close the onboarding loop that a bare `forge init` used to leave open:
546
+ // 1. install git hooks so stage commands are not HOOKS_NOT_ACTIVE-blocked, and
547
+ // 2. import any existing Beads store into the Kernel.
548
+ // Both reuse setup's real implementations (overridable via deps for tests) and
549
+ // degrade to a warning rather than failing init.
550
+ const installHooks = deps.installHooks
551
+ || ((root) => require('./setup').ensureGitHooksInstalled(root));
552
+ const autoMigrateBeads = deps.autoMigrateBeads
553
+ || ((root) => require('./migrate').autoMigrateBeadsIfPresent(root));
554
+ try {
555
+ await installHooks(projectRoot);
556
+ } catch (err) {
557
+ console.warn(`Warning: git hook installation skipped: ${err.message}`);
558
+ }
559
+ try {
560
+ await autoMigrateBeads(projectRoot);
561
+ } catch (err) {
562
+ console.warn(`Warning: Beads → Kernel migration skipped: ${err.message}`);
563
+ }
564
+
565
+ console.log(`Initialized Forge adoption profile '${profile}' at .forge/`);
566
+ console.log(`Classification: ${choices.classification}`);
567
+ console.log(`Harness targets: ${choices.harnessTargets.join(', ')}`);
568
+ console.log('Inspect with: forge options lint && forge options diff');
569
+
570
+ return {
571
+ success: true,
572
+ ...choices,
573
+ files: files.map(file => relativeForgePath(projectRoot, file.path)),
574
+ };
575
+ }
576
+
577
+ module.exports = {
578
+ name: 'init',
579
+ description: 'Initialize Forge adoption config in a fresh repository',
580
+ usage: usage(),
581
+ flags: {
582
+ '--profile <name>': 'Adoption profile: minimal, standard, or full',
583
+ '--minimal': 'Shortcut for --profile minimal --yes',
584
+ '--standard': 'Shortcut for --profile standard --yes',
585
+ '--full': 'Shortcut for --profile full --yes',
586
+ '--classification <name>': 'Default workflow classification: critical, standard, or refactor',
587
+ '--harness <targets>': 'Comma-separated harness targets: claude, cursor, codex',
588
+ '--yes': 'Use the standard profile when no profile is provided',
589
+ '--force': 'Overwrite existing day-one .forge files',
590
+ '--dry-run': 'Print the generated config YAML without writing files',
591
+ },
592
+ handler,
593
+ detectHarnessTargets,
594
+ parseInitFlags,
595
+ renderDayOneConfigYaml,
596
+ renderPatchMd,
597
+ renderProtectedPathsYaml,
598
+ };
@@ -0,0 +1,79 @@
1
+ 'use strict';
2
+
3
+ const {
4
+ analyzeInsights,
5
+ formatInsightsText,
6
+ recordInsightDecision,
7
+ } = require('../insights');
8
+
9
+ const usage = [
10
+ 'Usage: forge insights [--limit N] [--min-count N] [--since YYYY-MM-DD] [--json]',
11
+ ' forge insights accept <candidate-id> [--note text]',
12
+ ' forge insights reject <candidate-id> [--note text]',
13
+ ].join('\n');
14
+
15
+ function readOption(args, name, fallback) {
16
+ const equals = args.find(arg => arg.startsWith(`${name}=`));
17
+ if (equals) return equals.slice(name.length + 1);
18
+ const index = args.indexOf(name);
19
+ if (index >= 0 && args[index + 1] && !args[index + 1].startsWith('-')) return args[index + 1];
20
+ return fallback;
21
+ }
22
+
23
+ function positionals(args) {
24
+ const values = [];
25
+ const flagsWithValues = new Set(['--limit', '--min-count', '--since', '--note', '--path', '-p']);
26
+ for (let index = 0; index < args.length; index++) {
27
+ const arg = args[index];
28
+ if (arg.startsWith('--') && arg.includes('=')) continue;
29
+ if (flagsWithValues.has(arg)) {
30
+ index += 1;
31
+ continue;
32
+ }
33
+ if (arg.startsWith('-')) continue;
34
+ values.push(arg);
35
+ }
36
+ return values;
37
+ }
38
+
39
+ async function handler(args, flags, projectRoot) {
40
+ const commandFlags = flags ?? {};
41
+ const [subcommand, candidateId] = positionals(args);
42
+ if (subcommand === 'accept' || subcommand === 'reject') {
43
+ if (!candidateId) {
44
+ return { success: false, error: usage };
45
+ }
46
+ const status = subcommand === 'accept' ? 'accepted' : 'rejected';
47
+ const decision = recordInsightDecision(projectRoot, candidateId, status, {
48
+ note: readOption(args, '--note', ''),
49
+ memory: commandFlags.memory,
50
+ });
51
+ return {
52
+ success: true,
53
+ output: `Insight ${candidateId} ${status}. Decision recorded at ${decision.key}.\n`,
54
+ };
55
+ }
56
+
57
+ const result = analyzeInsights(projectRoot, {
58
+ limit: readOption(args, '--limit', undefined),
59
+ minCount: readOption(args, '--min-count', undefined),
60
+ since: readOption(args, '--since', undefined),
61
+ });
62
+ if (args.includes('--review-feedback')) {
63
+ result.limitations = [
64
+ 'Compatibility note: --review-feedback now reads Beads interactions and issue evidence; external review-provider comments are not inferred.',
65
+ ...result.limitations,
66
+ ];
67
+ }
68
+ return {
69
+ success: true,
70
+ output: args.includes('--json') ? `${JSON.stringify(result, null, 2)}\n` : formatInsightsText(result),
71
+ };
72
+ }
73
+
74
+ module.exports = {
75
+ name: 'insights',
76
+ description: 'Detect recurring evidence patterns and suggest conservative workflow follow-ups',
77
+ usage,
78
+ handler,
79
+ };
@@ -2,4 +2,15 @@
2
2
 
3
3
  const { createIssueCommand } = require('./_issue');
4
4
 
5
- module.exports = createIssueCommand();
5
+ // Static registry export for `forge issue`. The handler delegates to the issue
6
+ // surface built by createIssueCommand() in _issue.js (called inline so the
7
+ // delegation is visible to the release-readiness surface check), which dispatches
8
+ // each subcommand through the shared backend abstraction.
9
+ module.exports = {
10
+ name: 'issue',
11
+ description: 'Manage issues through the Forge command surface',
12
+ usage: 'forge issue <create|update|claim|release|close|show|list|ready|search|stats|dep> [...]',
13
+ flags: {},
14
+ handler: (args, flags, projectRoot, opts = {}) =>
15
+ createIssueCommand().handler(args, flags, projectRoot, opts),
16
+ };