forge-workflow 0.0.10 → 0.1.0-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (468) hide show
  1. package/.claude/rules/{greptile-review-process.md → review-process.md} +56 -41
  2. package/.claude/scripts/{greptile-resolve.sh → review-resolve.sh} +13 -3
  3. package/.cursor/rules/permissions-guidance.mdc +2 -2
  4. package/.forge/hooks/check-tdd.js +82 -5
  5. package/.forge/hooks/forge-native-hook.js +431 -0
  6. package/.forge/protected-paths.yaml +157 -0
  7. package/AGENTS.md +151 -61
  8. package/CHANGELOG.md +709 -0
  9. package/CLAUDE.md +9 -118
  10. package/QUICKSTART.md +175 -0
  11. package/README.md +275 -365
  12. package/bin/forge-cmd.js +120 -9
  13. package/bin/forge-preflight.js +26 -5
  14. package/bin/forge.js +532 -489
  15. package/docs/INDEX.md +93 -0
  16. package/docs/PROJECT_DESIGN.md +685 -0
  17. package/docs/architecture/index.md +66 -0
  18. package/docs/architecture/notes/README.md +35 -0
  19. package/docs/architecture/subsystems/README.md +46 -0
  20. package/docs/forge/TOOLCHAIN.md +670 -0
  21. package/docs/forge/VALIDATION.md +82 -0
  22. package/docs/{AGENT_INSTALL_PROMPT.md → guides/AGENT_INSTALL_PROMPT.md} +3 -3
  23. package/docs/guides/BEADS_GITHUB_SYNC.md +32 -0
  24. package/docs/{ENHANCED_ONBOARDING.md → guides/ENHANCED_ONBOARDING.md} +16 -12
  25. package/docs/guides/GREPTILE_SETUP.md +46 -0
  26. package/docs/guides/MANUAL_REVIEW_GUIDE.md +58 -0
  27. package/docs/guides/MIGRATION.md +56 -0
  28. package/docs/guides/SETUP.md +121 -0
  29. package/docs/guides/SUPPORT.md +190 -0
  30. package/docs/guides/WORKFLOW_TEMPLATES.md +74 -0
  31. package/docs/guides/memory-backends.md +183 -0
  32. package/docs/reference/ADAPTERS.md +128 -0
  33. package/docs/reference/AGENT_SKILL_PARITY.md +175 -0
  34. package/docs/reference/COMMANDS.md +214 -0
  35. package/docs/reference/DECISION_DRIFT_GUARDS.md +97 -0
  36. package/docs/{EXAMPLES.md → reference/EXAMPLES.md} +7 -5
  37. package/docs/reference/FORGE_KERNEL_STORAGE_MODEL.md +135 -0
  38. package/docs/reference/HERMES_INTEGRATION.md +118 -0
  39. package/docs/reference/INSIGHTS_RECAP.md +63 -0
  40. package/docs/reference/INSTALL.md +164 -0
  41. package/docs/reference/KERNEL_TAXONOMY_VALIDATION.md +161 -0
  42. package/docs/reference/PROTECTED_PATH_MANIFEST.md +25 -0
  43. package/docs/reference/RELEASE.md +68 -0
  44. package/docs/reference/RESEARCH_TEMPLATE.md +292 -0
  45. package/docs/{ROADMAP.md → reference/ROADMAP.md} +12 -9
  46. package/docs/reference/SKILLS.md +35 -0
  47. package/docs/reference/STATUS_BOARD.md +80 -0
  48. package/docs/reference/TEMPLATES.md +106 -0
  49. package/docs/{TOOLCHAIN.md → reference/TOOLCHAIN.md} +62 -47
  50. package/docs/reference/VALIDATION.md +82 -0
  51. package/docs/reference/agent-permissions.md +169 -0
  52. package/docs/reference/beads-to-kernel-migration-ux.md +61 -0
  53. package/docs/reference/control-plane-guarantees.md +125 -0
  54. package/docs/reference/dependency-chain.md +331 -0
  55. package/docs/reference/forge-kernel-issue-command-contract.md +161 -0
  56. package/docs/reference/forge-kernel-schema.md +72 -0
  57. package/docs/reference/kernel-conflict-evaluators.md +27 -0
  58. package/docs/reference/patch-md-format.md +77 -0
  59. package/docs/reference/protected-state-surfaces.md +59 -0
  60. package/docs/reference/shepherd.md +155 -0
  61. package/docs/reference/superpowers-analysis.md +320 -0
  62. package/docs/reference/superpowers-integration-options.md +404 -0
  63. package/docs/reference/test-environment.md +519 -0
  64. package/docs/reference/upgrade-safety.md +59 -0
  65. package/lefthook.yml +18 -0
  66. package/lib/activation/ensure-forge-home.js +135 -0
  67. package/lib/adapter-cli.js +307 -0
  68. package/lib/adapters/beads-issue-adapter.js +127 -0
  69. package/lib/adapters/beads-kernel-compat.js +1109 -0
  70. package/lib/adapters/greptile-review-adapter.js +141 -0
  71. package/lib/adapters/kernel-issue-adapter.js +101 -0
  72. package/lib/adapters/pr-state-adapter.js +484 -0
  73. package/lib/adoption-profiles.js +139 -0
  74. package/lib/agents/README.md +2 -6
  75. package/lib/agents/claude.plugin.json +3 -8
  76. package/lib/agents/codex.plugin.json +9 -1
  77. package/lib/agents/cursor.plugin.json +2 -6
  78. package/lib/agents/hermes.plugin.json +22 -0
  79. package/lib/agents-config.js +39 -1236
  80. package/lib/audit-evidence.js +282 -0
  81. package/lib/beads-detect.js +60 -0
  82. package/lib/beads-nudge.js +91 -0
  83. package/lib/beads-setup.js +121 -0
  84. package/lib/beads-sync-scaffold.js +25 -101
  85. package/lib/codex-skills.js +51 -1
  86. package/lib/commands/_aliases.js +248 -0
  87. package/lib/commands/_issue.js +780 -77
  88. package/lib/commands/_manifest.js +93 -0
  89. package/lib/commands/_registry.js +99 -34
  90. package/lib/commands/_resolve-command-opts.js +230 -0
  91. package/lib/commands/_serve-security.js +270 -0
  92. package/lib/commands/adapter.js +12 -0
  93. package/lib/commands/add.js +118 -0
  94. package/lib/commands/audit.js +70 -0
  95. package/lib/commands/blocked.js +5 -0
  96. package/lib/commands/board.js +64 -0
  97. package/lib/commands/claim.js +21 -2
  98. package/lib/commands/claims.js +7 -0
  99. package/lib/commands/clean.js +485 -75
  100. package/lib/commands/close.js +2 -2
  101. package/lib/commands/comment.js +5 -0
  102. package/lib/commands/control.js +148 -0
  103. package/lib/commands/create.js +2 -2
  104. package/lib/commands/dev.js +185 -7
  105. package/lib/commands/doc-gate.js +336 -0
  106. package/lib/commands/doctor.js +156 -0
  107. package/lib/commands/explain.js +15 -0
  108. package/lib/commands/export.js +237 -0
  109. package/lib/commands/gate.js +209 -0
  110. package/lib/commands/hooks.js +377 -0
  111. package/lib/commands/inbox.js +118 -0
  112. package/lib/commands/init.js +604 -0
  113. package/lib/commands/insights.js +79 -0
  114. package/lib/commands/issue.js +12 -1
  115. package/lib/commands/issues.js +17 -0
  116. package/lib/commands/lint.js +5 -0
  117. package/lib/commands/list.js +2 -2
  118. package/lib/commands/memory.js +81 -0
  119. package/lib/commands/merge.js +312 -0
  120. package/lib/commands/migrate.js +362 -0
  121. package/lib/commands/new.js +12 -0
  122. package/lib/commands/options.js +241 -0
  123. package/lib/commands/orient.js +13 -0
  124. package/lib/commands/orphans.js +5 -0
  125. package/lib/commands/patch.js +67 -0
  126. package/lib/commands/plan.js +481 -29
  127. package/lib/commands/pr.js +88 -0
  128. package/lib/commands/preflight.js +211 -0
  129. package/lib/commands/prime.js +13 -0
  130. package/lib/commands/push.js +135 -2
  131. package/lib/commands/ready.js +2 -2
  132. package/lib/commands/recall.js +171 -0
  133. package/lib/commands/recap.js +75 -0
  134. package/lib/commands/recommend.js +0 -1
  135. package/lib/commands/release.js +104 -0
  136. package/lib/commands/remember.js +140 -0
  137. package/lib/commands/role.js +99 -0
  138. package/lib/commands/serve.js +581 -0
  139. package/lib/commands/setup.js +900 -971
  140. package/lib/commands/shepherd.js +501 -0
  141. package/lib/commands/ship.js +59 -1
  142. package/lib/commands/show.js +2 -2
  143. package/lib/commands/stage.js +192 -0
  144. package/lib/commands/stale.js +5 -0
  145. package/lib/commands/status.js +158 -21
  146. package/lib/commands/sync.js +34 -46
  147. package/lib/commands/team.js +4 -1
  148. package/lib/commands/test.js +43 -27
  149. package/lib/commands/update.js +2 -2
  150. package/lib/commands/upgrade.js +47 -0
  151. package/lib/commands/validate.js +43 -18
  152. package/lib/commands/worktree.js +362 -99
  153. package/lib/config-writer.js +202 -0
  154. package/lib/control-plane.js +236 -0
  155. package/lib/core/runtime-graph.js +977 -0
  156. package/lib/dep-guard/keyword-ripple.js +2 -2
  157. package/lib/deprecated-sync-cleanup.js +362 -0
  158. package/lib/detect-agent.js +2 -28
  159. package/lib/detect-worktree.js +35 -9
  160. package/lib/doc-gate/declaration.js +177 -0
  161. package/lib/doc-gate/detect.js +289 -0
  162. package/lib/doc-gate/gate.js +375 -0
  163. package/lib/doc-gate/okf-config.js +128 -0
  164. package/lib/doc-gate/okf.js +429 -0
  165. package/lib/docs-command.js +1161 -6
  166. package/lib/forge-issues.js +382 -11
  167. package/lib/forge-lock.js +262 -0
  168. package/lib/gate-events.js +192 -0
  169. package/lib/global-flags.js +104 -0
  170. package/lib/greptile-match.js +7 -63
  171. package/lib/grounding/context-events.js +230 -0
  172. package/lib/grounding/read-first.js +112 -0
  173. package/lib/harness-capability-matrix.js +380 -0
  174. package/lib/hook-global-installer.js +347 -0
  175. package/lib/hook-renderer.js +541 -0
  176. package/lib/inbox.js +391 -0
  177. package/lib/insights.js +397 -0
  178. package/lib/issue-adapter.js +156 -0
  179. package/lib/issue-backend.js +145 -0
  180. package/lib/issue-render.js +220 -0
  181. package/lib/kernel/backing-issue.js +311 -0
  182. package/lib/kernel/broker.js +1218 -0
  183. package/lib/kernel/cli-broker-factory.js +130 -0
  184. package/lib/kernel/conflict-signal.js +82 -0
  185. package/lib/kernel/evaluators.js +195 -0
  186. package/lib/kernel/fs-class.js +495 -0
  187. package/lib/kernel/issue-command-contract.js +559 -0
  188. package/lib/kernel/issue-id-resolver.js +186 -0
  189. package/lib/kernel/lease-enforcer.js +158 -0
  190. package/lib/kernel/migrations.js +333 -0
  191. package/lib/kernel/owned-kernel.js +43 -0
  192. package/lib/kernel/planning-buckets-schema.js +109 -0
  193. package/lib/kernel/projection-jsonl-writer.js +450 -0
  194. package/lib/kernel/readiness-model.js +329 -0
  195. package/lib/kernel/schema.js +356 -0
  196. package/lib/kernel/sqlite-driver.js +2540 -0
  197. package/lib/kernel/taxonomy-validator.js +394 -0
  198. package/lib/lefthook-check.js +3 -2
  199. package/lib/lefthook-wiring.js +413 -0
  200. package/lib/mcp-config-renderer.js +288 -0
  201. package/lib/memory/graphiti-mcp.js +106 -0
  202. package/lib/memory/router.js +387 -0
  203. package/lib/memory/typed-api.js +102 -0
  204. package/lib/memory-digest.js +195 -0
  205. package/lib/merge-rules.js +395 -0
  206. package/lib/migrate-dry-run.js +466 -0
  207. package/lib/orientation.js +863 -0
  208. package/lib/package-manager-remediation.js +103 -0
  209. package/lib/package-root.js +381 -0
  210. package/lib/patch-intent.js +890 -0
  211. package/lib/plugin-catalog.js +3 -4
  212. package/lib/plugin-manager.js +0 -5
  213. package/lib/pr-bundle.js +186 -0
  214. package/lib/pr-monitor/auto-actions.js +175 -0
  215. package/lib/pr-monitor/differ.js +195 -0
  216. package/lib/pr-monitor/digest.js +206 -0
  217. package/lib/pr-monitor/events.js +0 -0
  218. package/lib/pr-monitor/gather.js +124 -0
  219. package/lib/pr-monitor/journal.js +299 -0
  220. package/lib/pr-monitor/monitor.js +146 -0
  221. package/lib/pr-monitor/render-sticky.js +192 -0
  222. package/lib/pr-monitor/upsert-sticky.js +169 -0
  223. package/lib/pr-monitor/watch-lifecycle.js +95 -0
  224. package/lib/pr-monitor/watch.js +247 -0
  225. package/lib/pr-pull.js +1314 -0
  226. package/lib/pr-shepherd.js +494 -0
  227. package/lib/pr-state-validator.js +59 -0
  228. package/lib/preflight/gates.js +237 -0
  229. package/lib/preflight/runner.js +116 -0
  230. package/lib/project-discovery.js +0 -53
  231. package/lib/project-memory.js +99 -497
  232. package/lib/protected-path-manifest.js +281 -0
  233. package/lib/protected-state-surfaces.js +387 -0
  234. package/lib/release-readiness.js +2105 -0
  235. package/lib/reset.js +59 -45
  236. package/lib/review-adapter.js +68 -0
  237. package/lib/rules-sync.js +260 -0
  238. package/lib/runtime-health.js +241 -20
  239. package/lib/safety-config-renderer.js +268 -0
  240. package/lib/setup-action-log.js +1 -7
  241. package/lib/setup.js +27 -65
  242. package/lib/shell-utils.js +76 -6
  243. package/lib/skills-sync.js +330 -0
  244. package/lib/smart-status/scoring.js +17 -3
  245. package/lib/status/beads-snapshot.js +45 -2
  246. package/lib/status/presenter.js +169 -18
  247. package/lib/status/snapshot.js +186 -0
  248. package/lib/sync-backend.js +202 -0
  249. package/lib/untrusted-content.js +52 -0
  250. package/lib/upgrade-safety.js +251 -0
  251. package/lib/workflow/enforce-stage.js +351 -45
  252. package/lib/workflow/stage-transition.js +115 -0
  253. package/lib/workflow/stages.js +30 -6
  254. package/lib/workflow/state-manager.js +11 -22
  255. package/lib/workflow/state.js +23 -1
  256. package/lib/workflow-profiles.js +17 -5
  257. package/package.json +37 -35
  258. package/rules/documentation.md +19 -0
  259. package/rules/kernel-tracking.md +26 -0
  260. package/rules/security.md +22 -0
  261. package/rules/tdd.md +20 -0
  262. package/rules/workflow.md +27 -0
  263. package/scripts/auto-backing-issue.js +47 -0
  264. package/scripts/beads-context.sh +81 -57
  265. package/scripts/beads-upgrade-smoke.sh +24 -3
  266. package/scripts/bootstrap-windows-tools.sh +78 -0
  267. package/scripts/branch-protection.js +2 -3
  268. package/scripts/check-agents.js +34 -137
  269. package/scripts/commitlint.js +3 -1
  270. package/scripts/conflict-detect.sh +3 -0
  271. package/scripts/dep-guard.sh +22 -3
  272. package/scripts/file-index.sh +3 -0
  273. package/scripts/forge-team/lib/claim.sh +34 -18
  274. package/scripts/forge-team/lib/dashboard.sh +61 -86
  275. package/scripts/forge-team/lib/epic.sh +99 -263
  276. package/scripts/forge-team/lib/hooks.sh +26 -28
  277. package/scripts/forge-team/lib/identity.sh +4 -4
  278. package/scripts/forge-team/lib/sync-github.sh +49 -84
  279. package/scripts/forge-team/lib/verify.sh +93 -83
  280. package/scripts/forge-team/lib/workload.sh +41 -65
  281. package/scripts/forge-team/tests/claim.test.sh +25 -19
  282. package/scripts/forge-team/tests/dashboard.test.sh +31 -46
  283. package/scripts/forge-team/tests/epic.test.sh +52 -71
  284. package/scripts/forge-team/tests/hooks.test.sh +38 -50
  285. package/scripts/forge-team/tests/identity.test.sh +3 -3
  286. package/scripts/forge-team/tests/integration.test.sh +44 -66
  287. package/scripts/forge-team/tests/sync-github.test.sh +50 -83
  288. package/scripts/forge-team/tests/verify.test.sh +37 -46
  289. package/scripts/forge-team/tests/workflow-integration.test.sh +4 -4
  290. package/scripts/forge-team/tests/workload.test.sh +32 -66
  291. package/scripts/gen-command-manifest.js +153 -0
  292. package/scripts/gen-embedded-assets.mjs +129 -0
  293. package/scripts/install.ps1 +139 -0
  294. package/scripts/install.sh +268 -0
  295. package/scripts/lib/release-asset.mjs +84 -0
  296. package/scripts/parity-check.mjs +145 -0
  297. package/scripts/parity-check.test.mjs +58 -0
  298. package/scripts/pin-agentic-workflow-images.js +112 -0
  299. package/scripts/pr-auto-actions.js +93 -0
  300. package/scripts/pr-coordinator.sh +3 -0
  301. package/scripts/pr-verdict-label.js +50 -0
  302. package/scripts/preflight-sonar.eslint.config.mjs +44 -0
  303. package/scripts/preflight.sh +21 -94
  304. package/scripts/protected-state-check.js +104 -0
  305. package/scripts/smart-status.sh +60 -57
  306. package/scripts/spikes/config-race-bench.js +111 -0
  307. package/scripts/spikes/harness-capability-matrix.js +13 -0
  308. package/scripts/spikes/patch-anchor-stability-bench.js +125 -0
  309. package/scripts/spikes/protected-path-manifest.js +20 -0
  310. package/scripts/spikes/skill-auto-invoke-parity.js +292 -0
  311. package/scripts/sync-agent-skills.js +62 -0
  312. package/scripts/sync-utils.sh +3 -0
  313. package/scripts/test-ci-shard.js +13 -6
  314. package/scripts/test.js +95 -12
  315. package/skills/claim-safety/SKILL.md +102 -0
  316. package/skills/claim-safety/evals/evals.json +46 -0
  317. package/{.github/prompts/dev.prompt.md → skills/dev/SKILL.md} +44 -50
  318. package/skills/dev/evals/evals.json +50 -0
  319. package/skills/hermes-forge/SKILL.md +185 -0
  320. package/skills/hermes-forge/evals/evals.json +46 -0
  321. package/skills/issue-basics/SKILL.md +111 -0
  322. package/skills/issue-basics/evals/evals.json +46 -0
  323. package/skills/kernel/SKILL.md +166 -0
  324. package/skills/kernel/evals/evals.json +50 -0
  325. package/skills/memory/SKILL.md +102 -0
  326. package/skills/parallel-deep-research/SKILL.md +14 -11
  327. package/skills/parallel-deep-research/evals/evals.json +11 -27
  328. package/{.github/prompts/plan.prompt.md → skills/plan/SKILL.md} +132 -157
  329. package/skills/plan/evals/evals.json +42 -0
  330. package/skills/research/SKILL.md +195 -0
  331. package/skills/research/evals/evals.json +42 -0
  332. package/{.github/prompts/review.prompt.md → skills/review/SKILL.md} +98 -62
  333. package/skills/review/evals/evals.json +42 -0
  334. package/skills/rollback/SKILL.md +110 -0
  335. package/skills/rollback/evals/evals.json +46 -0
  336. package/skills/rollback/references/methods.md +204 -0
  337. package/{.cursor/commands/rollback.md → skills/rollback/references/workflow-integration.md} +10 -284
  338. package/skills/shepherd/SKILL.md +66 -0
  339. package/skills/shepherd/evals/evals.json +42 -0
  340. package/{.github/prompts/ship.prompt.md → skills/ship/SKILL.md} +81 -45
  341. package/skills/ship/evals/evals.json +42 -0
  342. package/skills/smith/SKILL.md +142 -0
  343. package/skills/smith/evals/evals.json +46 -0
  344. package/skills/smith/references/autonomy-and-gates.md +94 -0
  345. package/{.github/prompts/sonarcloud.prompt.md → skills/sonarcloud/SKILL.md} +14 -3
  346. package/skills/sonarcloud/evals/evals.json +46 -0
  347. package/skills/sonarcloud-analysis/SKILL.md +18 -13
  348. package/skills/sonarcloud-analysis/evals/evals.json +11 -15
  349. package/{.github/prompts/status.prompt.md → skills/status/SKILL.md} +20 -10
  350. package/skills/status/evals/evals.json +50 -0
  351. package/skills/triage-ready/SKILL.md +121 -0
  352. package/skills/triage-ready/evals/evals.json +42 -0
  353. package/{.github/prompts/validate.prompt.md → skills/validate/SKILL.md} +52 -29
  354. package/skills/validate/evals/evals.json +42 -0
  355. package/skills/verify/SKILL.md +299 -0
  356. package/skills/verify/evals/evals.json +50 -0
  357. package/.claude/commands/dev.md +0 -345
  358. package/.claude/commands/plan.md +0 -566
  359. package/.claude/commands/premerge.md +0 -186
  360. package/.claude/commands/research.md +0 -42
  361. package/.claude/commands/review.md +0 -451
  362. package/.claude/commands/rollback.md +0 -721
  363. package/.claude/commands/ship.md +0 -213
  364. package/.claude/commands/sonarcloud.md +0 -152
  365. package/.claude/commands/status.md +0 -90
  366. package/.claude/commands/validate.md +0 -288
  367. package/.claude/commands/verify.md +0 -269
  368. package/.claude/rules/workflow.md +0 -121
  369. package/.cline/workflows/dev.md +0 -342
  370. package/.cline/workflows/plan.md +0 -563
  371. package/.cline/workflows/premerge.md +0 -183
  372. package/.cline/workflows/research.md +0 -39
  373. package/.cline/workflows/review.md +0 -448
  374. package/.cline/workflows/rollback.md +0 -718
  375. package/.cline/workflows/ship.md +0 -210
  376. package/.cline/workflows/sonarcloud.md +0 -146
  377. package/.cline/workflows/status.md +0 -87
  378. package/.cline/workflows/validate.md +0 -285
  379. package/.cline/workflows/verify.md +0 -266
  380. package/.codex/config.toml +0 -11
  381. package/.codex/skills/dev/SKILL.md +0 -345
  382. package/.codex/skills/plan/SKILL.md +0 -566
  383. package/.codex/skills/premerge/SKILL.md +0 -186
  384. package/.codex/skills/research/SKILL.md +0 -42
  385. package/.codex/skills/review/SKILL.md +0 -451
  386. package/.codex/skills/rollback/SKILL.md +0 -721
  387. package/.codex/skills/ship/SKILL.md +0 -213
  388. package/.codex/skills/sonarcloud/SKILL.md +0 -149
  389. package/.codex/skills/status/SKILL.md +0 -90
  390. package/.codex/skills/validate/SKILL.md +0 -288
  391. package/.codex/skills/verify/SKILL.md +0 -269
  392. package/.cursor/commands/dev.md +0 -342
  393. package/.cursor/commands/plan.md +0 -563
  394. package/.cursor/commands/premerge.md +0 -183
  395. package/.cursor/commands/research.md +0 -39
  396. package/.cursor/commands/review.md +0 -448
  397. package/.cursor/commands/ship.md +0 -210
  398. package/.cursor/commands/sonarcloud.md +0 -146
  399. package/.cursor/commands/status.md +0 -87
  400. package/.cursor/commands/validate.md +0 -285
  401. package/.cursor/commands/verify.md +0 -266
  402. package/.cursorrules +0 -149
  403. package/.github/prompts/premerge.prompt.md +0 -188
  404. package/.github/prompts/research.prompt.md +0 -44
  405. package/.github/prompts/rollback.prompt.md +0 -723
  406. package/.github/prompts/verify.prompt.md +0 -271
  407. package/.github/workflows/beads-to-github.yml +0 -89
  408. package/.github/workflows/github-to-beads.yml +0 -100
  409. package/.kilocode/workflows/dev.md +0 -346
  410. package/.kilocode/workflows/plan.md +0 -567
  411. package/.kilocode/workflows/premerge.md +0 -187
  412. package/.kilocode/workflows/research.md +0 -43
  413. package/.kilocode/workflows/review.md +0 -452
  414. package/.kilocode/workflows/rollback.md +0 -722
  415. package/.kilocode/workflows/ship.md +0 -214
  416. package/.kilocode/workflows/sonarcloud.md +0 -150
  417. package/.kilocode/workflows/status.md +0 -91
  418. package/.kilocode/workflows/validate.md +0 -289
  419. package/.kilocode/workflows/verify.md +0 -270
  420. package/.opencode/commands/dev.md +0 -345
  421. package/.opencode/commands/plan.md +0 -566
  422. package/.opencode/commands/premerge.md +0 -186
  423. package/.opencode/commands/research.md +0 -42
  424. package/.opencode/commands/review.md +0 -451
  425. package/.opencode/commands/rollback.md +0 -721
  426. package/.opencode/commands/ship.md +0 -213
  427. package/.opencode/commands/sonarcloud.md +0 -149
  428. package/.opencode/commands/status.md +0 -90
  429. package/.opencode/commands/validate.md +0 -288
  430. package/.opencode/commands/verify.md +0 -269
  431. package/.roo/commands/dev.md +0 -346
  432. package/.roo/commands/plan.md +0 -567
  433. package/.roo/commands/premerge.md +0 -187
  434. package/.roo/commands/research.md +0 -43
  435. package/.roo/commands/review.md +0 -452
  436. package/.roo/commands/rollback.md +0 -722
  437. package/.roo/commands/ship.md +0 -214
  438. package/.roo/commands/sonarcloud.md +0 -150
  439. package/.roo/commands/status.md +0 -91
  440. package/.roo/commands/validate.md +0 -289
  441. package/.roo/commands/verify.md +0 -270
  442. package/docs/BEADS_GITHUB_SYNC.md +0 -281
  443. package/docs/GREPTILE_SETUP.md +0 -400
  444. package/docs/MANUAL_REVIEW_GUIDE.md +0 -106
  445. package/docs/SETUP.md +0 -663
  446. package/docs/VALIDATION.md +0 -363
  447. package/lib/agents/cline.plugin.json +0 -29
  448. package/lib/agents/copilot.plugin.json +0 -24
  449. package/lib/agents/kilocode.plugin.json +0 -22
  450. package/lib/agents/opencode.plugin.json +0 -23
  451. package/lib/agents/roo.plugin.json +0 -30
  452. package/lib/beads-bootstrap.js +0 -225
  453. package/lib/beads-health-check.js +0 -188
  454. package/lib/commands/commands-reset.js +0 -147
  455. package/opencode.json +0 -67
  456. package/scripts/beads-context.test.js +0 -584
  457. package/scripts/github-beads-sync/comment.mjs +0 -64
  458. package/scripts/github-beads-sync/config.mjs +0 -148
  459. package/scripts/github-beads-sync/github-api.mjs +0 -131
  460. package/scripts/github-beads-sync/index.mjs +0 -356
  461. package/scripts/github-beads-sync/label-mapper.mjs +0 -54
  462. package/scripts/github-beads-sync/mapping.mjs +0 -132
  463. package/scripts/github-beads-sync/reverse-sync-cli.mjs +0 -31
  464. package/scripts/github-beads-sync/reverse-sync.mjs +0 -162
  465. package/scripts/github-beads-sync/run-bd.mjs +0 -161
  466. package/scripts/github-beads-sync/sanitize.mjs +0 -121
  467. package/scripts/github-beads-sync.config.json +0 -26
  468. package/scripts/sync-commands.js +0 -600
