forge-workflow 0.0.10 → 0.1.0-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (468) hide show
  1. package/.claude/rules/{greptile-review-process.md → review-process.md} +56 -41
  2. package/.claude/scripts/{greptile-resolve.sh → review-resolve.sh} +13 -3
  3. package/.cursor/rules/permissions-guidance.mdc +2 -2
  4. package/.forge/hooks/check-tdd.js +82 -5
  5. package/.forge/hooks/forge-native-hook.js +431 -0
  6. package/.forge/protected-paths.yaml +157 -0
  7. package/AGENTS.md +151 -61
  8. package/CHANGELOG.md +709 -0
  9. package/CLAUDE.md +9 -118
  10. package/QUICKSTART.md +175 -0
  11. package/README.md +275 -365
  12. package/bin/forge-cmd.js +120 -9
  13. package/bin/forge-preflight.js +26 -5
  14. package/bin/forge.js +532 -489
  15. package/docs/INDEX.md +93 -0
  16. package/docs/PROJECT_DESIGN.md +685 -0
  17. package/docs/architecture/index.md +66 -0
  18. package/docs/architecture/notes/README.md +35 -0
  19. package/docs/architecture/subsystems/README.md +46 -0
  20. package/docs/forge/TOOLCHAIN.md +670 -0
  21. package/docs/forge/VALIDATION.md +82 -0
  22. package/docs/{AGENT_INSTALL_PROMPT.md → guides/AGENT_INSTALL_PROMPT.md} +3 -3
  23. package/docs/guides/BEADS_GITHUB_SYNC.md +32 -0
  24. package/docs/{ENHANCED_ONBOARDING.md → guides/ENHANCED_ONBOARDING.md} +16 -12
  25. package/docs/guides/GREPTILE_SETUP.md +46 -0
  26. package/docs/guides/MANUAL_REVIEW_GUIDE.md +58 -0
  27. package/docs/guides/MIGRATION.md +56 -0
  28. package/docs/guides/SETUP.md +121 -0
  29. package/docs/guides/SUPPORT.md +190 -0
  30. package/docs/guides/WORKFLOW_TEMPLATES.md +74 -0
  31. package/docs/guides/memory-backends.md +183 -0
  32. package/docs/reference/ADAPTERS.md +128 -0
  33. package/docs/reference/AGENT_SKILL_PARITY.md +175 -0
  34. package/docs/reference/COMMANDS.md +214 -0
  35. package/docs/reference/DECISION_DRIFT_GUARDS.md +97 -0
  36. package/docs/{EXAMPLES.md → reference/EXAMPLES.md} +7 -5
  37. package/docs/reference/FORGE_KERNEL_STORAGE_MODEL.md +135 -0
  38. package/docs/reference/HERMES_INTEGRATION.md +118 -0
  39. package/docs/reference/INSIGHTS_RECAP.md +63 -0
  40. package/docs/reference/INSTALL.md +164 -0
  41. package/docs/reference/KERNEL_TAXONOMY_VALIDATION.md +161 -0
  42. package/docs/reference/PROTECTED_PATH_MANIFEST.md +25 -0
  43. package/docs/reference/RELEASE.md +68 -0
  44. package/docs/reference/RESEARCH_TEMPLATE.md +292 -0
  45. package/docs/{ROADMAP.md → reference/ROADMAP.md} +12 -9
  46. package/docs/reference/SKILLS.md +35 -0
  47. package/docs/reference/STATUS_BOARD.md +80 -0
  48. package/docs/reference/TEMPLATES.md +106 -0
  49. package/docs/{TOOLCHAIN.md → reference/TOOLCHAIN.md} +62 -47
  50. package/docs/reference/VALIDATION.md +82 -0
  51. package/docs/reference/agent-permissions.md +169 -0
  52. package/docs/reference/beads-to-kernel-migration-ux.md +61 -0
  53. package/docs/reference/control-plane-guarantees.md +125 -0
  54. package/docs/reference/dependency-chain.md +331 -0
  55. package/docs/reference/forge-kernel-issue-command-contract.md +161 -0
  56. package/docs/reference/forge-kernel-schema.md +72 -0
  57. package/docs/reference/kernel-conflict-evaluators.md +27 -0
  58. package/docs/reference/patch-md-format.md +77 -0
  59. package/docs/reference/protected-state-surfaces.md +59 -0
  60. package/docs/reference/shepherd.md +155 -0
  61. package/docs/reference/superpowers-analysis.md +320 -0
  62. package/docs/reference/superpowers-integration-options.md +404 -0
  63. package/docs/reference/test-environment.md +519 -0
  64. package/docs/reference/upgrade-safety.md +59 -0
  65. package/lefthook.yml +18 -0
  66. package/lib/activation/ensure-forge-home.js +135 -0
  67. package/lib/adapter-cli.js +307 -0
  68. package/lib/adapters/beads-issue-adapter.js +127 -0
  69. package/lib/adapters/beads-kernel-compat.js +1109 -0
  70. package/lib/adapters/greptile-review-adapter.js +141 -0
  71. package/lib/adapters/kernel-issue-adapter.js +101 -0
  72. package/lib/adapters/pr-state-adapter.js +484 -0
  73. package/lib/adoption-profiles.js +139 -0
  74. package/lib/agents/README.md +2 -6
  75. package/lib/agents/claude.plugin.json +3 -8
  76. package/lib/agents/codex.plugin.json +9 -1
  77. package/lib/agents/cursor.plugin.json +2 -6
  78. package/lib/agents/hermes.plugin.json +22 -0
  79. package/lib/agents-config.js +39 -1236
  80. package/lib/audit-evidence.js +282 -0
  81. package/lib/beads-detect.js +60 -0
  82. package/lib/beads-nudge.js +91 -0
  83. package/lib/beads-setup.js +121 -0
  84. package/lib/beads-sync-scaffold.js +25 -101
  85. package/lib/codex-skills.js +51 -1
  86. package/lib/commands/_aliases.js +248 -0
  87. package/lib/commands/_issue.js +780 -77
  88. package/lib/commands/_manifest.js +93 -0
  89. package/lib/commands/_registry.js +99 -34
  90. package/lib/commands/_resolve-command-opts.js +230 -0
  91. package/lib/commands/_serve-security.js +270 -0
  92. package/lib/commands/adapter.js +12 -0
  93. package/lib/commands/add.js +118 -0
  94. package/lib/commands/audit.js +70 -0
  95. package/lib/commands/blocked.js +5 -0
  96. package/lib/commands/board.js +64 -0
  97. package/lib/commands/claim.js +21 -2
  98. package/lib/commands/claims.js +7 -0
  99. package/lib/commands/clean.js +485 -75
  100. package/lib/commands/close.js +2 -2
  101. package/lib/commands/comment.js +5 -0
  102. package/lib/commands/control.js +148 -0
  103. package/lib/commands/create.js +2 -2
  104. package/lib/commands/dev.js +185 -7
  105. package/lib/commands/doc-gate.js +336 -0
  106. package/lib/commands/doctor.js +156 -0
  107. package/lib/commands/explain.js +15 -0
  108. package/lib/commands/export.js +237 -0
  109. package/lib/commands/gate.js +209 -0
  110. package/lib/commands/hooks.js +377 -0
  111. package/lib/commands/inbox.js +118 -0
  112. package/lib/commands/init.js +604 -0
  113. package/lib/commands/insights.js +79 -0
  114. package/lib/commands/issue.js +12 -1
  115. package/lib/commands/issues.js +17 -0
  116. package/lib/commands/lint.js +5 -0
  117. package/lib/commands/list.js +2 -2
  118. package/lib/commands/memory.js +81 -0
  119. package/lib/commands/merge.js +312 -0
  120. package/lib/commands/migrate.js +362 -0
  121. package/lib/commands/new.js +12 -0
  122. package/lib/commands/options.js +241 -0
  123. package/lib/commands/orient.js +13 -0
  124. package/lib/commands/orphans.js +5 -0
  125. package/lib/commands/patch.js +67 -0
  126. package/lib/commands/plan.js +481 -29
  127. package/lib/commands/pr.js +88 -0
  128. package/lib/commands/preflight.js +211 -0
  129. package/lib/commands/prime.js +13 -0
  130. package/lib/commands/push.js +135 -2
  131. package/lib/commands/ready.js +2 -2
  132. package/lib/commands/recall.js +171 -0
  133. package/lib/commands/recap.js +75 -0
  134. package/lib/commands/recommend.js +0 -1
  135. package/lib/commands/release.js +104 -0
  136. package/lib/commands/remember.js +140 -0
  137. package/lib/commands/role.js +99 -0
  138. package/lib/commands/serve.js +581 -0
  139. package/lib/commands/setup.js +900 -971
  140. package/lib/commands/shepherd.js +501 -0
  141. package/lib/commands/ship.js +59 -1
  142. package/lib/commands/show.js +2 -2
  143. package/lib/commands/stage.js +192 -0
  144. package/lib/commands/stale.js +5 -0
  145. package/lib/commands/status.js +158 -21
  146. package/lib/commands/sync.js +34 -46
  147. package/lib/commands/team.js +4 -1
  148. package/lib/commands/test.js +43 -27
  149. package/lib/commands/update.js +2 -2
  150. package/lib/commands/upgrade.js +47 -0
  151. package/lib/commands/validate.js +43 -18
  152. package/lib/commands/worktree.js +362 -99
  153. package/lib/config-writer.js +202 -0
  154. package/lib/control-plane.js +236 -0
  155. package/lib/core/runtime-graph.js +977 -0
  156. package/lib/dep-guard/keyword-ripple.js +2 -2
  157. package/lib/deprecated-sync-cleanup.js +362 -0
  158. package/lib/detect-agent.js +2 -28
  159. package/lib/detect-worktree.js +35 -9
  160. package/lib/doc-gate/declaration.js +177 -0
  161. package/lib/doc-gate/detect.js +289 -0
  162. package/lib/doc-gate/gate.js +375 -0
  163. package/lib/doc-gate/okf-config.js +128 -0
  164. package/lib/doc-gate/okf.js +429 -0
  165. package/lib/docs-command.js +1161 -6
  166. package/lib/forge-issues.js +382 -11
  167. package/lib/forge-lock.js +262 -0
  168. package/lib/gate-events.js +192 -0
  169. package/lib/global-flags.js +104 -0
  170. package/lib/greptile-match.js +7 -63
  171. package/lib/grounding/context-events.js +230 -0
  172. package/lib/grounding/read-first.js +112 -0
  173. package/lib/harness-capability-matrix.js +380 -0
  174. package/lib/hook-global-installer.js +347 -0
  175. package/lib/hook-renderer.js +541 -0
  176. package/lib/inbox.js +391 -0
  177. package/lib/insights.js +397 -0
  178. package/lib/issue-adapter.js +156 -0
  179. package/lib/issue-backend.js +145 -0
  180. package/lib/issue-render.js +220 -0
  181. package/lib/kernel/backing-issue.js +311 -0
  182. package/lib/kernel/broker.js +1218 -0
  183. package/lib/kernel/cli-broker-factory.js +130 -0
  184. package/lib/kernel/conflict-signal.js +82 -0
  185. package/lib/kernel/evaluators.js +195 -0
  186. package/lib/kernel/fs-class.js +495 -0
  187. package/lib/kernel/issue-command-contract.js +559 -0
  188. package/lib/kernel/issue-id-resolver.js +186 -0
  189. package/lib/kernel/lease-enforcer.js +158 -0
  190. package/lib/kernel/migrations.js +333 -0
  191. package/lib/kernel/owned-kernel.js +43 -0
  192. package/lib/kernel/planning-buckets-schema.js +109 -0
  193. package/lib/kernel/projection-jsonl-writer.js +450 -0
  194. package/lib/kernel/readiness-model.js +329 -0
  195. package/lib/kernel/schema.js +356 -0
  196. package/lib/kernel/sqlite-driver.js +2540 -0
  197. package/lib/kernel/taxonomy-validator.js +394 -0
  198. package/lib/lefthook-check.js +3 -2
  199. package/lib/lefthook-wiring.js +413 -0
  200. package/lib/mcp-config-renderer.js +288 -0
  201. package/lib/memory/graphiti-mcp.js +106 -0
  202. package/lib/memory/router.js +387 -0
  203. package/lib/memory/typed-api.js +102 -0
  204. package/lib/memory-digest.js +195 -0
  205. package/lib/merge-rules.js +395 -0
  206. package/lib/migrate-dry-run.js +466 -0
  207. package/lib/orientation.js +863 -0
  208. package/lib/package-manager-remediation.js +103 -0
  209. package/lib/package-root.js +381 -0
  210. package/lib/patch-intent.js +890 -0
  211. package/lib/plugin-catalog.js +3 -4
  212. package/lib/plugin-manager.js +0 -5
  213. package/lib/pr-bundle.js +186 -0
  214. package/lib/pr-monitor/auto-actions.js +175 -0
  215. package/lib/pr-monitor/differ.js +195 -0
  216. package/lib/pr-monitor/digest.js +206 -0
  217. package/lib/pr-monitor/events.js +0 -0
  218. package/lib/pr-monitor/gather.js +124 -0
  219. package/lib/pr-monitor/journal.js +299 -0
  220. package/lib/pr-monitor/monitor.js +146 -0
  221. package/lib/pr-monitor/render-sticky.js +192 -0
  222. package/lib/pr-monitor/upsert-sticky.js +169 -0
  223. package/lib/pr-monitor/watch-lifecycle.js +95 -0
  224. package/lib/pr-monitor/watch.js +247 -0
  225. package/lib/pr-pull.js +1314 -0
  226. package/lib/pr-shepherd.js +494 -0
  227. package/lib/pr-state-validator.js +59 -0
  228. package/lib/preflight/gates.js +237 -0
  229. package/lib/preflight/runner.js +116 -0
  230. package/lib/project-discovery.js +0 -53
  231. package/lib/project-memory.js +99 -497
  232. package/lib/protected-path-manifest.js +281 -0
  233. package/lib/protected-state-surfaces.js +387 -0
  234. package/lib/release-readiness.js +2105 -0
  235. package/lib/reset.js +59 -45
  236. package/lib/review-adapter.js +68 -0
  237. package/lib/rules-sync.js +260 -0
  238. package/lib/runtime-health.js +241 -20
  239. package/lib/safety-config-renderer.js +268 -0
  240. package/lib/setup-action-log.js +1 -7
  241. package/lib/setup.js +27 -65
  242. package/lib/shell-utils.js +76 -6
  243. package/lib/skills-sync.js +330 -0
  244. package/lib/smart-status/scoring.js +17 -3
  245. package/lib/status/beads-snapshot.js +45 -2
  246. package/lib/status/presenter.js +169 -18
  247. package/lib/status/snapshot.js +186 -0
  248. package/lib/sync-backend.js +202 -0
  249. package/lib/untrusted-content.js +52 -0
  250. package/lib/upgrade-safety.js +251 -0
  251. package/lib/workflow/enforce-stage.js +351 -45
  252. package/lib/workflow/stage-transition.js +115 -0
  253. package/lib/workflow/stages.js +30 -6
  254. package/lib/workflow/state-manager.js +11 -22
  255. package/lib/workflow/state.js +23 -1
  256. package/lib/workflow-profiles.js +17 -5
  257. package/package.json +37 -35
  258. package/rules/documentation.md +19 -0
  259. package/rules/kernel-tracking.md +26 -0
  260. package/rules/security.md +22 -0
  261. package/rules/tdd.md +20 -0
  262. package/rules/workflow.md +27 -0
  263. package/scripts/auto-backing-issue.js +47 -0
  264. package/scripts/beads-context.sh +81 -57
  265. package/scripts/beads-upgrade-smoke.sh +24 -3
  266. package/scripts/bootstrap-windows-tools.sh +78 -0
  267. package/scripts/branch-protection.js +2 -3
  268. package/scripts/check-agents.js +34 -137
  269. package/scripts/commitlint.js +3 -1
  270. package/scripts/conflict-detect.sh +3 -0
  271. package/scripts/dep-guard.sh +22 -3
  272. package/scripts/file-index.sh +3 -0
  273. package/scripts/forge-team/lib/claim.sh +34 -18
  274. package/scripts/forge-team/lib/dashboard.sh +61 -86
  275. package/scripts/forge-team/lib/epic.sh +99 -263
  276. package/scripts/forge-team/lib/hooks.sh +26 -28
  277. package/scripts/forge-team/lib/identity.sh +4 -4
  278. package/scripts/forge-team/lib/sync-github.sh +49 -84
  279. package/scripts/forge-team/lib/verify.sh +93 -83
  280. package/scripts/forge-team/lib/workload.sh +41 -65
  281. package/scripts/forge-team/tests/claim.test.sh +25 -19
  282. package/scripts/forge-team/tests/dashboard.test.sh +31 -46
  283. package/scripts/forge-team/tests/epic.test.sh +52 -71
  284. package/scripts/forge-team/tests/hooks.test.sh +38 -50
  285. package/scripts/forge-team/tests/identity.test.sh +3 -3
  286. package/scripts/forge-team/tests/integration.test.sh +44 -66
  287. package/scripts/forge-team/tests/sync-github.test.sh +50 -83
  288. package/scripts/forge-team/tests/verify.test.sh +37 -46
  289. package/scripts/forge-team/tests/workflow-integration.test.sh +4 -4
  290. package/scripts/forge-team/tests/workload.test.sh +32 -66
  291. package/scripts/gen-command-manifest.js +153 -0
  292. package/scripts/gen-embedded-assets.mjs +129 -0
  293. package/scripts/install.ps1 +139 -0
  294. package/scripts/install.sh +268 -0
  295. package/scripts/lib/release-asset.mjs +84 -0
  296. package/scripts/parity-check.mjs +145 -0
  297. package/scripts/parity-check.test.mjs +58 -0
  298. package/scripts/pin-agentic-workflow-images.js +112 -0
  299. package/scripts/pr-auto-actions.js +93 -0
  300. package/scripts/pr-coordinator.sh +3 -0
  301. package/scripts/pr-verdict-label.js +50 -0
  302. package/scripts/preflight-sonar.eslint.config.mjs +44 -0
  303. package/scripts/preflight.sh +21 -94
  304. package/scripts/protected-state-check.js +104 -0
  305. package/scripts/smart-status.sh +60 -57
  306. package/scripts/spikes/config-race-bench.js +111 -0
  307. package/scripts/spikes/harness-capability-matrix.js +13 -0
  308. package/scripts/spikes/patch-anchor-stability-bench.js +125 -0
  309. package/scripts/spikes/protected-path-manifest.js +20 -0
  310. package/scripts/spikes/skill-auto-invoke-parity.js +292 -0
  311. package/scripts/sync-agent-skills.js +62 -0
  312. package/scripts/sync-utils.sh +3 -0
  313. package/scripts/test-ci-shard.js +13 -6
  314. package/scripts/test.js +95 -12
  315. package/skills/claim-safety/SKILL.md +102 -0
  316. package/skills/claim-safety/evals/evals.json +46 -0
  317. package/{.github/prompts/dev.prompt.md → skills/dev/SKILL.md} +44 -50
  318. package/skills/dev/evals/evals.json +50 -0
  319. package/skills/hermes-forge/SKILL.md +185 -0
  320. package/skills/hermes-forge/evals/evals.json +46 -0
  321. package/skills/issue-basics/SKILL.md +111 -0
  322. package/skills/issue-basics/evals/evals.json +46 -0
  323. package/skills/kernel/SKILL.md +166 -0
  324. package/skills/kernel/evals/evals.json +50 -0
  325. package/skills/memory/SKILL.md +102 -0
  326. package/skills/parallel-deep-research/SKILL.md +14 -11
  327. package/skills/parallel-deep-research/evals/evals.json +11 -27
  328. package/{.github/prompts/plan.prompt.md → skills/plan/SKILL.md} +132 -157
  329. package/skills/plan/evals/evals.json +42 -0
  330. package/skills/research/SKILL.md +195 -0
  331. package/skills/research/evals/evals.json +42 -0
  332. package/{.github/prompts/review.prompt.md → skills/review/SKILL.md} +98 -62
  333. package/skills/review/evals/evals.json +42 -0
  334. package/skills/rollback/SKILL.md +110 -0
  335. package/skills/rollback/evals/evals.json +46 -0
  336. package/skills/rollback/references/methods.md +204 -0
  337. package/{.cursor/commands/rollback.md → skills/rollback/references/workflow-integration.md} +10 -284
  338. package/skills/shepherd/SKILL.md +66 -0
  339. package/skills/shepherd/evals/evals.json +42 -0
  340. package/{.github/prompts/ship.prompt.md → skills/ship/SKILL.md} +81 -45
  341. package/skills/ship/evals/evals.json +42 -0
  342. package/skills/smith/SKILL.md +142 -0
  343. package/skills/smith/evals/evals.json +46 -0
  344. package/skills/smith/references/autonomy-and-gates.md +94 -0
  345. package/{.github/prompts/sonarcloud.prompt.md → skills/sonarcloud/SKILL.md} +14 -3
  346. package/skills/sonarcloud/evals/evals.json +46 -0
  347. package/skills/sonarcloud-analysis/SKILL.md +18 -13
  348. package/skills/sonarcloud-analysis/evals/evals.json +11 -15
  349. package/{.github/prompts/status.prompt.md → skills/status/SKILL.md} +20 -10
  350. package/skills/status/evals/evals.json +50 -0
  351. package/skills/triage-ready/SKILL.md +121 -0
  352. package/skills/triage-ready/evals/evals.json +42 -0
  353. package/{.github/prompts/validate.prompt.md → skills/validate/SKILL.md} +52 -29
  354. package/skills/validate/evals/evals.json +42 -0
  355. package/skills/verify/SKILL.md +299 -0
  356. package/skills/verify/evals/evals.json +50 -0
  357. package/.claude/commands/dev.md +0 -345
  358. package/.claude/commands/plan.md +0 -566
  359. package/.claude/commands/premerge.md +0 -186
  360. package/.claude/commands/research.md +0 -42
  361. package/.claude/commands/review.md +0 -451
  362. package/.claude/commands/rollback.md +0 -721
  363. package/.claude/commands/ship.md +0 -213
  364. package/.claude/commands/sonarcloud.md +0 -152
  365. package/.claude/commands/status.md +0 -90
  366. package/.claude/commands/validate.md +0 -288
  367. package/.claude/commands/verify.md +0 -269
  368. package/.claude/rules/workflow.md +0 -121
  369. package/.cline/workflows/dev.md +0 -342
  370. package/.cline/workflows/plan.md +0 -563
  371. package/.cline/workflows/premerge.md +0 -183
  372. package/.cline/workflows/research.md +0 -39
  373. package/.cline/workflows/review.md +0 -448
  374. package/.cline/workflows/rollback.md +0 -718
  375. package/.cline/workflows/ship.md +0 -210
  376. package/.cline/workflows/sonarcloud.md +0 -146
  377. package/.cline/workflows/status.md +0 -87
  378. package/.cline/workflows/validate.md +0 -285
  379. package/.cline/workflows/verify.md +0 -266
  380. package/.codex/config.toml +0 -11
  381. package/.codex/skills/dev/SKILL.md +0 -345
  382. package/.codex/skills/plan/SKILL.md +0 -566
  383. package/.codex/skills/premerge/SKILL.md +0 -186
  384. package/.codex/skills/research/SKILL.md +0 -42
  385. package/.codex/skills/review/SKILL.md +0 -451
  386. package/.codex/skills/rollback/SKILL.md +0 -721
  387. package/.codex/skills/ship/SKILL.md +0 -213
  388. package/.codex/skills/sonarcloud/SKILL.md +0 -149
  389. package/.codex/skills/status/SKILL.md +0 -90
  390. package/.codex/skills/validate/SKILL.md +0 -288
  391. package/.codex/skills/verify/SKILL.md +0 -269
  392. package/.cursor/commands/dev.md +0 -342
  393. package/.cursor/commands/plan.md +0 -563
  394. package/.cursor/commands/premerge.md +0 -183
  395. package/.cursor/commands/research.md +0 -39
  396. package/.cursor/commands/review.md +0 -448
  397. package/.cursor/commands/ship.md +0 -210
  398. package/.cursor/commands/sonarcloud.md +0 -146
  399. package/.cursor/commands/status.md +0 -87
  400. package/.cursor/commands/validate.md +0 -285
  401. package/.cursor/commands/verify.md +0 -266
  402. package/.cursorrules +0 -149
  403. package/.github/prompts/premerge.prompt.md +0 -188
  404. package/.github/prompts/research.prompt.md +0 -44
  405. package/.github/prompts/rollback.prompt.md +0 -723
  406. package/.github/prompts/verify.prompt.md +0 -271
  407. package/.github/workflows/beads-to-github.yml +0 -89
  408. package/.github/workflows/github-to-beads.yml +0 -100
  409. package/.kilocode/workflows/dev.md +0 -346
  410. package/.kilocode/workflows/plan.md +0 -567
  411. package/.kilocode/workflows/premerge.md +0 -187
  412. package/.kilocode/workflows/research.md +0 -43
  413. package/.kilocode/workflows/review.md +0 -452
  414. package/.kilocode/workflows/rollback.md +0 -722
  415. package/.kilocode/workflows/ship.md +0 -214
  416. package/.kilocode/workflows/sonarcloud.md +0 -150
  417. package/.kilocode/workflows/status.md +0 -91
  418. package/.kilocode/workflows/validate.md +0 -289
  419. package/.kilocode/workflows/verify.md +0 -270
  420. package/.opencode/commands/dev.md +0 -345
  421. package/.opencode/commands/plan.md +0 -566
  422. package/.opencode/commands/premerge.md +0 -186
  423. package/.opencode/commands/research.md +0 -42
  424. package/.opencode/commands/review.md +0 -451
  425. package/.opencode/commands/rollback.md +0 -721
  426. package/.opencode/commands/ship.md +0 -213
  427. package/.opencode/commands/sonarcloud.md +0 -149
  428. package/.opencode/commands/status.md +0 -90
  429. package/.opencode/commands/validate.md +0 -288
  430. package/.opencode/commands/verify.md +0 -269
  431. package/.roo/commands/dev.md +0 -346
  432. package/.roo/commands/plan.md +0 -567
  433. package/.roo/commands/premerge.md +0 -187
  434. package/.roo/commands/research.md +0 -43
  435. package/.roo/commands/review.md +0 -452
  436. package/.roo/commands/rollback.md +0 -722
  437. package/.roo/commands/ship.md +0 -214
  438. package/.roo/commands/sonarcloud.md +0 -150
  439. package/.roo/commands/status.md +0 -91
  440. package/.roo/commands/validate.md +0 -289
  441. package/.roo/commands/verify.md +0 -270
  442. package/docs/BEADS_GITHUB_SYNC.md +0 -281
  443. package/docs/GREPTILE_SETUP.md +0 -400
  444. package/docs/MANUAL_REVIEW_GUIDE.md +0 -106
  445. package/docs/SETUP.md +0 -663
  446. package/docs/VALIDATION.md +0 -363
  447. package/lib/agents/cline.plugin.json +0 -29
  448. package/lib/agents/copilot.plugin.json +0 -24
  449. package/lib/agents/kilocode.plugin.json +0 -22
  450. package/lib/agents/opencode.plugin.json +0 -23
  451. package/lib/agents/roo.plugin.json +0 -30
  452. package/lib/beads-bootstrap.js +0 -225
  453. package/lib/beads-health-check.js +0 -188
  454. package/lib/commands/commands-reset.js +0 -147
  455. package/opencode.json +0 -67
  456. package/scripts/beads-context.test.js +0 -584
  457. package/scripts/github-beads-sync/comment.mjs +0 -64
  458. package/scripts/github-beads-sync/config.mjs +0 -148
  459. package/scripts/github-beads-sync/github-api.mjs +0 -131
  460. package/scripts/github-beads-sync/index.mjs +0 -356
  461. package/scripts/github-beads-sync/label-mapper.mjs +0 -54
  462. package/scripts/github-beads-sync/mapping.mjs +0 -132
  463. package/scripts/github-beads-sync/reverse-sync-cli.mjs +0 -31
  464. package/scripts/github-beads-sync/reverse-sync.mjs +0 -162
  465. package/scripts/github-beads-sync/run-bd.mjs +0 -161
  466. package/scripts/github-beads-sync/sanitize.mjs +0 -121
  467. package/scripts/github-beads-sync.config.json +0 -26
  468. package/scripts/sync-commands.js +0 -600
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env bash
2
2
  # smart-status.sh — Workflow intelligence scoring engine
