@khoavu882/doflow 2.0.0-beta.5 → 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.
- package/README.md +12 -11
- package/bin/doflow.js +21 -11
- package/core/.antigravity-plugin/plugin.json +1 -2
- package/core/.claude-plugin/plugin.json +1 -1
- package/core/.codex-plugin/plugin.json +1 -1
- package/core/.plugin/plugin.json +1 -1
- package/core/harnesses/claude/hooks/lib.sh +43 -24
- package/core/harnesses/claude/hooks/permission-audit.sh +3 -0
- package/core/harnesses/claude/hooks/post-compact.sh +35 -32
- package/core/harnesses/claude/hooks/post-edit-lint.sh +2 -0
- package/core/harnesses/claude/hooks/post-shell-observe.sh +48 -0
- package/core/harnesses/claude/hooks/post-tool-failure.sh +3 -0
- package/core/harnesses/claude/hooks/pre-compact.sh +23 -27
- package/core/harnesses/claude/hooks/session-end.sh +23 -10
- package/core/harnesses/claude/hooks/skill-config-audit.sh +3 -0
- package/core/harnesses/claude/settings/settings.json +18 -0
- package/core/harnesses/claude/statusline/doflow-statusline.sh +1 -0
- package/core/harnesses/codex/agents/core-implementer.toml +1 -0
- package/core/harnesses/codex/agents/delivery-lead.toml +10 -0
- package/core/harnesses/codex/agents/quality-guardian.toml +1 -1
- package/core/harnesses/codex/agents/research-writer.toml +1 -1
- package/core/harnesses/codex/agents/reviewer.toml +10 -0
- package/core/harnesses/codex/agents/spec-analyst.toml +1 -1
- package/core/harnesses/codex/agents/system-architect.toml +1 -1
- package/core/harnesses/codex/hooks/lib.sh +44 -25
- package/core/harnesses/codex/hooks/post-edit-lint.impl.sh +3 -1
- package/core/harnesses/codex/hooks/pre-compact.impl.sh +29 -26
- package/core/harnesses/codex/hooks/session-end.impl.sh +23 -10
- package/core/harnesses/codex/hooks/subagent-audit.sh +1 -0
- package/core/harnesses/copilot/hooks/doflow-lib.sh +93 -0
- package/core/harnesses/copilot/hooks/doflow-mcp-tool-guard.sh +9 -0
- package/core/harnesses/copilot/hooks/doflow-pre-bash-guard.sh +9 -0
- package/core/harnesses/copilot/hooks/doflow-pre-implement-gate.sh +9 -0
- package/core/harnesses/copilot/hooks/doflow-session-start.sh +9 -0
- package/core/harnesses/copilot/hooks/doflow-stop-check.sh +9 -0
- package/core/harnesses/copilot/hooks/doflow-subagent-start.sh +9 -0
- package/core/harnesses/copilot/hooks/doflow-subagent-stop.sh +9 -0
- package/core/harnesses/copilot/hooks/doflow.json +57 -0
- package/core/harnesses/kiro/agents/doflow.json +1 -1
- package/core/harnesses/kiro/hooks/lib.sh +26 -6
- package/core/harnesses/kiro/hooks/mcp-tool-guard.sh +1 -0
- package/core/harnesses/kiro/hooks/pre-bash-guard.sh +1 -0
- package/core/harnesses/kiro/hooks/pre-implement-gate.sh +1 -0
- package/core/harnesses/kiro/hooks/session-start.sh +1 -0
- package/core/harnesses/kiro/hooks/stop-check.sh +1 -0
- package/core/harnesses/pi/extensions/doflow-guard.js +8 -0
- package/core/harnesses/shared/hooks/ENVELOPE_MIGRATION.md +0 -1
- package/core/harnesses/shared/hooks/bridge/bridge.sh +102 -9
- package/core/harnesses/shared/hooks/bridge/envelope.jq +87 -18
- package/core/harnesses/shared/hooks/bridge/observe-model.sh +75 -0
- package/core/harnesses/shared/hooks/bridge/respond.sh +10 -2
- package/core/harnesses/shared/hooks/policies/blocked-patterns.conf +28 -14
- package/core/harnesses/shared/hooks/policies/capture-failure.sh +48 -15
- package/core/harnesses/shared/hooks/policies/compact-text.sh +46 -0
- package/core/harnesses/shared/hooks/policies/contract.sh +3 -0
- package/core/harnesses/shared/hooks/policies/deny-json.sh +2 -11
- package/core/harnesses/shared/hooks/policies/emission-rules.sh +37 -0
- package/core/harnesses/shared/hooks/policies/emission.jq +209 -0
- package/core/harnesses/shared/hooks/policies/emission.sh +383 -0
- package/core/harnesses/shared/hooks/policies/identity.sh +177 -0
- package/core/harnesses/shared/hooks/policies/lib.sh +63 -40
- package/core/harnesses/shared/hooks/policies/mcp-tool-guard.sh +3 -2
- package/core/harnesses/shared/hooks/policies/pre-bash-guard.sh +213 -12
- package/core/harnesses/shared/hooks/policies/pre-implementation-gate.sh +114 -38
- package/core/harnesses/shared/hooks/policies/session-context.sh +30 -1
- package/core/harnesses/shared/hooks/policies/stop-check.sh +20 -9
- package/core/harnesses/shared/hooks/policies/subagent-audit.sh +5 -2
- package/core/harnesses/shared/hooks/policies/summary-store.sh +347 -0
- package/core/harnesses/shared/hooks/policies/user-prompt-submit.sh +60 -155
- package/core/harnesses/shared/hooks/stream-hook-runner.js +47 -8
- package/core/harnesses/shared/locator/doflow-run +2 -3
- package/core/registry/advice.json +3 -3
- package/core/registry/assets.json +55 -82
- package/core/registry/capabilities.json +12 -0
- package/core/registry/contracts.json +58 -31
- package/core/registry/contribution-points.json +32 -0
- package/core/registry/gates.json +32 -0
- package/core/registry/guidance-caps.json +40 -0
- package/core/registry/harnesses.json +1442 -363
- package/core/registry/lifecycle.json +485 -304
- package/core/registry/mcp.json +5 -1
- package/core/registry/models.json +7 -1
- package/core/registry/package-templates/README.md +19 -0
- package/core/registry/package-templates/agent/files/agent.md +9 -0
- package/core/registry/package-templates/agent/template.json +4 -0
- package/core/registry/package-templates/capability-provider/files/provider.json +9 -0
- package/core/registry/package-templates/capability-provider/template.json +11 -0
- package/core/registry/package-templates/debate-preset/files/preset.json +26 -0
- package/core/registry/package-templates/debate-preset/template.json +4 -0
- package/core/registry/package-templates/review-preset/files/preset.json +30 -0
- package/core/registry/package-templates/review-preset/template.json +4 -0
- package/core/registry/package-templates/skill/files/SKILL.md +8 -0
- package/core/registry/package-templates/skill/template.json +4 -0
- package/core/registry/package-templates/worker/files/worker.json +92 -0
- package/core/registry/package-templates/worker/template.json +11 -0
- package/core/registry/packages/doflow/doflow-package.json +15 -0
- package/core/registry/packages/doflow/presets/debate-3.json +26 -0
- package/core/registry/protocols.json +61 -0
- package/core/registry/routes.json +17 -0
- package/core/registry/rules.json +431 -0
- package/core/registry/settings.json +276 -0
- package/core/registry/storage.json +679 -31
- package/core/registry/telemetry.json +236 -0
- package/core/registry/transcripts.json +142 -0
- package/core/registry/verification.json +76 -1
- package/core/registry/workflows.json +55 -0
- package/core/shared/agent-specs/core-implementer.md +3 -0
- package/core/shared/agent-specs/delivery-lead.md +68 -0
- package/core/shared/agent-specs/quality-guardian.md +5 -1
- package/core/shared/agent-specs/research-writer.md +10 -3
- package/core/shared/agent-specs/reviewer.md +53 -0
- package/core/shared/agent-specs/spec-analyst.md +5 -6
- package/core/shared/agent-specs/system-architect.md +5 -1
- package/core/shared/guidance/DOFLOW_CORE.md +1 -5
- package/core/shared/guidance/modes/MODE_DeepResearch.md +1 -1
- package/core/shared/guidance/modes/MODE_Orchestration.md +4 -3
- package/core/shared/guidance/modes/MODE_Task_Management.md +14 -14
- package/core/shared/guidance/pointers/codex.md +1 -4
- package/core/shared/guidance/references/ARTIFACT_FORMAT.md +30 -16
- package/core/shared/guidance/references/ARTIFACT_VOICE.md +3 -2
- package/core/shared/guidance/references/CONSTITUTION_BASE.md +17 -15
- package/core/shared/guidance/references/DIAGRAM_GUIDE.md +1 -1
- package/core/shared/guidance/references/DOFLOW_CHAIN.md +17 -19
- package/core/shared/guidance/references/EVIDENCE_LEDGER.md +7 -8
- package/core/shared/guidance/references/MODEL_SELECTION.md +5 -3
- package/core/shared/guidance/references/ORCHESTRATION.md +1 -2
- package/core/shared/guidance/rules/RULES.md +45 -0
- package/core/shared/scripts/doflow/bash/do-args.sh +37 -0
- package/core/shared/scripts/doflow/bash/do-exec-paths.sh +4 -0
- package/core/shared/scripts/doflow/bash/do-git-state.sh +15 -4
- package/core/shared/scripts/doflow/bash/do-parallel-check.sh +4 -0
- package/core/shared/scripts/doflow/bash/do-paths.sh +40 -2
- package/core/shared/scripts/doflow/bash/do-prereqs.sh +2 -1
- package/core/shared/scripts/doflow/bash/do-review-package.sh +4 -0
- package/core/shared/scripts/doflow/bash/do-task-brief.sh +58 -16
- package/core/shared/scripts/doflow/bash/render-audit.sh +26 -2
- package/core/shared/scripts/doflow/bash/render-diagrams.sh +1 -0
- package/core/shared/scripts/doflow/bash/render-puml.sh +2 -1
- package/core/shared/scripts/doflow/bash/validate-artifacts.sh +48 -4
- package/core/shared/scripts/doflow/bin/doflow-run +149 -34
- package/core/shared/skills/do/SKILL.md +12 -10
- package/core/shared/skills/do/references/advice_calls.md +26 -0
- package/core/shared/skills/do/references/pm_routing.md +1 -2
- package/core/shared/skills/do/references/program_mode.md +31 -0
- package/core/shared/skills/do-brainstorm/SKILL.md +20 -74
- package/core/shared/skills/do-brainstorm/references/handoff_branches.md +35 -0
- package/core/shared/skills/do-brainstorm/references/intent_seed.md +21 -0
- package/core/shared/skills/do-brainstorm/references/round_log.md +17 -0
- package/core/shared/skills/do-code-review/SKILL.md +41 -144
- package/core/shared/skills/do-code-review/content-types/markdown.md +24 -2
- package/core/shared/skills/do-code-review/references/tools.md +90 -0
- package/core/shared/skills/do-code-review/scripts/doc_quality_checker.py +549 -7
- package/core/shared/skills/do-design/SKILL.md +18 -17
- package/core/shared/skills/do-diagnose/SKILL.md +14 -4
- package/core/shared/skills/do-document/SKILL.md +11 -1
- package/core/shared/skills/do-document/references/deep_research.md +1 -2
- package/core/shared/skills/do-document/references/embedded-research.md +18 -6
- package/core/shared/skills/do-document/references/implementation-flow.md +5 -6
- package/core/shared/skills/do-execute-plan/SKILL.md +15 -58
- package/core/shared/skills/do-execute-plan/references/handoff_record.md +7 -2
- package/core/shared/skills/do-execute-plan/references/parallel_dispatch.md +13 -0
- package/core/shared/skills/do-execute-plan/references/readiness_gate.md +26 -1
- package/core/shared/skills/do-execute-plan/references/run_position.md +13 -1
- package/core/shared/skills/do-execute-plan/references/scaffold.md +17 -9
- package/core/shared/skills/do-execute-plan/references/state_checkpoint.md +11 -0
- package/core/shared/skills/do-execute-plan/references/task_attempts.md +78 -24
- package/core/shared/skills/do-flow/SKILL.md +8 -9
- package/core/shared/skills/do-flow/references/task_classes.md +2 -2
- package/core/shared/skills/do-git/SKILL.md +4 -0
- package/core/shared/skills/do-implement/SKILL.md +4 -7
- package/core/shared/skills/do-plan/SKILL.md +26 -15
- package/core/shared/skills/do-test/SKILL.md +7 -4
- package/core/shared/templates/doflow/constitution-template.md +9 -3
- package/core/shared/templates/doflow/data-model-template.md +1 -1
- package/core/shared/templates/doflow/design-template.md +113 -16
- package/core/shared/templates/doflow/plan-template.md +11 -10
- package/core/shared/templates/doflow/question-log-template.md +14 -2
- package/core/shared/templates/doflow/requirement-template.md +1 -1
- package/core/worker-evidence/antigravity/checks.json +14 -0
- package/core/worker-evidence/codex/2026-10-18-cli-check.json +107 -0
- package/core/worker-evidence/codex/2026-10-18-live-run-edit.json +73 -0
- package/core/worker-evidence/codex/2026-10-18-live-run-read-only.json +62 -0
- package/core/worker-evidence/codex/2026-10-24-cli-check.json +126 -0
- package/core/worker-evidence/codex/checks.json +38 -0
- package/package.json +10 -6
- package/src/adapters/antigravity/index.js +143 -66
- package/src/adapters/claude/index.js +24 -4
- package/src/adapters/codex/agents.js +25 -15
- package/src/adapters/codex/index.js +48 -13
- package/src/adapters/codex/native-projection.js +6 -2
- package/src/adapters/copilot/index.js +58 -23
- package/src/adapters/copy-tree.js +290 -44
- package/src/adapters/guidance-manifest.js +71 -0
- package/src/adapters/guidance-pointer.js +19 -0
- package/src/adapters/hook-commands.js +6 -10
- package/src/adapters/index.js +1 -0
- package/src/adapters/kiro/index.js +23 -12
- package/src/adapters/opencode/index.js +8 -8
- package/src/adapters/pi/hooks.js +2 -1
- package/src/adapters/pi/index.js +14 -7
- package/src/adapters/resolve-source.js +26 -2
- package/src/cli/commands/install.js +2 -1
- package/src/cli/commands/reconcile.js +53 -9
- package/src/cli/commands/remove.js +2 -2
- package/src/cli/commands/rollback.js +6 -3
- package/src/cli/commands/self-update.js +18 -9
- package/src/cli/commands/status.js +21 -2
- package/src/cli/commands/ui.js +99 -0
- package/src/cli/commands/update.js +2 -1
- package/src/cli/index.js +322 -29
- package/src/cli/runtime-commands.js +209 -57
- package/src/cli/shared.js +0 -2
- package/src/helper/git.js +1 -1
- package/src/helper/guardrails.js +1 -1
- package/src/helper/marker-merge.js +31 -13
- package/src/helper/package-ids.js +37 -0
- package/src/helper/semver.js +94 -0
- package/src/install/backup.js +105 -15
- package/src/install/context.js +1 -1
- package/src/install/targets.js +31 -16
- package/src/lifecycle/coverage.js +20 -3
- package/src/lifecycle/hook-tier.js +160 -0
- package/src/lifecycle/index.js +412 -78
- package/src/lifecycle/retired-harnesses.js +318 -0
- package/src/lifecycle/view.js +35 -15
- package/src/registry/index.js +551 -26
- package/src/registry/worker-ids.js +45 -0
- package/src/release/build-package.js +0 -3
- package/src/release/docs-blocks.js +492 -0
- package/src/release/preflight.js +425 -0
- package/src/release/rehearse.js +401 -0
- package/src/release/release-workflow.js +733 -0
- package/src/release/sync-plugin-versions.js +43 -7
- package/src/runtime/advice/bench-gate.js +25 -0
- package/src/runtime/advice/cli.js +59 -16
- package/src/runtime/advice/client.js +32 -9
- package/src/runtime/advice/config.js +98 -133
- package/src/runtime/advice/doctor.js +1 -1
- package/src/runtime/advice/elevation.js +97 -0
- package/src/runtime/advice/endpoint-guard.js +9 -3
- package/src/runtime/advice/mode.js +37 -0
- package/src/runtime/advice/record.js +18 -5
- package/src/runtime/advice/registry.js +4 -1
- package/src/runtime/advice/shadow-config.js +229 -0
- package/src/runtime/advice/shadow-dispatcher.js +276 -0
- package/src/runtime/brief-rules.js +81 -0
- package/src/runtime/brief-tools.js +111 -34
- package/src/runtime/candidate.js +20 -11
- package/src/runtime/capabilities/executor.js +450 -0
- package/src/runtime/capabilities/loopback.js +41 -0
- package/src/runtime/capabilities/sanitizer.js +88 -0
- package/src/runtime/capability-router.js +135 -3
- package/src/runtime/checkouts.js +73 -11
- package/src/runtime/claims.js +13 -7
- package/src/runtime/cli.js +196 -19
- package/src/runtime/config-home.js +42 -0
- package/src/runtime/context/arbitrate.js +767 -0
- package/src/runtime/context/delivery-store.js +4 -6
- package/src/runtime/context/emission-rules.js +118 -0
- package/src/runtime/context/identity.js +227 -0
- package/src/runtime/context/primary-command.js +117 -0
- package/src/runtime/context/primary.js +344 -0
- package/src/runtime/context/summary-store.js +655 -0
- package/src/runtime/context-pack.js +154 -78
- package/src/runtime/decision-register.js +13 -4
- package/src/runtime/dispatch/admission.js +392 -0
- package/src/runtime/dispatch/attempt-end.js +274 -0
- package/src/runtime/dispatch/command.js +628 -0
- package/src/runtime/dispatch/controls.js +904 -0
- package/src/runtime/dispatch/envelope.js +276 -0
- package/src/runtime/dispatch/grants.js +310 -0
- package/src/runtime/dispatch/integrate.js +617 -0
- package/src/runtime/dispatch/loop.js +1835 -0
- package/src/runtime/dispatch/store.js +352 -0
- package/src/runtime/dispatch/verify-run.js +201 -0
- package/src/runtime/evidence-ledger.js +34 -7
- package/src/runtime/failure/capture.js +3 -1
- package/src/runtime/failure/cli.js +25 -9
- package/src/runtime/failure/home.js +57 -30
- package/src/runtime/failure/store.js +7 -2
- package/src/runtime/feature-pointer.js +174 -0
- package/src/runtime/feature-resolve.js +13 -2
- package/src/runtime/fleet/command.js +77 -0
- package/src/runtime/fleet/projects.js +178 -0
- package/src/runtime/fleet/tree.js +383 -0
- package/src/runtime/freshness.js +33 -3
- package/src/runtime/git-memo.js +46 -0
- package/src/runtime/guidance/ablation.js +427 -0
- package/src/runtime/health.js +565 -17
- package/src/runtime/history-compactor.js +13 -3
- package/src/runtime/implementation-gate.js +277 -22
- package/src/runtime/inventory/coverage.js +1 -1
- package/src/runtime/inventory/index.js +1 -1
- package/src/runtime/inventory/precedence.js +2 -2
- package/src/runtime/inventory/siblings.js +6 -4
- package/src/runtime/knowledge/code-corpus.js +277 -0
- package/src/runtime/knowledge/code-lexical.js +130 -0
- package/src/runtime/knowledge/code-retrieval.js +307 -0
- package/src/runtime/knowledge/code-validation.js +106 -0
- package/src/runtime/knowledge/gp3-gate.js +74 -0
- package/src/runtime/knowledge/graph-adapter.js +288 -0
- package/src/runtime/knowledge/graph-fallback.js +394 -0
- package/src/runtime/knowledge/hybrid.js +136 -8
- package/src/runtime/knowledge/retrieval.js +34 -1
- package/src/runtime/knowledge/rtk-compress.js +77 -0
- package/src/runtime/knowledge/semble-bridge.py +106 -0
- package/src/runtime/knowledge/semble-lifecycle.js +114 -0
- package/src/runtime/knowledge/semble-provider.js +365 -0
- package/src/runtime/lifecycle/cli.js +16 -6
- package/src/runtime/lifecycle/event-store.js +8 -6
- package/src/runtime/lifecycle/followup.js +6 -1
- package/src/runtime/lifecycle/overview.js +24 -1
- package/src/runtime/lifecycle/report-store.js +8 -10
- package/src/runtime/lifecycle/retention.js +95 -31
- package/src/runtime/lifecycle/root.js +9 -1
- package/src/runtime/lifecycle/status.js +34 -17
- package/src/runtime/lifecycle/store-upkeep.js +56 -7
- package/src/runtime/mask.js +134 -7
- package/src/runtime/mcp-consultations.js +40 -6
- package/src/runtime/model-router.js +79 -7
- package/src/runtime/models/catalogue.js +191 -0
- package/src/runtime/models/command.js +153 -0
- package/src/runtime/off-words.js +12 -0
- package/src/runtime/outcome.js +2 -2
- package/src/runtime/packages/command.js +1009 -0
- package/src/runtime/packages/contributions.js +116 -0
- package/src/runtime/packages/digest.js +132 -0
- package/src/runtime/packages/fetch.js +182 -0
- package/src/runtime/packages/grants.js +192 -0
- package/src/runtime/packages/index-file.js +134 -0
- package/src/runtime/packages/instruction.js +90 -0
- package/src/runtime/packages/manifest.js +331 -0
- package/src/runtime/packages/points.js +477 -0
- package/src/runtime/packages/programs.js +216 -0
- package/src/runtime/packages/scaffold.js +277 -0
- package/src/runtime/packages/source.js +90 -0
- package/src/runtime/packages/state.js +164 -0
- package/src/runtime/packages/store.js +449 -0
- package/src/runtime/packages/tar.js +106 -0
- package/src/runtime/packages/view.js +406 -0
- package/src/runtime/plan-check.js +59 -0
- package/src/runtime/plan-content.js +324 -0
- package/src/runtime/policy-init.js +118 -0
- package/src/runtime/profiles/doctor.js +96 -0
- package/src/runtime/profiles/resolve.js +244 -0
- package/src/runtime/profiles/rollback.js +254 -0
- package/src/runtime/profiles/sampler.js +41 -0
- package/src/runtime/readiness-record.js +16 -11
- package/src/runtime/readiness.js +46 -5
- package/src/runtime/research-request.js +50 -25
- package/src/runtime/retrieval-plan.js +10 -30
- package/src/runtime/retrieval-record.js +75 -5
- package/src/runtime/review/command.js +246 -0
- package/src/runtime/review/dominance.js +68 -0
- package/src/runtime/review/findings.js +434 -0
- package/src/runtime/review/identity.js +255 -0
- package/src/runtime/review/protocol-command.js +109 -0
- package/src/runtime/review/protocols.js +405 -0
- package/src/runtime/review/resolve-protocol.js +302 -0
- package/src/runtime/review/start.js +530 -0
- package/src/runtime/roadmap/facts.js +479 -0
- package/src/runtime/roadmap/gates.js +270 -0
- package/src/runtime/roadmap/loop.js +1636 -0
- package/src/runtime/roadmap/merge.js +381 -0
- package/src/runtime/roadmap/rows.js +1113 -0
- package/src/runtime/roadmap/seed.js +951 -0
- package/src/runtime/rules-report.js +336 -0
- package/src/runtime/scaffold/artifacts.js +60 -9
- package/src/runtime/scaffold/generate.js +21 -9
- package/src/runtime/settings/autopilot.js +106 -0
- package/src/runtime/settings/cli.js +280 -0
- package/src/runtime/settings/config-write.js +314 -0
- package/src/runtime/settings/files.js +271 -0
- package/src/runtime/settings/legacy.js +154 -0
- package/src/runtime/settings/lexical.js +56 -0
- package/src/runtime/settings/prepared-run.js +269 -0
- package/src/runtime/settings/project-layers.js +118 -0
- package/src/runtime/settings/refs.js +288 -0
- package/src/runtime/settings/registry.js +553 -0
- package/src/runtime/settings/resolve.js +713 -0
- package/src/runtime/settings/shared.js +37 -0
- package/src/runtime/settings/worker-billing.js +107 -0
- package/src/runtime/settings/write.js +269 -0
- package/src/runtime/slot-command.js +78 -0
- package/src/runtime/slots.js +671 -0
- package/src/runtime/source-version.js +1 -0
- package/src/runtime/state-root.js +217 -0
- package/src/runtime/storage/cli.js +12 -5
- package/src/runtime/storage/engine.js +9 -2
- package/src/runtime/storage/registry.js +14 -1
- package/src/runtime/storage/roots.js +66 -16
- package/src/runtime/storage/rules.js +82 -10
- package/src/runtime/storage/upkeep.js +10 -2
- package/src/runtime/storage/work-status.js +245 -26
- package/src/runtime/task-attempts.js +589 -69
- package/src/runtime/task-classifier.js +47 -11
- package/src/runtime/task-graph.js +373 -0
- package/src/runtime/task-run.js +778 -0
- package/src/runtime/task-scope.js +176 -55
- package/src/runtime/task-sources.js +147 -0
- package/src/runtime/task-state.js +374 -64
- package/src/runtime/team/admission.js +301 -0
- package/src/runtime/team/envelope.js +324 -0
- package/src/runtime/team/review-guard.js +156 -0
- package/src/runtime/trace/analyze.js +427 -0
- package/src/runtime/trace/baseline.js +770 -0
- package/src/runtime/trace/ledger.js +63 -140
- package/src/runtime/trace/otlp-export.js +568 -0
- package/src/runtime/trace/otlp-map.js +481 -0
- package/src/runtime/trace/spans.js +745 -0
- package/src/runtime/trace/telemetry.js +225 -0
- package/src/runtime/trace/views.js +1 -0
- package/src/runtime/transcripts/command.js +98 -0
- package/src/runtime/transcripts/cursor.js +326 -0
- package/src/runtime/transcripts/read.js +126 -0
- package/src/runtime/transcripts/readers/claude-jsonl.js +74 -0
- package/src/runtime/transcripts/readers/codex-rollout.js +70 -0
- package/src/runtime/transcripts/readers/copilot-events.js +90 -0
- package/src/runtime/transcripts/readers/kiro-jsonl.js +77 -0
- package/src/runtime/transcripts/readers/pi-jsonl.js +59 -0
- package/src/runtime/transcripts/registry.js +161 -0
- package/src/runtime/transcripts/stats.js +161 -0
- package/src/runtime/verification/check-key.js +628 -0
- package/src/runtime/verification/contract-runner.js +546 -11
- package/src/runtime/verification/engine.js +499 -9
- package/src/runtime/verification/impact.js +617 -0
- package/src/runtime/verification/inflight.js +205 -0
- package/src/runtime/verification/registry.js +176 -0
- package/src/runtime/verification/reuse.js +184 -0
- package/src/runtime/verification/telemetry-emit.js +254 -0
- package/src/runtime/verification/test-selection.js +67 -7
- package/src/runtime/worker/active.js +90 -0
- package/src/runtime/worker/cancel.js +222 -0
- package/src/runtime/worker/catalogue.js +122 -0
- package/src/runtime/worker/command.js +677 -0
- package/src/runtime/worker/evidence.js +288 -0
- package/src/runtime/worker/launch.js +288 -0
- package/src/runtime/worker/models.js +137 -0
- package/src/runtime/worker/parsers.js +218 -0
- package/src/runtime/worker/probes/index.js +706 -0
- package/src/runtime/worker/process-tree.js +415 -0
- package/src/runtime/worker/quota.js +43 -0
- package/src/runtime/worker/readiness.js +713 -0
- package/src/runtime/worker/run-store.js +166 -0
- package/src/runtime/worker/supervisor.js +541 -0
- package/src/runtime/worker/worktree-check.js +252 -0
- package/src/runtime/workflow-engine.js +5 -1
- package/src/runtime/workflow-orchestrator.js +578 -63
- package/src/runtime/worktree.js +149 -22
- package/src/state/index.js +1 -1
- package/src/state/lockfile.js +64 -10
- package/src/state/run-lock.js +1 -1
- package/types/node-commonjs.d.ts +106 -7
- package/core/harnesses/gemini/hooks/hooks.json +0 -77
- package/core/harnesses/gemini/hooks/lib.sh +0 -302
- package/core/harnesses/gemini/hooks/mcp-tool-guard.sh +0 -10
- package/core/harnesses/gemini/hooks/post-edit-lint.sh +0 -39
- package/core/harnesses/gemini/hooks/pre-bash-guard.sh +0 -10
- package/core/harnesses/gemini/hooks/pre-compact.sh +0 -38
- package/core/harnesses/gemini/hooks/pre-implement-gate.sh +0 -10
- package/core/harnesses/gemini/hooks/session-end.impl.sh +0 -89
- package/core/harnesses/gemini/hooks/session-end.sh +0 -5
- package/core/harnesses/gemini/hooks/session-start.sh +0 -7
- package/core/harnesses/gemini/settings/adapter-defaults.json +0 -4
- package/core/shared/guidance/FLAGS.md +0 -25
- package/core/shared/guidance/rules/RULE_01_SAFETY.md +0 -25
- package/core/shared/guidance/rules/RULE_02_WORKFLOW.md +0 -23
- package/core/shared/guidance/rules/RULE_03_QUALITY.md +0 -14
- package/core/shared/guidance/rules/RULE_04_QUESTIONS.md +0 -46
- package/src/adapters/gemini/hooks.js +0 -251
- package/src/adapters/gemini/index.js +0 -429
|
@@ -1,4 +1,5 @@
|
|
|
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
|
|
2
3
|
# lib.sh — shared constants and helpers for the Canonical Policy Library
|
|
3
4
|
#
|
|
4
5
|
# Usage: source "<policy-dir>/lib.sh"
|
|
@@ -9,7 +10,7 @@
|
|
|
9
10
|
# 3. capture stdin once: INPUT=$(cat)
|
|
10
11
|
# 4. use: json_field "$INPUT" ".field_name"
|
|
11
12
|
|
|
12
|
-
|
|
13
|
+
_DOFLOW_SRC=${BASH_SOURCE[0]//\\//}; case $_DOFLOW_SRC in */*) _DOFLOW_LIB_DIR=${_DOFLOW_SRC%/*} ;; *) _DOFLOW_LIB_DIR=. ;; esac
|
|
13
14
|
#
|
|
14
15
|
# Deployment:
|
|
15
16
|
# This file is installed by the doflow CLI and overwritten on update — do
|
|
@@ -17,7 +18,7 @@ case ${BASH_SOURCE[0]} in */*) _DOFLOW_LIB_DIR=${BASH_SOURCE[0]%/*} ;; *) _DOFLO
|
|
|
17
18
|
#
|
|
18
19
|
# Consolidation note (022-normalize-hooks, Phase B): this is the single
|
|
19
20
|
# canonical copy every front door's dispatched policy script sources — the
|
|
20
|
-
# claude/
|
|
21
|
+
# claude/kiro/codex copies it replaces were already byte-identical
|
|
21
22
|
# except for one Claude-only default (see DOFLOW_AGENT below), confirmed via
|
|
22
23
|
# diff before consolidating.
|
|
23
24
|
|
|
@@ -25,16 +26,33 @@ set -euo pipefail
|
|
|
25
26
|
|
|
26
27
|
# ── State directories ────────────────────────────────────────────────────────
|
|
27
28
|
|
|
28
|
-
# XDG-compliant, agent-agnostic store shared by every harness DoFlow supports
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
29
|
+
# XDG-compliant, agent-agnostic store shared by every harness DoFlow supports, under the config home
|
|
30
|
+
# (doflow_config_home: an absolute XDG_CONFIG_HOME, else an absolute HOME + /.config, else none). With
|
|
31
|
+
# no config home every state path below is empty, sourcing this file still never exits, and each state
|
|
32
|
+
# function returns 0 at once: session work is skipped and a guard reaches its own decision (086 IC-010).
|
|
33
|
+
# BEGIN doflow-config-home v1 (rule: src/runtime/config-home.js; checked by test/guards/settings.test.js)
|
|
34
|
+
doflow_config_home() {
|
|
35
|
+
DOFLOW_HOME=""
|
|
36
|
+
case "${XDG_CONFIG_HOME:-}" in
|
|
37
|
+
/*) DOFLOW_HOME="${XDG_CONFIG_HOME}/doflow"; return 0 ;;
|
|
38
|
+
[A-Za-z]:[\\/]*) case "${OSTYPE:-}" in msys*|cygwin*|win32*) DOFLOW_HOME="${XDG_CONFIG_HOME}/doflow"; return 0 ;; esac ;;
|
|
39
|
+
esac
|
|
40
|
+
case "${HOME:-}" in
|
|
41
|
+
/*) DOFLOW_HOME="${HOME}/.config/doflow" ;;
|
|
42
|
+
[A-Za-z]:[\\/]*) case "${OSTYPE:-}" in msys*|cygwin*|win32*) DOFLOW_HOME="${HOME}/.config/doflow" ;; esac ;;
|
|
43
|
+
esac
|
|
44
|
+
return 0
|
|
45
|
+
}
|
|
46
|
+
# END doflow-config-home v1
|
|
47
|
+
doflow_config_home
|
|
48
|
+
STATE_DIR="${DOFLOW_HOME:+$DOFLOW_HOME/session-env}"
|
|
49
|
+
SESSION_DIR="${STATE_DIR:+$STATE_DIR/sessions}"
|
|
50
|
+
PROJECTS_DIR="${STATE_DIR:+$STATE_DIR/projects}"
|
|
33
51
|
# shellcheck disable=SC2034 # used by session-context.sh and stop-check.sh which source this file
|
|
34
|
-
SESSIONS_LOG="$DOFLOW_HOME/sessions.log"
|
|
52
|
+
SESSIONS_LOG="${DOFLOW_HOME:+$DOFLOW_HOME/sessions.log}"
|
|
35
53
|
|
|
36
54
|
# Identifies which harness is running. A front door sets this before sourcing
|
|
37
|
-
# this file (e.g. `export DOFLOW_AGENT=
|
|
55
|
+
# this file (e.g. `export DOFLOW_AGENT=codex; exec bash .../policies/...sh`);
|
|
38
56
|
# "unknown" here — not any one harness's name — is the honest fallback when a
|
|
39
57
|
# front door omits it, since every prior per-harness copy of this file
|
|
40
58
|
# defaulted to "claude-code" regardless of which harness actually shipped it.
|
|
@@ -253,18 +271,22 @@ has_uncommitted_changes() {
|
|
|
253
271
|
# ── Directory helpers ─────────────────────────────────────────────────────────
|
|
254
272
|
|
|
255
273
|
# Create and return the session-scoped state directory for a given session_id.
|
|
256
|
-
# Safe to call multiple times (mkdir -p is idempotent).
|
|
274
|
+
# Safe to call multiple times (mkdir -p is idempotent). Prints nothing and creates nothing when
|
|
275
|
+
# there is no config home (SESSION_DIR empty).
|
|
257
276
|
ensure_session_dir() {
|
|
258
277
|
local session_id="$1"
|
|
278
|
+
[ -n "$SESSION_DIR" ] || return 0
|
|
259
279
|
mkdir -p "$SESSION_DIR/$session_id"
|
|
260
280
|
echo "$SESSION_DIR/$session_id"
|
|
261
281
|
}
|
|
262
282
|
|
|
263
283
|
# Create and return the project-scoped state directory for a given cwd.
|
|
264
|
-
# Shared across all sessions in the same directory.
|
|
284
|
+
# Shared across all sessions in the same directory. Prints nothing and creates nothing when there
|
|
285
|
+
# is no config home (PROJECTS_DIR empty).
|
|
265
286
|
ensure_project_dir() {
|
|
266
287
|
local cwd="$1"
|
|
267
288
|
local hash
|
|
289
|
+
[ -n "$PROJECTS_DIR" ] || return 0
|
|
268
290
|
hash=$(cwd_hash "$cwd")
|
|
269
291
|
mkdir -p "$PROJECTS_DIR/$hash"
|
|
270
292
|
echo "$PROJECTS_DIR/$hash"
|
|
@@ -293,30 +315,16 @@ require_jq() {
|
|
|
293
315
|
fi
|
|
294
316
|
}
|
|
295
317
|
|
|
296
|
-
# ── Session role
|
|
297
|
-
|
|
298
|
-
#
|
|
299
|
-
|
|
300
|
-
# `worker` is `worker` and writes one line to stderr. A worker never writes or claims the
|
|
301
|
-
# project's compact summary or warning. Always returns 0. bash 3.2 safe (no ${var,,}).
|
|
302
|
-
doflow_session_role() {
|
|
303
|
-
local role
|
|
304
|
-
role=$(printf '%s' "${DOFLOW_SESSION_ROLE:-}" | tr '[:upper:]' '[:lower:]') || role=""
|
|
305
|
-
case "$role" in
|
|
306
|
-
""|main) printf 'main\n' ;;
|
|
307
|
-
worker) printf 'worker\n' ;;
|
|
308
|
-
*)
|
|
309
|
-
echo "[doflow] unknown DOFLOW_SESSION_ROLE; treating session as worker" >&2
|
|
310
|
-
printf 'worker\n'
|
|
311
|
-
;;
|
|
312
|
-
esac
|
|
313
|
-
return 0
|
|
314
|
-
}
|
|
318
|
+
# ── Session role and identity ─────────────────────────────────────────────────
|
|
319
|
+
|
|
320
|
+
# doflow_session_role and doflow_identity live in identity.sh, their only definition (IC-009).
|
|
321
|
+
. "$_DOFLOW_LIB_DIR/identity.sh"
|
|
315
322
|
|
|
316
323
|
# Start storage cleanup without changing the hook's output, status, or latency.
|
|
317
324
|
storage_upkeep_async() {
|
|
318
|
-
local cwd="${1:-}" root run home config_dir
|
|
325
|
+
local cwd="${1:-}" root run home config_dir detach=""
|
|
319
326
|
[ -n "$cwd" ] || return 0
|
|
327
|
+
command -v setsid >/dev/null 2>&1 && detach="setsid"
|
|
320
328
|
home="${HOME:-}"
|
|
321
329
|
config_dir="${CLAUDE_CONFIG_DIR:-$home/.claude}"
|
|
322
330
|
root=$(nudge_repo_root "$cwd" 2>/dev/null) || root="$cwd"
|
|
@@ -329,7 +337,9 @@ storage_upkeep_async() {
|
|
|
329
337
|
# Background the fully redirected subshell; an inner `&` leaves this shell
|
|
330
338
|
# holding the hook's captured stdout open until the dispatcher exits. The
|
|
331
339
|
# storage verb takes its project from the working directory: run it at the root.
|
|
332
|
-
|
|
340
|
+
# setsid (absent on macOS) moves the upkeep out of the hook's session, so a harness that
|
|
341
|
+
# signals the hook's process group when the hook exits does not take the upkeep with it.
|
|
342
|
+
( cd "$root" 2>/dev/null && nohup $detach "$run" storage --action upkeep </dev/null >/dev/null 2>&1 ) >/dev/null 2>&1 3>&- 5>&- &
|
|
333
343
|
return 0
|
|
334
344
|
done
|
|
335
345
|
return 0
|
|
@@ -379,7 +389,7 @@ nudge_repo_root() {
|
|
|
379
389
|
# file that cannot be read, is empty or holds anything else is `off`.
|
|
380
390
|
nudge_setting() {
|
|
381
391
|
local root="${1:-}" file line=""
|
|
382
|
-
for file in "${root:+$root/.doflow/prompt-nudge}" "$DOFLOW_HOME/prompt-nudge"; do
|
|
392
|
+
for file in "${root:+$root/.doflow/prompt-nudge}" "${DOFLOW_HOME:+$DOFLOW_HOME/prompt-nudge}"; do
|
|
383
393
|
[ -n "$file" ] && [ -e "$file" ] || continue
|
|
384
394
|
line=""
|
|
385
395
|
{ IFS= read -r line || true; } 2>/dev/null < "$file" || line=""
|
|
@@ -406,17 +416,20 @@ nudge_safe_id() {
|
|
|
406
416
|
return 0
|
|
407
417
|
}
|
|
408
418
|
|
|
409
|
-
# Print the marker path for a session id. The caller checks nudge_safe_id first.
|
|
419
|
+
# Print the marker path for a session id. The caller checks nudge_safe_id first. With no config
|
|
420
|
+
# home there is no marker path and nothing is printed.
|
|
410
421
|
nudge_marker_file() {
|
|
422
|
+
[ -n "$STATE_DIR" ] || return 0
|
|
411
423
|
printf '%s\n' "$STATE_DIR/nudge/$1"
|
|
412
424
|
}
|
|
413
425
|
|
|
414
426
|
# Create the marker for <id> holding <nudged|suppressed>. Succeeds only when this call
|
|
415
427
|
# created it: the create is exclusive, so a second call for the same id fails and
|
|
416
428
|
# leaves the first content. After a create, markers untouched for over 30 days are
|
|
417
|
-
# removed. Silent on every failure.
|
|
429
|
+
# removed. Silent on every failure. With no config home it creates nothing and returns 0 at once.
|
|
418
430
|
nudge_mark() {
|
|
419
|
-
local id="${1:-}" word="${2:-}" dir="$STATE_DIR/nudge" file
|
|
431
|
+
local id="${1:-}" word="${2:-}" dir="${STATE_DIR:+$STATE_DIR/nudge}" file
|
|
432
|
+
[ -n "$dir" ] || return 0
|
|
420
433
|
nudge_safe_id "$id" || return 1
|
|
421
434
|
case "$word" in nudged|suppressed) ;; *) return 1 ;; esac
|
|
422
435
|
file="$dir/$id"
|
|
@@ -452,7 +465,8 @@ nudge_feature_active() {
|
|
|
452
465
|
# S3: succeed when a `/do-*` skill already ran this session, read from the run ledger:
|
|
453
466
|
# the lexically last <config>/state/runs/*.jsonl, whose last line's timestamp is not
|
|
454
467
|
# earlier than the session's captured_at (both YYYY-MM-DDTHH:MM:SSZ). Config dir:
|
|
455
|
-
# $DOFLOW_CONFIG_DIR, else the nearest `.doflow` at or above <cwd>, else $HOME/.doflow
|
|
468
|
+
# $DOFLOW_CONFIG_DIR, else the nearest non-nested `.doflow` at or above <cwd>, else $HOME/.doflow
|
|
469
|
+
# (none when HOME is unset or empty).
|
|
456
470
|
# Without a captured_at the ledger counts when it is named for today's UTC date; a last
|
|
457
471
|
# line without a usable timestamp counts too. No ledger, or an empty one, does not.
|
|
458
472
|
nudge_ledger_active() {
|
|
@@ -462,10 +476,19 @@ nudge_ledger_active() {
|
|
|
462
476
|
if [ -n "${DOFLOW_CONFIG_DIR:-}" ]; then
|
|
463
477
|
config="$DOFLOW_CONFIG_DIR"
|
|
464
478
|
else
|
|
465
|
-
config="$HOME/.doflow"
|
|
479
|
+
config="${HOME:+$HOME/.doflow}"
|
|
466
480
|
# The ancestor in the walk's own spelling (`\` read as `/`), the form its test succeeded on.
|
|
467
|
-
if dir=$(nudge_find_up "$cwd" .doflow -d); then
|
|
481
|
+
if dir=$(nudge_find_up "$cwd" .doflow -d); then
|
|
482
|
+
while :; do
|
|
483
|
+
dir="${dir//\\//}"
|
|
484
|
+
case "$dir/" in
|
|
485
|
+
*/.doflow/*) dir=$(nudge_find_up "${dir%/*}" .doflow -d) || break ;;
|
|
486
|
+
*) config="$dir/.doflow"; break ;;
|
|
487
|
+
esac
|
|
488
|
+
done
|
|
489
|
+
fi
|
|
468
490
|
fi
|
|
491
|
+
[ -n "$config" ] || return 1
|
|
469
492
|
for f in "$config"/state/runs/*.jsonl; do
|
|
470
493
|
[ -f "$f" ] && ledger="$f"
|
|
471
494
|
done
|
|
@@ -493,7 +516,7 @@ nudge_registry() {
|
|
|
493
516
|
"${policy_dir:+$policy_dir/../../../runtime/core/registry/workflows.json}" \
|
|
494
517
|
"${policy_dir:+$policy_dir/../../../../registry/workflows.json}" \
|
|
495
518
|
"${root:+$root/.doflow/runtime/core/registry/workflows.json}" \
|
|
496
|
-
"$HOME/.doflow/runtime/core/registry/workflows.json"; do
|
|
519
|
+
"${HOME:+$HOME/.doflow/runtime/core/registry/workflows.json}"; do
|
|
497
520
|
if [ -n "$candidate" ] && [ -f "$candidate" ]; then
|
|
498
521
|
printf '%s\n' "$candidate"
|
|
499
522
|
return 0
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
-
case $
|
|
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
|
|
3
4
|
# mcp-tool-guard.sh — Canonical Policy Library: PreToolUse(mcp_*) hook
|
|
4
5
|
#
|
|
5
6
|
# Intercepts every MCP tool call and blocks matches against mcp-policy.conf, the
|
|
@@ -20,7 +21,7 @@ case $0 in */*) _DOFLOW_POLDIR=${0%/*} ;; *) _DOFLOW_POLDIR=. ;; esac
|
|
|
20
21
|
#
|
|
21
22
|
# mcp-policy.conf's shape (TAB-separated regex<TAB>reason, '#'-comments,
|
|
22
23
|
# blank lines skipped) is identical across every harness that ships one today
|
|
23
|
-
# (claude/codex/
|
|
24
|
+
# (claude/codex/kiro) — reconciliation found no divergence to resolve
|
|
24
25
|
# there.
|
|
25
26
|
|
|
26
27
|
set -uo pipefail
|
|
@@ -1,25 +1,28 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
-
case $
|
|
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
|
|
3
4
|
# pre-bash-guard.sh — Canonical Policy Library: PreToolUse(shell-command) hook
|
|
4
5
|
#
|
|
5
6
|
# Intercepts every shell-command tool call and blocks dangerous commands by
|
|
6
7
|
# matching against POSIX ERE patterns in blocked-patterns.conf (grep -E).
|
|
7
8
|
#
|
|
8
|
-
# Multi-session safe:
|
|
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.
|
|
9
12
|
# Must complete in <50ms.
|
|
10
13
|
#
|
|
11
14
|
# Canonical Policy Script Contract (design.md §4):
|
|
12
15
|
# env DOFLOW_PROJECT_DIR, DOFLOW_AGENT (both optional; not required to
|
|
13
16
|
# evaluate this policy)
|
|
14
17
|
# stdin a native payload with envelope v1 under doflow_event; only the
|
|
15
|
-
# envelope's operation, tool and command
|
|
18
|
+
# envelope's operation, tool and command and native root cwd are used.
|
|
16
19
|
# exit exit 2 + doflow_decide deny = deny; other faults per IC-011.
|
|
17
20
|
#
|
|
18
21
|
# Reconciliation note (022-normalize-hooks, Phase A / D1): this also absorbs
|
|
19
22
|
# stream-hook-runner.js's inline DESTRUCTIVE_COMMAND_PATTERN
|
|
20
23
|
# (`\brm\s+-rf\s+[/~]`, since narrowed to the recursive-rm-of-catastrophic-target
|
|
21
|
-
# rule below), which was the only pre-bash-guard protection
|
|
22
|
-
#
|
|
24
|
+
# rule below), which was the only pre-bash-guard protection
|
|
25
|
+
# Antigravity sessions routed through that runner actually had — it
|
|
23
26
|
# duplicated, rather than delegated to, this policy's fuller
|
|
24
27
|
# blocked-patterns.conf coverage (git force-push, git reset --hard, git clean
|
|
25
28
|
# -fd, SQL DROP/DELETE/TRUNCATE, curl|wget-pipe-to-shell, chmod -R 777, dd
|
|
@@ -28,8 +31,8 @@ case $0 in */*) _DOFLOW_POLDIR=${0%/*} ;; *) _DOFLOW_POLDIR=. ;; esac
|
|
|
28
31
|
# only the hardcoded regex before this change does not lose even that
|
|
29
32
|
# minimum floor of protection; once blocked-patterns.conf is present (the
|
|
30
33
|
# normal case), the full config-driven pattern list applies as it already
|
|
31
|
-
# does for claude/
|
|
32
|
-
# coverage for
|
|
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
|
|
33
36
|
# design.md R2/R3), not a silent side effect.
|
|
34
37
|
|
|
35
38
|
set -uo pipefail
|
|
@@ -87,6 +90,112 @@ PATTERNS_FILE="$_DOFLOW_POLDIR/blocked-patterns.conf"
|
|
|
87
90
|
# byte-wise (much faster than multibyte-aware in a UTF-8 locale).
|
|
88
91
|
export LC_ALL=C
|
|
89
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
|
+
|
|
90
199
|
# ── Quoted text, comments and heredoc bodies are not commands ────────────────
|
|
91
200
|
# scrub_quotes <text> -> sets SCRUBBED. Anchored shell-command patterns must
|
|
92
201
|
# not fire on text that is merely data (a commit message, an echo, a comment,
|
|
@@ -164,7 +273,7 @@ scrub_quotes() {
|
|
|
164
273
|
*) SCRUBBED=$text; return ;;
|
|
165
274
|
esac
|
|
166
275
|
case $text in
|
|
167
|
-
*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:]]*) ;;
|
|
168
277
|
*) SCRUBBED=$text; return ;;
|
|
169
278
|
esac
|
|
170
279
|
if [ "$SCRUB_DEPTH" -ge 8 ]; then SCRUBBED=$text; return; fi
|
|
@@ -269,12 +378,77 @@ scrub_quotes() {
|
|
|
269
378
|
scrub_quotes "$COMMAND"
|
|
270
379
|
SHELL_TEXT=$SCRUBBED
|
|
271
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
|
+
|
|
272
446
|
# Hardcoded floor, used only when blocked-patterns.conf is missing: recursive
|
|
273
447
|
# rm (any flag spelling, flag before or after the target) of a catastrophic
|
|
274
448
|
# target — the same rule as the rm lines in blocked-patterns.conf. Subpaths
|
|
275
449
|
# such as /tmp/x are not blocked.
|
|
276
450
|
_CMDPOS='(^|[;&|(`])[[:space:]]*'
|
|
277
|
-
_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:]]+)*'
|
|
278
452
|
_PATHRM='(\\|/(usr/)?bin/)?rm'
|
|
279
453
|
_RM_FLAG='(-[a-zA-Z]*[rR][a-zA-Z]*|--recursive)'
|
|
280
454
|
_RM_ARGS='([[:space:]]+[^[:space:];&|]+)*'
|
|
@@ -315,9 +489,14 @@ fi
|
|
|
315
489
|
# grep match or regex error falls through to the original per-line loop, which
|
|
316
490
|
# still owns the reason and optional exclude semantics.
|
|
317
491
|
_anchored_patterns="" _full_patterns="" _has_backreference=false
|
|
492
|
+
_has_worker_marker=false
|
|
318
493
|
while IFS=$'\t' read -r pattern _reason _exclude || [ -n "$pattern" ]; do
|
|
319
494
|
[ -z "$pattern" ] && continue
|
|
320
|
-
case "$pattern" in
|
|
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
|
|
321
500
|
if [[ "$pattern" =~ \\[1-9] ]]; then _has_backreference=true; fi
|
|
322
501
|
case "$pattern" in
|
|
323
502
|
'(^|'*) _anchored_patterns="${_anchored_patterns:+$_anchored_patterns|}($pattern)" ;;
|
|
@@ -333,14 +512,27 @@ if [ -n "$_full_patterns" ]; then
|
|
|
333
512
|
grep -qiE -- "$_full_patterns" <<<"$COMMAND" 2>/dev/null
|
|
334
513
|
_full_status=$?
|
|
335
514
|
fi
|
|
336
|
-
if [ "$_anchored_status" -eq 1 ] && [ "$_full_status" -eq 1 ] && [ "$_has_backreference" != true ]; then
|
|
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
|
|
337
521
|
|
|
338
522
|
# ── Pattern matching ──────────────────────────────────────────────────────────
|
|
339
523
|
|
|
524
|
+
_exempt_next= _worker_skipped=false
|
|
340
525
|
while IFS=$'\t' read -r pattern reason exclude || [ -n "$pattern" ]; do
|
|
341
526
|
# Skip comments and empty lines
|
|
342
527
|
[ -z "$pattern" ] && continue
|
|
343
|
-
case "$pattern" in
|
|
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
|
|
344
536
|
|
|
345
537
|
# Match pattern against command (case-insensitive, POSIX extended regex: the default macOS
|
|
346
538
|
# filesystem is case-insensitive, so RM and GIT run there).
|
|
@@ -368,6 +560,14 @@ while IFS=$'\t' read -r pattern reason exclude || [ -n "$pattern" ]; do
|
|
|
368
560
|
fi
|
|
369
561
|
|
|
370
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
|
|
371
571
|
echo "[pre-bash-guard] ${reason:-Command blocked by pre-bash-guard}" >&2
|
|
372
572
|
doflow_decide deny blocked-pattern
|
|
373
573
|
exit 2
|
|
@@ -375,4 +575,5 @@ while IFS=$'\t' read -r pattern reason exclude || [ -n "$pattern" ]; do
|
|
|
375
575
|
done < "$PATTERNS_FILE"
|
|
376
576
|
|
|
377
577
|
# No match — allow
|
|
578
|
+
[ "$_worker_skipped" != false ] && doflow_decide allow "$_worker_skipped"
|
|
378
579
|
exit 0
|