forge-workflow 0.0.10 → 0.1.0-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (468) hide show
  1. package/.claude/rules/{greptile-review-process.md → review-process.md} +56 -41
  2. package/.claude/scripts/{greptile-resolve.sh → review-resolve.sh} +13 -3
  3. package/.cursor/rules/permissions-guidance.mdc +2 -2
  4. package/.forge/hooks/check-tdd.js +82 -5
  5. package/.forge/hooks/forge-native-hook.js +431 -0
  6. package/.forge/protected-paths.yaml +157 -0
  7. package/AGENTS.md +151 -61
  8. package/CHANGELOG.md +709 -0
  9. package/CLAUDE.md +9 -118
  10. package/QUICKSTART.md +175 -0
  11. package/README.md +275 -365
  12. package/bin/forge-cmd.js +120 -9
  13. package/bin/forge-preflight.js +26 -5
  14. package/bin/forge.js +532 -489
  15. package/docs/INDEX.md +93 -0
  16. package/docs/PROJECT_DESIGN.md +685 -0
  17. package/docs/architecture/index.md +66 -0
  18. package/docs/architecture/notes/README.md +35 -0
  19. package/docs/architecture/subsystems/README.md +46 -0
  20. package/docs/forge/TOOLCHAIN.md +670 -0
  21. package/docs/forge/VALIDATION.md +82 -0
  22. package/docs/{AGENT_INSTALL_PROMPT.md → guides/AGENT_INSTALL_PROMPT.md} +3 -3
  23. package/docs/guides/BEADS_GITHUB_SYNC.md +32 -0
  24. package/docs/{ENHANCED_ONBOARDING.md → guides/ENHANCED_ONBOARDING.md} +16 -12
  25. package/docs/guides/GREPTILE_SETUP.md +46 -0
  26. package/docs/guides/MANUAL_REVIEW_GUIDE.md +58 -0
  27. package/docs/guides/MIGRATION.md +56 -0
  28. package/docs/guides/SETUP.md +121 -0
  29. package/docs/guides/SUPPORT.md +190 -0
  30. package/docs/guides/WORKFLOW_TEMPLATES.md +74 -0
  31. package/docs/guides/memory-backends.md +183 -0
  32. package/docs/reference/ADAPTERS.md +128 -0
  33. package/docs/reference/AGENT_SKILL_PARITY.md +175 -0
  34. package/docs/reference/COMMANDS.md +214 -0
  35. package/docs/reference/DECISION_DRIFT_GUARDS.md +97 -0
  36. package/docs/{EXAMPLES.md → reference/EXAMPLES.md} +7 -5
  37. package/docs/reference/FORGE_KERNEL_STORAGE_MODEL.md +135 -0
  38. package/docs/reference/HERMES_INTEGRATION.md +118 -0
  39. package/docs/reference/INSIGHTS_RECAP.md +63 -0
  40. package/docs/reference/INSTALL.md +164 -0
  41. package/docs/reference/KERNEL_TAXONOMY_VALIDATION.md +161 -0
  42. package/docs/reference/PROTECTED_PATH_MANIFEST.md +25 -0
  43. package/docs/reference/RELEASE.md +68 -0
  44. package/docs/reference/RESEARCH_TEMPLATE.md +292 -0
  45. package/docs/{ROADMAP.md → reference/ROADMAP.md} +12 -9
  46. package/docs/reference/SKILLS.md +35 -0
  47. package/docs/reference/STATUS_BOARD.md +80 -0
  48. package/docs/reference/TEMPLATES.md +106 -0
  49. package/docs/{TOOLCHAIN.md → reference/TOOLCHAIN.md} +62 -47
  50. package/docs/reference/VALIDATION.md +82 -0
  51. package/docs/reference/agent-permissions.md +169 -0
  52. package/docs/reference/beads-to-kernel-migration-ux.md +61 -0
  53. package/docs/reference/control-plane-guarantees.md +125 -0
  54. package/docs/reference/dependency-chain.md +331 -0
  55. package/docs/reference/forge-kernel-issue-command-contract.md +161 -0
  56. package/docs/reference/forge-kernel-schema.md +72 -0
  57. package/docs/reference/kernel-conflict-evaluators.md +27 -0
  58. package/docs/reference/patch-md-format.md +77 -0
  59. package/docs/reference/protected-state-surfaces.md +59 -0
  60. package/docs/reference/shepherd.md +155 -0
  61. package/docs/reference/superpowers-analysis.md +320 -0
  62. package/docs/reference/superpowers-integration-options.md +404 -0
  63. package/docs/reference/test-environment.md +519 -0
  64. package/docs/reference/upgrade-safety.md +59 -0
  65. package/lefthook.yml +18 -0
  66. package/lib/activation/ensure-forge-home.js +135 -0
  67. package/lib/adapter-cli.js +307 -0
  68. package/lib/adapters/beads-issue-adapter.js +127 -0
  69. package/lib/adapters/beads-kernel-compat.js +1109 -0
  70. package/lib/adapters/greptile-review-adapter.js +141 -0
  71. package/lib/adapters/kernel-issue-adapter.js +101 -0
  72. package/lib/adapters/pr-state-adapter.js +484 -0
  73. package/lib/adoption-profiles.js +139 -0
  74. package/lib/agents/README.md +2 -6
  75. package/lib/agents/claude.plugin.json +3 -8
  76. package/lib/agents/codex.plugin.json +9 -1
  77. package/lib/agents/cursor.plugin.json +2 -6
  78. package/lib/agents/hermes.plugin.json +22 -0
  79. package/lib/agents-config.js +39 -1236
  80. package/lib/audit-evidence.js +282 -0
  81. package/lib/beads-detect.js +60 -0
  82. package/lib/beads-nudge.js +91 -0
  83. package/lib/beads-setup.js +121 -0
  84. package/lib/beads-sync-scaffold.js +25 -101
  85. package/lib/codex-skills.js +51 -1
  86. package/lib/commands/_aliases.js +248 -0
  87. package/lib/commands/_issue.js +780 -77
  88. package/lib/commands/_manifest.js +93 -0
  89. package/lib/commands/_registry.js +99 -34
  90. package/lib/commands/_resolve-command-opts.js +230 -0
  91. package/lib/commands/_serve-security.js +270 -0
  92. package/lib/commands/adapter.js +12 -0
  93. package/lib/commands/add.js +118 -0
  94. package/lib/commands/audit.js +70 -0
  95. package/lib/commands/blocked.js +5 -0
  96. package/lib/commands/board.js +64 -0
  97. package/lib/commands/claim.js +21 -2
  98. package/lib/commands/claims.js +7 -0
  99. package/lib/commands/clean.js +485 -75
  100. package/lib/commands/close.js +2 -2
  101. package/lib/commands/comment.js +5 -0
  102. package/lib/commands/control.js +148 -0
  103. package/lib/commands/create.js +2 -2
  104. package/lib/commands/dev.js +185 -7
  105. package/lib/commands/doc-gate.js +336 -0
  106. package/lib/commands/doctor.js +156 -0
  107. package/lib/commands/explain.js +15 -0
  108. package/lib/commands/export.js +237 -0
  109. package/lib/commands/gate.js +209 -0
  110. package/lib/commands/hooks.js +377 -0
  111. package/lib/commands/inbox.js +118 -0
  112. package/lib/commands/init.js +604 -0
  113. package/lib/commands/insights.js +79 -0
  114. package/lib/commands/issue.js +12 -1
  115. package/lib/commands/issues.js +17 -0
  116. package/lib/commands/lint.js +5 -0
  117. package/lib/commands/list.js +2 -2
  118. package/lib/commands/memory.js +81 -0
  119. package/lib/commands/merge.js +312 -0
  120. package/lib/commands/migrate.js +362 -0
  121. package/lib/commands/new.js +12 -0
  122. package/lib/commands/options.js +241 -0
  123. package/lib/commands/orient.js +13 -0
  124. package/lib/commands/orphans.js +5 -0
  125. package/lib/commands/patch.js +67 -0
  126. package/lib/commands/plan.js +481 -29
  127. package/lib/commands/pr.js +88 -0
  128. package/lib/commands/preflight.js +211 -0
  129. package/lib/commands/prime.js +13 -0
  130. package/lib/commands/push.js +135 -2
  131. package/lib/commands/ready.js +2 -2
  132. package/lib/commands/recall.js +171 -0
  133. package/lib/commands/recap.js +75 -0
  134. package/lib/commands/recommend.js +0 -1
  135. package/lib/commands/release.js +104 -0
  136. package/lib/commands/remember.js +140 -0
  137. package/lib/commands/role.js +99 -0
  138. package/lib/commands/serve.js +581 -0
  139. package/lib/commands/setup.js +900 -971
  140. package/lib/commands/shepherd.js +501 -0
  141. package/lib/commands/ship.js +59 -1
  142. package/lib/commands/show.js +2 -2
  143. package/lib/commands/stage.js +192 -0
  144. package/lib/commands/stale.js +5 -0
  145. package/lib/commands/status.js +158 -21
  146. package/lib/commands/sync.js +34 -46
  147. package/lib/commands/team.js +4 -1
  148. package/lib/commands/test.js +43 -27
  149. package/lib/commands/update.js +2 -2
  150. package/lib/commands/upgrade.js +47 -0
  151. package/lib/commands/validate.js +43 -18
  152. package/lib/commands/worktree.js +362 -99
  153. package/lib/config-writer.js +202 -0
  154. package/lib/control-plane.js +236 -0
  155. package/lib/core/runtime-graph.js +977 -0
  156. package/lib/dep-guard/keyword-ripple.js +2 -2
  157. package/lib/deprecated-sync-cleanup.js +362 -0
  158. package/lib/detect-agent.js +2 -28
  159. package/lib/detect-worktree.js +35 -9
  160. package/lib/doc-gate/declaration.js +177 -0
  161. package/lib/doc-gate/detect.js +289 -0
  162. package/lib/doc-gate/gate.js +375 -0
  163. package/lib/doc-gate/okf-config.js +128 -0
  164. package/lib/doc-gate/okf.js +429 -0
  165. package/lib/docs-command.js +1161 -6
  166. package/lib/forge-issues.js +382 -11
  167. package/lib/forge-lock.js +262 -0
  168. package/lib/gate-events.js +192 -0
  169. package/lib/global-flags.js +104 -0
  170. package/lib/greptile-match.js +7 -63
  171. package/lib/grounding/context-events.js +230 -0
  172. package/lib/grounding/read-first.js +112 -0
  173. package/lib/harness-capability-matrix.js +380 -0
  174. package/lib/hook-global-installer.js +347 -0
  175. package/lib/hook-renderer.js +541 -0
  176. package/lib/inbox.js +391 -0
  177. package/lib/insights.js +397 -0
  178. package/lib/issue-adapter.js +156 -0
  179. package/lib/issue-backend.js +145 -0
  180. package/lib/issue-render.js +220 -0
  181. package/lib/kernel/backing-issue.js +311 -0
  182. package/lib/kernel/broker.js +1218 -0
  183. package/lib/kernel/cli-broker-factory.js +130 -0
  184. package/lib/kernel/conflict-signal.js +82 -0
  185. package/lib/kernel/evaluators.js +195 -0
  186. package/lib/kernel/fs-class.js +495 -0
  187. package/lib/kernel/issue-command-contract.js +559 -0
  188. package/lib/kernel/issue-id-resolver.js +186 -0
  189. package/lib/kernel/lease-enforcer.js +158 -0
  190. package/lib/kernel/migrations.js +333 -0
  191. package/lib/kernel/owned-kernel.js +43 -0
  192. package/lib/kernel/planning-buckets-schema.js +109 -0
  193. package/lib/kernel/projection-jsonl-writer.js +450 -0
  194. package/lib/kernel/readiness-model.js +329 -0
  195. package/lib/kernel/schema.js +356 -0
  196. package/lib/kernel/sqlite-driver.js +2540 -0
  197. package/lib/kernel/taxonomy-validator.js +394 -0
  198. package/lib/lefthook-check.js +3 -2
  199. package/lib/lefthook-wiring.js +413 -0
  200. package/lib/mcp-config-renderer.js +288 -0
  201. package/lib/memory/graphiti-mcp.js +106 -0
  202. package/lib/memory/router.js +387 -0
  203. package/lib/memory/typed-api.js +102 -0
  204. package/lib/memory-digest.js +195 -0
  205. package/lib/merge-rules.js +395 -0
  206. package/lib/migrate-dry-run.js +466 -0
  207. package/lib/orientation.js +863 -0
  208. package/lib/package-manager-remediation.js +103 -0
  209. package/lib/package-root.js +381 -0
  210. package/lib/patch-intent.js +890 -0
  211. package/lib/plugin-catalog.js +3 -4
  212. package/lib/plugin-manager.js +0 -5
  213. package/lib/pr-bundle.js +186 -0
  214. package/lib/pr-monitor/auto-actions.js +175 -0
  215. package/lib/pr-monitor/differ.js +195 -0
  216. package/lib/pr-monitor/digest.js +206 -0
  217. package/lib/pr-monitor/events.js +0 -0
  218. package/lib/pr-monitor/gather.js +124 -0
  219. package/lib/pr-monitor/journal.js +299 -0
  220. package/lib/pr-monitor/monitor.js +146 -0
  221. package/lib/pr-monitor/render-sticky.js +192 -0
  222. package/lib/pr-monitor/upsert-sticky.js +169 -0
  223. package/lib/pr-monitor/watch-lifecycle.js +95 -0
  224. package/lib/pr-monitor/watch.js +247 -0
  225. package/lib/pr-pull.js +1314 -0
  226. package/lib/pr-shepherd.js +494 -0
  227. package/lib/pr-state-validator.js +59 -0
  228. package/lib/preflight/gates.js +237 -0
  229. package/lib/preflight/runner.js +116 -0
  230. package/lib/project-discovery.js +0 -53
  231. package/lib/project-memory.js +99 -497
  232. package/lib/protected-path-manifest.js +281 -0
  233. package/lib/protected-state-surfaces.js +387 -0
  234. package/lib/release-readiness.js +2105 -0
  235. package/lib/reset.js +59 -45
  236. package/lib/review-adapter.js +68 -0
  237. package/lib/rules-sync.js +260 -0
  238. package/lib/runtime-health.js +241 -20
  239. package/lib/safety-config-renderer.js +268 -0
  240. package/lib/setup-action-log.js +1 -7
  241. package/lib/setup.js +27 -65
  242. package/lib/shell-utils.js +76 -6
  243. package/lib/skills-sync.js +330 -0
  244. package/lib/smart-status/scoring.js +17 -3
  245. package/lib/status/beads-snapshot.js +45 -2
  246. package/lib/status/presenter.js +169 -18
  247. package/lib/status/snapshot.js +186 -0
  248. package/lib/sync-backend.js +202 -0
  249. package/lib/untrusted-content.js +52 -0
  250. package/lib/upgrade-safety.js +251 -0
  251. package/lib/workflow/enforce-stage.js +351 -45
  252. package/lib/workflow/stage-transition.js +115 -0
  253. package/lib/workflow/stages.js +30 -6
  254. package/lib/workflow/state-manager.js +11 -22
  255. package/lib/workflow/state.js +23 -1
  256. package/lib/workflow-profiles.js +17 -5
  257. package/package.json +37 -35
  258. package/rules/documentation.md +19 -0
  259. package/rules/kernel-tracking.md +26 -0
  260. package/rules/security.md +22 -0
  261. package/rules/tdd.md +20 -0
  262. package/rules/workflow.md +27 -0
  263. package/scripts/auto-backing-issue.js +47 -0
  264. package/scripts/beads-context.sh +81 -57
  265. package/scripts/beads-upgrade-smoke.sh +24 -3
  266. package/scripts/bootstrap-windows-tools.sh +78 -0
  267. package/scripts/branch-protection.js +2 -3
  268. package/scripts/check-agents.js +34 -137
  269. package/scripts/commitlint.js +3 -1
  270. package/scripts/conflict-detect.sh +3 -0
  271. package/scripts/dep-guard.sh +22 -3
  272. package/scripts/file-index.sh +3 -0
  273. package/scripts/forge-team/lib/claim.sh +34 -18
  274. package/scripts/forge-team/lib/dashboard.sh +61 -86
  275. package/scripts/forge-team/lib/epic.sh +99 -263
  276. package/scripts/forge-team/lib/hooks.sh +26 -28
  277. package/scripts/forge-team/lib/identity.sh +4 -4
  278. package/scripts/forge-team/lib/sync-github.sh +49 -84
  279. package/scripts/forge-team/lib/verify.sh +93 -83
  280. package/scripts/forge-team/lib/workload.sh +41 -65
  281. package/scripts/forge-team/tests/claim.test.sh +25 -19
  282. package/scripts/forge-team/tests/dashboard.test.sh +31 -46
  283. package/scripts/forge-team/tests/epic.test.sh +52 -71
  284. package/scripts/forge-team/tests/hooks.test.sh +38 -50
  285. package/scripts/forge-team/tests/identity.test.sh +3 -3
  286. package/scripts/forge-team/tests/integration.test.sh +44 -66
  287. package/scripts/forge-team/tests/sync-github.test.sh +50 -83
  288. package/scripts/forge-team/tests/verify.test.sh +37 -46
  289. package/scripts/forge-team/tests/workflow-integration.test.sh +4 -4
  290. package/scripts/forge-team/tests/workload.test.sh +32 -66
  291. package/scripts/gen-command-manifest.js +153 -0
  292. package/scripts/gen-embedded-assets.mjs +129 -0
  293. package/scripts/install.ps1 +139 -0
  294. package/scripts/install.sh +268 -0
  295. package/scripts/lib/release-asset.mjs +84 -0
  296. package/scripts/parity-check.mjs +145 -0
  297. package/scripts/parity-check.test.mjs +58 -0
  298. package/scripts/pin-agentic-workflow-images.js +112 -0
  299. package/scripts/pr-auto-actions.js +93 -0
  300. package/scripts/pr-coordinator.sh +3 -0
  301. package/scripts/pr-verdict-label.js +50 -0
  302. package/scripts/preflight-sonar.eslint.config.mjs +44 -0
  303. package/scripts/preflight.sh +21 -94
  304. package/scripts/protected-state-check.js +104 -0
  305. package/scripts/smart-status.sh +60 -57
  306. package/scripts/spikes/config-race-bench.js +111 -0
  307. package/scripts/spikes/harness-capability-matrix.js +13 -0
  308. package/scripts/spikes/patch-anchor-stability-bench.js +125 -0
  309. package/scripts/spikes/protected-path-manifest.js +20 -0
  310. package/scripts/spikes/skill-auto-invoke-parity.js +292 -0
  311. package/scripts/sync-agent-skills.js +62 -0
  312. package/scripts/sync-utils.sh +3 -0
  313. package/scripts/test-ci-shard.js +13 -6
  314. package/scripts/test.js +95 -12
  315. package/skills/claim-safety/SKILL.md +102 -0
  316. package/skills/claim-safety/evals/evals.json +46 -0
  317. package/{.github/prompts/dev.prompt.md → skills/dev/SKILL.md} +44 -50
  318. package/skills/dev/evals/evals.json +50 -0
  319. package/skills/hermes-forge/SKILL.md +185 -0
  320. package/skills/hermes-forge/evals/evals.json +46 -0
  321. package/skills/issue-basics/SKILL.md +111 -0
  322. package/skills/issue-basics/evals/evals.json +46 -0
  323. package/skills/kernel/SKILL.md +166 -0
  324. package/skills/kernel/evals/evals.json +50 -0
  325. package/skills/memory/SKILL.md +102 -0
  326. package/skills/parallel-deep-research/SKILL.md +14 -11
  327. package/skills/parallel-deep-research/evals/evals.json +11 -27
  328. package/{.github/prompts/plan.prompt.md → skills/plan/SKILL.md} +132 -157
  329. package/skills/plan/evals/evals.json +42 -0
  330. package/skills/research/SKILL.md +195 -0
  331. package/skills/research/evals/evals.json +42 -0
  332. package/{.github/prompts/review.prompt.md → skills/review/SKILL.md} +98 -62
  333. package/skills/review/evals/evals.json +42 -0
  334. package/skills/rollback/SKILL.md +110 -0
  335. package/skills/rollback/evals/evals.json +46 -0
  336. package/skills/rollback/references/methods.md +204 -0
  337. package/{.cursor/commands/rollback.md → skills/rollback/references/workflow-integration.md} +10 -284
  338. package/skills/shepherd/SKILL.md +66 -0
  339. package/skills/shepherd/evals/evals.json +42 -0
  340. package/{.github/prompts/ship.prompt.md → skills/ship/SKILL.md} +81 -45
  341. package/skills/ship/evals/evals.json +42 -0
  342. package/skills/smith/SKILL.md +142 -0
  343. package/skills/smith/evals/evals.json +46 -0
  344. package/skills/smith/references/autonomy-and-gates.md +94 -0
  345. package/{.github/prompts/sonarcloud.prompt.md → skills/sonarcloud/SKILL.md} +14 -3
  346. package/skills/sonarcloud/evals/evals.json +46 -0
  347. package/skills/sonarcloud-analysis/SKILL.md +18 -13
  348. package/skills/sonarcloud-analysis/evals/evals.json +11 -15
  349. package/{.github/prompts/status.prompt.md → skills/status/SKILL.md} +20 -10
  350. package/skills/status/evals/evals.json +50 -0
  351. package/skills/triage-ready/SKILL.md +121 -0
  352. package/skills/triage-ready/evals/evals.json +42 -0
  353. package/{.github/prompts/validate.prompt.md → skills/validate/SKILL.md} +52 -29
  354. package/skills/validate/evals/evals.json +42 -0
  355. package/skills/verify/SKILL.md +299 -0
  356. package/skills/verify/evals/evals.json +50 -0
  357. package/.claude/commands/dev.md +0 -345
  358. package/.claude/commands/plan.md +0 -566
  359. package/.claude/commands/premerge.md +0 -186
  360. package/.claude/commands/research.md +0 -42
  361. package/.claude/commands/review.md +0 -451
  362. package/.claude/commands/rollback.md +0 -721
  363. package/.claude/commands/ship.md +0 -213
  364. package/.claude/commands/sonarcloud.md +0 -152
  365. package/.claude/commands/status.md +0 -90
  366. package/.claude/commands/validate.md +0 -288
  367. package/.claude/commands/verify.md +0 -269
  368. package/.claude/rules/workflow.md +0 -121
  369. package/.cline/workflows/dev.md +0 -342
  370. package/.cline/workflows/plan.md +0 -563
  371. package/.cline/workflows/premerge.md +0 -183
  372. package/.cline/workflows/research.md +0 -39
  373. package/.cline/workflows/review.md +0 -448
  374. package/.cline/workflows/rollback.md +0 -718
  375. package/.cline/workflows/ship.md +0 -210
  376. package/.cline/workflows/sonarcloud.md +0 -146
  377. package/.cline/workflows/status.md +0 -87
  378. package/.cline/workflows/validate.md +0 -285
  379. package/.cline/workflows/verify.md +0 -266
  380. package/.codex/config.toml +0 -11
  381. package/.codex/skills/dev/SKILL.md +0 -345
  382. package/.codex/skills/plan/SKILL.md +0 -566
  383. package/.codex/skills/premerge/SKILL.md +0 -186
  384. package/.codex/skills/research/SKILL.md +0 -42
  385. package/.codex/skills/review/SKILL.md +0 -451
  386. package/.codex/skills/rollback/SKILL.md +0 -721
  387. package/.codex/skills/ship/SKILL.md +0 -213
  388. package/.codex/skills/sonarcloud/SKILL.md +0 -149
  389. package/.codex/skills/status/SKILL.md +0 -90
  390. package/.codex/skills/validate/SKILL.md +0 -288
  391. package/.codex/skills/verify/SKILL.md +0 -269
  392. package/.cursor/commands/dev.md +0 -342
  393. package/.cursor/commands/plan.md +0 -563
  394. package/.cursor/commands/premerge.md +0 -183
  395. package/.cursor/commands/research.md +0 -39
  396. package/.cursor/commands/review.md +0 -448
  397. package/.cursor/commands/ship.md +0 -210
  398. package/.cursor/commands/sonarcloud.md +0 -146
  399. package/.cursor/commands/status.md +0 -87
  400. package/.cursor/commands/validate.md +0 -285
  401. package/.cursor/commands/verify.md +0 -266
  402. package/.cursorrules +0 -149
  403. package/.github/prompts/premerge.prompt.md +0 -188
  404. package/.github/prompts/research.prompt.md +0 -44
  405. package/.github/prompts/rollback.prompt.md +0 -723
  406. package/.github/prompts/verify.prompt.md +0 -271
  407. package/.github/workflows/beads-to-github.yml +0 -89
  408. package/.github/workflows/github-to-beads.yml +0 -100
  409. package/.kilocode/workflows/dev.md +0 -346
  410. package/.kilocode/workflows/plan.md +0 -567
  411. package/.kilocode/workflows/premerge.md +0 -187
  412. package/.kilocode/workflows/research.md +0 -43
  413. package/.kilocode/workflows/review.md +0 -452
  414. package/.kilocode/workflows/rollback.md +0 -722
  415. package/.kilocode/workflows/ship.md +0 -214
  416. package/.kilocode/workflows/sonarcloud.md +0 -150
  417. package/.kilocode/workflows/status.md +0 -91
  418. package/.kilocode/workflows/validate.md +0 -289
  419. package/.kilocode/workflows/verify.md +0 -270
  420. package/.opencode/commands/dev.md +0 -345
  421. package/.opencode/commands/plan.md +0 -566
  422. package/.opencode/commands/premerge.md +0 -186
  423. package/.opencode/commands/research.md +0 -42
  424. package/.opencode/commands/review.md +0 -451
  425. package/.opencode/commands/rollback.md +0 -721
  426. package/.opencode/commands/ship.md +0 -213
  427. package/.opencode/commands/sonarcloud.md +0 -149
  428. package/.opencode/commands/status.md +0 -90
  429. package/.opencode/commands/validate.md +0 -288
  430. package/.opencode/commands/verify.md +0 -269
  431. package/.roo/commands/dev.md +0 -346
  432. package/.roo/commands/plan.md +0 -567
  433. package/.roo/commands/premerge.md +0 -187
  434. package/.roo/commands/research.md +0 -43
  435. package/.roo/commands/review.md +0 -452
  436. package/.roo/commands/rollback.md +0 -722
  437. package/.roo/commands/ship.md +0 -214
  438. package/.roo/commands/sonarcloud.md +0 -150
  439. package/.roo/commands/status.md +0 -91
  440. package/.roo/commands/validate.md +0 -289
  441. package/.roo/commands/verify.md +0 -270
  442. package/docs/BEADS_GITHUB_SYNC.md +0 -281
  443. package/docs/GREPTILE_SETUP.md +0 -400
  444. package/docs/MANUAL_REVIEW_GUIDE.md +0 -106
  445. package/docs/SETUP.md +0 -663
  446. package/docs/VALIDATION.md +0 -363
  447. package/lib/agents/cline.plugin.json +0 -29
  448. package/lib/agents/copilot.plugin.json +0 -24
  449. package/lib/agents/kilocode.plugin.json +0 -22
  450. package/lib/agents/opencode.plugin.json +0 -23
  451. package/lib/agents/roo.plugin.json +0 -30
  452. package/lib/beads-bootstrap.js +0 -225
  453. package/lib/beads-health-check.js +0 -188
  454. package/lib/commands/commands-reset.js +0 -147
  455. package/opencode.json +0 -67
  456. package/scripts/beads-context.test.js +0 -584
  457. package/scripts/github-beads-sync/comment.mjs +0 -64
  458. package/scripts/github-beads-sync/config.mjs +0 -148
  459. package/scripts/github-beads-sync/github-api.mjs +0 -131
  460. package/scripts/github-beads-sync/index.mjs +0 -356
  461. package/scripts/github-beads-sync/label-mapper.mjs +0 -54
  462. package/scripts/github-beads-sync/mapping.mjs +0 -132
  463. package/scripts/github-beads-sync/reverse-sync-cli.mjs +0 -31
  464. package/scripts/github-beads-sync/reverse-sync.mjs +0 -162
  465. package/scripts/github-beads-sync/run-bd.mjs +0 -161
  466. package/scripts/github-beads-sync/sanitize.mjs +0 -121
  467. package/scripts/github-beads-sync.config.json +0 -26
  468. package/scripts/sync-commands.js +0 -600