3
3
  #
4
- # Reads issues via `bd list --json --limit 0`, computes a composite score
5
- # for each issue, and outputs them sorted by score descending.
4
+ # Reads issues via `forge issue list --json` (Forge Kernel), computes a composite
5
+ # score for each issue, and outputs them sorted by score descending.
6
6
  #
7
7
  # Composite score:
8
8
  # priority_weight * unblock_chain * type_weight * status_boost * epic_proximity * staleness_boost
@@ -11,7 +11,7 @@
11
11
  # smart-status.sh [--json]
12
12
  #
13
13
  # Environment:
14
- # BD_CMD — override the bd command (for testing with mocks)
14
+ # FORGE_CMD— override the forge command (for testing with mocks)
15
15
  # GIT_CMD — override the git command (for testing with mocks)
16
16
  # DEFAULT_BRANCH — override the default branch name (default: auto-detect)
17
17
  #
@@ -25,7 +25,28 @@ set -euo pipefail
25
25
  # sync-utils.sh: get_session_identity for current developer identity
26
26
 
27
27
  _SMART_STATUS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
28
+ if [ -f "$_SMART_STATUS_DIR/bootstrap-windows-tools.sh" ]; then
29
+ source "$_SMART_STATUS_DIR/bootstrap-windows-tools.sh"
30
+ fi
28
31
  NODE_CMD="${NODE_CMD:-node}"