@@ -0,0 +1,362 @@
1
+ 'use strict';
2
+
3
+ const fs = require('node:fs');
4
+ const os = require('node:os');
5
+ const path = require('node:path');
6
+ const { execFileSync } = require('node:child_process');
7
+
8
+ const {
9
+ buildMigrationDryRunReport,
10
+ renderMigrationDryRunReport,
11
+ } = require('../migrate-dry-run');
12
+ const {
13
+ loadBeadsSnapshotFromDirectory,
14
+ importBeadsSnapshot,
15
+ } = require('../adapters/beads-kernel-compat');
16
+ const { buildMigratedKernelIssueDeps } = require('../kernel/cli-broker-factory');
17
+
18
+ function hasArg(args, name) {
19
+ return Array.isArray(args) && args.includes(name);
20
+ }
21
+
22
+ /**
23
+ * Parse `forge migrate` options from positional args (with a parsed flags object
24
+ * as a fallback). Supported: --from <source>, --source <dir>, --dry-run, --json.
25
+ * Unknown tokens are ignored so the legacy v2→v3 PoC flags pass through untouched.
26
+ */
27
+ function parseMigrateOptions(args = [], flags = {}) {
28
+ const options = {
29
+ from: flags.from,
30
+ source: flags.source,
31
+ dryRun: Boolean(flags.dryRun || flags['dry-run']),
32
+ json: Boolean(flags.json),
33
+ errors: [],
34
+ };
35
+
36
+ const takeValue = (arg, prefix, current, index) => {
37
+ if (arg.startsWith(`${prefix}=`)) {
38
+ const value = arg.slice(prefix.length + 1);
39
+ if (!value) options.errors.push(`${prefix} requires a value`);
40
+ return { value: value || current, next: index };
41
+ }
42
+ const candidate = args[index + 1];
43
+ if (candidate && !candidate.startsWith('--')) {
44
+ return { value: candidate, next: index + 1 };
45
+ }
46
+ options.errors.push(`${prefix} requires a value`);
47
+ return { value: current, next: index };
48
+ };
49
+
50
+ let i = 0;
51
+ while (i < args.length) {
52
+ const arg = args[i];
53
+ if (arg === '--dry-run') options.dryRun = true;
54
+ else if (arg === '--json') options.json = true;
55
+ else if (arg === '--from' || arg.startsWith('--from=')) {
56
+ const parsed = takeValue(arg, '--from', options.from, i);
57
+ options.from = parsed.value;
58
+ i = parsed.next;
59
+ } else if (arg === '--source' || arg.startsWith('--source=')) {
60
+ const parsed = takeValue(arg, '--source', options.source, i);
61
+ options.source = parsed.value;
62
+ i = parsed.next;
63
+ }
64
+ i += 1;
65
+ }
66
+
67
+ return options;
68
+ }
69
+
70
+ function directoryHasJsonl(dir, fsImpl) {
71
+ try {
72
+ return fsImpl.readdirSync(dir).some(entry => entry.endsWith('.jsonl'));
73
+ } catch (_err) {
74
+ /* intentional: unreadable directory has no usable jsonl */ // NOSONAR S2486
75
+ return false;
76
+ }
77
+ }
78
+
79
+ /**
80
+ * Export a Dolt-only Beads store to JSONL in a temp dir via `bd export --all`,
81
+ * then return that dir for the loader. Defensive: a missing `bd` on PATH yields a
82
+ * clear, actionable error instead of a stack trace.
83
+ *
84
+ * NOTE (flagged ambiguity): the exact on-disk shape `bd export --all` emits is not
85
+ * pinned in this repo. We capture stdout into `<temp>/issues.jsonl`, which the
86
+ * loader reads. Operators with a different layout should prefer `--source <dir>`.
87
+ */
88
+ function exportDoltStoreToJsonl(beadsDir, projectRoot, deps) {
89
+ const exec = deps.execFileSync || execFileSync;
90
+ const fsImpl = deps.fs || fs;
91
+ const tempDir = fsImpl.mkdtempSync(path.join(os.tmpdir(), 'forge-migrate-bd-'));
92
+ try {
93
+ const stdout = exec('bd', ['export', '--all'], {
94
+ cwd: projectRoot || process.cwd(),
95
+ encoding: 'utf8',
96
+ });
97
+ fsImpl.writeFileSync(path.join(tempDir, 'issues.jsonl'), stdout || '');
98
+ return { dir: tempDir, kind: 'dolt-export', temp: tempDir };
99
+ } catch (err) {
100
+ fsImpl.rmSync(tempDir, { recursive: true, force: true });
101
+ const message = err && err.message ? err.message : String(err);
102
+ if (/ENOENT|not found|not recognized|no such file/i.test(message)) {
103
+ return {
104
+ error:
105
+ "Beads CLI 'bd' is not on PATH — cannot export the Dolt store at " +
106
+ `${beadsDir}. Install bd, or pass --source <dir> with exported *.jsonl files.`,
107
+ };
108
+ }
109
+ return { error: `bd export --all failed: ${message}` };
110
+ }
111
+ }
112
+
113
+ /**
114
+ * Resolve the directory holding Beads JSONL the loader will read.
115
+ * 1. --source wins (used as given).
116
+ * 2. else auto-detect a `.beads/` dir containing *.jsonl.
117
+ * 3. else a Dolt-only `.beads/` (no jsonl) → `bd export --all` into a temp dir.
118
+ * 4. else nothing found.
119
+ */
120
+ function resolveBeadsSource(options, projectRoot, deps) {
121
+ const fsImpl = deps.fs || fs;
122
+ const root = projectRoot || process.cwd();
123
+
124
+ if (options.source) {
125
+ const dir = path.resolve(root, options.source);
126
+ if (!fsImpl.existsSync(dir)) {
127
+ return { error: `No beads data found at --source ${dir} (directory does not exist)` };
128
+ }
129
+ return { dir, kind: 'source' };
130
+ }
131
+
132
+ const beadsDir = path.join(root, '.beads');
133
+ if (fsImpl.existsSync(beadsDir)) {
134
+ if (directoryHasJsonl(beadsDir, fsImpl)) {
135
+ return { dir: beadsDir, kind: 'jsonl-autodetect' };
136
+ }
137
+ return exportDoltStoreToJsonl(beadsDir, root, deps);
138
+ }
139
+
140
+ return {
141
+ error:
142
+ 'No beads data found. Looked for a .beads/ directory with *.jsonl under ' +
143
+ `${root}. Pass --source <dir> to point at an exported Beads store.`,
144
+ };
145
+ }
146
+
147
+ function cleanupResolved(resolved, deps) {
148
+ if (resolved && resolved.temp) {
149
+ const fsImpl = deps.fs || fs;
150
+ fsImpl.rmSync(resolved.temp, { recursive: true, force: true });
151
+ }
152
+ }
153
+
154
+ function summarizeGaps(gaps) {
155
+ const items = Array.isArray(gaps) ? gaps : [];
156
+ return {
157
+ count: items.length,
158
+ items: items.map(gap => ({ field: gap.field, reason: gap.reason })),
159
+ };
160
+ }
161
+
162
+ function renderHuman(payload) {
163
+ if (payload.error) {
164
+ return `forge migrate failed: ${payload.error}`;
165
+ }
166
+
167
+ const gaps = payload.gaps || { count: 0, items: [] };
168
+ const gapBrief = gaps.count > 0
169
+ ? ` (${gaps.items.map(item => item.field).join(', ')})`
170
+ : '';
171
+
172
+ if (payload.dryRun) {
173
+ return [
174
+ `Dry run — would import beads → kernel from ${payload.source}:`,
175
+ ` issues: ${payload.planned.issues}, comments: ${payload.planned.comments}, ` +
176
+ `dependencies: ${payload.planned.dependencies}, events: ${payload.planned.events ?? 0}`,
177
+ ` gaps: ${gaps.count}${gapBrief}`,
178
+ ' (nothing written to the kernel)',
179
+ ].join('\n');
180
+ }
181
+
182
+ const imported = payload.imported;
183
+ const importedEvents = imported.events || { inserted: 0, skipped: 0 };
184
+ return [
185
+ `Migrated beads → kernel from ${payload.source}:`,
186
+ ` issues: ${imported.issues.inserted} imported, ${imported.issues.skipped} skipped`,
187
+ ` comments: ${imported.comments.inserted} imported, ${imported.comments.skipped || 0} skipped`,
188
+ ` dependencies: ${imported.dependencies.inserted} imported, ` +
189
+ `${imported.dependencies.skipped} skipped`,
190
+ ` events: ${importedEvents.inserted} imported, ${importedEvents.skipped || 0} skipped`,
191
+ ` gaps: ${gaps.count}${gapBrief}`,
192
+ ].join('\n');
193
+ }
194
+
195
+ function finalize(options, payload, exitCode) {
196
+ const output = options.json ? JSON.stringify(payload, null, 2) : renderHuman(payload);
197
+ const result = { ...payload, output, json: Boolean(options.json) };
198
+ if (payload.success === false && Number.isInteger(exitCode)) {
199
+ result.exitCode = exitCode;
200
+ }
201
+ return result;
202
+ }
203
+
204
+ /**
205
+ * Beads → Forge Kernel transport. Reuses the faithful-import spine end-to-end:
206
+ * loadBeadsSnapshotFromDirectory → importBeadsSnapshot → broker.importIssues.
207
+ */
208
+ async function runBeadsMigration(options, projectRoot, opts) {
209
+ const now = opts._now || new Date().toISOString();
210
+ const deps = { execFileSync: opts._execFileSync, fs: opts._fs };
211
+
212
+ const resolved = resolveBeadsSource(options, projectRoot, deps);
213
+ if (resolved.error) {
214
+ return finalize(options, { success: false, from: 'beads', error: resolved.error }, 1);
215
+ }
216
+
217
+ let snapshot;
218
+ try {
219
+ snapshot = loadBeadsSnapshotFromDirectory(resolved.dir);
220
+ } catch (err) {
221
+ cleanupResolved(resolved, deps);
222
+ return finalize(
223
+ options,
224
+ { success: false, from: 'beads', source: resolved.dir, error: `Failed to read beads data: ${err.message}` },
225
+ 1,
226
+ );
227
+ }
228
+
229
+ if (snapshot.issues.length === 0 && snapshot.comments.length === 0 && snapshot.dependencies.length === 0) {
230
+ cleanupResolved(resolved, deps);
231
+ return finalize(
232
+ options,
233
+ { success: false, from: 'beads', source: resolved.dir, error: `No beads data found in ${resolved.dir}` },
234
+ 1,
235
+ );
236
+ }
237
+
238
+ let kernel;
239
+ let report;
240
+ try {
241
+ ({ kernel, report } = importBeadsSnapshot(snapshot, { importedAt: now }));
242
+ } catch (err) {
243
+ cleanupResolved(resolved, deps);
244
+ return finalize(
245
+ options,
246
+ { success: false, from: 'beads', source: resolved.dir, error: `Failed to map beads data: ${err.message}` },
247
+ 1,
248
+ );
249
+ }
250
+ const gaps = summarizeGaps(report?.gaps);
251
+ const planned = {
252
+ issues: kernel.issues.length,
253
+ comments: kernel.comments.length,
254
+ dependencies: kernel.dependencies.length,
255
+ events: Array.isArray(kernel.activityEvents) ? kernel.activityEvents.length : 0,
256
+ };
257
+
258
+ if (options.dryRun) {
259
+ cleanupResolved(resolved, deps);
260
+ return finalize(options, {
261
+ success: true,
262
+ from: 'beads',
263
+ dryRun: true,
264
+ source: resolved.dir,
265
+ sourceKind: resolved.kind,
266
+ planned,
267
+ gaps,
268
+ });
269
+ }
270
+
271
+ try {
272
+ let broker = opts._broker;
273
+ if (!broker) {
274
+ const built = await buildMigratedKernelIssueDeps({ projectRoot });
275
+ broker = built.kernelBroker;
276
+ }
277
+ const summary = await broker.importIssues(kernel, { now });
278
+ cleanupResolved(resolved, deps);
279
+ return finalize(options, {
280
+ success: true,
281
+ from: 'beads',
282
+ dryRun: false,
283
+ source: resolved.dir,
284
+ sourceKind: resolved.kind,
285
+ planned,
286
+ imported: {
287
+ issues: summary.issues,
288
+ comments: summary.comments,
289
+ dependencies: summary.dependencies,
290
+ events: summary.events,
291
+ },
292
+ gaps,
293
+ });
294
+ } catch (err) {
295
+ cleanupResolved(resolved, deps);
296
+ return finalize(
297
+ options,
298
+ { success: false, from: 'beads', source: resolved.dir, error: `Kernel import failed: ${err.message}` },
299
+ 1,
300
+ );
301
+ }
302
+ }
303
+
304
+ module.exports = {
305
+ name: 'migrate',
306
+ description: 'Migrate a Beads issue store into the Forge Kernel with --from beads, '
307
+ + 'or preview the v2→v3 migration (preview only — --dry-run required; applying it is not yet available)',
308
+ usage: 'forge migrate --from beads [--dry-run] [--source <dir>] [--json]',
309
+ flags: {
310
+ '--from <source>': 'Migration source. Use "beads" to import a Beads issue store into the Kernel.',
311
+ '--source <dir>': 'Directory of exported beads *.jsonl files (defaults to auto-detecting .beads/). '
312
+ + 'A split .beads layout is tolerated: files missing from the given dir are also read from a '
313
+ + 'backup/ subdir and the parent dir, so events (under .beads/backup/) and interactions '
314
+ + '(at .beads/interactions.jsonl) are both picked up regardless of which you point at.',
315
+ '--dry-run': 'Read + map only; print what WOULD be imported without writing to the Kernel. '
316
+ + 'Without --from, this is the only supported mode (preview only).',
317
+ '--json': 'Emit a structured JSON result (counts + gaps + dryRun flag).',
318
+ '--fixture-corpus': 'v2→v3 preview only: also dry-run the source-tree v2 fixture corpus when available.',
319
+ },
320
+
321
+ async handler(args, flags, projectRoot, opts = {}) {
322
+ const options = parseMigrateOptions(args, flags);
323
+ if (options.errors.length > 0) {
324
+ return finalize(options, { success: false, error: options.errors.join('; ') }, 1);
325
+ }
326
+
327
+ // New beads → kernel transport, gated on `--from beads`. Any other (or absent)
328
+ // `--from` falls through to the pre-existing v2→v3 dry-run PoC so its contract
329
+ // (and tests) stay intact.
330
+ if (options.from) {
331
+ if (options.from === 'beads') {
332
+ return runBeadsMigration(options, projectRoot, opts);
333
+ }
334
+ return finalize(
335
+ options,
336
+ { success: false, error: `Unsupported migration source '${options.from}'. Supported sources: beads.` },
337
+ 1,
338
+ );
339
+ }
340
+
341
+ // --- legacy v2 → v3 dry-run PoC (unchanged) ---
342
+ const dryRun = flags?.dryRun === true || hasArg(args, '--dry-run');
343
+ if (!dryRun) {
344
+ return {
345
+ success: false,
346
+ error: "forge migrate currently supports preview only. Run 'forge migrate --dry-run' "
347
+ + 'to see what would change; applying migrations is not yet available.',
348
+ };
349
+ }
350
+
351
+ const report = buildMigrationDryRunReport(projectRoot, {
352
+ fixtureCorpus: hasArg(args, '--fixture-corpus'),
353
+ });
354
+ const output = renderMigrationDryRunReport(report);
355
+
356
+ return {
357
+ success: report.ok,
358
+ output,
359
+ error: report.ok ? undefined : output,
360
+ };
361
+ },
362
+ };
@@ -0,0 +1,12 @@
1
+ 'use strict';
2
+
3
+ const { scaffoldAdapter } = require('../adapter-cli');
4
+
5
+ module.exports = {
6
+ name: 'new',
7
+ description: 'Create Forge extension scaffolds',
8
+ usage: 'forge new adapter <name> --kind=review --template=greptile',
9
+ async handler(args, _flags, projectRoot) {
10
+ return scaffoldAdapter(args, projectRoot);
11
+ },
12
+ };
@@ -0,0 +1,241 @@
1
+ 'use strict';
2
+
3
+ const {
4
+ getDefaultRuntimeGraph,
5
+ getResolvedRuntimeGraph,
6
+ lintRuntimeGraphConfig,
7
+ } = require('../core/runtime-graph');
8
+ const { describeControl } = require('../control-plane');
9
+
10
+ const COLLECTIONS = {
11
+ stages: { key: 'phases', label: 'Stages' },
12
+ gates: { key: 'gates', label: 'Gates' },
13
+ adapters: { key: 'adapters', label: 'Adapters' },
14
+ roles: { key: 'roles', label: 'Roles' },
15
+ };
16
+
17
+ function hasJson(args) {
18
+ return args.includes('--json');
19
+ }
20
+
21
+ function withoutFlags(args) {
22
+ return args.filter(arg => arg !== '--json');
23
+ }
24
+
25
+ function jsonOutput(value) {
26
+ return `${JSON.stringify(value, null, 2)}\n`;
27
+ }
28
+
29
+ function summarizeRole(item) {
30
+ const parts = [`skill=${item.skill}`];
31
+ if (item.ideology) parts.push(`ideology=${item.ideology}`);
32
+ return `${item.id} (${parts.join(', ')})`;
33
+ }
34
+
35
+ function summarizeItem(item) {
36
+ if (item.role) return summarizeRole(item);
37
+ const state = item.enabled === false ? 'disabled' : 'enabled';
38
+ const locked = item.locked ? ', locked' : '';
39
+ const label = item.label ?? item.kind ?? item.command ?? 'graph primitive';
40
+ const badge = item.badge ? ` [${item.badge}]` : '';
41
+ return `${item.id} (${state}${locked}) - ${label}${badge}`;
42
+ }
43
+
44
+ function renderCollection(label, items) {
45
+ return [
46
+ label,
47
+ ...items.map(item => `- ${summarizeItem(item)}`),
48
+ ].join('\n') + '\n';
49
+ }
50
+
51
+ function allPrimitiveEntries(graph) {
52
+ return [
53
+ ...graph.phases.map(item => ['stage', item]),
54
+ ...graph.gates.map(item => ['gate', item]),
55
+ ...graph.adapters.map(item => ['adapter', item]),
56
+ ...graph.rails.map(item => ['rail', item]),
57
+ ...graph.actions.map(item => ['action', item]),
58
+ ...graph.artifacts.map(item => ['artifact', item]),
59
+ ...graph.evaluatorRegions.map(item => ['evaluatorRegion', item]),
60
+ ...graph.evidence.map(item => ['evidence', item]),
61
+ ...(graph.planning?.subSkills ?? []).map(item => ['planningSubSkill', item]),
62
+ ];
63
+ }
64
+
65
+ function findPrimitive(graph, id) {
66
+ return allPrimitiveEntries(graph).find(([type, item]) => item.id === id || item.key === id || `${type}.${item.id}` === id);
67
+ }
68
+
69
+ function renderWhy(type, item) {
70
+ const lines = [
71
+ `${item.id}`,
72
+ `type: ${type}`,
73
+ `state: ${item.enabled === false ? 'disabled' : 'enabled'}`,
74
+ `source: ${item.configSource ?? 'package-defaults'}`,
75
+ ];
76
+ if (item.locked) lines.push('locked: true');
77
+ if (item.requires) lines.push(`requires: ${item.requires.join(', ')}`);
78
+ if (item.reads?.length) lines.push(`reads: ${item.reads.join(', ')}`);
79
+ if (item.writes?.length) lines.push(`writes: ${item.writes.join(', ')}`);
80
+ if (item.description) lines.push(`description: ${item.description}`);
81
+ return `${lines.join('\n')}\n`;
82
+ }
83
+
84
+ function primitiveMap(graph, key) {
85
+ return new Map((graph[key] ?? []).map(item => [item.id, item]));
86
+ }
87
+
88
+ function collectDiff(defaultGraph, resolvedGraph) {
89
+ const changes = [];
90
+ for (const key of ['phases', 'gates', 'adapters', 'rails']) {
91
+ const defaults = primitiveMap(defaultGraph, key);
92
+ const resolved = primitiveMap(resolvedGraph, key);
93
+ for (const [id, afterItem] of resolved) {
94
+ const beforeItem = defaults.get(id);
95
+ if (!beforeItem) continue;
96
+ for (const field of ['enabled', 'disabled', 'configSource', 'config']) {
97
+ const before = beforeItem[field];
98
+ const after = afterItem[field];
99
+ if (JSON.stringify(before) !== JSON.stringify(after)) {
100
+ changes.push({ collection: key, id, field, before, after });
101
+ }
102
+ }
103
+ }
104
+ }
105
+ if (JSON.stringify(defaultGraph.protectedPaths) !== JSON.stringify(resolvedGraph.protectedPaths)) {
106
+ changes.push({
107
+ collection: 'protectedPaths',
108
+ id: 'protectedPaths',
109
+ field: 'patterns',
110
+ before: defaultGraph.protectedPaths,
111
+ after: resolvedGraph.protectedPaths,
112
+ });
113
+ }
114
+ if (JSON.stringify(defaultGraph.planning?.template) !== JSON.stringify(resolvedGraph.planning?.template)) {
115
+ changes.push({
116
+ collection: 'planning',
117
+ id: 'planning.template',
118
+ field: 'config',
119
+ before: defaultGraph.planning?.template,
120
+ after: resolvedGraph.planning?.template,
121
+ });
122
+ }
123
+ return changes;
124
+ }
125
+
126
+ function renderDiff(changes) {
127
+ if (changes.length === 0) {
128
+ return 'No graph config changes.\n';
129
+ }
130
+ return changes
131
+ .map(change => `${change.id}.${change.field}: ${JSON.stringify(change.before)} -> ${JSON.stringify(change.after)}`)
132
+ .join('\n') + '\n';
133
+ }
134
+
135
+ function renderLint(result) {
136
+ if (result.ok) {
137
+ return 'Graph config lint passed.\n';
138
+ }
139
+ return [
140
+ 'Graph config lint failed.',
141
+ ...result.errors.map(error => `- ${error.code}: ${error.message}`),
142
+ ].join('\n') + '\n';
143
+ }
144
+
145
+ function usage() {
146
+ return [
147
+ 'Usage: forge options <stages|gates|adapters|roles|diff|why <id>|lint> [--json]',
148
+ '',
149
+ 'Inspect resolved runtime graph primitives and project config effects.',
150
+ ].join('\n');
151
+ }
152
+
153
+ function lintCommand(projectRoot, json) {
154
+ const result = lintRuntimeGraphConfig({ projectRoot });
155
+ const output = json ? jsonOutput(result) : renderLint(result);
156
+ return {
157
+ success: result.ok,
158
+ output,
159
+ error: result.ok ? undefined : output,
160
+ };
161
+ }
162
+
163
+ function resolveGraphResult(projectRoot, json) {
164
+ try {
165
+ return { success: true, graph: getResolvedRuntimeGraph({ projectRoot }) };
166
+ } catch (err) {
167
+ const output = json
168
+ ? jsonOutput({ ok: false, errors: err.message.split('\n').map(message => ({ message })) })
169
+ : `${err.message}\n`;
170
+ return { success: false, output, error: output };
171
+ }
172
+ }
173
+
174
+ // Gates carry enforcement-locus badges (724356ea): decorate each with the
175
+ // honest surface/state/locus/badge from the guarantee matrix so the read view
176
+ // never implies enforcement a surface lacks (human gates read PERMISSION,
177
+ // ordinary gates read ENFORCED).
178
+ function decorateWithLocus(subcommand, items) {
179
+ if (subcommand !== 'gates') return items;
180
+ return items.map(item => ({ ...item, ...describeControl(item) }));
181
+ }
182
+
183
+ function collectionCommand(graph, subcommand, json) {
184
+ const { key, label } = COLLECTIONS[subcommand];
185
+ const items = decorateWithLocus(subcommand, graph[key]);
186
+ return {
187
+ success: true,
188
+ output: json ? jsonOutput({ kind: subcommand, items }) : renderCollection(label, items),
189
+ };
190
+ }
191
+
192
+ function whyCommand(graph, id, json) {
193
+ const match = id ? findPrimitive(graph, id) : null;
194
+ if (!match) {
195
+ const message = `Unknown graph primitive: ${id ?? '<missing>'}`;
196
+ const output = json
197
+ ? jsonOutput({ ok: false, errors: [{ code: 'UNKNOWN_GRAPH_PRIMITIVE', message }] })
198
+ : message;
199
+ return { success: false, output, error: output };
200
+ }
201
+ const [type, item] = match;
202
+ return {
203
+ success: true,
204
+ output: json ? jsonOutput({ type, item }) : renderWhy(type, item),
205
+ };
206
+ }
207
+
208
+ function diffCommand(graph, json) {
209
+ const changes = collectDiff(getDefaultRuntimeGraph(), graph);
210
+ return {
211
+ success: true,
212
+ output: json ? jsonOutput({ changes }) : renderDiff(changes),
213
+ };
214
+ }
215
+
216
+ async function handler(args, _flags, projectRoot) {
217
+ const json = hasJson(args);
218
+ const tokens = withoutFlags(args);
219
+ const subcommand = tokens[0];
220
+
221
+ if (!subcommand) return { success: false, error: usage() };
222
+ if (subcommand === 'lint') return lintCommand(projectRoot, json);
223
+
224
+ const graphResult = resolveGraphResult(projectRoot, json);
225
+ if (!graphResult.success) return graphResult;
226
+ if (COLLECTIONS[subcommand]) return collectionCommand(graphResult.graph, subcommand, json);
227
+ if (subcommand === 'why') return whyCommand(graphResult.graph, tokens[1], json);
228
+ if (subcommand === 'diff') return diffCommand(graphResult.graph, json);
229
+ return { success: false, error: usage() };
230
+ }
231
+
232
+ module.exports = {
233
+ name: 'options',
234
+ description: 'Inspect runtime graph primitives and config',
235
+ usage: usage(),
236
+ flags: {
237
+ '--json': 'Emit machine-readable JSON output',
238
+ },
239
+ handler,
240
+ collectDiff,
241
+ };
@@ -0,0 +1,13 @@
1
+ 'use strict';
2
+
3
+ const {
4
+ buildOrientation,
5
+ runOrientationCommand,
6
+ } = require('../orientation');
7
+
8
+ module.exports = {
9
+ name: 'orient',
10
+ description: 'Emit bounded project orientation from deterministic source files',
11
+ usage: 'Usage: forge orient [--budget N] [--json]',
12
+ handler: (args, _flags, projectRoot) => runOrientationCommand(buildOrientation, args, projectRoot),
13
+ };
@@ -0,0 +1,5 @@
1
+ 'use strict';
2
+
3
+ const { createIssueSubcommand } = require('./_issue');
4
+
5
+ module.exports = createIssueSubcommand('orphans');
@@ -0,0 +1,67 @@
1
+ 'use strict';
2
+
3
+ const {
4
+ recordPatchIntentFromDiff,
5
+ resolvePatchIntentRecords,
6
+ } = require('../patch-intent');
7
+
8
+ const usage = [
9
+ 'forge patch record --from-diff',
10
+ 'forge patch status',
11
+ ].join('\n');
12
+
13
+ function formatRecordSummary(result) {
14
+ const count = result.records.length;
15
+ const label = count === 1 ? 'patch intent' : 'patch intents';
16
+ return [
17
+ `Recorded ${count} ${label} in ${result.path}.`,
18
+ ...result.records.map(record => `- ${record.id} -> ${record.anchorId} (${record.path})`),
19
+ ].join('\n');
20
+ }
21
+
22
+ async function handler(args, _flags, projectRoot) {
23
+ const [subcommand, ...rest] = args;
24
+
25
+ if (subcommand === 'record') {
26
+ if (!rest.includes('--from-diff')) {
27
+ return {
28
+ success: false,
29
+ error: `Missing --from-diff.\n\nUsage:\n${usage}`,
30
+ };
31
+ }
32
+ const result = recordPatchIntentFromDiff(projectRoot);
33
+ return {
34
+ success: true,
35
+ output: formatRecordSummary(result),
36
+ };
37
+ }
38
+
39
+ if (subcommand === 'status') {
40
+ const result = resolvePatchIntentRecords(projectRoot);
41
+ const lines = [
42
+ `Patch intent file: ${result.path}`,
43
+ `Records: ${result.records.length}`,
44
+ `Orphans: ${result.orphans.length}`,
45
+ ];
46
+ for (const record of result.records) {
47
+ lines.push(`- ${record.id}: ${record.status} ${record.anchorId} -> ${record.currentPath || record.path}`);
48
+ }
49
+ return {
50
+ success: true,
51
+ output: lines.join('\n'),
52
+ };
53
+ }
54
+
55
+ return {
56
+ success: false,
57
+ error: `Unknown patch subcommand: ${subcommand || '(none)'}\n\nUsage:\n${usage}`,
58
+ };
59
+ }
60
+
61
+ module.exports = {
62
+ name: 'patch',
63
+ description: 'Record and inspect patch intent anchored in patch.md',
64
+ usage,
65
+ handler,
66
+ };
67
+