forge-workflow 0.0.10 → 0.1.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (454) hide show
  1. package/.claude/rules/{greptile-review-process.md → review-process.md} +56 -41
  2. package/.claude/scripts/{greptile-resolve.sh → review-resolve.sh} +13 -3
  3. package/.cursor/rules/permissions-guidance.mdc +2 -2
  4. package/.forge/hooks/check-tdd.js +3 -0
  5. package/.forge/hooks/forge-native-hook.js +245 -0
  6. package/.forge/protected-paths.yaml +157 -0
  7. package/AGENTS.md +150 -61
  8. package/CHANGELOG.md +681 -0
  9. package/CLAUDE.md +9 -118
  10. package/QUICKSTART.md +171 -0
  11. package/README.md +271 -363
  12. package/bin/forge-cmd.js +120 -9
  13. package/bin/forge-preflight.js +26 -5
  14. package/bin/forge.js +461 -489
  15. package/docs/INDEX.md +93 -0
  16. package/docs/PROJECT_DESIGN.md +685 -0
  17. package/docs/architecture/index.md +66 -0
  18. package/docs/architecture/notes/README.md +35 -0
  19. package/docs/architecture/subsystems/README.md +46 -0
  20. package/docs/forge/TOOLCHAIN.md +670 -0
  21. package/docs/forge/VALIDATION.md +82 -0
  22. package/docs/{AGENT_INSTALL_PROMPT.md → guides/AGENT_INSTALL_PROMPT.md} +3 -3
  23. package/docs/guides/BEADS_GITHUB_SYNC.md +32 -0
  24. package/docs/{ENHANCED_ONBOARDING.md → guides/ENHANCED_ONBOARDING.md} +16 -12
  25. package/docs/guides/GREPTILE_SETUP.md +46 -0
  26. package/docs/guides/MANUAL_REVIEW_GUIDE.md +58 -0
  27. package/docs/guides/MIGRATION.md +56 -0
  28. package/docs/guides/SETUP.md +118 -0
  29. package/docs/guides/SUPPORT.md +185 -0
  30. package/docs/guides/WORKFLOW_TEMPLATES.md +74 -0
  31. package/docs/guides/memory-backends.md +183 -0
  32. package/docs/reference/ADAPTERS.md +128 -0
  33. package/docs/reference/AGENT_SKILL_PARITY.md +175 -0
  34. package/docs/reference/COMMANDS.md +205 -0
  35. package/docs/reference/DECISION_DRIFT_GUARDS.md +97 -0
  36. package/docs/{EXAMPLES.md → reference/EXAMPLES.md} +7 -5
  37. package/docs/reference/FORGE_KERNEL_STORAGE_MODEL.md +135 -0
  38. package/docs/reference/HERMES_INTEGRATION.md +118 -0
  39. package/docs/reference/INSIGHTS_RECAP.md +63 -0
  40. package/docs/reference/INSTALL.md +164 -0
  41. package/docs/reference/KERNEL_TAXONOMY_VALIDATION.md +161 -0
  42. package/docs/reference/PROTECTED_PATH_MANIFEST.md +25 -0
  43. package/docs/reference/RELEASE.md +68 -0
  44. package/docs/reference/RESEARCH_TEMPLATE.md +292 -0
  45. package/docs/{ROADMAP.md → reference/ROADMAP.md} +12 -9
  46. package/docs/reference/SKILLS.md +35 -0
  47. package/docs/reference/STATUS_BOARD.md +80 -0
  48. package/docs/reference/TEMPLATES.md +106 -0
  49. package/docs/{TOOLCHAIN.md → reference/TOOLCHAIN.md} +62 -47
  50. package/docs/reference/VALIDATION.md +82 -0
  51. package/docs/reference/agent-permissions.md +169 -0
  52. package/docs/reference/beads-to-kernel-migration-ux.md +61 -0
  53. package/docs/reference/control-plane-guarantees.md +125 -0
  54. package/docs/reference/dependency-chain.md +331 -0
  55. package/docs/reference/forge-kernel-issue-command-contract.md +161 -0
  56. package/docs/reference/forge-kernel-schema.md +72 -0
  57. package/docs/reference/kernel-conflict-evaluators.md +27 -0
  58. package/docs/reference/patch-md-format.md +77 -0
  59. package/docs/reference/protected-state-surfaces.md +59 -0
  60. package/docs/reference/shepherd.md +115 -0
  61. package/docs/reference/superpowers-analysis.md +320 -0
  62. package/docs/reference/superpowers-integration-options.md +404 -0
  63. package/docs/reference/test-environment.md +519 -0
  64. package/docs/reference/upgrade-safety.md +59 -0
  65. package/lefthook.yml +18 -0
  66. package/lib/adapter-cli.js +307 -0
  67. package/lib/adapters/beads-issue-adapter.js +127 -0
  68. package/lib/adapters/beads-kernel-compat.js +1042 -0
  69. package/lib/adapters/greptile-review-adapter.js +141 -0
  70. package/lib/adapters/kernel-issue-adapter.js +101 -0
  71. package/lib/adapters/pr-state-adapter.js +484 -0
  72. package/lib/adoption-profiles.js +126 -0
  73. package/lib/agents/README.md +2 -6
  74. package/lib/agents/claude.plugin.json +3 -8
  75. package/lib/agents/codex.plugin.json +9 -1
  76. package/lib/agents/cursor.plugin.json +2 -6
  77. package/lib/agents/hermes.plugin.json +22 -0
  78. package/lib/agents-config.js +39 -1236
  79. package/lib/audit-evidence.js +282 -0
  80. package/lib/beads-setup.js +121 -0
  81. package/lib/beads-sync-scaffold.js +25 -101
  82. package/lib/codex-skills.js +51 -1
  83. package/lib/commands/_issue.js +741 -77
  84. package/lib/commands/_manifest.js +91 -0
  85. package/lib/commands/_registry.js +85 -34
  86. package/lib/commands/_resolve-command-opts.js +261 -0
  87. package/lib/commands/_serve-security.js +270 -0
  88. package/lib/commands/adapter.js +12 -0
  89. package/lib/commands/add.js +118 -0
  90. package/lib/commands/audit.js +70 -0
  91. package/lib/commands/blocked.js +5 -0
  92. package/lib/commands/board.js +64 -0
  93. package/lib/commands/claim.js +21 -2
  94. package/lib/commands/claims.js +7 -0
  95. package/lib/commands/clean.js +485 -75
  96. package/lib/commands/close.js +2 -2
  97. package/lib/commands/comment.js +5 -0
  98. package/lib/commands/control.js +148 -0
  99. package/lib/commands/create.js +2 -2
  100. package/lib/commands/dev.js +185 -7
  101. package/lib/commands/doc-gate.js +336 -0
  102. package/lib/commands/doctor.js +156 -0
  103. package/lib/commands/explain.js +15 -0
  104. package/lib/commands/export.js +237 -0
  105. package/lib/commands/gate.js +192 -0
  106. package/lib/commands/hooks.js +242 -0
  107. package/lib/commands/inbox.js +118 -0
  108. package/lib/commands/init.js +598 -0
  109. package/lib/commands/insights.js +79 -0
  110. package/lib/commands/issue.js +12 -1
  111. package/lib/commands/issues.js +17 -0
  112. package/lib/commands/lint.js +5 -0
  113. package/lib/commands/list.js +2 -2
  114. package/lib/commands/merge.js +312 -0
  115. package/lib/commands/migrate.js +523 -0
  116. package/lib/commands/new.js +12 -0
  117. package/lib/commands/options.js +241 -0
  118. package/lib/commands/orient.js +13 -0
  119. package/lib/commands/orphans.js +5 -0
  120. package/lib/commands/patch.js +67 -0
  121. package/lib/commands/plan.js +436 -24
  122. package/lib/commands/preflight.js +211 -0
  123. package/lib/commands/prime.js +13 -0
  124. package/lib/commands/push.js +69 -2
  125. package/lib/commands/ready.js +2 -2
  126. package/lib/commands/recall.js +116 -0
  127. package/lib/commands/recap.js +61 -0
  128. package/lib/commands/recommend.js +0 -1
  129. package/lib/commands/release.js +91 -0
  130. package/lib/commands/remember.js +74 -0
  131. package/lib/commands/role.js +99 -0
  132. package/lib/commands/serve.js +581 -0
  133. package/lib/commands/setup.js +838 -972
  134. package/lib/commands/shepherd.js +436 -0
  135. package/lib/commands/ship.js +23 -1
  136. package/lib/commands/show.js +2 -2
  137. package/lib/commands/stage.js +192 -0
  138. package/lib/commands/stale.js +5 -0
  139. package/lib/commands/status.js +158 -21
  140. package/lib/commands/sync.js +34 -46
  141. package/lib/commands/team.js +4 -1
  142. package/lib/commands/test.js +43 -27
  143. package/lib/commands/update.js +2 -2
  144. package/lib/commands/upgrade.js +47 -0
  145. package/lib/commands/validate.js +43 -18
  146. package/lib/commands/worktree.js +307 -100
  147. package/lib/config-writer.js +202 -0
  148. package/lib/control-plane.js +236 -0
  149. package/lib/core/runtime-graph.js +946 -0
  150. package/lib/dep-guard/keyword-ripple.js +2 -2
  151. package/lib/deprecated-sync-cleanup.js +362 -0
  152. package/lib/detect-agent.js +2 -28
  153. package/lib/detect-worktree.js +35 -9
  154. package/lib/doc-gate/declaration.js +177 -0
  155. package/lib/doc-gate/detect.js +289 -0
  156. package/lib/doc-gate/gate.js +375 -0
  157. package/lib/doc-gate/okf-config.js +128 -0
  158. package/lib/doc-gate/okf.js +429 -0
  159. package/lib/docs-command.js +1161 -6
  160. package/lib/forge-issues.js +382 -11
  161. package/lib/forge-lock.js +262 -0
  162. package/lib/gate-events.js +193 -0
  163. package/lib/global-flags.js +74 -0
  164. package/lib/greptile-match.js +7 -63
  165. package/lib/harness-capability-matrix.js +380 -0
  166. package/lib/hook-global-installer.js +347 -0
  167. package/lib/hook-renderer.js +451 -0
  168. package/lib/inbox.js +391 -0
  169. package/lib/insights.js +397 -0
  170. package/lib/issue-adapter.js +156 -0
  171. package/lib/issue-backend.js +145 -0
  172. package/lib/issue-render.js +220 -0
  173. package/lib/kernel/backing-issue.js +305 -0
  174. package/lib/kernel/broker.js +1218 -0
  175. package/lib/kernel/cli-broker-factory.js +130 -0
  176. package/lib/kernel/conflict-signal.js +82 -0
  177. package/lib/kernel/evaluators.js +195 -0
  178. package/lib/kernel/fs-class.js +495 -0
  179. package/lib/kernel/issue-command-contract.js +559 -0
  180. package/lib/kernel/issue-id-resolver.js +186 -0
  181. package/lib/kernel/lease-enforcer.js +158 -0
  182. package/lib/kernel/migrations.js +333 -0
  183. package/lib/kernel/planning-buckets-schema.js +109 -0
  184. package/lib/kernel/projection-jsonl-writer.js +450 -0
  185. package/lib/kernel/readiness-model.js +329 -0
  186. package/lib/kernel/schema.js +356 -0
  187. package/lib/kernel/sqlite-driver.js +2504 -0
  188. package/lib/kernel/taxonomy-validator.js +394 -0
  189. package/lib/lefthook-check.js +3 -2
  190. package/lib/lefthook-wiring.js +413 -0
  191. package/lib/mcp-config-renderer.js +288 -0
  192. package/lib/memory/graphiti-mcp.js +106 -0
  193. package/lib/memory/router.js +387 -0
  194. package/lib/memory/typed-api.js +102 -0
  195. package/lib/memory-digest.js +195 -0
  196. package/lib/merge-rules.js +395 -0
  197. package/lib/migrate-dry-run.js +466 -0
  198. package/lib/orientation.js +863 -0
  199. package/lib/package-manager-remediation.js +103 -0
  200. package/lib/package-root.js +381 -0
  201. package/lib/patch-intent.js +890 -0
  202. package/lib/plugin-catalog.js +3 -4
  203. package/lib/plugin-manager.js +0 -5
  204. package/lib/pr-bundle.js +186 -0
  205. package/lib/pr-monitor/differ.js +195 -0
  206. package/lib/pr-monitor/events.js +0 -0
  207. package/lib/pr-monitor/gather.js +124 -0
  208. package/lib/pr-monitor/journal.js +299 -0
  209. package/lib/pr-monitor/monitor.js +146 -0
  210. package/lib/pr-monitor/render-sticky.js +157 -0
  211. package/lib/pr-monitor/watch-lifecycle.js +95 -0
  212. package/lib/pr-monitor/watch.js +247 -0
  213. package/lib/pr-pull.js +1273 -0
  214. package/lib/pr-shepherd.js +494 -0
  215. package/lib/pr-state-validator.js +59 -0
  216. package/lib/preflight/gates.js +237 -0
  217. package/lib/preflight/runner.js +116 -0
  218. package/lib/project-discovery.js +0 -53
  219. package/lib/project-memory.js +99 -497
  220. package/lib/protected-path-manifest.js +281 -0
  221. package/lib/protected-state-surfaces.js +387 -0
  222. package/lib/release-readiness.js +2089 -0
  223. package/lib/reset.js +59 -45
  224. package/lib/review-adapter.js +68 -0
  225. package/lib/rules-sync.js +260 -0
  226. package/lib/runtime-health.js +241 -20
  227. package/lib/safety-config-renderer.js +268 -0
  228. package/lib/setup-action-log.js +1 -7
  229. package/lib/setup.js +27 -65
  230. package/lib/shell-utils.js +76 -6
  231. package/lib/skills-sync.js +330 -0
  232. package/lib/smart-status/scoring.js +17 -3
  233. package/lib/status/beads-snapshot.js +45 -2
  234. package/lib/status/presenter.js +169 -18
  235. package/lib/status/snapshot.js +186 -0
  236. package/lib/sync-backend.js +202 -0
  237. package/lib/untrusted-content.js +52 -0
  238. package/lib/upgrade-safety.js +199 -0
  239. package/lib/workflow/enforce-stage.js +296 -47
  240. package/lib/workflow/stage-transition.js +115 -0
  241. package/lib/workflow/stages.js +30 -6
  242. package/lib/workflow/state-manager.js +11 -22
  243. package/lib/workflow/state.js +23 -1
  244. package/lib/workflow-profiles.js +17 -5
  245. package/package.json +37 -35
  246. package/rules/documentation.md +19 -0
  247. package/rules/kernel-tracking.md +26 -0
  248. package/rules/security.md +22 -0
  249. package/rules/tdd.md +20 -0
  250. package/rules/workflow.md +27 -0
  251. package/scripts/auto-backing-issue.js +47 -0
  252. package/scripts/beads-context.sh +81 -57
  253. package/scripts/beads-upgrade-smoke.sh +24 -3
  254. package/scripts/bootstrap-windows-tools.sh +78 -0
  255. package/scripts/branch-protection.js +2 -3
  256. package/scripts/check-agents.js +34 -137
  257. package/scripts/commitlint.js +3 -1
  258. package/scripts/conflict-detect.sh +3 -0
  259. package/scripts/dep-guard.sh +22 -3
  260. package/scripts/file-index.sh +3 -0
  261. package/scripts/forge-team/lib/claim.sh +34 -18
  262. package/scripts/forge-team/lib/dashboard.sh +61 -86
  263. package/scripts/forge-team/lib/epic.sh +99 -263
  264. package/scripts/forge-team/lib/hooks.sh +26 -28
  265. package/scripts/forge-team/lib/identity.sh +4 -4
  266. package/scripts/forge-team/lib/sync-github.sh +49 -84
  267. package/scripts/forge-team/lib/verify.sh +93 -83
  268. package/scripts/forge-team/lib/workload.sh +41 -65
  269. package/scripts/forge-team/tests/claim.test.sh +25 -19
  270. package/scripts/forge-team/tests/dashboard.test.sh +31 -46
  271. package/scripts/forge-team/tests/epic.test.sh +52 -71
  272. package/scripts/forge-team/tests/hooks.test.sh +38 -50
  273. package/scripts/forge-team/tests/identity.test.sh +3 -3
  274. package/scripts/forge-team/tests/integration.test.sh +44 -66
  275. package/scripts/forge-team/tests/sync-github.test.sh +50 -83
  276. package/scripts/forge-team/tests/verify.test.sh +37 -46
  277. package/scripts/forge-team/tests/workflow-integration.test.sh +4 -4
  278. package/scripts/forge-team/tests/workload.test.sh +32 -66
  279. package/scripts/gen-command-manifest.js +153 -0
  280. package/scripts/gen-embedded-assets.mjs +129 -0
  281. package/scripts/install.ps1 +139 -0
  282. package/scripts/install.sh +268 -0
  283. package/scripts/lib/release-asset.mjs +84 -0
  284. package/scripts/parity-check.mjs +145 -0
  285. package/scripts/parity-check.test.mjs +58 -0
  286. package/scripts/pin-agentic-workflow-images.js +112 -0
  287. package/scripts/pr-coordinator.sh +3 -0
  288. package/scripts/preflight-sonar.eslint.config.mjs +44 -0
  289. package/scripts/preflight.sh +21 -94
  290. package/scripts/protected-state-check.js +104 -0
  291. package/scripts/smart-status.sh +60 -57
  292. package/scripts/spikes/config-race-bench.js +111 -0
  293. package/scripts/spikes/harness-capability-matrix.js +13 -0
  294. package/scripts/spikes/patch-anchor-stability-bench.js +125 -0
  295. package/scripts/spikes/protected-path-manifest.js +20 -0
  296. package/scripts/spikes/skill-auto-invoke-parity.js +292 -0
  297. package/scripts/sync-agent-skills.js +62 -0
  298. package/scripts/sync-utils.sh +3 -0
  299. package/scripts/test-ci-shard.js +13 -6
  300. package/scripts/test.js +95 -12
  301. package/skills/claim-safety/SKILL.md +102 -0
  302. package/skills/claim-safety/evals/evals.json +46 -0
  303. package/{.github/prompts/dev.prompt.md → skills/dev/SKILL.md} +44 -50
  304. package/skills/dev/evals/evals.json +50 -0
  305. package/skills/hermes-forge/SKILL.md +185 -0
  306. package/skills/hermes-forge/evals/evals.json +46 -0
  307. package/skills/issue-basics/SKILL.md +111 -0
  308. package/skills/issue-basics/evals/evals.json +46 -0
  309. package/skills/kernel/SKILL.md +166 -0
  310. package/skills/kernel/evals/evals.json +50 -0
  311. package/skills/memory/SKILL.md +102 -0
  312. package/skills/parallel-deep-research/SKILL.md +14 -11
  313. package/skills/parallel-deep-research/evals/evals.json +11 -27
  314. package/{.github/prompts/plan.prompt.md → skills/plan/SKILL.md} +132 -157
  315. package/skills/plan/evals/evals.json +42 -0
  316. package/skills/research/SKILL.md +195 -0
  317. package/skills/research/evals/evals.json +42 -0
  318. package/{.github/prompts/review.prompt.md → skills/review/SKILL.md} +98 -62
  319. package/skills/review/evals/evals.json +42 -0
  320. package/skills/rollback/SKILL.md +110 -0
  321. package/skills/rollback/evals/evals.json +46 -0
  322. package/skills/rollback/references/methods.md +204 -0
  323. package/{.cursor/commands/rollback.md → skills/rollback/references/workflow-integration.md} +10 -284
  324. package/skills/shepherd/SKILL.md +66 -0
  325. package/skills/shepherd/evals/evals.json +42 -0
  326. package/{.github/prompts/ship.prompt.md → skills/ship/SKILL.md} +81 -45
  327. package/skills/ship/evals/evals.json +42 -0
  328. package/skills/smith/SKILL.md +142 -0
  329. package/skills/smith/evals/evals.json +46 -0
  330. package/skills/smith/references/autonomy-and-gates.md +94 -0
  331. package/{.github/prompts/sonarcloud.prompt.md → skills/sonarcloud/SKILL.md} +14 -3
  332. package/skills/sonarcloud/evals/evals.json +46 -0
  333. package/skills/sonarcloud-analysis/SKILL.md +18 -13
  334. package/skills/sonarcloud-analysis/evals/evals.json +11 -15
  335. package/{.github/prompts/status.prompt.md → skills/status/SKILL.md} +20 -10
  336. package/skills/status/evals/evals.json +50 -0
  337. package/skills/triage-ready/SKILL.md +121 -0
  338. package/skills/triage-ready/evals/evals.json +42 -0
  339. package/{.github/prompts/validate.prompt.md → skills/validate/SKILL.md} +52 -29
  340. package/skills/validate/evals/evals.json +42 -0
  341. package/skills/verify/SKILL.md +299 -0
  342. package/skills/verify/evals/evals.json +50 -0
  343. package/.claude/commands/dev.md +0 -345
  344. package/.claude/commands/plan.md +0 -566
  345. package/.claude/commands/premerge.md +0 -186
  346. package/.claude/commands/research.md +0 -42
  347. package/.claude/commands/review.md +0 -451
  348. package/.claude/commands/rollback.md +0 -721
  349. package/.claude/commands/ship.md +0 -213
  350. package/.claude/commands/sonarcloud.md +0 -152
  351. package/.claude/commands/status.md +0 -90
  352. package/.claude/commands/validate.md +0 -288
  353. package/.claude/commands/verify.md +0 -269
  354. package/.claude/rules/workflow.md +0 -121
  355. package/.cline/workflows/dev.md +0 -342
  356. package/.cline/workflows/plan.md +0 -563
  357. package/.cline/workflows/premerge.md +0 -183
  358. package/.cline/workflows/research.md +0 -39
  359. package/.cline/workflows/review.md +0 -448
  360. package/.cline/workflows/rollback.md +0 -718
  361. package/.cline/workflows/ship.md +0 -210
  362. package/.cline/workflows/sonarcloud.md +0 -146
  363. package/.cline/workflows/status.md +0 -87
  364. package/.cline/workflows/validate.md +0 -285
  365. package/.cline/workflows/verify.md +0 -266
  366. package/.codex/config.toml +0 -11
  367. package/.codex/skills/dev/SKILL.md +0 -345
  368. package/.codex/skills/plan/SKILL.md +0 -566
  369. package/.codex/skills/premerge/SKILL.md +0 -186
  370. package/.codex/skills/research/SKILL.md +0 -42
  371. package/.codex/skills/review/SKILL.md +0 -451
  372. package/.codex/skills/rollback/SKILL.md +0 -721
  373. package/.codex/skills/ship/SKILL.md +0 -213
  374. package/.codex/skills/sonarcloud/SKILL.md +0 -149
  375. package/.codex/skills/status/SKILL.md +0 -90
  376. package/.codex/skills/validate/SKILL.md +0 -288
  377. package/.codex/skills/verify/SKILL.md +0 -269
  378. package/.cursor/commands/dev.md +0 -342
  379. package/.cursor/commands/plan.md +0 -563
  380. package/.cursor/commands/premerge.md +0 -183
  381. package/.cursor/commands/research.md +0 -39
  382. package/.cursor/commands/review.md +0 -448
  383. package/.cursor/commands/ship.md +0 -210
  384. package/.cursor/commands/sonarcloud.md +0 -146
  385. package/.cursor/commands/status.md +0 -87
  386. package/.cursor/commands/validate.md +0 -285
  387. package/.cursor/commands/verify.md +0 -266
  388. package/.cursorrules +0 -149
  389. package/.github/prompts/premerge.prompt.md +0 -188
  390. package/.github/prompts/research.prompt.md +0 -44
  391. package/.github/prompts/rollback.prompt.md +0 -723
  392. package/.github/prompts/verify.prompt.md +0 -271
  393. package/.github/workflows/beads-to-github.yml +0 -89
  394. package/.github/workflows/github-to-beads.yml +0 -100
  395. package/.kilocode/workflows/dev.md +0 -346
  396. package/.kilocode/workflows/plan.md +0 -567
  397. package/.kilocode/workflows/premerge.md +0 -187
  398. package/.kilocode/workflows/research.md +0 -43
  399. package/.kilocode/workflows/review.md +0 -452
  400. package/.kilocode/workflows/rollback.md +0 -722
  401. package/.kilocode/workflows/ship.md +0 -214
  402. package/.kilocode/workflows/sonarcloud.md +0 -150
  403. package/.kilocode/workflows/status.md +0 -91
  404. package/.kilocode/workflows/validate.md +0 -289
  405. package/.kilocode/workflows/verify.md +0 -270
  406. package/.opencode/commands/dev.md +0 -345
  407. package/.opencode/commands/plan.md +0 -566
  408. package/.opencode/commands/premerge.md +0 -186
  409. package/.opencode/commands/research.md +0 -42
  410. package/.opencode/commands/review.md +0 -451
  411. package/.opencode/commands/rollback.md +0 -721
  412. package/.opencode/commands/ship.md +0 -213
  413. package/.opencode/commands/sonarcloud.md +0 -149
  414. package/.opencode/commands/status.md +0 -90
  415. package/.opencode/commands/validate.md +0 -288
  416. package/.opencode/commands/verify.md +0 -269
  417. package/.roo/commands/dev.md +0 -346
  418. package/.roo/commands/plan.md +0 -567
  419. package/.roo/commands/premerge.md +0 -187
  420. package/.roo/commands/research.md +0 -43
  421. package/.roo/commands/review.md +0 -452
  422. package/.roo/commands/rollback.md +0 -722
  423. package/.roo/commands/ship.md +0 -214
  424. package/.roo/commands/sonarcloud.md +0 -150
  425. package/.roo/commands/status.md +0 -91
  426. package/.roo/commands/validate.md +0 -289
  427. package/.roo/commands/verify.md +0 -270
  428. package/docs/BEADS_GITHUB_SYNC.md +0 -281
  429. package/docs/GREPTILE_SETUP.md +0 -400
  430. package/docs/MANUAL_REVIEW_GUIDE.md +0 -106
  431. package/docs/SETUP.md +0 -663
  432. package/docs/VALIDATION.md +0 -363
  433. package/lib/agents/cline.plugin.json +0 -29
  434. package/lib/agents/copilot.plugin.json +0 -24
  435. package/lib/agents/kilocode.plugin.json +0 -22
  436. package/lib/agents/opencode.plugin.json +0 -23
  437. package/lib/agents/roo.plugin.json +0 -30
  438. package/lib/beads-bootstrap.js +0 -225
  439. package/lib/beads-health-check.js +0 -188
  440. package/lib/commands/commands-reset.js +0 -147
  441. package/opencode.json +0 -67
  442. package/scripts/beads-context.test.js +0 -584
  443. package/scripts/github-beads-sync/comment.mjs +0 -64
  444. package/scripts/github-beads-sync/config.mjs +0 -148
  445. package/scripts/github-beads-sync/github-api.mjs +0 -131
  446. package/scripts/github-beads-sync/index.mjs +0 -356
  447. package/scripts/github-beads-sync/label-mapper.mjs +0 -54
  448. package/scripts/github-beads-sync/mapping.mjs +0 -132
  449. package/scripts/github-beads-sync/reverse-sync-cli.mjs +0 -31
  450. package/scripts/github-beads-sync/reverse-sync.mjs +0 -162
  451. package/scripts/github-beads-sync/run-bd.mjs +0 -161
  452. package/scripts/github-beads-sync/sanitize.mjs +0 -121
  453. package/scripts/github-beads-sync.config.json +0 -26
  454. package/scripts/sync-commands.js +0 -600
