forge-workflow 0.0.9 → 0.1.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (479) hide show
  1. package/.claude/rules/{greptile-review-process.md → review-process.md} +56 -41
  2. package/.claude/scripts/{greptile-resolve.sh → review-resolve.sh} +13 -3
  3. package/.cursor/rules/permissions-guidance.mdc +2 -2
  4. package/.forge/hooks/check-tdd.js +3 -0
  5. package/.forge/hooks/forge-native-hook.js +245 -0
  6. package/.forge/protected-paths.yaml +157 -0
  7. package/AGENTS.md +151 -61
  8. package/CHANGELOG.md +681 -0
  9. package/CLAUDE.md +9 -106
  10. package/QUICKSTART.md +171 -0
  11. package/README.md +271 -363
  12. package/bin/forge-cmd.js +120 -9
  13. package/bin/forge-preflight.js +26 -5
  14. package/bin/forge.js +466 -489
  15. package/docs/INDEX.md +93 -0
  16. package/docs/PROJECT_DESIGN.md +685 -0
  17. package/docs/architecture/index.md +66 -0
  18. package/docs/architecture/notes/README.md +35 -0
  19. package/docs/architecture/subsystems/README.md +46 -0
  20. package/docs/{TOOLCHAIN.md → forge/TOOLCHAIN.md} +56 -47
  21. package/docs/forge/VALIDATION.md +82 -0
  22. package/docs/{AGENT_INSTALL_PROMPT.md → guides/AGENT_INSTALL_PROMPT.md} +3 -3
  23. package/docs/guides/BEADS_GITHUB_SYNC.md +32 -0
  24. package/docs/{ENHANCED_ONBOARDING.md → guides/ENHANCED_ONBOARDING.md} +16 -12
  25. package/docs/guides/GREPTILE_SETUP.md +46 -0
  26. package/docs/guides/MANUAL_REVIEW_GUIDE.md +58 -0
  27. package/docs/guides/MIGRATION.md +56 -0
  28. package/docs/guides/SETUP.md +118 -0
  29. package/docs/guides/SUPPORT.md +185 -0
  30. package/docs/guides/WORKFLOW_TEMPLATES.md +74 -0
  31. package/docs/guides/memory-backends.md +183 -0
  32. package/docs/reference/ADAPTERS.md +128 -0
  33. package/docs/reference/AGENT_SKILL_PARITY.md +175 -0
  34. package/docs/reference/COMMANDS.md +205 -0
  35. package/docs/reference/DECISION_DRIFT_GUARDS.md +97 -0
  36. package/docs/{EXAMPLES.md → reference/EXAMPLES.md} +7 -5
  37. package/docs/reference/FORGE_KERNEL_STORAGE_MODEL.md +135 -0
  38. package/docs/reference/HERMES_INTEGRATION.md +118 -0
  39. package/docs/reference/INSIGHTS_RECAP.md +63 -0
  40. package/docs/reference/INSTALL.md +164 -0
  41. package/docs/reference/KERNEL_TAXONOMY_VALIDATION.md +161 -0
  42. package/docs/reference/PROTECTED_PATH_MANIFEST.md +25 -0
  43. package/docs/reference/RELEASE.md +68 -0
  44. package/docs/reference/RESEARCH_TEMPLATE.md +292 -0
  45. package/docs/{ROADMAP.md → reference/ROADMAP.md} +12 -9
  46. package/docs/reference/SKILLS.md +35 -0
  47. package/docs/reference/STATUS_BOARD.md +80 -0
  48. package/docs/reference/TEMPLATES.md +106 -0
  49. package/docs/reference/TOOLCHAIN.md +658 -0
  50. package/docs/reference/VALIDATION.md +82 -0
  51. package/docs/reference/agent-permissions.md +169 -0
  52. package/docs/reference/beads-to-kernel-migration-ux.md +61 -0
  53. package/docs/reference/control-plane-guarantees.md +125 -0
  54. package/docs/reference/dependency-chain.md +331 -0
  55. package/docs/reference/forge-kernel-issue-command-contract.md +161 -0
  56. package/docs/reference/forge-kernel-schema.md +72 -0
  57. package/docs/reference/kernel-conflict-evaluators.md +27 -0
  58. package/docs/reference/patch-md-format.md +77 -0
  59. package/docs/reference/protected-state-surfaces.md +59 -0
  60. package/docs/reference/shepherd.md +115 -0
  61. package/docs/reference/superpowers-analysis.md +320 -0
  62. package/docs/reference/superpowers-integration-options.md +404 -0
  63. package/docs/reference/test-environment.md +519 -0
  64. package/docs/reference/upgrade-safety.md +59 -0
  65. package/lefthook.yml +18 -0
  66. package/lib/adapter-cli.js +307 -0
  67. package/lib/adapters/beads-issue-adapter.js +127 -0
  68. package/lib/adapters/beads-kernel-compat.js +1042 -0
  69. package/lib/adapters/greptile-review-adapter.js +141 -0
  70. package/lib/adapters/kernel-issue-adapter.js +101 -0
  71. package/lib/adapters/pr-state-adapter.js +484 -0
  72. package/lib/adoption-profiles.js +126 -0
  73. package/lib/agents/README.md +2 -6
  74. package/lib/agents/claude.plugin.json +3 -8
  75. package/lib/agents/codex.plugin.json +9 -1
  76. package/lib/agents/cursor.plugin.json +2 -6
  77. package/lib/agents/hermes.plugin.json +22 -0
  78. package/lib/agents-config.js +39 -1236
  79. package/lib/audit-evidence.js +282 -0
  80. package/lib/beads-setup.js +225 -28
  81. package/lib/beads-sync-scaffold.js +36 -107
  82. package/lib/codex-skills.js +51 -1
  83. package/lib/commands/_issue.js +744 -70
  84. package/lib/commands/_manifest.js +91 -0
  85. package/lib/commands/_registry.js +85 -34
  86. package/lib/commands/_resolve-command-opts.js +261 -0
  87. package/lib/commands/_serve-security.js +270 -0
  88. package/lib/commands/adapter.js +12 -0
  89. package/lib/commands/add.js +118 -0
  90. package/lib/commands/audit.js +70 -0
  91. package/lib/commands/blocked.js +5 -0
  92. package/lib/commands/board.js +64 -0
  93. package/lib/commands/claim.js +21 -2
  94. package/lib/commands/claims.js +7 -0
  95. package/lib/commands/clean.js +485 -75
  96. package/lib/commands/close.js +2 -2
  97. package/lib/commands/comment.js +5 -0
  98. package/lib/commands/control.js +148 -0
  99. package/lib/commands/create.js +2 -2
  100. package/lib/commands/dev.js +185 -7
  101. package/lib/commands/doc-gate.js +336 -0
  102. package/lib/commands/doctor.js +156 -0
  103. package/lib/commands/explain.js +15 -0
  104. package/lib/commands/export.js +237 -0
  105. package/lib/commands/gate.js +192 -0
  106. package/lib/commands/hooks.js +242 -0
  107. package/lib/commands/inbox.js +118 -0
  108. package/lib/commands/init.js +598 -0
  109. package/lib/commands/insights.js +79 -0
  110. package/lib/commands/issue.js +12 -1
  111. package/lib/commands/issues.js +66 -0
  112. package/lib/commands/lint.js +5 -0
  113. package/lib/commands/list.js +2 -2
  114. package/lib/commands/merge.js +312 -0
  115. package/lib/commands/migrate.js +523 -0
  116. package/lib/commands/new.js +12 -0
  117. package/lib/commands/options.js +241 -0
  118. package/lib/commands/orient.js +13 -0
  119. package/lib/commands/orphans.js +5 -0
  120. package/lib/commands/patch.js +67 -0
  121. package/lib/commands/plan.js +436 -24
  122. package/lib/commands/preflight.js +211 -0
  123. package/lib/commands/prime.js +13 -0
  124. package/lib/commands/push.js +69 -2
  125. package/lib/commands/ready.js +2 -2
  126. package/lib/commands/recall.js +116 -0
  127. package/lib/commands/recap.js +61 -0
  128. package/lib/commands/recommend.js +22 -2
  129. package/lib/commands/release.js +91 -0
  130. package/lib/commands/remember.js +74 -0
  131. package/lib/commands/role.js +99 -0
  132. package/lib/commands/serve.js +581 -0
  133. package/lib/commands/setup.js +851 -979
  134. package/lib/commands/shepherd.js +436 -0
  135. package/lib/commands/ship.js +23 -1
  136. package/lib/commands/show.js +2 -2
  137. package/lib/commands/stage.js +192 -0
  138. package/lib/commands/stale.js +5 -0
  139. package/lib/commands/status.js +329 -11
  140. package/lib/commands/sync.js +34 -46
  141. package/lib/commands/team.js +15 -2
  142. package/lib/commands/test.js +58 -7
  143. package/lib/commands/update.js +2 -2
  144. package/lib/commands/upgrade.js +47 -0
  145. package/lib/commands/validate.js +56 -25
  146. package/lib/commands/worktree.js +308 -128
  147. package/lib/config-writer.js +202 -0
  148. package/lib/control-plane.js +236 -0
  149. package/lib/core/runtime-graph.js +946 -0
  150. package/lib/dep-guard/keyword-ripple.js +184 -0
  151. package/lib/deprecated-sync-cleanup.js +362 -0
  152. package/lib/detect-agent.js +2 -28
  153. package/lib/detect-worktree.js +42 -17
  154. package/lib/doc-gate/declaration.js +177 -0
  155. package/lib/doc-gate/detect.js +289 -0
  156. package/lib/doc-gate/gate.js +375 -0
  157. package/lib/doc-gate/okf-config.js +128 -0
  158. package/lib/doc-gate/okf.js +429 -0
  159. package/lib/docs-command.js +1161 -6
  160. package/lib/forge-issues.js +697 -0
  161. package/lib/forge-lock.js +262 -0
  162. package/lib/gate-events.js +193 -0
  163. package/lib/global-flags.js +74 -0
  164. package/lib/greptile-match.js +7 -63
  165. package/lib/harness-capability-matrix.js +380 -0
  166. package/lib/hook-global-installer.js +347 -0
  167. package/lib/hook-renderer.js +451 -0
  168. package/lib/inbox.js +391 -0
  169. package/lib/insights.js +397 -0
  170. package/lib/issue-adapter.js +156 -0
  171. package/lib/issue-backend.js +145 -0
  172. package/lib/issue-render.js +220 -0
  173. package/lib/issue-sync/authority.js +100 -0
  174. package/lib/issue-sync/github-pull.js +184 -0
  175. package/lib/issue-sync/import-primitives.js +98 -0
  176. package/lib/issue-sync/legacy-link-bridge.js +436 -0
  177. package/lib/issue-sync/link-store.js +292 -0
  178. package/lib/issue-sync/project-github.js +123 -0
  179. package/lib/issue-sync/reconcile.js +195 -0
  180. package/lib/issue-sync/schema.js +126 -0
  181. package/lib/kernel/backing-issue.js +305 -0
  182. package/lib/kernel/broker.js +1218 -0
  183. package/lib/kernel/cli-broker-factory.js +130 -0
  184. package/lib/kernel/conflict-signal.js +82 -0
  185. package/lib/kernel/evaluators.js +195 -0
  186. package/lib/kernel/fs-class.js +495 -0
  187. package/lib/kernel/issue-command-contract.js +559 -0
  188. package/lib/kernel/issue-id-resolver.js +186 -0
  189. package/lib/kernel/lease-enforcer.js +158 -0
  190. package/lib/kernel/migrations.js +333 -0
  191. package/lib/kernel/planning-buckets-schema.js +109 -0
  192. package/lib/kernel/projection-jsonl-writer.js +450 -0
  193. package/lib/kernel/readiness-model.js +329 -0
  194. package/lib/kernel/schema.js +356 -0
  195. package/lib/kernel/sqlite-driver.js +2504 -0
  196. package/lib/kernel/taxonomy-validator.js +394 -0
  197. package/lib/lefthook-check.js +8 -4
  198. package/lib/lefthook-wiring.js +413 -0
  199. package/lib/mcp-config-renderer.js +288 -0
  200. package/lib/memory/graphiti-mcp.js +106 -0
  201. package/lib/memory/router.js +387 -0
  202. package/lib/memory/typed-api.js +102 -0
  203. package/lib/memory-digest.js +195 -0
  204. package/lib/merge-rules.js +395 -0
  205. package/lib/migrate-dry-run.js +466 -0
  206. package/lib/orientation.js +863 -0
  207. package/lib/package-manager-remediation.js +103 -0
  208. package/lib/package-root.js +381 -0
  209. package/lib/patch-intent.js +890 -0
  210. package/lib/plugin-catalog.js +3 -4
  211. package/lib/plugin-manager.js +0 -5
  212. package/lib/pr-bundle.js +186 -0
  213. package/lib/pr-monitor/differ.js +195 -0
  214. package/lib/pr-monitor/events.js +0 -0
  215. package/lib/pr-monitor/gather.js +124 -0
  216. package/lib/pr-monitor/journal.js +299 -0
  217. package/lib/pr-monitor/monitor.js +146 -0
  218. package/lib/pr-monitor/render-sticky.js +157 -0
  219. package/lib/pr-monitor/watch-lifecycle.js +95 -0
  220. package/lib/pr-monitor/watch.js +247 -0
  221. package/lib/pr-pull.js +1273 -0
  222. package/lib/pr-shepherd.js +494 -0
  223. package/lib/pr-state-validator.js +59 -0
  224. package/lib/preflight/gates.js +237 -0
  225. package/lib/preflight/runner.js +116 -0
  226. package/lib/project-discovery.js +0 -53
  227. package/lib/project-memory.js +166 -0
  228. package/lib/protected-path-manifest.js +281 -0
  229. package/lib/protected-state-surfaces.js +387 -0
  230. package/lib/release-readiness.js +2089 -0
  231. package/lib/reset.js +59 -45
  232. package/lib/review-adapter.js +68 -0
  233. package/lib/rules-sync.js +260 -0
  234. package/lib/runtime-health.js +332 -23
  235. package/lib/safety-config-renderer.js +268 -0
  236. package/lib/setup-action-log.js +1 -7
  237. package/lib/setup.js +27 -65
  238. package/lib/shell-utils.js +76 -6
  239. package/lib/skills-sync.js +330 -0
  240. package/lib/smart-status/conflicts.js +205 -0
  241. package/lib/smart-status/scoring.js +191 -0
  242. package/lib/status/beads-snapshot.js +145 -0
  243. package/lib/status/presenter.js +216 -0
  244. package/lib/status/snapshot.js +186 -0
  245. package/lib/sync-backend.js +202 -0
  246. package/lib/untrusted-content.js +52 -0
  247. package/lib/upgrade-safety.js +199 -0
  248. package/lib/workflow/enforce-stage.js +298 -47
  249. package/lib/workflow/stage-transition.js +115 -0
  250. package/lib/workflow/stages.js +30 -6
  251. package/lib/workflow/state-manager.js +159 -14
  252. package/lib/workflow/state.js +23 -1
  253. package/lib/workflow-profiles.js +17 -5
  254. package/package.json +46 -36
  255. package/rules/documentation.md +19 -0
  256. package/rules/kernel-tracking.md +26 -0
  257. package/rules/security.md +22 -0
  258. package/rules/tdd.md +20 -0
  259. package/rules/workflow.md +27 -0
  260. package/scripts/auto-backing-issue.js +47 -0
  261. package/scripts/beads-context.sh +165 -22
  262. package/scripts/beads-migrate-to-dolt.sh +7 -0
  263. package/scripts/beads-upgrade-smoke.sh +284 -0
  264. package/scripts/behavioral-judge.sh +115 -11
  265. package/scripts/benchmark.js +349 -63
  266. package/scripts/bootstrap-windows-tools.sh +78 -0
  267. package/scripts/branch-protection.js +2 -3
  268. package/scripts/check-agents.js +34 -137
  269. package/scripts/commitlint.js +3 -1
  270. package/scripts/conflict-detect.sh +3 -0
  271. package/scripts/dep-guard-analyze.js +52 -17
  272. package/scripts/dep-guard-keyword-ripple.js +29 -0
  273. package/scripts/dep-guard-render-review.js +86 -0
  274. package/scripts/dep-guard.sh +64 -232
  275. package/scripts/file-index.sh +3 -0
  276. package/scripts/forge-team/lib/claim.sh +34 -18
  277. package/scripts/forge-team/lib/dashboard.sh +61 -86
  278. package/scripts/forge-team/lib/epic.sh +99 -263
  279. package/scripts/forge-team/lib/hooks.sh +26 -28
  280. package/scripts/forge-team/lib/identity.sh +4 -4
  281. package/scripts/forge-team/lib/sync-github.sh +144 -47
  282. package/scripts/forge-team/lib/verify.sh +93 -83
  283. package/scripts/forge-team/lib/workload.sh +41 -65
  284. package/scripts/forge-team/tests/claim.test.sh +25 -19
  285. package/scripts/forge-team/tests/dashboard.test.sh +31 -46
  286. package/scripts/forge-team/tests/epic.test.sh +52 -71
  287. package/scripts/forge-team/tests/hooks.test.sh +38 -50
  288. package/scripts/forge-team/tests/identity.test.sh +3 -3
  289. package/scripts/forge-team/tests/integration.test.sh +44 -66
  290. package/scripts/forge-team/tests/sync-github.test.sh +183 -79
  291. package/scripts/forge-team/tests/verify.test.sh +37 -46
  292. package/scripts/forge-team/tests/workflow-integration.test.sh +4 -4
  293. package/scripts/forge-team/tests/workload.test.sh +32 -66
  294. package/scripts/gen-command-manifest.js +153 -0
  295. package/scripts/gen-embedded-assets.mjs +129 -0
  296. package/scripts/install.ps1 +139 -0
  297. package/scripts/install.sh +268 -0
  298. package/scripts/lib/beads-migrate-to-dolt.mjs +503 -0
  299. package/scripts/lib/release-asset.mjs +84 -0
  300. package/scripts/parity-check.mjs +145 -0
  301. package/scripts/parity-check.test.mjs +58 -0
  302. package/scripts/pin-agentic-workflow-images.js +112 -0
  303. package/scripts/pr-coordinator.sh +3 -0
  304. package/scripts/preflight-sonar.eslint.config.mjs +44 -0
  305. package/scripts/preflight.sh +108 -0
  306. package/scripts/protected-state-check.js +104 -0
  307. package/scripts/smart-status-score.js +31 -0
  308. package/scripts/smart-status-sessions.js +51 -0
  309. package/scripts/smart-status.sh +117 -369
  310. package/scripts/spikes/config-race-bench.js +111 -0
  311. package/scripts/spikes/harness-capability-matrix.js +13 -0
  312. package/scripts/spikes/patch-anchor-stability-bench.js +125 -0
  313. package/scripts/spikes/protected-path-manifest.js +20 -0
  314. package/scripts/spikes/skill-auto-invoke-parity.js +292 -0
  315. package/scripts/sync-agent-skills.js +62 -0
  316. package/scripts/sync-agentic-workflow.js +48 -0
  317. package/scripts/sync-utils.sh +3 -0
  318. package/scripts/test-ci-shard.js +251 -0
  319. package/scripts/test-dashboard.js +188 -52
  320. package/scripts/test-full-suite.js +186 -0
  321. package/scripts/test-profile.js +278 -0
  322. package/scripts/test.js +302 -28
  323. package/scripts/validate.js +143 -0
  324. package/scripts/validate.sh +18 -1
  325. package/skills/claim-safety/SKILL.md +102 -0
  326. package/skills/claim-safety/evals/evals.json +46 -0
  327. package/{.github/prompts/dev.prompt.md → skills/dev/SKILL.md} +46 -52
  328. package/skills/dev/evals/evals.json +50 -0
  329. package/skills/hermes-forge/SKILL.md +185 -0
  330. package/skills/hermes-forge/evals/evals.json +46 -0
  331. package/skills/issue-basics/SKILL.md +111 -0
  332. package/skills/issue-basics/evals/evals.json +46 -0
  333. package/skills/kernel/SKILL.md +166 -0
  334. package/skills/kernel/evals/evals.json +50 -0
  335. package/skills/memory/SKILL.md +102 -0
  336. package/skills/parallel-deep-research/SKILL.md +14 -11
  337. package/skills/parallel-deep-research/evals/evals.json +11 -27
  338. package/{.github/prompts/plan.prompt.md → skills/plan/SKILL.md} +134 -159
  339. package/skills/plan/evals/evals.json +42 -0
  340. package/skills/research/SKILL.md +195 -0
  341. package/skills/research/evals/evals.json +42 -0
  342. package/{.github/prompts/review.prompt.md → skills/review/SKILL.md} +98 -62
  343. package/skills/review/evals/evals.json +42 -0
  344. package/skills/rollback/SKILL.md +110 -0
  345. package/skills/rollback/evals/evals.json +46 -0
  346. package/skills/rollback/references/methods.md +204 -0
  347. package/{.cursor/commands/rollback.md → skills/rollback/references/workflow-integration.md} +10 -284
  348. package/skills/shepherd/SKILL.md +66 -0
  349. package/skills/shepherd/evals/evals.json +42 -0
  350. package/skills/ship/SKILL.md +251 -0
  351. package/skills/ship/evals/evals.json +42 -0
  352. package/skills/smith/SKILL.md +142 -0
  353. package/skills/smith/evals/evals.json +46 -0
  354. package/skills/smith/references/autonomy-and-gates.md +94 -0
  355. package/{.github/prompts/sonarcloud.prompt.md → skills/sonarcloud/SKILL.md} +14 -3
  356. package/skills/sonarcloud/evals/evals.json +46 -0
  357. package/skills/sonarcloud-analysis/SKILL.md +18 -13
  358. package/skills/sonarcloud-analysis/evals/evals.json +11 -15
  359. package/skills/status/SKILL.md +102 -0
  360. package/skills/status/evals/evals.json +50 -0
  361. package/skills/triage-ready/SKILL.md +121 -0
  362. package/skills/triage-ready/evals/evals.json +42 -0
  363. package/{.github/prompts/validate.prompt.md → skills/validate/SKILL.md} +52 -29
  364. package/skills/validate/evals/evals.json +42 -0
  365. package/skills/verify/SKILL.md +299 -0
  366. package/skills/verify/evals/evals.json +50 -0
  367. package/.claude/commands/dev.md +0 -345
  368. package/.claude/commands/plan.md +0 -566
  369. package/.claude/commands/premerge.md +0 -186
  370. package/.claude/commands/research.md +0 -42
  371. package/.claude/commands/review.md +0 -451
  372. package/.claude/commands/rollback.md +0 -721
  373. package/.claude/commands/ship.md +0 -213
  374. package/.claude/commands/sonarcloud.md +0 -152
  375. package/.claude/commands/status.md +0 -90
  376. package/.claude/commands/validate.md +0 -288
  377. package/.claude/commands/verify.md +0 -269
  378. package/.claude/rules/workflow.md +0 -121
  379. package/.cline/workflows/dev.md +0 -342
  380. package/.cline/workflows/plan.md +0 -563
  381. package/.cline/workflows/premerge.md +0 -183
  382. package/.cline/workflows/research.md +0 -39
  383. package/.cline/workflows/review.md +0 -448
  384. package/.cline/workflows/rollback.md +0 -718
  385. package/.cline/workflows/ship.md +0 -210
  386. package/.cline/workflows/sonarcloud.md +0 -146
  387. package/.cline/workflows/status.md +0 -87
  388. package/.cline/workflows/validate.md +0 -285
  389. package/.cline/workflows/verify.md +0 -266
  390. package/.codex/config.toml +0 -11
  391. package/.codex/skills/dev/SKILL.md +0 -345
  392. package/.codex/skills/plan/SKILL.md +0 -566
  393. package/.codex/skills/premerge/SKILL.md +0 -186
  394. package/.codex/skills/research/SKILL.md +0 -42
  395. package/.codex/skills/review/SKILL.md +0 -451
  396. package/.codex/skills/rollback/SKILL.md +0 -721
  397. package/.codex/skills/ship/SKILL.md +0 -213
  398. package/.codex/skills/sonarcloud/SKILL.md +0 -149
  399. package/.codex/skills/status/SKILL.md +0 -90
  400. package/.codex/skills/validate/SKILL.md +0 -288
  401. package/.codex/skills/verify/SKILL.md +0 -269
  402. package/.cursor/commands/dev.md +0 -342
  403. package/.cursor/commands/plan.md +0 -563
  404. package/.cursor/commands/premerge.md +0 -183
  405. package/.cursor/commands/research.md +0 -39
  406. package/.cursor/commands/review.md +0 -448
  407. package/.cursor/commands/ship.md +0 -210
  408. package/.cursor/commands/sonarcloud.md +0 -146
  409. package/.cursor/commands/status.md +0 -87
  410. package/.cursor/commands/validate.md +0 -285
  411. package/.cursor/commands/verify.md +0 -266
  412. package/.cursorrules +0 -149
  413. package/.github/prompts/premerge.prompt.md +0 -188
  414. package/.github/prompts/research.prompt.md +0 -44
  415. package/.github/prompts/rollback.prompt.md +0 -723
  416. package/.github/prompts/ship.prompt.md +0 -215
  417. package/.github/prompts/status.prompt.md +0 -92
  418. package/.github/prompts/verify.prompt.md +0 -271
  419. package/.github/workflows/beads-to-github.yml +0 -56
  420. package/.github/workflows/github-to-beads.yml +0 -97
  421. package/.kilocode/workflows/dev.md +0 -346
  422. package/.kilocode/workflows/plan.md +0 -567
  423. package/.kilocode/workflows/premerge.md +0 -187
  424. package/.kilocode/workflows/research.md +0 -43
  425. package/.kilocode/workflows/review.md +0 -452
  426. package/.kilocode/workflows/rollback.md +0 -722
  427. package/.kilocode/workflows/ship.md +0 -214
  428. package/.kilocode/workflows/sonarcloud.md +0 -150
  429. package/.kilocode/workflows/status.md +0 -91
  430. package/.kilocode/workflows/validate.md +0 -289
  431. package/.kilocode/workflows/verify.md +0 -270
  432. package/.opencode/commands/dev.md +0 -345
  433. package/.opencode/commands/plan.md +0 -566
  434. package/.opencode/commands/premerge.md +0 -186
  435. package/.opencode/commands/research.md +0 -42
  436. package/.opencode/commands/review.md +0 -451
  437. package/.opencode/commands/rollback.md +0 -721
  438. package/.opencode/commands/ship.md +0 -213
  439. package/.opencode/commands/sonarcloud.md +0 -149
  440. package/.opencode/commands/status.md +0 -90
  441. package/.opencode/commands/validate.md +0 -288
  442. package/.opencode/commands/verify.md +0 -269
  443. package/.roo/commands/dev.md +0 -346
  444. package/.roo/commands/plan.md +0 -567
  445. package/.roo/commands/premerge.md +0 -187
  446. package/.roo/commands/research.md +0 -43
  447. package/.roo/commands/review.md +0 -452
  448. package/.roo/commands/rollback.md +0 -722
  449. package/.roo/commands/ship.md +0 -214
  450. package/.roo/commands/sonarcloud.md +0 -150
  451. package/.roo/commands/status.md +0 -91
  452. package/.roo/commands/validate.md +0 -289
  453. package/.roo/commands/verify.md +0 -270
  454. package/docs/BEADS_GITHUB_SYNC.md +0 -255
  455. package/docs/GREPTILE_SETUP.md +0 -400
  456. package/docs/MANUAL_REVIEW_GUIDE.md +0 -106
  457. package/docs/SETUP.md +0 -663
  458. package/docs/VALIDATION.md +0 -363
  459. package/lib/agents/cline.plugin.json +0 -29
  460. package/lib/agents/copilot.plugin.json +0 -24
  461. package/lib/agents/kilocode.plugin.json +0 -22
  462. package/lib/agents/opencode.plugin.json +0 -23
  463. package/lib/agents/roo.plugin.json +0 -30
  464. package/lib/beads-health-check.js +0 -143
  465. package/lib/commands/commands-reset.js +0 -147
  466. package/opencode.json +0 -67
  467. package/scripts/beads-context.test.js +0 -567
  468. package/scripts/github-beads-sync/comment.mjs +0 -64
  469. package/scripts/github-beads-sync/config.mjs +0 -148
  470. package/scripts/github-beads-sync/github-api.mjs +0 -131
  471. package/scripts/github-beads-sync/index.mjs +0 -332
  472. package/scripts/github-beads-sync/label-mapper.mjs +0 -54
  473. package/scripts/github-beads-sync/mapping.mjs +0 -78
  474. package/scripts/github-beads-sync/reverse-sync-cli.mjs +0 -31
  475. package/scripts/github-beads-sync/reverse-sync.mjs +0 -138
  476. package/scripts/github-beads-sync/run-bd.mjs +0 -161
  477. package/scripts/github-beads-sync/sanitize.mjs +0 -121
  478. package/scripts/github-beads-sync.config.json +0 -26
  479. package/scripts/sync-commands.js +0 -600