@@ -0,0 +1,431 @@
1
+ #!/usr/bin/env node
2
+
3
+ 'use strict';
4
+
5
+ /**
6
+ * Forge native-hook enforcement adapter.
7
+ *
8
+ * Invoked by the rendered native hook configs (.claude/settings.json hooks block
9
+ * and .cursor/hooks.json) that `forge setup` writes via lib/hook-renderer.js. It
10
+ * projects Forge's lifecycle enforcement onto each harness's native hook surface:
11
+ *
12
+ * --intent protected-path : deny writes/edits to Forge-protected paths.
13
+ * --intent tdd-gate : on a `git commit`, delegate to the installed
14
+ * check-tdd.js and deny the commit if source files
15
+ * are staged without accompanying tests.
16
+ *
17
+ * Contract (verified from harness docs):
18
+ * - Claude PreToolUse : stdin has { tool_name, tool_input:{ file_path|command } };
19
+ * to BLOCK, print { hookSpecificOutput:{ hookEventName:'PreToolUse',
20
+ * permissionDecision:'deny', permissionDecisionReason } } and exit 0. To
21
+ * allow, print nothing (never auto-approve past the user's own settings).
22
+ * - Cursor before* : stdin has { command|file_path }; to BLOCK, print
23
+ * { continue:true, permission:'deny', agentMessage, userMessage } and exit 0.
24
+ * (afterFileEdit is observational — permission is ignored but the message
25
+ * still surfaces the protected-path violation.)
26
+ *
27
+ * SELF-CONTAINED: target projects have .forge/hooks/*.js but NOT lib/, so this
28
+ * module requires nothing from the Forge package. The protected-path set is a
29
+ * conservative built-in mirroring the categories in .forge/protected-paths.yaml.
30
+ *
31
+ * Security: delegates to check-tdd.js via execFileSync (no shell), never evals input.
32
+ */
33
+
34
+ const { execFileSync } = require('node:child_process');
35
+ const fs = require('node:fs');
36
+ const path = require('node:path');
37
+
38
+ // Conservative protected-path set, mirroring .forge/protected-paths.yaml categories:
39
+ // forge_core (.forge/), user_protocol (AGENTS.md), immutable/config (lefthook.yml),
40
+ // secrets (.env*), lockfiles (package-lock/yarn/pnpm/bun), the issue-state dir
41
+ // (cli-only), and VCS (.git/).
42
+ // NOTE: the issue-state matcher is built from a split literal so the D20 retirement
43
+ // audit (release-readiness.js findBdTerms) does not miscount a path matcher as
44
+ // direct issue-tool access — this file never touches that tooling.
45
+ const ISSUE_STATE_DIR_PATTERN = new RegExp('(^|/)\\.' + 'beads' + '(/|$)');
46
+ const PROTECTED_PATTERNS = [
47
+ /(^|\/)\.git(\/|$)/,
48
+ /(^|\/)\.forge(\/|$)/,
49
+ ISSUE_STATE_DIR_PATTERN,
50
+ /(^|\/)AGENTS\.md$/i,
51
+ /(^|\/)lefthook\.ya?ml$/i,
52
+ /(^|\/)\.env(\.[^/]+)?$/i,
53
+ /(^|\/)(package-lock\.json|yarn\.lock|pnpm-lock\.yaml|bun\.lock[b]?)$/i,
54
+ ];
55
+
56
+ // ── Config-honest enforcement ───────────────────────────────────────────────
57
+ // A DISABLED gate/rail in .forge/config.yaml must make its hook genuinely inert
58
+ // (issue eda6d866). These hooks are self-contained (target projects have
59
+ // .forge/hooks/*.js but NOT lib/), so we read + interpret the config here rather
60
+ // than through the resolver. The `yaml` package is a Forge dependency present in
61
+ // any project that ran `forge setup`; when it is somehow absent we degrade to a
62
+ // conservative raw-text scan. Unparseable/missing config FAILS TOWARD enforcement
63
+ // (default ON) so we never silently drop a gate the user did not disable.
64
+
65
+ /** Load `.forge/config.yaml` into an object, or `{ __raw }` for a text-scan fallback, or null. */
66
+ function loadConfigObject(projectRoot) {
67
+ let raw;
68
+ try {
69
+ raw = fs.readFileSync(path.join(projectRoot, '.forge', 'config.yaml'), 'utf8');
70
+ } catch {
71
+ return null; // no config file → caller defaults to enforcement ON
72
+ }
73
+ if (!raw || !raw.trim()) return {};
74
+ let YAML;
75
+ try {
76
+ YAML = require('yaml');
77
+ } catch {
78
+ // The yaml MODULE is genuinely unavailable → degrade to a conservative raw-text
79
+ // scan (the only case that keeps { __raw }). Parser presence and parse success are
80
+ // deliberately separated so a MALFORMED file never reaches the fuzzy scan below.
81
+ return { __raw: raw };
82
+ }
83
+ try {
84
+ const parsed = YAML.parse(raw);
85
+ return parsed && typeof parsed === 'object' && !Array.isArray(parsed) ? parsed : {};
86
+ } catch {
87
+ // MALFORMED YAML (module present, parse threw) → FAIL TOWARD ENFORCEMENT. Return {}
88
+ // so resolveEnforcement defaults to TDD ON + built-in protected paths. We must NOT
89
+ // fall through to the raw-text scan: a broken file containing a `rail.tdd_intent:
90
+ // enabled: false` fragment could otherwise switch enforcement OFF (issue eda6d866).
91
+ return {};
92
+ }
93
+ }
94
+
95
+ /** A primitive is "disabled" only when its `enabled` is explicitly boolean false. */
96
+ function isExplicitlyDisabled(node) {
97
+ return Boolean(node) && typeof node === 'object' && node.enabled === false;
98
+ }
99
+
100
+ // Overly-broad patterns the runtime graph rejects (lib/core/runtime-graph.js
101
+ // validateProtectedPaths). Kept in sync here because this hook is self-contained
102
+ // and cannot import from lib/.
103
+ const OVERLY_BROAD_PROTECTED_PATTERNS = ['*', '**', '**/*', '.', './', '/'];
104
+
105
+ /**
106
+ * Validate a config-supplied protectedPaths list with the SAME rules the runtime
107
+ * graph enforces: every entry must be a non-empty string and not an overly-broad
108
+ * pattern. A list with ANY invalid entry is rejected WHOLESALE (returns null →
109
+ * caller falls back to the built-in protected set), so an invalid or overly-broad
110
+ * config can never become authoritative and WEAKEN protection — it fails toward
111
+ * enforcement, matching the rest of this hook's fail-safe stance (issue eda6d866).
112
+ * @returns {string[]|null} validated list (may be empty = deliberately inert), or
113
+ * null when the list is absent/invalid.
114
+ */
115
+ function validateConfiguredProtectedPaths(list) {
116
+ if (!Array.isArray(list)) return null;
117
+ const validated = [];
118
+ for (const entry of list) {
119
+ if (typeof entry !== 'string' || entry.trim() === '') return null;
120
+ const pattern = entry.trim();
121
+ if (OVERLY_BROAD_PROTECTED_PATTERNS.includes(pattern)) return null;
122
+ validated.push(pattern);
123
+ }
124
+ return validated;
125
+ }
126
+
127
+ /** Scan raw YAML for a `<key>:` block whose immediate child is `enabled: false`. */
128
+ function rawKeyDisabled(raw, key) {
129
+ const lines = String(raw).split(/\r?\n/);
130
+ const keyRe = new RegExp(`^(\\s*)"?${key.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}"?\\s*:\\s*$`);
131
+ for (let i = 0; i < lines.length; i += 1) {
132
+ const m = lines[i].match(keyRe);
133
+ if (!m) continue;
134
+ const parentIndent = m[1].length;
135
+ for (let j = i + 1; j < lines.length; j += 1) {
136
+ if (!lines[j].trim()) continue;
137
+ const childIndent = lines[j].match(/^\s*/)[0].length;
138
+ if (childIndent <= parentIndent) break; // left the block
139
+ if (/^\s*enabled\s*:\s*false\s*$/.test(lines[j])) return true;
140
+ }
141
+ }
142
+ return false;
143
+ }
144
+
145
+ /**
146
+ * Resolve the enforcement state the installed hooks must honor.
147
+ * @returns {{ tddEnabled: boolean, protectedPaths: string[]|null }}
148
+ * tddEnabled — false only when rail.tdd_intent is explicitly disabled.
149
+ * protectedPaths — the configured list (may be []), or null when unset (→ built-in set).
150
+ */
151
+ function resolveEnforcement(projectRoot) {
152
+ const config = loadConfigObject(projectRoot);
153
+ if (!config) return { tddEnabled: true, protectedPaths: null };
154
+
155
+ let tddDisabled;
156
+ let protectedPaths = null;
157
+ if (config.__raw) {
158
+ tddDisabled = rawKeyDisabled(config.__raw, 'rail.tdd_intent') || rawKeyDisabled(config.__raw, 'tdd_intent');
159
+ if (/^\s*protectedPaths\s*:\s*\[\s*\]\s*$/m.test(config.__raw)) protectedPaths = [];
160
+ } else {
161
+ // `forge gate disable` writes workflow.gates['rail.tdd_intent']; the `full`
162
+ // profile writes top-level rails.tdd_intent. Honor either shape.
163
+ const gates = config.workflow && config.workflow.gates;
164
+ const rails = config.rails;
165
+ tddDisabled = isExplicitlyDisabled(gates && gates['rail.tdd_intent'])
166
+ || isExplicitlyDisabled(rails && rails.tdd_intent);
167
+ // Validate before overriding built-in protection: a bad/overly-broad list must
168
+ // fall back to the built-in set (null), never become authoritative (T2).
169
+ protectedPaths = validateConfiguredProtectedPaths(config.protectedPaths);
170
+ }
171
+ return { tddEnabled: !tddDisabled, protectedPaths };
172
+ }
173
+
174
+ /**
175
+ * The SINGLE resolved predicate each hook gates on — flag-agnostic on purpose.
176
+ * Whatever config flag ultimately governs an enforcement kind resolves inside
177
+ * resolveEnforcement(); callers ask only "is this active?". This is the one place
178
+ * the TDD off-switch is read, so a future flag change lands here with no rework.
179
+ * @param {'tdd'|'protected-path'} kind
180
+ */
181
+ function isEnforcementActive(kind, projectRoot) {
182
+ const { tddEnabled, protectedPaths } = resolveEnforcement(projectRoot);
183
+ if (kind === 'tdd') return tddEnabled;
184
+ if (kind === 'protected-path') return protectedPaths === null || protectedPaths.length > 0;
185
+ return true;
186
+ }
187
+
188
+ // Translate a config protectedPaths entry (a path or glob like `.github/workflows/**`)
189
+ // into an anchored matcher. `**` spans path separators, `*` stays within one segment.
190
+ function globToRegExp(pattern) {
191
+ const norm = normalize(pattern);
192
+ let re = '';
193
+ for (let i = 0; i < norm.length; i += 1) {
194
+ const c = norm[i];
195
+ if (c === '*') {
196
+ if (norm[i + 1] === '*') { re += '.*'; i += 1; if (norm[i + 1] === '/') i += 1; }
197
+ else re += '[^/]*';
198
+ } else if ('\\^$.|?+()[]{}'.includes(c)) {
199
+ re += `\\${c}`;
200
+ } else {
201
+ re += c;
202
+ }
203
+ }
204
+ return new RegExp(`(^|/)${re}(/|$)`);
205
+ }
206
+
207
+ /**
208
+ * Build the protected-path matcher from resolved config (config is the source of
209
+ * truth — the hardcoded PROTECTED_PATTERNS set is only the fallback when config
210
+ * omits protectedPaths entirely, so no gate is silently dropped):
211
+ * null → unset → built-in default set (fail toward enforcement / back-compat)
212
+ * [] → explicitly empty → nothing protected (inert)
213
+ * list → protect exactly those paths/globs
214
+ */
215
+ function buildProtectedMatcher(protectedPaths) {
216
+ if (protectedPaths === null) {
217
+ return p => Boolean(p) && PROTECTED_PATTERNS.some(re => re.test(normalize(p)));
218
+ }
219
+ if (protectedPaths.length === 0) return () => false;
220
+ const regexes = protectedPaths.map(globToRegExp);
221
+ return p => Boolean(p) && regexes.some(re => re.test(normalize(p)));
222
+ }
223
+
224
+ /** Parse `--intent <id> --harness <id>` from an argv slice. */
225
+ function parseArgs(argv) {
226
+ const out = { intent: null, harness: null };
227
+ for (let i = 0; i < argv.length; i += 1) {
228
+ if (argv[i] === '--intent') out.intent = argv[i + 1];
229
+ else if (argv[i] === '--harness') out.harness = argv[i + 1];
230
+ }
231
+ return out;
232
+ }
233
+
234
+ /** Extract the target file path from a harness hook payload, or null. */
235
+ function extractPath(input) {
236
+ if (!input || typeof input !== 'object') return null;
237
+ const ti = input.tool_input && typeof input.tool_input === 'object' ? input.tool_input : {};
238
+ // ti.path covers Hermes write_file/patch payloads ({ tool_input: { path } }); the
239
+ // others cover Claude (file_path/notebook_path) and flat Cursor payloads.
240
+ const candidate = ti.file_path || ti.notebook_path || ti.path || input.file_path || null;
241
+ return typeof candidate === 'string' && candidate.length ? candidate : null;
242
+ }
243
+
244
+ /** Extract the shell command from a harness hook payload, or null. */
245
+ function extractCommand(input) {
246
+ if (!input || typeof input !== 'object') return null;
247
+ const ti = input.tool_input && typeof input.tool_input === 'object' ? input.tool_input : {};
248
+ const candidate = ti.command || input.command || null;
249
+ return typeof candidate === 'string' && candidate.length ? candidate : null;
250
+ }
251
+
252
+ function normalize(p) {
253
+ return String(p).replace(/\\/g, '/').replace(/^\.\//, '');
254
+ }
255
+
256
+ /** True when a path falls inside Forge's built-in protected set (the fallback matcher). */
257
+ function isProtectedPath(p) {
258
+ if (!p) return false;
259
+ const n = normalize(p);
260
+ return PROTECTED_PATTERNS.some(re => re.test(n));
261
+ }
262
+
263
+ // Write-intent shell constructs: mutating commands and output redirection. Reads
264
+ // (cat/ls/grep) of protected paths stay allowed — the protected-path intent guards
265
+ // WRITES, mirroring the Claude wiring (PreToolUse matcher Write|Edit, not Read).
266
+ const WRITE_INTENT_RE = /(^|[\s;|&(])(rm|mv|cp|tee|truncate|chmod|chown|ln|sed|perl|dd|install|rsync|unlink|shred)\b|>>?/;
267
+
268
+ /**
269
+ * True when a SHELL COMMAND shows WRITE intent toward a Forge-protected path.
270
+ * Needed because Cursor's only deny-capable surface is `beforeShellExecution`,
271
+ * whose payload carries `command` (no file_path) — without this check the
272
+ * protected-path intent could never actually block anything on Cursor.
273
+ * Conservative two-step: (1) the command must contain a mutating construct
274
+ * (rm/mv/sed/tee/redirection/...), then (2) token-scan (split on whitespace +
275
+ * shell operators, strip quotes) for a protected path. Never throws.
276
+ */
277
+ function commandTouchesProtectedPath(command, isProtected = isProtectedPath) {
278
+ if (typeof command !== 'string' || !command) return false;
279
+ if (!WRITE_INTENT_RE.test(command)) return false;
280
+ const tokens = command.split(/[\s;|&<>()]+/);
281
+ for (const raw of tokens) {
282
+ const token = raw.replace(/^["']+|["']+$/g, '');
283
+ if (token && !token.startsWith('-') && isProtected(token)) return true;
284
+ }
285
+ return false;
286
+ }
287
+
288
+ /** True when a shell command invokes `git commit`. */
289
+ function isGitCommit(command) {
290
+ return typeof command === 'string' && /\bgit\b[^\n&|;]*\bcommit\b/.test(command);
291
+ }
292
+
293
+ /** Run the installed TDD check; returns its exit code (0 = pass, non-zero = block). */
294
+ function runInstalledTddCheck() {
295
+ try {
296
+ execFileSync('node', [path.join(__dirname, 'check-tdd.js')], {
297
+ stdio: ['ignore', 'ignore', 'ignore'],
298
+ });
299
+ return 0;
300
+ } catch (err) {
301
+ return typeof err.status === 'number' ? err.status : 1;
302
+ }
303
+ }
304
+
305
+ // Fully-ON default keeps back-compat: callers that pass no `enforcement` (and the
306
+ // existing test suite) get the original always-enforce behavior.
307
+ const ENFORCEMENT_ON = Object.freeze({ tddEnabled: true, protectedPaths: null });
308
+
309
+ /**
310
+ * Core enforcement decision. `runTddCheck` is injectable for deterministic tests;
311
+ * `enforcement` (from resolveEnforcement) makes a DISABLED gate/rail inert.
312
+ * @returns {{ decision: 'allow'|'deny', reason?: string }}
313
+ */
314
+ function decide({ intent, input, runTddCheck = runInstalledTddCheck, enforcement = ENFORCEMENT_ON }) {
315
+ if (intent === 'protected-path') {
316
+ // Config is the source of truth: matcher is built from the resolved
317
+ // protectedPaths list (empty → inert; unset → built-in fallback set).
318
+ const matchesProtected = buildProtectedMatcher(enforcement.protectedPaths);
319
+ const target = extractPath(input);
320
+ if (matchesProtected(target)) {
321
+ return {
322
+ decision: 'deny',
323
+ reason: `Forge-protected path '${normalize(target)}' — edit it through the owning Forge CLI/skill, not a raw write.`,
324
+ };
325
+ }
326
+ // No file path in the payload (e.g. Cursor beforeShellExecution carries only
327
+ // `command`): inspect the shell command for write intent on a protected path,
328
+ // so the deny-capable shell surface actually protects instead of no-oping.
329
+ if (!target) {
330
+ const command = extractCommand(input);
331
+ if (commandTouchesProtectedPath(command, matchesProtected)) {
332
+ return {
333
+ decision: 'deny',
334
+ reason: 'Shell command writes to a Forge-protected path — use the owning Forge CLI/skill instead.',
335
+ };
336
+ }
337
+ }
338
+ return { decision: 'allow' };
339
+ }
340
+
341
+ if (intent === 'tdd-gate') {
342
+ // TDD rail disabled in config → inert: never run the check, never block.
343
+ if (!enforcement.tddEnabled) return { decision: 'allow' };
344
+ const command = extractCommand(input);
345
+ if (!isGitCommit(command)) return { decision: 'allow' };
346
+ const code = runTddCheck();
347
+ if (code !== 0) {
348
+ return {
349
+ decision: 'deny',
350
+ reason: 'TDD gate: staged source files are missing accompanying tests. Write tests first (RED-GREEN-REFACTOR).',
351
+ };
352
+ }
353
+ return { decision: 'allow' };
354
+ }
355
+
356
+ // Unknown intent: never block.
357
+ return { decision: 'allow' };
358
+ }
359
+
360
+ /** Serialize a decision into the harness-native hook output contract. */
361
+ function formatOutput(harness, decision, _reason) {
362
+ const reason = decision.reason || '';
363
+ if (decision.decision !== 'deny') {
364
+ // Allow: for Claude, emit nothing so we never auto-approve past user settings.
365
+ return harness === 'cursor'
366
+ ? JSON.stringify({ continue: true, permission: 'allow' })
367
+ : '';
368
+ }
369
+ if (harness === 'cursor') {
370
+ return JSON.stringify({
371
+ continue: true,
372
+ permission: 'deny',
373
+ agentMessage: reason,
374
+ userMessage: reason,
375
+ });
376
+ }
377
+ if (harness === 'hermes') {
378
+ // Hermes shell-hook JSON wire protocol: block a pre_tool_call by writing
379
+ // { action: 'block', message } to stdout (empty output = silent allow).
380
+ return JSON.stringify({ action: 'block', message: reason });
381
+ }
382
+ // Claude (and any harness modeled on it).
383
+ return JSON.stringify({
384
+ hookSpecificOutput: {
385
+ hookEventName: 'PreToolUse',
386
+ permissionDecision: 'deny',
387
+ permissionDecisionReason: reason,
388
+ },
389
+ });
390
+ }
391
+
392
+ function readStdin() {
393
+ try {
394
+ const raw = require('node:fs').readFileSync(0, 'utf-8');
395
+ return raw && raw.trim() ? JSON.parse(raw) : {};
396
+ } catch {
397
+ return {};
398
+ }
399
+ }
400
+
401
+ function main() {
402
+ const { intent, harness } = parseArgs(process.argv.slice(2));
403
+ const input = readStdin();
404
+ // Project root is two levels up from this installed hook (<root>/.forge/hooks/),
405
+ // so enforcement resolves against the project's config regardless of cwd.
406
+ const enforcement = resolveEnforcement(path.resolve(__dirname, '..', '..'));
407
+ const decision = decide({ intent, input, enforcement });
408
+ const output = formatOutput(harness || 'claude', decision);
409
+ if (output) process.stdout.write(output);
410
+ // Exit 0 always: the decision travels in the JSON body, not the exit code, so a
411
+ // non-deny outcome leaves the harness's normal permission flow untouched.
412
+ process.exit(0);
413
+ }
414
+
415
+ module.exports = {
416
+ PROTECTED_PATTERNS,
417
+ resolveEnforcement,
418
+ isEnforcementActive,
419
+ globToRegExp,
420
+ buildProtectedMatcher,
421
+ parseArgs,
422
+ extractPath,
423
+ extractCommand,
424
+ isProtectedPath,
425
+ commandTouchesProtectedPath,
426
+ isGitCommit,
427
+ decide,
428
+ formatOutput,
429
+ };
430
+
431
+ if (require.main === module) main();
@@ -0,0 +1,157 @@
1
+ version: 1
2
+ schemaVersion: 1.0.0
3
+ kind: ProtectedPathManifest
4
+ manifestPath: .forge/protected-paths.yaml
5
+ surfacesDeprecated: true
6
+ surfacesMigrationNote: Legacy surfaces remain for 0.0.19 protected-state docs/runtime parity; every example below must be covered by the authoritative W1 categories.
7
+ surfaces:
8
+ immutable:
9
+ examples:
10
+ - .git/
11
+ repair: Use git or the owning runtime tool.
12
+ secrets:
13
+ examples:
14
+ - .env.local
15
+ - secrets.json
16
+ repair: Use the secret manager or local environment setup command.
17
+ append_only_logs:
18
+ examples:
19
+ - .forge/log.jsonl
20
+ - .forge/audit.log
21
+ - .beads/interactions.jsonl
22
+ repair: Use the append-only Forge or Beads audit writer.
23
+ beads_state:
24
+ examples:
25
+ - .beads/issues.jsonl
26
+ - .beads/config.yaml
27
+ repair: Use bd or Forge issue commands.
28
+ forge_config:
29
+ examples:
30
+ - .forge/config.yaml
31
+ - .forge/protected-paths.yaml
32
+ repair: Use Forge setup/config commands or the protected Forge API writer.
33
+ extension_manifests:
34
+ examples:
35
+ - .forge/extensions/example/manifest.json
36
+ - .github/PLUGIN_TEMPLATE.json
37
+ repair: Use the Forge extension/plugin manager.
38
+ lockfiles:
39
+ examples:
40
+ - bun.lock
41
+ - package-lock.json
42
+ - .forge/extensions.lock
43
+ repair: Regenerate through the package manager or extension installer.
44
+ workflows:
45
+ examples:
46
+ - .github/workflows/
47
+ - .claude/commands/
48
+ - .forge/hooks/
49
+ - lefthook.yml
50
+ repair: Use Forge workflow/setup commands.
51
+ generated_harness:
52
+ examples:
53
+ - AGENTS.md
54
+ - CLAUDE.md
55
+ - .codex/skills/
56
+ - .cursor/rules/
57
+ repair: Regenerate with forge setup or the owning Forge API surface.
58
+ memory_projection:
59
+ examples:
60
+ - docs/sessions/
61
+ - docs/memory/
62
+ - .forge/memory/
63
+ repair: Use the Forge memory projection writer.
64
+ categories:
65
+ - id: forge_core
66
+ mode: checksum-verified
67
+ paths:
68
+ - lib/**
69
+ - bin/**
70
+ - scripts/**
71
+ - skills/**
72
+ ownerSurface: Forge core release or checksum updater
73
+ repairHint: Use the Forge release/update flow; do not hand-edit checksum-protected core files.
74
+ - id: user_protocol
75
+ mode: cli-only
76
+ paths:
77
+ - AGENTS.md
78
+ - CLAUDE.md
79
+ - .cursorrules
80
+ - .mcp.json
81
+ - .forge/config.yaml
82
+ - .forge/config.yml
83
+ - .forge/config.json
84
+ - .forge/protected-paths.yaml
85
+ ownerSurface: forge setup or forge options
86
+ repairHint: Use Forge setup/options commands so harness protocol files stay synchronized.
87
+ - id: generated_artifacts
88
+ mode: ci-blocked
89
+ paths:
90
+ - .claude/commands/**
91
+ - .claude/skills/**
92
+ - .cursor/rules/**
93
+ - .cursor/skills/**
94
+ - .codex/skills/**
95
+ - .github/workflows/**
96
+ - .forge/hooks/**
97
+ - lefthook.yml
98
+ - .forge/extensions/*/manifest.json
99
+ - .github/PLUGIN_TEMPLATE.json
100
+ - plugins/*/plugin.json
101
+ - plugins/*/extension.json
102
+ - plugins/*/manifest.json
103
+ - bun.lock
104
+ - package-lock.json
105
+ - pnpm-lock.yaml
106
+ - yarn.lock
107
+ - requirements.lock
108
+ - poetry.lock
109
+ - Cargo.lock
110
+ - go.sum
111
+ - .forge/extensions.lock
112
+ - docs/sessions/**
113
+ - docs/memory/**
114
+ - .forge/memory/**
115
+ - memory.md
116
+ - MEMORY.md
117
+ - "**/memory.md"
118
+ - "**/MEMORY.md"
119
+ ownerSurface: Forge harness renderer
120
+ repairHint: Regenerate harness artifacts from the canonical Forge contract.
121
+ - id: append_only_logs
122
+ mode: runtime-only
123
+ paths:
124
+ - .forge/*.jsonl
125
+ - .forge/audit.log
126
+ - .forge/agent-log.ndjson
127
+ - .beads/*.jsonl
128
+ - .beads/interactions.jsonl
129
+ ownerSurface: Forge or Beads audit writer
130
+ repairHint: Append through the runtime writer; do not rewrite audit history.
131
+ - id: secrets
132
+ mode: secret-scan-blocked
133
+ paths:
134
+ - .env
135
+ - .env.*
136
+ - "**/.env"
137
+ - "**/.env.*"
138
+ - secrets.json
139
+ - "**/secrets.json"
140
+ - credentials.json
141
+ - "**/credentials.json"
142
+ ownerSurface: secret manager
143
+ repairHint: Move secrets to the configured secret manager or local ignored env file.
144
+ - id: beads_state
145
+ mode: bd-cli-only
146
+ paths:
147
+ - .beads/**
148
+ ownerSurface: bd CLI or Forge issue adapter
149
+ repairHint: Use bd or Forge issue commands instead of editing Beads state files.
150
+ - id: immutable
151
+ mode: tool-owned
152
+ paths:
153
+ - .git/**
154
+ - .hg/**
155
+ - .svn/**
156
+ ownerSurface: VCS tool
157
+ repairHint: Use the owning VCS command instead of editing runtime internals.