@@ -0,0 +1,44 @@
1
+ // Isolated ESLint flat config for `forge preflight`'s SonarCloud-parity gate.
2
+ //
3
+ // Run ONLY via `eslint --no-config-lookup --config scripts/preflight-sonar.eslint.config.mjs`
4
+ // on changed files, so these Sonar rules never merge with the repo's main
5
+ // eslint.config.js. The point is deterministic parity with the SonarCloud
6
+ // quality gate WITHOUT the full (slow) Sonar scanner, on the change blast radius.
7
+ //
8
+ // cognitive-complexity is pinned to 15 — the same threshold SonarCloud's default
9
+ // "Cognitive Complexity" (S3776) gate uses, and the most common gate failure.
10
+ //
11
+ // Rule name ↔ Sonar rule ID (eslint-plugin-sonarjs v4):
12
+ // sonarjs/cognitive-complexity S3776 (pinned to 15)
13
+ // sonarjs/void-use S3735 (void should not be used)
14
+ // sonarjs/regex-complexity S5843 (regex too complex)
15
+ //
16
+ // prefer-optional-chain (S6582) is intentionally omitted: sonarjs exposes it
17
+ // only through the TypeScript type-checker path, which this fast JS-only gate
18
+ // does not wire (it would require @typescript-eslint/parser + a project graph
19
+ // and defeats the speed goal). CI's full Sonar scan still enforces it.
20
+ import sonarjs from 'eslint-plugin-sonarjs';
21
+
22
+ const sonarRules = {
23
+ 'sonarjs/cognitive-complexity': ['error', 15],
24
+ 'sonarjs/void-use': 'error',
25
+ 'sonarjs/regex-complexity': 'error',
26
+ };
27
+
28
+ export default [
29
+ {
30
+ ignores: ['node_modules/', 'coverage/', 'dist/', 'build/', '**/*.min.js'],
31
+ },
32
+ {
33
+ files: ['**/*.mjs'],
34
+ languageOptions: { ecmaVersion: 2023, sourceType: 'module' },
35
+ plugins: { sonarjs },
36
+ rules: sonarRules,
37
+ },
38
+ {
39
+ files: ['**/*.js', '**/*.cjs'],
40
+ languageOptions: { ecmaVersion: 2023, sourceType: 'commonjs' },
41
+ plugins: { sonarjs },
42
+ rules: sonarRules,
43
+ },
44
+ ];
@@ -1,8 +1,14 @@
1
1
  #!/usr/bin/env bash
