@khoavu882/doflow 0.0.0-stage → 2.0.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 (407) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +132 -2
  3. package/bin/doflow.js +44 -0
  4. package/core/.antigravity-plugin/hooks.json +39 -0
  5. package/core/.antigravity-plugin/mcp_config.json +18 -0
  6. package/core/.antigravity-plugin/plugin.json +31 -0
  7. package/core/.claude-plugin/marketplace.json +20 -0
  8. package/core/.claude-plugin/plugin.json +21 -0
  9. package/core/.codex-plugin/marketplace.json +20 -0
  10. package/core/.codex-plugin/plugin.json +35 -0
  11. package/core/.plugin/plugin.json +19 -0
  12. package/core/harnesses/antigravity/hooks/pre-implementation-gate.sh +9 -0
  13. package/core/harnesses/antigravity/hooks/stop-check.sh +10 -0
  14. package/core/harnesses/claude/hooks/lib.sh +304 -0
  15. package/core/harnesses/claude/hooks/mcp-tool-guard.sh +20 -0
  16. package/core/harnesses/claude/hooks/permission-audit.sh +47 -0
  17. package/core/harnesses/claude/hooks/post-compact.sh +74 -0
  18. package/core/harnesses/claude/hooks/post-edit-lint.sh +36 -0
  19. package/core/harnesses/claude/hooks/post-tool-failure.sh +47 -0
  20. package/core/harnesses/claude/hooks/pre-bash-guard.sh +20 -0
  21. package/core/harnesses/claude/hooks/pre-compact.sh +43 -0
  22. package/core/harnesses/claude/hooks/pre-implement-gate.sh +21 -0
  23. package/core/harnesses/claude/hooks/session-end.sh +89 -0
  24. package/core/harnesses/claude/hooks/session-start.sh +5 -0
  25. package/core/harnesses/claude/hooks/skill-config-audit.sh +39 -0
  26. package/core/harnesses/claude/hooks/stop-check.sh +5 -0
  27. package/core/harnesses/claude/hooks/subagent-audit.sh +7 -0
  28. package/core/harnesses/claude/hooks/user-prompt-submit.sh +5 -0
  29. package/core/harnesses/claude/settings/keybindings.json +20 -0
  30. package/core/harnesses/claude/settings/settings.json +201 -0
  31. package/core/harnesses/claude/statusline/doflow-statusline.sh +49 -0
  32. package/core/harnesses/codex/agents/core-implementer.toml +7 -0
  33. package/core/harnesses/codex/agents/quality-guardian.toml +8 -0
  34. package/core/harnesses/codex/agents/research-writer.toml +8 -0
  35. package/core/harnesses/codex/agents/spec-analyst.toml +8 -0
  36. package/core/harnesses/codex/agents/system-architect.toml +9 -0
  37. package/core/harnesses/codex/config/config.toml +10 -0
  38. package/core/harnesses/codex/hooks/hooks.json +122 -0
  39. package/core/harnesses/codex/hooks/lib.sh +335 -0
  40. package/core/harnesses/codex/hooks/mcp-tool-guard.sh +18 -0
  41. package/core/harnesses/codex/hooks/post-edit-lint.impl.sh +52 -0
  42. package/core/harnesses/codex/hooks/post-edit-lint.sh +6 -0
  43. package/core/harnesses/codex/hooks/pre-bash-guard.sh +18 -0
  44. package/core/harnesses/codex/hooks/pre-compact.impl.sh +46 -0
  45. package/core/harnesses/codex/hooks/pre-compact.sh +9 -0
  46. package/core/harnesses/codex/hooks/pre-implement-gate.sh +19 -0
  47. package/core/harnesses/codex/hooks/session-end.impl.sh +92 -0
  48. package/core/harnesses/codex/hooks/session-end.sh +5 -0
  49. package/core/harnesses/codex/hooks/session-start.sh +5 -0
  50. package/core/harnesses/codex/hooks/stop-check.sh +8 -0
  51. package/core/harnesses/codex/hooks/subagent-audit.sh +8 -0
  52. package/core/harnesses/codex/hooks/user-prompt-submit.sh +6 -0
  53. package/core/harnesses/gemini/hooks/hooks.json +77 -0
  54. package/core/harnesses/gemini/hooks/lib.sh +302 -0
  55. package/core/harnesses/gemini/hooks/mcp-tool-guard.sh +21 -0
  56. package/core/harnesses/gemini/hooks/post-edit-lint.sh +39 -0
  57. package/core/harnesses/gemini/hooks/pre-bash-guard.sh +21 -0
  58. package/core/harnesses/gemini/hooks/pre-compact.sh +38 -0
  59. package/core/harnesses/gemini/hooks/pre-implement-gate.sh +22 -0
  60. package/core/harnesses/gemini/hooks/session-end.impl.sh +89 -0
  61. package/core/harnesses/gemini/hooks/session-end.sh +5 -0
  62. package/core/harnesses/gemini/hooks/session-start.sh +5 -0
  63. package/core/harnesses/gemini/settings/adapter-defaults.json +4 -0
  64. package/core/harnesses/kiro/agents/doflow.json +58 -0
  65. package/core/harnesses/kiro/hooks/doflow.json +53 -0
  66. package/core/harnesses/kiro/hooks/lib.sh +324 -0
  67. package/core/harnesses/kiro/hooks/mcp-tool-guard.sh +9 -0
  68. package/core/harnesses/kiro/hooks/pre-bash-guard.sh +9 -0
  69. package/core/harnesses/kiro/hooks/pre-implement-gate.sh +9 -0
  70. package/core/harnesses/kiro/hooks/session-start.sh +9 -0
  71. package/core/harnesses/kiro/hooks/stop-check.sh +43 -0
  72. package/core/harnesses/shared/hooks/ENVELOPE_MIGRATION.md +39 -0
  73. package/core/harnesses/shared/hooks/adapters/antigravity.js +111 -0
  74. package/core/harnesses/shared/hooks/adapters/arg-fields.js +19 -0
  75. package/core/harnesses/shared/hooks/adapters/gemini.js +114 -0
  76. package/core/harnesses/shared/hooks/hooks.json +47 -0
  77. package/core/harnesses/shared/hooks/policies/blocked-patterns.conf +91 -0
  78. package/core/harnesses/shared/hooks/policies/capture-failure.sh +97 -0
  79. package/core/harnesses/shared/hooks/policies/deny-json.sh +29 -0
  80. package/core/harnesses/shared/hooks/policies/lib.sh +501 -0
  81. package/core/harnesses/shared/hooks/policies/mcp-policy.conf +21 -0
  82. package/core/harnesses/shared/hooks/policies/mcp-tool-guard.sh +91 -0
  83. package/core/harnesses/shared/hooks/policies/pre-bash-guard.sh +328 -0
  84. package/core/harnesses/shared/hooks/policies/pre-implementation-gate.sh +496 -0
  85. package/core/harnesses/shared/hooks/policies/prompt-nudge.jq +131 -0
  86. package/core/harnesses/shared/hooks/policies/session-context.sh +141 -0
  87. package/core/harnesses/shared/hooks/policies/stop-check.sh +264 -0
  88. package/core/harnesses/shared/hooks/policies/subagent-audit.sh +46 -0
  89. package/core/harnesses/shared/hooks/policies/user-prompt-submit.sh +235 -0
  90. package/core/harnesses/shared/hooks/stream-hook-runner.js +590 -0
  91. package/core/harnesses/shared/locator/doflow-run +87 -0
  92. package/core/registry/advice.json +101 -0
  93. package/core/registry/assets.json +792 -0
  94. package/core/registry/capabilities.json +120 -0
  95. package/core/registry/contracts.json +189 -0
  96. package/core/registry/external-tools.json +191 -0
  97. package/core/registry/harnesses.json +2062 -0
  98. package/core/registry/lifecycle.json +231 -0
  99. package/core/registry/mcp.json +18 -0
  100. package/core/registry/models.json +79 -0
  101. package/core/registry/readiness-templates.json +118 -0
  102. package/core/registry/routes.json +47 -0
  103. package/core/registry/storage.json +1057 -0
  104. package/core/registry/verification.json +258 -0
  105. package/core/registry/workflows.json +790 -0
  106. package/core/shared/agent-specs/core-implementer.md +73 -0
  107. package/core/shared/agent-specs/quality-guardian.md +28 -0
  108. package/core/shared/agent-specs/research-writer.md +31 -0
  109. package/core/shared/agent-specs/spec-analyst.md +33 -0
  110. package/core/shared/agent-specs/system-architect.md +29 -0
  111. package/core/shared/guidance/DOFLOW_CORE.md +8 -0
  112. package/core/shared/guidance/FLAGS.md +25 -0
  113. package/core/shared/guidance/PRINCIPLES.md +61 -0
  114. package/core/shared/guidance/VERSION +1 -0
  115. package/core/shared/guidance/mcp/MCP_Context7.md +18 -0
  116. package/core/shared/guidance/mcp/MCP_Sequential.md +17 -0
  117. package/core/shared/guidance/modes/MODE_Brainstorming.md +46 -0
  118. package/core/shared/guidance/modes/MODE_DeepResearch.md +69 -0
  119. package/core/shared/guidance/modes/MODE_Introspection.md +33 -0
  120. package/core/shared/guidance/modes/MODE_Orchestration.md +57 -0
  121. package/core/shared/guidance/modes/MODE_Task_Management.md +74 -0
  122. package/core/shared/guidance/pointers/claude-gemini.md +2 -0
  123. package/core/shared/guidance/pointers/codex.md +6 -0
  124. package/core/shared/guidance/references/ARTIFACT_FORMAT.md +373 -0
  125. package/core/shared/guidance/references/ARTIFACT_VOICE.md +104 -0
  126. package/core/shared/guidance/references/CONSTITUTION_BASE.md +47 -0
  127. package/core/shared/guidance/references/DIAGRAM_GUIDE.md +161 -0
  128. package/core/shared/guidance/references/DOFLOW_CHAIN.md +87 -0
  129. package/core/shared/guidance/references/EVIDENCE_LEDGER.md +93 -0
  130. package/core/shared/guidance/references/MODEL_SELECTION.md +74 -0
  131. package/core/shared/guidance/references/ORCHESTRATION.md +36 -0
  132. package/core/shared/guidance/references/RESEARCH_CONFIG.md +21 -0
  133. package/core/shared/guidance/references/WORKFLOW_HANDOFF.md +81 -0
  134. package/core/shared/guidance/rules/RULE_01_SAFETY.md +25 -0
  135. package/core/shared/guidance/rules/RULE_02_WORKFLOW.md +23 -0
  136. package/core/shared/guidance/rules/RULE_03_QUALITY.md +14 -0
  137. package/core/shared/guidance/rules/RULE_04_QUESTIONS.md +46 -0
  138. package/core/shared/scripts/doflow/assets/mermaid-theme.json +46 -0
  139. package/core/shared/scripts/doflow/bash/do-exec-paths.sh +167 -0
  140. package/core/shared/scripts/doflow/bash/do-git-state.sh +546 -0
  141. package/core/shared/scripts/doflow/bash/do-parallel-check.sh +208 -0
  142. package/core/shared/scripts/doflow/bash/do-paths.sh +347 -0
  143. package/core/shared/scripts/doflow/bash/do-prereqs.sh +66 -0
  144. package/core/shared/scripts/doflow/bash/do-review-package.sh +127 -0
  145. package/core/shared/scripts/doflow/bash/do-task-brief.sh +698 -0
  146. package/core/shared/scripts/doflow/bash/render-audit.sh +224 -0
  147. package/core/shared/scripts/doflow/bash/render-diagrams.sh +177 -0
  148. package/core/shared/scripts/doflow/bash/render-puml.sh +223 -0
  149. package/core/shared/scripts/doflow/bash/sync-context.sh +66 -0
  150. package/core/shared/scripts/doflow/bash/validate-artifacts.sh +526 -0
  151. package/core/shared/scripts/doflow/bin/doflow-run +592 -0
  152. package/core/shared/skills/do/SKILL.md +128 -0
  153. package/core/shared/skills/do/references/estimation.md +13 -0
  154. package/core/shared/skills/do/references/pm_routing.md +25 -0
  155. package/core/shared/skills/do/references/tool_matrix.md +52 -0
  156. package/core/shared/skills/do-brainstorm/SKILL.md +252 -0
  157. package/core/shared/skills/do-code-review/README.md +49 -0
  158. package/core/shared/skills/do-code-review/SKILL.md +333 -0
  159. package/core/shared/skills/do-code-review/assets/sample_c_clean.c +71 -0
  160. package/core/shared/skills/do-code-review/assets/sample_c_smells.c +66 -0
  161. package/core/shared/skills/do-code-review/assets/sample_cpp_shift.cpp +19 -0
  162. package/core/shared/skills/do-code-review/assets/sample_csharp_clean.cs +100 -0
  163. package/core/shared/skills/do-code-review/assets/sample_csharp_smells.cs +78 -0
  164. package/core/shared/skills/do-code-review/assets/sample_java_clean.java +55 -0
  165. package/core/shared/skills/do-code-review/assets/sample_java_smells.java +56 -0
  166. package/core/shared/skills/do-code-review/assets/sample_json_clean.json +7 -0
  167. package/core/shared/skills/do-code-review/assets/sample_markdown_clean.md +30 -0
  168. package/core/shared/skills/do-code-review/assets/sample_markdown_smells.md +29 -0
  169. package/core/shared/skills/do-code-review/assets/sample_shell_heredoc.sh +38 -0
  170. package/core/shared/skills/do-code-review/assets/sample_shell_smells.sh +15 -0
  171. package/core/shared/skills/do-code-review/assets/sample_typescript_strings.ts +36 -0
  172. package/core/shared/skills/do-code-review/assets/sample_yaml_smells.yaml +6 -0
  173. package/core/shared/skills/do-code-review/content-types/config.md +83 -0
  174. package/core/shared/skills/do-code-review/content-types/markdown.md +132 -0
  175. package/core/shared/skills/do-code-review/expected_outputs/sample_c_clean_quality.json +79 -0
  176. package/core/shared/skills/do-code-review/expected_outputs/sample_c_smells_quality.json +169 -0
  177. package/core/shared/skills/do-code-review/expected_outputs/sample_cpp_shift_quality.json +49 -0
  178. package/core/shared/skills/do-code-review/expected_outputs/sample_csharp_clean_quality.json +149 -0
  179. package/core/shared/skills/do-code-review/expected_outputs/sample_csharp_smells_quality.json +157 -0
  180. package/core/shared/skills/do-code-review/expected_outputs/sample_java_clean_quality.json +67 -0
  181. package/core/shared/skills/do-code-review/expected_outputs/sample_java_smells_quality.json +97 -0
  182. package/core/shared/skills/do-code-review/expected_outputs/sample_json_clean_quality.json +33 -0
  183. package/core/shared/skills/do-code-review/expected_outputs/sample_markdown_clean_quality.json +1 -0
  184. package/core/shared/skills/do-code-review/expected_outputs/sample_markdown_smells_quality.json +16 -0
  185. package/core/shared/skills/do-code-review/expected_outputs/sample_shell_heredoc_quality.json +54 -0
  186. package/core/shared/skills/do-code-review/expected_outputs/sample_shell_smells_quality.json +91 -0
  187. package/core/shared/skills/do-code-review/expected_outputs/sample_typescript_strings_quality.json +60 -0
  188. package/core/shared/skills/do-code-review/expected_outputs/sample_yaml_smells_quality.json +46 -0
  189. package/core/shared/skills/do-code-review/languages/c.md +103 -0
  190. package/core/shared/skills/do-code-review/languages/cpp.md +103 -0
  191. package/core/shared/skills/do-code-review/languages/csharp.md +97 -0
  192. package/core/shared/skills/do-code-review/languages/dart.md +108 -0
  193. package/core/shared/skills/do-code-review/languages/go.md +92 -0
  194. package/core/shared/skills/do-code-review/languages/java.md +103 -0
  195. package/core/shared/skills/do-code-review/languages/kotlin.md +88 -0
  196. package/core/shared/skills/do-code-review/languages/php.md +109 -0
  197. package/core/shared/skills/do-code-review/languages/python.md +94 -0
  198. package/core/shared/skills/do-code-review/languages/ruby.md +105 -0
  199. package/core/shared/skills/do-code-review/languages/rust.md +99 -0
  200. package/core/shared/skills/do-code-review/languages/shell.md +90 -0
  201. package/core/shared/skills/do-code-review/languages/swift.md +88 -0
  202. package/core/shared/skills/do-code-review/languages/typescript.md +97 -0
  203. package/core/shared/skills/do-code-review/review-policy.json +47 -0
  204. package/core/shared/skills/do-code-review/rules/universal.md +49 -0
  205. package/core/shared/skills/do-code-review/scripts/code_quality_checker.py +1696 -0
  206. package/core/shared/skills/do-code-review/scripts/doc_quality_checker.py +532 -0
  207. package/core/shared/skills/do-code-review/scripts/pr_analyzer.py +620 -0
  208. package/core/shared/skills/do-code-review/scripts/review_report_generator.py +505 -0
  209. package/core/shared/skills/do-constitution/SKILL.md +72 -0
  210. package/core/shared/skills/do-design/SKILL.md +212 -0
  211. package/core/shared/skills/do-diagnose/SKILL.md +156 -0
  212. package/core/shared/skills/do-diagnose/references/code_audit.md +15 -0
  213. package/core/shared/skills/do-diagnose/references/refactoring.md +12 -0
  214. package/core/shared/skills/do-diagnose/references/root_cause.md +17 -0
  215. package/core/shared/skills/do-document/SKILL.md +81 -0
  216. package/core/shared/skills/do-document/references/api-reference.md +42 -0
  217. package/core/shared/skills/do-document/references/deep_research.md +18 -0
  218. package/core/shared/skills/do-document/references/embedded-research.md +11 -0
  219. package/core/shared/skills/do-document/references/implementation-flow.md +105 -0
  220. package/core/shared/skills/do-document/references/index_generator.md +9 -0
  221. package/core/shared/skills/do-document/references/user-guide.md +22 -0
  222. package/core/shared/skills/do-execute-plan/SKILL.md +261 -0
  223. package/core/shared/skills/do-execute-plan/references/handoff_record.md +57 -0
  224. package/core/shared/skills/do-execute-plan/references/parallel_dispatch.md +92 -0
  225. package/core/shared/skills/do-execute-plan/references/readiness_gate.md +155 -0
  226. package/core/shared/skills/do-execute-plan/references/run_position.md +63 -0
  227. package/core/shared/skills/do-execute-plan/references/scaffold.md +441 -0
  228. package/core/shared/skills/do-execute-plan/references/task_attempts.md +41 -0
  229. package/core/shared/skills/do-flow/SKILL.md +186 -0
  230. package/core/shared/skills/do-flow/references/task_classes.md +134 -0
  231. package/core/shared/skills/do-git/SKILL.md +115 -0
  232. package/core/shared/skills/do-git/references/hotfix-ritual.md +44 -0
  233. package/core/shared/skills/do-git/references/lifecycle-policy.md +54 -0
  234. package/core/shared/skills/do-git/references/release-ritual.md +64 -0
  235. package/core/shared/skills/do-implement/SKILL.md +222 -0
  236. package/core/shared/skills/do-plan/SKILL.md +219 -0
  237. package/core/shared/skills/do-test/SKILL.md +113 -0
  238. package/core/shared/templates/doflow/constitution-template.md +28 -0
  239. package/core/shared/templates/doflow/data-model-template.md +169 -0
  240. package/core/shared/templates/doflow/design-template.md +193 -0
  241. package/core/shared/templates/doflow/external-contract-template.md +35 -0
  242. package/core/shared/templates/doflow/intent-template.md +45 -0
  243. package/core/shared/templates/doflow/plan-template.md +151 -0
  244. package/core/shared/templates/doflow/question-log-template.md +51 -0
  245. package/core/shared/templates/doflow/requirement-template.md +126 -0
  246. package/core/shared/templates/doflow/specs-template.md +55 -0
  247. package/core/shared/templates/doflow/state-template.md +59 -0
  248. package/core/shared/workflows/do-flow-chain.md +17 -0
  249. package/package.json +46 -4
  250. package/src/adapters/antigravity/index.ts +631 -0
  251. package/src/adapters/claude/index.ts +548 -0
  252. package/src/adapters/claude/mcp.ts +94 -0
  253. package/src/adapters/codex/agents.ts +208 -0
  254. package/src/adapters/codex/config.ts +272 -0
  255. package/src/adapters/codex/hooks.ts +203 -0
  256. package/src/adapters/codex/index.ts +707 -0
  257. package/src/adapters/codex/mcp.ts +271 -0
  258. package/src/adapters/codex/native-projection.ts +34 -0
  259. package/src/adapters/copilot/index.ts +413 -0
  260. package/src/adapters/copy-tree.ts +620 -0
  261. package/src/adapters/gemini/hooks.ts +210 -0
  262. package/src/adapters/gemini/index.ts +390 -0
  263. package/src/adapters/hook-commands.ts +60 -0
  264. package/src/adapters/index.ts +106 -0
  265. package/src/adapters/kiro/index.ts +310 -0
  266. package/src/adapters/mcp-entries.ts +331 -0
  267. package/src/adapters/opencode/index.ts +466 -0
  268. package/src/adapters/pi/index.ts +279 -0
  269. package/src/adapters/pi/json-members.ts +185 -0
  270. package/src/adapters/pi/mcp.ts +373 -0
  271. package/src/adapters/resolve-source.ts +19 -0
  272. package/src/cli/commands/install.ts +218 -0
  273. package/src/cli/commands/list-backups.ts +21 -0
  274. package/src/cli/commands/reconcile.ts +120 -0
  275. package/src/cli/commands/remove.ts +82 -0
  276. package/src/cli/commands/rollback.ts +172 -0
  277. package/src/cli/commands/self-update.ts +33 -0
  278. package/src/cli/commands/status.ts +138 -0
  279. package/src/cli/commands/tools.ts +92 -0
  280. package/src/cli/commands/update.ts +162 -0
  281. package/src/cli/index.ts +568 -0
  282. package/src/cli/runtime-commands.ts +281 -0
  283. package/src/cli/shared.ts +218 -0
  284. package/src/helper/bash-helper.ts +34 -0
  285. package/src/helper/git.ts +24 -0
  286. package/src/helper/guardrails.ts +49 -0
  287. package/src/helper/harness-paths.ts +140 -0
  288. package/src/helper/marker-merge.ts +116 -0
  289. package/src/helper/prompt.ts +61 -0
  290. package/src/helper/repo-root.ts +29 -0
  291. package/src/helper/settings-merge.ts +151 -0
  292. package/src/helper/settings-scope.ts +33 -0
  293. package/src/helper/toml.ts +244 -0
  294. package/src/install/backup-set.ts +149 -0
  295. package/src/install/backup.ts +724 -0
  296. package/src/install/context.ts +58 -0
  297. package/src/install/manifest.ts +145 -0
  298. package/src/install/mcp.ts +254 -0
  299. package/src/install/paths.ts +84 -0
  300. package/src/install/targets.ts +90 -0
  301. package/src/install/tool-lifecycle.ts +151 -0
  302. package/src/lifecycle/bash-availability.ts +25 -0
  303. package/src/lifecycle/index.ts +812 -0
  304. package/src/lifecycle/mcp-index.ts +28 -0
  305. package/src/lifecycle/policies.ts +73 -0
  306. package/src/lifecycle/view.ts +175 -0
  307. package/src/registry/index.ts +611 -0
  308. package/src/release/sync-plugin-versions.ts +66 -0
  309. package/src/runtime/advice/cli.ts +283 -0
  310. package/src/runtime/advice/client.ts +324 -0
  311. package/src/runtime/advice/config.ts +189 -0
  312. package/src/runtime/advice/doctor.ts +169 -0
  313. package/src/runtime/advice/endpoint-guard.ts +134 -0
  314. package/src/runtime/advice/kinds.ts +154 -0
  315. package/src/runtime/advice/providers/ollama-systemone.ts +209 -0
  316. package/src/runtime/advice/record.ts +166 -0
  317. package/src/runtime/advice/registry.ts +170 -0
  318. package/src/runtime/advice/strength.ts +66 -0
  319. package/src/runtime/brief-tools.ts +342 -0
  320. package/src/runtime/c4-project.ts +371 -0
  321. package/src/runtime/capability-router.ts +484 -0
  322. package/src/runtime/checkouts.ts +170 -0
  323. package/src/runtime/claims.ts +468 -0
  324. package/src/runtime/cli-result.ts +55 -0
  325. package/src/runtime/cli.ts +678 -0
  326. package/src/runtime/command-detect.ts +516 -0
  327. package/src/runtime/context-pack.ts +492 -0
  328. package/src/runtime/decision-register.ts +493 -0
  329. package/src/runtime/evidence-ledger.ts +338 -0
  330. package/src/runtime/failure/capture.ts +272 -0
  331. package/src/runtime/failure/classifier.ts +68 -0
  332. package/src/runtime/failure/cli.ts +178 -0
  333. package/src/runtime/failure/home.ts +64 -0
  334. package/src/runtime/failure/store.ts +226 -0
  335. package/src/runtime/feature-resolve.ts +79 -0
  336. package/src/runtime/freshness.ts +177 -0
  337. package/src/runtime/health.ts +863 -0
  338. package/src/runtime/history-compactor.ts +237 -0
  339. package/src/runtime/implementation-gate.ts +321 -0
  340. package/src/runtime/inventory/coverage.ts +218 -0
  341. package/src/runtime/inventory/identity.ts +65 -0
  342. package/src/runtime/inventory/index.ts +705 -0
  343. package/src/runtime/inventory/precedence.ts +134 -0
  344. package/src/runtime/inventory/read-scopes.ts +131 -0
  345. package/src/runtime/inventory/siblings.ts +192 -0
  346. package/src/runtime/knowledge/chunker.ts +124 -0
  347. package/src/runtime/knowledge/hybrid.ts +149 -0
  348. package/src/runtime/knowledge/index-store.ts +145 -0
  349. package/src/runtime/knowledge/retrieval.ts +194 -0
  350. package/src/runtime/leak-scan.ts +185 -0
  351. package/src/runtime/lifecycle/cli.ts +276 -0
  352. package/src/runtime/lifecycle/event-store.ts +340 -0
  353. package/src/runtime/lifecycle/fold.ts +353 -0
  354. package/src/runtime/lifecycle/followup.ts +432 -0
  355. package/src/runtime/lifecycle/goal.ts +249 -0
  356. package/src/runtime/lifecycle/intent-writer.ts +86 -0
  357. package/src/runtime/lifecycle/overview.ts +292 -0
  358. package/src/runtime/lifecycle/release.ts +241 -0
  359. package/src/runtime/lifecycle/report-store.ts +221 -0
  360. package/src/runtime/lifecycle/retention.ts +212 -0
  361. package/src/runtime/lifecycle/root.ts +71 -0
  362. package/src/runtime/lifecycle/status.ts +353 -0
  363. package/src/runtime/lifecycle/store-upkeep.ts +393 -0
  364. package/src/runtime/locator-resolve.ts +158 -0
  365. package/src/runtime/mask.ts +210 -0
  366. package/src/runtime/mcp-consultations.ts +412 -0
  367. package/src/runtime/mcp-reach.ts +157 -0
  368. package/src/runtime/model-router.ts +153 -0
  369. package/src/runtime/outcome.ts +467 -0
  370. package/src/runtime/reach.ts +148 -0
  371. package/src/runtime/readiness-record.ts +150 -0
  372. package/src/runtime/readiness.ts +435 -0
  373. package/src/runtime/recovery.ts +282 -0
  374. package/src/runtime/research-request.ts +231 -0
  375. package/src/runtime/retrieval-plan.ts +578 -0
  376. package/src/runtime/scaffold/artifacts.ts +217 -0
  377. package/src/runtime/scaffold/fingerprint.ts +56 -0
  378. package/src/runtime/scaffold/generate.ts +911 -0
  379. package/src/runtime/scaffold/languages.ts +245 -0
  380. package/src/runtime/storage/cli.ts +64 -0
  381. package/src/runtime/storage/engine.ts +249 -0
  382. package/src/runtime/storage/registry.ts +130 -0
  383. package/src/runtime/storage/roots.ts +63 -0
  384. package/src/runtime/storage/rules.ts +282 -0
  385. package/src/runtime/storage/upkeep.ts +243 -0
  386. package/src/runtime/storage/work-status.ts +326 -0
  387. package/src/runtime/task-attempts.ts +415 -0
  388. package/src/runtime/task-classifier.ts +550 -0
  389. package/src/runtime/task-scope.ts +130 -0
  390. package/src/runtime/task-state.ts +176 -0
  391. package/src/runtime/trace/indicators.ts +235 -0
  392. package/src/runtime/trace/ledger.ts +626 -0
  393. package/src/runtime/trace/render.ts +76 -0
  394. package/src/runtime/trace/views.ts +459 -0
  395. package/src/runtime/verification/contract-runner.ts +341 -0
  396. package/src/runtime/verification/engine.ts +1461 -0
  397. package/src/runtime/verification/registry.ts +130 -0
  398. package/src/runtime/verification/scope-bound.ts +418 -0
  399. package/src/runtime/verification/test-selection.ts +172 -0
  400. package/src/runtime/workflow-engine.ts +588 -0
  401. package/src/runtime/workflow-orchestrator.ts +953 -0
  402. package/src/runtime/worktree.ts +340 -0
  403. package/src/state/index.ts +193 -0
  404. package/src/state/lockfile.ts +136 -0
  405. package/src/state/run-lock.ts +408 -0
  406. package/types/node-commonjs.d.ts +68 -0
  407. package/types/runtime.d.ts +91 -0
