@khoavu882/doflow 0.0.0-stage → 2.0.0-beta.4
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.
- package/LICENSE +21 -0
- package/README.md +132 -2
- package/bin/doflow.js +44 -0
- package/core/.antigravity-plugin/hooks.json +39 -0
- package/core/.antigravity-plugin/mcp_config.json +18 -0
- package/core/.antigravity-plugin/plugin.json +31 -0
- package/core/.claude-plugin/marketplace.json +20 -0
- package/core/.claude-plugin/plugin.json +21 -0
- package/core/.codex-plugin/marketplace.json +20 -0
- package/core/.codex-plugin/plugin.json +35 -0
- package/core/.plugin/plugin.json +19 -0
- package/core/harnesses/antigravity/hooks/pre-implementation-gate.sh +9 -0
- package/core/harnesses/antigravity/hooks/stop-check.sh +10 -0
- package/core/harnesses/claude/hooks/lib.sh +304 -0
- package/core/harnesses/claude/hooks/mcp-tool-guard.sh +20 -0
- package/core/harnesses/claude/hooks/permission-audit.sh +47 -0
- package/core/harnesses/claude/hooks/post-compact.sh +74 -0
- package/core/harnesses/claude/hooks/post-edit-lint.sh +36 -0
- package/core/harnesses/claude/hooks/post-tool-failure.sh +47 -0
- package/core/harnesses/claude/hooks/pre-bash-guard.sh +20 -0
- package/core/harnesses/claude/hooks/pre-compact.sh +43 -0
- package/core/harnesses/claude/hooks/pre-implement-gate.sh +21 -0
- package/core/harnesses/claude/hooks/session-end.sh +89 -0
- package/core/harnesses/claude/hooks/session-start.sh +5 -0
- package/core/harnesses/claude/hooks/skill-config-audit.sh +39 -0
- package/core/harnesses/claude/hooks/stop-check.sh +5 -0
- package/core/harnesses/claude/hooks/subagent-audit.sh +7 -0
- package/core/harnesses/claude/hooks/user-prompt-submit.sh +5 -0
- package/core/harnesses/claude/settings/keybindings.json +20 -0
- package/core/harnesses/claude/settings/settings.json +201 -0
- package/core/harnesses/claude/statusline/doflow-statusline.sh +49 -0
- package/core/harnesses/codex/agents/core-implementer.toml +7 -0
- package/core/harnesses/codex/agents/quality-guardian.toml +8 -0
- package/core/harnesses/codex/agents/research-writer.toml +8 -0
- package/core/harnesses/codex/agents/spec-analyst.toml +8 -0
- package/core/harnesses/codex/agents/system-architect.toml +9 -0
- package/core/harnesses/codex/config/config.toml +10 -0
- package/core/harnesses/codex/hooks/hooks.json +122 -0
- package/core/harnesses/codex/hooks/lib.sh +335 -0
- package/core/harnesses/codex/hooks/mcp-tool-guard.sh +18 -0
- package/core/harnesses/codex/hooks/post-edit-lint.impl.sh +52 -0
- package/core/harnesses/codex/hooks/post-edit-lint.sh +6 -0
- package/core/harnesses/codex/hooks/pre-bash-guard.sh +18 -0
- package/core/harnesses/codex/hooks/pre-compact.impl.sh +46 -0
- package/core/harnesses/codex/hooks/pre-compact.sh +9 -0
- package/core/harnesses/codex/hooks/pre-implement-gate.sh +19 -0
- package/core/harnesses/codex/hooks/session-end.impl.sh +92 -0
- package/core/harnesses/codex/hooks/session-end.sh +5 -0
- package/core/harnesses/codex/hooks/session-start.sh +5 -0
- package/core/harnesses/codex/hooks/stop-check.sh +8 -0
- package/core/harnesses/codex/hooks/subagent-audit.sh +8 -0
- package/core/harnesses/codex/hooks/user-prompt-submit.sh +6 -0
- package/core/harnesses/gemini/hooks/hooks.json +77 -0
- package/core/harnesses/gemini/hooks/lib.sh +302 -0
- package/core/harnesses/gemini/hooks/mcp-tool-guard.sh +21 -0
- package/core/harnesses/gemini/hooks/post-edit-lint.sh +39 -0
- package/core/harnesses/gemini/hooks/pre-bash-guard.sh +21 -0
- package/core/harnesses/gemini/hooks/pre-compact.sh +38 -0
- package/core/harnesses/gemini/hooks/pre-implement-gate.sh +22 -0
- package/core/harnesses/gemini/hooks/session-end.impl.sh +89 -0
- package/core/harnesses/gemini/hooks/session-end.sh +5 -0
- package/core/harnesses/gemini/hooks/session-start.sh +5 -0
- package/core/harnesses/gemini/settings/adapter-defaults.json +4 -0
- package/core/harnesses/kiro/agents/doflow.json +58 -0
- package/core/harnesses/kiro/hooks/doflow.json +53 -0
- package/core/harnesses/kiro/hooks/lib.sh +324 -0
- package/core/harnesses/kiro/hooks/mcp-tool-guard.sh +9 -0
- package/core/harnesses/kiro/hooks/pre-bash-guard.sh +9 -0
- package/core/harnesses/kiro/hooks/pre-implement-gate.sh +9 -0
- package/core/harnesses/kiro/hooks/session-start.sh +9 -0
- package/core/harnesses/kiro/hooks/stop-check.sh +43 -0
- package/core/harnesses/shared/hooks/ENVELOPE_MIGRATION.md +39 -0
- package/core/harnesses/shared/hooks/adapters/antigravity.js +111 -0
- package/core/harnesses/shared/hooks/adapters/arg-fields.js +19 -0
- package/core/harnesses/shared/hooks/adapters/gemini.js +114 -0
- package/core/harnesses/shared/hooks/hooks.json +47 -0
- package/core/harnesses/shared/hooks/policies/blocked-patterns.conf +91 -0
- package/core/harnesses/shared/hooks/policies/capture-failure.sh +97 -0
- package/core/harnesses/shared/hooks/policies/deny-json.sh +29 -0
- package/core/harnesses/shared/hooks/policies/lib.sh +501 -0
- package/core/harnesses/shared/hooks/policies/mcp-policy.conf +21 -0
- package/core/harnesses/shared/hooks/policies/mcp-tool-guard.sh +91 -0
- package/core/harnesses/shared/hooks/policies/pre-bash-guard.sh +328 -0
- package/core/harnesses/shared/hooks/policies/pre-implementation-gate.sh +496 -0
- package/core/harnesses/shared/hooks/policies/prompt-nudge.jq +131 -0
- package/core/harnesses/shared/hooks/policies/session-context.sh +141 -0
- package/core/harnesses/shared/hooks/policies/stop-check.sh +264 -0
- package/core/harnesses/shared/hooks/policies/subagent-audit.sh +46 -0
- package/core/harnesses/shared/hooks/policies/user-prompt-submit.sh +235 -0
- package/core/harnesses/shared/hooks/stream-hook-runner.js +590 -0
- package/core/harnesses/shared/locator/doflow-run +87 -0
- package/core/registry/advice.json +101 -0
- package/core/registry/assets.json +792 -0
- package/core/registry/capabilities.json +120 -0
- package/core/registry/contracts.json +189 -0
- package/core/registry/external-tools.json +191 -0
- package/core/registry/harnesses.json +2062 -0
- package/core/registry/lifecycle.json +231 -0
- package/core/registry/mcp.json +18 -0
- package/core/registry/models.json +79 -0
- package/core/registry/readiness-templates.json +118 -0
- package/core/registry/routes.json +47 -0
- package/core/registry/storage.json +1061 -0
- package/core/registry/verification.json +258 -0
- package/core/registry/workflows.json +790 -0
- package/core/shared/agent-specs/core-implementer.md +73 -0
- package/core/shared/agent-specs/quality-guardian.md +28 -0
- package/core/shared/agent-specs/research-writer.md +31 -0
- package/core/shared/agent-specs/spec-analyst.md +33 -0
- package/core/shared/agent-specs/system-architect.md +29 -0
- package/core/shared/guidance/DOFLOW_CORE.md +8 -0
- package/core/shared/guidance/FLAGS.md +25 -0
- package/core/shared/guidance/PRINCIPLES.md +61 -0
- package/core/shared/guidance/VERSION +1 -0
- package/core/shared/guidance/mcp/MCP_Context7.md +18 -0
- package/core/shared/guidance/mcp/MCP_Sequential.md +17 -0
- package/core/shared/guidance/modes/MODE_Brainstorming.md +46 -0
- package/core/shared/guidance/modes/MODE_DeepResearch.md +69 -0
- package/core/shared/guidance/modes/MODE_Introspection.md +33 -0
- package/core/shared/guidance/modes/MODE_Orchestration.md +57 -0
- package/core/shared/guidance/modes/MODE_Task_Management.md +74 -0
- package/core/shared/guidance/pointers/claude-gemini.md +2 -0
- package/core/shared/guidance/pointers/codex.md +6 -0
- package/core/shared/guidance/references/ARTIFACT_FORMAT.md +373 -0
- package/core/shared/guidance/references/ARTIFACT_VOICE.md +104 -0
- package/core/shared/guidance/references/CONSTITUTION_BASE.md +47 -0
- package/core/shared/guidance/references/DIAGRAM_GUIDE.md +161 -0
- package/core/shared/guidance/references/DOFLOW_CHAIN.md +87 -0
- package/core/shared/guidance/references/EVIDENCE_LEDGER.md +93 -0
- package/core/shared/guidance/references/MODEL_SELECTION.md +74 -0
- package/core/shared/guidance/references/ORCHESTRATION.md +36 -0
- package/core/shared/guidance/references/RESEARCH_CONFIG.md +21 -0
- package/core/shared/guidance/references/WORKFLOW_HANDOFF.md +81 -0
- package/core/shared/guidance/rules/RULE_01_SAFETY.md +25 -0
- package/core/shared/guidance/rules/RULE_02_WORKFLOW.md +23 -0
- package/core/shared/guidance/rules/RULE_03_QUALITY.md +14 -0
- package/core/shared/guidance/rules/RULE_04_QUESTIONS.md +46 -0
- package/core/shared/scripts/doflow/assets/mermaid-theme.json +46 -0
- package/core/shared/scripts/doflow/bash/do-exec-paths.sh +167 -0
- package/core/shared/scripts/doflow/bash/do-git-state.sh +546 -0
- package/core/shared/scripts/doflow/bash/do-parallel-check.sh +208 -0
- package/core/shared/scripts/doflow/bash/do-paths.sh +347 -0
- package/core/shared/scripts/doflow/bash/do-prereqs.sh +66 -0
- package/core/shared/scripts/doflow/bash/do-review-package.sh +127 -0
- package/core/shared/scripts/doflow/bash/do-task-brief.sh +698 -0
- package/core/shared/scripts/doflow/bash/render-audit.sh +224 -0
- package/core/shared/scripts/doflow/bash/render-diagrams.sh +177 -0
- package/core/shared/scripts/doflow/bash/render-puml.sh +223 -0
- package/core/shared/scripts/doflow/bash/sync-context.sh +66 -0
- package/core/shared/scripts/doflow/bash/validate-artifacts.sh +526 -0
- package/core/shared/scripts/doflow/bin/doflow-run +592 -0
- package/core/shared/skills/do/SKILL.md +128 -0
- package/core/shared/skills/do/references/estimation.md +13 -0
- package/core/shared/skills/do/references/pm_routing.md +25 -0
- package/core/shared/skills/do/references/tool_matrix.md +52 -0
- package/core/shared/skills/do-brainstorm/SKILL.md +252 -0
- package/core/shared/skills/do-code-review/README.md +49 -0
- package/core/shared/skills/do-code-review/SKILL.md +333 -0
- package/core/shared/skills/do-code-review/assets/sample_c_clean.c +71 -0
- package/core/shared/skills/do-code-review/assets/sample_c_smells.c +66 -0
- package/core/shared/skills/do-code-review/assets/sample_cpp_shift.cpp +19 -0
- package/core/shared/skills/do-code-review/assets/sample_csharp_clean.cs +100 -0
- package/core/shared/skills/do-code-review/assets/sample_csharp_smells.cs +78 -0
- package/core/shared/skills/do-code-review/assets/sample_java_clean.java +55 -0
- package/core/shared/skills/do-code-review/assets/sample_java_smells.java +56 -0
- package/core/shared/skills/do-code-review/assets/sample_json_clean.json +7 -0
- package/core/shared/skills/do-code-review/assets/sample_markdown_clean.md +30 -0
- package/core/shared/skills/do-code-review/assets/sample_markdown_smells.md +29 -0
- package/core/shared/skills/do-code-review/assets/sample_shell_heredoc.sh +38 -0
- package/core/shared/skills/do-code-review/assets/sample_shell_smells.sh +15 -0
- package/core/shared/skills/do-code-review/assets/sample_typescript_strings.ts +36 -0
- package/core/shared/skills/do-code-review/assets/sample_yaml_smells.yaml +6 -0
- package/core/shared/skills/do-code-review/content-types/config.md +83 -0
- package/core/shared/skills/do-code-review/content-types/markdown.md +132 -0
- package/core/shared/skills/do-code-review/expected_outputs/sample_c_clean_quality.json +79 -0
- package/core/shared/skills/do-code-review/expected_outputs/sample_c_smells_quality.json +169 -0
- package/core/shared/skills/do-code-review/expected_outputs/sample_cpp_shift_quality.json +49 -0
- package/core/shared/skills/do-code-review/expected_outputs/sample_csharp_clean_quality.json +149 -0
- package/core/shared/skills/do-code-review/expected_outputs/sample_csharp_smells_quality.json +157 -0
- package/core/shared/skills/do-code-review/expected_outputs/sample_java_clean_quality.json +67 -0
- package/core/shared/skills/do-code-review/expected_outputs/sample_java_smells_quality.json +97 -0
- package/core/shared/skills/do-code-review/expected_outputs/sample_json_clean_quality.json +33 -0
- package/core/shared/skills/do-code-review/expected_outputs/sample_markdown_clean_quality.json +1 -0
- package/core/shared/skills/do-code-review/expected_outputs/sample_markdown_smells_quality.json +16 -0
- package/core/shared/skills/do-code-review/expected_outputs/sample_shell_heredoc_quality.json +54 -0
- package/core/shared/skills/do-code-review/expected_outputs/sample_shell_smells_quality.json +91 -0
- package/core/shared/skills/do-code-review/expected_outputs/sample_typescript_strings_quality.json +60 -0
- package/core/shared/skills/do-code-review/expected_outputs/sample_yaml_smells_quality.json +46 -0
- package/core/shared/skills/do-code-review/languages/c.md +103 -0
- package/core/shared/skills/do-code-review/languages/cpp.md +103 -0
- package/core/shared/skills/do-code-review/languages/csharp.md +97 -0
- package/core/shared/skills/do-code-review/languages/dart.md +108 -0
- package/core/shared/skills/do-code-review/languages/go.md +92 -0
- package/core/shared/skills/do-code-review/languages/java.md +103 -0
- package/core/shared/skills/do-code-review/languages/kotlin.md +88 -0
- package/core/shared/skills/do-code-review/languages/php.md +109 -0
- package/core/shared/skills/do-code-review/languages/python.md +94 -0
- package/core/shared/skills/do-code-review/languages/ruby.md +105 -0
- package/core/shared/skills/do-code-review/languages/rust.md +99 -0
- package/core/shared/skills/do-code-review/languages/shell.md +90 -0
- package/core/shared/skills/do-code-review/languages/swift.md +88 -0
- package/core/shared/skills/do-code-review/languages/typescript.md +97 -0
- package/core/shared/skills/do-code-review/review-policy.json +47 -0
- package/core/shared/skills/do-code-review/rules/universal.md +49 -0
- package/core/shared/skills/do-code-review/scripts/code_quality_checker.py +1696 -0
- package/core/shared/skills/do-code-review/scripts/doc_quality_checker.py +532 -0
- package/core/shared/skills/do-code-review/scripts/pr_analyzer.py +620 -0
- package/core/shared/skills/do-code-review/scripts/review_report_generator.py +505 -0
- package/core/shared/skills/do-constitution/SKILL.md +72 -0
- package/core/shared/skills/do-design/SKILL.md +212 -0
- package/core/shared/skills/do-diagnose/SKILL.md +156 -0
- package/core/shared/skills/do-diagnose/references/code_audit.md +15 -0
- package/core/shared/skills/do-diagnose/references/refactoring.md +12 -0
- package/core/shared/skills/do-diagnose/references/root_cause.md +17 -0
- package/core/shared/skills/do-document/SKILL.md +81 -0
- package/core/shared/skills/do-document/references/api-reference.md +42 -0
- package/core/shared/skills/do-document/references/deep_research.md +18 -0
- package/core/shared/skills/do-document/references/embedded-research.md +11 -0
- package/core/shared/skills/do-document/references/implementation-flow.md +105 -0
- package/core/shared/skills/do-document/references/index_generator.md +9 -0
- package/core/shared/skills/do-document/references/user-guide.md +22 -0
- package/core/shared/skills/do-execute-plan/SKILL.md +261 -0
- package/core/shared/skills/do-execute-plan/references/handoff_record.md +57 -0
- package/core/shared/skills/do-execute-plan/references/parallel_dispatch.md +92 -0
- package/core/shared/skills/do-execute-plan/references/readiness_gate.md +155 -0
- package/core/shared/skills/do-execute-plan/references/run_position.md +63 -0
- package/core/shared/skills/do-execute-plan/references/scaffold.md +441 -0
- package/core/shared/skills/do-execute-plan/references/task_attempts.md +41 -0
- package/core/shared/skills/do-flow/SKILL.md +186 -0
- package/core/shared/skills/do-flow/references/task_classes.md +134 -0
- package/core/shared/skills/do-git/SKILL.md +115 -0
- package/core/shared/skills/do-git/references/hotfix-ritual.md +44 -0
- package/core/shared/skills/do-git/references/lifecycle-policy.md +54 -0
- package/core/shared/skills/do-git/references/release-ritual.md +64 -0
- package/core/shared/skills/do-implement/SKILL.md +222 -0
- package/core/shared/skills/do-plan/SKILL.md +219 -0
- package/core/shared/skills/do-test/SKILL.md +113 -0
- package/core/shared/templates/doflow/constitution-template.md +28 -0
- package/core/shared/templates/doflow/data-model-template.md +169 -0
- package/core/shared/templates/doflow/design-template.md +193 -0
- package/core/shared/templates/doflow/external-contract-template.md +35 -0
- package/core/shared/templates/doflow/intent-template.md +45 -0
- package/core/shared/templates/doflow/plan-template.md +151 -0
- package/core/shared/templates/doflow/question-log-template.md +51 -0
- package/core/shared/templates/doflow/requirement-template.md +126 -0
- package/core/shared/templates/doflow/specs-template.md +55 -0
- package/core/shared/templates/doflow/state-template.md +59 -0
- package/core/shared/workflows/do-flow-chain.md +17 -0
- package/package.json +48 -4
- package/src/adapters/antigravity/index.js +631 -0
- package/src/adapters/claude/index.js +548 -0
- package/src/adapters/claude/mcp.js +94 -0
- package/src/adapters/codex/agents.js +208 -0
- package/src/adapters/codex/config.js +272 -0
- package/src/adapters/codex/hooks.js +203 -0
- package/src/adapters/codex/index.js +707 -0
- package/src/adapters/codex/mcp.js +271 -0
- package/src/adapters/codex/native-projection.js +34 -0
- package/src/adapters/copilot/index.js +413 -0
- package/src/adapters/copy-tree.js +620 -0
- package/src/adapters/gemini/hooks.js +210 -0
- package/src/adapters/gemini/index.js +390 -0
- package/src/adapters/hook-commands.js +60 -0
- package/src/adapters/index.js +106 -0
- package/src/adapters/kiro/index.js +310 -0
- package/src/adapters/mcp-entries.js +331 -0
- package/src/adapters/opencode/index.js +466 -0
- package/src/adapters/pi/index.js +279 -0
- package/src/adapters/pi/json-members.js +185 -0
- package/src/adapters/pi/mcp.js +373 -0
- package/src/adapters/resolve-source.js +19 -0
- package/src/cli/commands/install.js +218 -0
- package/src/cli/commands/list-backups.js +21 -0
- package/src/cli/commands/reconcile.js +120 -0
- package/src/cli/commands/remove.js +82 -0
- package/src/cli/commands/rollback.js +172 -0
- package/src/cli/commands/self-update.js +33 -0
- package/src/cli/commands/status.js +138 -0
- package/src/cli/commands/tools.js +92 -0
- package/src/cli/commands/update.js +162 -0
- package/src/cli/index.js +568 -0
- package/src/cli/runtime-commands.js +281 -0
- package/src/cli/shared.js +218 -0
- package/src/helper/bash-helper.js +34 -0
- package/src/helper/git.js +24 -0
- package/src/helper/guardrails.js +49 -0
- package/src/helper/harness-paths.js +140 -0
- package/src/helper/marker-merge.js +116 -0
- package/src/helper/prompt.js +61 -0
- package/src/helper/repo-root.js +29 -0
- package/src/helper/settings-merge.js +151 -0
- package/src/helper/settings-scope.js +33 -0
- package/src/helper/toml.js +244 -0
- package/src/install/backup-set.js +149 -0
- package/src/install/backup.js +724 -0
- package/src/install/context.js +58 -0
- package/src/install/manifest.js +145 -0
- package/src/install/mcp.js +254 -0
- package/src/install/paths.js +84 -0
- package/src/install/targets.js +90 -0
- package/src/install/tool-lifecycle.js +151 -0
- package/src/lifecycle/bash-availability.js +25 -0
- package/src/lifecycle/index.js +812 -0
- package/src/lifecycle/mcp-index.js +28 -0
- package/src/lifecycle/policies.js +73 -0
- package/src/lifecycle/view.js +175 -0
- package/src/registry/index.js +611 -0
- package/src/release/build-package.js +91 -0
- package/src/release/changelog-section.js +70 -0
- package/src/release/sync-plugin-versions.js +66 -0
- package/src/runtime/advice/cli.js +283 -0
- package/src/runtime/advice/client.js +324 -0
- package/src/runtime/advice/config.js +189 -0
- package/src/runtime/advice/doctor.js +169 -0
- package/src/runtime/advice/endpoint-guard.js +134 -0
- package/src/runtime/advice/kinds.js +154 -0
- package/src/runtime/advice/providers/ollama-systemone.js +209 -0
- package/src/runtime/advice/record.js +166 -0
- package/src/runtime/advice/registry.js +170 -0
- package/src/runtime/advice/strength.js +66 -0
- package/src/runtime/brief-tools.js +342 -0
- package/src/runtime/c4-project.js +371 -0
- package/src/runtime/capability-router.js +484 -0
- package/src/runtime/checkouts.js +170 -0
- package/src/runtime/claims.js +468 -0
- package/src/runtime/cli-result.js +55 -0
- package/src/runtime/cli.js +678 -0
- package/src/runtime/command-detect.js +516 -0
- package/src/runtime/context-pack.js +492 -0
- package/src/runtime/decision-register.js +493 -0
- package/src/runtime/evidence-ledger.js +338 -0
- package/src/runtime/failure/capture.js +272 -0
- package/src/runtime/failure/classifier.js +68 -0
- package/src/runtime/failure/cli.js +178 -0
- package/src/runtime/failure/home.js +64 -0
- package/src/runtime/failure/store.js +226 -0
- package/src/runtime/feature-resolve.js +79 -0
- package/src/runtime/freshness.js +177 -0
- package/src/runtime/health.js +863 -0
- package/src/runtime/history-compactor.js +237 -0
- package/src/runtime/implementation-gate.js +321 -0
- package/src/runtime/inventory/coverage.js +218 -0
- package/src/runtime/inventory/identity.js +65 -0
- package/src/runtime/inventory/index.js +705 -0
- package/src/runtime/inventory/precedence.js +134 -0
- package/src/runtime/inventory/read-scopes.js +131 -0
- package/src/runtime/inventory/siblings.js +192 -0
- package/src/runtime/knowledge/chunker.js +124 -0
- package/src/runtime/knowledge/hybrid.js +149 -0
- package/src/runtime/knowledge/index-store.js +145 -0
- package/src/runtime/knowledge/retrieval.js +194 -0
- package/src/runtime/leak-scan.js +185 -0
- package/src/runtime/lifecycle/cli.js +276 -0
- package/src/runtime/lifecycle/event-store.js +340 -0
- package/src/runtime/lifecycle/fold.js +353 -0
- package/src/runtime/lifecycle/followup.js +432 -0
- package/src/runtime/lifecycle/goal.js +249 -0
- package/src/runtime/lifecycle/intent-writer.js +86 -0
- package/src/runtime/lifecycle/overview.js +292 -0
- package/src/runtime/lifecycle/release.js +241 -0
- package/src/runtime/lifecycle/report-store.js +221 -0
- package/src/runtime/lifecycle/retention.js +212 -0
- package/src/runtime/lifecycle/root.js +71 -0
- package/src/runtime/lifecycle/status.js +353 -0
- package/src/runtime/lifecycle/store-upkeep.js +393 -0
- package/src/runtime/locator-resolve.js +158 -0
- package/src/runtime/mask.js +210 -0
- package/src/runtime/mcp-consultations.js +412 -0
- package/src/runtime/mcp-reach.js +157 -0
- package/src/runtime/model-router.js +153 -0
- package/src/runtime/outcome.js +467 -0
- package/src/runtime/reach.js +148 -0
- package/src/runtime/readiness-record.js +150 -0
- package/src/runtime/readiness.js +435 -0
- package/src/runtime/recovery.js +282 -0
- package/src/runtime/research-request.js +231 -0
- package/src/runtime/retrieval-plan.js +578 -0
- package/src/runtime/scaffold/artifacts.js +217 -0
- package/src/runtime/scaffold/fingerprint.js +56 -0
- package/src/runtime/scaffold/generate.js +911 -0
- package/src/runtime/scaffold/languages.js +245 -0
- package/src/runtime/storage/cli.js +64 -0
- package/src/runtime/storage/engine.js +249 -0
- package/src/runtime/storage/registry.js +130 -0
- package/src/runtime/storage/roots.js +63 -0
- package/src/runtime/storage/rules.js +282 -0
- package/src/runtime/storage/upkeep.js +243 -0
- package/src/runtime/storage/work-status.js +326 -0
- package/src/runtime/task-attempts.js +415 -0
- package/src/runtime/task-classifier.js +550 -0
- package/src/runtime/task-scope.js +130 -0
- package/src/runtime/task-state.js +176 -0
- package/src/runtime/trace/indicators.js +235 -0
- package/src/runtime/trace/ledger.js +626 -0
- package/src/runtime/trace/render.js +76 -0
- package/src/runtime/trace/views.js +459 -0
- package/src/runtime/verification/contract-runner.js +341 -0
- package/src/runtime/verification/engine.js +1461 -0
- package/src/runtime/verification/registry.js +130 -0
- package/src/runtime/verification/scope-bound.js +418 -0
- package/src/runtime/verification/test-selection.js +172 -0
- package/src/runtime/workflow-engine.js +588 -0
- package/src/runtime/workflow-orchestrator.js +953 -0
- package/src/runtime/worktree.js +340 -0
- package/src/state/index.js +193 -0
- package/src/state/lockfile.js +136 -0
- package/src/state/run-lock.js +408 -0
- package/types/node-commonjs.d.ts +68 -0
- 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
|