2
2
  set -u
3
3
 
4
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
5
+ if [ -f "$SCRIPT_DIR/bootstrap-windows-tools.sh" ]; then
6
+ source "$SCRIPT_DIR/bootstrap-windows-tools.sh"
7
+ fi
8
+
9
+ FORGE_CLI="$SCRIPT_DIR/../bin/forge.js"
10
+
4
11
  exit_code=0
5
- have_bd=0
6
12
  have_gh=0
7
13
 
8
14
  ok() {
@@ -21,62 +27,6 @@ action() {
21
27
  exit_code=2
22
28
  }
23
29
 
24
- snapshot_hooks_dir() {
25
- hooks_dir="$1"
26
- hooks_snapshot_dir="$(mktemp -d 2>/dev/null || mktemp -d -t forge-preflight-hooks)"
27
-
28
- if [ -d "$hooks_dir" ]; then
29
- cp -pR "$hooks_dir"/. "$hooks_snapshot_dir"/
30
- fi
31
- }
32
-
33
- restore_hooks_dir() {
34
- hooks_dir="$1"
35
- mkdir -p "$hooks_dir"
36
-
37
- find "$hooks_dir" -mindepth 1 -maxdepth 1 -exec rm -rf {} +
38
-
39
- if [ -d "$hooks_snapshot_dir" ]; then
40
- cp -pR "$hooks_snapshot_dir"/. "$hooks_dir"/
41
- rm -rf "$hooks_snapshot_dir"
42
- fi
43
- }
44
-
45
- write_beads_config() {
46
- mkdir -p .beads
47
- {
48
- printf '%s\n' 'issue-prefix: forge'
49
- printf '\n'
50
- printf '%s\n' 'database:'
51
- printf '%s\n' ' backend: dolt'
52
- printf '\n'
53
- } > .beads/config.yaml
54
- }
55
-
56
- write_beads_gitignore() {
57
- mkdir -p .beads
58
- {
59
- printf '%s\n' '# Dolt database files (binary, not suitable for git)'
60
- printf '%s\n' 'dolt/'
61
- printf '%s\n' '*.db'
62
- printf '%s\n' '*.lock'
63
- printf '\n'
64
- } > .beads/.gitignore
65
- }
66
-
67
- safe_bd_init() {
68
- hooks_dir="$(git rev-parse --git-path hooks 2>/dev/null || printf '.git/hooks')"
69
- write_beads_config
70
- write_beads_gitignore
71
- snapshot_hooks_dir "$hooks_dir"
72
-
73
- bd init --database forge --prefix forge >/dev/null 2>&1
74
- init_status=$?
75
-
76
- restore_hooks_dir "$hooks_dir"
77
- return "$init_status"
78
- }
79
-
80
30
  is_windows_shell() {
81
31
  case "$(uname -s 2>/dev/null || printf unknown)" in
82
32
  MINGW*|MSYS*|CYGWIN*)
@@ -107,10 +57,7 @@ check_tool() {
107
57
  }
108
58
 
109
59
  check_tools() {
110
- if check_tool "bd" "install Forge/Beads tooling, then rerun: bunx forge setup --quick"; then
111
- have_bd=1
112
- fi
113
-
60
+ check_tool "node" "install Node.js (https://nodejs.org)" || true
114
61
  check_tool "jq" "winget install jqlang.jq" || true
115
62
 
116
63
  if check_tool "gh" "winget install GitHub.cli"; then
@@ -131,50 +78,30 @@ check_github_auth() {
131
78
  action "github-auth" "not logged in; run: gh auth login"
132
79
  }
133
80
 
134
- check_beads() {
135
- if [ "$have_bd" -ne 1 ]; then
136
- return 0
137
- fi
138
-
139
- init_ok=0
140
- if bd list --json --limit 1 >/dev/null 2>&1; then
141
- ok "beads-init" "Beads database is readable"
142
- init_ok=1
81
+ # Validate the Forge Kernel issue store. The kernel DB is a single-machine
82
+ # SQLite store in the git common dir; any kernel issue command auto-migrates it
83
+ # via broker.initialize(), so the ensure step is just a kernel read. `forge
84
+ # doctor` then reports the filesystem class of that DB path (D19) — it only
85
+ # reports, it does not init, which is why the ensure step runs first.
86
+ check_kernel() {
87
+ if node "$FORGE_CLI" issue list --json >/dev/null 2>&1; then
88
+ ok "kernel-init" "Kernel issue store is readable"
143
89
  else
144
- if safe_bd_init; then
145
- fixed "beads-init" "ran hook-preserving bd init --database forge --prefix forge"
146
- init_ok=1
147
- else
148
- action "beads-init" "bd init failed; inspect Beads setup manually"
149
- fi
150
- fi
151
-
152
- if [ "$init_ok" -ne 1 ]; then
90
+ action "kernel-init" "kernel issue store not initializable; inspect: node bin/forge.js doctor"
153
91
  return 0
154
92
  fi
155
93
 
156
- doctor_output="$(bd doctor --fix --yes 2>&1)"
157
- doctor_status=$?
158
- if [ "$doctor_status" -eq 0 ]; then
159
- doctor_output_lower="$(printf '%s' "$doctor_output" | tr '[:upper:]' '[:lower:]')"
160
- if [ "$exit_code" -eq 1 ] ||
161
- [[ "$doctor_output_lower" == *fix* ]] ||
162
- [[ "$doctor_output_lower" == *repair* ]] ||
163
- [[ "$doctor_output_lower" == *migrat* ]] ||
164
- [[ "$doctor_output_lower" == *updat* ]]; then
165
- fixed "beads-doctor" "ran bd doctor --fix --yes after Beads repair"
166
- else
167
- ok "beads-doctor" "bd doctor --fix --yes succeeded"
168
- fi
94
+ if node "$FORGE_CLI" doctor >/dev/null 2>&1; then
95
+ ok "kernel-doctor" "forge doctor reports a healthy filesystem for the kernel database"
169
96
  else
170
- action "beads-doctor" "bd doctor --fix --yes failed; inspect Beads manually"
97
+ action "kernel-doctor" "forge doctor reports an unhealthy filesystem; inspect the kernel database path"
171
98
  fi
172
99
  }
173
100
 
174
101
  main() {
175
102
  check_tools
176
103
  check_github_auth
177
- check_beads
104
+ check_kernel
178
105
  exit "$exit_code"
179
106
  }
180
107
 
@@ -0,0 +1,104 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { execFileSync } = require('node:child_process');
4
+ const {
5
+ assertProtectedWriteAllowed,
6
+ recordProtectedStateAuditEvent,
7
+ } = require('../lib/protected-state-surfaces');
8
+
9
+ function parseNameStatus(output) {
10
+ const files = [];
11
+ for (const line of output.split(/\r?\n/)) {
12
+ const trimmed = line.trim();
13
+ if (!trimmed) continue;
14
+ const parts = trimmed.split('\t').filter(Boolean);
15
+ const status = parts[0] || '';
16
+ if (/^[RC]/.test(status)) {
17
+ files.push(...parts.slice(1, 3));
18
+ } else {
19
+ files.push(parts[1]);
20
+ }
21
+ }
22
+ return [...new Set(files.filter(Boolean))];
23
+ }
24
+
25
+ function getStagedFiles() {
26
+ if (process.env.FORGE_PROTECTED_STATE_STAGED_NAME_STATUS !== undefined) {
27
+ return parseNameStatus(process.env.FORGE_PROTECTED_STATE_STAGED_NAME_STATUS);
28
+ }
29
+
30
+ if (process.env.FORGE_PROTECTED_STATE_STAGED_FILES !== undefined) {
31
+ return process.env.FORGE_PROTECTED_STATE_STAGED_FILES
32
+ .split(/\r?\n/)
33
+ .map(line => line.trim())
34
+ .filter(Boolean);
35
+ }
36
+
37
+ const output = execFileSync('git', ['diff', '--cached', '--name-status', '--diff-filter=ACMRDT'], {
38
+ encoding: 'utf8',
39
+ stdio: ['ignore', 'pipe', 'pipe'],
40
+ });
41
+ return parseNameStatus(output);
42
+ }
43
+
44
+ function getAllowedSurfaces() {
45
+ return new Set(
46
+ String(process.env.FORGE_PROTECTED_STATE_ALLOWED_SURFACES || '')
47
+ .split(',')
48
+ .map(surface => surface.trim())
49
+ .filter(Boolean),
50
+ );
51
+ }
52
+
53
+ function main() {
54
+ const actor =
55
+ process.env.FORGE_PROTECTED_STATE_ACTOR ||
56
+ process.env.FORGE_ACTOR ||
57
+ process.env.USER ||
58
+ process.env.USERNAME ||
59
+ 'unknown';
60
+ const allowedSurfaces = getAllowedSurfaces();
61
+ const decisions = getStagedFiles()
62
+ .map(file => {
63
+ const probe = assertProtectedWriteAllowed(file, { actor, operation: 'staged_edit' });
64
+ if (probe.requiredSurface && allowedSurfaces.has(probe.requiredSurface)) {
65
+ return assertProtectedWriteAllowed(file, {
66
+ actor,
67
+ operation: 'staged_edit',
68
+ viaForgeApi: true,
69
+ surface: probe.requiredSurface,
70
+ });
71
+ }
72
+ return probe;
73
+ })
74
+ .filter(decision => !decision.allowed);
75
+
76
+ for (const decision of decisions) {
77
+ const audit = recordProtectedStateAuditEvent(decision, { cwd: process.cwd() });
78
+ if (!audit.success) {
79
+ console.error(`WARN: Failed to record protected-state audit for ${decision.path}: ${audit.error}`);
80
+ }
81
+ }
82
+
83
+ if (decisions.length === 0) {
84
+ console.log('OK: No protected state edits detected.');
85
+ process.exit(0);
86
+ }
87
+
88
+ console.error('ERROR: Protected state edit detected. Direct edits to these paths are blocked:');
89
+ for (const decision of decisions) {
90
+ console.error(` - ${decision.path} [${decision.requiredSurface}]`);
91
+ console.error(` Decision: ${decision.decision}`);
92
+ console.error(` Repair: ${decision.repairHint}`);
93
+ }
94
+ console.error('');
95
+ console.error('Use the owning Forge or Beads API surface, then stage the generated result if that command explicitly owns it.');
96
+ process.exit(1);
97
+ }
98
+
99
+ try {
100
+ main();
101
+ } catch (error) {
102
+ console.error(`Protected state check failed: ${error.message}`);
103
+ process.exit(1);
104
+ }
@@ -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
+ }