@@ -0,0 +1,145 @@
1
+ // Byte-for-byte parity check between the two Forge distribution channels.
2
+ //
3
+ // Runs `forge setup` from BOTH the npm path (`node bin/forge.js`) and the compiled
4
+ // single-file binary into two throwaway git projects, then compares the produced
5
+ // trees by relative-path set + per-file SHA-256. Catches flattening, missing files,
6
+ // CRLF mangling, and corruption in one assertion.
7
+ //
8
+ // This is the "one real-compile leg" the reliability guidance asks for. It is
9
+ // runnable locally (`bun run parity:binary`) and by the step-3 CI matrix on each
10
+ // host target. Requires `bun` and `git` on PATH.
11
+
12
+ import { execFileSync, spawnSync } from 'node:child_process';
13
+ import fs from 'node:fs';
14
+ import os from 'node:os';
15
+ import path from 'node:path';
16
+ import crypto from 'node:crypto';
17
+ import { fileURLToPath } from 'node:url';
18
+
19
+ const REPO = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
20
+ const BIN = process.platform === 'win32' ? 'forge-bin.exe' : 'forge-bin';
21
+ const BIN_PATH = path.join(REPO, BIN);
22
+
23
+ function run(cmd, args, opts = {}) {
24
+ const r = spawnSync(cmd, args, { encoding: 'utf8', ...opts });
25
+ return r;
26
+ }
27
+
28
+ function sha256(file) {
29
+ return crypto.createHash('sha256').update(fs.readFileSync(file)).digest('hex');
30
+ }
31
+
32
+ // Directories to skip entirely while walking a setup tree. `node_modules` is a
33
+ // package-manager install artifact, NOT a Forge-managed asset — `setup --quick`
34
+ // may run an npm/bun install whose output (dependency trees, registry metadata)
35
+ // is legitimately non-deterministic between runs, channels, and OSes. Comparing
36
+ // it produces false-positive drift, so it is excluded. `.git` is runtime VCS state.
37
+ const EXCLUDED_DIRS = new Set(['.git', 'node_modules']);
38
+
39
+ // Files to skip regardless of location. Lockfiles are install byproducts: their
40
+ // bytes vary with registry ordering/timestamps and are not Forge assets. Excluding
41
+ // them keeps parity strict for real assets (skills/rules/hooks/.forge/AGENTS.md)
42
+ // while ignoring package-manager noise. `.package-lock.json` normally lives under
43
+ // node_modules/ (already excluded) but is guarded here too for robustness.
44
+ const EXCLUDED_FILES = new Set(['package-lock.json', '.package-lock.json']);
45
+
46
+ /**
47
+ * Map of relative-posix-path → sha256 for every Forge-managed file under dir.
48
+ * Excludes .git, node_modules/**, and package-manager lockfiles (see the
49
+ * EXCLUDED_* sets above) so parity compares only Forge assets, not install output.
50
+ */
51
+ function hashTree(dir) {
52
+ const map = {};
53
+ const walk = (abs, rel) => {
54
+ for (const e of fs.readdirSync(abs)) {
55
+ if (EXCLUDED_DIRS.has(e)) continue;
56
+ const a = path.join(abs, e);
57
+ const r = rel ? `${rel}/${e}` : e;
58
+ const st = fs.lstatSync(a);
59
+ if (st.isDirectory()) walk(a, r);
60
+ else if (st.isFile() && !EXCLUDED_FILES.has(e)) map[r] = sha256(a);
61
+ }
62
+ };
63
+ walk(dir, '');
64
+ return map;
65
+ }
66
+
67
+ function makeProject(label) {
68
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), `forge-parity-${label}-`));
69
+ execFileSync('git', ['init', '-q'], { cwd: dir });
70
+ execFileSync('git', ['config', 'user.email', 'parity@forge.test'], { cwd: dir });
71
+ execFileSync('git', ['config', 'user.name', 'parity'], { cwd: dir });
72
+ return dir;
73
+ }
74
+
75
+ function runSetup(label, cmd, args, dir) {
76
+ console.log(`\n[${label}] ${cmd} ${args.join(' ')} (cwd=${dir})`);
77
+ const r = run(cmd, args, { cwd: dir });
78
+ if (r.status !== 0) {
79
+ console.error(`[${label}] setup exited ${r.status}`);
80
+ if (r.stdout) console.error(r.stdout.slice(-2000));
81
+ if (r.stderr) console.error(r.stderr.slice(-2000));
82
+ throw new Error(`[${label}] setup failed`);
83
+ }
84
+ return r;
85
+ }
86
+
87
+ function main() {
88
+ // 1. Build the binary (regenerates the embed manifest first).
89
+ console.log('Building single-file binary (bun run build:binary)…');
90
+ const build = run('bun', ['run', 'build:binary'], { cwd: REPO });
91
+ if (build.status !== 0) {
92
+ console.error(build.stdout || '');
93
+ console.error(build.stderr || '');
94
+ throw new Error('build:binary failed');
95
+ }
96
+ if (!fs.existsSync(BIN_PATH)) throw new Error(`binary not found at ${BIN_PATH}`);
97
+
98
+ // 2. Run setup from both channels into fresh git projects.
99
+ const setupArgs = ['setup', '--quick', '--yes'];
100
+ const npmDir = makeProject('npm');
101
+ const binDir = makeProject('bin');
102
+
103
+ // try/finally so the throwaway temp git projects are removed even when setup
104
+ // or the comparison throws (no leaked dirs on any failure path).
105
+ try {
106
+ runSetup('npm', 'node', [path.join(REPO, 'bin', 'forge.js'), ...setupArgs], npmDir);
107
+ runSetup('bin', BIN_PATH, setupArgs, binDir);
108
+
109
+ // 3. Compare trees.
110
+ const a = hashTree(npmDir);
111
+ const b = hashTree(binDir);
112
+ const keys = new Set([...Object.keys(a), ...Object.keys(b)]);
113
+ const missingInBin = [];
114
+ const missingInNpm = [];
115
+ const differing = [];
116
+ for (const k of keys) {
117
+ if (!(k in b)) missingInBin.push(k);
118
+ else if (!(k in a)) missingInNpm.push(k);
119
+ else if (a[k] !== b[k]) differing.push(k);
120
+ }
121
+
122
+ const problems = missingInBin.length + missingInNpm.length + differing.length;
123
+ console.log(`\nParity: ${Object.keys(a).length} npm files vs ${Object.keys(b).length} binary files.`);
124
+ if (missingInBin.length) console.log(` Missing in binary: ${missingInBin.join(', ')}`);
125
+ if (missingInNpm.length) console.log(` Missing in npm: ${missingInNpm.join(', ')}`);
126
+ if (differing.length) console.log(` Differing bytes: ${differing.join(', ')}`);
127
+
128
+ if (problems > 0) {
129
+ console.error(`\nPARITY FAILED (${problems} discrepancies).`);
130
+ process.exit(1);
131
+ }
132
+ console.log('\nPARITY OK — npm and compiled binary produced byte-identical setup trees.');
133
+ } finally {
134
+ fs.rmSync(npmDir, { recursive: true, force: true });
135
+ fs.rmSync(binDir, { recursive: true, force: true });
136
+ }
137
+ }
138
+
139
+ // Exported for unit testing the asset-vs-install-artifact filtering. `hashTree`
140
+ // and the exclusion sets are the load-bearing parity logic; the rest of the file
141
+ // drives real builds and only runs when executed directly (guarded below).
142
+ export { hashTree, EXCLUDED_DIRS, EXCLUDED_FILES };
143
+
144
+ // Only build + compare when run as a script, not when imported by a test.
145
+ if (import.meta.main) main();
@@ -0,0 +1,58 @@
1
+ // Unit test for the parity-check asset filtering. The parity check compares the
2
+ // npm-vs-binary `setup --quick` trees; it MUST ignore package-manager install
3
+ // byproducts (node_modules/**, lockfiles) that are legitimately non-deterministic
4
+ // between runs/channels/OSes, while staying strict for real Forge assets. This
5
+ // test pins that exclusion so a genuine skills/rules/hook drift still fails but
6
+ // install junk never produces a false-positive parity failure.
7
+
8
+ import { test, expect } from 'bun:test';
9
+ import fs from 'node:fs';
10
+ import os from 'node:os';
11
+ import path from 'node:path';
12
+ import { hashTree, EXCLUDED_DIRS, EXCLUDED_FILES } from './parity-check.mjs';
13
+
14
+ function mkTree() {
15
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'parity-hashtree-'));
16
+ // Real Forge-managed assets — these MUST be compared.
17
+ fs.mkdirSync(path.join(dir, 'skills'), { recursive: true });
18
+ fs.writeFileSync(path.join(dir, 'skills', 'SKILL.md'), 'real asset\n');
19
+ fs.writeFileSync(path.join(dir, 'AGENTS.md'), 'real asset\n');
20
+ // Install byproducts — these MUST be excluded.
21
+ fs.mkdirSync(path.join(dir, 'node_modules', 'left-pad'), { recursive: true });
22
+ fs.writeFileSync(path.join(dir, 'node_modules', 'left-pad', 'index.js'), 'junk\n');
23
+ fs.writeFileSync(path.join(dir, 'node_modules', '.package-lock.json'), '{}\n');
24
+ fs.writeFileSync(path.join(dir, 'package-lock.json'), '{"v":1}\n');
25
+ return dir;
26
+ }
27
+
28
+ test('hashTree excludes node_modules and lockfiles but keeps real assets', () => {
29
+ const dir = mkTree();
30
+ try {
31
+ const keys = Object.keys(hashTree(dir)).sort();
32
+ expect(keys).toEqual(['AGENTS.md', 'skills/SKILL.md']);
33
+ // No install artifact leaked into the comparison set.
34
+ expect(keys.some(k => k.includes('node_modules'))).toBe(false);
35
+ expect(keys.some(k => k.endsWith('package-lock.json'))).toBe(false);
36
+ } finally {
37
+ fs.rmSync(dir, { recursive: true, force: true });
38
+ }
39
+ });
40
+
41
+ test('a real asset byte change is still detected (parity stays strict)', () => {
42
+ const dir = mkTree();
43
+ try {
44
+ const before = hashTree(dir);
45
+ fs.writeFileSync(path.join(dir, 'skills', 'SKILL.md'), 'DRIFTED asset\n');
46
+ const after = hashTree(dir);
47
+ expect(after['skills/SKILL.md']).not.toBe(before['skills/SKILL.md']);
48
+ } finally {
49
+ fs.rmSync(dir, { recursive: true, force: true });
50
+ }
51
+ });
52
+
53
+ test('exclusion sets document the intended artifacts', () => {
54
+ expect(EXCLUDED_DIRS.has('node_modules')).toBe(true);
55
+ expect(EXCLUDED_DIRS.has('.git')).toBe(true);
56
+ expect(EXCLUDED_FILES.has('package-lock.json')).toBe(true);
57
+ expect(EXCLUDED_FILES.has('.package-lock.json')).toBe(true);
58
+ });
@@ -0,0 +1,112 @@
1
+ #!/usr/bin/env node
2
+
3
+ const fs = require('node:fs');
4
+ const path = require('node:path');
5
+
6
+ const DEFAULT_LOCK_FILES = [
7
+ '.github/agentic-workflows/behavioral-test.lock.yml',
8
+ '.github/workflows/behavioral-test.lock.yml',
9
+ ];
10
+
11
+ const IMAGE_PINS = [
12
+ {
13
+ image: 'ghcr.io/github/gh-aw-mcpg:v0.3.0',
14
+ digest: 'sha256:9c2228324fb1f26f39dc9471612e530ae3efc3156dac05efb2e8d212878d454d',
15
+ pinnedImage: 'ghcr.io/github/gh-aw-mcpg@sha256:9c2228324fb1f26f39dc9471612e530ae3efc3156dac05efb2e8d212878d454d',
16
+ },
17
+ {
18
+ image: 'ghcr.io/github/github-mcp-server:v1.0.2',
19
+ digest: 'sha256:26db03408086a99cf1916348dcc4f9614206658f9082a8060dc7c81ad787f4ba',
20
+ pinnedImage: 'ghcr.io/github/github-mcp-server@sha256:26db03408086a99cf1916348dcc4f9614206658f9082a8060dc7c81ad787f4ba',
21
+ },
22
+ ];
23
+
24
+ function updateManifestLine(line) {
25
+ const prefix = '# gh-aw-manifest: ';
26
+ if (!line.startsWith(prefix)) {
27
+ return line;
28
+ }
29
+
30
+ const manifest = JSON.parse(line.slice(prefix.length));
31
+ if (!Array.isArray(manifest.containers)) {
32
+ return line;
33
+ }
34
+
35
+ manifest.containers = manifest.containers.map((container) => {
36
+ const pin = IMAGE_PINS.find(candidate => candidate.image === container.image);
37
+ if (!pin) {
38
+ return container;
39
+ }
40
+
41
+ return {
42
+ ...container,
43
+ digest: pin.digest,
44
+ pinned_image: pin.pinnedImage,
45
+ };
46
+ });
47
+
48
+ return `${prefix}${JSON.stringify(manifest)}`;
49
+ }
50
+
51
+ function pinLockContent(content) {
52
+ const lines = content.split(/\r?\n/);
53
+ if (lines.length > 1) {
54
+ lines[1] = updateManifestLine(lines[1]);
55
+ }
56
+
57
+ let pinned = lines.join('\n');
58
+ const manifestPrefix = /^# gh-aw-manifest: .*$/m;
59
+ const manifestMatch = pinned.match(manifestPrefix);
60
+ const manifestLine = manifestMatch ? manifestMatch[0] : null;
61
+ pinned = pinned.replace(manifestPrefix, '__GH_AW_MANIFEST_PLACEHOLDER__');
62
+
63
+ for (const pin of IMAGE_PINS) {
64
+ pinned = pinned.split(pin.image).join(pin.pinnedImage);
65
+ }
66
+
67
+ if (manifestLine) {
68
+ pinned = pinned.replace('__GH_AW_MANIFEST_PLACEHOLDER__', updateManifestLine(manifestLine));
69
+ }
70
+
71
+ return pinned;
72
+ }
73
+
74
+ function pinLockFile(filePath) {
75
+ const original = fs.readFileSync(filePath, 'utf8');
76
+ const pinned = pinLockContent(original);
77
+ if (pinned !== original) {
78
+ fs.writeFileSync(filePath, pinned, 'utf8');
79
+ return true;
80
+ }
81
+ return false;
82
+ }
83
+
84
+ function main() {
85
+ const args = process.argv.slice(2);
86
+ const files = args.length > 0 ? args : DEFAULT_LOCK_FILES;
87
+ const changed = [];
88
+
89
+ for (const file of files) {
90
+ const filePath = path.resolve(process.cwd(), file);
91
+ if (pinLockFile(filePath)) {
92
+ changed.push(file);
93
+ }
94
+ }
95
+
96
+ if (changed.length === 0) {
97
+ console.log('Agentic workflow runtime images already pinned');
98
+ return;
99
+ }
100
+
101
+ console.log(`Pinned agentic workflow runtime images: ${changed.join(', ')}`);
102
+ }
103
+
104
+ if (require.main === module) {
105
+ main();
106
+ }
107
+
108
+ module.exports = {
109
+ IMAGE_PINS,
110
+ pinLockContent,
111
+ pinLockFile,
112
+ };
@@ -15,6 +15,9 @@
15
15
  set -euo pipefail