@@ -0,0 +1,328 @@
1
+ #!/usr/bin/env bash
2
+ # pre-bash-guard.sh — Canonical Policy Library: PreToolUse(shell-command) hook
3
+ #
4
+ # Intercepts every shell-command tool call and blocks dangerous commands by
5
+ # matching against POSIX ERE patterns in blocked-patterns.conf (grep -E).
6
+ #
7
+ # Multi-session safe: stateless — reads only the conf file, no shared state.
8
+ # Must complete in <50ms.
9
+ #
10
+ # Canonical Policy Script Contract (design.md §4):
11
+ # env DOFLOW_PROJECT_DIR, DOFLOW_AGENT (both optional; not required to
12
+ # 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.
21
+ #
22
+ # Reconciliation note (022-normalize-hooks, Phase A / D1): this also absorbs
23
+ # stream-hook-runner.js's inline DESTRUCTIVE_COMMAND_PATTERN
24
+ # (`\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
27
+ # duplicated, rather than delegated to, this policy's fuller
28
+ # blocked-patterns.conf coverage (git force-push, git reset --hard, git clean
29
+ # -fd, SQL DROP/DELETE/TRUNCATE, curl|wget-pipe-to-shell, chmod -R 777, dd
30
+ # from a block device). That pattern is kept here as a hardcoded floor for
31
+ # the case blocked-patterns.conf itself is missing, so a harness that had
32
+ # only the hardcoded regex before this change does not lose even that
33
+ # minimum floor of protection; once blocked-patterns.conf is present (the
34
+ # 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
37
+ # design.md R2/R3), not a silent side effect.
38
+
39
+ set -uo pipefail
40
+
41
+ command -v jq >/dev/null 2>&1 || exit 0 # no jq -> cannot evaluate -> allow
42
+
43
+ INPUT=$(cat)
44
+
45
+ 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)
59
+
60
+ # Nothing to check if command is empty
61
+ [ -z "$COMMAND" ] && exit 0
62
+
63
+ PATTERNS_FILE="$(dirname "$0")/blocked-patterns.conf"
64
+
65
+ # ASCII-only patterns: the C locale keeps bash's substring/pattern operations
66
+ # byte-wise (much faster than multibyte-aware in a UTF-8 locale).
67
+ export LC_ALL=C
68
+
69
+ # ── Quoted text, comments and heredoc bodies are not commands ────────────────
70
+ # scrub_quotes <text> -> sets SCRUBBED. Anchored shell-command patterns must
71
+ # not fire on text that is merely data (a commit message, an echo, a comment,
72
+ # a heredoc body). One linear pass, line by line, pure bash, no forks:
73
+ # - quoted text containing whitespace or ; & | is blanked to "" (it could
74
+ # otherwise fake a command position, e.g. echo "done && rm -rf /x");
75
+ # a quoted word with none of those ("/", "$HOME", $'/') is kept, unquoted,
76
+ # so rm -rf "/" is still seen as a target
77
+ # - the argument of sh|bash|zsh -c, eval and a here-string fed to a shell IS executed: it is kept and put
78
+ # in command position (wrapped in ";"), scrubbed again inside
79
+ # - inside double quotes, $( ... ) and `...` bodies also run: kept the same way
80
+ # - a # that starts a word comments out the rest of the line
81
+ # - a heredoc body (<<WORD, <<-WORD, quoted or not) is data and is dropped,
82
+ # except when the heredoc feeds a shell (bash <<EOF), whose body runs
83
+ # - a backslash-newline joins the two lines (outside a heredoc body)
84
+ # - a backslash-escaped character is literal; an unterminated quote keeps the
85
+ # rest of the text as is (errs toward blocking)
86
+ # Nesting depth is capped; beyond the cap the raw text is used (errs toward
87
+ # blocking). Text with no quote, # or << (or no command word at all) is
88
+ # returned unchanged without scanning.
89
+ _EXEC_CTX='(^|[[:space:];&|(])((([^[:space:]]*/)?(ba|z|da|k)?sh[[:space:]]+(-[[:alnum:]]+[[:space:]]+)*-[[:alnum:]]*c|eval)[[:space:]]+|([^[:space:]]*/)?(ba|z|da|k)?sh([[:space:]]+-[-[:alnum:]]*)*[[:space:]]*[0-9]*<<<[[:space:]]*)$'
90
+ _SH_HERE='(^|[[:space:];&|(])([^[:space:]]*/)?(ba|z|da|k)?sh([[:space:]]+-[[:alnum:]]+)*[[:space:]]*$'
91
+ _HD_WORD="^(-?)[[:space:]]*[\"']?\\\\?([A-Za-z_][A-Za-z0-9_.-]*)"
92
+ SCRUB_DEPTH=0
93
+
94
+ # Closes the quote scrub_quotes just read (uses its locals: out qc qin qexec).
95
+ _scrub_close_quote() {
96
+ local rest pre body acc depth ch
97
+ if [ "$qexec" = 1 ]; then
98
+ [ "$qc" = '"' ] && qin=${qin//\\\"/\"} # \" inside "..." is a quote of the inner command
99
+ scrub_quotes "$qin"; cur+="; $SCRUBBED ; "
100
+ return
101
+ fi
102
+ case $qin in
103
+ *[[:space:]\;\&\|]*) ;;
104
+ *) cur+=$qin; return ;;
105
+ esac
106
+ cur+=$qc$qc
107
+ [ "$qc" = '"' ] || return
108
+ case $qin in *'$('*|*\`*) ;; *) return ;; esac
109
+ rest=$qin
110
+ while :; do
111
+ pre=${rest%%[\`\$\\]*}
112
+ [ "$pre" = "$rest" ] && break
113
+ rest=${rest#"$pre"}
114
+ case ${rest:0:1} in
115
+ '\') rest=${rest:2} ;;
116
+ '`')
117
+ body=${rest:1}
118
+ case $body in *\`*) acc=${body%%\`*}; rest=${body#*\`} ;; *) acc=$body; rest="" ;; esac
119
+ scrub_quotes "$acc"; cur+="; $SCRUBBED ; " ;;
120
+ *)
121
+ if [ "${rest:1:1}" = "(" ]; then
122
+ body=${rest:2}; acc=""; depth=1
123
+ while [ -n "$body" ]; do
124
+ pre=${body%%[()]*}
125
+ if [ "$pre" = "$body" ]; then acc+=$body; body=""; break; fi
126
+ acc+=$pre; ch=${body:${#pre}:1}; body=${body:$((${#pre} + 1))}
127
+ if [ "$ch" = "(" ]; then depth=$((depth + 1)); acc+=$ch
128
+ else depth=$((depth - 1)); [ "$depth" -eq 0 ] && break; acc+=$ch; fi
129
+ done
130
+ rest=$body
131
+ scrub_quotes "$acc"; cur+="; $SCRUBBED ; "
132
+ else
133
+ rest=${rest:1}
134
+ fi ;;
135
+ esac
136
+ done
137
+ }
138
+
139
+ scrub_quotes() {
140
+ local text=$1
141
+ case $text in
142
+ *[\'\"#]*|*'<<'*|*'\'$'\n'*) ;;
143
+ *) SCRUBBED=$text; return ;;
144
+ esac
145
+ case $text in
146
+ *rm[[:space:]]*|*git[[:space:]]*|*curl[[:space:]]*|*wget[[:space:]]*|*chmod[[:space:]]*|*dd[[:space:]]*|*find[[:space:]]*|*eval*|*sh[[:space:]]*) ;;
147
+ *) SCRUBBED=$text; return ;;
148
+ esac
149
+ if [ "$SCRUB_DEPTH" -ge 8 ]; then SCRUBBED=$text; return; fi
150
+ SCRUB_DEPTH=$((SCRUB_DEPTH + 1))
151
+
152
+ local out="" cur="" line L first=1 qc="" qin="" qexec=0 qansi=0 hd_word="" hd_dash=0
153
+ local pre c tail w d
154
+ while IFS= read -r line; do
155
+ if [ -z "$hd_word" ]; then # backslash-newline joins lines
156
+ while [[ $line == *[!\\]'\' || $line == '\' ]] && IFS= read -r w; do line="${line%?} $w"; done
157
+ fi
158
+ L=$line
159
+ if [ -n "$qc" ]; then
160
+ qin+=$'\n'
161
+ else
162
+ [ "$first" = 1 ] || cur+=$'\n'
163
+ if [ -n "$hd_word" ]; then # inside a heredoc body: skip the line
164
+ if [ "$hd_dash" = 1 ]; then while [ "${L:0:1}" = $'\t' ]; do L=${L:1}; done; fi
165
+ [ "$L" = "$hd_word" ] && hd_word=""
166
+ first=0; continue
167
+ fi
168
+ fi
169
+ first=0
170
+ # A very long line is scanned in ~1 KB segments (quote state carries over),
171
+ # so the per-token slicing below never copies a huge remainder: stays linear.
172
+ while [ -n "$line" ]; do
173
+ if [ ${#line} -gt 2048 ]; then
174
+ L=${line:0:1024}; line=${line:1024}
175
+ while [[ $L == *'\' || $L == *'<' ]] && [ -n "$line" ]; do L+=${line:0:1}; line=${line:1}; done
176
+ else
177
+ L=$line; line=""
178
+ fi
179
+ while [ -n "$L" ]; do
180
+ if [ ${#cur} -gt 512 ]; then # keep the tail buffer small
181
+ out+=${cur:0:$((${#cur} - 128))}; cur=${cur: -128}
182
+ fi
183
+ if [ -n "$qc" ]; then # inside a quote: look for the close
184
+ if [ "$qc" = "'" ] && [ "$qansi" = 0 ]; then
185
+ case $L in
186
+ *\'*) qin+=${L%%\'*}; L=${L#*\'}; _scrub_close_quote; qc="" ;;
187
+ *) qin+=$L; L="" ;;
188
+ esac
189
+ else
190
+ if [ "$qc" = '"' ]; then pre=${L%%[\"\\]*}; else pre=${L%%[\'\\]*}; fi
191
+ if [ "$pre" = "$L" ]; then
192
+ qin+=$L; L=""
193
+ else
194
+ qin+=$pre; L=${L#"$pre"}
195
+ if [ "${L:0:1}" = '\' ]; then
196
+ qin+=${L:0:2}; L=${L:2}
197
+ else
198
+ L=${L:1}; _scrub_close_quote; qc=""
199
+ fi
200
+ fi
201
+ fi
202
+ continue
203
+ fi
204
+ pre=${L%%[\'\"\\#<]*}
205
+ if [ "$pre" = "$L" ]; then cur+=$L; L=""; break; fi
206
+ cur+=$pre; L=${L#"$pre"}
207
+ c=${L:0:1}
208
+ case $c in
209
+ '\') cur+=${L:0:2}; L=${L:2} ;;
210
+ '#')
211
+ case ${cur: -1} in
212
+ ""|[[:space:]\;\&\|\(]) L="" ;;
213
+ *) cur+=$c; L=${L:1} ;;
214
+ esac ;;
215
+ '<')
216
+ if [ "${L:0:3}" = '<<<' ]; then
217
+ cur+='<<<'; L=${L:3}
218
+ elif [ "${L:0:2}" = '<<' ]; then
219
+ cur+='<<'; L=${L:2}
220
+ case $out$cur in
221
+ *'(('*) ;;
222
+ *)
223
+ if [[ $L =~ $_HD_WORD ]]; then
224
+ d=${BASH_REMATCH[1]}; w=${BASH_REMATCH[2]}
225
+ if [ ${#cur} -gt 122 ]; then tail=${cur: -122}; else tail=$cur; fi
226
+ tail=${tail%??}
227
+ [[ $tail =~ $_SH_HERE ]] || { hd_word=$w; [ -n "$d" ] && hd_dash=1 || hd_dash=0; }
228
+ fi ;;
229
+ esac
230
+ else
231
+ cur+='<'; L=${L:1}
232
+ fi ;;
233
+ *) # opening quote
234
+ qc=$c; qin=""; qexec=0; qansi=0; L=${L:1}
235
+ if [ "$c" = "'" ] && [ "${cur: -1}" = '$' ]; then
236
+ cur=${cur%?}; qansi=1
237
+ fi
238
+ if [ ${#cur} -gt 100 ]; then tail=${cur: -100}; else tail=$cur; fi
239
+ [[ $tail =~ $_EXEC_CTX ]] && qexec=1 ;;
240
+ esac
241
+ done
242
+ done
243
+ done <<< "$text"
244
+ [ -n "$qc" ] && cur+=$qc$qin # unterminated quote: keep as is
245
+ SCRUB_DEPTH=$((SCRUB_DEPTH - 1))
246
+ SCRUBBED=$out$cur
247
+ }
248
+ scrub_quotes "$COMMAND"
249
+ SHELL_TEXT=$SCRUBBED
250
+
251
+ # Hardcoded floor, used only when blocked-patterns.conf is missing: recursive
252
+ # rm (any flag spelling, flag before or after the target) of a catastrophic
253
+ # target — the same rule as the rm lines in blocked-patterns.conf. Subpaths
254
+ # such as /tmp/x are not blocked.
255
+ _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:]]+)*'
257
+ _PATHRM='(\\|/(usr/)?bin/)?rm'
258
+ _RM_FLAG='(-[a-zA-Z]*[rR][a-zA-Z]*|--recursive)'
259
+ _RM_ARGS='([[:space:]]+[^[:space:];&|]+)*'
260
+ _END='([[:space:];&|)`]|$)'
261
+ _RM_PREFIX="${_CMDPOS}${_WRAP}${_PATHRM}${_RM_ARGS}[[:space:]]+"
262
+ # _floor_rm_hits <target-regex> : does the scrubbed command recursively rm it?
263
+ _floor_rm_hits() {
264
+ grep -qiE -- "${_RM_PREFIX}(${_RM_FLAG}${_RM_ARGS}[[:space:]]+($1)${_END}|($1)${_RM_ARGS}[[:space:]]+${_RM_FLAG}${_END})" <<<"$SHELL_TEXT" 2>/dev/null
265
+ }
266
+
267
+ if [ ! -f "$PATTERNS_FILE" ]; then
268
+ # The pattern file ships with DoFlow, so a missing one means a broken install: record it on this
269
+ # machine (feature 046, IC-018) and go on exactly as before. Subshell, output discarded: nothing
270
+ # 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
272
+ if _floor_rm_hits '/+\*{0,2}'; then
273
+ echo "[pre-bash-guard] Catastrophic delete blocked — recursive rm of the root directory (/)" >&2
274
+ exit 2
275
+ fi
276
+ if _floor_rm_hits '(~[A-Za-z_][A-Za-z0-9_.-]*|~|\$HOME|\$\{HOME\})(/\*{0,2})?'; then
277
+ echo "[pre-bash-guard] Catastrophic delete blocked — recursive rm of the home directory" >&2
278
+ exit 2
279
+ fi
280
+ 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
+ echo "[pre-bash-guard] Catastrophic delete blocked — recursive rm of a system directory" >&2
282
+ exit 2
283
+ fi
284
+ # No patterns file beyond the hardcoded floor — allow everything else
285
+ # (fail open — don't block the agent).
286
+ exit 0
287
+ fi
288
+
289
+ # ── Pattern matching ──────────────────────────────────────────────────────────
290
+
291
+ while IFS=$'\t' read -r pattern reason exclude || [ -n "$pattern" ]; do
292
+ # Skip comments and empty lines
293
+ [ -z "$pattern" ] && continue
294
+ case "$pattern" in \#*) continue ;; esac
295
+
296
+ # Match pattern against command (case-insensitive, POSIX extended regex: the default macOS
297
+ # filesystem is case-insensitive, so RM and GIT run there).
298
+ # A bad regex makes grep exit 2, which "if" reads as no match (fail open).
299
+ # "--" stops grep from treating a pattern beginning with '-' (e.g. an
300
+ # exclude pattern like "--force-with-lease") as an option flag.
301
+ # Anchored shell-command patterns (they begin with the "(^|" command-position
302
+ # anchor) match the scrubbed text; every other pattern (the SQL ones)
303
+ # matches the full text, so statements inside quoted psql -c / heredocs are
304
+ # still caught.
305
+ case "$pattern" in '(^|'*) target=$SHELL_TEXT ;; *) target=$COMMAND ;; esac
306
+ matched=false
307
+ if grep -qiE -- "$pattern" <<<"$target" 2>/dev/null; then
308
+ matched=true
309
+ fi
310
+
311
+ # Optional third column: if the command also matches the exclude pattern,
312
+ # this pattern line is skipped entirely (approximates negative lookahead,
313
+ # which POSIX ERE cannot express — e.g. "--force-with-lease" excludes the
314
+ # "git push --force" block).
315
+ if [ "$matched" = "true" ] && [ -n "$exclude" ]; then
316
+ if grep -qiE -- "$exclude" <<<"$target" 2>/dev/null; then
317
+ matched=false
318
+ fi
319
+ fi
320
+
321
+ if [ "$matched" = "true" ]; then
322
+ echo "[pre-bash-guard] ${reason:-Command blocked by pre-bash-guard}" >&2
323
+ exit 2
324
+ fi
325
+ done < "$PATTERNS_FILE"
326
+
327
+ # No match — allow
328
+ exit 0