@khoavu882/doflow 2.0.0-beta.4 → 2.0.0

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 (497) hide show
  1. package/README.md +12 -11
  2. package/bin/doflow.js +21 -11
  3. package/core/.antigravity-plugin/plugin.json +1 -3
  4. package/core/.claude-plugin/plugin.json +1 -1
  5. package/core/.codex-plugin/plugin.json +1 -1
  6. package/core/.plugin/plugin.json +1 -1
  7. package/core/harnesses/claude/hooks/lib.sh +43 -24
  8. package/core/harnesses/claude/hooks/mcp-tool-guard.sh +7 -17
  9. package/core/harnesses/claude/hooks/permission-audit.sh +3 -0
  10. package/core/harnesses/claude/hooks/post-compact.sh +35 -32
  11. package/core/harnesses/claude/hooks/post-edit-lint.sh +2 -0
  12. package/core/harnesses/claude/hooks/post-shell-observe.sh +48 -0
  13. package/core/harnesses/claude/hooks/post-tool-failure.sh +3 -0
  14. package/core/harnesses/claude/hooks/pre-bash-guard.sh +7 -17
  15. package/core/harnesses/claude/hooks/pre-compact.sh +23 -27
  16. package/core/harnesses/claude/hooks/pre-implement-gate.sh +7 -18
  17. package/core/harnesses/claude/hooks/session-end.sh +23 -10
  18. package/core/harnesses/claude/hooks/session-start.sh +5 -3
  19. package/core/harnesses/claude/hooks/skill-config-audit.sh +3 -0
  20. package/core/harnesses/claude/hooks/stop-check.sh +5 -3
  21. package/core/harnesses/claude/hooks/subagent-audit.sh +5 -5
  22. package/core/harnesses/claude/hooks/user-prompt-submit.sh +5 -3
  23. package/core/harnesses/claude/settings/settings.json +18 -0
  24. package/core/harnesses/claude/statusline/doflow-statusline.sh +1 -0
  25. package/core/harnesses/codex/agents/core-implementer.toml +1 -0
  26. package/core/harnesses/codex/agents/delivery-lead.toml +10 -0
  27. package/core/harnesses/codex/agents/quality-guardian.toml +1 -1
  28. package/core/harnesses/codex/agents/research-writer.toml +1 -1
  29. package/core/harnesses/codex/agents/reviewer.toml +10 -0
  30. package/core/harnesses/codex/agents/spec-analyst.toml +1 -1
  31. package/core/harnesses/codex/agents/system-architect.toml +1 -1
  32. package/core/harnesses/codex/hooks/lib.sh +44 -25
  33. package/core/harnesses/codex/hooks/mcp-tool-guard.sh +7 -15
  34. package/core/harnesses/codex/hooks/post-edit-lint.impl.sh +3 -1
  35. package/core/harnesses/codex/hooks/pre-bash-guard.sh +7 -15
  36. package/core/harnesses/codex/hooks/pre-compact.impl.sh +29 -26
  37. package/core/harnesses/codex/hooks/pre-implement-gate.sh +7 -16
  38. package/core/harnesses/codex/hooks/session-end.impl.sh +23 -10
  39. package/core/harnesses/codex/hooks/session-start.sh +5 -3
  40. package/core/harnesses/codex/hooks/stop-check.sh +6 -5
  41. package/core/harnesses/codex/hooks/subagent-audit.sh +18 -6
  42. package/core/harnesses/codex/hooks/user-prompt-submit.sh +5 -4
  43. package/core/harnesses/copilot/hooks/doflow-lib.sh +93 -0
  44. package/core/harnesses/copilot/hooks/doflow-mcp-tool-guard.sh +9 -0
  45. package/core/harnesses/copilot/hooks/doflow-pre-bash-guard.sh +9 -0
  46. package/core/harnesses/copilot/hooks/doflow-pre-implement-gate.sh +9 -0
  47. package/core/harnesses/copilot/hooks/doflow-session-start.sh +9 -0
  48. package/core/harnesses/copilot/hooks/doflow-stop-check.sh +9 -0
  49. package/core/harnesses/copilot/hooks/doflow-subagent-start.sh +9 -0
  50. package/core/harnesses/copilot/hooks/doflow-subagent-stop.sh +9 -0
  51. package/core/harnesses/copilot/hooks/doflow.json +57 -0
  52. package/core/harnesses/kiro/agents/doflow.json +1 -1
  53. package/core/harnesses/kiro/hooks/lib.sh +26 -6
  54. package/core/harnesses/kiro/hooks/mcp-tool-guard.sh +21 -5
  55. package/core/harnesses/kiro/hooks/pre-bash-guard.sh +21 -5
  56. package/core/harnesses/kiro/hooks/pre-implement-gate.sh +21 -5
  57. package/core/harnesses/kiro/hooks/session-start.sh +12 -5
  58. package/core/harnesses/kiro/hooks/stop-check.sh +22 -30
  59. package/core/harnesses/pi/extensions/doflow-guard.js +167 -0
  60. package/core/harnesses/shared/hooks/ENVELOPE_MIGRATION.md +27 -12
  61. package/core/harnesses/shared/hooks/adapters/antigravity.js +14 -57
  62. package/core/harnesses/shared/hooks/bridge/bridge.sh +277 -0
  63. package/core/harnesses/shared/hooks/bridge/envelope.jq +129 -0
  64. package/core/harnesses/shared/hooks/bridge/observe-model.sh +75 -0
  65. package/core/harnesses/shared/hooks/bridge/respond.sh +70 -0
  66. package/core/harnesses/shared/hooks/policies/blocked-patterns.conf +28 -14
  67. package/core/harnesses/shared/hooks/policies/capture-failure.sh +51 -16
  68. package/core/harnesses/shared/hooks/policies/compact-text.sh +46 -0
  69. package/core/harnesses/shared/hooks/policies/contract.sh +78 -0
  70. package/core/harnesses/shared/hooks/policies/deny-json.sh +35 -9
  71. package/core/harnesses/shared/hooks/policies/emission-rules.sh +37 -0
  72. package/core/harnesses/shared/hooks/policies/emission.jq +209 -0
  73. package/core/harnesses/shared/hooks/policies/emission.sh +383 -0
  74. package/core/harnesses/shared/hooks/policies/identity.sh +177 -0
  75. package/core/harnesses/shared/hooks/policies/lib.sh +65 -40
  76. package/core/harnesses/shared/hooks/policies/mcp-tool-guard.sh +48 -35
  77. package/core/harnesses/shared/hooks/policies/pre-bash-guard.sh +284 -33
  78. package/core/harnesses/shared/hooks/policies/pre-implementation-gate.sh +180 -110
  79. package/core/harnesses/shared/hooks/policies/session-context.sh +66 -7
  80. package/core/harnesses/shared/hooks/policies/stop-check.sh +61 -23
  81. package/core/harnesses/shared/hooks/policies/subagent-audit.sh +39 -6
  82. package/core/harnesses/shared/hooks/policies/summary-store.sh +347 -0
  83. package/core/harnesses/shared/hooks/policies/user-prompt-submit.sh +97 -159
  84. package/core/harnesses/shared/hooks/stream-hook-runner.js +114 -187
  85. package/core/harnesses/shared/locator/doflow-run +2 -3
  86. package/core/registry/advice.json +3 -3
  87. package/core/registry/assets.json +72 -80
  88. package/core/registry/capabilities.json +12 -0
  89. package/core/registry/contracts.json +60 -33
  90. package/core/registry/contribution-points.json +32 -0
  91. package/core/registry/gates.json +32 -0
  92. package/core/registry/guidance-caps.json +40 -0
  93. package/core/registry/harnesses.json +1542 -277
  94. package/core/registry/lifecycle.json +2837 -37
  95. package/core/registry/mcp.json +5 -1
  96. package/core/registry/models.json +7 -1
  97. package/core/registry/package-templates/README.md +19 -0
  98. package/core/registry/package-templates/agent/files/agent.md +9 -0
  99. package/core/registry/package-templates/agent/template.json +4 -0
  100. package/core/registry/package-templates/capability-provider/files/provider.json +9 -0
  101. package/core/registry/package-templates/capability-provider/template.json +11 -0
  102. package/core/registry/package-templates/debate-preset/files/preset.json +26 -0
  103. package/core/registry/package-templates/debate-preset/template.json +4 -0
  104. package/core/registry/package-templates/review-preset/files/preset.json +30 -0
  105. package/core/registry/package-templates/review-preset/template.json +4 -0
  106. package/core/registry/package-templates/skill/files/SKILL.md +8 -0
  107. package/core/registry/package-templates/skill/template.json +4 -0
  108. package/core/registry/package-templates/worker/files/worker.json +92 -0
  109. package/core/registry/package-templates/worker/template.json +11 -0
  110. package/core/registry/packages/doflow/doflow-package.json +15 -0
  111. package/core/registry/packages/doflow/presets/debate-3.json +26 -0
  112. package/core/registry/protocols.json +61 -0
  113. package/core/registry/routes.json +17 -0
  114. package/core/registry/rules.json +431 -0
  115. package/core/registry/settings.json +276 -0
  116. package/core/registry/storage.json +701 -30
  117. package/core/registry/telemetry.json +236 -0
  118. package/core/registry/transcripts.json +142 -0
  119. package/core/registry/verification.json +76 -1
  120. package/core/registry/workflows.json +55 -0
  121. package/core/shared/agent-specs/core-implementer.md +3 -0
  122. package/core/shared/agent-specs/delivery-lead.md +68 -0
  123. package/core/shared/agent-specs/quality-guardian.md +5 -1
  124. package/core/shared/agent-specs/research-writer.md +10 -3
  125. package/core/shared/agent-specs/reviewer.md +53 -0
  126. package/core/shared/agent-specs/spec-analyst.md +5 -6
  127. package/core/shared/agent-specs/system-architect.md +5 -1
  128. package/core/shared/guidance/DOFLOW_CORE.md +1 -5
  129. package/core/shared/guidance/modes/MODE_DeepResearch.md +1 -1
  130. package/core/shared/guidance/modes/MODE_Orchestration.md +4 -3
  131. package/core/shared/guidance/modes/MODE_Task_Management.md +14 -14
  132. package/core/shared/guidance/pointers/codex.md +1 -4
  133. package/core/shared/guidance/references/ARTIFACT_FORMAT.md +30 -16
  134. package/core/shared/guidance/references/ARTIFACT_VOICE.md +3 -2
  135. package/core/shared/guidance/references/CONSTITUTION_BASE.md +17 -15
  136. package/core/shared/guidance/references/DIAGRAM_GUIDE.md +1 -1
  137. package/core/shared/guidance/references/DOFLOW_CHAIN.md +17 -19
  138. package/core/shared/guidance/references/EVIDENCE_LEDGER.md +7 -8
  139. package/core/shared/guidance/references/MODEL_SELECTION.md +5 -3
  140. package/core/shared/guidance/references/ORCHESTRATION.md +1 -2
  141. package/core/shared/guidance/rules/RULES.md +45 -0
  142. package/core/shared/scripts/doflow/bash/do-args.sh +37 -0
  143. package/core/shared/scripts/doflow/bash/do-exec-paths.sh +4 -0
  144. package/core/shared/scripts/doflow/bash/do-git-state.sh +15 -4
  145. package/core/shared/scripts/doflow/bash/do-parallel-check.sh +4 -0
  146. package/core/shared/scripts/doflow/bash/do-paths.sh +40 -2
  147. package/core/shared/scripts/doflow/bash/do-prereqs.sh +2 -1
  148. package/core/shared/scripts/doflow/bash/do-review-package.sh +4 -0
  149. package/core/shared/scripts/doflow/bash/do-task-brief.sh +58 -16
  150. package/core/shared/scripts/doflow/bash/render-audit.sh +26 -2
  151. package/core/shared/scripts/doflow/bash/render-diagrams.sh +1 -0
  152. package/core/shared/scripts/doflow/bash/render-puml.sh +2 -1
  153. package/core/shared/scripts/doflow/bash/validate-artifacts.sh +48 -4
  154. package/core/shared/scripts/doflow/bin/doflow-run +154 -35
  155. package/core/shared/skills/do/SKILL.md +12 -10
  156. package/core/shared/skills/do/references/advice_calls.md +26 -0
  157. package/core/shared/skills/do/references/pm_routing.md +1 -2
  158. package/core/shared/skills/do/references/program_mode.md +31 -0
  159. package/core/shared/skills/do-brainstorm/SKILL.md +20 -74
  160. package/core/shared/skills/do-brainstorm/references/handoff_branches.md +35 -0
  161. package/core/shared/skills/do-brainstorm/references/intent_seed.md +21 -0
  162. package/core/shared/skills/do-brainstorm/references/round_log.md +17 -0
  163. package/core/shared/skills/do-code-review/SKILL.md +41 -144
  164. package/core/shared/skills/do-code-review/content-types/markdown.md +24 -2
  165. package/core/shared/skills/do-code-review/references/tools.md +90 -0
  166. package/core/shared/skills/do-code-review/scripts/doc_quality_checker.py +549 -7
  167. package/core/shared/skills/do-design/SKILL.md +24 -23
  168. package/core/shared/skills/do-diagnose/SKILL.md +14 -4
  169. package/core/shared/skills/do-document/SKILL.md +11 -1
  170. package/core/shared/skills/do-document/references/deep_research.md +1 -2
  171. package/core/shared/skills/do-document/references/embedded-research.md +18 -6
  172. package/core/shared/skills/do-document/references/implementation-flow.md +5 -6
  173. package/core/shared/skills/do-execute-plan/SKILL.md +17 -59
  174. package/core/shared/skills/do-execute-plan/references/handoff_record.md +7 -2
  175. package/core/shared/skills/do-execute-plan/references/parallel_dispatch.md +13 -0
  176. package/core/shared/skills/do-execute-plan/references/readiness_gate.md +28 -1
  177. package/core/shared/skills/do-execute-plan/references/run_position.md +13 -1
  178. package/core/shared/skills/do-execute-plan/references/scaffold.md +17 -9
  179. package/core/shared/skills/do-execute-plan/references/state_checkpoint.md +11 -0
  180. package/core/shared/skills/do-execute-plan/references/task_attempts.md +78 -24
  181. package/core/shared/skills/do-flow/SKILL.md +8 -9
  182. package/core/shared/skills/do-flow/references/task_classes.md +2 -2
  183. package/core/shared/skills/do-git/SKILL.md +4 -0
  184. package/core/shared/skills/do-implement/SKILL.md +7 -9
  185. package/core/shared/skills/do-plan/SKILL.md +29 -19
  186. package/core/shared/skills/do-test/SKILL.md +7 -4
  187. package/core/shared/templates/doflow/constitution-template.md +9 -3
  188. package/core/shared/templates/doflow/data-model-template.md +1 -1
  189. package/core/shared/templates/doflow/design-template.md +113 -16
  190. package/core/shared/templates/doflow/plan-template.md +11 -10
  191. package/core/shared/templates/doflow/question-log-template.md +14 -2
  192. package/core/shared/templates/doflow/requirement-template.md +1 -1
  193. package/core/worker-evidence/antigravity/checks.json +14 -0
  194. package/core/worker-evidence/codex/2026-10-18-cli-check.json +107 -0
  195. package/core/worker-evidence/codex/2026-10-18-live-run-edit.json +73 -0
  196. package/core/worker-evidence/codex/2026-10-18-live-run-read-only.json +62 -0
  197. package/core/worker-evidence/codex/2026-10-24-cli-check.json +126 -0
  198. package/core/worker-evidence/codex/checks.json +38 -0
  199. package/package.json +10 -6
  200. package/src/adapters/antigravity/index.js +226 -113
  201. package/src/adapters/claude/index.js +39 -5
  202. package/src/adapters/codex/agents.js +25 -15
  203. package/src/adapters/codex/hooks.js +40 -5
  204. package/src/adapters/codex/index.js +100 -22
  205. package/src/adapters/codex/native-projection.js +6 -2
  206. package/src/adapters/copilot/index.js +58 -23
  207. package/src/adapters/copy-tree.js +294 -48
  208. package/src/adapters/guidance-manifest.js +71 -0
  209. package/src/adapters/guidance-pointer.js +19 -0
  210. package/src/adapters/hook-commands.js +6 -10
  211. package/src/adapters/index.js +1 -0
  212. package/src/adapters/kiro/index.js +38 -13
  213. package/src/adapters/opencode/index.js +8 -8
  214. package/src/adapters/pi/hooks.js +120 -0
  215. package/src/adapters/pi/index.js +48 -16
  216. package/src/adapters/resolve-source.js +26 -2
  217. package/src/cli/commands/install.js +3 -2
  218. package/src/cli/commands/reconcile.js +53 -9
  219. package/src/cli/commands/remove.js +2 -2
  220. package/src/cli/commands/rollback.js +6 -3
  221. package/src/cli/commands/self-update.js +18 -9
  222. package/src/cli/commands/status.js +21 -2
  223. package/src/cli/commands/ui.js +99 -0
  224. package/src/cli/commands/update.js +3 -2
  225. package/src/cli/index.js +338 -33
  226. package/src/cli/runtime-commands.js +243 -52
  227. package/src/cli/shared.js +0 -2
  228. package/src/helper/git.js +1 -1
  229. package/src/helper/guardrails.js +1 -1
  230. package/src/helper/marker-merge.js +31 -13
  231. package/src/helper/package-ids.js +37 -0
  232. package/src/helper/semver.js +94 -0
  233. package/src/install/backup.js +105 -15
  234. package/src/install/context.js +1 -1
  235. package/src/install/targets.js +31 -16
  236. package/src/lifecycle/coverage.js +74 -0
  237. package/src/lifecycle/hook-step.js +61 -0
  238. package/src/lifecycle/hook-tier.js +160 -0
  239. package/src/lifecycle/index.js +434 -86
  240. package/src/lifecycle/retired-harnesses.js +318 -0
  241. package/src/lifecycle/view.js +35 -15
  242. package/src/registry/index.js +686 -32
  243. package/src/registry/worker-ids.js +45 -0
  244. package/src/release/build-package.js +0 -3
  245. package/src/release/docs-blocks.js +492 -0
  246. package/src/release/preflight.js +425 -0
  247. package/src/release/rehearse.js +401 -0
  248. package/src/release/release-workflow.js +733 -0
  249. package/src/release/sync-plugin-versions.js +43 -7
  250. package/src/runtime/advice/bench-gate.js +25 -0
  251. package/src/runtime/advice/cli.js +59 -16
  252. package/src/runtime/advice/client.js +32 -9
  253. package/src/runtime/advice/config.js +98 -133
  254. package/src/runtime/advice/doctor.js +1 -1
  255. package/src/runtime/advice/elevation.js +97 -0
  256. package/src/runtime/advice/endpoint-guard.js +9 -3
  257. package/src/runtime/advice/mode.js +37 -0
  258. package/src/runtime/advice/record.js +18 -5
  259. package/src/runtime/advice/registry.js +4 -1
  260. package/src/runtime/advice/shadow-config.js +229 -0
  261. package/src/runtime/advice/shadow-dispatcher.js +276 -0
  262. package/src/runtime/brief-rules.js +81 -0
  263. package/src/runtime/brief-tools.js +111 -34
  264. package/src/runtime/candidate.js +514 -0
  265. package/src/runtime/capabilities/executor.js +450 -0
  266. package/src/runtime/capabilities/loopback.js +41 -0
  267. package/src/runtime/capabilities/sanitizer.js +88 -0
  268. package/src/runtime/capability-router.js +135 -3
  269. package/src/runtime/checkouts.js +73 -11
  270. package/src/runtime/claims.js +27 -12
  271. package/src/runtime/cli-result.js +11 -4
  272. package/src/runtime/cli.js +221 -277
  273. package/src/runtime/config-home.js +42 -0
  274. package/src/runtime/context/arbitrate.js +767 -0
  275. package/src/runtime/context/budget.js +203 -0
  276. package/src/runtime/context/compose.js +1367 -0
  277. package/src/runtime/context/delivery-store.js +100 -0
  278. package/src/runtime/context/emission-rules.js +118 -0
  279. package/src/runtime/context/identity.js +227 -0
  280. package/src/runtime/context/mandatory.js +594 -0
  281. package/src/runtime/context/pointer.js +142 -0
  282. package/src/runtime/context/primary-command.js +117 -0
  283. package/src/runtime/context/primary.js +344 -0
  284. package/src/runtime/context/summary-store.js +655 -0
  285. package/src/runtime/context-pack.js +1106 -245
  286. package/src/runtime/decision-register.js +13 -4
  287. package/src/runtime/dispatch/admission.js +392 -0
  288. package/src/runtime/dispatch/attempt-end.js +274 -0
  289. package/src/runtime/dispatch/command.js +628 -0
  290. package/src/runtime/dispatch/controls.js +904 -0
  291. package/src/runtime/dispatch/envelope.js +276 -0
  292. package/src/runtime/dispatch/grants.js +310 -0
  293. package/src/runtime/dispatch/integrate.js +617 -0
  294. package/src/runtime/dispatch/loop.js +1835 -0
  295. package/src/runtime/dispatch/store.js +352 -0
  296. package/src/runtime/dispatch/verify-run.js +201 -0
  297. package/src/runtime/evidence-fields.js +39 -0
  298. package/src/runtime/evidence-ledger.js +41 -7
  299. package/src/runtime/failure/capture.js +3 -1
  300. package/src/runtime/failure/cli.js +25 -9
  301. package/src/runtime/failure/home.js +57 -30
  302. package/src/runtime/failure/store.js +7 -2
  303. package/src/runtime/feature-pointer.js +174 -0
  304. package/src/runtime/feature-resolve.js +13 -2
  305. package/src/runtime/fleet/command.js +77 -0
  306. package/src/runtime/fleet/projects.js +178 -0
  307. package/src/runtime/fleet/tree.js +383 -0
  308. package/src/runtime/freshness.js +77 -10
  309. package/src/runtime/git-memo.js +46 -0
  310. package/src/runtime/guidance/ablation.js +427 -0
  311. package/src/runtime/health.js +565 -17
  312. package/src/runtime/history-compactor.js +13 -3
  313. package/src/runtime/implementation-gate.js +277 -22
  314. package/src/runtime/inventory/coverage.js +1 -1
  315. package/src/runtime/inventory/index.js +1 -1
  316. package/src/runtime/inventory/precedence.js +2 -2
  317. package/src/runtime/inventory/siblings.js +6 -4
  318. package/src/runtime/knowledge/code-corpus.js +277 -0
  319. package/src/runtime/knowledge/code-lexical.js +130 -0
  320. package/src/runtime/knowledge/code-retrieval.js +307 -0
  321. package/src/runtime/knowledge/code-validation.js +106 -0
  322. package/src/runtime/knowledge/gp3-gate.js +74 -0
  323. package/src/runtime/knowledge/graph-adapter.js +288 -0
  324. package/src/runtime/knowledge/graph-fallback.js +394 -0
  325. package/src/runtime/knowledge/hybrid.js +136 -8
  326. package/src/runtime/knowledge/retrieval.js +34 -1
  327. package/src/runtime/knowledge/rtk-compress.js +77 -0
  328. package/src/runtime/knowledge/semble-bridge.py +106 -0
  329. package/src/runtime/knowledge/semble-lifecycle.js +114 -0
  330. package/src/runtime/knowledge/semble-provider.js +365 -0
  331. package/src/runtime/lifecycle/cli.js +16 -6
  332. package/src/runtime/lifecycle/event-store.js +8 -6
  333. package/src/runtime/lifecycle/followup.js +6 -1
  334. package/src/runtime/lifecycle/overview.js +24 -1
  335. package/src/runtime/lifecycle/report-store.js +8 -10
  336. package/src/runtime/lifecycle/retention.js +95 -31
  337. package/src/runtime/lifecycle/root.js +9 -1
  338. package/src/runtime/lifecycle/status.js +34 -17
  339. package/src/runtime/lifecycle/store-upkeep.js +56 -7
  340. package/src/runtime/mask.js +134 -7
  341. package/src/runtime/mcp-consultations.js +40 -6
  342. package/src/runtime/model-router.js +79 -7
  343. package/src/runtime/models/catalogue.js +191 -0
  344. package/src/runtime/models/command.js +153 -0
  345. package/src/runtime/off-words.js +12 -0
  346. package/src/runtime/outcome.js +3 -3
  347. package/src/runtime/packages/command.js +1009 -0
  348. package/src/runtime/packages/contributions.js +116 -0
  349. package/src/runtime/packages/digest.js +132 -0
  350. package/src/runtime/packages/fetch.js +182 -0
  351. package/src/runtime/packages/grants.js +192 -0
  352. package/src/runtime/packages/index-file.js +134 -0
  353. package/src/runtime/packages/instruction.js +90 -0
  354. package/src/runtime/packages/manifest.js +331 -0
  355. package/src/runtime/packages/points.js +477 -0
  356. package/src/runtime/packages/programs.js +216 -0
  357. package/src/runtime/packages/scaffold.js +277 -0
  358. package/src/runtime/packages/source.js +90 -0
  359. package/src/runtime/packages/state.js +164 -0
  360. package/src/runtime/packages/store.js +449 -0
  361. package/src/runtime/packages/tar.js +106 -0
  362. package/src/runtime/packages/view.js +406 -0
  363. package/src/runtime/plan-check.js +59 -0
  364. package/src/runtime/plan-content.js +324 -0
  365. package/src/runtime/policy-init.js +118 -0
  366. package/src/runtime/profiles/doctor.js +96 -0
  367. package/src/runtime/profiles/resolve.js +244 -0
  368. package/src/runtime/profiles/rollback.js +254 -0
  369. package/src/runtime/profiles/sampler.js +41 -0
  370. package/src/runtime/readiness-record.js +16 -11
  371. package/src/runtime/readiness.js +127 -16
  372. package/src/runtime/research-request.js +50 -25
  373. package/src/runtime/retrieval-plan.js +402 -73
  374. package/src/runtime/retrieval-record.js +293 -0
  375. package/src/runtime/review/command.js +246 -0
  376. package/src/runtime/review/dominance.js +68 -0
  377. package/src/runtime/review/findings.js +434 -0
  378. package/src/runtime/review/identity.js +255 -0
  379. package/src/runtime/review/protocol-command.js +109 -0
  380. package/src/runtime/review/protocols.js +405 -0
  381. package/src/runtime/review/resolve-protocol.js +302 -0
  382. package/src/runtime/review/start.js +530 -0
  383. package/src/runtime/roadmap/facts.js +479 -0
  384. package/src/runtime/roadmap/gates.js +270 -0
  385. package/src/runtime/roadmap/loop.js +1636 -0
  386. package/src/runtime/roadmap/merge.js +381 -0
  387. package/src/runtime/roadmap/rows.js +1113 -0
  388. package/src/runtime/roadmap/seed.js +951 -0
  389. package/src/runtime/rules-report.js +336 -0
  390. package/src/runtime/scaffold/artifacts.js +63 -9
  391. package/src/runtime/scaffold/generate.js +21 -9
  392. package/src/runtime/settings/autopilot.js +106 -0
  393. package/src/runtime/settings/cli.js +280 -0
  394. package/src/runtime/settings/config-write.js +314 -0
  395. package/src/runtime/settings/files.js +271 -0
  396. package/src/runtime/settings/legacy.js +154 -0
  397. package/src/runtime/settings/lexical.js +56 -0
  398. package/src/runtime/settings/prepared-run.js +269 -0
  399. package/src/runtime/settings/project-layers.js +118 -0
  400. package/src/runtime/settings/refs.js +288 -0
  401. package/src/runtime/settings/registry.js +553 -0
  402. package/src/runtime/settings/resolve.js +713 -0
  403. package/src/runtime/settings/shared.js +37 -0
  404. package/src/runtime/settings/worker-billing.js +107 -0
  405. package/src/runtime/settings/write.js +269 -0
  406. package/src/runtime/slot-command.js +78 -0
  407. package/src/runtime/slots.js +671 -0
  408. package/src/runtime/source-version.js +290 -0
  409. package/src/runtime/state-root.js +217 -0
  410. package/src/runtime/storage/cli.js +12 -5
  411. package/src/runtime/storage/engine.js +9 -2
  412. package/src/runtime/storage/registry.js +14 -1
  413. package/src/runtime/storage/roots.js +66 -16
  414. package/src/runtime/storage/rules.js +82 -10
  415. package/src/runtime/storage/upkeep.js +10 -2
  416. package/src/runtime/storage/work-status.js +245 -26
  417. package/src/runtime/task-attempts.js +589 -69
  418. package/src/runtime/task-classifier.js +47 -11
  419. package/src/runtime/task-graph.js +373 -0
  420. package/src/runtime/task-run.js +778 -0
  421. package/src/runtime/task-scope.js +202 -56
  422. package/src/runtime/task-sources.js +147 -0
  423. package/src/runtime/task-state.js +440 -65
  424. package/src/runtime/team/admission.js +301 -0
  425. package/src/runtime/team/envelope.js +324 -0
  426. package/src/runtime/team/review-guard.js +156 -0
  427. package/src/runtime/trace/analyze.js +427 -0
  428. package/src/runtime/trace/baseline.js +770 -0
  429. package/src/runtime/trace/ledger.js +63 -140
  430. package/src/runtime/trace/otlp-export.js +568 -0
  431. package/src/runtime/trace/otlp-map.js +481 -0
  432. package/src/runtime/trace/spans.js +745 -0
  433. package/src/runtime/trace/telemetry.js +225 -0
  434. package/src/runtime/trace/views.js +1 -0
  435. package/src/runtime/transcripts/command.js +98 -0
  436. package/src/runtime/transcripts/cursor.js +326 -0
  437. package/src/runtime/transcripts/read.js +126 -0
  438. package/src/runtime/transcripts/readers/claude-jsonl.js +74 -0
  439. package/src/runtime/transcripts/readers/codex-rollout.js +70 -0
  440. package/src/runtime/transcripts/readers/copilot-events.js +90 -0
  441. package/src/runtime/transcripts/readers/kiro-jsonl.js +77 -0
  442. package/src/runtime/transcripts/readers/pi-jsonl.js +59 -0
  443. package/src/runtime/transcripts/registry.js +161 -0
  444. package/src/runtime/transcripts/stats.js +161 -0
  445. package/src/runtime/verification/check-key.js +628 -0
  446. package/src/runtime/verification/contract-runner.js +546 -11
  447. package/src/runtime/verification/engine.js +499 -9
  448. package/src/runtime/verification/impact.js +617 -0
  449. package/src/runtime/verification/inflight.js +205 -0
  450. package/src/runtime/verification/registry.js +176 -0
  451. package/src/runtime/verification/reuse.js +184 -0
  452. package/src/runtime/verification/telemetry-emit.js +254 -0
  453. package/src/runtime/verification/test-selection.js +67 -7
  454. package/src/runtime/worker/active.js +90 -0
  455. package/src/runtime/worker/cancel.js +222 -0
  456. package/src/runtime/worker/catalogue.js +122 -0
  457. package/src/runtime/worker/command.js +677 -0
  458. package/src/runtime/worker/evidence.js +288 -0
  459. package/src/runtime/worker/launch.js +288 -0
  460. package/src/runtime/worker/models.js +137 -0
  461. package/src/runtime/worker/parsers.js +218 -0
  462. package/src/runtime/worker/probes/index.js +706 -0
  463. package/src/runtime/worker/process-tree.js +415 -0
  464. package/src/runtime/worker/quota.js +43 -0
  465. package/src/runtime/worker/readiness.js +713 -0
  466. package/src/runtime/worker/run-store.js +166 -0
  467. package/src/runtime/worker/supervisor.js +541 -0
  468. package/src/runtime/worker/worktree-check.js +252 -0
  469. package/src/runtime/workflow-engine.js +5 -1
  470. package/src/runtime/workflow-orchestrator.js +578 -63
  471. package/src/runtime/worktree.js +149 -22
  472. package/src/state/index.js +1 -1
  473. package/src/state/lockfile.js +64 -10
  474. package/src/state/run-lock.js +1 -1
  475. package/types/node-commonjs.d.ts +106 -7
  476. package/core/.antigravity-plugin/hooks.json +0 -39
  477. package/core/harnesses/gemini/hooks/hooks.json +0 -77
  478. package/core/harnesses/gemini/hooks/lib.sh +0 -302
  479. package/core/harnesses/gemini/hooks/mcp-tool-guard.sh +0 -21
  480. package/core/harnesses/gemini/hooks/post-edit-lint.sh +0 -39
  481. package/core/harnesses/gemini/hooks/pre-bash-guard.sh +0 -21
  482. package/core/harnesses/gemini/hooks/pre-compact.sh +0 -38
  483. package/core/harnesses/gemini/hooks/pre-implement-gate.sh +0 -22
  484. package/core/harnesses/gemini/hooks/session-end.impl.sh +0 -89
  485. package/core/harnesses/gemini/hooks/session-end.sh +0 -5
  486. package/core/harnesses/gemini/hooks/session-start.sh +0 -5
  487. package/core/harnesses/gemini/settings/adapter-defaults.json +0 -4
  488. package/core/harnesses/shared/hooks/adapters/arg-fields.js +0 -19
  489. package/core/harnesses/shared/hooks/adapters/gemini.js +0 -114
  490. package/core/harnesses/shared/hooks/hooks.json +0 -47
  491. package/core/shared/guidance/FLAGS.md +0 -25
  492. package/core/shared/guidance/rules/RULE_01_SAFETY.md +0 -25
  493. package/core/shared/guidance/rules/RULE_02_WORKFLOW.md +0 -23
  494. package/core/shared/guidance/rules/RULE_03_QUALITY.md +0 -14
  495. package/core/shared/guidance/rules/RULE_04_QUESTIONS.md +0 -46
  496. package/src/adapters/gemini/hooks.js +0 -210
  497. package/src/adapters/gemini/index.js +0 -390