16
16
 
17
17
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
18
+ if [[ -f "$SCRIPT_DIR/bootstrap-windows-tools.sh" ]]; then
19
+ source "$SCRIPT_DIR/bootstrap-windows-tools.sh"
20
+ fi
18
21
  source "$SCRIPT_DIR/lib/sanitize.sh" || { echo "FATAL: failed to source sanitize.sh" >&2; exit 2; }
19
22
 
20
23
  # Source these but don't fail if missing (tests may not have them)
@@ -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
+ ];
@@ -0,0 +1,108 @@
1
+ #!/usr/bin/env bash
2
+ set -u
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
+
11
+ exit_code=0
12
+ have_gh=0
13
+
14
+ ok() {
15
+ printf 'OK %s - %s\n' "$1" "$2"
16
+ }
17
+
18
+ fixed() {
19
+ printf 'FIXED %s - %s\n' "$1" "$2"
20
+ if [ "$exit_code" -lt 1 ]; then
21
+ exit_code=1
22
+ fi
23
+ }
24
+
25
+ action() {
26
+ printf 'ACTION %s - %s\n' "$1" "$2"
27
+ exit_code=2
28
+ }
29
+
30
+ is_windows_shell() {
31
+ case "$(uname -s 2>/dev/null || printf unknown)" in
32
+ MINGW*|MSYS*|CYGWIN*)
33
+ return 0
34
+ ;;
35
+ *)
36
+ return 1
37
+ ;;
38
+ esac
39
+ }
40
+
41
+ check_tool() {
42
+ tool="$1"
43
+ hint="$2"
44
+
45
+ if command -v "$tool" >/dev/null 2>&1; then
46
+ ok "tool $tool" "found $(command -v "$tool")"
47
+ return 0
48
+ fi
49
+
50
+ action "tool $tool" "missing"
51
+ if is_windows_shell; then
52
+ printf ' Windows hint: %s\n' "$hint"
53
+ else
54
+ printf ' Install hint: %s\n' "$hint"
55
+ fi
56
+ return 1
57
+ }
58
+
59
+ check_tools() {
60
+ check_tool "node" "install Node.js (https://nodejs.org)" || true
61
+ check_tool "jq" "winget install jqlang.jq" || true
62
+
63
+ if check_tool "gh" "winget install GitHub.cli"; then
64
+ have_gh=1
65
+ fi
66
+ }
67
+
68
+ check_github_auth() {
69
+ if [ "$have_gh" -ne 1 ]; then
70
+ return 0
71
+ fi
72
+
73
+ if gh auth status >/dev/null 2>&1; then
74
+ ok "github-auth" "gh auth status succeeded"
75
+ return 0
76
+ fi
77
+
78
+ action "github-auth" "not logged in; run: gh auth login"
79
+ }
80
+
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"
89
+ else
90
+ action "kernel-init" "kernel issue store not initializable; inspect: node bin/forge.js doctor"
91
+ return 0
92
+ fi
93
+
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"
96
+ else
97
+ action "kernel-doctor" "forge doctor reports an unhealthy filesystem; inspect the kernel database path"
98
+ fi
99
+ }
100
+
101
+ main() {
102
+ check_tools
103
+ check_github_auth
104
+ check_kernel
105
+ exit "$exit_code"
106
+ }
107
+
108
+ main "$@"
@@ -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
+ }
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const fs = require('node:fs');
5
+
6
+ const { scoreIssues } = require('../lib/smart-status/scoring.js');
7
+
8
+ function readPayload() {
9
+ const raw = fs.readFileSync(0, 'utf8');
10
+ if (!raw.trim()) {
11
+ return { issues: [], epicStats: {} };
12
+ }
13
+
14
+ const payload = JSON.parse(raw);
15
+ return {
16
+ issues: Array.isArray(payload.issues) ? payload.issues : [],
17
+ epicStats: payload.epicStats && typeof payload.epicStats === 'object' ? payload.epicStats : {},
18
+ };
19
+ }
20
+
21
+ function main() {
22
+ try {
23
+ const payload = readPayload();
24
+ process.stdout.write(JSON.stringify(scoreIssues(payload.issues, { epicStats: payload.epicStats })));
25
+ } catch (error) {
26
+ console.error(`smart-status-score: ${error.message}`);
27
+ process.exit(1);
28
+ }
29
+ }
30
+
31
+ main();
@@ -0,0 +1,51 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const fs = require('node:fs');
5
+
6
+ const {
7
+ applyMergeTreeConflicts,
8
+ computeFileConflicts,
9
+ matchInProgressIssues,
10
+ parseWorktreePorcelain,
11
+ } = require('../lib/smart-status/conflicts.js');
12
+
13
+ function readPayload() {
14
+ const raw = fs.readFileSync(0, 'utf8');
15
+ if (!raw.trim()) {
16
+ return {};
17
+ }
18
+
19
+ return JSON.parse(raw);
20
+ }
21
+
22
+ function buildSessions(payload) {
23
+ let sessions = Array.isArray(payload.sessions)
24
+ ? payload.sessions
25
+ : matchInProgressIssues(
26
+ parseWorktreePorcelain(payload.worktreePorcelain || '', payload.baseBranch || 'master'),
27
+ Array.isArray(payload.inProgressIssues) ? payload.inProgressIssues : [],
28
+ );
29
+
30
+ if (payload.branchFiles) {
31
+ sessions = computeFileConflicts(sessions, payload.branchFiles);
32
+ }
33
+
34
+ if (payload.mergeTreeResults) {
35
+ sessions = applyMergeTreeConflicts(sessions, payload.mergeTreeResults);
36
+ }
37
+
38
+ return sessions;
39
+ }
40
+
41
+ function main() {
42
+ try {
43
+ const payload = readPayload();
44
+ process.stdout.write(JSON.stringify(buildSessions(payload)));
45
+ } catch (error) {
46
+ console.error(`smart-status-sessions: ${error.message}`);
47
+ process.exit(1);
48
+ }
49
+ }
50
+
51
+ main();