32
+ JQ_CMD="${JQ_CMD:-jq}"
33
+
34
+ node_script_path() {
35
+ case "$1" in
36
+ /[A-Za-z]/*)
37
+ _drive="$(printf '%s' "${1:1:1}" | tr '[:lower:]' '[:upper:]')"
38
+ printf '%s:/%s\n' "$_drive" "${1:3}"
39
+ ;;
40
+ *)
41
+ if command -v cygpath >/dev/null 2>&1; then
42
+ cygpath -m "$1"
43
+ else
44
+ printf '%s\n' "$1"
45
+ fi
46
+ ;;
47
+ esac
48
+ }
49
+
29
50
  if [ -f "$_SMART_STATUS_DIR/lib/sanitize.sh" ]; then
30
51
  source "$_SMART_STATUS_DIR/lib/sanitize.sh"
31
52
  fi
@@ -59,7 +80,7 @@ fi
59
80
 
60
81
  # ── Dependency check ────────────────────────────────────────────────────
61
82
 
62
- if ! command -v jq &>/dev/null; then
83
+ if ! command -v "$JQ_CMD" &>/dev/null; then
63
84
  echo "Error: jq is required but not found." >&2
64
85
  echo "Install jq:" >&2
65
86
  echo " macOS: brew install jq" >&2
@@ -71,7 +92,7 @@ fi
71
92
  # Warn if jq < 1.6 (fromdateiso8601 and sub/2 require 1.6+)
72
93
  # Strip CR here as well because Windows jq.exe (or a CRLF-emitting wrapper in
73
94
  # tests) can affect the version probe before the jq() shim is defined below.
74
- _jq_version="$(command jq --version 2>/dev/null | tr -d '\r' | sed 's/jq-//')" || true
95
+ _jq_version="$(command "$JQ_CMD" --version 2>/dev/null | tr -d '\r' | sed 's/jq-//')" || true
75
96
  if [ -n "$_jq_version" ]; then
76
97
  _jq_major="${_jq_version%%.*}"
77
98
  _jq_minor="${_jq_version#*.}"; _jq_minor="${_jq_minor%%.*}"
@@ -84,12 +105,12 @@ fi
84
105
  # numeric comparisons like `[ "$count" -gt 0 ]`. Strip trailing CRs from
85
106
  # all jq output after the dependency/version checks above.
86
107
  jq() {
87
- command jq "$@" | tr -d '\r'
108
+ command "$JQ_CMD" "$@" | tr -d '\r'
88
109
  }
89
110
 
90
111
  # ── Configuration ───────────────────────────────────────────────────────
91
112
 
92
- BD="${BD_CMD:-bd}"
113
+ FORGE="${FORGE_CMD:-forge}"
93
114
  GIT="${GIT_CMD:-git}"
94
115
  JSON_MODE=0
95
116
 
@@ -127,42 +148,16 @@ done
127
148
 
128
149
  # ── Fetch issues ────────────────────────────────────────────────────────
129
150
 
130
- # Auto-recover beads database if Dolt server lost the database (e.g. branch
131
- # switch, fresh clone, server restart). Checks for the specific "database
132
- # not found" error, runs bd init --force + bd backup restore, then retries.
133
- # Capture stderr into variable (2>&1 redirects stderr to stdout for capture,
134
- # then >/dev/null discards original stdout so only errors remain).
135
- if ! command -v "$BD" >/dev/null 2>&1; then
136
- echo "Error: bd is required but not found." >&2
137
- exit 1
138
- fi
139
-
140
- _bd_list_err="$("$BD" list --json --limit 0 2>&1 >/dev/null || true)"
141
- if printf '%s' "$_bd_list_err" | grep -qi "database.*not found"; then
142
- _repo_root="$("$GIT" rev-parse --show-toplevel 2>/dev/null || pwd)"
143
- _metadata_path="$_repo_root/.beads/metadata.json"
144
- _bd_prefix=""
145
- if [ -f "$_metadata_path" ]; then
146
- if _metadata_prefix="$(jq -r '(.dolt_database // "") | strings' "$_metadata_path" 2>/dev/null)"; then
147
- _bd_prefix="$(printf '%s' "$_metadata_prefix" | tr -d '\r')"
148
- fi
149
- fi
150
- if [ -z "$_bd_prefix" ]; then
151
- _bd_prefix="$(basename "$_repo_root" | tr '[:upper:]' '[:lower:]' | tr -cs '[:alnum:]-' '-' | sed 's/^-//;s/-$//')"
152
- fi
153
- echo "Beads database not found - attempting auto-recovery..." >&2
154
- if "$BD" init --force --prefix "$_bd_prefix" >/dev/null 2>&1; then
155
- if [ -d "$_repo_root/.beads/backup" ] && ls "$_repo_root/.beads/backup"/*.jsonl >/dev/null 2>&1; then
156
- "$BD" backup restore >/dev/null 2>&1 && echo "Beads: restored from backup." >&2 || echo "Beads: backup restore failed." >&2
157
- else
158
- echo "Beads: initialized fresh (no backup found)." >&2
159
- fi
160
- else
161
- echo "Beads: auto-recovery failed - run 'bd doctor' manually." >&2
162
- fi
163
- fi
164
-
165
- ISSUES_JSON="$("$BD" list --json --limit 0 2>/dev/null || echo '[]')"
151
+ # Fetch issues from the Forge Kernel and normalize the envelope into the bare
152
+ # array the scorer + grouping expect: extract .data.issues and drop terminal
153
+ # (done/cancelled) issues so completed work never pollutes the work queue. The
154
+ # kernel already supplies each issue's `dependents` (reverse-graph) and
155
+ # `dependencies` arrays, so no per-issue reshaping is needed. The kernel
156
+ # auto-migrates its single-machine SQLite store on read — nothing to recover.
157
+ ISSUES_JSON="$("$FORGE" issue list --json 2>/dev/null | jq '[
158
+ .data.issues[]
159
+ | select(.status != "done" and .status != "cancelled")
160
+ ]' 2>/dev/null || echo '[]')"
166
161
 
167
162
  # Bail early on empty
168
163
  if [ "$(printf '%s' "$ISSUES_JSON" | jq 'length')" = "0" ]; then
@@ -185,9 +180,14 @@ if [ -n "$EPIC_IDS" ]; then
185
180
  # Process each epic (bash 3.2 compatible — read line by line)
186
181
  while IFS= read -r epic_id; do
187
182
  [ -z "$epic_id" ] && continue
188
- CHILDREN_JSON="$("$BD" children "$epic_id" --json 2>/dev/null || echo '[]')"
189
- TOTAL="$(printf '%s' "$CHILDREN_JSON" | jq 'length')"
190
- CLOSED="$(printf '%s' "$CHILDREN_JSON" | jq '[.[] | select(.status == "closed")] | length')"
183
+ # Kernel `forge issue children` returns the rollup envelope; read total + the done
184
+ # count straight from the kernel-computed rollup (the kernel `done` status replaces
185
+ # the beads `closed` this math used to count). EPIC_STATS keeps its { total, closed }
186
+ # shape, so smart-status-score.js / scoring.js:getEpicProximity stay untouched.
187
+ CHILDREN_JSON="$("$FORGE" issue children "$epic_id" --json 2>/dev/null || echo '{}')"
188
+ [ -z "$CHILDREN_JSON" ] && CHILDREN_JSON='{}'
189
+ TOTAL="$(printf '%s' "$CHILDREN_JSON" | jq -r '(.data.rollup.total // 0)')"
190
+ CLOSED="$(printf '%s' "$CHILDREN_JSON" | jq -r '(.data.rollup.done // 0)')"
191
191
  EPIC_STATS="$(printf '%s' "$EPIC_STATS" | jq --arg id "$epic_id" --argjson total "$TOTAL" --argjson closed "$CLOSED" '. + {($id): {total: $total, closed: $closed}}')"
192
192
  done <<EOF
193
193
  $EPIC_IDS
@@ -201,7 +201,7 @@ if ! command -v "$NODE_CMD" >/dev/null 2>&1; then
201
201
  exit 1
202
202
  fi
203
203
 
204
- SCORED_JSON="$(printf '{"issues":%s,"epicStats":%s}' "$ISSUES_JSON" "$EPIC_STATS" | "$NODE_CMD" "$_SMART_STATUS_DIR/smart-status-score.js")"
204
+ SCORED_JSON="$(printf '{"issues":%s,"epicStats":%s}' "$ISSUES_JSON" "$EPIC_STATS" | "$NODE_CMD" "$(node_script_path "$_SMART_STATUS_DIR/smart-status-score.js")")"
205
205
 
206
206
  # ── Session detection ─────────────────────────────────────────────────
207
207
 
@@ -218,16 +218,15 @@ WORKTREE_PORCELAIN="$("$GIT" worktree list --porcelain 2>/dev/null || echo '')"
218
218
  # only performs command execution and rendering.
219
219
  IN_PROGRESS_JSON="[]"
220
220
  if [ -n "$WORKTREE_PORCELAIN" ]; then
221
- IN_PROGRESS_JSON="$("$BD" list --status in_progress --json --limit 0 2>/dev/null || echo '')"
222
- if [ -z "$IN_PROGRESS_JSON" ] || ! printf '%s' "$IN_PROGRESS_JSON" | jq empty 2>/dev/null; then
223
- IN_PROGRESS_JSON="$(printf '%s' "$ISSUES_JSON" | jq '[.[] | select(.status == "in_progress")]')"
224
- fi
221
+ # In-progress issues come straight from the already-fetched kernel list (it
222
+ # includes in_progress; only done/cancelled were dropped during the fetch).
223
+ IN_PROGRESS_JSON="$(printf '%s' "$ISSUES_JSON" | jq '[.[] | select(.status == "in_progress")]')"
225
224
  fi
226
225
 
227
226
  SESSIONS_JSON="$(printf '{"baseBranch":%s,"worktreePorcelain":%s,"inProgressIssues":%s}' \
228
227
  "$(printf '%s' "$BASE_BRANCH" | jq -R '.')" \
229
228
  "$(printf '%s' "$WORKTREE_PORCELAIN" | jq -Rs '.')" \
230
- "$IN_PROGRESS_JSON" | "$NODE_CMD" "$_SMART_STATUS_DIR/smart-status-sessions.js")"
229
+ "$IN_PROGRESS_JSON" | "$NODE_CMD" "$(node_script_path "$_SMART_STATUS_DIR/smart-status-sessions.js")")"
231
230
  SESSION_COUNT="$(printf '%s' "$SESSIONS_JSON" | jq 'length')"
232
231
 
233
232
  if [ "$SESSION_COUNT" -ge 2 ]; then
@@ -246,7 +245,7 @@ if [ "$SESSION_COUNT" -ge 2 ]; then
246
245
  $_session_branches
247
246
  BRANCHEOF
248
247
 
249
- SESSIONS_JSON="$(printf '{"sessions":%s,"branchFiles":%s}' "$SESSIONS_JSON" "$BRANCH_FILES_JSON" | "$NODE_CMD" "$_SMART_STATUS_DIR/smart-status-sessions.js")"
248
+ SESSIONS_JSON="$(printf '{"sessions":%s,"branchFiles":%s}' "$SESSIONS_JSON" "$BRANCH_FILES_JSON" | "$NODE_CMD" "$(node_script_path "$_SMART_STATUS_DIR/smart-status-sessions.js")")"
250
249
  fi
251
250
 
252
251
  TIER2_ENABLED=0
@@ -294,7 +293,7 @@ if [ "$TIER2_ENABLED" = "1" ]; then
294
293
  $_conflict_pairs
295
294
  PAIRSEOF
296
295
 
297
- SESSIONS_JSON="$(printf '{"sessions":%s,"mergeTreeResults":%s}' "$SESSIONS_JSON" "$MERGE_TREE_RESULTS_JSON" | "$NODE_CMD" "$_SMART_STATUS_DIR/smart-status-sessions.js")"
296
+ SESSIONS_JSON="$(printf '{"sessions":%s,"mergeTreeResults":%s}' "$SESSIONS_JSON" "$MERGE_TREE_RESULTS_JSON" | "$NODE_CMD" "$(node_script_path "$_SMART_STATUS_DIR/smart-status-sessions.js")")"
298
297
  fi
299
298
  fi
300
299
 
@@ -478,14 +477,18 @@ else
478
477
  # Group assignment (priority order: RESUME > UNBLOCK_CHAINS > BLOCKED > BACKLOG > READY_WORK)
479
478
  # Note: in_progress issues with active blockers still show in RESUME (you started
480
479
  # the work, you need to see it) but get a "BLOCKED" annotation in the output.
480
+ # Counts come from the scorer output: dependents is the reverse-graph
481
+ # array it computes, dependencies is the normalized { depends_on_id }
482
+ # list. done/cancelled were dropped at fetch; the status guards below stay
483
+ # as defense-in-depth so a terminal issue can never land in BLOCKED.
481
484
  (if .status == "in_progress" then "RESUME"
482
- elif (.dependent_count // 0) >= 2 then "UNBLOCK_CHAINS"
483
- elif (.dependency_count // 0) > 0 and .status != "closed" then "BLOCKED"
485
+ elif ((.dependents // []) | length) >= 2 then "UNBLOCK_CHAINS"
486
+ elif ((.dependencies // []) | length) > 0 and .status != "done" and .status != "cancelled" then "BLOCKED"
484
487
  elif (.priority == "P4" or .priority == 4) then "BACKLOG"
485
488
  else "READY_WORK"
486
489
  end) as $group |
487
490
  # Flag in_progress issues that have active blockers
488
- (if .status == "in_progress" and (.dependency_count // 0) > 0 then true else false end) as $blocked_resume |
491
+ (if .status == "in_progress" and ((.dependencies // []) | length) > 0 then true else false end) as $blocked_resume |
489
492
  $item + { group: $group, days_ago: $days_ago, blocked_resume: $blocked_resume }
490
493
  ] |
491
494
 
@@ -0,0 +1,111 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const { performance } = require('node:perf_hooks');
5
+
6
+ function readNumberFlag(args, name, fallback) {
7
+ const index = args.indexOf(name);
8
+ if (index === -1) return fallback;
9
+ const value = Number(args[index + 1]);
10
+ if (!Number.isFinite(value) || value < 0) {
11
+ throw new Error(`${name} must be a non-negative number`);
12
+ }
13
+ return value;
14
+ }
15
+
16
+ function assertPositiveInteger(name, value) {
17
+ if (!Number.isInteger(value) || value <= 0) {
18
+ throw new Error(`${name} must be a positive integer`);
19
+ }
20
+ }
21
+
22
+ function machinePatch(trial, machine) {
23
+ const sharedValue = trial % 10 === 0 ? `shared-${trial}` : undefined;
24
+ const conflictingValue = trial === 37 ? `${machine}-conflict-${trial}` : undefined;
25
+ return {
26
+ machine,
27
+ global: {
28
+ ...(sharedValue ? { 'stage.review.timeout': sharedValue } : {}),
29
+ ...(conflictingValue ? { 'stage.dev.parallelism': conflictingValue } : {}),
30
+ },
31
+ machineLocal: {
32
+ [`${machine}.shell`]: machine === 'machine-a' ? 'git-bash' : 'pwsh',
33
+ [`${machine}.workspace`]: `.forge/machines/${machine}`,
34
+ },
35
+ };
36
+ }
37
+
38
+ function mergeTrial(trial) {
39
+ const left = machinePatch(trial, 'machine-a');
40
+ const right = machinePatch(trial, 'machine-b');
41
+ const merged = { global: {}, machineLocal: {} };
42
+ const conflicts = [];
43
+
44
+ for (const patch of [left, right]) {
45
+ Object.assign(merged.machineLocal, patch.machineLocal);
46
+ }
47
+
48
+ const globalKeys = new Set([...Object.keys(left.global), ...Object.keys(right.global)]);
49
+ for (const key of globalKeys) {
50
+ const leftHas = Object.prototype.hasOwnProperty.call(left.global, key);
51
+ const rightHas = Object.prototype.hasOwnProperty.call(right.global, key);
52
+ if (leftHas && rightHas && left.global[key] !== right.global[key]) {
53
+ conflicts.push(key);
54
+ continue;
55
+ }
56
+ merged.global[key] = leftHas ? left.global[key] : right.global[key];
57
+ }
58
+
59
+ return {
60
+ trial,
61
+ manualResolve: conflicts.length > 0,
62
+ conflicts,
63
+ mergedKeyCount: Object.keys(merged.global).length + Object.keys(merged.machineLocal).length,
64
+ };
65
+ }
66
+
67
+ function runBench(options = {}) {
68
+ const trials = options.trials ?? 50;
69
+ const threshold = options.threshold ?? 0.05;
70
+ assertPositiveInteger('trials', trials);
71
+
72
+ const start = performance.now();
73
+ const results = Array.from({ length: trials }, (_, index) => mergeTrial(index + 1));
74
+ const manualResolves = results.filter((result) => result.manualResolve);
75
+ const manualResolveRate = manualResolves.length / trials;
76
+ const elapsedMs = performance.now() - start;
77
+
78
+ return {
79
+ spike: 'cross-machine-config-race',
80
+ trials,
81
+ manualResolves: manualResolves.length,
82
+ manualResolveRate,
83
+ threshold,
84
+ passed: manualResolveRate < threshold,
85
+ elapsedMs: Number(elapsedMs.toFixed(3)),
86
+ complexity: 'O(trials * changed keys); machine-local files avoid shared-file git conflicts',
87
+ conflictTrials: manualResolves.map((result) => ({
88
+ trial: result.trial,
89
+ conflicts: result.conflicts,
90
+ })),
91
+ };
92
+ }
93
+
94
+ function main() {
95
+ const args = process.argv.slice(2);
96
+ const result = runBench({
97
+ trials: readNumberFlag(args, '--trials', 50),
98
+ threshold: readNumberFlag(args, '--threshold', 0.05),
99
+ });
100
+
101
+ console.log(JSON.stringify(result, null, args.includes('--json') ? 0 : 2));
102
+ if (!result.passed) {
103
+ process.exitCode = 1;
104
+ }
105
+ }
106
+
107
+ if (require.main === module) {
108
+ main();
109
+ }
110
+
111
+ module.exports = { runBench, mergeTrial };
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const { buildHarnessCapabilityEvidence } = require('../../lib/harness-capability-matrix');
5
+
6
+ function main() {
7
+ const evidence = buildHarnessCapabilityEvidence();
8
+ console.log(JSON.stringify(evidence, null, 2));
9
+ }
10
+
11
+ if (require.main === module) {
12
+ main();
13
+ }
@@ -0,0 +1,125 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const { performance } = require('node:perf_hooks');
5
+
6
+ function readNumberFlag(args, name, fallback) {
7
+ const index = args.indexOf(name);
8
+ if (index === -1) return fallback;
9
+ const value = Number(args[index + 1]);
10
+ if (!Number.isFinite(value) || value < 0) {
11
+ throw new Error(`${name} must be a non-negative number`);
12
+ }
13
+ return value;
14
+ }
15
+
16
+ function assertPositiveInteger(name, value) {
17
+ if (!Number.isInteger(value) || value <= 0) {
18
+ throw new Error(`${name} must be a positive integer`);
19
+ }
20
+ }
21
+
22
+ function assertNonNegativeInteger(name, value) {
23
+ if (!Number.isInteger(value) || value < 0) {
24
+ throw new Error(`${name} must be a non-negative integer`);
25
+ }
26
+ }
27
+
28
+ function runBench(options = {}) {
29
+ const anchorCount = options.anchorCount ?? 500;
30
+ const patchCount = options.patchCount ?? 50;
31
+ const renameCount = options.renameCount ?? patchCount;
32
+ const unmappedCount = options.unmappedCount ?? 2;
33
+ const threshold = options.threshold ?? 0.10;
34
+
35
+ assertPositiveInteger('anchorCount', anchorCount);
36
+ assertPositiveInteger('patchCount', patchCount);
37
+ assertNonNegativeInteger('renameCount', renameCount);
38
+ assertNonNegativeInteger('unmappedCount', unmappedCount);
39
+ if (patchCount > anchorCount) {
40
+ throw new Error('patchCount must be <= anchorCount');
41
+ }
42
+ if (renameCount > patchCount) {
43
+ throw new Error('renameCount must be <= patchCount');
44
+ }
45
+ if (unmappedCount > renameCount) {
46
+ throw new Error('unmappedCount must be <= renameCount');
47
+ }
48
+
49
+ const start = performance.now();
50
+ const oldAnchors = Array.from({ length: anchorCount }, (_, i) => `stage.${i}.body`);
51
+ const patches = oldAnchors.slice(0, patchCount).map((anchor, i) => ({
52
+ id: `patch-${String(i + 1).padStart(3, '0')}`,
53
+ anchor,
54
+ }));
55
+
56
+ const currentAnchors = new Set(oldAnchors);
57
+ const aliases = new Map();
58
+ for (let i = 0; i < renameCount; i += 1) {
59
+ const oldAnchor = oldAnchors[i];
60
+ const newAnchor = `${oldAnchor}.v2`;
61
+ currentAnchors.delete(oldAnchor);
62
+ currentAnchors.add(newAnchor);
63
+ if (i >= unmappedCount) {
64
+ aliases.set(oldAnchor, newAnchor);
65
+ }
66
+ }
67
+
68
+ let resolved = 0;
69
+ let orphaned = 0;
70
+ const orphanIds = [];
71
+ for (const patch of patches) {
72
+ if (currentAnchors.has(patch.anchor)) {
73
+ resolved += 1;
74
+ continue;
75
+ }
76
+ const alias = aliases.get(patch.anchor);
77
+ if (alias && currentAnchors.has(alias)) {
78
+ resolved += 1;
79
+ continue;
80
+ }
81
+ orphaned += 1;
82
+ orphanIds.push(patch.id);
83
+ }
84
+
85
+ const elapsedMs = performance.now() - start;
86
+ const orphanRate = orphaned / patchCount;
87
+ return {
88
+ spike: 'patch-anchor-stability',
89
+ patchCount,
90
+ anchorCount,
91
+ renamedAnchors: renameCount,
92
+ aliasEntries: aliases.size,
93
+ orphaned,
94
+ resolved,
95
+ orphanRate,
96
+ threshold,
97
+ passed: orphanRate < threshold,
98
+ elapsedMs: Number(elapsedMs.toFixed(3)),
99
+ complexity: 'O(patches + anchors + aliases) with Map/Set lookups',
100
+ orphanIds,
101
+ };
102
+ }
103
+
104
+ function main() {
105
+ const args = process.argv.slice(2);
106
+ const patchCount = readNumberFlag(args, '--patches', 50);
107
+ const result = runBench({
108
+ anchorCount: readNumberFlag(args, '--anchors', 500),
109
+ patchCount,
110
+ renameCount: readNumberFlag(args, '--renames', patchCount),
111
+ unmappedCount: readNumberFlag(args, '--unmapped', 2),
112
+ threshold: readNumberFlag(args, '--threshold', 0.10),
113
+ });
114
+
115
+ console.log(JSON.stringify(result, null, args.includes('--json') ? 0 : 2));
116
+ if (!result.passed) {
117
+ process.exitCode = 1;
118
+ }
119
+ }
120
+
121
+ if (require.main === module) {
122
+ main();
123
+ }
124
+
125
+ module.exports = { runBench };
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const path = require('node:path');
5
+ const {
6
+ buildProtectedPathManifestEvidence,
7
+ loadProtectedPathManifest,
8
+ } = require('../../lib/protected-path-manifest');
9
+
10
+ const root = path.resolve(__dirname, '..', '..');
11
+ const manifestPath = path.join(root, '.forge', 'protected-paths.yaml');
12
+
13
+ try {
14
+ const manifest = loadProtectedPathManifest(manifestPath);
15
+ process.stdout.write(`${JSON.stringify(buildProtectedPathManifestEvidence(manifest), null, 2)}\n`);
16
+ } catch (error) {
17
+ const message = error instanceof Error ? error.message : String(error);
18
+ process.stderr.write(`Failed to build protected path manifest evidence from ${manifestPath}: ${message}\n`);
19
+ process.exit(1);
20
+ }