@@ -1,29 +1,28 @@
1
1
  #!/usr/bin/env bash
2
+ case "${OSTYPE:-}" in msys*|cygwin*|win32*) if command -v jq >/dev/null 2>&1; then jq() { command jq -b "$@"; }; fi ;; esac # native jq.exe ends lines with CRLF unless -b
3
+ _DOFLOW_SRC=${0//\\//}; case $_DOFLOW_SRC in */*) _DOFLOW_POLDIR=${_DOFLOW_SRC%/*} ;; *) _DOFLOW_POLDIR=. ;; esac
2
4
  # pre-bash-guard.sh — Canonical Policy Library: PreToolUse(shell-command) hook
3
5
  #
4
6
  # Intercepts every shell-command tool call and blocks dangerous commands by
5
7
  # matching against POSIX ERE patterns in blocked-patterns.conf (grep -E).
6
8
  #
7
- # Multi-session safe: stateless — reads only the conf file, no shared state.
9
+ # Multi-session safe: reads the conf and canonical worker/cwd directories only.
10
+ # Marked reset/clean rules and an exact DROP DATABASE launch snapshot may exempt a dispatch worker;
11
+ # every failed scope/command check retains the ordinary pattern verdict.
8
12
  # Must complete in <50ms.
9
13
  #
10
14
  # Canonical Policy Script Contract (design.md §4):
11
15
  # env DOFLOW_PROJECT_DIR, DOFLOW_AGENT (both optional; not required to
12
16
  # evaluate this policy)
13
- # stdin a PreToolUse-shaped JSON payload; tool name is read from the union
14
- # of field names harnesses use, and matched against the union of
15
- # known shell-command tool names (Bash/bash — Claude/Codex;
16
- # run_shell_command — Gemini; run_command — the generic name
17
- # stream-hook-runner.js's own COMMAND_TOOL_PATTERN already
18
- # recognized), since a native front door (Claude/Codex/Kiro) execs
19
- # this script directly with no payload translation of its own.
20
- # exit 0 = allow, non-zero = deny with the reason on stderr.
17
+ # stdin a native payload with envelope v1 under doflow_event; only the
18
+ # envelope's operation, tool and command and native root cwd are used.
19
+ # exit exit 2 + doflow_decide deny = deny; other faults per IC-011.
21
20
  #
22
21
  # Reconciliation note (022-normalize-hooks, Phase A / D1): this also absorbs
23
22
  # stream-hook-runner.js's inline DESTRUCTIVE_COMMAND_PATTERN
24
23
  # (`\brm\s+-rf\s+[/~]`, since narrowed to the recursive-rm-of-catastrophic-target
25
- # rule below), which was the only pre-bash-guard protection Gemini
26
- # and Antigravity sessions routed through that runner actually had — it
24
+ # rule below), which was the only pre-bash-guard protection
25
+ # Antigravity sessions routed through that runner actually had — it
27
26
  # duplicated, rather than delegated to, this policy's fuller
28
27
  # blocked-patterns.conf coverage (git force-push, git reset --hard, git clean
29
28
  # -fd, SQL DROP/DELETE/TRUNCATE, curl|wget-pipe-to-shell, chmod -R 777, dd
@@ -32,40 +31,171 @@
32
31
  # only the hardcoded regex before this change does not lose even that
33
32
  # minimum floor of protection; once blocked-patterns.conf is present (the
34
33
  # normal case), the full config-driven pattern list applies as it already
35
- # does for claude/gemini/codex today, which is a real, intended widening of
36
- # coverage for Gemini/Antigravity once B.5 wires this policy for them (see
34
+ # does for claude/codex today, which is a real, intended widening of
35
+ # coverage for Antigravity once B.5 wires this policy for them (see
37
36
  # design.md R2/R3), not a silent side effect.
38
37
 
39
38
  set -uo pipefail
40
39
 
41
- command -v jq >/dev/null 2>&1 || exit 0 # no jq -> cannot evaluate -> allow
42
-
43
40
  INPUT=$(cat)
41
+ if [ -f "$_DOFLOW_POLDIR/contract.sh" ]; then
42
+ . "$_DOFLOW_POLDIR/contract.sh"
43
+ else
44
+ doflow_decision_init() { :; }
45
+ doflow_decide() { :; }
46
+ doflow_read_envelope() { DF_ENV_CLASS=missing; DF_ENV_CODE=contract-missing; }
47
+ ( . "$_DOFLOW_POLDIR/capture-failure.sh"; doflow_capture_failure pre-bash-guard contract-missing ) >/dev/null 2>&1 || true
48
+ if [[ "${DOFLOW_AGENT:-}" =~ ^[a-z]+$ ]]; then
49
+ printf '[pre-bash-guard] DoFlow hooks out of step; run: doflow update -t %s\n' "$DOFLOW_AGENT" >&2
50
+ else
51
+ printf '[pre-bash-guard] DoFlow hooks out of step; run: doflow update\n' >&2
52
+ fi
53
+ doflow_decide deny contract-missing
54
+ exit 2
55
+ fi
56
+ doflow_decision_init pre-bash-guard 1
57
+ command -v jq >/dev/null 2>&1 || {
58
+ doflow_decide error dependency-missing:jq
59
+ ( . "$_DOFLOW_POLDIR/capture-failure.sh"; doflow_capture_failure pre-bash-guard dependency-missing:jq ) >/dev/null 2>&1 || true
60
+ exit 0
61
+ }
62
+ DF_ENV_CLASS=missing DF_ENV_CODE=envelope-missing
63
+ doflow_read_envelope || true
44
64
 
45
65
  TOOL_NAME=""
46
- for field in '.tool_name' '.tool' '.toolName' '.name'; do
47
- TOOL_NAME=$(printf '%s' "$INPUT" | jq -r "${field} // empty" 2>/dev/null)
48
- [ -n "$TOOL_NAME" ] && break
49
- done
50
-
51
- # Fast exit for non-shell-command tool events (union of every known
52
- # shell-command tool name across harnesses, case-insensitive).
53
- case "$TOOL_NAME" in
54
- Bash|bash|run_shell_command|run_command) ;;
55
- *) exit 0 ;;
56
- esac
57
-
58
- COMMAND=$(printf '%s' "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
66
+ COMMAND=""
67
+ if [ "$DF_ENV_CLASS" = v1 ]; then
68
+ [ "$DF_ENV_OP" = command ] || exit 0
69
+ TOOL_NAME=$DF_ENV_TOOL
70
+ COMMAND=$DF_ENV_COMMAND
71
+ elif [ "$DF_ENV_CLASS" = unsupported ]; then
72
+ doflow_decide unsupported envelope-version
73
+ ( . "$_DOFLOW_POLDIR/capture-failure.sh"; doflow_capture_failure pre-bash-guard unsupported:envelope-version ) >/dev/null 2>&1 || true
74
+ exit 0
75
+ else
76
+ if [ "${DF_ENV_CODE:-envelope-missing}" != contract-missing ]; then
77
+ ( . "$_DOFLOW_POLDIR/capture-failure.sh"; doflow_capture_failure pre-bash-guard envelope-missing ) >/dev/null 2>&1 || true
78
+ fi
79
+ if [[ "${DOFLOW_AGENT:-}" =~ ^[a-z]+$ ]]; then printf '[pre-bash-guard] DoFlow hooks out of step; run: doflow update -t %s\n' "$DOFLOW_AGENT" >&2; else printf '[pre-bash-guard] DoFlow hooks out of step; run: doflow update\n' >&2; fi
80
+ doflow_decide deny "${DF_ENV_CODE:-envelope-missing}"
81
+ exit 2
82
+ fi
59
83
 
60
84
  # Nothing to check if command is empty
61
85
  [ -z "$COMMAND" ] && exit 0
62
86
 
63
- PATTERNS_FILE="$(dirname "$0")/blocked-patterns.conf"
87
+ PATTERNS_FILE="$_DOFLOW_POLDIR/blocked-patterns.conf"
64
88
 
65
89
  # ASCII-only patterns: the C locale keeps bash's substring/pattern operations
66
90
  # byte-wise (much faster than multibyte-aware in a UTF-8 locale).
67
91
  export LC_ALL=C
68
92
 
93
+ # Shape checks accept one terminal line ending, never an additional command.
94
+ # Keep COMMAND raw for all ordinary pattern verdicts.
95
+ SHAPE_COMMAND=$COMMAND
96
+ case $SHAPE_COMMAND in
97
+ *$'\r\n') SHAPE_COMMAND=${SHAPE_COMMAND%$'\r\n'} ;;
98
+ *$'\n') SHAPE_COMMAND=${SHAPE_COMMAND%$'\n'} ;;
99
+ esac
100
+
101
+ # Lazy and cached: shape checks precede the shared scope's only two subshells
102
+ # (cd/pwd builtins), then one git probe for reset/clean only.
103
+ # Never infer worker identity from command text.
104
+ _WORKER_EXEMPT=
105
+ _worker_exempt() {
106
+ case $_WORKER_EXEMPT in allow) return 0 ;; deny) return 1 ;; esac
107
+ _WORKER_EXEMPT=deny
108
+ local reset_re='^[[:blank:]]*git[[:blank:]]+reset([[:blank:]]+(--hard|-q|--quiet))+([[:blank:]]+[A-Za-z0-9_@][A-Za-z0-9_./^~@{}-]*)?[[:blank:]]*$'
109
+ local clean_re='^[[:blank:]]*git[[:blank:]]+clean([[:blank:]]+(-[dfqxX]+|--force|--quiet))+[[:blank:]]*$'
110
+ local forces command=$SHAPE_COMMAND
111
+ if [[ $command =~ $reset_re ]]; then
112
+ case " $command " in *[[:blank:]]--hard[[:blank:]]*) ;; *) return 1 ;; esac
113
+ elif [[ $command =~ $clean_re ]]; then
114
+ forces=${command//[!f]/}
115
+ [ "${#forces}" -eq 1 ] || return 1
116
+ else
117
+ return 1
118
+ fi
119
+ _worker_scope || return 1
120
+ local project=${_WORKER_DIR%/.doflow/state/dispatch-worktrees/*}
121
+ local name=${_WORKER_DIR##*/} info git_dir top suffix
122
+ [ -d "$project/.git" ] || return 1
123
+ # No inherited GIT_* / config environment can redirect this read-only probe.
124
+ info=$(env -i PATH="$PATH" HOME="${HOME:-}" git -C "$_WORKER_CWD" rev-parse --path-format=absolute --git-dir --show-toplevel 2>/dev/null) || return 1
125
+ git_dir=${info%%$'\n'*}; top=${info#*$'\n'}
126
+ [ "$top" = "$_WORKER_DIR" ] || return 1
127
+ case $git_dir in "$project/.git/worktrees/$name"*) ;; *) return 1 ;; esac
128
+ suffix=${git_dir#"$project/.git/worktrees/$name"}
129
+ case $suffix in *[!0-9]*) return 1 ;; esac
130
+ _WORKER_EXEMPT=allow
131
+ return 0
132
+ }
133
+
134
+ # Both exemptions use exactly the same worker, dispatch-path, cwd and GIT_* checks.
135
+ _WORKER_SCOPE=
136
+ _worker_scope() {
137
+ case $_WORKER_SCOPE in allow) return 0 ;; deny) return 1 ;; esac
138
+ _WORKER_SCOPE=deny
139
+ local worktree cwd config_key
140
+ [ "${DOFLOW_SESSION_ROLE:-}" = worker ] || return 1
141
+ [ -z "${GIT_DIR+x}${GIT_WORK_TREE+x}${GIT_INDEX_FILE+x}${GIT_COMMON_DIR+x}${GIT_CONFIG_PARAMETERS+x}${GIT_CONFIG_COUNT+x}" ] || return 1
142
+ for config_key in ${!GIT_CONFIG_KEY_@}; do return 1; done
143
+ case ${DOFLOW_WORKTREE:-} in /*) ;; *) return 1 ;; esac
144
+ [ -d "$DOFLOW_WORKTREE" ] || return 1
145
+ # A sentinel preserves path-ending newlines across command substitution.
146
+ worktree=$(CDPATH= cd -P -- "$DOFLOW_WORKTREE" 2>/dev/null && pwd -P && printf '.') || return 1
147
+ worktree=${worktree%.}; worktree=${worktree%$'\n'}
148
+ local dispatch_re='/\.doflow/state/dispatch-worktrees/d-[0-9a-f]{12}$'
149
+ [[ $worktree =~ $dispatch_re ]] || return 1
150
+ [ -n "${DF_ENV_CWD:-}" ] || return 1
151
+ cwd=$(CDPATH= cd -P -- "$DF_ENV_CWD" 2>/dev/null && pwd -P && printf '.') || return 1
152
+ cwd=${cwd%.}; cwd=${cwd%$'\n'}
153
+ case $cwd in "$worktree"|"$worktree"/*) ;; *) return 1 ;; esac
154
+ _WORKER_DIR=$worktree _WORKER_CWD=$cwd
155
+ _WORKER_SCOPE=allow
156
+ return 0
157
+ }
158
+
159
+ # 112: no settings reads here. Re-validate only the launcher's snapshot, then
160
+ # recognise one full bare client invocation and one statement. No shell eval,
161
+ # substitutions, variables, wrappers, redirects, additional args or statements.
162
+ _worker_dropdb_exempt() {
163
+ local list=${DOFLOW_GUARD_DROP_DATABASES:-} list_re='^[a-z][a-z0-9_]{0,62}( [a-z][a-z0-9_]{0,62})*$'
164
+ [ "${#list}" -le 1024 ] && [[ $list =~ $list_re ]] || return 1
165
+ local names=() name rest client quote statement id_re sql_re command=$SHAPE_COMMAND
166
+ IFS=' ' read -r -a names <<< "$list"
167
+ [ "${#names[@]}" -le 32 ] || return 1
168
+ local psql_re='^[[:blank:]]*psql([[:blank:]]+(-[hpUd][[:blank:]]+[A-Za-z0-9_.:-]+|--(host|port|username|dbname)=[A-Za-z0-9_.:-]+|-w))*[[:blank:]]+-c[[:blank:]]+'
169
+ local mysql_re='^[[:blank:]]*mysql([[:blank:]]+(-[hPu][[:blank:]]+[A-Za-z0-9_.:-]+|--(host|port|user)=[A-Za-z0-9_.:-]+))*[[:blank:]]+-e[[:blank:]]+'
170
+ if [[ $command =~ $psql_re ]]; then client=psql
171
+ elif [[ $command =~ $mysql_re ]]; then client=mysql
172
+ else return 1
173
+ fi
174
+ rest=${command:${#BASH_REMATCH[0]}}
175
+ local single_re="^'([^']*)'[[:blank:]]*$" double_re='^"([^"]*)"[[:blank:]]*$'
176
+ if [[ $rest =~ $single_re ]]; then quote=single
177
+ elif [[ $rest =~ $double_re ]]; then quote=double
178
+ else return 1
179
+ fi
180
+ statement=${BASH_REMATCH[1]}
181
+ id_re='[a-z][a-z0-9_]*'
182
+ if [ "$quote" = single ]; then
183
+ if [ "$client" = psql ]; then id_re='([a-z][a-z0-9_]*|"[a-z][a-z0-9_]*")'
184
+ else id_re='([a-z][a-z0-9_]*|`[a-z][a-z0-9_]*`)'
185
+ fi
186
+ fi
187
+ sql_re="^[[:blank:]]*[Dd][Rr][Oo][Pp][[:blank:]]+[Dd][Aa][Tt][Aa][Bb][Aa][Ss][Ee][[:blank:]]+([Ii][Ff][[:blank:]]+[Ee][Xx][Ii][Ss][Tt][Ss][[:blank:]]+)?($id_re)[[:blank:]]*;?[[:blank:]]*$"
188
+ [[ $statement =~ $sql_re ]] || return 1
189
+ name=${BASH_REMATCH[2]}
190
+ case $name in \"*\"|\`*\`) name=${name#?}; name=${name%?} ;; esac
191
+ local listed found=false
192
+ for listed in "${names[@]}"; do
193
+ if [ "$name" = "$listed" ]; then found=true; break; fi
194
+ done
195
+ [ "$found" = true ] || return 1
196
+ _worker_scope
197
+ }
198
+
69
199
  # ── Quoted text, comments and heredoc bodies are not commands ────────────────
70
200
  # scrub_quotes <text> -> sets SCRUBBED. Anchored shell-command patterns must
71
201
  # not fire on text that is merely data (a commit message, an echo, a comment,
@@ -143,7 +273,7 @@ scrub_quotes() {
143
273
  *) SCRUBBED=$text; return ;;
144
274
  esac
145
275
  case $text in
146
- *rm[[:space:]]*|*git[[:space:]]*|*curl[[:space:]]*|*wget[[:space:]]*|*chmod[[:space:]]*|*dd[[:space:]]*|*find[[:space:]]*|*eval*|*sh[[:space:]]*) ;;
276
+ *rm[[:space:]]*|*git[[:space:]]*|*curl[[:space:]]*|*wget[[:space:]]*|*chmod[[:space:]]*|*dd[[:space:]]*|*find[[:space:]]*|*eval*|*sh[[:space:]]*|*echo[[:space:]]*|*printf[[:space:]]*|*cat[[:space:]]*|*tee[[:space:]]*|*mkdir[[:space:]]*|*cd[[:space:]]*|*true[[:space:]]*|*:[[:space:]]*|*gh[[:space:]]*) ;;
147
277
  *) SCRUBBED=$text; return ;;
148
278
  esac
149
279
  if [ "$SCRUB_DEPTH" -ge 8 ]; then SCRUBBED=$text; return; fi
@@ -248,12 +378,77 @@ scrub_quotes() {
248
378
  scrub_quotes "$COMMAND"
249
379
  SHELL_TEXT=$SCRUBBED
250
380
 
381
+ # Positive SQL text-only allow-list, ALWAYS on raw COMMAND, never SHELL_TEXT.
382
+ # Whole-command matches permit only commit messages, echo/printf literals,
383
+ # cat with a single-quoted heredoc, and gh pr/issue create/comment/edit bodies.
384
+ # Double quotes forbid $, backticks and backslashes; file paths have no dot-led
385
+ # segment. Heredoc delimiters are single-quoted identifiers, close exactly once
386
+ # on the final line, and allow one trailing newline. The sole substitution is
387
+ # the exact Claude commit $(cat <<'WORD' ... WORD) idiom. No eval or shell parser:
388
+ # every non-match keeps the original raw SQL verdict, including malformed input.
389
+ _text_only_command() {
390
+ local text=${COMMAND%$'\n'} b='[[:blank:]]' single="'[^']*'" literal path git gh args re header body word line closed=false
391
+ literal="($single|\"[^\"\$\`\\\\]*\")"
392
+ path='/?[A-Za-z0-9_-][A-Za-z0-9_.-]*(/[A-Za-z0-9_-][A-Za-z0-9_.-]*)*'
393
+ git="git${b}+commit(${b}+(-a|-q|--no-verify))*"
394
+ args="(${b}+([A-Za-z0-9_./:=,@%+-]+|$literal))*"
395
+ gh="gh${b}+(pr|issue)${b}+(create|comment|edit)$args"
396
+ re="^${b}*$git(${b}+-m${b}+$literal(${b}+(-a|-q|--no-verify))*)+${b}*$"
397
+ [[ $text =~ $re ]] && return 0
398
+ re="^${b}*(echo|printf)${b}+$literal(${b}*>>?${b}*$path)?${b}*$"
399
+ [[ $text =~ $re ]] && return 0
400
+ re="^${b}*$gh${b}+--body${b}+$single$args${b}*$"
401
+ [[ $text =~ $re ]] && return 0
402
+
403
+ # Split only the first line. The body is inert only if its first delimiter
404
+ # occurrence is also its last line; otherwise a hidden second command runs.
405
+ case $text in *$'\n'*) ;; *) return 1 ;; esac
406
+ header=${text%%$'\n'*}; body=${text#*$'\n'}
407
+ local hd="<<'([A-Za-z_][A-Za-z0-9_]*)'" cat_start='"\$\(cat' cat_end=$'\n)"'
408
+ local redir=">>?${b}*$path" tee_flag="(-a|--append)"
409
+ local re_git="^${b}*($git${b}+-F${b}+-${b}+|$gh${b}+--body-file${b}+-${b}+)${hd}${b}*$"
410
+ local re_cat_before="^${b}*cat(${b}+${redir})?${b}+${hd}${b}*$"
411
+ local re_cat_after="^${b}*cat${b}+${hd}(${b}*${redir})?${b}*$"
412
+ local re_tee_before="^${b}*tee(${b}+${tee_flag})?${b}+${path}${b}+${hd}${b}*$"
413
+ local re_tee_after="^${b}*tee(${b}+${tee_flag})?${b}+${hd}${b}+(${tee_flag}${b}+)?${path}${b}*$"
414
+ if [[ $header =~ $re_git ]] || [[ $header =~ $re_cat_before ]] || [[ $header =~ $re_cat_after ]] || [[ $header =~ $re_tee_before ]] || [[ $header =~ $re_tee_after ]]; then
415
+ # Match the delimiter separately so prefix capture groups cannot change its index.
416
+ [[ $header =~ $hd ]] || return 1
417
+ word=${BASH_REMATCH[1]}
418
+ else
419
+ re="^${b}*$git${b}+-m${b}+$cat_start${b}+${hd}${b}*$"
420
+ [[ $header =~ $re ]] || return 1
421
+ [[ $header =~ $hd ]] || return 1
422
+ word=${BASH_REMATCH[1]}
423
+ [[ $body == *"$cat_end" ]] || return 1
424
+ body=${body%"$cat_end"}
425
+ fi
426
+ while IFS= read -r line; do
427
+ [ "$closed" = false ] || return 1
428
+ [ "$line" != "$word" ] || closed=true
429
+ done <<< "$body"
430
+ [ "$closed" = true ]
431
+ }
432
+ DATA_ONLY=false
433
+ _text_only_command && DATA_ONLY=true
434
+
435
+ # Project-specific unanchored patterns keep their verdicts too: only these
436
+ # three shipped SQL families participate in the text-only exception.
437
+ _sql_pattern() {
438
+ case $1 in
439
+ 'DROP[[:space:]]+(TABLE|DATABASE|SCHEMA)[[:space:]]'|\
440
+ 'DELETE[[:space:]]+FROM[[:space:]]+[[:alnum:]_]+[[:space:]]*;'|\
441
+ 'TRUNCATE[[:space:]]+TABLE') return 0 ;;
442
+ esac
443
+ return 1
444
+ }
445
+
251
446
  # Hardcoded floor, used only when blocked-patterns.conf is missing: recursive
252
447
  # rm (any flag spelling, flag before or after the target) of a catastrophic
253
448
  # target — the same rule as the rm lines in blocked-patterns.conf. Subpaths
254
449
  # such as /tmp/x are not blocked.
255
450
  _CMDPOS='(^|[;&|(`])[[:space:]]*'
256
- _WRAP='((sudo([[:space:]]+(-[ugChprtUDR][[:space:]]+[^-[:space:];&|][^[:space:];&|]*|--(user|group|host|prompt|role|type|chdir)[[:space:]]+[^-[:space:];&|][^[:space:];&|]*|-[^[:space:];&|]*|[A-Za-z_][A-Za-z0-9_]*=[^[:space:];&|]*))*|xargs([[:space:]]+(-[nILPsdEa][[:space:]]+[^-[:space:];&|][^[:space:];&|]*|-[^[:space:];&|]*|[A-Za-z_][A-Za-z0-9_]*=[^[:space:];&|]*))*|env([[:space:]]+(-[uCS][[:space:]]+[^-[:space:];&|][^[:space:];&|]*|-[^[:space:];&|]*|[A-Za-z_][A-Za-z0-9_]*=[^[:space:];&|]*))*|(command|time|nohup|exec|eval|then|do|else)([[:space:]]+(-[^[:space:];&|]*|[A-Za-z_][A-Za-z0-9_]*=[^[:space:];&|]*))*)[[:space:]]+)*'
451
+ _WRAP='((sudo([[:space:]]+(-[ugChprtUDR][[:space:]]+[^-[:space:];&|][^[:space:];&|]*|--(user|group|host|prompt|role|type|chdir)[[:space:]]+[^-[:space:];&|][^[:space:];&|]*|-[^[:space:];&|]*|[A-Za-z_][A-Za-z0-9_]*=[^[:space:];&|]*))*|xargs([[:space:]]+(-[nILPsdEa][[:space:]]+[^-[:space:];&|][^[:space:];&|]*|-[^[:space:];&|]*|[A-Za-z_][A-Za-z0-9_]*=[^[:space:];&|]*))*|env([[:space:]]+(-[uCS][[:space:]]+[^-[:space:];&|][^[:space:];&|]*|-[^[:space:];&|]*|[A-Za-z_][A-Za-z0-9_]*=[^[:space:];&|]*))*|[A-Za-z_][A-Za-z0-9_]*=[^[:space:];&|]*|(command|time|nohup|exec|eval|then|do|else)([[:space:]]+(-[^[:space:];&|]*|[A-Za-z_][A-Za-z0-9_]*=[^[:space:];&|]*))*)[[:space:]]+)*'
257
452
  _PATHRM='(\\|/(usr/)?bin/)?rm'
258
453
  _RM_FLAG='(-[a-zA-Z]*[rR][a-zA-Z]*|--recursive)'
259
454
  _RM_ARGS='([[:space:]]+[^[:space:];&|]+)*'
@@ -268,17 +463,21 @@ if [ ! -f "$PATTERNS_FILE" ]; then
268
463
  # The pattern file ships with DoFlow, so a missing one means a broken install: record it on this
269
464
  # machine (feature 046, IC-018) and go on exactly as before. Subshell, output discarded: nothing
270
465
  # the helper does can reach this policy's options, variables, output or exit status.
271
- ( . "$(dirname "$0")/capture-failure.sh"; doflow_capture_failure pre-bash-guard patterns-missing ) >/dev/null 2>&1 || true
466
+ ( . "$_DOFLOW_POLDIR/capture-failure.sh"; doflow_capture_failure pre-bash-guard patterns-missing ) >/dev/null 2>&1 || true
467
+ doflow_decide error patterns-missing
272
468
  if _floor_rm_hits '/+\*{0,2}'; then
273
469
  echo "[pre-bash-guard] Catastrophic delete blocked — recursive rm of the root directory (/)" >&2
470
+ doflow_decide deny catastrophic-rm-root
274
471
  exit 2
275
472
  fi
276
473
  if _floor_rm_hits '(~[A-Za-z_][A-Za-z0-9_.-]*|~|\$HOME|\$\{HOME\})(/\*{0,2})?'; then
277
474
  echo "[pre-bash-guard] Catastrophic delete blocked — recursive rm of the home directory" >&2
475
+ doflow_decide deny catastrophic-rm-home
278
476
  exit 2
279
477
  fi
280
478
  if _floor_rm_hits '/(Users|home|etc|usr|bin|sbin|var|opt|System|Library|Applications|Volumes|private|root|boot|lib|dev|proc)(/\*{0,2})?'; then
281
479
  echo "[pre-bash-guard] Catastrophic delete blocked — recursive rm of a system directory" >&2
480
+ doflow_decide deny catastrophic-rm-system
282
481
  exit 2
283
482
  fi
284
483
  # No patterns file beyond the hardcoded floor — allow everything else
@@ -286,12 +485,54 @@ if [ ! -f "$PATTERNS_FILE" ]; then
286
485
  exit 0
287
486
  fi
288
487
 
488
+ # One combined ERE cheaply rules out commands that match no live pattern. A
489
+ # grep match or regex error falls through to the original per-line loop, which
490
+ # still owns the reason and optional exclude semantics.
491
+ _anchored_patterns="" _full_patterns="" _has_backreference=false
492
+ _has_worker_marker=false
493
+ while IFS=$'\t' read -r pattern _reason _exclude || [ -n "$pattern" ]; do
494
+ [ -z "$pattern" ] && continue
495
+ case "$pattern" in
496
+ '#@exempt-next worker-worktree') _has_worker_marker=true; continue ;;
497
+ \#*) continue ;;
498
+ esac
499
+ if [ "$DATA_ONLY" = true ] && _sql_pattern "$pattern"; then continue; fi
500
+ if [[ "$pattern" =~ \\[1-9] ]]; then _has_backreference=true; fi
501
+ case "$pattern" in
502
+ '(^|'*) _anchored_patterns="${_anchored_patterns:+$_anchored_patterns|}($pattern)" ;;
503
+ *) _full_patterns="${_full_patterns:+$_full_patterns|}($pattern)" ;;
504
+ esac
505
+ done < "$PATTERNS_FILE"
506
+ _anchored_status=1 _full_status=1
507
+ if [ -n "$_anchored_patterns" ]; then
508
+ grep -qiE -- "$_anchored_patterns" <<<"$SHELL_TEXT" 2>/dev/null
509
+ _anchored_status=$?
510
+ fi
511
+ if [ -n "$_full_patterns" ]; then
512
+ grep -qiE -- "$_full_patterns" <<<"$COMMAND" 2>/dev/null
513
+ _full_status=$?
514
+ fi
515
+ if [ "$_anchored_status" -eq 1 ] && [ "$_full_status" -eq 1 ] && [ "$_has_backreference" != true ]; then
516
+ # Some accepted worker shapes (reset -q --hard, clean -f) already match no
517
+ # deny rule. Give those allows the same scope code without widening a rule.
518
+ if [ "$_has_worker_marker" = true ] && _worker_exempt; then doflow_decide allow worker-worktree; fi
519
+ exit 0
520
+ fi
521
+
289
522
  # ── Pattern matching ──────────────────────────────────────────────────────────
290
523
 
524
+ _exempt_next= _worker_skipped=false
291
525
  while IFS=$'\t' read -r pattern reason exclude || [ -n "$pattern" ]; do
292
526
  # Skip comments and empty lines
293
527
  [ -z "$pattern" ] && continue
294
- case "$pattern" in \#*) continue ;; esac
528
+ case "$pattern" in
529
+ '#@exempt-next worker-worktree') _exempt_next=worker-worktree; continue ;;
530
+ '#@exempt-next worker-dropdb') _exempt_next=worker-dropdb; continue ;;
531
+ \#*) continue ;;
532
+ esac
533
+ exemption=$_exempt_next
534
+ _exempt_next=
535
+ if [ "$DATA_ONLY" = true ] && _sql_pattern "$pattern"; then continue; fi
295
536
 
296
537
  # Match pattern against command (case-insensitive, POSIX extended regex: the default macOS
297
538
  # filesystem is case-insensitive, so RM and GIT run there).
@@ -319,10 +560,20 @@ while IFS=$'\t' read -r pattern reason exclude || [ -n "$pattern" ]; do
319
560
  fi
320
561
 
321
562
  if [ "$matched" = "true" ]; then
563
+ if [ "$exemption" = worker-worktree ] && _worker_exempt; then
564
+ _worker_skipped=worker-worktree
565
+ continue
566
+ fi
567
+ if [ "$exemption" = worker-dropdb ] && _worker_dropdb_exempt; then
568
+ _worker_skipped=worker-dropdb
569
+ continue
570
+ fi
322
571
  echo "[pre-bash-guard] ${reason:-Command blocked by pre-bash-guard}" >&2
572
+ doflow_decide deny blocked-pattern
323
573
  exit 2
324
574
  fi
325
575
  done < "$PATTERNS_FILE"
326
576
 
327
577
  # No match — allow
578
+ [ "$_worker_skipped" != false ] && doflow_decide allow "$_worker_skipped"
328
579
  exit 0