ceo-orchestration 1.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/.claude/adr/ADR-001-runtime-state-directory.md +164 -0
- package/.claude/adr/ADR-002-hooks-package-layout.md +228 -0
- package/.claude/adr/ADR-003-branch-protection-replaces-skill-signing.md +266 -0
- package/.claude/adr/ADR-004-defer-bash-legacy-removal.md +171 -0
- package/.claude/adr/ADR-005-event-stream-v2.md +153 -0
- package/.claude/adr/ADR-006-registry-derived-manifests.md +145 -0
- package/.claude/adr/ADR-007-spec-v1-semver-rc-policy.md +159 -0
- package/.claude/adr/ADR-008-hook-adapter-layer.md +169 -0
- package/.claude/adr/ADR-009-squad-contract.md +167 -0
- package/.claude/adr/ADR-010-canonical-edit-sentinel.md +181 -0
- package/.claude/adr/ADR-011-event-stream-v2.1-injection-flag.md +150 -0
- package/.claude/adr/ADR-012-cross-adapter-golden-fixtures.md +182 -0
- package/.claude/adr/ADR-013-squad-trading-hft.md +135 -0
- package/.claude/adr/ADR-014-hook-migration-batch-policy.md +197 -0
- package/.claude/adr/ADR-015-reflexion-v2-outcome-loop.md +248 -0
- package/.claude/adr/ADR-016-spawn-token-tracking.md +179 -0
- package/.claude/adr/ADR-017-lesson-pruning-policy.md +193 -0
- package/.claude/adr/ADR-018-claim-grammar.md +302 -0
- package/.claude/adr/ADR-019-AMEND-1-confidence-gate-block-mode-lifecycle.md +128 -0
- package/.claude/adr/ADR-019-AMEND-2-CLASS-SHA_EXISTS-promote-to-high-confidence-block.md +67 -0
- package/.claude/adr/ADR-019-confidence-gate-enforcement-lifecycle.md +221 -0
- package/.claude/adr/ADR-020-lesson-pruning-policy-v2.md +171 -0
- package/.claude/adr/ADR-021-e2e-harness-contract.md +189 -0
- package/.claude/adr/ADR-022-reserved-slot.md +52 -0
- package/.claude/adr/ADR-023-docs-freshness-lifecycle.md +184 -0
- package/.claude/adr/ADR-024-perf-baseline-policy.md +222 -0
- package/.claude/adr/ADR-025-squad-edtech.md +236 -0
- package/.claude/adr/ADR-026-squad-government.md +263 -0
- package/.claude/adr/ADR-027-unified-agent-state-backend.md +266 -0
- package/.claude/adr/ADR-028-multi-llm-canonical-parity.md +244 -0
- package/.claude/adr/ADR-029-lexical-tfidf-retrieval.md +205 -0
- package/.claude/adr/ADR-030-llm-as-judge-methodology.md +336 -0
- package/.claude/adr/ADR-031-self-improving-skills.md +221 -0
- package/.claude/adr/ADR-032-interactive-debate-protocol.md +337 -0
- package/.claude/adr/ADR-033-cost-budget-enforcement.md +275 -0
- package/.claude/adr/ADR-034-shared-working-memory.md +233 -0
- package/.claude/adr/ADR-035-otel-export.md +242 -0
- package/.claude/adr/ADR-036-output-safety.md +263 -0
- package/.claude/adr/ADR-037-chaos-testing-methodology.md +289 -0
- package/.claude/adr/ADR-038-session-graph-continuity.md +243 -0
- package/.claude/adr/ADR-039-skill-marketplace-protocol.md +170 -0
- package/.claude/adr/ADR-040-AMEND-2-credential-blocking.md +390 -0
- package/.claude/adr/ADR-040-live-adapter-activation-contract.md +285 -0
- package/.claude/adr/ADR-041-transition-log-convention.md +272 -0
- package/.claude/adr/ADR-042-AMEND-1-read-only-mcp-tools-expansion.md +214 -0
- package/.claude/adr/ADR-042-mcp-server-contract.md +727 -0
- package/.claude/adr/ADR-043-soc2-audit-trail-mapping.md +503 -0
- package/.claude/adr/ADR-044-formal-verification-pilot.md +505 -0
- package/.claude/adr/ADR-045-policy-as-code-engine.md +705 -0
- package/.claude/adr/ADR-046-deterministic-replay.md +167 -0
- package/.claude/adr/ADR-047-predictive-budgeting.md +213 -0
- package/.claude/adr/ADR-048-cross-plan-memory.md +227 -0
- package/.claude/adr/ADR-049-policy-engine-dual-path-deprecation.md +96 -0
- package/.claude/adr/ADR-049a-worktree-orchestration-policy.md +414 -0
- package/.claude/adr/ADR-050-native-subagents-dual-rail.md +165 -0
- package/.claude/adr/ADR-051-skill-reference-expanded-trust-boundary.md +282 -0
- package/.claude/adr/ADR-052-multi-model-dispatch-by-role.md +444 -0
- package/.claude/adr/ADR-053-sentinel-hmac-deferred.md +227 -0
- package/.claude/adr/ADR-054-AMEND-1-anthropic-admin-key-tier.md +131 -0
- package/.claude/adr/ADR-054-github-token-rotation.md +111 -0
- package/.claude/adr/ADR-055-AMEND-1-spool-writer-async-drain.md +170 -0
- package/.claude/adr/ADR-055-AMEND-2-chain-reset-marker.md +126 -0
- package/.claude/adr/ADR-055-AMEND-3-opportunistic-drain-nonblocking.md +183 -0
- package/.claude/adr/ADR-055-audit-log-hmac-chain.md +264 -0
- package/.claude/adr/ADR-056-hook-lifecycle-expansion.md +261 -0
- package/.claude/adr/ADR-057-output-scan-redaction.md +268 -0
- package/.claude/adr/ADR-058-brainstorm-gate-and-two-pass-review.md +240 -0
- package/.claude/adr/ADR-059-skill-bootstrap-env-knob.md +204 -0
- package/.claude/adr/ADR-060-curated-skill-import-pipeline.md +464 -0
- package/.claude/adr/ADR-061-runtime-cost-streaming.md +171 -0
- package/.claude/adr/ADR-062-AMEND-1-rag-conditional-default-on-supersedes-opt-in.md +232 -0
- package/.claude/adr/ADR-062-rag-sidecar-mcp-opt-in.md +231 -0
- package/.claude/adr/ADR-063-agent-eval-empirical-dispatch-validation.md +609 -0
- package/.claude/adr/ADR-064-dynamic-tier-policy-learned-dispatch.md +288 -0
- package/.claude/adr/ADR-065-audit-event-naming-convention.md +185 -0
- package/.claude/adr/ADR-066-context-mode-orthogonal-to-manifest.md +92 -0
- package/.claude/adr/ADR-067-ceo-model-downshift-static-routing.md +219 -0
- package/.claude/adr/ADR-069-wondelai-skills-import-refused.md +183 -0
- package/.claude/adr/ADR-070-audit-emit-package-layout.md +228 -0
- package/.claude/adr/ADR-071-benchmark-comparison-methodology.md +209 -0
- package/.claude/adr/ADR-072-test-discovery-via-conftest.md +184 -0
- package/.claude/adr/ADR-073-semver-bump-criteria-sprint-32.md +209 -0
- package/.claude/adr/ADR-074-sprint-32-phase-3-b1-refused.md +320 -0
- package/.claude/adr/ADR-075-sprint-32-phase-5-b5-benchmark-refused.md +250 -0
- package/.claude/adr/ADR-076-sprint-32-final-closure.md +218 -0
- package/.claude/adr/ADR-077-2026-04-24-webfetch-injection-incident.md +203 -0
- package/.claude/adr/ADR-078-sentinel-cosign-clarification.md +295 -0
- package/.claude/adr/ADR-079-prompt-sha-salt-hmac-impact.md +221 -0
- package/.claude/adr/ADR-080-rail-anomaly-h4-defense-in-depth.md +1143 -0
- package/.claude/adr/ADR-081-token-as-time-unit.md +272 -0
- package/.claude/adr/ADR-082-l7c-mitigation-default-on.md +240 -0
- package/.claude/adr/ADR-083-mcp-injection-scanner.md +225 -0
- package/.claude/adr/ADR-084-multi-adapter-refused-claude-only.md +152 -0
- package/.claude/adr/ADR-085-framework-landscape-claude-only.md +183 -0
- package/.claude/adr/ADR-086-checkpointing-refused.md +124 -0
- package/.claude/adr/ADR-087-AMEND-1-otel-consume-native-opt-in.md +217 -0
- package/.claude/adr/ADR-087-otel-emit-refused.md +136 -0
- package/.claude/adr/ADR-088-guardrails-library-refused.md +128 -0
- package/.claude/adr/ADR-089-sec-cluster-disposition.md +182 -0
- package/.claude/adr/ADR-090-framework-activation-defaults.md +217 -0
- package/.claude/adr/ADR-091-dogfood-validation-deferred.md +128 -0
- package/.claude/adr/ADR-092-plan-closure-honest-deferral.md +165 -0
- package/.claude/adr/ADR-093-refused-adr-moratorium.md +181 -0
- package/.claude/adr/ADR-094-claude-sdk-compat-version-pinning.md +160 -0
- package/.claude/adr/ADR-095-calendar-gate-retraction.md +202 -0
- package/.claude/adr/ADR-096-vibecoder-only-by-design.md +215 -0
- package/.claude/adr/ADR-097-function-length-advisory-permanent.md +186 -0
- package/.claude/adr/ADR-098-ceo-boot-audit-emit-register.md +251 -0
- package/.claude/adr/ADR-099-changesets-adoption.md +245 -0
- package/.claude/adr/ADR-100-trusted-dependencies-re-affirm.md +208 -0
- package/.claude/adr/ADR-101-replay-redact-helper.md +106 -0
- package/.claude/adr/ADR-102-mcp-introspection-extends-042.md +165 -0
- package/.claude/adr/ADR-103-calendar-gate-final-purge.md +121 -0
- package/.claude/adr/ADR-104-AMEND-1-aek-dated-promotion-criteria.md +338 -0
- package/.claude/adr/ADR-104-adaptive-execution-kernel-advisory.md +210 -0
- package/.claude/adr/ADR-105-multi-llm-coordinated-supersede.md +126 -0
- package/.claude/adr/ADR-106-codex-mcp-adapter-contract.md +153 -0
- package/.claude/adr/ADR-107-pair-rail-mandatory-l2-plus.md +189 -0
- package/.claude/adr/ADR-108-cross-llm-veto-floor.md +129 -0
- package/.claude/adr/ADR-109-codex-skill-rehash-protocol.md +104 -0
- package/.claude/adr/ADR-110-codex-pretool-enforcement.md +94 -0
- package/.claude/adr/ADR-111-locked-corpus-governance.md +191 -0
- package/.claude/adr/ADR-112-grandfather-cap-scope-clarification.md +192 -0
- package/.claude/adr/ADR-113-plan-084-canonical-guard-extension.md +59 -0
- package/.claude/adr/ADR-114-codex-egress-redaction-symmetry.md +72 -0
- package/.claude/adr/ADR-115-post-sota-maintenance-mode.md +152 -0
- package/.claude/adr/ADR-116-AMEND-1-kernel-extension-v2.md +640 -0
- package/.claude/adr/ADR-116-kernel-hard-deny-tier-0-extension.md +465 -0
- package/.claude/adr/ADR-117-adr-id-collision-rename-policy.md +279 -0
- package/.claude/adr/ADR-118-AMEND-1-phase-c-enforcing-flip.md +191 -0
- package/.claude/adr/ADR-118-god-mode-auto-usable-state.md +338 -0
- package/.claude/adr/ADR-119-sentinel-unlock-contract.md +133 -0
- package/.claude/adr/ADR-120-pii-core-promotion.md +280 -0
- package/.claude/adr/ADR-121-sentinel-signers-rotation-policy.md +434 -0
- package/.claude/adr/ADR-122-dpop-mcp-bearer-replay-defense.md +232 -0
- package/.claude/adr/ADR-123-streaming-adapter-canonical-source.md +130 -0
- package/.claude/adr/ADR-124-post-audit-sota-execution-mode.md +362 -0
- package/.claude/adr/ADR-125-risk-tiered-defaulting-doctrine.md +355 -0
- package/.claude/adr/ADR-126-governed-sidecar-capability-model.md +509 -0
- package/.claude/adr/ADR-127-pair-rail-advisory-promotion.md +218 -0
- package/.claude/adr/ADR-128-c2-vector-memory-capability-class.md +380 -0
- package/.claude/adr/ADR-129-AMEND-1-key-floor-waiver-lift.md +249 -0
- package/.claude/adr/ADR-129-c1-crypto-capability-class.md +289 -0
- package/.claude/adr/ADR-131-c5-dev-tools-capability-class.md +215 -0
- package/.claude/adr/ADR-132-goap-advisory-planning-doctrine.md +333 -0
- package/.claude/adr/ADR-133-autonomous-loop-opt-in-capability-doctrine.md +440 -0
- package/.claude/adr/ADR-135-AMEND-1-write-mode-trust-boundary.md +457 -0
- package/.claude/adr/ADR-135-AMEND-2-write-mode-activation.md +175 -0
- package/.claude/adr/ADR-135-federation-contract-mvp.md +253 -0
- package/.claude/adr/ADR-136-AMEND-1-workflow-primitive-adoption.md +139 -0
- package/.claude/adr/ADR-136-workflow-engine-doctrine.md +155 -0
- package/.claude/adr/ADR-137-skill-priority-stack-decision.md +162 -0
- package/.claude/adr/ADR-138-ac-format-priority-and-story-anchor.md +149 -0
- package/.claude/adr/ADR-139-coverage-doctrine-tiered.md +133 -0
- package/.claude/adr/ADR-140-receiving-review-doctrine.md +136 -0
- package/.claude/adr/ADR-141-reduce-protocol.md +124 -0
- package/.claude/adr/ADR-142-opus-4-8-model-bump.md +116 -0
- package/.claude/adr/ADR-143-git-hook-bypass-guard.md +166 -0
- package/.claude/adr/ADR-144-subagent-model-tiering-frontmatter.md +111 -0
- package/.claude/adr/ADR-145-cross-model-review-persona-demand-modality.md +103 -0
- package/.claude/adr/ADR-146-adversary-review-hook.md +122 -0
- package/.claude/adr/ADR-147-eval-harness-doctrine.md +109 -0
- package/.claude/adr/ADR-148-canonical-pricing-source.md +123 -0
- package/.claude/adr/ADR-149-model-id-allowlist.md +196 -0
- package/.claude/adr/ADR-150-commit-signing-policy.md +12 -0
- package/.claude/adr/ADR-151-fan-plan-advisory-bridge.md +178 -0
- package/.claude/adr/ADR-152-claude-md-decomposition.md +262 -0
- package/.claude/adr/ADR-153-compaction-continuity.md +141 -0
- package/.claude/adr/ADR-154-updatedinput-single-rewriter.md +68 -0
- package/.claude/adr/ADR-155-install-baseline-manifest.md +66 -0
- package/.claude/adr/ADR-156-constitution-sync-cascade.md +122 -0
- package/.claude/adr/README.md +392 -0
- package/.claude/adversary.md +116 -0
- package/.claude/agent-metrics.md +101 -0
- package/.claude/agents/_dispatch.md +30 -0
- package/.claude/agents/_probe_architect.md +45 -0
- package/.claude/agents/_probe_canonical_edit.md +46 -0
- package/.claude/agents/_probe_missing_skill.md +42 -0
- package/.claude/agents/code-reviewer.md +166 -0
- package/.claude/agents/devops.md +114 -0
- package/.claude/agents/identity-trust-architect.md +234 -0
- package/.claude/agents/incident-commander.md +285 -0
- package/.claude/agents/llm-finops-architect.md +265 -0
- package/.claude/agents/performance-engineer.md +148 -0
- package/.claude/agents/qa-architect.md +167 -0
- package/.claude/agents/security-engineer.md +192 -0
- package/.claude/agents/threat-detection-engineer.md +238 -0
- package/.claude/benchmarks/_schemas/judge-prompt.md +26 -0
- package/.claude/benchmarks/_schemas/judge-rubric-example.json +11 -0
- package/.claude/benchmarks/_schemas/judge-rubric.yaml +39 -0
- package/.claude/benchmarks/calibration-grades.jsonl +6 -0
- package/.claude/benchmarks/human-sample-calibration.md +232 -0
- package/.claude/benchmarks/judge-rotation-schedule.md +61 -0
- package/.claude/benchmarks/retrieval-judgment-set.yaml +194 -0
- package/.claude/benchmarks/tests/test_retrieval_recall_gate.py +330 -0
- package/.claude/commands/agent-budget.md +105 -0
- package/.claude/commands/architect.md +130 -0
- package/.claude/commands/audit-page.md +149 -0
- package/.claude/commands/audit-tokens.md +89 -0
- package/.claude/commands/ceo-boot.md +118 -0
- package/.claude/commands/ceo-info.md +71 -0
- package/.claude/commands/debate.md +258 -0
- package/.claude/commands/effort.md +99 -0
- package/.claude/commands/fan-plan.md +129 -0
- package/.claude/commands/goap.md +163 -0
- package/.claude/commands/lesson-review.md +66 -0
- package/.claude/commands/memory-scratchpad.md +100 -0
- package/.claude/commands/onboard.md +204 -0
- package/.claude/commands/pitfall.md +54 -0
- package/.claude/commands/resume.md +90 -0
- package/.claude/commands/self-test.md +83 -0
- package/.claude/commands/skill-review.md +102 -0
- package/.claude/commands/spawn.md +212 -0
- package/.claude/commands/squad-install.md +94 -0
- package/.claude/commands/status.md +177 -0
- package/.claude/commands/terse.md +81 -0
- package/.claude/commands/veto-check.md +63 -0
- package/.claude/data/audit-registry.golden.txt +306 -0
- package/.claude/data/canonical_models.json +1030 -0
- package/.claude/data/confidence-gate-class-tiers.json +24 -0
- package/.claude/data/cookbook_patterns.json +139 -0
- package/.claude/data/federation/enabled.md +34 -0
- package/.claude/data/federation/lan-enabled.md +38 -0
- package/.claude/data/federation/peers.example.yaml +89 -0
- package/.claude/data/goap/action-cost-baseline.json +29 -0
- package/.claude/dispatcher/disable_predicate_eval.py +630 -0
- package/.claude/dispatcher/routing-matrix-loader.py +874 -0
- package/.claude/dispatcher/routing-matrix.yaml +343 -0
- package/.claude/dispatcher/tests/conftest.py +11 -0
- package/.claude/dispatcher/tests/test_disable_predicate_eval.py +424 -0
- package/.claude/dispatcher/tests/test_routing_matrix_loader.py +461 -0
- package/.claude/docs/dpop-scope.md +79 -0
- package/.claude/docs/sentinel-signers-rotation-DRAFT.md +117 -0
- package/.claude/eval/README.md +73 -0
- package/.claude/eval/reporter.py +109 -0
- package/.claude/eval/runner.py +532 -0
- package/.claude/eval/self_test.yaml +57 -0
- package/.claude/eval/tasks/__init__.py +185 -0
- package/.claude/eval/tasks/t01_fix_off_by_one.py +52 -0
- package/.claude/eval/tasks/t02_implement_fizzbuzz.py +65 -0
- package/.claude/eval/tasks/t03_json_config_parse.py +80 -0
- package/.claude/eval/tasks/t04_refactor_dedupe.py +71 -0
- package/.claude/eval/tasks/t05_add_unit_test.py +77 -0
- package/.claude/eval/tasks/t06_palindrome.py +58 -0
- package/.claude/eval/tasks/t07_sql_param_fix.py +69 -0
- package/.claude/eval/tasks/t08_word_count.py +53 -0
- package/.claude/eval/tasks/t09_readme_doc.py +64 -0
- package/.claude/eval/tasks/t10_binary_search.py +58 -0
- package/.claude/frontend-team.md +202 -0
- package/.claude/governance/README.md +37 -0
- package/.claude/governance/audit_tokens_allowlist.json +37 -0
- package/.claude/governance/codex-cli-binary-sha256.txt +32 -0
- package/.claude/governance/codex-cli-pin.txt +26 -0
- package/.claude/governance/function-length-grandfather.yaml +2095 -0
- package/.claude/governance/governance-waivers.yaml +28 -0
- package/.claude/governance/pair-rail-inputs-hash-manifest.txt +32 -0
- package/.claude/governance/pair-rail-verdict-template.md +58 -0
- package/.claude/governance/pair-rail-verdict-v1.16.0-rc.1.md +120 -0
- package/.claude/governance/pair-rail-verdict-v1.16.0.md +64 -0
- package/.claude/gpg-revocations.jsonl +1 -0
- package/.claude/hooks/SessionEnd.py +353 -0
- package/.claude/hooks/SessionStart.py +345 -0
- package/.claude/hooks/Stop.py +195 -0
- package/.claude/hooks/UserPromptSubmit.py +329 -0
- package/.claude/hooks/_lib/EXECUTION-CONTEXT-DEFERRED.md +82 -0
- package/.claude/hooks/_lib/__init__.py +26 -0
- package/.claude/hooks/_lib/action_required.py +592 -0
- package/.claude/hooks/_lib/adapters/__init__.py +87 -0
- package/.claude/hooks/_lib/adapters/_constants.py +127 -0
- package/.claude/hooks/_lib/adapters/claude.py +167 -0
- package/.claude/hooks/_lib/adapters/codex.py +754 -0
- package/.claude/hooks/_lib/adapters/live/__init__.py +378 -0
- package/.claude/hooks/_lib/adapters/live/_breaker.py +309 -0
- package/.claude/hooks/_lib/adapters/live/_cost.py +389 -0
- package/.claude/hooks/_lib/adapters/live/_policy.py +319 -0
- package/.claude/hooks/_lib/adapters/live/_result.py +206 -0
- package/.claude/hooks/_lib/adapters/live/_transport.py +681 -0
- package/.claude/hooks/_lib/adapters/live/claude.py +1027 -0
- package/.claude/hooks/_lib/adapters/live/claude_batch.py +652 -0
- package/.claude/hooks/_lib/adapters/live/gemini.py +270 -0
- package/.claude/hooks/_lib/adapters/live/local.py +195 -0
- package/.claude/hooks/_lib/adapters/live/openai.py +371 -0
- package/.claude/hooks/_lib/adversary_rules.py +196 -0
- package/.claude/hooks/_lib/agent_frontmatter.py +288 -0
- package/.claude/hooks/_lib/audit_emit.py +11746 -0
- package/.claude/hooks/_lib/audit_emit_dispatch.py +179 -0
- package/.claude/hooks/_lib/audit_hmac.py +1146 -0
- package/.claude/hooks/_lib/audit_rotation.py +101 -0
- package/.claude/hooks/_lib/canonical_json.py +145 -0
- package/.claude/hooks/_lib/codex_cli_shape.py +502 -0
- package/.claude/hooks/_lib/codex_egress_redact.py +185 -0
- package/.claude/hooks/_lib/confidence_labels.py +338 -0
- package/.claude/hooks/_lib/contract.py +254 -0
- package/.claude/hooks/_lib/cookbook_patterns.py +136 -0
- package/.claude/hooks/_lib/cost_envelope.py +719 -0
- package/.claude/hooks/_lib/credentials.py +188 -0
- package/.claude/hooks/_lib/effective_config.py +767 -0
- package/.claude/hooks/_lib/egress_taxonomy.py +448 -0
- package/.claude/hooks/_lib/embeddings.py +322 -0
- package/.claude/hooks/_lib/env_guard.py +353 -0
- package/.claude/hooks/_lib/env_persist_allowlist.py +147 -0
- package/.claude/hooks/_lib/escalation_signals.py +335 -0
- package/.claude/hooks/_lib/estimation/__init__.py +12 -0
- package/.claude/hooks/_lib/estimation/bayesian.py +147 -0
- package/.claude/hooks/_lib/estimation/pipeline.py +209 -0
- package/.claude/hooks/_lib/exceptions.py +101 -0
- package/.claude/hooks/_lib/execution_context.py +208 -0
- package/.claude/hooks/_lib/federation/__init__.py +104 -0
- package/.claude/hooks/_lib/federation/audit_chain.py +118 -0
- package/.claude/hooks/_lib/federation/audit_chain_ext.py +408 -0
- package/.claude/hooks/_lib/federation/cert_inspector.py +573 -0
- package/.claude/hooks/_lib/federation/client.py +327 -0
- package/.claude/hooks/_lib/federation/handlers/__init__.py +30 -0
- package/.claude/hooks/_lib/federation/handlers/audit_event_batch.py +346 -0
- package/.claude/hooks/_lib/federation/handlers/audit_event_push.py +395 -0
- package/.claude/hooks/_lib/federation/handlers/peer_register.py +484 -0
- package/.claude/hooks/_lib/federation/handlers/peer_revoke.py +356 -0
- package/.claude/hooks/_lib/federation/identity.py +1056 -0
- package/.claude/hooks/_lib/federation/rate_limit.py +476 -0
- package/.claude/hooks/_lib/federation/replay.py +284 -0
- package/.claude/hooks/_lib/federation/scopes.py +168 -0
- package/.claude/hooks/_lib/federation/server.py +2218 -0
- package/.claude/hooks/_lib/file_walker.py +145 -0
- package/.claude/hooks/_lib/filelock.py +191 -0
- package/.claude/hooks/_lib/frontmatter.py +124 -0
- package/.claude/hooks/_lib/git_bypass.py +971 -0
- package/.claude/hooks/_lib/gpg_verify.py +356 -0
- package/.claude/hooks/_lib/guardrail_validator.py +478 -0
- package/.claude/hooks/_lib/injection_patterns.py +252 -0
- package/.claude/hooks/_lib/injection_salt.py +160 -0
- package/.claude/hooks/_lib/mcp/__init__.py +5 -0
- package/.claude/hooks/_lib/mcp/bearer_replay.py +279 -0
- package/.claude/hooks/_lib/mcp/canonical_guard.py +1140 -0
- package/.claude/hooks/_lib/mcp_bearer_friction.py +475 -0
- package/.claude/hooks/_lib/mcp_injection_scan.py +250 -0
- package/.claude/hooks/_lib/mcp_routing.py +151 -0
- package/.claude/hooks/_lib/memory_shared.py +592 -0
- package/.claude/hooks/_lib/metrics.py +241 -0
- package/.claude/hooks/_lib/model_routing.py +227 -0
- package/.claude/hooks/_lib/otel/__init__.py +34 -0
- package/.claude/hooks/_lib/otel/bounded_exporter.py +373 -0
- package/.claude/hooks/_lib/otel/hook_bridge.py +53 -0
- package/.claude/hooks/_lib/otel/queue.py +229 -0
- package/.claude/hooks/_lib/otel_emit.py +604 -0
- package/.claude/hooks/_lib/output_scan.py +1062 -0
- package/.claude/hooks/_lib/output_scan_dedup.py +379 -0
- package/.claude/hooks/_lib/pair_rail_decide.py +244 -0
- package/.claude/hooks/_lib/payload.py +195 -0
- package/.claude/hooks/_lib/persona_routing.py +244 -0
- package/.claude/hooks/_lib/pii_patterns.py +851 -0
- package/.claude/hooks/_lib/plan_frontmatter.py +166 -0
- package/.claude/hooks/_lib/policy.py +1527 -0
- package/.claude/hooks/_lib/policy_preprocessors.py +462 -0
- package/.claude/hooks/_lib/rag_bridge.py +624 -0
- package/.claude/hooks/_lib/rag_events.py +171 -0
- package/.claude/hooks/_lib/rag_router.py +253 -0
- package/.claude/hooks/_lib/redact.py +228 -0
- package/.claude/hooks/_lib/replay_redact.py +511 -0
- package/.claude/hooks/_lib/scratchpad_lib.py +225 -0
- package/.claude/hooks/_lib/secret_patterns.py +905 -0
- package/.claude/hooks/_lib/sentinel_signers.py +740 -0
- package/.claude/hooks/_lib/spec_context_sanitizer.py +258 -0
- package/.claude/hooks/_lib/spool_writer.py +2613 -0
- package/.claude/hooks/_lib/state_store.py +476 -0
- package/.claude/hooks/_lib/subagent_dispatch.py +244 -0
- package/.claude/hooks/_lib/swarm_circuit_breaker.py +203 -0
- package/.claude/hooks/_lib/swarm_enable_gate.py +152 -0
- package/.claude/hooks/_lib/team.py +128 -0
- package/.claude/hooks/_lib/test_isolation.py +352 -0
- package/.claude/hooks/_lib/testing.py +351 -0
- package/.claude/hooks/_lib/tests/federation/test_federation_attack_surface.py +251 -0
- package/.claude/hooks/_lib/tests/federation/test_federation_audit_stitching.py +135 -0
- package/.claude/hooks/_lib/tests/federation/test_federation_identity.py +234 -0
- package/.claude/hooks/_lib/tests/federation/test_federation_replay.py +204 -0
- package/.claude/hooks/_lib/tests/federation/test_federation_sentinel_stage2.py +214 -0
- package/.claude/hooks/_lib/tests/federation/test_federation_server.py +385 -0
- package/.claude/hooks/_lib/tests/test_confidence_gate_class_block.py +313 -0
- package/.claude/hooks/_lib/tests/test_cost_envelope.py +759 -0
- package/.claude/hooks/_lib/tests/test_execution_context.py +254 -0
- package/.claude/hooks/_lib/tests/test_goap_advisory_invariant.py +134 -0
- package/.claude/hooks/_lib/tests/test_goap_planner.py +368 -0
- package/.claude/hooks/_lib/tests/test_plan104_audit_emit.py +324 -0
- package/.claude/hooks/_lib/tests/test_plan104_demand_resolver.py +584 -0
- package/.claude/hooks/_lib/tests/test_plan104_demand_scan.py +164 -0
- package/.claude/hooks/_lib/tests/test_plan104_microbench.py +109 -0
- package/.claude/hooks/_lib/tests/test_plan104_waive_parser.py +113 -0
- package/.claude/hooks/_lib/tests/test_plan105_audit_emit.py +259 -0
- package/.claude/hooks/_lib/tests/test_plan105_check_roadmap_binding.py +68 -0
- package/.claude/hooks/_lib/tests/test_plan105_goap_planner.py +158 -0
- package/.claude/hooks/_lib/tests/test_plan105_spawn_outcome.py +234 -0
- package/.claude/hooks/_lib/tests/test_rag_dead_code_disposition.py +262 -0
- package/.claude/hooks/_lib/tests/test_rag_router.py +209 -0
- package/.claude/hooks/_lib/tests/test_swarm_circuit_breaker.py +278 -0
- package/.claude/hooks/_lib/tests/test_swarm_kill_switch_chain.py +360 -0
- package/.claude/hooks/_lib/tier_policy/__init__.py +123 -0
- package/.claude/hooks/_lib/tier_policy/_agent_frontmatter.py +509 -0
- package/.claude/hooks/_lib/tier_policy/_constants.py +376 -0
- package/.claude/hooks/_lib/tier_policy/_types.py +355 -0
- package/.claude/hooks/_lib/tier_policy/fixtures/baseline.json +17 -0
- package/.claude/hooks/_lib/tier_policy/fixtures/oversize_64kib.json +1 -0
- package/.claude/hooks/_lib/tier_policy/fixtures/prototype_pollution_attack.yaml +14 -0
- package/.claude/hooks/_lib/tier_policy/fixtures/schema_v1_sample.json +5 -0
- package/.claude/hooks/_lib/tier_policy/fixtures/schema_v2_sample.json +17 -0
- package/.claude/hooks/_lib/tier_policy/fixtures/yaml_bomb_attack.yaml +20 -0
- package/.claude/hooks/_lib/tier_policy/loader.py +476 -0
- package/.claude/hooks/_lib/tokens.py +136 -0
- package/.claude/hooks/_lib/tool_lifecycle.py +488 -0
- package/.claude/hooks/_lib/trusted_env.py +77 -0
- package/.claude/hooks/_python-hook.sh +242 -0
- package/.claude/hooks/accel_dispatch.py +172 -0
- package/.claude/hooks/adequacy_gate.py +424 -0
- package/.claude/hooks/audit_log.py +1352 -0
- package/.claude/hooks/auto_boot.py +518 -0
- package/.claude/hooks/check_adversary.py +273 -0
- package/.claude/hooks/check_agent_spawn.py +2696 -0
- package/.claude/hooks/check_anti_ceo_overhead.py +786 -0
- package/.claude/hooks/check_arbitration_kernel.py +544 -0
- package/.claude/hooks/check_bash_canonical_forensic.py +180 -0
- package/.claude/hooks/check_bash_safety.py +1483 -0
- package/.claude/hooks/check_budget.py +916 -0
- package/.claude/hooks/check_canonical_edit.py +1197 -0
- package/.claude/hooks/check_closeout_guard.py +154 -0
- package/.claude/hooks/check_codex_filewrite.py +366 -0
- package/.claude/hooks/check_codex_response.py +403 -0
- package/.claude/hooks/check_confidence_gate.py +545 -0
- package/.claude/hooks/check_config_change.py +346 -0
- package/.claude/hooks/check_config_protection.py +381 -0
- package/.claude/hooks/check_cost_envelope.py +286 -0
- package/.claude/hooks/check_fluency_nudge.py +747 -0
- package/.claude/hooks/check_mcp_response.py +234 -0
- package/.claude/hooks/check_output_safety.py +237 -0
- package/.claude/hooks/check_output_secrets.py +518 -0
- package/.claude/hooks/check_pair_rail.py +1700 -0
- package/.claude/hooks/check_plan_edit.py +905 -0
- package/.claude/hooks/check_postcompact_reinject.py +265 -0
- package/.claude/hooks/check_precompact_continuity.py +379 -0
- package/.claude/hooks/check_protocol_semver_cascade.py +401 -0
- package/.claude/hooks/check_read_injection.py +366 -0
- package/.claude/hooks/check_scratchpad_access.py +228 -0
- package/.claude/hooks/check_setup_verification.py +297 -0
- package/.claude/hooks/check_skill_bootstrap_post.py +339 -0
- package/.claude/hooks/check_skill_patch_sentinel.py +413 -0
- package/.claude/hooks/check_skill_reference_read.py +518 -0
- package/.claude/hooks/check_subagent_fabrication.py +45 -0
- package/.claude/hooks/check_subagent_start.py +232 -0
- package/.claude/hooks/check_tier_policy.py +211 -0
- package/.claude/hooks/check_tier_policy_misrouting_24h.py +187 -0
- package/.claude/hooks/check_webfetch_injection.py +277 -0
- package/.claude/hooks/check_worktree_writer.py +773 -0
- package/.claude/hooks/codex_review_user_code.py +304 -0
- package/.claude/hooks/emit_architect_outcome.py +232 -0
- package/.claude/hooks/latency_report.py +343 -0
- package/.claude/hooks/policy_dispatch.py +168 -0
- package/.claude/hooks/review_loop.py +560 -0
- package/.claude/hooks/route.py +115 -0
- package/.claude/hooks/tests/_agent_fixture.py +153 -0
- package/.claude/hooks/tests/adapters/__init__.py +0 -0
- package/.claude/hooks/tests/adapters/live/__init__.py +0 -0
- package/.claude/hooks/tests/adapters/live/test_adapters.py +488 -0
- package/.claude/hooks/tests/adapters/live/test_audit_wiring.py +81 -0
- package/.claude/hooks/tests/adapters/live/test_breaker.py +272 -0
- package/.claude/hooks/tests/adapters/live/test_cost.py +191 -0
- package/.claude/hooks/tests/adapters/live/test_o7_modernization.py +670 -0
- package/.claude/hooks/tests/adapters/live/test_policy.py +168 -0
- package/.claude/hooks/tests/conftest.py +139 -0
- package/.claude/hooks/tests/fixtures/adapters/claude/in/agent_spawn_compliant.json +9 -0
- package/.claude/hooks/tests/fixtures/adapters/claude/in/bash_safe_command.json +8 -0
- package/.claude/hooks/tests/fixtures/adapters/claude/in/post_audit_event.json +1 -0
- package/.claude/hooks/tests/fixtures/adapters/claude/out/allow.json +1 -0
- package/.claude/hooks/tests/fixtures/adapters/claude/out/block_with_reason.json +1 -0
- package/.claude/hooks/tests/fixtures/adapters/codex/in/.gitkeep +1 -0
- package/.claude/hooks/tests/fixtures/adapters/codex/out/.gitkeep +1 -0
- package/.claude/hooks/tests/fixtures/adapters/gemini/GAPS.md +46 -0
- package/.claude/hooks/tests/fixtures/adapters/gemini/in/agent_spawn_minimal.json +1 -0
- package/.claude/hooks/tests/fixtures/adapters/gemini/in/bash_minimal.json +1 -0
- package/.claude/hooks/tests/fixtures/adapters/gemini/out/allow.json +1 -0
- package/.claude/hooks/tests/fixtures/adapters/local/in/agent_spawn_ollama.json +19 -0
- package/.claude/hooks/tests/fixtures/adapters/local/in/bash_minimal.json +8 -0
- package/.claude/hooks/tests/fixtures/adapters/local/out/allow.json +1 -0
- package/.claude/hooks/tests/fixtures/adapters/openai/in/agent_spawn_chat_completions.json +13 -0
- package/.claude/hooks/tests/fixtures/adapters/openai/in/bash_responses_api.json +9 -0
- package/.claude/hooks/tests/fixtures/adapters/openai/out/allow.json +1 -0
- package/.claude/hooks/tests/fixtures/anti_ceo_overhead/should-NOT-block-on-Y.ndjson +13 -0
- package/.claude/hooks/tests/fixtures/anti_ceo_overhead/should-block-on-X.ndjson +9 -0
- package/.claude/hooks/tests/fixtures/byte_identity/__init__.py +5 -0
- package/.claude/hooks/tests/fixtures/byte_identity/bash_safety_fuzzer.py +287 -0
- package/.claude/hooks/tests/fixtures/byte_identity/plan_edit_fuzzer.py +364 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/negative/aws-iam-policy-arn-id-25.txt +2 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/negative/blog-paragraph-18.txt +1 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/negative/boilerplate-26.txt +4 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/negative/cdn-cache-key-12.txt +2 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/negative/certificate-fingerprint-10.txt +2 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/negative/changelog-19.txt +1 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/negative/commit-sha-01.txt +4 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/negative/django-csrf-token-24.txt +3 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/negative/docker-image-04.txt +2 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/negative/docs-example-22.txt +3 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/negative/haiku-20.txt +1 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/negative/hex-placeholder-15.txt +3 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/negative/hex-short-23.txt +5 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/negative/image-thumbnail-09.txt +3 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/negative/jwt-payload-decoded-08.txt +3 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/negative/kubernetes-uid-06.txt +3 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/negative/md5-hash-02.txt +2 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/negative/phone-number-16.txt +3 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/negative/postgres-uuid-05.txt +2 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/negative/redis-cluster-node-13.txt +3 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/negative/session-token-11.txt +3 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/negative/sha256-checksum-03.txt +3 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/negative/short-token-21.txt +2 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/negative/software-license-14.txt +4 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/negative/telemetry-trace-07.txt +3 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/negative/zip-postal-17.txt +4 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/positive/binance-api-key-alnum-03.txt +1 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/positive/binance-api-key-hex-01.txt +3 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/positive/binance-api-key-hex-02.txt +2 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/positive/bip39-mnemonic-12-31.txt +2 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/positive/bip39-mnemonic-12-33.txt +2 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/positive/bip39-mnemonic-24-32.txt +2 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/positive/bitfinex-api-key-11.txt +1 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/positive/bitfinex-api-key-12.txt +1 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/positive/bitfinex-api-key-13.txt +2 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/positive/bitstamp-api-key-30.txt +3 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/positive/bitstamp-customer-id-29.txt +2 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/positive/bybit-api-key-18.txt +2 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/positive/bybit-api-key-19.txt +1 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/positive/bybit-api-secret-20.txt +1 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/positive/bybit-combined-21.txt +3 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/positive/coinbase-api-key-uuid-04.txt +2 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/positive/coinbase-api-secret-b64-05.txt +1 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/positive/coinbase-combined-07.txt +4 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/positive/coinbase-passphrase-06.txt +1 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/positive/evm-private-key-34.txt +2 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/positive/evm-private-key-35.txt +1 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/positive/evm-private-key-36.txt +2 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/positive/generic-api-key-37.txt +2 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/positive/generic-api-key-38.txt +3 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/positive/generic-api-key-39.txt +2 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/positive/kraken-api-key-08.txt +1 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/positive/kraken-api-secret-09.txt +1 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/positive/kraken-combined-10.txt +4 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/positive/kucoin-api-key-uuid-26.txt +2 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/positive/kucoin-api-secret-uuid-27.txt +1 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/positive/kucoin-passphrase-28.txt +1 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/positive/okx-api-key-uuid-22.txt +1 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/positive/okx-api-secret-23.txt +2 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/positive/okx-combined-25.txt +4 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/positive/okx-passphrase-24.txt +1 -0
- package/.claude/hooks/tests/fixtures/hooks/audit_log/in.json +1 -0
- package/.claude/hooks/tests/fixtures/hooks/audit_log/out.json +0 -0
- package/.claude/hooks/tests/fixtures/hooks/check_agent_spawn/in.json +1 -0
- package/.claude/hooks/tests/fixtures/hooks/check_agent_spawn/out.json +1 -0
- package/.claude/hooks/tests/fixtures/hooks/check_bash_safety/in.json +1 -0
- package/.claude/hooks/tests/fixtures/hooks/check_bash_safety/out.json +1 -0
- package/.claude/hooks/tests/fixtures/hooks/check_canonical_edit/in.json +1 -0
- package/.claude/hooks/tests/fixtures/hooks/check_canonical_edit/out.json +1 -0
- package/.claude/hooks/tests/fixtures/hooks/check_confidence_gate/in.json +1 -0
- package/.claude/hooks/tests/fixtures/hooks/check_confidence_gate/out.json +1 -0
- package/.claude/hooks/tests/fixtures/hooks/check_plan_edit/in.json +1 -0
- package/.claude/hooks/tests/fixtures/hooks/check_plan_edit/out.json +1 -0
- package/.claude/hooks/tests/fixtures/hooks/check_read_injection/in.json +1 -0
- package/.claude/hooks/tests/fixtures/hooks/check_read_injection/out.json +1 -0
- package/.claude/hooks/tests/fixtures/lifecycle/concurrent_interleaved.json +36 -0
- package/.claude/hooks/tests/fixtures/lifecycle/orphaned_pre.json +8 -0
- package/.claude/hooks/tests/fixtures/lifecycle/paired_bash_post.json +8 -0
- package/.claude/hooks/tests/fixtures/lifecycle/paired_bash_pre.json +9 -0
- package/.claude/hooks/tests/fixtures/normalized/agent_spawn_chat_completions.json +36 -0
- package/.claude/hooks/tests/fixtures/normalized/agent_spawn_compliant.json +24 -0
- package/.claude/hooks/tests/fixtures/normalized/agent_spawn_minimal.json +24 -0
- package/.claude/hooks/tests/fixtures/normalized/agent_spawn_ollama.json +42 -0
- package/.claude/hooks/tests/fixtures/normalized/bash_minimal.json +23 -0
- package/.claude/hooks/tests/fixtures/normalized/bash_responses_api.json +32 -0
- package/.claude/hooks/tests/fixtures/normalized/bash_safe_command.json +23 -0
- package/.claude/hooks/tests/fixtures/normalized/post_audit_event.json +31 -0
- package/.claude/hooks/tests/fixtures/output_safety/control/01_random_hash_log.txt +1 -0
- package/.claude/hooks/tests/fixtures/output_safety/control/02_docs_mention_email_no_address.txt +1 -0
- package/.claude/hooks/tests/fixtures/output_safety/control/03_partial_jwt_two_segments.txt +1 -0
- package/.claude/hooks/tests/fixtures/output_safety/control/04_random_11_digits_no_cpf_context.txt +1 -0
- package/.claude/hooks/tests/fixtures/output_safety/control/05_credit_card_shape_invalid_luhn.txt +1 -0
- package/.claude/hooks/tests/fixtures/output_safety/positive/01_api_key_anthropic.txt +1 -0
- package/.claude/hooks/tests/fixtures/output_safety/positive/02_api_key_github_pat_classic.txt +1 -0
- package/.claude/hooks/tests/fixtures/output_safety/positive/03_api_key_github_fine_grained.txt +1 -0
- package/.claude/hooks/tests/fixtures/output_safety/positive/04_api_key_aws_access_key.txt +1 -0
- package/.claude/hooks/tests/fixtures/output_safety/positive/05_api_key_aws_secret_assignment.txt +1 -0
- package/.claude/hooks/tests/fixtures/output_safety/positive/06_jwt.txt +1 -0
- package/.claude/hooks/tests/fixtures/output_safety/positive/07_bearer.txt +1 -0
- package/.claude/hooks/tests/fixtures/output_safety/positive/08_cpf_with_context.txt +1 -0
- package/.claude/hooks/tests/fixtures/output_safety/positive/09_cnpj_with_context.txt +1 -0
- package/.claude/hooks/tests/fixtures/output_safety/positive/10_credit_card_luhn_valid.txt +1 -0
- package/.claude/hooks/tests/fixtures/output_safety/positive/11_email_in_login_context.txt +1 -0
- package/.claude/hooks/tests/fixtures/output_safety/positive/12_nfkc_full_width.txt +1 -0
- package/.claude/hooks/tests/fixtures/output_safety/positive/13_zero_width_evasion.txt +1 -0
- package/.claude/hooks/tests/fixtures/output_safety/positive/14_bidi_evasion.txt +1 -0
- package/.claude/hooks/tests/fixtures/output_safety/positive/15_base64_encoded_secret.txt +1 -0
- package/.claude/hooks/tests/fixtures/output_scan/scenarios.jsonl +45 -0
- package/.claude/hooks/tests/fixtures/sample_payload_clean.json +13 -0
- package/.claude/hooks/tests/fixtures/sample_payload_with_secrets.json +12 -0
- package/.claude/hooks/tests/mutations/README.md +86 -0
- package/.claude/hooks/tests/mutations/__init__.py +14 -0
- package/.claude/hooks/tests/mutations/engine_mutations/__init__.py +15 -0
- package/.claude/hooks/tests/mutations/engine_mutations/mutation_01_parser_accepts_anchor.py +51 -0
- package/.claude/hooks/tests/mutations/engine_mutations/mutation_02_parser_skip_depth_limit.py +38 -0
- package/.claude/hooks/tests/mutations/engine_mutations/mutation_03_parser_accept_multi_doc.py +47 -0
- package/.claude/hooks/tests/mutations/engine_mutations/mutation_04_parser_accepts_bom.py +41 -0
- package/.claude/hooks/tests/mutations/engine_mutations/mutation_05_parser_scalar_len_off_by_one.py +61 -0
- package/.claude/hooks/tests/mutations/engine_mutations/mutation_06_parser_accepts_python_tag.py +50 -0
- package/.claude/hooks/tests/mutations/engine_mutations/mutation_07_parser_accepts_tab_indent.py +56 -0
- package/.claude/hooks/tests/mutations/engine_mutations/mutation_08_compiler_skip_regex_compile.py +45 -0
- package/.claude/hooks/tests/mutations/engine_mutations/mutation_09_compiler_regex_pattern_cap_off.py +31 -0
- package/.claude/hooks/tests/mutations/engine_mutations/mutation_10_compiler_accept_unknown_form.py +42 -0
- package/.claude/hooks/tests/mutations/engine_mutations/mutation_11_compiler_missing_predicate_tolerated.py +79 -0
- package/.claude/hooks/tests/mutations/engine_mutations/mutation_12_compiler_duplicate_rule_id_tolerated.py +66 -0
- package/.claude/hooks/tests/mutations/engine_mutations/mutation_13_compiler_missing_top_level_key_tolerated.py +46 -0
- package/.claude/hooks/tests/mutations/engine_mutations/mutation_14_compiler_schema_version_passthrough.py +43 -0
- package/.claude/hooks/tests/mutations/engine_mutations/mutation_15_evaluator_any_empty_returns_true.py +41 -0
- package/.claude/hooks/tests/mutations/engine_mutations/mutation_16_evaluator_all_empty_returns_true.py +37 -0
- package/.claude/hooks/tests/mutations/engine_mutations/mutation_17_evaluator_not_passthrough.py +37 -0
- package/.claude/hooks/tests/mutations/engine_mutations/mutation_18_evaluator_eq_true_on_type_mismatch.py +51 -0
- package/.claude/hooks/tests/mutations/engine_mutations/mutation_19_evaluator_regex_match_only.py +43 -0
- package/.claude/hooks/tests/mutations/engine_mutations/mutation_20_evaluator_path_under_no_realpath.py +48 -0
- package/.claude/hooks/tests/mutations/engine_mutations/mutation_21_evaluator_in_accepts_any.py +37 -0
- package/.claude/hooks/tests/mutations/engine_mutations/mutation_22_evaluator_length_off_by_one.py +45 -0
- package/.claude/hooks/tests/mutations/engine_mutations/mutation_23_evaluator_first_match_becomes_last.py +66 -0
- package/.claude/hooks/tests/mutations/engine_mutations/mutation_24_error_model_wrong_kind_on_parse.py +39 -0
- package/.claude/hooks/tests/mutations/engine_mutations/mutation_25_error_model_fail_open_on_load.py +42 -0
- package/.claude/hooks/tests/mutations/policy_mutations/__init__.py +16 -0
- package/.claude/hooks/tests/mutations/policy_mutations/mutation_bash_01_remove_credential_leak.py +49 -0
- package/.claude/hooks/tests/mutations/policy_mutations/mutation_bash_02_remove_rm_rf.py +44 -0
- package/.claude/hooks/tests/mutations/policy_mutations/mutation_bash_03_remove_git_reset_hard.py +44 -0
- package/.claude/hooks/tests/mutations/policy_mutations/mutation_bash_04_remove_git_push_force.py +44 -0
- package/.claude/hooks/tests/mutations/policy_mutations/mutation_bash_05_reorder_rules.py +59 -0
- package/.claude/hooks/tests/mutations/policy_mutations/mutation_bash_06_change_reason_enum.py +54 -0
- package/.claude/hooks/tests/mutations/policy_mutations/mutation_bash_07_default_flipped_to_block.py +56 -0
- package/.claude/hooks/tests/mutations/policy_mutations/mutation_bash_08_flip_rm_rf_to_allow.py +49 -0
- package/.claude/hooks/tests/mutations/policy_mutations/mutation_plan_01_remove_illegal_transition.py +79 -0
- package/.claude/hooks/tests/mutations/policy_mutations/mutation_plan_02_remove_illegal_status.py +80 -0
- package/.claude/hooks/tests/mutations/policy_mutations/mutation_plan_03_remove_missing_reviewed_at.py +80 -0
- package/.claude/hooks/tests/mutations/policy_mutations/mutation_plan_04_remove_missing_completed_at.py +80 -0
- package/.claude/hooks/tests/mutations/policy_mutations/mutation_plan_05_remove_missing_related_commits.py +79 -0
- package/.claude/hooks/tests/mutations/policy_mutations/mutation_plan_06_remove_missing_abandonment_reason.py +80 -0
- package/.claude/hooks/tests/mutations/policy_mutations/mutation_plan_07_scope_guard_inverted.py +93 -0
- package/.claude/hooks/tests/mutations/policy_mutations/mutation_plan_08_default_block.py +90 -0
- package/.claude/hooks/tests/probes/test_architect_probe.py +286 -0
- package/.claude/hooks/tests/probes/test_canonical_edit_probe.py +190 -0
- package/.claude/hooks/tests/probes/test_skill_content_probe.py +219 -0
- package/.claude/hooks/tests/test_SessionEnd.py +59 -0
- package/.claude/hooks/tests/test_SessionStart.py +42 -0
- package/.claude/hooks/tests/test_UserPromptSubmit.py +47 -0
- package/.claude/hooks/tests/test_accel_dispatch.py +96 -0
- package/.claude/hooks/tests/test_action_required_invariants.py +274 -0
- package/.claude/hooks/tests/test_adapter_drift_detector.py +254 -0
- package/.claude/hooks/tests/test_adapter_golden.py +198 -0
- package/.claude/hooks/tests/test_adequacy_gate.py +86 -0
- package/.claude/hooks/tests/test_adr_052_role_to_model_coverage.py +112 -0
- package/.claude/hooks/tests/test_adr_058_brainstorm_structure.py +280 -0
- package/.claude/hooks/tests/test_adversary_rules_live.py +400 -0
- package/.claude/hooks/tests/test_agent_frontmatter.py +377 -0
- package/.claude/hooks/tests/test_anti_ceo_overhead.py +591 -0
- package/.claude/hooks/tests/test_audit_emit.py +1707 -0
- package/.claude/hooks/tests/test_audit_emit_api_contract.py +693 -0
- package/.claude/hooks/tests/test_audit_emit_async_flush.py +563 -0
- package/.claude/hooks/tests/test_audit_emit_backpressure.py +138 -0
- package/.claude/hooks/tests/test_audit_emit_callsite_coverage_matrix.py +101 -0
- package/.claude/hooks/tests/test_audit_emit_chain_length.py +357 -0
- package/.claude/hooks/tests/test_audit_emit_coverage.py +2679 -0
- package/.claude/hooks/tests/test_audit_emit_ghost_action_guard.py +447 -0
- package/.claude/hooks/tests/test_audit_emit_plan088_canonical13.py +323 -0
- package/.claude/hooks/tests/test_audit_emit_rotation.py +218 -0
- package/.claude/hooks/tests/test_audit_emit_veto_v214.py +202 -0
- package/.claude/hooks/tests/test_audit_emit_wire_audit.py +699 -0
- package/.claude/hooks/tests/test_audit_hmac.py +334 -0
- package/.claude/hooks/tests/test_audit_hmac_branch_coverage.py +212 -0
- package/.claude/hooks/tests/test_audit_hmac_chain_monotonicity_property.py +136 -0
- package/.claude/hooks/tests/test_audit_hmac_coverage_v214.py +358 -0
- package/.claude/hooks/tests/test_audit_hmac_hardening.py +302 -0
- package/.claude/hooks/tests/test_audit_hmac_rotation_scenarios.py +231 -0
- package/.claude/hooks/tests/test_audit_hmac_verify_chain.py +443 -0
- package/.claude/hooks/tests/test_audit_log.py +280 -0
- package/.claude/hooks/tests/test_audit_log_coverage.py +173 -0
- package/.claude/hooks/tests/test_audit_log_path_d.py +516 -0
- package/.claude/hooks/tests/test_audit_log_phase1.py +358 -0
- package/.claude/hooks/tests/test_audit_log_schema_consistency.py +97 -0
- package/.claude/hooks/tests/test_audit_log_security.py +289 -0
- package/.claude/hooks/tests/test_audit_log_tokens.py +92 -0
- package/.claude/hooks/tests/test_audit_log_v2_7.py +378 -0
- package/.claude/hooks/tests/test_audit_log_v2_8_model.py +201 -0
- package/.claude/hooks/tests/test_audit_rotation.py +158 -0
- package/.claude/hooks/tests/test_audit_stream_verbose_protection.py +86 -0
- package/.claude/hooks/tests/test_audit_tokens_content_ban.py +512 -0
- package/.claude/hooks/tests/test_auto_boot.py +28 -0
- package/.claude/hooks/tests/test_available_models_mirror.py +226 -0
- package/.claude/hooks/tests/test_bash_canonical_forensic.py +74 -0
- package/.claude/hooks/tests/test_bash_canonical_interceptor.py +79 -0
- package/.claude/hooks/tests/test_brotli_passthrough.py +145 -0
- package/.claude/hooks/tests/test_byte_identity_fuzzer.py +185 -0
- package/.claude/hooks/tests/test_byte_identity_harness.py +953 -0
- package/.claude/hooks/tests/test_canonical_guard_typed_exceptions.py +117 -0
- package/.claude/hooks/tests/test_canonical_json.py +153 -0
- package/.claude/hooks/tests/test_chain_invariants_property.py +132 -0
- package/.claude/hooks/tests/test_check_adversary_live.py +149 -0
- package/.claude/hooks/tests/test_check_agent_spawn.py +1084 -0
- package/.claude/hooks/tests/test_check_agent_spawn_coverage.py +277 -0
- package/.claude/hooks/tests/test_check_agent_spawn_effort_token.py +74 -0
- package/.claude/hooks/tests/test_check_agent_spawn_import_isolation.py +82 -0
- package/.claude/hooks/tests/test_check_agent_spawn_model_routing_mode.py +245 -0
- package/.claude/hooks/tests/test_check_agent_spawn_reference_bypass.py +385 -0
- package/.claude/hooks/tests/test_check_agent_spawn_routing_promotion.py +302 -0
- package/.claude/hooks/tests/test_check_agent_spawn_skill_reference.py +336 -0
- package/.claude/hooks/tests/test_check_arbitration_kernel.py +472 -0
- package/.claude/hooks/tests/test_check_arbitration_kernel_v214.py +157 -0
- package/.claude/hooks/tests/test_check_bash_safety.py +546 -0
- package/.claude/hooks/tests/test_check_bash_safety_canonical_matrix.py +336 -0
- package/.claude/hooks/tests/test_check_bash_safety_cp_chaining.py +120 -0
- package/.claude/hooks/tests/test_check_bash_safety_h5_rewrite.py +462 -0
- package/.claude/hooks/tests/test_check_budget.py +580 -0
- package/.claude/hooks/tests/test_check_budget_max_tokens.py +397 -0
- package/.claude/hooks/tests/test_check_budget_quota_hint.py +115 -0
- package/.claude/hooks/tests/test_check_canonical_edit.py +302 -0
- package/.claude/hooks/tests/test_check_canonical_edit_coverage.py +370 -0
- package/.claude/hooks/tests/test_check_canonical_edit_kernel_v2.py +401 -0
- package/.claude/hooks/tests/test_check_canonical_edit_markers.py +473 -0
- package/.claude/hooks/tests/test_check_canonical_edit_mcp.py +401 -0
- package/.claude/hooks/tests/test_check_canonical_edit_session67_format.py +245 -0
- package/.claude/hooks/tests/test_check_codex_filewrite.py +964 -0
- package/.claude/hooks/tests/test_check_codex_response.py +419 -0
- package/.claude/hooks/tests/test_check_compaction_continuity.py +450 -0
- package/.claude/hooks/tests/test_check_confidence_gate.py +326 -0
- package/.claude/hooks/tests/test_check_config_change.py +369 -0
- package/.claude/hooks/tests/test_check_config_protection.py +364 -0
- package/.claude/hooks/tests/test_check_fluency_nudge.py +321 -0
- package/.claude/hooks/tests/test_check_mcp_response.py +261 -0
- package/.claude/hooks/tests/test_check_output_safety.py +314 -0
- package/.claude/hooks/tests/test_check_output_secrets.py +488 -0
- package/.claude/hooks/tests/test_check_output_secrets_coverage.py +321 -0
- package/.claude/hooks/tests/test_check_pair_rail.py +897 -0
- package/.claude/hooks/tests/test_check_pair_rail_decide_canonical.py +297 -0
- package/.claude/hooks/tests/test_check_pair_rail_golden.py +362 -0
- package/.claude/hooks/tests/test_check_pair_rail_hook_integration.py +120 -0
- package/.claude/hooks/tests/test_check_pair_rail_matrix.py +1077 -0
- package/.claude/hooks/tests/test_check_plan_edit.py +679 -0
- package/.claude/hooks/tests/test_check_plan_edit_stranded.py +310 -0
- package/.claude/hooks/tests/test_check_protocol_semver_cascade.py +141 -0
- package/.claude/hooks/tests/test_check_protocol_semver_cascade_settings_wired.py +297 -0
- package/.claude/hooks/tests/test_check_protocol_semver_cascade_synccascade.py +365 -0
- package/.claude/hooks/tests/test_check_read_injection.py +143 -0
- package/.claude/hooks/tests/test_check_read_injection_coverage.py +237 -0
- package/.claude/hooks/tests/test_check_read_injection_pathbound.py +153 -0
- package/.claude/hooks/tests/test_check_scratchpad_access.py +244 -0
- package/.claude/hooks/tests/test_check_skill_bootstrap_post.py +256 -0
- package/.claude/hooks/tests/test_check_skill_patch_sentinel.py +439 -0
- package/.claude/hooks/tests/test_check_skill_reference_read.py +170 -0
- package/.claude/hooks/tests/test_check_skill_reference_read_v2.py +388 -0
- package/.claude/hooks/tests/test_check_subagent_fabrication.py +54 -0
- package/.claude/hooks/tests/test_check_subagent_start.py +505 -0
- package/.claude/hooks/tests/test_check_tier_policy.py +48 -0
- package/.claude/hooks/tests/test_check_tier_policy_misrouting_24h.py +294 -0
- package/.claude/hooks/tests/test_check_webfetch_injection.py +49 -0
- package/.claude/hooks/tests/test_claim_producer_pair_end_to_end_loop_perf.py +227 -0
- package/.claude/hooks/tests/test_claude_adapter_thinking.py +731 -0
- package/.claude/hooks/tests/test_claude_batch_adapter.py +672 -0
- package/.claude/hooks/tests/test_closeout_guard.py +184 -0
- package/.claude/hooks/tests/test_codex_adapter.py +777 -0
- package/.claude/hooks/tests/test_codex_cli_shape.py +217 -0
- package/.claude/hooks/tests/test_codex_egress_proof_telemetry.py +214 -0
- package/.claude/hooks/tests/test_codex_egress_redact.py +342 -0
- package/.claude/hooks/tests/test_codex_egress_redact_outgoing.py +236 -0
- package/.claude/hooks/tests/test_codex_reply_multi_turn.py +72 -0
- package/.claude/hooks/tests/test_codex_review_user_code.py +44 -0
- package/.claude/hooks/tests/test_codex_strict_json.py +123 -0
- package/.claude/hooks/tests/test_confidence_gate_producer_pair.py +522 -0
- package/.claude/hooks/tests/test_confidence_labels.py +362 -0
- package/.claude/hooks/tests/test_contract.py +237 -0
- package/.claude/hooks/tests/test_cookbook_advisor_hook.py +208 -0
- package/.claude/hooks/tests/test_credentials.py +195 -0
- package/.claude/hooks/tests/test_detect_repo_profile_branches.py +116 -0
- package/.claude/hooks/tests/test_e2e_hook_chain.py +184 -0
- package/.claude/hooks/tests/test_effective_config.py +648 -0
- package/.claude/hooks/tests/test_emit_architect_outcome.py +175 -0
- package/.claude/hooks/tests/test_env_persist_allowlist.py +365 -0
- package/.claude/hooks/tests/test_escalation_signals.py +357 -0
- package/.claude/hooks/tests/test_estimation_bayesian_pipeline.py +140 -0
- package/.claude/hooks/tests/test_execution_context_deferral.py +222 -0
- package/.claude/hooks/tests/test_fail_open_contract.py +118 -0
- package/.claude/hooks/tests/test_file_walker.py +332 -0
- package/.claude/hooks/tests/test_filelock.py +131 -0
- package/.claude/hooks/tests/test_filelock_contract.py +172 -0
- package/.claude/hooks/tests/test_find_sentinels_pattern_matrix.py +114 -0
- package/.claude/hooks/tests/test_flip_closures.py +219 -0
- package/.claude/hooks/tests/test_frontmatter.py +139 -0
- package/.claude/hooks/tests/test_git_bypass_guard.py +1095 -0
- package/.claude/hooks/tests/test_gpg_verify.py +578 -0
- package/.claude/hooks/tests/test_hook_byte_fidelity.py +113 -0
- package/.claude/hooks/tests/test_hook_latency.py +245 -0
- package/.claude/hooks/tests/test_hook_latency_import.py +178 -0
- package/.claude/hooks/tests/test_injection_patterns.py +276 -0
- package/.claude/hooks/tests/test_injection_patterns_bypass.py +276 -0
- package/.claude/hooks/tests/test_injection_salt.py +191 -0
- package/.claude/hooks/tests/test_kernel_subsumes_security_critical_lib.py +88 -0
- package/.claude/hooks/tests/test_kill_switch_godmode_enforcing.py +101 -0
- package/.claude/hooks/tests/test_latency_report.py +28 -0
- package/.claude/hooks/tests/test_lib_canonical_import.py +355 -0
- package/.claude/hooks/tests/test_lifecycle_edge_cases.py +565 -0
- package/.claude/hooks/tests/test_live_adapters.py +463 -0
- package/.claude/hooks/tests/test_live_audit_isolation.py +357 -0
- package/.claude/hooks/tests/test_mcp_bearer_friction_buffer.py +276 -0
- package/.claude/hooks/tests/test_mcp_bearer_friction_emit.py +117 -0
- package/.claude/hooks/tests/test_mcp_canonical_guard.py +1989 -0
- package/.claude/hooks/tests/test_mcp_injection_repro_harness.py +437 -0
- package/.claude/hooks/tests/test_mcp_injection_scan.py +228 -0
- package/.claude/hooks/tests/test_mcp_routing_resolve.py +246 -0
- package/.claude/hooks/tests/test_memory_shared.py +412 -0
- package/.claude/hooks/tests/test_metrics.py +115 -0
- package/.claude/hooks/tests/test_migrated_hooks_fixtures.py +121 -0
- package/.claude/hooks/tests/test_model_routing.py +175 -0
- package/.claude/hooks/tests/test_model_routing_resolve.py +97 -0
- package/.claude/hooks/tests/test_model_routing_resolve_full.py +318 -0
- package/.claude/hooks/tests/test_otel_bounded_exporter.py +521 -0
- package/.claude/hooks/tests/test_otel_emit.py +243 -0
- package/.claude/hooks/tests/test_otel_queue.py +334 -0
- package/.claude/hooks/tests/test_otel_wire_defaultoff.py +392 -0
- package/.claude/hooks/tests/test_output_scan.py +1119 -0
- package/.claude/hooks/tests/test_output_scan_dedup.py +329 -0
- package/.claude/hooks/tests/test_output_scan_fixtures.py +136 -0
- package/.claude/hooks/tests/test_pair_rail_decide.py +141 -0
- package/.claude/hooks/tests/test_payload.py +89 -0
- package/.claude/hooks/tests/test_persona_coverage_wire.py +376 -0
- package/.claude/hooks/tests/test_persona_routing_enforcing.py +119 -0
- package/.claude/hooks/tests/test_phase_c_advisory_audit.py +75 -0
- package/.claude/hooks/tests/test_pii_patterns.py +558 -0
- package/.claude/hooks/tests/test_plan114_wires.py +468 -0
- package/.claude/hooks/tests/test_plan128_emit_wiring.py +74 -0
- package/.claude/hooks/tests/test_plan132_codex_review_observe.py +99 -0
- package/.claude/hooks/tests/test_plan133_a1_env_guard.py +221 -0
- package/.claude/hooks/tests/test_plan133_a2_canonical_skill_unicode.py +359 -0
- package/.claude/hooks/tests/test_plan133_a2_invisible_unicode.py +239 -0
- package/.claude/hooks/tests/test_plan133_a3_egress_taxonomy.py +221 -0
- package/.claude/hooks/tests/test_plan133_e1_adversary.py +360 -0
- package/.claude/hooks/tests/test_plan_085_wave_c_callsites_preserved.py +147 -0
- package/.claude/hooks/tests/test_plan_091_expected_callsites.py +206 -0
- package/.claude/hooks/tests/test_plan_frontmatter.py +217 -0
- package/.claude/hooks/tests/test_policy_coverage_residual_session73.py +597 -0
- package/.claude/hooks/tests/test_policy_coverage_v214.py +1099 -0
- package/.claude/hooks/tests/test_policy_dispatch.py +454 -0
- package/.claude/hooks/tests/test_policy_engine.py +791 -0
- package/.claude/hooks/tests/test_policy_fuzz_bomb.py +356 -0
- package/.claude/hooks/tests/test_policy_golden_error_kinds.py +287 -0
- package/.claude/hooks/tests/test_policy_mutations.py +359 -0
- package/.claude/hooks/tests/test_policy_preprocessors.py +514 -0
- package/.claude/hooks/tests/test_policy_redos_guards.py +393 -0
- package/.claude/hooks/tests/test_rag_bridge.py +675 -0
- package/.claude/hooks/tests/test_rag_events.py +202 -0
- package/.claude/hooks/tests/test_red_team_fixtures.py +427 -0
- package/.claude/hooks/tests/test_redact.py +506 -0
- package/.claude/hooks/tests/test_redact_redos.py +254 -0
- package/.claude/hooks/tests/test_redact_secrets_parity.py +334 -0
- package/.claude/hooks/tests/test_replay_determinism.py +263 -0
- package/.claude/hooks/tests/test_review_loop.py +28 -0
- package/.claude/hooks/tests/test_review_loop_wiring.py +206 -0
- package/.claude/hooks/tests/test_route.py +36 -0
- package/.claude/hooks/tests/test_rubric_catalogue.py +359 -0
- package/.claude/hooks/tests/test_scratchpad_lib.py +259 -0
- package/.claude/hooks/tests/test_secret_patterns.py +680 -0
- package/.claude/hooks/tests/test_secret_patterns_provenance.py +82 -0
- package/.claude/hooks/tests/test_sentinel_session_cache.py +324 -0
- package/.claude/hooks/tests/test_sentinel_session_cache_tier1.py +205 -0
- package/.claude/hooks/tests/test_sentinel_signers.py +641 -0
- package/.claude/hooks/tests/test_session_75_kernel_findings.py +180 -0
- package/.claude/hooks/tests/test_session_76_audit_v3_findings.py +493 -0
- package/.claude/hooks/tests/test_session_77_audit_v3_backlog_findings.py +644 -0
- package/.claude/hooks/tests/test_session_77_round_2_findings.py +135 -0
- package/.claude/hooks/tests/test_session_77_round_3_findings.py +159 -0
- package/.claude/hooks/tests/test_session_77_round_4_findings.py +120 -0
- package/.claude/hooks/tests/test_session_end.py +113 -0
- package/.claude/hooks/tests/test_session_start.py +293 -0
- package/.claude/hooks/tests/test_skill_unknown_ratio_path_d.py +249 -0
- package/.claude/hooks/tests/test_smart_loading_resolver_caching.py +140 -0
- package/.claude/hooks/tests/test_spec_context_sanitizer.py +179 -0
- package/.claude/hooks/tests/test_spool_drain_contended_skip.py +249 -0
- package/.claude/hooks/tests/test_spool_drain_rotation_property_b.py +227 -0
- package/.claude/hooks/tests/test_spool_drain_rotation_race.py +395 -0
- package/.claude/hooks/tests/test_spool_writer_cache.py +463 -0
- package/.claude/hooks/tests/test_state_store.py +302 -0
- package/.claude/hooks/tests/test_stop.py +133 -0
- package/.claude/hooks/tests/test_streaming_rate_cap.py +108 -0
- package/.claude/hooks/tests/test_subagent_dispatch.py +248 -0
- package/.claude/hooks/tests/test_subagent_model_override_removed.py +108 -0
- package/.claude/hooks/tests/test_team.py +95 -0
- package/.claude/hooks/tests/test_template_dogfood_parity.py +106 -0
- package/.claude/hooks/tests/test_terminal_compress.py +135 -0
- package/.claude/hooks/tests/test_test_env_context_agent_binding.py +140 -0
- package/.claude/hooks/tests/test_testing_helper.py +53 -0
- package/.claude/hooks/tests/test_thinking_budget_command.py +229 -0
- package/.claude/hooks/tests/test_tier_policy_agent_frontmatter.py +421 -0
- package/.claude/hooks/tests/test_tier_policy_agent_frontmatter_disposition.py +175 -0
- package/.claude/hooks/tests/test_tier_policy_constants.py +336 -0
- package/.claude/hooks/tests/test_tier_policy_loader.py +544 -0
- package/.claude/hooks/tests/test_tier_policy_loader_fallback_observed.py +169 -0
- package/.claude/hooks/tests/test_tier_policy_types.py +270 -0
- package/.claude/hooks/tests/test_tokens_lib.py +118 -0
- package/.claude/hooks/tests/test_tool_lifecycle.py +598 -0
- package/.claude/hooks/tests/test_tool_lifecycle_perf.py +110 -0
- package/.claude/hooks/tests/test_turbo_profile.py +28 -0
- package/.claude/hooks/tests/test_turbo_sessionstart.py +79 -0
- package/.claude/hooks/tests/test_two_writer_chain.py +175 -0
- package/.claude/hooks/tests/test_upgrade_retry.py +346 -0
- package/.claude/hooks/tests/test_user_prompt_submit.py +254 -0
- package/.claude/hooks/tests/test_user_prompt_submit_salt.py +204 -0
- package/.claude/hooks/tests/test_verify_after_edit.py +100 -0
- package/.claude/hooks/tests/test_veto_floor_bijection.py +174 -0
- package/.claude/hooks/tests/test_w5_cookbook_remediation.py +712 -0
- package/.claude/hooks/tests/test_w5_scrub_enforcement.py +371 -0
- package/.claude/hooks/tests/test_webfetch_injection.py +280 -0
- package/.claude/hooks/tests/test_wiredeadmod_estimation_wiring.py +283 -0
- package/.claude/hooks/tests/test_wiredeadmod_spawn_wiring.py +303 -0
- package/.claude/hooks/tests/test_worktree_writer.py +509 -0
- package/.claude/hooks/turbo_profile.py +554 -0
- package/.claude/hooks/turbo_sessionstart.py +472 -0
- package/.claude/hooks/verify_after_edit.py +281 -0
- package/.claude/pitfalls-catalog.yaml +150 -0
- package/.claude/plans/AUDIT-LOG-SCHEMA.md +548 -0
- package/.claude/plans/DEBATE-SCHEMA.md +539 -0
- package/.claude/plans/PLAN-128/AB-PROTOCOL.md +121 -0
- package/.claude/plans/PLAN-128/measure-state.sh +101 -0
- package/.claude/plans/PLAN-139-canonical-invariants-and-debt-ledger.md +253 -0
- package/.claude/plans/PLAN-140/architect/round-1/approved.md +40 -0
- package/.claude/plans/PLAN-140-compaction-hook-origin-dropfix.md +95 -0
- package/.claude/plans/PLAN-141/architect/round-1/approved.md +28 -0
- package/.claude/plans/PLAN-141-mcp-smoke-staging-ruff-tolerance.md +72 -0
- package/.claude/plans/PLAN-142/architect/round-1/anonymization-map.md +11 -0
- package/.claude/plans/PLAN-142/architect/round-1/consensus.md +95 -0
- package/.claude/plans/PLAN-142/architect/round-1/devops-engineer.md +57 -0
- package/.claude/plans/PLAN-142/architect/round-1/proposal.md +57 -0
- package/.claude/plans/PLAN-142/architect/round-1/security-engineer.md +55 -0
- package/.claude/plans/PLAN-142/architect/round-1/vp-engineering.md +58 -0
- package/.claude/plans/PLAN-142/architect/round-2/anonymization-map.md +11 -0
- package/.claude/plans/PLAN-142/architect/round-2/approved.md +65 -0
- package/.claude/plans/PLAN-142/architect/round-2/consensus.md +78 -0
- package/.claude/plans/PLAN-142/architect/round-2/devops-engineer.md +58 -0
- package/.claude/plans/PLAN-142/architect/round-2/security-engineer.md +56 -0
- package/.claude/plans/PLAN-142/architect/round-2/vp-engineering.md +54 -0
- package/.claude/plans/PLAN-142/staging/EXECUTION-RUNBOOK.md +74 -0
- package/.claude/plans/PLAN-142/staging/STAGING-NOTES.md +63 -0
- package/.claude/plans/PLAN-142/staging/check_pair_rail__invoke_and_consume.py.txt +644 -0
- package/.claude/plans/PLAN-142/staging/codex_adapter_parsers.py.txt +677 -0
- package/.claude/plans/PLAN-142/staging/codex_cli_shape.py +433 -0
- package/.claude/plans/PLAN-142-codex-cli-0139-adapter-migration.md +224 -0
- package/.claude/plans/PLAN-143/architect/round-1/anonymization-map.md +22 -0
- package/.claude/plans/PLAN-143/architect/round-1/consensus.md +108 -0
- package/.claude/plans/PLAN-143/architect/round-1/devops-engineer.md +228 -0
- package/.claude/plans/PLAN-143/architect/round-1/proposal.md +48 -0
- package/.claude/plans/PLAN-143/architect/round-1/security-engineer.md +224 -0
- package/.claude/plans/PLAN-143/architect/round-1/vp-engineering.md +166 -0
- package/.claude/plans/PLAN-143/patches/PLAN143-item1-env-inventory.NOTE.md +106 -0
- package/.claude/plans/PLAN-143/patches/PLAN143-item2-spool-writer-rotate-guard.patch +41 -0
- package/.claude/plans/PLAN-143/patches/PLAN143-item3-audit-emit-exit-code.patch +32 -0
- package/.claude/plans/PLAN-143-repo-hygiene-debt.md +201 -0
- package/.claude/plans/PLAN-SCHEMA.md +870 -0
- package/.claude/plans/README.md +208 -0
- package/.claude/plans/examples/debate-round-1/consensus.md +166 -0
- package/.claude/plans/examples/debate-round-1/devops-engineer.md +133 -0
- package/.claude/plans/examples/debate-round-1/proposal.md +66 -0
- package/.claude/plans/examples/debate-round-1/security-engineer.md +109 -0
- package/.claude/plans/examples/debate-round-1/vp-engineering.md +110 -0
- package/.claude/policies/.drift-manifest.json +16 -0
- package/.claude/policies/bash-safety.policy.yaml +37 -0
- package/.claude/policies/fixtures/.gitkeep +0 -0
- package/.claude/policies/fixtures/bash-safety.fixtures.jsonl +46 -0
- package/.claude/policies/fixtures/plan-edit.fixtures.jsonl +36 -0
- package/.claude/policies/grandfather-cap.policy.yaml +85 -0
- package/.claude/policies/plan-edit.policy.yaml +152 -0
- package/.claude/policies/rubric-violation-catalogue.yaml +187 -0
- package/.claude/policies/schemas/repo-profile-skill-binding.schema.json +126 -0
- package/.claude/policies/schemas/repo-profile.schema.json +83 -0
- package/.claude/policies/schemas/squad-bundle-frontmatter.schema.json +152 -0
- package/.claude/policies/secret-patterns-exchange.yaml +368 -0
- package/.claude/policies/smart-loading-cap-table.yaml +34 -0
- package/.claude/proposals/.gitkeep +0 -0
- package/.claude/proposals/README.md +42 -0
- package/.claude/proposals/SP-001-code-review-checklist-2026-04-20.md +65 -0
- package/.claude/proposals/SP-001-code-review-checklist-2026-04-20.md.asc +8 -0
- package/.claude/proposals/SP-002-security-and-auth-2026-04-20.md +74 -0
- package/.claude/proposals/SP-002-security-and-auth-2026-04-20.md.asc +8 -0
- package/.claude/proposals/SP-003-design-system-and-components-2026-04-20.md +67 -0
- package/.claude/proposals/SP-003-design-system-and-components-2026-04-20.md.asc +8 -0
- package/.claude/proposals/SP-004-accessibility-and-wcag-2026-04-20.md +68 -0
- package/.claude/proposals/SP-004-accessibility-and-wcag-2026-04-20.md.asc +8 -0
- package/.claude/proposals/SP-005-ux-and-user-journeys-2026-04-20.md +63 -0
- package/.claude/proposals/SP-005-ux-and-user-journeys-2026-04-20.md.asc +8 -0
- package/.claude/proposals/SP-006-chaos-and-resilience-2026-04-20.md +79 -0
- package/.claude/proposals/SP-006-chaos-and-resilience-2026-04-20.md.asc +8 -0
- package/.claude/proposals/SP-007-ai-llm-orchestration-2026-04-20.md +76 -0
- package/.claude/proposals/SP-007-ai-llm-orchestration-2026-04-20.md.asc +8 -0
- package/.claude/proposals/SP-008-performance-engineering-2026-04-20.md +82 -0
- package/.claude/proposals/SP-008-performance-engineering-2026-04-20.md.asc +8 -0
- package/.claude/proposals/SP-009-code-review-checklist-2026-04-20.md +76 -0
- package/.claude/proposals/SP-009-code-review-checklist-2026-04-20.md.asc +8 -0
- package/.claude/proposals/SP-010-accessibility-and-wcag-adopter-note-2026-04-20.md +77 -0
- package/.claude/proposals/SP-010-accessibility-and-wcag-adopter-note-2026-04-20.md.asc +8 -0
- package/.claude/proposals/SP-011-design-system-and-components-adopter-note-2026-04-20.md +79 -0
- package/.claude/proposals/SP-011-design-system-and-components-adopter-note-2026-04-20.md.asc +8 -0
- package/.claude/proposals/SP-012-ux-and-user-journeys-adopter-note-2026-04-20.md +83 -0
- package/.claude/proposals/SP-012-ux-and-user-journeys-adopter-note-2026-04-20.md.asc +8 -0
- package/.claude/proposals/SP-013-frontend-performance-optimization-2026-04-20.md +82 -0
- package/.claude/proposals/SP-013-frontend-performance-optimization-2026-04-20.md.asc +8 -0
- package/.claude/proposals/SP-014-observability-and-ops-2026-04-20.md +80 -0
- package/.claude/proposals/SP-014-observability-and-ops-2026-04-20.md.asc +8 -0
- package/.claude/proposals/SP-015-testing-strategy-2026-04-20.md +87 -0
- package/.claude/proposals/SP-015-testing-strategy-2026-04-20.md.asc +8 -0
- package/.claude/proposals/SP-016-code-review-checklist-fluency-rubric-2026-04-28.md +111 -0
- package/.claude/proposals/SP-016-code-review-checklist-fluency-rubric-2026-04-28.md.asc +8 -0
- package/.claude/proposals/SP-017-chaos-and-resilience-adopter-note-2026-04-28.md +87 -0
- package/.claude/proposals/SP-017-chaos-and-resilience-adopter-note-2026-04-28.md.asc +8 -0
- package/.claude/proposals/SP-018-ceo-orchestration-inventory-regen-2026-04-21.md +64 -0
- package/.claude/proposals/SP-018-ceo-orchestration-inventory-regen-2026-04-21.md.asc +8 -0
- package/.claude/proposals/SP-019-terse-mode-2026-04-21.md +107 -0
- package/.claude/proposals/SP-019-terse-mode-2026-04-21.md.asc +8 -0
- package/.claude/proposals/SP-020-ceo-orchestration-audit-tokens-2026-04-21.md +74 -0
- package/.claude/proposals/SP-020-ceo-orchestration-audit-tokens-2026-04-21.md.asc +8 -0
- package/.claude/proposals/SP-021-ceo-orchestration-autonomous-loop-2026-04-21.md +71 -0
- package/.claude/proposals/SP-021-ceo-orchestration-autonomous-loop-2026-04-21.md.asc +8 -0
- package/.claude/rag/_index_core.py +344 -0
- package/.claude/rag/indexignore +101 -0
- package/.claude/rag/install-sidecar.sh +275 -0
- package/.claude/rag/models.manifest.json +19 -0
- package/.claude/rag/requirements.lock +40 -0
- package/.claude/rag/sidecar-config.template.json +53 -0
- package/.claude/rag/tests/test_index_core.py +262 -0
- package/.claude/rag/tests/test_install_sidecar.sh +132 -0
- package/.claude/scripts/.known_actions_floor.lock +0 -0
- package/.claude/scripts/admin-invite.py +199 -0
- package/.claude/scripts/adopter-metrics.py +712 -0
- package/.claude/scripts/aek-calibration-c2.py +253 -0
- package/.claude/scripts/aek-calibration-c3.py +382 -0
- package/.claude/scripts/aggregate-changesets.py +350 -0
- package/.claude/scripts/architect-bundle-validate.py +227 -0
- package/.claude/scripts/audit-dashboard.py +1320 -0
- package/.claude/scripts/audit-log-labels.jsonl +0 -0
- package/.claude/scripts/audit-log-retain.py +404 -0
- package/.claude/scripts/audit-query.py +3333 -0
- package/.claude/scripts/audit-telemetry.py +337 -0
- package/.claude/scripts/audit-tokens.py +502 -0
- package/.claude/scripts/audit-verify-chain.py +537 -0
- package/.claude/scripts/backup-audit.py +247 -0
- package/.claude/scripts/benchmark/plan-071-import-floor/README.md +194 -0
- package/.claude/scripts/benchmark/plan-071-import-floor/fixtures/baseline.json +1 -0
- package/.claude/scripts/benchmark/plan-071-import-floor/fixtures/expected_quantiles.json +11 -0
- package/.claude/scripts/benchmark/plan-071-import-floor/import_floor_bench.py +791 -0
- package/.claude/scripts/benchmark/plan-071-import-floor/run_bench.sh +180 -0
- package/.claude/scripts/benchmark-fallback-scorer.py +254 -0
- package/.claude/scripts/benchmark-judge.py +621 -0
- package/.claude/scripts/budget-summary.py +946 -0
- package/.claude/scripts/build-canonical-models.py +645 -0
- package/.claude/scripts/calibration-kappa.py +262 -0
- package/.claude/scripts/cc-analytics-pull.py +393 -0
- package/.claude/scripts/ceo-backup.sh +307 -0
- package/.claude/scripts/ceo-boot.py +3017 -0
- package/.claude/scripts/ceo-cost.py +1116 -0
- package/.claude/scripts/ceo-diagnose.py +486 -0
- package/.claude/scripts/ceo-escalation-detector.py +743 -0
- package/.claude/scripts/ceo-health.py +584 -0
- package/.claude/scripts/ceo-info.py +1001 -0
- package/.claude/scripts/ceo-restore.sh +215 -0
- package/.claude/scripts/chaos-inject.py +439 -0
- package/.claude/scripts/check-action-sha-drift.py +275 -0
- package/.claude/scripts/check-active-hooks-executable.py +119 -0
- package/.claude/scripts/check-adr-chain.py +617 -0
- package/.claude/scripts/check-audit-action-name-convention.py +221 -0
- package/.claude/scripts/check-audit-hmac-null.py +253 -0
- package/.claude/scripts/check-audit-read-api-stable.py +239 -0
- package/.claude/scripts/check-audit-registry-coverage.py +999 -0
- package/.claude/scripts/check-auto-activation-flags.py +180 -0
- package/.claude/scripts/check-canonical-doc-freshness.py +222 -0
- package/.claude/scripts/check-claude-md-claims.py +346 -0
- package/.claude/scripts/check-confidence-gate-drift.py +295 -0
- package/.claude/scripts/check-conformance-harness-mapping.py +503 -0
- package/.claude/scripts/check-contamination.sh +25 -0
- package/.claude/scripts/check-creative-rewrite.py +596 -0
- package/.claude/scripts/check-debate-round-lifecycle.py +185 -0
- package/.claude/scripts/check-debt-ledger.py +305 -0
- package/.claude/scripts/check-docs-drift.py +259 -0
- package/.claude/scripts/check-docs-freshness.py +487 -0
- package/.claude/scripts/check-flip-criteria-drift.py +426 -0
- package/.claude/scripts/check-flip-release-gate-consistency.py +134 -0
- package/.claude/scripts/check-framework-updates.sh +239 -0
- package/.claude/scripts/check-function-length.py +426 -0
- package/.claude/scripts/check-model-deprecations.py +377 -0
- package/.claude/scripts/check-originator-residue.py +248 -0
- package/.claude/scripts/check-pitfall-regression.sh +153 -0
- package/.claude/scripts/check-policy-drift.py +74 -0
- package/.claude/scripts/check-roadmap-binding.py +170 -0
- package/.claude/scripts/check-rule-invariants.py +385 -0
- package/.claude/scripts/check-sdk-compat.sh +76 -0
- package/.claude/scripts/check-secret-pattern-coverage.py +175 -0
- package/.claude/scripts/check-sidecar-manifest.py +493 -0
- package/.claude/scripts/check-skill-activation-mode.py +41 -0
- package/.claude/scripts/check-skill-health.sh +179 -0
- package/.claude/scripts/check-spec-drift.py +147 -0
- package/.claude/scripts/check-staleness.py +506 -0
- package/.claude/scripts/check-stdlib-only.py +373 -0
- package/.claude/scripts/check-substrate-watch.py +285 -0
- package/.claude/scripts/check-swarm-harness-mapping.py +380 -0
- package/.claude/scripts/check-test-audit-isolation.py +622 -0
- package/.claude/scripts/check-test-env-hygiene.py +509 -0
- package/.claude/scripts/check-threat-model-freshness.py +313 -0
- package/.claude/scripts/check-tier-boundaries.py +233 -0
- package/.claude/scripts/check-tla-schema-drift.py +272 -0
- package/.claude/scripts/check_atlas_fpr.py +595 -0
- package/.claude/scripts/check_contamination.py +337 -0
- package/.claude/scripts/check_known_actions_floor.py +155 -0
- package/.claude/scripts/check_threat_model_coverage.py +214 -0
- package/.claude/scripts/check_translations_drift.py +199 -0
- package/.claude/scripts/codex_invoke.py +436 -0
- package/.claude/scripts/compare-adopters.py +549 -0
- package/.claude/scripts/confidence-gate-backfill.py +261 -0
- package/.claude/scripts/confidence_gate.py +736 -0
- package/.claude/scripts/context-budget.py +1887 -0
- package/.claude/scripts/contextual-recommender.py +815 -0
- package/.claude/scripts/cost-table.yaml +99 -0
- package/.claude/scripts/debate-converge.py +335 -0
- package/.claude/scripts/debate-emit.py +132 -0
- package/.claude/scripts/debate-orchestrate.py +972 -0
- package/.claude/scripts/detect-repo-profile.py +1280 -0
- package/.claude/scripts/detectors/__init__.py +19 -0
- package/.claude/scripts/detectors/looping.py +127 -0
- package/.claude/scripts/detectors/overpowered.py +96 -0
- package/.claude/scripts/detectors/retry_churn.py +119 -0
- package/.claude/scripts/detectors/schema.py +94 -0
- package/.claude/scripts/detectors/tests/__init__.py +0 -0
- package/.claude/scripts/detectors/tests/fixtures.py +420 -0
- package/.claude/scripts/detectors/tests/test_looping.py +124 -0
- package/.claude/scripts/detectors/tests/test_overpowered.py +114 -0
- package/.claude/scripts/detectors/tests/test_retry_churn.py +101 -0
- package/.claude/scripts/detectors/tests/test_schema.py +109 -0
- package/.claude/scripts/detectors/tests/test_tool_cascade.py +131 -0
- package/.claude/scripts/detectors/tests/test_wasteful_thinking.py +112 -0
- package/.claude/scripts/detectors/tests/test_weak_model.py +104 -0
- package/.claude/scripts/detectors/tool_cascade.py +127 -0
- package/.claude/scripts/detectors/wasteful_thinking.py +99 -0
- package/.claude/scripts/detectors/weak_model.py +92 -0
- package/.claude/scripts/env-inventory-check.py +268 -0
- package/.claude/scripts/env-inventory.json +3305 -0
- package/.claude/scripts/extract-skill.py +456 -0
- package/.claude/scripts/fan-plan-parser.py +370 -0
- package/.claude/scripts/find-orphan-sentinels.py +89 -0
- package/.claude/scripts/first-run-wizard.py +1151 -0
- package/.claude/scripts/fixtures/cloned-trading-repo/.env.example +1 -0
- package/.claude/scripts/fixtures/cloned-trading-repo/exchanges/binance.py +3 -0
- package/.claude/scripts/fixtures/cloned-trading-repo/exchanges/coinbase.py +3 -0
- package/.claude/scripts/fixtures/cloned-trading-repo/package.json +5 -0
- package/.claude/scripts/fixtures/cloned-trading-repo/strategies/grid.py +3 -0
- package/.claude/scripts/fixtures/cloned-trading-repo/strategies/pairs.py +3 -0
- package/.claude/scripts/fixtures/missing-package-manifest/README.md +3 -0
- package/.claude/scripts/fixtures/missing-package-manifest/src/main.py +1 -0
- package/.claude/scripts/fixtures/mixed-frontend-backend/package.json +9 -0
- package/.claude/scripts/fixtures/mixed-frontend-backend/requirements.txt +2 -0
- package/.claude/scripts/fixtures/mixed-frontend-backend/src/api/handler.py +2 -0
- package/.claude/scripts/fixtures/mixed-frontend-backend/src/pages/index.tsx +1 -0
- package/.claude/scripts/fixtures/monorepo/apps/app-a/README.md +1 -0
- package/.claude/scripts/fixtures/monorepo/apps/app-b/index.ts +1 -0
- package/.claude/scripts/fixtures/monorepo/package.json +5 -0
- package/.claude/scripts/fixtures/monorepo/packages/lib-a/index.js +1 -0
- package/.claude/scripts/fixtures/monorepo/packages/lib-b/index.js +1 -0
- package/.claude/scripts/fixtures/monorepo/pnpm-workspace.yaml +3 -0
- package/.claude/scripts/fixtures/persona-coverage-expected-thresholds.yaml +20 -0
- package/.claude/scripts/flip-criteria-drift-allowlist.txt +31 -0
- package/.claude/scripts/generate-adr-index.py +339 -0
- package/.claude/scripts/generate-available-models.py +280 -0
- package/.claude/scripts/generate-dispatch.py +430 -0
- package/.claude/scripts/generate-sbom.py +287 -0
- package/.claude/scripts/generate-skill-inventory.sh +193 -0
- package/.claude/scripts/github-api-client.py +297 -0
- package/.claude/scripts/goap-planner.py +742 -0
- package/.claude/scripts/hook-profiler.py +671 -0
- package/.claude/scripts/import-skill.py +569 -0
- package/.claude/scripts/import_ui_ux_pro_max.py +137 -0
- package/.claude/scripts/inject-agent-context.sh +948 -0
- package/.claude/scripts/k-calibration.py +456 -0
- package/.claude/scripts/key-hygiene.py +511 -0
- package/.claude/scripts/lesson-restore.py +171 -0
- package/.claude/scripts/lesson_ranker.py +100 -0
- package/.claude/scripts/lessons.py +883 -0
- package/.claude/scripts/lint-skills.py +555 -0
- package/.claude/scripts/local/README.md +280 -0
- package/.claude/scripts/local/check-doc-skill-paths.sh +124 -0
- package/.claude/scripts/local/dependency-graph.py +684 -0
- package/.claude/scripts/local/estimate-calibrator.py +240 -0
- package/.claude/scripts/local/findings-pretty-print.py +78 -0
- package/.claude/scripts/local/generate-ceremony.sh +558 -0
- package/.claude/scripts/local/pair-rail-gate.sh +156 -0
- package/.claude/scripts/local/release-dry-run.py +853 -0
- package/.claude/scripts/local/tests/test_dependency_graph.py +364 -0
- package/.claude/scripts/local/tests/test_generate_ceremony.sh +144 -0
- package/.claude/scripts/local/tests/test_release_dry_run.py +743 -0
- package/.claude/scripts/local/validate-findings.py +168 -0
- package/.claude/scripts/local/validate-saved-workflows.js +69 -0
- package/.claude/scripts/local/verify-counts.sh +420 -0
- package/.claude/scripts/local/verify-scope-coverage.py +205 -0
- package/.claude/scripts/local/verify-staging-manifest.py +188 -0
- package/.claude/scripts/local/wave-readonly-monitor.py +271 -0
- package/.claude/scripts/log-friction.sh +290 -0
- package/.claude/scripts/mcp/code_nav_bridge.py +259 -0
- package/.claude/scripts/mcp-server/__init__.py +16 -0
- package/.claude/scripts/mcp-server/auth.py +333 -0
- package/.claude/scripts/mcp-server/cost.py +108 -0
- package/.claude/scripts/mcp-server/dispatch.py +853 -0
- package/.claude/scripts/mcp-server/handlers/__init__.py +16 -0
- package/.claude/scripts/mcp-server/handlers/audit_query.py +384 -0
- package/.claude/scripts/mcp-server/handlers/get_audit_log.py +163 -0
- package/.claude/scripts/mcp-server/handlers/get_cost_budget.py +130 -0
- package/.claude/scripts/mcp-server/handlers/get_debate_state.py +207 -0
- package/.claude/scripts/mcp-server/handlers/get_skill.py +199 -0
- package/.claude/scripts/mcp-server/handlers/list_agents.py +236 -0
- package/.claude/scripts/mcp-server/handlers/list_pitfalls.py +192 -0
- package/.claude/scripts/mcp-server/handlers/list_skills.py +197 -0
- package/.claude/scripts/mcp-server/handlers/plan_status.py +489 -0
- package/.claude/scripts/mcp-server/handlers/server_capabilities.py +127 -0
- package/.claude/scripts/mcp-server/handlers/spawn_agent.py +274 -0
- package/.claude/scripts/mcp-server/http_transport.py +373 -0
- package/.claude/scripts/mcp-server/rate_limit.py +345 -0
- package/.claude/scripts/mcp-server/server.py +212 -0
- package/.claude/scripts/mcp-server/start-mcp-server.sh +111 -0
- package/.claude/scripts/mcp-server/stdio_transport.py +150 -0
- package/.claude/scripts/mcp-server/tests/__init__.py +1 -0
- package/.claude/scripts/mcp-server/tests/test_auth.py +454 -0
- package/.claude/scripts/mcp-server/tests/test_cost.py +122 -0
- package/.claude/scripts/mcp-server/tests/test_dispatch.py +448 -0
- package/.claude/scripts/mcp-server/tests/test_dispatch_bearer_replay_wire.py +358 -0
- package/.claude/scripts/mcp-server/tests/test_handlers_get_audit_log.py +107 -0
- package/.claude/scripts/mcp-server/tests/test_handlers_get_skill.py +108 -0
- package/.claude/scripts/mcp-server/tests/test_handlers_list_agents.py +92 -0
- package/.claude/scripts/mcp-server/tests/test_handlers_list_pitfalls.py +103 -0
- package/.claude/scripts/mcp-server/tests/test_handlers_list_skills.py +121 -0
- package/.claude/scripts/mcp-server/tests/test_handlers_server_capabilities.py +128 -0
- package/.claude/scripts/mcp-server/tests/test_handlers_spawn_agent.py +275 -0
- package/.claude/scripts/mcp-server/tests/test_http_transport.py +418 -0
- package/.claude/scripts/mcp-server/tests/test_rate_limit.py +239 -0
- package/.claude/scripts/mcp-server/tests/test_server.py +125 -0
- package/.claude/scripts/mcp-server/tests/test_stdio_transport.py +196 -0
- package/.claude/scripts/mcp-soak-monitor.py +224 -0
- package/.claude/scripts/memory-prioritize.py +516 -0
- package/.claude/scripts/migrate-grandfather-to-sha256.py +384 -0
- package/.claude/scripts/model-deprecations.json +165 -0
- package/.claude/scripts/morning-ceremony.py +266 -0
- package/.claude/scripts/morning_ledger.py +446 -0
- package/.claude/scripts/mutation-floors.yaml +51 -0
- package/.claude/scripts/mutation-test.py +506 -0
- package/.claude/scripts/nightly-proposals.py +210 -0
- package/.claude/scripts/optimizer/__init__.py +46 -0
- package/.claude/scripts/optimizer/_codex_redaction.py +101 -0
- package/.claude/scripts/optimizer/_skeleton.py +137 -0
- package/.claude/scripts/optimizer/codex_phase_gate.py +257 -0
- package/.claude/scripts/optimizer/complexity_gate.py +208 -0
- package/.claude/scripts/optimizer/fanout.py +249 -0
- package/.claude/scripts/optimizer/model_choice.py +151 -0
- package/.claude/scripts/optimizer/model_normalize.py +118 -0
- package/.claude/scripts/optimizer/rag_recommender.py +110 -0
- package/.claude/scripts/optimizer/recommender.py +213 -0
- package/.claude/scripts/optimizer/tests/__init__.py +0 -0
- package/.claude/scripts/optimizer/tests/test_codex_phase_gate.py +314 -0
- package/.claude/scripts/optimizer/tests/test_codex_review_invoked_emission.py +225 -0
- package/.claude/scripts/optimizer/tests/test_optimizer_complexity_gate.py +122 -0
- package/.claude/scripts/optimizer/tests/test_optimizer_fanout.py +134 -0
- package/.claude/scripts/optimizer/tests/test_optimizer_model_choice.py +124 -0
- package/.claude/scripts/optimizer/tests/test_optimizer_model_normalize.py +155 -0
- package/.claude/scripts/optimizer/tests/test_optimizer_rag_recommender.py +190 -0
- package/.claude/scripts/optimizer/tests/test_optimizer_recommender.py +131 -0
- package/.claude/scripts/optimizer/tests/test_optimizer_skeleton.py +117 -0
- package/.claude/scripts/optimizer/tests/test_optimizer_types.py +53 -0
- package/.claude/scripts/optimizer/types.py +122 -0
- package/.claude/scripts/osv_check.py +559 -0
- package/.claude/scripts/otel-export.py +329 -0
- package/.claude/scripts/otel-local-sink.py +470 -0
- package/.claude/scripts/persona_demand_resolver.py +658 -0
- package/.claude/scripts/persona_demand_scan.py +382 -0
- package/.claude/scripts/persona_waive_parser.py +127 -0
- package/.claude/scripts/pitfall-query.py +218 -0
- package/.claude/scripts/plan-tokens.py +843 -0
- package/.claude/scripts/policy-shadow-runner.py +445 -0
- package/.claude/scripts/predict-budget/predict-plan-cost.py +581 -0
- package/.claude/scripts/predict-budget/tests/test_predict_plan_cost.py +375 -0
- package/.claude/scripts/profile-opus-4-7.py +557 -0
- package/.claude/scripts/prune-lessons.py +453 -0
- package/.claude/scripts/rate-card-calibrate.py +283 -0
- package/.claude/scripts/rate-card-fixtures.json +18 -0
- package/.claude/scripts/reality-ledger.py +2175 -0
- package/.claude/scripts/red-team-corpus/.byte-identity-check.txt +86 -0
- package/.claude/scripts/red-team-corpus/README.md +132 -0
- package/.claude/scripts/red-team-corpus/external/EXT-001-prompt-inject.md +24 -0
- package/.claude/scripts/red-team-corpus/external/EXT-002-hackaprompt.md +25 -0
- package/.claude/scripts/red-team-corpus/external/EXT-003-gcg.md +31 -0
- package/.claude/scripts/red-team-corpus/external/EXT-004-tap.md +23 -0
- package/.claude/scripts/red-team-corpus/external/EXT-005-cybersecurity-eval.md +30 -0
- package/.claude/scripts/red-team-corpus/external/EXT-006-anthropic-samples.md +26 -0
- package/.claude/scripts/red-team-corpus/external/EXT-007-trojan-source.md +26 -0
- package/.claude/scripts/red-team-corpus/external/EXT-008-owasp-llm-top10.md +33 -0
- package/.claude/scripts/red-team-corpus/external/EXT-009-jailbreak-bench.md +24 -0
- package/.claude/scripts/red-team-corpus/external/EXT-010-advbench.md +22 -0
- package/.claude/scripts/red-team-corpus/external/EXT-011-mitre-atlas.md +25 -0
- package/.claude/scripts/red-team-corpus/external/EXT-012-npm-typosquat.md +23 -0
- package/.claude/scripts/red-team-corpus/external/EXT-013-log-tamper-poc.md +25 -0
- package/.claude/scripts/red-team-corpus/external/EXT-014-cwe-798-credentials.md +24 -0
- package/.claude/scripts/red-team-corpus/external/EXT-015-garak.md +28 -0
- package/.claude/scripts/red-team-corpus/external/EXT-016-skill-content-injection-via-markdown.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/external/EXT-017-persona-impersonation-ceo.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/external/EXT-018-file-assignment-wildcard-escape.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/external/EXT-019-veto-bypass-force-proceed.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/external/EXT-020-canonical-edit-circumvent-settings.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/external/EXT-021-spawn-without-agent-profile.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/external/EXT-022-hidden-unicode-in-skill-name.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/external/EXT-023-mcp-spawn-governance-bypass.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/external/EXT-024-adapter-credential-in-error-trace.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/external/EXT-025-sandbox-escape-nested-subshell.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/external/EXT-026-plan-edit-without-debate.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/external/EXT-027-audit-log-rotation-race.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/external/EXT-028-npm-dependency-confusion.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/external/EXT-029-output-safety-unicode-confusable.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/external/EXT-030-adapter-retry-storm-dos.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/external/EXT-031-team-md-direct-edit.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/external/EXT-032-sandbox-env-var-exfil.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/external/EXT-033-mcp-rate-limit-bypass-headers.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/external/EXT-034-otel-span-attribute-leak.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/external/EXT-035-skill-patch-polyglot-payload.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/external/EXT-036-output-safety-base64-triple-wrap.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/external/EXT-037-plan-id-cross-plan-memory-read.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/external/EXT-038-npm-slsa-provenance-strip.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/external/EXT-039-adapter-exfil-streaming-chunk.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/external/EXT-040-sandbox-symlink-to-secrets.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/external/README.md +63 -0
- package/.claude/scripts/red-team-corpus/flake-budget.yaml +244 -0
- package/.claude/scripts/red-team-corpus/provenance.md +74 -0
- package/.claude/scripts/red-team-corpus/regression/REG-001-s3-audit-emission-gap.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/regression/REG-002-audit-registry-miss.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/regression/REG-003-breaker-provider-kwarg-missing.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/regression/REG-004-canonical-edit-conftest-block.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/regression/REG-005-mcp-dispatch-oversized-handler.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/regression/REG-006-audit-registry-false-orphan.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/regression/REG-007-spec-count-undercount.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/regression/REG-008-adr-reserved-slot-phantom.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/regression/REG-009-tlc-pending-placeholder.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/regression/REG-010-mutation-kill-rate-fake.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/regression/REG-011-byte-identity-governance-persona.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/regression/REG-012-conformance-mapping-partial-path.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/regression/REG-013-l1-fairness-lazy-fire.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/regression/REG-014-mcp-path-traversal-skill.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/regression/REG-015-mcp-hmac-timestamp-skew.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/synthetic/SYN-001-skill-patch-bidi-trojan.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/synthetic/SYN-002-skill-patch-zero-width-smuggle.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/synthetic/SYN-003-skill-patch-exec-smuggled-fence.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/synthetic/SYN-004-skill-patch-oversized-diff.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/synthetic/SYN-005-audit-log-byte-rewrite.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/synthetic/SYN-006-audit-log-truncation.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/synthetic/SYN-007-audit-log-lock-race.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/synthetic/SYN-008-plan-id-env-spoof.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/synthetic/SYN-009-plan-id-frontmatter-hijack.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/synthetic/SYN-010-plan-id-cross-plan-read.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/synthetic/SYN-011-sandbox-escape-curl-exfil.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/synthetic/SYN-012-sandbox-escape-env-dump.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/synthetic/SYN-013-sandbox-escape-symlink-plant.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/synthetic/SYN-014-mcp-handler-governance-bypass.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/synthetic/SYN-015-mcp-handler-acl-enumeration.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/synthetic/SYN-016-mcp-handler-rate-limit-evasion.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/synthetic/SYN-017-adapter-exfil-via-error-message.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/synthetic/SYN-018-adapter-exfil-otel-attr.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/synthetic/SYN-019-adapter-exfil-retry-replay.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/synthetic/SYN-020-output-safety-nfkc-bypass.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/synthetic/SYN-021-output-safety-base64-double-wrap.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/synthetic/SYN-022-output-safety-entropy-below-threshold.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/synthetic/SYN-023-output-safety-regex-obfuscation.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/synthetic/SYN-024-output-safety-luhn-partial.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/synthetic/SYN-025-npm-tamper-supply-chain.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/synthetic/SYN-026-npm-tamper-typo-squat.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/synthetic/SYN-027-npm-tamper-unsigned-slsa.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/v1/fixtures.jsonl +67 -0
- package/.claude/scripts/red-team-corpus/v1/fixtures.jsonl.sha256 +1 -0
- package/.claude/scripts/red-team-corpus/v1/labels.json +88 -0
- package/.claude/scripts/red-team-eval.py +1099 -0
- package/.claude/scripts/registry.py +438 -0
- package/.claude/scripts/replay/__init__.py +0 -0
- package/.claude/scripts/replay/replay-session.py +1232 -0
- package/.claude/scripts/replay/tests/__init__.py +0 -0
- package/.claude/scripts/replay/tests/fixtures/api-key-01-positive.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/api-key-02-positive.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/api-key-03-positive.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/api-key-04-positive.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/api-key-05-negative.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/api-key-06-negative.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/api-key-07-negative.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/api-key-08-negative.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/cpf-cnpj-01-positive.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/cpf-cnpj-02-positive.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/cpf-cnpj-03-positive.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/cpf-cnpj-04-positive.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/cpf-cnpj-05-negative.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/cpf-cnpj-06-negative.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/cpf-cnpj-07-negative.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/cpf-cnpj-08-negative.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/email-in-log-01-positive.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/email-in-log-02-positive.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/email-in-log-03-positive.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/email-in-log-04-positive.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/email-in-log-05-negative.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/email-in-log-06-negative.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/email-in-log-07-negative.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/email-in-log-08-negative.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/homoglyph-01-positive.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/homoglyph-02-positive.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/homoglyph-03-positive.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/homoglyph-04-positive.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/homoglyph-05-negative.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/homoglyph-06-negative.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/homoglyph-07-negative.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/homoglyph-08-negative.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/jwt-01-positive.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/jwt-02-positive.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/jwt-03-positive.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/jwt-04-positive.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/jwt-05-negative.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/jwt-06-negative.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/jwt-07-negative.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/jwt-08-negative.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/os-path-01-positive.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/os-path-02-positive.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/os-path-03-positive.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/os-path-04-positive.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/os-path-05-negative.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/os-path-06-negative.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/os-path-07-negative.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/os-path-08-negative.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/pan-01-positive.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/pan-02-positive.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/pan-03-positive.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/pan-04-positive.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/pan-05-negative.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/pan-06-negative.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/pan-07-negative.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/pan-08-negative.jsonl +1 -0
- package/.claude/scripts/replay/tests/test_replay_redact_lib.py +971 -0
- package/.claude/scripts/replay/tests/test_replay_session.py +396 -0
- package/.claude/scripts/replay/tests/test_replay_session_capture.py +522 -0
- package/.claude/scripts/repo-profile.schema.json +83 -0
- package/.claude/scripts/run-promotion-gate.py +631 -0
- package/.claude/scripts/run-skill-benchmark.py +1276 -0
- package/.claude/scripts/scan-injection-strict.sh +162 -0
- package/.claude/scripts/scan-injection.py +305 -0
- package/.claude/scripts/scan-upstream-injection.py +663 -0
- package/.claude/scripts/scratchpad.py +427 -0
- package/.claude/scripts/self_test.py +602 -0
- package/.claude/scripts/session-graph-build.py +728 -0
- package/.claude/scripts/session-resume.py +363 -0
- package/.claude/scripts/set-quality-profile.sh +229 -0
- package/.claude/scripts/skill-budget-generator.py +599 -0
- package/.claude/scripts/skill-import-rubric.py +368 -0
- package/.claude/scripts/skill-index-build.py +534 -0
- package/.claude/scripts/skill-patch-apply.py +1088 -0
- package/.claude/scripts/skill-patch-propose.py +690 -0
- package/.claude/scripts/skill-retrieve.py +522 -0
- package/.claude/scripts/skill_grandfather_parser.py +295 -0
- package/.claude/scripts/smart-loading-resolver.py +994 -0
- package/.claude/scripts/spot-check-findings.py +211 -0
- package/.claude/scripts/squad-export.py +437 -0
- package/.claude/scripts/squad-import.py +741 -0
- package/.claude/scripts/status.py +315 -0
- package/.claude/scripts/statusline-ceo.py +597 -0
- package/.claude/scripts/substrate-watch.json +54 -0
- package/.claude/scripts/success-receipt.py +1038 -0
- package/.claude/scripts/swarm/__init__.py +42 -0
- package/.claude/scripts/swarm/_benchmark_replay.py +259 -0
- package/.claude/scripts/swarm/_child_isolation.py +113 -0
- package/.claude/scripts/swarm/_coordinator_sim.py +293 -0
- package/.claude/scripts/swarm/_governors.py +277 -0
- package/.claude/scripts/swarm/_integration.py +547 -0
- package/.claude/scripts/swarm/_parent_death.py +176 -0
- package/.claude/scripts/swarm/_process_group.py +250 -0
- package/.claude/scripts/swarm/_replay_tournament.py +214 -0
- package/.claude/scripts/swarm/_spawn_gate.py +292 -0
- package/.claude/scripts/swarm/_subagent_fabrication.py +444 -0
- package/.claude/scripts/swarm/_worktree_pool.py +276 -0
- package/.claude/scripts/swarm/coordinator.py +543 -0
- package/.claude/scripts/swarm/file_assignment.py +111 -0
- package/.claude/scripts/swarm/fixtures/mcp_corpus.json +111 -0
- package/.claude/scripts/swarm/kill_switch.py +260 -0
- package/.claude/scripts/swarm/loop_runner.py +486 -0
- package/.claude/scripts/swarm/recovery.py +178 -0
- package/.claude/scripts/swarm/test_mcp_injection_repro.py +518 -0
- package/.claude/scripts/swarm/test_rail_anomaly_repro.py +586 -0
- package/.claude/scripts/swarm/tests/__init__.py +1 -0
- package/.claude/scripts/swarm/tests/test_benchmark_manifest_schema.py +227 -0
- package/.claude/scripts/swarm/tests/test_benchmark_replay.py +248 -0
- package/.claude/scripts/swarm/tests/test_child_isolation.py +138 -0
- package/.claude/scripts/swarm/tests/test_coordinator.py +289 -0
- package/.claude/scripts/swarm/tests/test_coordinator_production_integration.py +434 -0
- package/.claude/scripts/swarm/tests/test_coordinator_sim.py +192 -0
- package/.claude/scripts/swarm/tests/test_coordinator_tick.py +165 -0
- package/.claude/scripts/swarm/tests/test_file_assignment.py +100 -0
- package/.claude/scripts/swarm/tests/test_governors.py +269 -0
- package/.claude/scripts/swarm/tests/test_integration.py +344 -0
- package/.claude/scripts/swarm/tests/test_kill_switch.py +307 -0
- package/.claude/scripts/swarm/tests/test_loop_runner.py +168 -0
- package/.claude/scripts/swarm/tests/test_loop_runner_circuit_breaker.py +555 -0
- package/.claude/scripts/swarm/tests/test_loop_runner_gate_enforcement.py +304 -0
- package/.claude/scripts/swarm/tests/test_loop_runner_gate_kill_switch.py +147 -0
- package/.claude/scripts/swarm/tests/test_loop_runner_sentinel_revocation_slo.py +112 -0
- package/.claude/scripts/swarm/tests/test_optimizer_killswitch.py +205 -0
- package/.claude/scripts/swarm/tests/test_parent_death.py +128 -0
- package/.claude/scripts/swarm/tests/test_parent_death_integration.py +305 -0
- package/.claude/scripts/swarm/tests/test_process_group.py +132 -0
- package/.claude/scripts/swarm/tests/test_process_group_reap.py +212 -0
- package/.claude/scripts/swarm/tests/test_rail_anomaly_repro.py +516 -0
- package/.claude/scripts/swarm/tests/test_recovery.py +165 -0
- package/.claude/scripts/swarm/tests/test_replay_tournament.py +284 -0
- package/.claude/scripts/swarm/tests/test_spawn_gate.py +265 -0
- package/.claude/scripts/swarm/tests/test_subagent_fabrication.py +824 -0
- package/.claude/scripts/swarm/tests/test_swarm_activation_smoke.py +112 -0
- package/.claude/scripts/swarm/tests/test_tournament.py +195 -0
- package/.claude/scripts/swarm/tests/test_worktree_pool.py +252 -0
- package/.claude/scripts/swarm/tournament.py +261 -0
- package/.claude/scripts/task-route.py +807 -0
- package/.claude/scripts/test-env-hygiene-allowlist.yaml +1093 -0
- package/.claude/scripts/tests/DEFERRED.md +99 -0
- package/.claude/scripts/tests/conftest.py +42 -0
- package/.claude/scripts/tests/fixtures/aggregate-changesets/bad-type.md +4 -0
- package/.claude/scripts/tests/fixtures/aggregate-changesets/missing-frontmatter.md +1 -0
- package/.claude/scripts/tests/fixtures/aggregate-changesets/multidoc.md +6 -0
- package/.claude/scripts/tests/fixtures/aggregate-changesets/sample-CHANGELOG.md +29 -0
- package/.claude/scripts/tests/fixtures/aggregate-changesets/second-minor.md +4 -0
- package/.claude/scripts/tests/fixtures/aggregate-changesets/single-patch.md +4 -0
- package/.claude/scripts/tests/fixtures/aggregate-changesets/third-major.md +4 -0
- package/.claude/scripts/tests/fixtures/aggregate-changesets/unknown-key.md +6 -0
- package/.claude/scripts/tests/fixtures/bad_lessons/bidi_override.md +12 -0
- package/.claude/scripts/tests/fixtures/bad_lessons/fenced_python.md +19 -0
- package/.claude/scripts/tests/fixtures/bad_lessons/homoglyph.md +11 -0
- package/.claude/scripts/tests/fixtures/bad_lessons/injection.md +11 -0
- package/.claude/scripts/tests/fixtures/bad_lessons/long_line.md +9 -0
- package/.claude/scripts/tests/fixtures/bad_lessons/oversized.md +261 -0
- package/.claude/scripts/tests/fixtures/bad_lessons/zero_width.md +11 -0
- package/.claude/scripts/tests/fixtures/budget_summary/generate_fixtures.py +368 -0
- package/.claude/scripts/tests/fixtures/claims/README.md +21 -0
- package/.claude/scripts/tests/fixtures/claims/function_exists/neg-missing.txt +1 -0
- package/.claude/scripts/tests/fixtures/claims/function_exists/neg-no-file.txt +1 -0
- package/.claude/scripts/tests/fixtures/claims/function_exists/pos-extract.txt +1 -0
- package/.claude/scripts/tests/fixtures/claims/function_exists/pos-main.txt +1 -0
- package/.claude/scripts/tests/fixtures/claims/function_exists/pos-verify.txt +1 -0
- package/.claude/scripts/tests/fixtures/claims/function_exists/quoted-colon-path.txt +1 -0
- package/.claude/scripts/tests/fixtures/claims/import_resolves/codeblock-skipped.txt +8 -0
- package/.claude/scripts/tests/fixtures/claims/import_resolves/neg-blocked-os.txt +6 -0
- package/.claude/scripts/tests/fixtures/claims/import_resolves/neg-relative.txt +5 -0
- package/.claude/scripts/tests/fixtures/claims/import_resolves/pos-dotted.txt +6 -0
- package/.claude/scripts/tests/fixtures/claims/import_resolves/pos-stdlib-like.txt +5 -0
- package/.claude/scripts/tests/fixtures/claims/line_range/neg-missing-file.txt +1 -0
- package/.claude/scripts/tests/fixtures/claims/line_range/neg-too-long.txt +1 -0
- package/.claude/scripts/tests/fixtures/claims/line_range/pos-large.txt +1 -0
- package/.claude/scripts/tests/fixtures/claims/line_range/pos-small.txt +1 -0
- package/.claude/scripts/tests/fixtures/claims/line_range/quoted-path.txt +1 -0
- package/.claude/scripts/tests/fixtures/claims/path_exists/codeblock-skipped.txt +7 -0
- package/.claude/scripts/tests/fixtures/claims/path_exists/neg-absolute-outside.txt +6 -0
- package/.claude/scripts/tests/fixtures/claims/path_exists/neg-dotdot-escape.txt +7 -0
- package/.claude/scripts/tests/fixtures/claims/path_exists/neg-imaginary.txt +1 -0
- package/.claude/scripts/tests/fixtures/claims/path_exists/neg-proc-self.txt +6 -0
- package/.claude/scripts/tests/fixtures/claims/path_exists/neg-symlink-escape.txt +8 -0
- package/.claude/scripts/tests/fixtures/claims/path_exists/neg-typo.txt +1 -0
- package/.claude/scripts/tests/fixtures/claims/path_exists/pos-claude.txt +1 -0
- package/.claude/scripts/tests/fixtures/claims/path_exists/pos-readme.txt +1 -0
- package/.claude/scripts/tests/fixtures/claims/path_exists/pos-self.txt +1 -0
- package/.claude/scripts/tests/fixtures/claims/sha_exists/neg-fake.txt +1 -0
- package/.claude/scripts/tests/fixtures/claims/sha_exists/neg-not-sha.txt +1 -0
- package/.claude/scripts/tests/fixtures/claims/sha_exists/pos-head.txt +4 -0
- package/.claude/scripts/tests/fixtures/claims/sha_exists/pos-root.txt +1 -0
- package/.claude/scripts/tests/fixtures/claims/sha_exists/pos-short.txt +1 -0
- package/.claude/scripts/tests/fixtures/claims/test_passes/neg-missing-file.txt +1 -0
- package/.claude/scripts/tests/fixtures/claims/test_passes/neg-wrong-test.txt +1 -0
- package/.claude/scripts/tests/fixtures/claims/test_passes/pos-audit-emit.txt +1 -0
- package/.claude/scripts/tests/fixtures/claims/test_passes/pos-extra.txt +1 -0
- package/.claude/scripts/tests/fixtures/claims/test_passes/pos-file.txt +1 -0
- package/.claude/scripts/tests/fixtures/claims/test_passes/quoted-pytest-selector.txt +1 -0
- package/.claude/scripts/tests/fixtures/debate_convergence/converged-pair-1/round-1/a.md +39 -0
- package/.claude/scripts/tests/fixtures/debate_convergence/converged-pair-1/round-1/b.md +36 -0
- package/.claude/scripts/tests/fixtures/debate_convergence/converged-pair-1/round-2/a.md +36 -0
- package/.claude/scripts/tests/fixtures/debate_convergence/converged-pair-1/round-2/b.md +36 -0
- package/.claude/scripts/tests/fixtures/debate_convergence/not-converged-pair-1/round-1/a.md +35 -0
- package/.claude/scripts/tests/fixtures/debate_convergence/not-converged-pair-1/round-1/b.md +34 -0
- package/.claude/scripts/tests/fixtures/debate_convergence/not-converged-pair-1/round-2/a.md +35 -0
- package/.claude/scripts/tests/fixtures/debate_convergence/not-converged-pair-1/round-2/b.md +34 -0
- package/.claude/scripts/tests/fixtures/debate_convergence/partial-overlap/round-1/a.md +35 -0
- package/.claude/scripts/tests/fixtures/debate_convergence/partial-overlap/round-2/a.md +36 -0
- package/.claude/scripts/tests/fixtures/debate_convergence/with-secret/round-1/a.md +36 -0
- package/.claude/scripts/tests/fixtures/debate_convergence/with-secret/round-1/b.md +33 -0
- package/.claude/scripts/tests/fixtures/debate_convergence/with-secret/round-2/a.md +34 -0
- package/.claude/scripts/tests/fixtures/docs_freshness/link_anchor_only.md +10 -0
- package/.claude/scripts/tests/fixtures/docs_freshness/link_broken.md +5 -0
- package/.claude/scripts/tests/fixtures/docs_freshness/link_external_url.md +9 -0
- package/.claude/scripts/tests/fixtures/docs_freshness/link_in_fenced_code.md +18 -0
- package/.claude/scripts/tests/fixtures/docs_freshness/link_in_frontmatter.md +10 -0
- package/.claude/scripts/tests/fixtures/docs_freshness/link_in_html_comment.md +10 -0
- package/.claude/scripts/tests/fixtures/docs_freshness/link_in_inline_code.md +7 -0
- package/.claude/scripts/tests/fixtures/docs_freshness/link_in_table.md +6 -0
- package/.claude/scripts/tests/fixtures/docs_freshness/link_relative_parent.md +7 -0
- package/.claude/scripts/tests/fixtures/docs_freshness/link_url_encoded.md +5 -0
- package/.claude/scripts/tests/fixtures/docs_freshness/real_target.md +3 -0
- package/.claude/scripts/tests/fixtures/docs_freshness/sub/dir.md +3 -0
- package/.claude/scripts/tests/fixtures/docs_freshness/with%20space.md +3 -0
- package/.claude/scripts/tests/fixtures/good_lessons/clean_auth.md +11 -0
- package/.claude/scripts/tests/fixtures/good_lessons/clean_logging.md +11 -0
- package/.claude/scripts/tests/fixtures/good_lessons/clean_retry.md +11 -0
- package/.claude/scripts/tests/fixtures/gpg-keyring-fixture.py +209 -0
- package/.claude/scripts/tests/fixtures/injection/benign-01.txt +8 -0
- package/.claude/scripts/tests/fixtures/injection/benign-02.txt +5 -0
- package/.claude/scripts/tests/fixtures/injection/benign-03.txt +7 -0
- package/.claude/scripts/tests/fixtures/injection/benign-04.txt +9 -0
- package/.claude/scripts/tests/fixtures/injection/benign-05.txt +7 -0
- package/.claude/scripts/tests/fixtures/injection/benign-06.txt +7 -0
- package/.claude/scripts/tests/fixtures/injection/benign-07.txt +11 -0
- package/.claude/scripts/tests/fixtures/injection/benign-08.txt +4 -0
- package/.claude/scripts/tests/fixtures/injection/malicious-01.txt +4 -0
- package/.claude/scripts/tests/fixtures/injection/malicious-02.txt +2 -0
- package/.claude/scripts/tests/fixtures/injection/malicious-03.txt +4 -0
- package/.claude/scripts/tests/fixtures/injection/malicious-04.txt +2 -0
- package/.claude/scripts/tests/fixtures/injection/malicious-05.txt +2 -0
- package/.claude/scripts/tests/fixtures/injection/malicious-06.txt +5 -0
- package/.claude/scripts/tests/fixtures/injection/malicious-07.txt +5 -0
- package/.claude/scripts/tests/fixtures/injection/malicious-08.txt +2 -0
- package/.claude/scripts/tests/fixtures/injection/malicious-09.txt +3 -0
- package/.claude/scripts/tests/fixtures/injection/malicious-10.txt +2 -0
- package/.claude/scripts/tests/fixtures/injection/malicious-11.txt +3 -0
- package/.claude/scripts/tests/fixtures/injection/malicious-12.txt +5 -0
- package/.claude/scripts/tests/fixtures/plan-tokens-calibration/manifest.json +49 -0
- package/.claude/scripts/tests/fixtures/plan-tokens-calibration/plan-051.md +36 -0
- package/.claude/scripts/tests/fixtures/plan-tokens-calibration/plan-052.md +32 -0
- package/.claude/scripts/tests/fixtures/plan-tokens-calibration/plan-058.md +31 -0
- package/.claude/scripts/tests/fixtures/reality-ledger/detector-1-boundary/docs/SAMPLE.md +8 -0
- package/.claude/scripts/tests/fixtures/reality-ledger/detector-1-negative/.claude/scripts/sample.py +12 -0
- package/.claude/scripts/tests/fixtures/reality-ledger/detector-1-negative/docs/SAMPLE.md +4 -0
- package/.claude/scripts/tests/fixtures/reality-ledger/detector-1-positive/.claude/scripts/sample.py +12 -0
- package/.claude/scripts/tests/fixtures/reality-ledger/detector-1-positive/docs/SAMPLE.md +9 -0
- package/.claude/scripts/tests/fixtures/reality-ledger/detector-2-boundary/README.md +4 -0
- package/.claude/scripts/tests/fixtures/reality-ledger/detector-2-negative/.claude/rag/requirements.lock +4 -0
- package/.claude/scripts/tests/fixtures/reality-ledger/detector-2-positive/.claude/rag/requirements.lock +2 -0
- package/.claude/scripts/tests/fixtures/reality-ledger/detector-3-boundary/.claude/agents/devops.md +8 -0
- package/.claude/scripts/tests/fixtures/reality-ledger/detector-3-negative/.claude/agents/devops.md +5 -0
- package/.claude/scripts/tests/fixtures/reality-ledger/detector-3-negative/audit-log.jsonl +2 -0
- package/.claude/scripts/tests/fixtures/reality-ledger/detector-3-positive/.claude/agents/devops.md +7 -0
- package/.claude/scripts/tests/fixtures/reality-ledger/detector-3-positive/audit-log.jsonl +4 -0
- package/.claude/scripts/tests/fixtures/reality-ledger/detector-4-boundary/.claude/adr/ADR-997-fixture-superseded.md +8 -0
- package/.claude/scripts/tests/fixtures/reality-ledger/detector-4-negative/.claude/adr/ADR-998-fixture-negative.md +16 -0
- package/.claude/scripts/tests/fixtures/reality-ledger/detector-4-positive/.claude/adr/ADR-999-fixture-positive.md +15 -0
- package/.claude/scripts/tests/fixtures/reality-ledger/detector-6-boundary/.claude/hooks/_lib/.do-not-import-from-here +15 -0
- package/.claude/scripts/tests/fixtures/reality-ledger/detector-6-boundary/.claude/hooks/_lib/audit_emit.py +8 -0
- package/.claude/scripts/tests/fixtures/reality-ledger/detector-6-boundary/.claude/scripts/dynamic_action.py +12 -0
- package/.claude/scripts/tests/fixtures/reality-ledger/detector-6-negative/.claude/hooks/_lib/.do-not-import-from-here +15 -0
- package/.claude/scripts/tests/fixtures/reality-ledger/detector-6-negative/.claude/hooks/_lib/audit_emit.py +11 -0
- package/.claude/scripts/tests/fixtures/reality-ledger/detector-6-negative/.claude/scripts/registered_emitter.py +8 -0
- package/.claude/scripts/tests/fixtures/reality-ledger/detector-6-positive/.claude/hooks/_lib/.do-not-import-from-here +15 -0
- package/.claude/scripts/tests/fixtures/reality-ledger/detector-6-positive/.claude/hooks/_lib/audit_emit.py +12 -0
- package/.claude/scripts/tests/fixtures/reality-ledger/detector-6-positive/.claude/scripts/phantom_emitter.py +13 -0
- package/.claude/scripts/tests/fixtures/reality-ledger/issue-body-template.md +47 -0
- package/.claude/scripts/tests/fixtures/reality-ledger/redaction/_test_corpus.py +7 -0
- package/.claude/scripts/tests/fixtures/repo_profile/cloned-trading-repo/.env.example +5 -0
- package/.claude/scripts/tests/fixtures/repo_profile/cloned-trading-repo/Cargo.toml +9 -0
- package/.claude/scripts/tests/fixtures/repo_profile/cloned-trading-repo/README.md +6 -0
- package/.claude/scripts/tests/fixtures/repo_profile/cloned-trading-repo/exchanges/binance.py +6 -0
- package/.claude/scripts/tests/fixtures/repo_profile/cloned-trading-repo/strategies/triangular.py +4 -0
- package/.claude/scripts/tests/fixtures/repo_profile/missing-package-manifest/README.md +7 -0
- package/.claude/scripts/tests/fixtures/repo_profile/missing-package-manifest/notes.md +1 -0
- package/.claude/scripts/tests/fixtures/repo_profile/mixed-frontend-backend/README.md +6 -0
- package/.claude/scripts/tests/fixtures/repo_profile/mixed-frontend-backend/api/server.js +4 -0
- package/.claude/scripts/tests/fixtures/repo_profile/mixed-frontend-backend/package.json +15 -0
- package/.claude/scripts/tests/fixtures/repo_profile/mixed-frontend-backend/pages/index.tsx +3 -0
- package/.claude/scripts/tests/fixtures/repo_profile/monorepo/README.md +6 -0
- package/.claude/scripts/tests/fixtures/repo_profile/monorepo/apps/backend/.gitkeep +0 -0
- package/.claude/scripts/tests/fixtures/repo_profile/monorepo/apps/frontend/.gitkeep +0 -0
- package/.claude/scripts/tests/fixtures/repo_profile/monorepo/package.json +5 -0
- package/.claude/scripts/tests/fixtures/repo_profile/monorepo/packages/shared/.gitkeep +0 -0
- package/.claude/scripts/tests/fixtures/sample_audit_log.jsonl +50 -0
- package/.claude/scripts/tests/fixtures/siem/.gitkeep +0 -0
- package/.claude/scripts/tests/fixtures/smart_loading/profile-engine.yaml +8 -0
- package/.claude/scripts/tests/fixtures/smart_loading/profile-fail-closed.yaml +7 -0
- package/.claude/scripts/tests/fixtures/smart_loading/profile-fintech.yaml +9 -0
- package/.claude/scripts/tests/fixtures/smart_loading/profile-frontend.yaml +9 -0
- package/.claude/scripts/tests/fixtures/smart_loading/profile-generic.yaml +8 -0
- package/.claude/scripts/tests/fixtures/smart_loading/profile-trading-readonly.yaml +9 -0
- package/.claude/scripts/tests/fixtures/smart_loading/synthetic-skill-catalog.yaml +186 -0
- package/.claude/scripts/tests/fixtures/squad_marketplace/.gitkeep +4 -0
- package/.claude/scripts/tests/fixtures/task-route/calibration-holdout.json +49 -0
- package/.claude/scripts/tests/fixtures/task-route/calibration-train.json +174 -0
- package/.claude/scripts/tests/perf/__init__.py +3 -0
- package/.claude/scripts/tests/perf/perf_utils.py +134 -0
- package/.claude/scripts/tests/perf/test_kernel_hard_deny_microbench.py +149 -0
- package/.claude/scripts/tests/perf/test_optimizer_complexity_gate_p99.py +145 -0
- package/.claude/scripts/tests/perf/test_wave_c_canonical_json.py +132 -0
- package/.claude/scripts/tests/perf/test_wave_c_filelock_mkdir.py +71 -0
- package/.claude/scripts/tests/perf/test_wave_c_plan_glob_cache.py +84 -0
- package/.claude/scripts/tests/perf/test_wave_c_preview_collapse.py +98 -0
- package/.claude/scripts/tests/perf/test_wave_c_sys_modules.py +104 -0
- package/.claude/scripts/tests/test_a4_pricing_doctrine.py +127 -0
- package/.claude/scripts/tests/test_admin_invite.py +173 -0
- package/.claude/scripts/tests/test_adopter_metrics.py +723 -0
- package/.claude/scripts/tests/test_aek_calibration_c2.py +107 -0
- package/.claude/scripts/tests/test_aek_calibration_c3.py +192 -0
- package/.claude/scripts/tests/test_aek_state_machine.py +385 -0
- package/.claude/scripts/tests/test_aggregate_changesets.py +646 -0
- package/.claude/scripts/tests/test_architect_bundle_validate.py +159 -0
- package/.claude/scripts/tests/test_audit_dashboard.py +822 -0
- package/.claude/scripts/tests/test_audit_log_dispatch_hint.py +91 -0
- package/.claude/scripts/tests/test_audit_log_retain.py +394 -0
- package/.claude/scripts/tests/test_audit_query.py +1177 -0
- package/.claude/scripts/tests/test_audit_query_by_domain.py +576 -0
- package/.claude/scripts/tests/test_audit_query_claims.py +92 -0
- package/.claude/scripts/tests/test_audit_query_critical.py +267 -0
- package/.claude/scripts/tests/test_audit_query_tokens.py +106 -0
- package/.claude/scripts/tests/test_audit_telemetry.py +214 -0
- package/.claude/scripts/tests/test_audit_tokens.py +255 -0
- package/.claude/scripts/tests/test_audit_verify_chain.py +189 -0
- package/.claude/scripts/tests/test_backup_audit.py +295 -0
- package/.claude/scripts/tests/test_benchmark_fallback_scorer.py +299 -0
- package/.claude/scripts/tests/test_benchmark_judge.py +569 -0
- package/.claude/scripts/tests/test_benchmarks_replay.py +313 -0
- package/.claude/scripts/tests/test_budget_summary.py +628 -0
- package/.claude/scripts/tests/test_build_canonical_models.py +349 -0
- package/.claude/scripts/tests/test_calibration_kappa.py +234 -0
- package/.claude/scripts/tests/test_cc_analytics_pull.py +296 -0
- package/.claude/scripts/tests/test_ceo_backup.py +318 -0
- package/.claude/scripts/tests/test_ceo_boot.py +643 -0
- package/.claude/scripts/tests/test_ceo_boot_audit_emit.py +484 -0
- package/.claude/scripts/tests/test_ceo_boot_enhanced.py +706 -0
- package/.claude/scripts/tests/test_ceo_boot_persona_cadence.py +392 -0
- package/.claude/scripts/tests/test_ceo_boot_plan_082.py +365 -0
- package/.claude/scripts/tests/test_ceo_boot_tamper_tripwires.py +556 -0
- package/.claude/scripts/tests/test_ceo_boot_task_candidate.py +868 -0
- package/.claude/scripts/tests/test_ceo_cost.py +221 -0
- package/.claude/scripts/tests/test_ceo_cost_stream.py +1076 -0
- package/.claude/scripts/tests/test_ceo_diagnose.py +314 -0
- package/.claude/scripts/tests/test_ceo_escalation_detector.py +591 -0
- package/.claude/scripts/tests/test_ceo_health.py +202 -0
- package/.claude/scripts/tests/test_ceo_info.py +542 -0
- package/.claude/scripts/tests/test_chaos_inject_lockdown.py +384 -0
- package/.claude/scripts/tests/test_check_action_sha_drift.py +174 -0
- package/.claude/scripts/tests/test_check_active_hooks_executable.py +79 -0
- package/.claude/scripts/tests/test_check_adr_chain.py +665 -0
- package/.claude/scripts/tests/test_check_audit_hmac_null.py +178 -0
- package/.claude/scripts/tests/test_check_audit_read_api_stable.py +176 -0
- package/.claude/scripts/tests/test_check_audit_registry_coverage.py +744 -0
- package/.claude/scripts/tests/test_check_auto_activation_flags.py +140 -0
- package/.claude/scripts/tests/test_check_canonical_doc_freshness.py +149 -0
- package/.claude/scripts/tests/test_check_claude_md_claims.py +223 -0
- package/.claude/scripts/tests/test_check_conformance_harness_mapping.py +243 -0
- package/.claude/scripts/tests/test_check_contamination.py +161 -0
- package/.claude/scripts/tests/test_check_creative_rewrite.py +183 -0
- package/.claude/scripts/tests/test_check_debate_round_lifecycle.py +162 -0
- package/.claude/scripts/tests/test_check_debt_ledger.py +227 -0
- package/.claude/scripts/tests/test_check_doc_skill_paths.py +99 -0
- package/.claude/scripts/tests/test_check_docs_freshness.py +224 -0
- package/.claude/scripts/tests/test_check_flip_criteria_drift.py +343 -0
- package/.claude/scripts/tests/test_check_flip_release_gate_consistency.py +195 -0
- package/.claude/scripts/tests/test_check_function_length.py +519 -0
- package/.claude/scripts/tests/test_check_model_deprecations.py +368 -0
- package/.claude/scripts/tests/test_check_originator_residue.py +165 -0
- package/.claude/scripts/tests/test_check_rule_invariants.py +327 -0
- package/.claude/scripts/tests/test_check_sdk_compat.py +88 -0
- package/.claude/scripts/tests/test_check_sidecar_manifest_sbom_sync.py +177 -0
- package/.claude/scripts/tests/test_check_spec_drift.py +358 -0
- package/.claude/scripts/tests/test_check_staleness.py +128 -0
- package/.claude/scripts/tests/test_check_stdlib_only_exceptions.py +91 -0
- package/.claude/scripts/tests/test_check_substrate_watch.py +234 -0
- package/.claude/scripts/tests/test_check_test_audit_isolation.py +322 -0
- package/.claude/scripts/tests/test_check_test_env_hygiene.py +432 -0
- package/.claude/scripts/tests/test_check_threat_model_coverage.py +251 -0
- package/.claude/scripts/tests/test_check_threat_model_freshness.py +235 -0
- package/.claude/scripts/tests/test_check_tier_boundaries.py +225 -0
- package/.claude/scripts/tests/test_check_tla_schema_drift.py +246 -0
- package/.claude/scripts/tests/test_check_translations_drift.py +262 -0
- package/.claude/scripts/tests/test_code_nav_bridge.py +192 -0
- package/.claude/scripts/tests/test_compaction_template.py +163 -0
- package/.claude/scripts/tests/test_compare_adopters.py +646 -0
- package/.claude/scripts/tests/test_confidence_gate.py +611 -0
- package/.claude/scripts/tests/test_confidence_gate_backfill.py +212 -0
- package/.claude/scripts/tests/test_context_budget.py +1400 -0
- package/.claude/scripts/tests/test_contextual_recommender.py +723 -0
- package/.claude/scripts/tests/test_coverage_audit_marker.py +109 -0
- package/.claude/scripts/tests/test_debate_converge.py +399 -0
- package/.claude/scripts/tests/test_debate_emit_cli.py +153 -0
- package/.claude/scripts/tests/test_debate_orchestrate.py +575 -0
- package/.claude/scripts/tests/test_detect_repo_profile.py +434 -0
- package/.claude/scripts/tests/test_discover_foreign_context.py +208 -0
- package/.claude/scripts/tests/test_dispatch_archetype_hint.py +429 -0
- package/.claude/scripts/tests/test_dispatch_frontmatter_validation.py +274 -0
- package/.claude/scripts/tests/test_drift_wire.py +259 -0
- package/.claude/scripts/tests/test_embeddings.py +249 -0
- package/.claude/scripts/tests/test_env_inventory_check.py +197 -0
- package/.claude/scripts/tests/test_eval_c3.py +474 -0
- package/.claude/scripts/tests/test_extract_skill.py +572 -0
- package/.claude/scripts/tests/test_fan_plan_parser.py +213 -0
- package/.claude/scripts/tests/test_find_orphan_sentinels.py +62 -0
- package/.claude/scripts/tests/test_first_run_wizard.py +634 -0
- package/.claude/scripts/tests/test_generate_adr_index.py +146 -0
- package/.claude/scripts/tests/test_generate_available_models.py +209 -0
- package/.claude/scripts/tests/test_generate_dispatch.py +90 -0
- package/.claude/scripts/tests/test_generate_skill_inventory.py +76 -0
- package/.claude/scripts/tests/test_github_api_client.py +146 -0
- package/.claude/scripts/tests/test_governance_waivers_gate.py +176 -0
- package/.claude/scripts/tests/test_hook_profiler.py +426 -0
- package/.claude/scripts/tests/test_import_skill.py +927 -0
- package/.claude/scripts/tests/test_import_skill_skip_rubric_auth.py +198 -0
- package/.claude/scripts/tests/test_inject_agent_context_mitigated_dispatch.py +266 -0
- package/.claude/scripts/tests/test_inject_agent_context_reference_mode.py +105 -0
- package/.claude/scripts/tests/test_inspired_by_validator.py +307 -0
- package/.claude/scripts/tests/test_install_dispatcher_present_maintainer.py +76 -0
- package/.claude/scripts/tests/test_install_maintainer_unchanged.py +86 -0
- package/.claude/scripts/tests/test_install_npm_sha256.py +113 -0
- package/.claude/scripts/tests/test_install_sh_placeholders.py +268 -0
- package/.claude/scripts/tests/test_install_sh_self_sha.py +244 -0
- package/.claude/scripts/tests/test_install_sh_session_75_flags.py +147 -0
- package/.claude/scripts/tests/test_install_user_dispatcher_present.py +75 -0
- package/.claude/scripts/tests/test_install_user_no_writes_outside_claude.py +75 -0
- package/.claude/scripts/tests/test_install_user_passes_validate_governance.py +73 -0
- package/.claude/scripts/tests/test_install_user_preserves_existing_repo.py +135 -0
- package/.claude/scripts/tests/test_install_user_skips_governance_hooks.py +102 -0
- package/.claude/scripts/tests/test_k_calibration.py +415 -0
- package/.claude/scripts/tests/test_key_hygiene.py +372 -0
- package/.claude/scripts/tests/test_lesson_ranker.py +82 -0
- package/.claude/scripts/tests/test_lesson_restore.py +91 -0
- package/.claude/scripts/tests/test_lessons.py +278 -0
- package/.claude/scripts/tests/test_lessons_concurrency.py +118 -0
- package/.claude/scripts/tests/test_lessons_emit.py +114 -0
- package/.claude/scripts/tests/test_lessons_inject.py +144 -0
- package/.claude/scripts/tests/test_lessons_v2.py +264 -0
- package/.claude/scripts/tests/test_lint_skills.py +525 -0
- package/.claude/scripts/tests/test_log_friction.py +436 -0
- package/.claude/scripts/tests/test_memory_prioritize.py +315 -0
- package/.claude/scripts/tests/test_morning_ledger.py +415 -0
- package/.claude/scripts/tests/test_mutation_test.py +144 -0
- package/.claude/scripts/tests/test_npm_rebuild.py +154 -0
- package/.claude/scripts/tests/test_osv_check.py +411 -0
- package/.claude/scripts/tests/test_otel_export.py +613 -0
- package/.claude/scripts/tests/test_otel_local_sink.py +262 -0
- package/.claude/scripts/tests/test_owasp_llm_top_10_benchmark.py +235 -0
- package/.claude/scripts/tests/test_parse_coverage_tier1.py +107 -0
- package/.claude/scripts/tests/test_pitfall_query.py +148 -0
- package/.claude/scripts/tests/test_plan_frontmatter_status.py +217 -0
- package/.claude/scripts/tests/test_plan_id_uniqueness.py +133 -0
- package/.claude/scripts/tests/test_plan_schema_enforcement.py +251 -0
- package/.claude/scripts/tests/test_plan_tokens.py +513 -0
- package/.claude/scripts/tests/test_plan_vcheck_gate.py +257 -0
- package/.claude/scripts/tests/test_policy_shadow_runner.py +312 -0
- package/.claude/scripts/tests/test_prune_lessons.py +341 -0
- package/.claude/scripts/tests/test_quality_profile.py +392 -0
- package/.claude/scripts/tests/test_rate_card_calibrate.py +185 -0
- package/.claude/scripts/tests/test_reality_ledger.py +1723 -0
- package/.claude/scripts/tests/test_red_team_eval.py +566 -0
- package/.claude/scripts/tests/test_red_team_eval_sha.py +260 -0
- package/.claude/scripts/tests/test_registry.py +290 -0
- package/.claude/scripts/tests/test_run_benchmark.py +639 -0
- package/.claude/scripts/tests/test_run_skill_benchmark_emit.py +195 -0
- package/.claude/scripts/tests/test_run_skill_benchmark_judge_mode.py +306 -0
- package/.claude/scripts/tests/test_scan_injection.py +191 -0
- package/.claude/scripts/tests/test_scan_injection_strict.sh +201 -0
- package/.claude/scripts/tests/test_scratchpad_cli.py +317 -0
- package/.claude/scripts/tests/test_self_test.py +369 -0
- package/.claude/scripts/tests/test_session_graph.py +511 -0
- package/.claude/scripts/tests/test_session_resume.py +306 -0
- package/.claude/scripts/tests/test_siem_rule_fixtures_have_paired_positive_negative.py +112 -0
- package/.claude/scripts/tests/test_skill_budget_generator.py +329 -0
- package/.claude/scripts/tests/test_skill_grandfather_parser.py +314 -0
- package/.claude/scripts/tests/test_skill_import_rubric.py +497 -0
- package/.claude/scripts/tests/test_skill_patch_apply_create_new_skill.py +459 -0
- package/.claude/scripts/tests/test_skill_patch_propose.py +294 -0
- package/.claude/scripts/tests/test_skill_patch_shadow_race.py +271 -0
- package/.claude/scripts/tests/test_skill_retrieval.py +486 -0
- package/.claude/scripts/tests/test_skill_retrieve_rag_wire.py +747 -0
- package/.claude/scripts/tests/test_smart_loading_resolver.py +808 -0
- package/.claude/scripts/tests/test_squad_export.py +265 -0
- package/.claude/scripts/tests/test_squad_grandfather_cap.py +434 -0
- package/.claude/scripts/tests/test_squad_import.py +905 -0
- package/.claude/scripts/tests/test_statusline_ceo.py +543 -0
- package/.claude/scripts/tests/test_success_receipt.py +448 -0
- package/.claude/scripts/tests/test_task_route.py +456 -0
- package/.claude/scripts/tests/test_token_budget_guard.py +418 -0
- package/.claude/scripts/tests/test_token_estimator.py +395 -0
- package/.claude/scripts/tests/test_trading_readonly.py +705 -0
- package/.claude/scripts/tests/test_ui_ux_imports.py +223 -0
- package/.claude/scripts/tests/test_validate_skill_frontmatter_pii_core.py +630 -0
- package/.claude/scripts/tests/test_validate_spec_context.py +128 -0
- package/.claude/scripts/tests/test_validate_squad_contract.py +221 -0
- package/.claude/scripts/tests/test_value_dashboard.py +593 -0
- package/.claude/scripts/tests/test_verify_adr_118_rationale.py +183 -0
- package/.claude/scripts/tests/test_verify_atlas_binding.py +159 -0
- package/.claude/scripts/tests/test_verify_counts.py +138 -0
- package/.claude/scripts/tests/test_verify_counts_remediation.py +258 -0
- package/.claude/scripts/tests/test_verify_persona_coverage.py +576 -0
- package/.claude/scripts/tests/test_veto_check.py +171 -0
- package/.claude/scripts/tests/test_workflow_devops_p2.py +229 -0
- package/.claude/scripts/tier_policy_cli/__init__.py +43 -0
- package/.claude/scripts/tier_policy_cli/_agent_frontmatter.py +196 -0
- package/.claude/scripts/tier_policy_cli/_constants.py +92 -0
- package/.claude/scripts/tier_policy_cli/_types.py +228 -0
- package/.claude/scripts/tier_policy_cli/apply.py +1139 -0
- package/.claude/scripts/tier_policy_cli/cli.py +795 -0
- package/.claude/scripts/tier_policy_cli/learn.py +846 -0
- package/.claude/scripts/tier_policy_cli/loader.py +535 -0
- package/.claude/scripts/tier_policy_cli/setup.py +33 -0
- package/.claude/scripts/tier_policy_cli/tests/__init__.py +0 -0
- package/.claude/scripts/tier_policy_cli/tests/test_adversarial.py +605 -0
- package/.claude/scripts/tier_policy_cli/tests/test_agent_frontmatter.py +231 -0
- package/.claude/scripts/tier_policy_cli/tests/test_apply.py +698 -0
- package/.claude/scripts/tier_policy_cli/tests/test_check_tier_policy_hook.py +187 -0
- package/.claude/scripts/tier_policy_cli/tests/test_cli.py +434 -0
- package/.claude/scripts/tier_policy_cli/tests/test_constants.py +113 -0
- package/.claude/scripts/tier_policy_cli/tests/test_learn.py +1380 -0
- package/.claude/scripts/tier_policy_cli/tests/test_learn_mutation.py +549 -0
- package/.claude/scripts/tier_policy_cli/tests/test_loader.py +368 -0
- package/.claude/scripts/tier_policy_cli/tests/test_types.py +152 -0
- package/.claude/scripts/token-budget-guard.py +657 -0
- package/.claude/scripts/token-estimator.py +957 -0
- package/.claude/scripts/tournament/__init__.py +22 -0
- package/.claude/scripts/tournament/check_fixture.py +271 -0
- package/.claude/scripts/tournament/fixtures/CORPUS_SHA256.txt +10 -0
- package/.claude/scripts/tournament/fixtures/code-review.jsonl +10 -0
- package/.claude/scripts/tournament/fixtures/docs-writing.jsonl +10 -0
- package/.claude/scripts/tournament/fixtures/performance-triage.jsonl +10 -0
- package/.claude/scripts/tournament/fixtures/security-review.jsonl +10 -0
- package/.claude/scripts/tournament/fixtures/test-design.jsonl +10 -0
- package/.claude/scripts/tournament/judge.py +269 -0
- package/.claude/scripts/tournament/loader.py +262 -0
- package/.claude/scripts/tournament/regen_corpus_sha.py +93 -0
- package/.claude/scripts/tournament/reporter.py +328 -0
- package/.claude/scripts/tournament/runner.py +707 -0
- package/.claude/scripts/tournament/scorer.py +118 -0
- package/.claude/scripts/tournament/tests/__init__.py +0 -0
- package/.claude/scripts/tournament/tests/_fake_dispatcher.py +233 -0
- package/.claude/scripts/tournament/tests/golden/strict_report_seed42.jsonl +6 -0
- package/.claude/scripts/tournament/tests/test_fixture_envelope.py +106 -0
- package/.claude/scripts/tournament/tests/test_fixture_security.py +227 -0
- package/.claude/scripts/tournament/tests/test_judge.py +299 -0
- package/.claude/scripts/tournament/tests/test_loader.py +223 -0
- package/.claude/scripts/tournament/tests/test_model_id_parity.py +136 -0
- package/.claude/scripts/tournament/tests/test_reporter.py +450 -0
- package/.claude/scripts/tournament/tests/test_reporter_golden.py +182 -0
- package/.claude/scripts/tournament/tests/test_runner.py +313 -0
- package/.claude/scripts/tournament/tests/test_runner_fail_open.py +204 -0
- package/.claude/scripts/tournament/tests/test_scorer.py +138 -0
- package/.claude/scripts/tournament/tests/test_tournament_e2e_smoke.py +147 -0
- package/.claude/scripts/tournament/tests/test_tournament_properties.py +181 -0
- package/.claude/scripts/trading-readonly-escape-hatch.sh +244 -0
- package/.claude/scripts/trading-readonly-guardrails.py +1136 -0
- package/.claude/scripts/translations-pairs.yaml +60 -0
- package/.claude/scripts/validate-findings.py +243 -0
- package/.claude/scripts/validate-governance.sh +1238 -0
- package/.claude/scripts/validate-skill-frontmatter.py +679 -0
- package/.claude/scripts/validate-spec-context.py +146 -0
- package/.claude/scripts/validate-squad-contract.py +318 -0
- package/.claude/scripts/validate_governance_fast.py +555 -0
- package/.claude/scripts/value-dashboard.py +851 -0
- package/.claude/scripts/verify-adr-118-rationale.py +285 -0
- package/.claude/scripts/verify-atlas-binding.py +331 -0
- package/.claude/scripts/verify-persona-coverage.py +531 -0
- package/.claude/scripts/verify-sprint3-invariants.sh +133 -0
- package/.claude/scripts/veto-check.py +218 -0
- package/.claude/security/README.md +200 -0
- package/.claude/security/sentinel-signers-registry.yaml +60 -0
- package/.claude/sentinel-signers.txt +24 -0
- package/.claude/settings.json +786 -0
- package/.claude/sidecars/c1-crypto/cryptography-mvp/README.md +89 -0
- package/.claude/sidecars/c1-crypto/cryptography-mvp/boundary_test.py +114 -0
- package/.claude/sidecars/c1-crypto/cryptography-mvp/install.sh +45 -0
- package/.claude/sidecars/c1-crypto/cryptography-mvp/manifest.json +52 -0
- package/.claude/sidecars/c1-crypto/cryptography-mvp/sidecar_code/cert_inspector.py +775 -0
- package/.claude/sidecars/c1-crypto/stdlib-ssl-mvp/boundary_test.py +318 -0
- package/.claude/sidecars/c1-crypto/stdlib-ssl-mvp/install.sh +57 -0
- package/.claude/sidecars/c1-crypto/stdlib-ssl-mvp/manifest.json +48 -0
- package/.claude/sidecars/c2-vector-memory/lightrag-mvp/README.md +88 -0
- package/.claude/sidecars/c2-vector-memory/lightrag-mvp/boundary_test.py +221 -0
- package/.claude/sidecars/c2-vector-memory/lightrag-mvp/install.sh +33 -0
- package/.claude/sidecars/c2-vector-memory/lightrag-mvp/manifest.json +59 -0
- package/.claude/sidecars/c5-dev-tools/hypothesis/boundary_test.py +142 -0
- package/.claude/sidecars/c5-dev-tools/hypothesis/install.sh +46 -0
- package/.claude/sidecars/c5-dev-tools/hypothesis/manifest.json +52 -0
- package/.claude/sidecars/c5-dev-tools/hypothesis/tests/__init__.py +0 -0
- package/.claude/sidecars/c5-dev-tools/hypothesis/tests/test_audit_emit_known_actions_property.py +123 -0
- package/.claude/sidecars/c5-dev-tools/hypothesis/tests/test_canonical_guard_symmetry_property.py +67 -0
- package/.claude/sidecars/c5-dev-tools/hypothesis/tests/test_payload_roundtrip_property.py +73 -0
- package/.claude/sidecars/c5-dev-tools/hypothesis/tests/test_redact_idempotence_property.py +68 -0
- package/.claude/skill-governance-grandfather.yaml +39 -0
- package/.claude/skill-patch-signers.txt +19 -0
- package/.claude/skills/core/agent-architect/SKILL.md +126 -0
- package/.claude/skills/core/ai-llm-orchestration/SKILL.md +620 -0
- package/.claude/skills/core/ai-llm-orchestration/SKILL.md.shadow.md +121 -0
- package/.claude/skills/core/architecture-decisions/SKILL.md +364 -0
- package/.claude/skills/core/architecture-decisions/benchmarks/architecture-decisions.yaml +257 -0
- package/.claude/skills/core/ceo-orchestration/SKILL-frontend.md +117 -0
- package/.claude/skills/core/ceo-orchestration/SKILL.md +700 -0
- package/.claude/skills/core/chaos-and-resilience/SKILL.md +568 -0
- package/.claude/skills/core/chaos-and-resilience/SKILL.md.shadow.md +553 -0
- package/.claude/skills/core/code-intelligence-lsp/SKILL.md +375 -0
- package/.claude/skills/core/code-review-checklist/SKILL.md +675 -0
- package/.claude/skills/core/code-review-checklist/SKILL.md.shadow.md +337 -0
- package/.claude/skills/core/code-review-checklist/benchmarks/code-review-checklist.yaml +444 -0
- package/.claude/skills/core/codebase-onboarding/SKILL.md +515 -0
- package/.claude/skills/core/compliance-lgpd/SKILL-frontend.md +513 -0
- package/.claude/skills/core/compliance-lgpd/SKILL.md +817 -0
- package/.claude/skills/core/consent-lifecycle/SKILL.md +149 -0
- package/.claude/skills/core/cookbook-advisor/SKILL.md +191 -0
- package/.claude/skills/core/coverage-audit/SKILL.md +116 -0
- package/.claude/skills/core/cross-llm-pair-review/SKILL.md +212 -0
- package/.claude/skills/core/data-schema-design/SKILL.md +933 -0
- package/.claude/skills/core/devops-ci-cd/SKILL.md +659 -0
- package/.claude/skills/core/dpo-reporting/SKILL.md +187 -0
- package/.claude/skills/core/evidence-based-qa/SKILL.md +565 -0
- package/.claude/skills/core/git-workflow-discipline/SKILL.md +600 -0
- package/.claude/skills/core/growth-and-launch/SKILL-frontend.md +800 -0
- package/.claude/skills/core/growth-and-launch/SKILL.md +903 -0
- package/.claude/skills/core/help-me/SKILL.md +177 -0
- package/.claude/skills/core/help-me/tests/test_help_me_skill.py +490 -0
- package/.claude/skills/core/identity-and-trust-architecture/SKILL.md +1062 -0
- package/.claude/skills/core/incident-management/SKILL.md +421 -0
- package/.claude/skills/core/incremental-refactoring/SKILL-frontend.md +210 -0
- package/.claude/skills/core/incremental-refactoring/SKILL.md +226 -0
- package/.claude/skills/core/llm-routing-and-finops/SKILL.md +828 -0
- package/.claude/skills/core/mcp-server-authoring/SKILL.md +685 -0
- package/.claude/skills/core/minimal-change-discipline/SKILL.md +545 -0
- package/.claude/skills/core/monetization-and-billing/SKILL-frontend.md +562 -0
- package/.claude/skills/core/monetization-and-billing/SKILL.md +585 -0
- package/.claude/skills/core/observability-and-ops/SKILL-frontend.md +290 -0
- package/.claude/skills/core/observability-and-ops/SKILL.md +612 -0
- package/.claude/skills/core/observability-and-ops/SKILL.md.shadow.md +324 -0
- package/.claude/skills/core/parallelization-by-default/SKILL.md +176 -0
- package/.claude/skills/core/parallelization-by-default/tests/test_parallelization_skill.py +490 -0
- package/.claude/skills/core/performance-engineering/SKILL.md +219 -0
- package/.claude/skills/core/performance-engineering/SKILL.md.shadow.md +204 -0
- package/.claude/skills/core/pii-data-flow/SKILL.md +166 -0
- package/.claude/skills/core/pre-plan-brainstorm/CHECKLIST.md +87 -0
- package/.claude/skills/core/pre-plan-brainstorm/SKILL.md +186 -0
- package/.claude/skills/core/product-conversion-readiness/SKILL-frontend.md +668 -0
- package/.claude/skills/core/product-conversion-readiness/SKILL.md +941 -0
- package/.claude/skills/core/public-api-design/SKILL.md +603 -0
- package/.claude/skills/core/public-api-design/benchmarks/public-api-design.yaml +261 -0
- package/.claude/skills/core/receiving-review/SKILL.md +131 -0
- package/.claude/skills/core/receiving-review/benchmarks/receiving-review.yaml +254 -0
- package/.claude/skills/core/requirement-quality-checklist/SKILL.md +97 -0
- package/.claude/skills/core/security-and-auth/SKILL.md +868 -0
- package/.claude/skills/core/security-and-auth/SKILL.md.shadow.md +500 -0
- package/.claude/skills/core/security-and-auth/benchmarks/owasp-basics.yaml +491 -0
- package/.claude/skills/core/security-and-auth/benchmarks/owasp-llm-top-10.yaml +769 -0
- package/.claude/skills/core/spec-clarify/SKILL.md +120 -0
- package/.claude/skills/core/state-machines-and-invariants/SKILL.md +288 -0
- package/.claude/skills/core/technical-writing/SKILL.md +432 -0
- package/.claude/skills/core/terse-mode/SKILL.md +80 -0
- package/.claude/skills/core/terse-mode/SKILL.md.shadow.md +65 -0
- package/.claude/skills/core/testing-strategy/SKILL.md +1026 -0
- package/.claude/skills/core/testing-strategy/SKILL.md.shadow.md +983 -0
- package/.claude/skills/domains/academic-humanities/examples/PLAN-EXAMPLE-ACH.md +126 -0
- package/.claude/skills/domains/academic-humanities/pitfalls.yaml +68 -0
- package/.claude/skills/domains/academic-humanities/skills/anthropologist/SKILL.md +394 -0
- package/.claude/skills/domains/academic-humanities/skills/geographer/SKILL.md +453 -0
- package/.claude/skills/domains/academic-humanities/skills/historian/SKILL.md +255 -0
- package/.claude/skills/domains/academic-humanities/skills/narratologist/SKILL.md +398 -0
- package/.claude/skills/domains/academic-humanities/skills/psychologist/SKILL.md +271 -0
- package/.claude/skills/domains/academic-humanities/task-chains.yaml +125 -0
- package/.claude/skills/domains/academic-humanities/team-personas.md +278 -0
- package/.claude/skills/domains/business-support/examples/PLAN-EXAMPLE-BSP.md +115 -0
- package/.claude/skills/domains/business-support/pitfalls.yaml +69 -0
- package/.claude/skills/domains/business-support/skills/analytics-reporter/SKILL.md +339 -0
- package/.claude/skills/domains/business-support/skills/executive-summary/SKILL.md +268 -0
- package/.claude/skills/domains/business-support/skills/finance-tracker/SKILL.md +321 -0
- package/.claude/skills/domains/business-support/skills/support-responder/SKILL.md +341 -0
- package/.claude/skills/domains/business-support/task-chains.yaml +118 -0
- package/.claude/skills/domains/business-support/team-personas.md +259 -0
- package/.claude/skills/domains/civil-engineering/skills/civil-engineer/SKILL.md +275 -0
- package/.claude/skills/domains/community/NOTICE.md +83 -0
- package/.claude/skills/domains/community/skills/advanced-evaluation/SKILL.md +463 -0
- package/.claude/skills/domains/community/skills/agent-evaluation/SKILL.md +400 -0
- package/.claude/skills/domains/community/skills/agentic-actions-auditor/SKILL.md +410 -0
- package/.claude/skills/domains/community/team-personas.md +41 -0
- package/.claude/skills/domains/devrel/examples/api-deprecation-comms.md +180 -0
- package/.claude/skills/domains/devrel/pitfalls.yaml +74 -0
- package/.claude/skills/domains/devrel/skills/developer-advocate/SKILL.md +382 -0
- package/.claude/skills/domains/devrel/task-chains.yaml +129 -0
- package/.claude/skills/domains/devrel/team-personas.md +260 -0
- package/.claude/skills/domains/edtech/examples/PLAN-EXAMPLE.md +89 -0
- package/.claude/skills/domains/edtech/pitfalls.yaml +98 -0
- package/.claude/skills/domains/edtech/skills/assessment-integrity/SKILL.md +208 -0
- package/.claude/skills/domains/edtech/skills/learning-analytics/SKILL.md +212 -0
- package/.claude/skills/domains/edtech/skills/student-data-privacy/SKILL.md +197 -0
- package/.claude/skills/domains/edtech/skills/study-abroad-advisory/SKILL.md +582 -0
- package/.claude/skills/domains/edtech/task-chains.yaml +122 -0
- package/.claude/skills/domains/edtech/team-personas.md +252 -0
- package/.claude/skills/domains/embedded/skills/embedded-firmware/SKILL.md +471 -0
- package/.claude/skills/domains/finance-accounting/examples/new-subscription-revenue.md +135 -0
- package/.claude/skills/domains/finance-accounting/pitfalls.yaml +74 -0
- package/.claude/skills/domains/finance-accounting/skills/bookkeeper-controller/SKILL.md +427 -0
- package/.claude/skills/domains/finance-accounting/skills/financial-analyst/SKILL.md +348 -0
- package/.claude/skills/domains/finance-accounting/skills/fpa-analyst/SKILL.md +366 -0
- package/.claude/skills/domains/finance-accounting/skills/tax-strategist/SKILL.md +358 -0
- package/.claude/skills/domains/finance-accounting/task-chains.yaml +90 -0
- package/.claude/skills/domains/finance-accounting/team-personas.md +281 -0
- package/.claude/skills/domains/fintech/ORG_CHART.md +167 -0
- package/.claude/skills/domains/fintech/commands/audit-ai.md +124 -0
- package/.claude/skills/domains/fintech/commands/deploy.md +15 -0
- package/.claude/skills/domains/fintech/commands/status.md +13 -0
- package/.claude/skills/domains/fintech/frontend-team-personas.md +503 -0
- package/.claude/skills/domains/fintech/pitfalls.yaml +58 -0
- package/.claude/skills/domains/fintech/scripts/check-pitfall-regression.sh +80 -0
- package/.claude/skills/domains/fintech/scripts/check-type-sync.sh +110 -0
- package/.claude/skills/domains/fintech/skills/blockchain-security-audit/SKILL.md +492 -0
- package/.claude/skills/domains/fintech/skills/equity-research/SKILL.md +459 -0
- package/.claude/skills/domains/fintech/skills/exchange-api-integration/SKILL.md +315 -0
- package/.claude/skills/domains/fintech/skills/exchange-onboarding-playbook/SKILL.md +527 -0
- package/.claude/skills/domains/fintech/skills/financial-correctness-and-math/SKILL-frontend.md +308 -0
- package/.claude/skills/domains/fintech/skills/financial-correctness-and-math/SKILL.md +340 -0
- package/.claude/skills/domains/fintech/skills/financial-display/SKILL.md +193 -0
- package/.claude/skills/domains/fintech/skills/frontend-data-layer/SKILL.md +206 -0
- package/.claude/skills/domains/fintech/skills/frontend-patterns/SKILL.md +387 -0
- package/.claude/skills/domains/fintech/skills/prediction-markets/SKILL.md +139 -0
- package/.claude/skills/domains/fintech/skills/real-time-market-systems/SKILL.md +315 -0
- package/.claude/skills/domains/fintech/skills/solidity-smart-contracts/SKILL.md +356 -0
- package/.claude/skills/domains/fintech/skills/trading-execution/SKILL.md +126 -0
- package/.claude/skills/domains/fintech/task-chains.yaml +46 -0
- package/.claude/skills/domains/fintech/team-personas.md +773 -0
- package/.claude/skills/domains/government/examples/PLAN-EXAMPLE.md +158 -0
- package/.claude/skills/domains/government/pitfalls.yaml +114 -0
- package/.claude/skills/domains/government/skills/accessibility-section-508/SKILL.md +183 -0
- package/.claude/skills/domains/government/skills/digital-presales/SKILL.md +359 -0
- package/.claude/skills/domains/government/skills/foia-and-records/SKILL.md +211 -0
- package/.claude/skills/domains/government/skills/public-procurement/SKILL.md +264 -0
- package/.claude/skills/domains/government/task-chains.yaml +88 -0
- package/.claude/skills/domains/government/team-personas.md +296 -0
- package/.claude/skills/domains/healthcare/examples/patient-portal-symptom-checker.md +130 -0
- package/.claude/skills/domains/healthcare/pitfalls.yaml +74 -0
- package/.claude/skills/domains/healthcare/skills/healthcare-customer-service/SKILL.md +369 -0
- package/.claude/skills/domains/healthcare/skills/marketing-compliance/SKILL.md +367 -0
- package/.claude/skills/domains/healthcare/task-chains.yaml +87 -0
- package/.claude/skills/domains/healthcare/team-personas.md +273 -0
- package/.claude/skills/domains/hospitality/skills/guest-services/SKILL.md +417 -0
- package/.claude/skills/domains/hr/examples/attrition-model-launch.md +128 -0
- package/.claude/skills/domains/hr/pitfalls.yaml +74 -0
- package/.claude/skills/domains/hr/skills/hr-onboarding/SKILL.md +435 -0
- package/.claude/skills/domains/hr/skills/recruitment-specialist/SKILL.md +400 -0
- package/.claude/skills/domains/hr/task-chains.yaml +91 -0
- package/.claude/skills/domains/hr/team-personas.md +251 -0
- package/.claude/skills/domains/i18n-business/examples/PLAN-EXAMPLE-I18N.md +115 -0
- package/.claude/skills/domains/i18n-business/pitfalls.yaml +68 -0
- package/.claude/skills/domains/i18n-business/skills/cultural-intelligence/SKILL.md +448 -0
- package/.claude/skills/domains/i18n-business/skills/french-consulting/SKILL.md +347 -0
- package/.claude/skills/domains/i18n-business/skills/korean-business/SKILL.md +360 -0
- package/.claude/skills/domains/i18n-business/skills/language-translator/SKILL.md +389 -0
- package/.claude/skills/domains/i18n-business/task-chains.yaml +117 -0
- package/.claude/skills/domains/i18n-business/team-personas.md +258 -0
- package/.claude/skills/domains/identity-systems/examples/passkey-rollout.md +137 -0
- package/.claude/skills/domains/identity-systems/pitfalls.yaml +74 -0
- package/.claude/skills/domains/identity-systems/skills/identity-graph-operator/SKILL.md +353 -0
- package/.claude/skills/domains/identity-systems/task-chains.yaml +90 -0
- package/.claude/skills/domains/identity-systems/team-personas.md +233 -0
- package/.claude/skills/domains/legal/examples/client-intake-pii-flow.md +177 -0
- package/.claude/skills/domains/legal/pitfalls.yaml +77 -0
- package/.claude/skills/domains/legal/skills/client-intake/SKILL.md +407 -0
- package/.claude/skills/domains/legal/skills/document-review/SKILL.md +373 -0
- package/.claude/skills/domains/legal/skills/legal-billing/SKILL.md +331 -0
- package/.claude/skills/domains/legal/task-chains.yaml +131 -0
- package/.claude/skills/domains/legal/team-personas.md +260 -0
- package/.claude/skills/domains/lgpd-heavy-saas/examples/PLAN-EXAMPLE.md +120 -0
- package/.claude/skills/domains/lgpd-heavy-saas/pitfalls.yaml +90 -0
- package/.claude/skills/domains/lgpd-heavy-saas/task-chains.yaml +83 -0
- package/.claude/skills/domains/lgpd-heavy-saas/team-personas.md +159 -0
- package/.claude/skills/domains/marketing-global/skills/agentic-search-optimizer/SKILL.md +391 -0
- package/.claude/skills/domains/marketing-global/skills/ai-citation-strategist/SKILL.md +343 -0
- package/.claude/skills/domains/marketing-global/skills/app-store-optimizer/SKILL.md +495 -0
- package/.claude/skills/domains/marketing-global/skills/book-co-author/SKILL.md +220 -0
- package/.claude/skills/domains/marketing-global/skills/carousel-growth-engine/SKILL.md +393 -0
- package/.claude/skills/domains/marketing-global/skills/content-creator/SKILL.md +416 -0
- package/.claude/skills/domains/marketing-global/skills/growth-hacker/SKILL.md +495 -0
- package/.claude/skills/domains/marketing-global/skills/instagram-curator/SKILL.md +419 -0
- package/.claude/skills/domains/marketing-global/skills/linkedin-content-creator/SKILL.md +291 -0
- package/.claude/skills/domains/marketing-global/skills/podcast-strategist/SKILL.md +408 -0
- package/.claude/skills/domains/marketing-global/skills/reddit-community-builder/SKILL.md +295 -0
- package/.claude/skills/domains/marketing-global/skills/seo-specialist/SKILL.md +352 -0
- package/.claude/skills/domains/marketing-global/skills/social-media-strategist/SKILL.md +349 -0
- package/.claude/skills/domains/marketing-global/skills/tiktok-strategist/SKILL.md +329 -0
- package/.claude/skills/domains/marketing-global/skills/twitter-engager/SKILL.md +382 -0
- package/.claude/skills/domains/marketing-global/skills/video-optimization-specialist/SKILL.md +386 -0
- package/.claude/skills/domains/mobile/examples/PLAN-EXAMPLE-MOB.md +129 -0
- package/.claude/skills/domains/mobile/pitfalls.yaml +69 -0
- package/.claude/skills/domains/mobile/skills/mobile-app-builder/SKILL.md +446 -0
- package/.claude/skills/domains/mobile/task-chains.yaml +126 -0
- package/.claude/skills/domains/mobile/team-personas.md +292 -0
- package/.claude/skills/domains/paid-media/examples/new-channel-launch.md +122 -0
- package/.claude/skills/domains/paid-media/pitfalls.yaml +79 -0
- package/.claude/skills/domains/paid-media/skills/auditor/SKILL.md +362 -0
- package/.claude/skills/domains/paid-media/skills/creative-strategist/SKILL.md +457 -0
- package/.claude/skills/domains/paid-media/skills/paid-social-strategist/SKILL.md +493 -0
- package/.claude/skills/domains/paid-media/skills/ppc-strategist/SKILL.md +450 -0
- package/.claude/skills/domains/paid-media/skills/programmatic-buyer/SKILL.md +396 -0
- package/.claude/skills/domains/paid-media/skills/search-query-analyst/SKILL.md +336 -0
- package/.claude/skills/domains/paid-media/skills/tracking-specialist/SKILL.md +457 -0
- package/.claude/skills/domains/paid-media/task-chains.yaml +121 -0
- package/.claude/skills/domains/paid-media/team-personas.md +251 -0
- package/.claude/skills/domains/project-management/examples/PLAN-EXAMPLE-PMG.md +117 -0
- package/.claude/skills/domains/project-management/pitfalls.yaml +68 -0
- package/.claude/skills/domains/project-management/skills/experiment-tracker/SKILL.md +293 -0
- package/.claude/skills/domains/project-management/skills/project-shepherd/SKILL.md +312 -0
- package/.claude/skills/domains/project-management/skills/studio-operations/SKILL.md +333 -0
- package/.claude/skills/domains/project-management/skills/studio-producer/SKILL.md +329 -0
- package/.claude/skills/domains/project-management/task-chains.yaml +118 -0
- package/.claude/skills/domains/project-management/team-personas.md +264 -0
- package/.claude/skills/domains/real-estate-finance/examples/PLAN-EXAMPLE-REF.md +129 -0
- package/.claude/skills/domains/real-estate-finance/pitfalls.yaml +68 -0
- package/.claude/skills/domains/real-estate-finance/skills/buyer-seller-agent/SKILL.md +410 -0
- package/.claude/skills/domains/real-estate-finance/skills/loan-officer-assistant/SKILL.md +415 -0
- package/.claude/skills/domains/real-estate-finance/task-chains.yaml +123 -0
- package/.claude/skills/domains/real-estate-finance/team-personas.md +287 -0
- package/.claude/skills/domains/retail/skills/customer-returns/SKILL.md +363 -0
- package/.claude/skills/domains/saas-platforms/examples/enterprise-tier-isolation.md +147 -0
- package/.claude/skills/domains/saas-platforms/pitfalls.yaml +74 -0
- package/.claude/skills/domains/saas-platforms/skills/cms-developer/SKILL.md +377 -0
- package/.claude/skills/domains/saas-platforms/skills/filament-specialist/SKILL.md +316 -0
- package/.claude/skills/domains/saas-platforms/skills/salesforce-architect/SKILL.md +369 -0
- package/.claude/skills/domains/saas-platforms/task-chains.yaml +90 -0
- package/.claude/skills/domains/saas-platforms/team-personas.md +283 -0
- package/.claude/skills/domains/sales/examples/qbr-revenue-forecast.md +158 -0
- package/.claude/skills/domains/sales/pitfalls.yaml +73 -0
- package/.claude/skills/domains/sales/skills/account-strategist/SKILL.md +408 -0
- package/.claude/skills/domains/sales/skills/deal-strategist/SKILL.md +292 -0
- package/.claude/skills/domains/sales/skills/discovery-coach/SKILL.md +257 -0
- package/.claude/skills/domains/sales/skills/outbound-strategist/SKILL.md +262 -0
- package/.claude/skills/domains/sales/skills/pipeline-analyst/SKILL.md +317 -0
- package/.claude/skills/domains/sales/skills/proposal-strategist/SKILL.md +288 -0
- package/.claude/skills/domains/sales/skills/sales-coach/SKILL.md +306 -0
- package/.claude/skills/domains/sales/skills/sales-engineer/SKILL.md +272 -0
- package/.claude/skills/domains/sales/skills/sales-outreach/SKILL.md +338 -0
- package/.claude/skills/domains/sales/task-chains.yaml +123 -0
- package/.claude/skills/domains/sales/team-personas.md +249 -0
- package/.claude/skills/domains/supply-chain/skills/supply-chain-strategist/SKILL.md +340 -0
- package/.claude/skills/domains/trading-hft/examples/PLAN-EXAMPLE.md +145 -0
- package/.claude/skills/domains/trading-hft/pitfalls.yaml +99 -0
- package/.claude/skills/domains/trading-hft/skills/kill-switches/SKILL.md +128 -0
- package/.claude/skills/domains/trading-hft/skills/latency-budgets/SKILL.md +117 -0
- package/.claude/skills/domains/trading-hft/skills/order-routing/SKILL.md +97 -0
- package/.claude/skills/domains/trading-hft/task-chains.yaml +97 -0
- package/.claude/skills/domains/trading-hft/team-personas.md +155 -0
- package/.claude/skills/domains/training-l-and-d/skills/corporate-training-designer/SKILL.md +268 -0
- package/.claude/skills/domains/voice-ai/skills/voice-ai-integration/SKILL.md +405 -0
- package/.claude/skills/frontend/NOTICE.md +80 -0
- package/.claude/skills/frontend/accessibility-and-wcag/SKILL.md +395 -0
- package/.claude/skills/frontend/accessibility-and-wcag/SKILL.md.shadow.md +181 -0
- package/.claude/skills/frontend/accessibility-and-wcag/benchmarks/accessibility-and-wcag.yaml +420 -0
- package/.claude/skills/frontend/accessibility-and-wcag/reference/charts-accessibility.yaml +357 -0
- package/.claude/skills/frontend/code-quality-and-typescript/SKILL.md +167 -0
- package/.claude/skills/frontend/design-system-and-components/SKILL.md +155 -0
- package/.claude/skills/frontend/design-system-and-components/SKILL.md.shadow.md +138 -0
- package/.claude/skills/frontend/design-system-and-components/reference/fonts.yaml +811 -0
- package/.claude/skills/frontend/design-system-and-components/reference/palettes.yaml +3066 -0
- package/.claude/skills/frontend/frontend-accessibility/SKILL.md +213 -0
- package/.claude/skills/frontend/frontend-data-layer/SKILL.md +310 -0
- package/.claude/skills/frontend/frontend-patterns/SKILL.md +771 -0
- package/.claude/skills/frontend/frontend-performance-optimization/SKILL.md +228 -0
- package/.claude/skills/frontend/frontend-performance-optimization/SKILL.md.shadow.md +213 -0
- package/.claude/skills/frontend/ux-and-user-journeys/SKILL.md +153 -0
- package/.claude/skills/frontend/ux-and-user-journeys/SKILL.md.shadow.md +138 -0
- package/.claude/skills/frontend/ux-and-user-journeys/reference/guidelines.yaml +997 -0
- package/.claude/squad-revocations.jsonl +5 -0
- package/.claude/task-chains.yaml +151 -0
- package/.claude/team.md +825 -0
- package/.claude/templates/squad-bundle/README.md +208 -0
- package/.claude/templates/squad-bundle/conftest.py +27 -0
- package/.claude/templates/squad-bundle/examples/template-example.md.template +94 -0
- package/.claude/templates/squad-bundle/pitfalls.yaml.template +88 -0
- package/.claude/templates/squad-bundle/task-chains.yaml.template +92 -0
- package/.claude/templates/squad-bundle/team-personas.md.template +161 -0
- package/.claude/trust/README.md +89 -0
- package/.claude/trust/owner.asc +11 -0
- package/.claude/workflows/README.md +124 -0
- package/.claude/workflows/audit-fanout.js +204 -0
- package/.claude/workflows/eval-baseline-n20.js +330 -0
- package/.claude/workflows/nightly-hygiene.js +176 -0
- package/LICENSE +21 -0
- package/PROTOCOL.md +597 -0
- package/README.md +167 -0
- package/SPEC/v1/README.md +181 -0
- package/SPEC/v1/adapters.schema.md +272 -0
- package/SPEC/v1/audit-log.schema.md +1514 -0
- package/SPEC/v1/audit-query.schema.md +152 -0
- package/SPEC/v1/benchmarks.schema.md +166 -0
- package/SPEC/v1/claude-sdk-compat.md +123 -0
- package/SPEC/v1/debate.schema.md +35 -0
- package/SPEC/v1/hook-io.schema.md +94 -0
- package/SPEC/v1/install-cli.md +234 -0
- package/SPEC/v1/judge-payload.schema.md +98 -0
- package/SPEC/v1/live-adapters-policy.schema.md +118 -0
- package/SPEC/v1/mcp-server.schema.md +558 -0
- package/SPEC/v1/memory-shared.schema.md +365 -0
- package/SPEC/v1/normalized_envelope.schema.md +183 -0
- package/SPEC/v1/npm-shim.md +95 -0
- package/SPEC/v1/plan.schema.md +34 -0
- package/SPEC/v1/policy-dsl.schema.md +466 -0
- package/SPEC/v1/predict-budget.schema.md +289 -0
- package/SPEC/v1/rag-sidecar.schema.md +222 -0
- package/SPEC/v1/red-team-corpus.schema.md +186 -0
- package/SPEC/v1/replay.schema.md +272 -0
- package/SPEC/v1/scratchpad.schema.md +172 -0
- package/SPEC/v1/sentinel-format.schema.md +306 -0
- package/SPEC/v1/session-graph.schema.md +236 -0
- package/SPEC/v1/skill-frontmatter.schema.md +83 -0
- package/SPEC/v1/skill-index.schema.md +197 -0
- package/SPEC/v1/skill-proposals.schema.md +175 -0
- package/SPEC/v1/soc2-control-map.schema.md +797 -0
- package/SPEC/v1/squad-manifest.schema.md +157 -0
- package/SPEC/v1/state-stores.schema.md +146 -0
- package/SPEC/v1/tier-policy.schema.md +264 -0
- package/SPEC/v1/tournament-report.schema.md +156 -0
- package/VERSION +1 -0
- package/bin/ceo-orch-init.js +55 -0
- package/package.json +42 -0
- package/scripts/_framework_manifest_set.sh +237 -0
- package/scripts/_hash_lib.sh +92 -0
- package/scripts/build-plugin.py +351 -0
- package/scripts/discover_foreign_context.py +151 -0
- package/scripts/install-accelerators.sh +166 -0
- package/scripts/install-npm.sh +254 -0
- package/scripts/install.sh +1932 -0
- package/scripts/local/OWNER-CEREMONY-PLAN-094-WAVE-A.sh +648 -0
- package/scripts/local/OWNER-CEREMONY-S82-V1120.sh +169 -0
- package/scripts/local/plan-093-apply-kernel-edits.py +496 -0
- package/scripts/local/plan-093-execute-ceremony.sh +118 -0
- package/scripts/local/plan-093-kernel-override-restart.sh +115 -0
- package/scripts/local/plan-093-ship-v1.26.0.sh +226 -0
- package/scripts/local/plan-094-apply-wave-a-c-e.py +398 -0
- package/scripts/local/smoke-install-parity.sh +168 -0
- package/scripts/local/trading-readonly-escape-hatch.sh +244 -0
- package/scripts/measure-repo-size.sh +98 -0
- package/scripts/npm-rebuild.sh +172 -0
- package/scripts/publish-plugin.sh +144 -0
- package/scripts/tests/smoke-install.sh +260 -0
- package/scripts/tests/test-install-sandbox-merge.sh +137 -0
- package/scripts/tests/test_install_baseline_manifest.sh +392 -0
- package/scripts/uninstall.sh +282 -0
- package/scripts/upgrade.sh +1260 -0
- package/templates/.claude/tier-policy.json +35 -0
- package/templates/.claude/tier-policy.json.sigchain +1 -0
- package/templates/.env.example +134 -0
- package/templates/.github/CODEOWNERS.template +33 -0
- package/templates/.github/workflows/benchmarks.yml.template +145 -0
- package/templates/.github/workflows/validate.yml.template +226 -0
- package/templates/.mcp.json +13 -0
- package/templates/CLAUDE.md +125 -0
- package/templates/MEMORY.md +36 -0
- package/templates/README.md +46 -0
- package/templates/compaction.md +130 -0
- package/templates/docs/BRANCH-PROTECTION.md +203 -0
- package/templates/docs/rotation-log.md +18 -0
- package/templates/oidc-proxy/README.md +141 -0
- package/templates/oidc-proxy/broker.config.example.json +29 -0
- package/templates/oidc-proxy/oidc_key_broker.py +361 -0
- package/templates/oidc-proxy/tests/test_oidc_key_broker.py +361 -0
- package/templates/scripts/statusline-ceo.py +597 -0
- package/templates/settings/settings.base.json +708 -0
- package/templates/settings/settings.stack.node.json +19 -0
- package/templates/settings/settings.stack.otel.json +25 -0
- package/templates/settings/settings.stack.sandbox.json +57 -0
- package/templates/settings/settings.user.json +265 -0
- package/templates/team-personas-reference.md +269 -0
|
@@ -0,0 +1,1483 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Governance Hook: parser-aware block of destructive Bash commands.
|
|
3
|
+
|
|
4
|
+
Registered in `.claude/settings.json` under `hooks.PreToolUse.Bash`.
|
|
5
|
+
Runs via the `_python-hook.sh` shim. Replaces 5 substring-matching
|
|
6
|
+
`Bash(...)` `if:` rules that bit us twice during Sprint 2 execution:
|
|
7
|
+
|
|
8
|
+
- `echo "git reset --hard"` inside a string → falsely blocked
|
|
9
|
+
- A compound command containing `rm -rf` inside quotes → falsely blocked
|
|
10
|
+
|
|
11
|
+
## Root cause of the old rules
|
|
12
|
+
|
|
13
|
+
Claude Code's `if: "Bash(rm -rf*)"` does substring/prefix matching on
|
|
14
|
+
the raw command string. It has no parser awareness: quoted strings
|
|
15
|
+
match, subcommands can't be targeted individually, and the rule language
|
|
16
|
+
has no way to express "only when the first token is `rm`".
|
|
17
|
+
|
|
18
|
+
## Fix: shlex-based parser
|
|
19
|
+
|
|
20
|
+
This hook:
|
|
21
|
+
|
|
22
|
+
1. Reads `tool_input.command` from the hook stdin JSON.
|
|
23
|
+
2. Splits the command on top-level shell control operators (`&&`, `||`,
|
|
24
|
+
`;`, `|`) via a naive regex. (The split over-splits inside quotes,
|
|
25
|
+
but `shlex.split` on each piece fails closed on unbalanced quotes
|
|
26
|
+
and the chunk is skipped — a safe failure mode.)
|
|
27
|
+
3. For each subcommand, uses `shlex.split()` to tokenize. Crucially,
|
|
28
|
+
shlex strips quoting BEFORE the rules see the tokens, so
|
|
29
|
+
`echo "rm -rf foo"` tokenizes to `['echo', 'rm -rf foo']` and the
|
|
30
|
+
first token is `echo`, not `rm`.
|
|
31
|
+
4. Applies three rules per subcommand:
|
|
32
|
+
- `rm` with both `-r` and `-f` (catches `-rf`, `-fr`, `-Rf`, `-r -f`)
|
|
33
|
+
- `git reset --hard` (exact first 3 tokens)
|
|
34
|
+
- `git push --force` or `git push -f` — but NOT `--force-with-lease`
|
|
35
|
+
5. Any match → block with a concrete remediation.
|
|
36
|
+
6. Any error → fail-open (allow), log breadcrumb to stderr.
|
|
37
|
+
|
|
38
|
+
## Output contract
|
|
39
|
+
|
|
40
|
+
Writes a single-line JSON decision to stdout:
|
|
41
|
+
|
|
42
|
+
{} # allow
|
|
43
|
+
{"decision":"block","reason":"BLOCKED: ..."}
|
|
44
|
+
|
|
45
|
+
PLAN-135 W2 H5 adds a THIRD shape — a corrective `updatedInput` rewrite
|
|
46
|
+
for the `git push --force`/`-f` pilot pattern (single subcommand only):
|
|
47
|
+
|
|
48
|
+
{"hookSpecificOutput":{"hookEventName":"PreToolUse",
|
|
49
|
+
"permissionDecision":"ask",
|
|
50
|
+
"permissionDecisionReason":"REWRITTEN ... --force-with-lease ...",
|
|
51
|
+
"updatedInput":{"command":"git push --force-with-lease"}}}
|
|
52
|
+
|
|
53
|
+
The rewrite NEVER degrades a BLOCK into a silent allow: it always emits
|
|
54
|
+
`ask` (the permission prompt is retained, constraint (b)), and any
|
|
55
|
+
ambiguity / compound command falls back to the legacy BLOCK
|
|
56
|
+
(constraint (a)). Exit code is 0 in every case — Claude Code reads the
|
|
57
|
+
decision from stdout, not the exit code.
|
|
58
|
+
"""
|
|
59
|
+
|
|
60
|
+
from __future__ import annotations
|
|
61
|
+
|
|
62
|
+
import hashlib
|
|
63
|
+
import json
|
|
64
|
+
import re
|
|
65
|
+
import shlex
|
|
66
|
+
import sys
|
|
67
|
+
from dataclasses import dataclass, field
|
|
68
|
+
from pathlib import Path
|
|
69
|
+
from typing import Dict, List, Optional
|
|
70
|
+
|
|
71
|
+
# ---------------------------------------------------------------------------
|
|
72
|
+
# PLAN-019 P0-01 / P0-02 — destructive-command bypass hardening
|
|
73
|
+
# ---------------------------------------------------------------------------
|
|
74
|
+
#
|
|
75
|
+
# Two coordinated fixes to the destructive-command matchers below:
|
|
76
|
+
#
|
|
77
|
+
# P0-01: recognize long-option spellings of destructive flags.
|
|
78
|
+
# Old: `rm --recursive --force dir` ALLOWED (flag-char scan skipped
|
|
79
|
+
# any token starting with "--").
|
|
80
|
+
# New: long options `--recursive`, `-r`, `--force` (and `--x=value`
|
|
81
|
+
# forms) are parsed with exact-name matching.
|
|
82
|
+
#
|
|
83
|
+
# P0-02: strip privilege-escalation prefixes and absolute/escaped paths
|
|
84
|
+
# before the literal-equality check on ``tokens[0]``.
|
|
85
|
+
# Old: `sudo rm -rf /`, `/bin/rm -rf /`, and `\rm -rf /` all ALLOWED
|
|
86
|
+
# because ``tokens[0] != "rm"`` in each case.
|
|
87
|
+
# New: we normalize ``tokens`` via :func:`_normalize_command_tokens`
|
|
88
|
+
# so each matcher sees the effective command basename.
|
|
89
|
+
#
|
|
90
|
+
# These live in this file (not _lib) because they're intimately tied to
|
|
91
|
+
# the Bash-safety policy: adopters should never grep _lib for
|
|
92
|
+
# "destructive".
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
_PRIVILEGE_PREFIXES = frozenset({"sudo", "doas", "nocorrect"})
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def _normalize_command_tokens(tokens: List[str]) -> List[str]:
|
|
99
|
+
"""Strip privilege-escalation prefixes + normalize the command token.
|
|
100
|
+
|
|
101
|
+
Behavior (see P0-02 above):
|
|
102
|
+
|
|
103
|
+
- Drops leading ``sudo`` / ``doas`` / ``nocorrect`` tokens AND the
|
|
104
|
+
flags that belong to them (``-u USER``, ``--user=USER``, ``-i``,
|
|
105
|
+
``-s``, ``-k``, ``-n``, ``-E``, etc.). Heuristic: after the prefix,
|
|
106
|
+
any token starting with ``-`` is consumed as a prefix-flag; a known
|
|
107
|
+
value-taking flag (``-u`` / ``--user``) additionally consumes the
|
|
108
|
+
following non-flag token as its argument.
|
|
109
|
+
- Replaces ``tokens[0]`` with its basename (``/bin/rm`` → ``rm``,
|
|
110
|
+
``./rm`` → ``rm``) after stripping a single leading backslash
|
|
111
|
+
(shell alias-escape: ``\\rm`` → ``rm``).
|
|
112
|
+
|
|
113
|
+
Returns a NEW list; never mutates ``tokens``. Empty input returns
|
|
114
|
+
the input unchanged. Pure function (no I/O).
|
|
115
|
+
|
|
116
|
+
Examples
|
|
117
|
+
--------
|
|
118
|
+
>>> _normalize_command_tokens(["sudo", "rm", "-rf", "/"])
|
|
119
|
+
['rm', '-rf', '/']
|
|
120
|
+
>>> _normalize_command_tokens(["/bin/rm", "-rf", "/tmp"])
|
|
121
|
+
['rm', '-rf', '/tmp']
|
|
122
|
+
>>> _normalize_command_tokens(["\\\\rm", "-rf", "/tmp"])
|
|
123
|
+
['rm', '-rf', '/tmp']
|
|
124
|
+
>>> _normalize_command_tokens(["sudo", "-u", "root", "rm", "-rf", "/"])
|
|
125
|
+
['rm', '-rf', '/']
|
|
126
|
+
>>> _normalize_command_tokens(["doas", "rm", "-rf", "/"])
|
|
127
|
+
['rm', '-rf', '/']
|
|
128
|
+
>>> _normalize_command_tokens([])
|
|
129
|
+
[]
|
|
130
|
+
"""
|
|
131
|
+
if not tokens:
|
|
132
|
+
return tokens
|
|
133
|
+
working = list(tokens)
|
|
134
|
+
# Drop leading privilege prefixes (sudo/doas/nocorrect) and any flags
|
|
135
|
+
# that belong to them.
|
|
136
|
+
while working and working[0] in _PRIVILEGE_PREFIXES:
|
|
137
|
+
working.pop(0)
|
|
138
|
+
# Consume prefix-owned flags: any -flag until we hit a non-flag
|
|
139
|
+
# or run out. For value-taking flags (-u USER / --user=USER),
|
|
140
|
+
# also pop the following non-flag value token.
|
|
141
|
+
while working and working[0].startswith("-"):
|
|
142
|
+
flag = working.pop(0)
|
|
143
|
+
if (flag in ("-u", "--user")
|
|
144
|
+
and working
|
|
145
|
+
and not working[0].startswith("-")):
|
|
146
|
+
working.pop(0) # consume USER arg
|
|
147
|
+
if not working:
|
|
148
|
+
return working
|
|
149
|
+
first = working[0]
|
|
150
|
+
# Strip leading backslash (alias-escape: ``\rm`` ≡ ``rm``).
|
|
151
|
+
if first.startswith("\\"):
|
|
152
|
+
first = first.lstrip("\\")
|
|
153
|
+
# Basename ("/bin/rm" → "rm", "./rm" → "rm"). Path.name is empty for
|
|
154
|
+
# pure-slash strings; fall back to the pre-basename value so a weird
|
|
155
|
+
# path like "/" doesn't crash downstream matchers.
|
|
156
|
+
basename = Path(first).name if first else first
|
|
157
|
+
working[0] = basename or first
|
|
158
|
+
return working
|
|
159
|
+
|
|
160
|
+
# Make the _lib package importable — hooks live in .claude/hooks/ and
|
|
161
|
+
# _lib is a sibling package.
|
|
162
|
+
_HOOKS_DIR = Path(__file__).resolve().parent
|
|
163
|
+
if str(_HOOKS_DIR) not in sys.path:
|
|
164
|
+
sys.path.insert(0, str(_HOOKS_DIR))
|
|
165
|
+
|
|
166
|
+
from _lib import contract as _contract # noqa: E402
|
|
167
|
+
from _lib import credentials as _credentials # noqa: E402
|
|
168
|
+
from _lib import git_bypass as _git_bypass # noqa: E402
|
|
169
|
+
from _lib.adapters import claude as _claude_adapter # noqa: E402
|
|
170
|
+
|
|
171
|
+
try: # noqa: E402
|
|
172
|
+
from _lib import audit_emit as _audit_emit # noqa: E402
|
|
173
|
+
except Exception: # pragma: no cover
|
|
174
|
+
_audit_emit = None # type: ignore
|
|
175
|
+
|
|
176
|
+
try: # noqa: E402
|
|
177
|
+
from _lib import trusted_env as _trusted_env # noqa: E402
|
|
178
|
+
except Exception: # pragma: no cover
|
|
179
|
+
_trusted_env = None # type: ignore
|
|
180
|
+
|
|
181
|
+
try: # noqa: E402
|
|
182
|
+
from _lib import env_guard as _env_guard # noqa: E402
|
|
183
|
+
except Exception: # pragma: no cover
|
|
184
|
+
_env_guard = None # type: ignore
|
|
185
|
+
|
|
186
|
+
try: # noqa: E402
|
|
187
|
+
from _lib import egress_taxonomy as _egress_taxonomy # noqa: E402
|
|
188
|
+
except Exception: # pragma: no cover
|
|
189
|
+
_egress_taxonomy = None # type: ignore
|
|
190
|
+
|
|
191
|
+
# PLAN-124 WS-1 — git hook-bypass guard dual-auth escape hatch (MF-E).
|
|
192
|
+
# Reuses the proven canonical-edit dual-auth pattern
|
|
193
|
+
# (check_canonical_edit.py:701-705, ADR-040-AMEND-2 §Layer-1): a non-empty
|
|
194
|
+
# reason/ticket env var + the literal `_ACK == "I-ACCEPT"` + a ticket regex.
|
|
195
|
+
# CRITICAL: both vars are read from the IMPORT-TIME trusted_env snapshot
|
|
196
|
+
# (`_lib.trusted_env.get_trusted`), NEVER live os.environ, so a late-set
|
|
197
|
+
# (post-anchor) value injected by a sub-agent / subprocess cannot grant the
|
|
198
|
+
# bypass. Both names begin with `CEO_` so they are captured by the snapshot.
|
|
199
|
+
_GIT_BYPASS_ALLOW_VAR = "CEO_GIT_BYPASS_ALLOW"
|
|
200
|
+
_GIT_BYPASS_ALLOW_ACK_VAR = "CEO_GIT_BYPASS_ALLOW_ACK"
|
|
201
|
+
_GIT_BYPASS_TICKET_RE = re.compile(
|
|
202
|
+
r"^(ADR-\d{3,4}|PLAN-\d{3})-[a-z0-9-]{3,100}$"
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
# Split on top-level &&, ||, ;, | — shell control operators.
|
|
207
|
+
# NOTE: this is a NAIVE split that ignores quoting. A command like
|
|
208
|
+
# `echo "a && b"` will be over-split into `echo "a` and `b"`, both of
|
|
209
|
+
# which fail to tokenize cleanly under shlex → skipped. Fail-safe.
|
|
210
|
+
_SUBCOMMAND_SPLIT_RE = re.compile(r"\s*(?:&&|\|\||[;|])\s*")
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
@dataclass
|
|
214
|
+
class Rewrite:
|
|
215
|
+
"""A corrective `updatedInput` rewrite (PLAN-135 W2 H5).
|
|
216
|
+
|
|
217
|
+
Carries the new command string + the before/after sha256 hashes used
|
|
218
|
+
for the audit event (`bash_input_rewritten`) and a closed-enum
|
|
219
|
+
`rewrite_class`. Built ONLY by :func:`_rewrite_git_push_force` and
|
|
220
|
+
ONLY for the single-subcommand `git push --force`/`-f` pilot pattern.
|
|
221
|
+
The single-rewriter invariant (mini-ADR-154) is structural here: at
|
|
222
|
+
most ONE Rewrite is ever attached to a Decision, and the hook never
|
|
223
|
+
chains a second rewrite within the same tool-call.
|
|
224
|
+
"""
|
|
225
|
+
|
|
226
|
+
new_command: str
|
|
227
|
+
before_sha256: str
|
|
228
|
+
after_sha256: str
|
|
229
|
+
rewrite_class: str # closed enum (audit) — only "git_push_force_to_lease"
|
|
230
|
+
reason: str # human-readable; NAMES the rewrite for the permission prompt
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
@dataclass
|
|
234
|
+
class Decision:
|
|
235
|
+
"""Typed result of the safety check.
|
|
236
|
+
|
|
237
|
+
A Decision is one of three shapes:
|
|
238
|
+
* allow (allow=True, rewrite=None) → empty `{}`
|
|
239
|
+
* block (allow=False, reason=...) → block JSON
|
|
240
|
+
* rewrite-ask (allow=True, rewrite=Rewrite(...)) → permissionDecision
|
|
241
|
+
`ask` + `updatedInput` (constraint (b): the rewritten command STILL
|
|
242
|
+
goes through the permission prompt; the prompt text NAMES the
|
|
243
|
+
rewrite). The rewrite-ask shape is materialized in `main()` (it
|
|
244
|
+
needs the adapter vendor channel), NOT in `to_json()`.
|
|
245
|
+
"""
|
|
246
|
+
|
|
247
|
+
allow: bool
|
|
248
|
+
reason: Optional[str] = None
|
|
249
|
+
rewrite: Optional["Rewrite"] = None
|
|
250
|
+
|
|
251
|
+
def to_json(self) -> str:
|
|
252
|
+
# Allow: emit empty JSON object — Claude Code hook schema rejects
|
|
253
|
+
# top-level {"decision":"allow"} (enum is "approve"|"block"; "allow"
|
|
254
|
+
# is only valid inside hookSpecificOutput.permissionDecision).
|
|
255
|
+
# NOTE: to_json() is the BLOCK/ALLOW serializer only; the rewrite-ask
|
|
256
|
+
# shape (updatedInput) is emitted by main() via the adapter `extra`
|
|
257
|
+
# channel and never round-trips through here.
|
|
258
|
+
if self.allow:
|
|
259
|
+
return json.dumps({}, ensure_ascii=False)
|
|
260
|
+
return json.dumps(
|
|
261
|
+
{"decision": "block", "reason": self.reason or ""},
|
|
262
|
+
ensure_ascii=False,
|
|
263
|
+
)
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
def _split_subcommands(command: str) -> List[str]:
|
|
267
|
+
"""Split on &&, ||, ;, |. Empty/whitespace chunks are dropped."""
|
|
268
|
+
if not command or not command.strip():
|
|
269
|
+
return []
|
|
270
|
+
parts = _SUBCOMMAND_SPLIT_RE.split(command)
|
|
271
|
+
return [p for p in (s.strip() for s in parts) if p]
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
def _tokenize(subcommand: str) -> List[str]:
|
|
275
|
+
"""shlex.split with fail-safe: returns [] on parse error.
|
|
276
|
+
|
|
277
|
+
Unbalanced quotes, etc. produce an empty token list so the caller
|
|
278
|
+
skips the chunk — fail-safe, not fail-open, because a chunk we
|
|
279
|
+
cannot parse also cannot match a block rule.
|
|
280
|
+
"""
|
|
281
|
+
try:
|
|
282
|
+
return shlex.split(subcommand)
|
|
283
|
+
except ValueError:
|
|
284
|
+
return []
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
def _check_rm_rf(tokens: List[str]) -> Optional[str]:
|
|
288
|
+
"""Return a block reason if tokens match `rm` with -r AND -f.
|
|
289
|
+
|
|
290
|
+
Post PLAN-019 P0-01 + P0-02:
|
|
291
|
+
|
|
292
|
+
- Privilege prefixes (``sudo``/``doas``/``nocorrect``) + their flags
|
|
293
|
+
are stripped via :func:`_normalize_command_tokens`.
|
|
294
|
+
- Absolute-path invocations (``/bin/rm``) and escaped-alias
|
|
295
|
+
invocations (``\\rm``) are normalized to ``rm`` by the same helper.
|
|
296
|
+
- Long options ``--recursive``, ``-r`` (alias), ``--force`` and their
|
|
297
|
+
``=value`` forms are detected alongside the original short-form
|
|
298
|
+
character scan (``-rf``, ``-fr``, ``-Rf``, etc.).
|
|
299
|
+
"""
|
|
300
|
+
tokens = _normalize_command_tokens(tokens)
|
|
301
|
+
if not tokens or tokens[0] != "rm":
|
|
302
|
+
return None
|
|
303
|
+
has_r = False
|
|
304
|
+
has_f = False
|
|
305
|
+
for t in tokens[1:]:
|
|
306
|
+
if not t.startswith("-"):
|
|
307
|
+
continue # positional argument
|
|
308
|
+
if t.startswith("--"):
|
|
309
|
+
# Long option: match exact names (+ optional =value tail).
|
|
310
|
+
# The ``=value`` form on ``--recursive``/``--force`` is NON-
|
|
311
|
+
# STANDARD for POSIX ``rm`` (which treats both as boolean
|
|
312
|
+
# flags). Security-first interpretation: if someone types
|
|
313
|
+
# ``--recursive=<value>`` they are almost certainly probing
|
|
314
|
+
# the parser; treat the equals-form on destructive flags as
|
|
315
|
+
# implying BOTH ``-r`` and ``-f`` (defensive fail-closed).
|
|
316
|
+
# See PLAN-019 P0-01 live-verification vector
|
|
317
|
+
# ``rm --recursive=true /tmp``.
|
|
318
|
+
has_eq = "=" in t
|
|
319
|
+
name = t[2:].split("=", 1)[0].lower()
|
|
320
|
+
if name in ("recursive", "r"):
|
|
321
|
+
has_r = True
|
|
322
|
+
if has_eq:
|
|
323
|
+
has_f = True
|
|
324
|
+
elif name == "force":
|
|
325
|
+
has_f = True
|
|
326
|
+
if has_eq:
|
|
327
|
+
has_r = True
|
|
328
|
+
if has_r and has_f:
|
|
329
|
+
break
|
|
330
|
+
continue
|
|
331
|
+
body = t[1:] # strip single leading dash
|
|
332
|
+
# Case-insensitive match catches -Rf, -rF, etc.
|
|
333
|
+
lowered = body.lower()
|
|
334
|
+
if "r" in lowered:
|
|
335
|
+
has_r = True
|
|
336
|
+
if "f" in lowered:
|
|
337
|
+
has_f = True
|
|
338
|
+
if has_r and has_f:
|
|
339
|
+
break
|
|
340
|
+
if has_r and has_f:
|
|
341
|
+
return (
|
|
342
|
+
"BLOCKED: `rm` with -r and -f is destructive. "
|
|
343
|
+
"Specify exact files (`rm <file>` without -r), use trash-cli, "
|
|
344
|
+
"or run the command outside Claude Code if you really mean it."
|
|
345
|
+
)
|
|
346
|
+
return None
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
def _check_git_reset_hard(tokens: List[str]) -> Optional[str]:
|
|
350
|
+
"""Return a block reason if tokens start with `git reset --hard`.
|
|
351
|
+
|
|
352
|
+
Post PLAN-019 P0-02: tokens are normalized (``sudo git …``,
|
|
353
|
+
``/usr/bin/git …``, ``\\git …`` all reach the same decision).
|
|
354
|
+
"""
|
|
355
|
+
tokens = _normalize_command_tokens(tokens)
|
|
356
|
+
if (
|
|
357
|
+
len(tokens) >= 3
|
|
358
|
+
and tokens[0] == "git"
|
|
359
|
+
and tokens[1] == "reset"
|
|
360
|
+
and tokens[2] == "--hard"
|
|
361
|
+
):
|
|
362
|
+
return (
|
|
363
|
+
"BLOCKED: `git reset --hard` is destructive. "
|
|
364
|
+
"Use `git stash` to save uncommitted changes, or "
|
|
365
|
+
"`git checkout <file>` to discard specific files."
|
|
366
|
+
)
|
|
367
|
+
return None
|
|
368
|
+
|
|
369
|
+
|
|
370
|
+
def _check_git_push_force(tokens: List[str]) -> Optional[str]:
|
|
371
|
+
"""Return a block reason if tokens are a `git push --force` / `-f`.
|
|
372
|
+
|
|
373
|
+
Does NOT block `--force-with-lease`, which is the safe alternative.
|
|
374
|
+
|
|
375
|
+
Post PLAN-019 P0-02: tokens are normalized (``sudo git …``,
|
|
376
|
+
``/usr/bin/git …``, ``\\git …`` all reach the same decision).
|
|
377
|
+
"""
|
|
378
|
+
tokens = _normalize_command_tokens(tokens)
|
|
379
|
+
if len(tokens) < 3 or tokens[0] != "git" or tokens[1] != "push":
|
|
380
|
+
return None
|
|
381
|
+
for t in tokens[2:]:
|
|
382
|
+
if t == "--force" or t == "-f":
|
|
383
|
+
return (
|
|
384
|
+
"BLOCKED: `git push --force` is destructive. "
|
|
385
|
+
"Use `git push --force-with-lease` to avoid overwriting "
|
|
386
|
+
"unseen commits pushed by others."
|
|
387
|
+
)
|
|
388
|
+
return None
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
# ---------------------------------------------------------------------------
|
|
392
|
+
# PLAN-135 W2 H5 — corrective `updatedInput` rewrite (mini-ADR-154)
|
|
393
|
+
# ---------------------------------------------------------------------------
|
|
394
|
+
#
|
|
395
|
+
# PILOT: exactly ONE pattern — a single-subcommand `git push --force`/`-f`
|
|
396
|
+
# is REWRITTEN to `git push --force-with-lease` and surfaced as a
|
|
397
|
+
# permission-prompt (`ask`) carrying the new command via `updatedInput`,
|
|
398
|
+
# instead of a hard BLOCK. Constraints (NORMATIVE, debate R1 security
|
|
399
|
+
# must-fix; THREAT-MODEL-WORKSHEET §1; Doctrine 1 corollary):
|
|
400
|
+
#
|
|
401
|
+
# (a) FAILURE MODE IS BLOCK. The rewrite must NEVER pass the original
|
|
402
|
+
# `--force` input through on a half-applied / ambiguous rewrite. If
|
|
403
|
+
# reconstruction is anything but trivially safe (compound command,
|
|
404
|
+
# both flags present, an unparseable chunk, a token that does not
|
|
405
|
+
# round-trip), `_rewrite_git_push_force` returns None and the caller
|
|
406
|
+
# falls back to the existing BLOCK. (`fail-open §5` covers
|
|
407
|
+
# hook-INFRA crashes — NOT rewrite errors.)
|
|
408
|
+
# (b) STILL ASKS. The rewritten command goes through the permission
|
|
409
|
+
# prompt (`permissionDecision: "ask"`), never a silent allow — a
|
|
410
|
+
# bare `--force-with-lease` after a `git fetch` is ≈ a force-push,
|
|
411
|
+
# so a human stays in the loop. `permissionDecisionReason` NAMES the
|
|
412
|
+
# rewrite.
|
|
413
|
+
# (c) TOKEN-LEVEL. The rewrite operates on the SAME normalized token
|
|
414
|
+
# list the detector uses (`_normalize_command_tokens`), never a
|
|
415
|
+
# string-level `.replace()` against the raw command (that is an
|
|
416
|
+
# injection seam — `echo "--force" && git push -f` would mis-rewrite
|
|
417
|
+
# the echo'd literal). The new command is reassembled from tokens
|
|
418
|
+
# via `shlex.quote`, so quoting is re-applied safely.
|
|
419
|
+
#
|
|
420
|
+
# The single-rewriter invariant (mini-ADR-154 §1): at most ONE rewriting
|
|
421
|
+
# hook per tool-call; this is the only one. Downstream hooks (and the
|
|
422
|
+
# audit log) see the POST-rewrite input. A before/after sha256 hash PAIR
|
|
423
|
+
# is recorded in the `bash_input_rewritten` audit event so the audited
|
|
424
|
+
# command provably equals the executed command.
|
|
425
|
+
#
|
|
426
|
+
# Opt-in flag: CEO_BASH_FORCE_PUSH_REWRITE=1 ENABLES the rewrite. PILOT,
|
|
427
|
+
# DEFAULT-OFF (W2 H5 — until its ceremony + Codex round close): the legacy
|
|
428
|
+
# force-push BLOCK stays the shipped behavior, so the existing byte-identity
|
|
429
|
+
# fixture corpus is unchanged. Read from the import-time trusted_env snapshot
|
|
430
|
+
# (NOT live os.environ) so a late-set value cannot toggle the rewriter mid-op.
|
|
431
|
+
|
|
432
|
+
_FORCE_PUSH_REWRITE_DISABLE_VAR = "CEO_BASH_FORCE_PUSH_REWRITE"
|
|
433
|
+
_FORCE_PUSH_REWRITE_CLASS = "git_push_force_to_lease"
|
|
434
|
+
|
|
435
|
+
|
|
436
|
+
def _force_push_rewrite_enabled() -> bool:
|
|
437
|
+
"""True iff the H5 force-push→lease rewrite is enabled (PILOT, default-OFF).
|
|
438
|
+
|
|
439
|
+
Enabled ONLY when CEO_BASH_FORCE_PUSH_REWRITE == "1" in the import-time
|
|
440
|
+
trusted_env snapshot (NOT live os.environ — a late-set value cannot toggle
|
|
441
|
+
the rewriter mid-op). Default-OFF restores the legacy force-push BLOCK as
|
|
442
|
+
the shipped behavior (existing byte-identity fixtures unchanged); the
|
|
443
|
+
rewrite is an opt-in pilot. When the snapshot is unavailable the rewrite
|
|
444
|
+
stays DISABLED (fail to the legacy BLOCK — the most conservative state).
|
|
445
|
+
Pure; never raises.
|
|
446
|
+
"""
|
|
447
|
+
if _trusted_env is None: # pragma: no cover — import failure → default-OFF (block)
|
|
448
|
+
return False
|
|
449
|
+
try:
|
|
450
|
+
raw = _trusted_env.get_trusted(_FORCE_PUSH_REWRITE_DISABLE_VAR)
|
|
451
|
+
except Exception: # pragma: no cover
|
|
452
|
+
return False
|
|
453
|
+
if raw is None:
|
|
454
|
+
return False
|
|
455
|
+
return str(raw).strip() == "1"
|
|
456
|
+
|
|
457
|
+
|
|
458
|
+
def _sha256_hex(text: str) -> str:
|
|
459
|
+
"""sha256 hex digest of ``text`` (utf-8). Pure; never raises."""
|
|
460
|
+
return hashlib.sha256(text.encode("utf-8", "surrogatepass")).hexdigest()
|
|
461
|
+
|
|
462
|
+
|
|
463
|
+
def _rewrite_git_push_force(command: str) -> Optional[Rewrite]:
|
|
464
|
+
"""Build a `git push --force-with-lease` rewrite, or None to fall back.
|
|
465
|
+
|
|
466
|
+
Returns a :class:`Rewrite` ONLY for the pilot pattern — a command that
|
|
467
|
+
is a SINGLE subcommand (no `&&`/`||`/`;`/`|`), whose normalized tokens
|
|
468
|
+
are exactly ``git push ...`` carrying ``--force``/``-f`` (and NOT
|
|
469
|
+
already ``--force-with-lease``). Anything else → None (caller BLOCKs;
|
|
470
|
+
constraint (a)). The new command is rebuilt token-by-token from the
|
|
471
|
+
normalized list and re-quoted with ``shlex.quote`` (constraint (c)),
|
|
472
|
+
so a quoted/embedded ``--force`` literal in a different argv position
|
|
473
|
+
can never be rewritten.
|
|
474
|
+
|
|
475
|
+
Pure function (no I/O). The before/after hashes let the audit event
|
|
476
|
+
prove audited-cmd == executed-cmd (mini-ADR-154 §2).
|
|
477
|
+
"""
|
|
478
|
+
if not command or not command.strip():
|
|
479
|
+
return None
|
|
480
|
+
# Constraint (a)+(c): a COMPOUND command (multiple subcommands) is NOT
|
|
481
|
+
# rewritten — reassembling a multi-subcommand line from a flat token
|
|
482
|
+
# view is exactly the injection seam THREAT-MODEL-WORKSHEET §1 names
|
|
483
|
+
# (`echo "--force" && git push -f`). Fall back to BLOCK.
|
|
484
|
+
subcommands = _split_subcommands(command)
|
|
485
|
+
if len(subcommands) != 1:
|
|
486
|
+
return None
|
|
487
|
+
raw_tokens = _tokenize(subcommands[0])
|
|
488
|
+
if not raw_tokens:
|
|
489
|
+
return None # unparseable → BLOCK (fail-safe)
|
|
490
|
+
tokens = _normalize_command_tokens(raw_tokens)
|
|
491
|
+
if len(tokens) < 3 or tokens[0] != "git" or tokens[1] != "push":
|
|
492
|
+
return None
|
|
493
|
+
# The token-list view is the SAME the detector saw. Rewrite EXACTLY the
|
|
494
|
+
# destructive flag tokens; leave every other token byte-for-byte. If a
|
|
495
|
+
# `--force-with-lease` is already present we do not touch it.
|
|
496
|
+
has_force_flag = False
|
|
497
|
+
new_tokens: List[str] = []
|
|
498
|
+
for t in tokens:
|
|
499
|
+
if t == "--force" or t == "-f":
|
|
500
|
+
has_force_flag = True
|
|
501
|
+
new_tokens.append("--force-with-lease")
|
|
502
|
+
else:
|
|
503
|
+
new_tokens.append(t)
|
|
504
|
+
if not has_force_flag:
|
|
505
|
+
return None # nothing to rewrite (e.g. already --force-with-lease)
|
|
506
|
+
# Reassemble with shlex.quote so the rewrite is shell-safe (constraint
|
|
507
|
+
# (c) — re-quoting closes the round-trip seam). The normalization
|
|
508
|
+
# already basenamed token[0] and stripped any sudo/escape prefix, which
|
|
509
|
+
# is the SAME effective command the rail audited and the user intended;
|
|
510
|
+
# the pilot deliberately does not try to preserve a `/usr/bin/git`
|
|
511
|
+
# absolute path (it would re-open the path-normalization question).
|
|
512
|
+
new_command = " ".join(shlex.quote(tok) for tok in new_tokens)
|
|
513
|
+
before = _sha256_hex(command)
|
|
514
|
+
after = _sha256_hex(new_command)
|
|
515
|
+
# Defense-in-depth: if the rewrite somehow did not change the command
|
|
516
|
+
# (impossible given has_force_flag, but the audit invariant must hold),
|
|
517
|
+
# fall back to BLOCK rather than emit a no-op `ask` (constraint (a)).
|
|
518
|
+
if after == before or new_command == command: # pragma: no cover
|
|
519
|
+
return None
|
|
520
|
+
reason = (
|
|
521
|
+
"REWRITTEN (asks before running): `git push --force` → "
|
|
522
|
+
"`git push --force-with-lease`. The original `--force` overwrites "
|
|
523
|
+
"remote commits unconditionally; `--force-with-lease` refuses if "
|
|
524
|
+
"the remote advanced since your last fetch. Review the rewritten "
|
|
525
|
+
"command and approve to proceed, or reject to cancel. "
|
|
526
|
+
f"Rewritten command: {new_command}"
|
|
527
|
+
)
|
|
528
|
+
return Rewrite(
|
|
529
|
+
new_command=new_command,
|
|
530
|
+
before_sha256=before,
|
|
531
|
+
after_sha256=after,
|
|
532
|
+
rewrite_class=_FORCE_PUSH_REWRITE_CLASS,
|
|
533
|
+
reason=reason,
|
|
534
|
+
)
|
|
535
|
+
|
|
536
|
+
|
|
537
|
+
def _git_bypass_escape_hatch_active() -> bool:
|
|
538
|
+
"""True iff the proven dual-auth git-bypass escape hatch is set (MF-E).
|
|
539
|
+
|
|
540
|
+
Reads BOTH env vars from the import-time trusted_env snapshot (NOT live
|
|
541
|
+
os.environ): a value set AFTER process trust-anchor is ignored. Requires:
|
|
542
|
+
|
|
543
|
+
- ``CEO_GIT_BYPASS_ALLOW`` — non-empty, matches the ticket regex
|
|
544
|
+
(``ADR-NNN[N]-slug`` | ``PLAN-NNN-slug``)
|
|
545
|
+
- ``CEO_GIT_BYPASS_ALLOW_ACK`` — exactly ``I-ACCEPT``
|
|
546
|
+
|
|
547
|
+
Off-path (missing / wrong ACK / bad ticket) → False → the bypass stays
|
|
548
|
+
BLOCKED. Pure function (snapshot read only); never raises.
|
|
549
|
+
"""
|
|
550
|
+
if _trusted_env is None: # pragma: no cover — import failure fail-CLOSED
|
|
551
|
+
return False
|
|
552
|
+
try:
|
|
553
|
+
reason = (_trusted_env.get_trusted(_GIT_BYPASS_ALLOW_VAR) or "").strip()
|
|
554
|
+
ack = (_trusted_env.get_trusted(_GIT_BYPASS_ALLOW_ACK_VAR) or "").strip()
|
|
555
|
+
except Exception: # pragma: no cover
|
|
556
|
+
return False
|
|
557
|
+
return bool(
|
|
558
|
+
reason
|
|
559
|
+
and ack == "I-ACCEPT"
|
|
560
|
+
and _GIT_BYPASS_TICKET_RE.match(reason)
|
|
561
|
+
)
|
|
562
|
+
|
|
563
|
+
|
|
564
|
+
def _env_guard_enforced() -> bool:
|
|
565
|
+
"""True iff CEO_ENV_GUARD_ENFORCE=='1' in the import-time trusted_env snapshot.
|
|
566
|
+
|
|
567
|
+
Default-OFF (PLAN-133 A1 doctrine #1): when unset/anything-but-"1" the
|
|
568
|
+
env-hijack scan is advisory (emit, do NOT block). Read from the snapshot
|
|
569
|
+
(NOT live os.environ) so a late-set value can't toggle enforcement mid-op.
|
|
570
|
+
Pure; never raises.
|
|
571
|
+
"""
|
|
572
|
+
if _trusted_env is None or _env_guard is None: # pragma: no cover
|
|
573
|
+
return False
|
|
574
|
+
try:
|
|
575
|
+
return (
|
|
576
|
+
_trusted_env.get_trusted(_env_guard.ENV_GUARD_ENFORCE_FLAG) or ""
|
|
577
|
+
).strip() == "1"
|
|
578
|
+
except Exception: # pragma: no cover
|
|
579
|
+
return False
|
|
580
|
+
|
|
581
|
+
|
|
582
|
+
def _check_env_hijack(command: str) -> "Optional[tuple]":
|
|
583
|
+
"""Scan for a denylisted env-var SET (PLAN-133 A1).
|
|
584
|
+
|
|
585
|
+
Returns ``(hijack_class, key, reason)`` on a match, else ``None``. Pure;
|
|
586
|
+
fail-OPEN on infra (a scan exception → None, no block, no emit) per the hook
|
|
587
|
+
contract. The block/allow decision (default-OFF) is the caller's; this returns
|
|
588
|
+
the match so both the emit and the decision can use it.
|
|
589
|
+
"""
|
|
590
|
+
if _env_guard is None:
|
|
591
|
+
return None
|
|
592
|
+
try:
|
|
593
|
+
m = _env_guard.scan_command(command)
|
|
594
|
+
except Exception as e: # pragma: no cover — fail-OPEN on infra
|
|
595
|
+
print(
|
|
596
|
+
f"[check_bash_safety] env-hijack scan failure; failing OPEN: "
|
|
597
|
+
f"{e.__class__.__name__}",
|
|
598
|
+
file=sys.stderr,
|
|
599
|
+
)
|
|
600
|
+
return None
|
|
601
|
+
if m is None:
|
|
602
|
+
return None
|
|
603
|
+
return (m.hijack_class, m.key, m.reason)
|
|
604
|
+
|
|
605
|
+
|
|
606
|
+
def _egress_emit_enabled() -> bool:
|
|
607
|
+
"""True iff CEO_EGRESS_TAXONOMY_EMIT=='1' in the trusted_env snapshot.
|
|
608
|
+
|
|
609
|
+
Default-OFF (PLAN-133 A3 doctrine #1): the egress breadcrumb is suppressed
|
|
610
|
+
during the measure-first window unless the flag is set. Read from the
|
|
611
|
+
import-time snapshot (NOT live os.environ). A3 NEVER blocks regardless of this
|
|
612
|
+
flag — it only gates the advisory emit. Pure; never raises.
|
|
613
|
+
"""
|
|
614
|
+
if _trusted_env is None or _egress_taxonomy is None: # pragma: no cover
|
|
615
|
+
return False
|
|
616
|
+
try:
|
|
617
|
+
return (
|
|
618
|
+
_trusted_env.get_trusted(
|
|
619
|
+
_egress_taxonomy.EGRESS_TAXONOMY_EMIT_FLAG
|
|
620
|
+
) or ""
|
|
621
|
+
).strip() == "1"
|
|
622
|
+
except Exception: # pragma: no cover
|
|
623
|
+
return False
|
|
624
|
+
|
|
625
|
+
|
|
626
|
+
def _classify_egress(command): # noqa: ANN001
|
|
627
|
+
"""Classify ALL egress destinations in `command` (PLAN-133 A3).
|
|
628
|
+
|
|
629
|
+
Returns a list of (egress_class, destination) tuples (possibly empty). Pure;
|
|
630
|
+
fail-OPEN on infra (a scan exception -> [], no emit) per the hook contract.
|
|
631
|
+
"""
|
|
632
|
+
if _egress_taxonomy is None:
|
|
633
|
+
return []
|
|
634
|
+
try:
|
|
635
|
+
return [
|
|
636
|
+
(m.egress_class, m.destination)
|
|
637
|
+
for m in _egress_taxonomy.classify_command(command)
|
|
638
|
+
]
|
|
639
|
+
except Exception as e: # pragma: no cover — fail-OPEN on infra
|
|
640
|
+
print(
|
|
641
|
+
f"[check_bash_safety] egress classify failure; failing OPEN: "
|
|
642
|
+
f"{e.__class__.__name__}",
|
|
643
|
+
file=sys.stderr,
|
|
644
|
+
)
|
|
645
|
+
return []
|
|
646
|
+
|
|
647
|
+
|
|
648
|
+
def _check_git_bypass(command: str) -> "Optional[tuple]":
|
|
649
|
+
"""Scan for git hook-bypass vectors (PLAN-124 WS-1).
|
|
650
|
+
|
|
651
|
+
Returns ``(decision_kind, flag_class)`` where ``decision_kind`` is one of:
|
|
652
|
+
|
|
653
|
+
- ``"block"`` — a bypass was detected and is NOT authorized; the second
|
|
654
|
+
element is the matched closed-enum ``flag_class`` and the reason is
|
|
655
|
+
rebuilt by the caller / re-scan. (We return the reason via a 3-tuple.)
|
|
656
|
+
- ``"escape"`` — a bypass was detected but the dual-auth escape hatch is
|
|
657
|
+
active (MF-E); the caller ALLOWs and emits ``escape_hatch_used``.
|
|
658
|
+
|
|
659
|
+
Returns ``None`` when no bypass is detected (allow, no emit).
|
|
660
|
+
|
|
661
|
+
Tuple shape: ``(kind, flag_class, reason)``. Pure function — no I/O beyond
|
|
662
|
+
the trusted_env snapshot read; never raises (fail-OPEN on infra error per
|
|
663
|
+
the hook contract, EXCEPT the tokenizer's own bounded fail-CLOSED
|
|
664
|
+
parse_failure which is a deliberate BLOCK, MF-L).
|
|
665
|
+
"""
|
|
666
|
+
try:
|
|
667
|
+
match = _git_bypass.scan_command(command)
|
|
668
|
+
except Exception as e: # pragma: no cover — tokenizer infra bug → fail-OPEN
|
|
669
|
+
print(
|
|
670
|
+
f"[check_bash_safety] git-bypass scan failure; failing OPEN: "
|
|
671
|
+
f"{e.__class__.__name__}",
|
|
672
|
+
file=sys.stderr,
|
|
673
|
+
)
|
|
674
|
+
return None
|
|
675
|
+
if match is None:
|
|
676
|
+
return None
|
|
677
|
+
if _git_bypass_escape_hatch_active():
|
|
678
|
+
return ("escape", _git_bypass.FLAG_CLASS_ESCAPE_HATCH, match.reason)
|
|
679
|
+
return ("block", match.flag_class, match.reason)
|
|
680
|
+
|
|
681
|
+
|
|
682
|
+
def _check_credential_leak(command: str) -> Optional[tuple]:
|
|
683
|
+
"""Sprint 12 / CRITICAL-2 (ADR-040): scan raw command for live keys.
|
|
684
|
+
Fail-CLOSED on exception (intentional break from hook's fail-open)."""
|
|
685
|
+
if not command:
|
|
686
|
+
return None
|
|
687
|
+
try:
|
|
688
|
+
for provider, match, _off in _credentials.detect_keys(command):
|
|
689
|
+
if _credentials.is_likely_real_key(match, command):
|
|
690
|
+
return provider, _credentials.redacted_display(provider, match)
|
|
691
|
+
return None
|
|
692
|
+
except Exception as e:
|
|
693
|
+
print(f"[check_bash_safety] credential-scan failure; failing closed: "
|
|
694
|
+
f"{e.__class__.__name__}", file=sys.stderr)
|
|
695
|
+
return "unknown", "unknown:****"
|
|
696
|
+
|
|
697
|
+
|
|
698
|
+
|
|
699
|
+
|
|
700
|
+
# -----------------------------------------------------------------------------
|
|
701
|
+
# PLAN-085 Wave E.3 — canonical-path Bash interceptor (heuristic v1)
|
|
702
|
+
# PLAN-089 Wave B — canonical-path Bash interceptor (matrix v2, +6 matchers)
|
|
703
|
+
# -----------------------------------------------------------------------------
|
|
704
|
+
|
|
705
|
+
# Write-shape operators (regex token patterns) the interceptor scans for.
|
|
706
|
+
# v1 is intentionally conservative; full robust parsing is deferred to
|
|
707
|
+
# PLAN-089 long-term per evolution roadmap.
|
|
708
|
+
_E3_WRITE_OPERATORS = (
|
|
709
|
+
">", ">>", # shell redirect
|
|
710
|
+
"tee", "tee-a", # tee + tee -a
|
|
711
|
+
)
|
|
712
|
+
|
|
713
|
+
# Operator tokens that take the NEXT argv as the target path.
|
|
714
|
+
_E3_NEXT_ARG_OPERATORS = frozenset({">", ">>", "tee"})
|
|
715
|
+
|
|
716
|
+
# Commands whose token-N argv is the target path (sed -i ...).
|
|
717
|
+
_E3_SED_INPLACE_RE = re.compile(r"^-i") # match -i, -i.bak, -iE, etc.
|
|
718
|
+
|
|
719
|
+
|
|
720
|
+
# PLAN-089 Wave B — additional matchers for matrix v2.
|
|
721
|
+
#
|
|
722
|
+
# Each entry maps a "command first token" to a *path-extractor* callable
|
|
723
|
+
# that returns the list of candidate file paths from the remaining
|
|
724
|
+
# tokens. Returning [] means "command not matched; let other checks
|
|
725
|
+
# decide". The function is given the LIST of tokens (already
|
|
726
|
+
# shlex-split) starting from the command name itself.
|
|
727
|
+
|
|
728
|
+
# Languages with -c / -e bodies that may contain literal canonical paths.
|
|
729
|
+
# We do NOT execute the body — we substring-scan for any guard pattern.
|
|
730
|
+
_E3_INTERPRETER_C_FLAGS = {
|
|
731
|
+
"python": ("-c",),
|
|
732
|
+
"python3": ("-c",),
|
|
733
|
+
"ruby": ("-e", "-rb"),
|
|
734
|
+
"node": ("-e", "--eval"),
|
|
735
|
+
"perl": ("-e", "-E"),
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
# Interpreters whose "-i" / "-i inplace" flag implies in-place edit
|
|
739
|
+
# of the LAST positional path argument.
|
|
740
|
+
_E3_INPLACE_INTERPRETERS = {"perl", "ruby", "awk"}
|
|
741
|
+
|
|
742
|
+
# 1:1 file-mover / copy / truncator commands. The destination is the
|
|
743
|
+
# SEGMENT-LOCAL last positional (+ any -t/--target-directory value), NOT the
|
|
744
|
+
# global tokens[-1] — see _e3_segment_positionals / _e3_filemover_targets.
|
|
745
|
+
# (`dd of=PATH` handled separately as kv form; `touch` handled as all-args.)
|
|
746
|
+
# File operations split by which operands are WRITES (S207/Codex 019e90de):
|
|
747
|
+
# COPY — source is read-only; only the DEST landing path is a write.
|
|
748
|
+
# MOVE — DEST landing path is a write AND the SOURCE is removed/renamed
|
|
749
|
+
# (a canonical source is destroyed) → both are canonical mutations.
|
|
750
|
+
# DESTROY — every operand is a write/destroy target (rm/truncate).
|
|
751
|
+
_E3_COPY_CMDS = frozenset({"cp", "install", "rsync", "ditto", "ln"})
|
|
752
|
+
_E3_MOVE_CMDS = frozenset({"mv"})
|
|
753
|
+
_E3_DESTROY_CMDS = frozenset({"rm", "truncate"})
|
|
754
|
+
# Back-compat alias kept for any external reference (the union of all three).
|
|
755
|
+
_E3_FILE_MOVER_LAST_ARG = _E3_COPY_CMDS | _E3_MOVE_CMDS | _E3_DESTROY_CMDS
|
|
756
|
+
|
|
757
|
+
# Command TERMINATORS — end the current simple command's operand list. A
|
|
758
|
+
# last-arg matcher (cp/mv/sed -i/...) MUST resolve its target relative to the
|
|
759
|
+
# CURRENT command segment, not the global tokens[-1] (`cp evil x && true`).
|
|
760
|
+
# Includes `(` `)` `` ` `` so a `$(cp … canonical)` body is its own segment.
|
|
761
|
+
_E3_TERMINATORS = frozenset({"&&", "||", ";", ";;", "|", "|&", "&", "(", ")", "`"})
|
|
762
|
+
|
|
763
|
+
# Redirection operators. Bash permits redirections ANYWHERE in a simple command,
|
|
764
|
+
# so a redirect clause (operator + its target) is SKIPPED while the command keeps
|
|
765
|
+
# collecting operands AFTER it — else `cp src < /dev/null .claude/hooks/x` hides
|
|
766
|
+
# the dest behind the redirect (Codex 019e90de R2#1). Read-only: < << <<<.
|
|
767
|
+
_E3_REDIRECTS = frozenset({
|
|
768
|
+
"<", "<<", "<<<", ">", ">>", ">|", "<>",
|
|
769
|
+
"1>", "1>>", "2>", "2>>", "&>", "&>>",
|
|
770
|
+
">&", "<&", # fd-dup (`2>&1`, `0<&3`) — skip so the fd target
|
|
771
|
+
# ('1'/'3') doesn't poison operand parsing (R3#1).
|
|
772
|
+
})
|
|
773
|
+
|
|
774
|
+
# Redirects whose TARGET is itself a WRITE (a canonical target there is a write).
|
|
775
|
+
# `<>` opens read/write (can create/truncate); `>&FILE` (csh-style) redirects
|
|
776
|
+
# stdout+stderr to a file, so a canonical target there is a write too (R3#1).
|
|
777
|
+
# A fd-dup `2>&1` has a DIGIT target → not canonical → correctly not blocked.
|
|
778
|
+
_E3_WRITE_REDIRECTS = frozenset({">", ">>", ">|", "<>", "1>", "1>>", "2>", "2>>", "&>", "&>>", ">&"})
|
|
779
|
+
|
|
780
|
+
# Back-compat alias (the union) for any external reference.
|
|
781
|
+
_E3_BOUNDARY_TOKENS = _E3_TERMINATORS | _E3_REDIRECTS
|
|
782
|
+
|
|
783
|
+
# tee flags that take NO separate value (--output-error carries =MODE attached);
|
|
784
|
+
# every remaining file operand is a write target. Codex 019e90de R2#3.
|
|
785
|
+
_E3_TEE_FLAG_PREFIXES = ("-a", "--append", "-i", "--ignore-interrupts", "-p", "--output-error")
|
|
786
|
+
|
|
787
|
+
# Commands where EVERY positional in the segment is a create/modify target
|
|
788
|
+
# (no source/dest split): `touch` creates or updates each path it is given.
|
|
789
|
+
_E3_ALL_ARGS_TARGET = frozenset({"touch"})
|
|
790
|
+
# touch flags that CONSUME the next token as a value (a read/reference, NOT a
|
|
791
|
+
# target) — so `touch -r CANONICAL /tmp/out` does not false-positive on the ref.
|
|
792
|
+
_E3_TOUCH_VALUE_FLAGS = frozenset({"-r", "--reference", "-d", "--date", "-t", "--time"})
|
|
793
|
+
|
|
794
|
+
|
|
795
|
+
def _e3_cmd_name(tok): # noqa: ANN001
|
|
796
|
+
"""Normalise a command token to its bare name: '/bin/cp'->'cp', '\\\\cp'->'cp',
|
|
797
|
+
so absolute/escaped command paths can't bypass the matchers (Codex 019e90de #4)."""
|
|
798
|
+
return tok.lstrip("\\").rsplit("/", 1)[-1]
|
|
799
|
+
|
|
800
|
+
|
|
801
|
+
def _e3_segment_positionals(tokens, start): # noqa: ANN001
|
|
802
|
+
"""Positional operands of the command beginning at index ``start`` (its first
|
|
803
|
+
argument). Stops at the next command TERMINATOR; SKIPS redirect clauses
|
|
804
|
+
(operator + target, and an optional leading fd digit) so operands that follow
|
|
805
|
+
a mid-command redirect are still collected. Chaining-safe."""
|
|
806
|
+
out = []
|
|
807
|
+
k = start
|
|
808
|
+
n = len(tokens)
|
|
809
|
+
while k < n:
|
|
810
|
+
t = tokens[k]
|
|
811
|
+
if t in _E3_TERMINATORS:
|
|
812
|
+
break
|
|
813
|
+
if t in _E3_REDIRECTS:
|
|
814
|
+
k += 2 # skip redirect operator + its target
|
|
815
|
+
continue
|
|
816
|
+
if t in ("1", "2") and k + 1 < n and tokens[k + 1] in _E3_REDIRECTS:
|
|
817
|
+
k += 3 # skip fd-prefix + redirect + target
|
|
818
|
+
continue
|
|
819
|
+
out.append(t)
|
|
820
|
+
k += 1
|
|
821
|
+
return out
|
|
822
|
+
|
|
823
|
+
|
|
824
|
+
def _e3_basename(p): # noqa: ANN001
|
|
825
|
+
return p.rstrip("/").rsplit("/", 1)[-1]
|
|
826
|
+
|
|
827
|
+
|
|
828
|
+
def _e3_filemover_landing_paths(args): # noqa: ANN001
|
|
829
|
+
"""All paths a cp/mv/install/rsync/ln/truncate/rm/ditto command could WRITE,
|
|
830
|
+
from its segment-local positional args. Handles the three destination shapes:
|
|
831
|
+
• explicit DEST file (`cp s .claude/hooks/x.py`) -> DEST
|
|
832
|
+
• DEST directory (`cp s .claude/hooks/`) -> DEST/basename(s)
|
|
833
|
+
• -t/--target-directory DIR (`cp -t .claude/hooks s`) -> DIR/basename(s)
|
|
834
|
+
Sources are read-only, so a canonical SOURCE with a non-canonical DEST stays
|
|
835
|
+
allowed (`cp .claude/hooks/x.py /tmp/bak` -> only /tmp/... is a landing path)."""
|
|
836
|
+
flags_dir = []
|
|
837
|
+
j = 0
|
|
838
|
+
while j < len(args):
|
|
839
|
+
a = args[j]
|
|
840
|
+
if a == "-t" and j + 1 < len(args):
|
|
841
|
+
flags_dir.append(args[j + 1]); j += 2; continue
|
|
842
|
+
if a.startswith("--target-directory="):
|
|
843
|
+
flags_dir.append(a.split("=", 1)[1]); j += 1; continue
|
|
844
|
+
if a == "--target-directory" and j + 1 < len(args):
|
|
845
|
+
flags_dir.append(args[j + 1]); j += 2; continue
|
|
846
|
+
j += 1
|
|
847
|
+
positionals = [a for a in args if not a.startswith("-")]
|
|
848
|
+
out = []
|
|
849
|
+
if flags_dir:
|
|
850
|
+
for d in flags_dir:
|
|
851
|
+
dd = d.rstrip("/")
|
|
852
|
+
out.append(d)
|
|
853
|
+
for s in positionals: # every positional is a SOURCE here
|
|
854
|
+
out.append(dd + "/" + _e3_basename(s))
|
|
855
|
+
elif positionals:
|
|
856
|
+
dest = positionals[-1]
|
|
857
|
+
out.append(dest) # explicit DEST file
|
|
858
|
+
dd = dest.rstrip("/")
|
|
859
|
+
for s in positionals[:-1]: # SRC... landing inside DEST-as-dir
|
|
860
|
+
out.append(dd + "/" + _e3_basename(s))
|
|
861
|
+
return out
|
|
862
|
+
|
|
863
|
+
# Commands that wrap a sub-Bash via `-c`. We treat the next argument as
|
|
864
|
+
# an *unparsed body* and substring-scan against the guard set; the body
|
|
865
|
+
# is NOT re-shlex-split for deep evaluation because each layer of
|
|
866
|
+
# expansion is a new attack surface — a single canonical-path substring
|
|
867
|
+
# match is already a strong signal.
|
|
868
|
+
_E3_SHELL_C_INTERPRETERS = {"bash", "sh", "zsh", "ksh", "dash"}
|
|
869
|
+
|
|
870
|
+
# `eval` / `xargs` indirection — body is the next token.
|
|
871
|
+
_E3_INDIRECTION_VERBS = {"xargs", "eval", "find"}
|
|
872
|
+
# R2 Codex iter-1 Q3 fold (2026-05-13): `find` added for row 19
|
|
873
|
+
# `find -name 'CLAUDE.md' -exec sed -i ... {} +`. Indirection block below
|
|
874
|
+
# walks ALL subsequent tokens for `find` (variable -name/-exec positions);
|
|
875
|
+
# eval/xargs keep single-next-token scan.
|
|
876
|
+
|
|
877
|
+
# ReDoS / pathological-input cap for body scan.
|
|
878
|
+
_E3_BODY_CAP_BYTES = 16 * 1024
|
|
879
|
+
|
|
880
|
+
|
|
881
|
+
def _e3_check_canonical_path_write(command: str) -> Optional[str]:
|
|
882
|
+
"""Return a deny reason string if ``command`` writes to a canonical
|
|
883
|
+
governance path; None otherwise.
|
|
884
|
+
|
|
885
|
+
Heuristic v1 — uses ``shlex.split`` for tokenization. Fail-CLOSED
|
|
886
|
+
on parse failure (returns a deny reason, not None) per R1 Sec-2.
|
|
887
|
+
|
|
888
|
+
Cross-references target paths against ``check_canonical_edit._CANONICAL_GUARDS``
|
|
889
|
+
via a delayed import to avoid circular dependency at module load.
|
|
890
|
+
|
|
891
|
+
Detection set:
|
|
892
|
+
- ``> path`` / ``>> path`` (shell redirect)
|
|
893
|
+
- ``tee path`` / ``tee -a path`` (tee write)
|
|
894
|
+
- ``sed -i ... path`` (in-place edit)
|
|
895
|
+
- ``cat > path`` / ``cat >> path`` (cat redirect)
|
|
896
|
+
- ``git checkout <ref> -- path`` (checkout-overwrite)
|
|
897
|
+
"""
|
|
898
|
+
import shlex
|
|
899
|
+
try:
|
|
900
|
+
# punctuation_chars=True isolates the shell operators ( ) ; < > | & even
|
|
901
|
+
# when written ADJACENT to a path (`x.py&&echo`, `printf x>file`, `$(cp …)`),
|
|
902
|
+
# grouping runs into single tokens (&&, ||, ;;, |&, &>). This closes the
|
|
903
|
+
# attached-operator + command-substitution bypasses (S207/Codex 019e90de).
|
|
904
|
+
_lx = shlex.shlex(command, posix=True, punctuation_chars="();<>|&`")
|
|
905
|
+
_lx.whitespace_split = True
|
|
906
|
+
tokens = list(_lx)
|
|
907
|
+
except ValueError as exc:
|
|
908
|
+
# PLAN-085 Wave E.3 R1 Sec-2 — fail-CLOSED on parse failure.
|
|
909
|
+
try:
|
|
910
|
+
if _audit_emit is not None:
|
|
911
|
+
_audit_emit.emit_veto_triggered(
|
|
912
|
+
hook="check_bash_safety",
|
|
913
|
+
reason_code="bash_parse_failed_fail_closed",
|
|
914
|
+
reason_preview=f"shlex parse failure: {exc!s}"[:200],
|
|
915
|
+
blocked_tool="Bash",
|
|
916
|
+
)
|
|
917
|
+
except Exception: # pragma: no cover
|
|
918
|
+
pass
|
|
919
|
+
return (
|
|
920
|
+
"GOVERNANCE: bash command failed shlex.split parse "
|
|
921
|
+
"(fail-CLOSED per Wave E.3). Re-quote tokens and retry."
|
|
922
|
+
)
|
|
923
|
+
|
|
924
|
+
if not tokens:
|
|
925
|
+
return None
|
|
926
|
+
|
|
927
|
+
# Resolve canonical guards via delayed import.
|
|
928
|
+
try:
|
|
929
|
+
sys.path_hooks # cheap shim to ensure sys is imported
|
|
930
|
+
from check_canonical_edit import _CANONICAL_GUARDS, _fnmatch_segments
|
|
931
|
+
except Exception: # pragma: no cover
|
|
932
|
+
return None # fail-OPEN ON dependency failure (defense layer issue)
|
|
933
|
+
|
|
934
|
+
import os as _os
|
|
935
|
+
|
|
936
|
+
def _is_canonical(path: str) -> bool:
|
|
937
|
+
# Candidate forms to test against the (repo-root-relative) guard globs.
|
|
938
|
+
cands = [path[2:] if path.startswith("./") else path]
|
|
939
|
+
# An ABSOLUTE path under the project root bypasses a relative-only match
|
|
940
|
+
# (`cp evil /abs/repo/.claude/hooks/x.py`) — normalise it to repo-relative
|
|
941
|
+
# (string-only normpath, no filesystem hit; collapses ./ and ..). S207 fix.
|
|
942
|
+
if path.startswith("/"):
|
|
943
|
+
root = _os.path.normpath(_os.environ.get("CLAUDE_PROJECT_DIR") or _os.getcwd())
|
|
944
|
+
norm = _os.path.normpath(path)
|
|
945
|
+
if norm.startswith(root + _os.sep):
|
|
946
|
+
cands.append(norm[len(root) + 1:])
|
|
947
|
+
for cand in cands:
|
|
948
|
+
for pattern in _CANONICAL_GUARDS:
|
|
949
|
+
try:
|
|
950
|
+
if _fnmatch_segments(cand, pattern):
|
|
951
|
+
return True
|
|
952
|
+
except Exception:
|
|
953
|
+
continue
|
|
954
|
+
return False
|
|
955
|
+
|
|
956
|
+
# Scan tokens for write-shape operators and check target paths.
|
|
957
|
+
i = 0
|
|
958
|
+
n = len(tokens)
|
|
959
|
+
while i < n:
|
|
960
|
+
tok = tokens[i]
|
|
961
|
+
cmd = _e3_cmd_name(tok) # normalised command name (/bin/cp -> cp, \cp -> cp)
|
|
962
|
+
# write redirect (> >> >| <> 1> 1>> 2> 2>> &> &>>) — next token is target.
|
|
963
|
+
if tok in _E3_WRITE_REDIRECTS:
|
|
964
|
+
if i + 1 < n and _is_canonical(tokens[i + 1]):
|
|
965
|
+
return (
|
|
966
|
+
f"GOVERNANCE: bash command writes to canonical path "
|
|
967
|
+
f"{tokens[i + 1]!r} via {tok!r}. Use Edit/Write tool "
|
|
968
|
+
"(sentinel-gated) instead. Wave E.3 interceptor."
|
|
969
|
+
)
|
|
970
|
+
# `tee [flags] file...` — tee writes EVERY file operand. Consume flags
|
|
971
|
+
# (-a/--append/-i/--ignore-interrupts/-p/--output-error[=MODE]), honor --.
|
|
972
|
+
if cmd == "tee":
|
|
973
|
+
seen_ddash = False
|
|
974
|
+
for a in _e3_segment_positionals(tokens, i + 1):
|
|
975
|
+
if not seen_ddash:
|
|
976
|
+
if a == "--":
|
|
977
|
+
seen_ddash = True; continue
|
|
978
|
+
if a == "-" or a.startswith(_E3_TEE_FLAG_PREFIXES):
|
|
979
|
+
continue
|
|
980
|
+
if _is_canonical(a):
|
|
981
|
+
return (
|
|
982
|
+
f"GOVERNANCE: bash 'tee' writes canonical path "
|
|
983
|
+
f"{a!r}. Use Edit/Write with sentinel. Wave E.3."
|
|
984
|
+
)
|
|
985
|
+
# `sed -i <expr> path...` — targets are the segment-local positionals
|
|
986
|
+
# after the script expr (chaining-safe; not global tokens[-1]).
|
|
987
|
+
if cmd == "sed" and i + 1 < n and _E3_SED_INPLACE_RE.match(tokens[i + 1]):
|
|
988
|
+
seg = _e3_segment_positionals(tokens, i + 1)
|
|
989
|
+
positionals = [a for a in seg if not a.startswith("-")]
|
|
990
|
+
for cand in positionals[1:]: # positionals[0] = the sed script expr
|
|
991
|
+
if _is_canonical(cand):
|
|
992
|
+
return (
|
|
993
|
+
f"GOVERNANCE: bash 'sed -i' to canonical path "
|
|
994
|
+
f"{cand!r} blocked. Wave E.3 interceptor."
|
|
995
|
+
)
|
|
996
|
+
# `git checkout <ref> -- <path>` — token after `--` is target (segment-bounded).
|
|
997
|
+
if cmd == "git" and i + 2 < n and tokens[i + 1] == "checkout":
|
|
998
|
+
seg = _e3_segment_positionals(tokens, i) # includes 'git'
|
|
999
|
+
for k in range(len(seg) - 1):
|
|
1000
|
+
if seg[k] == "--" and _is_canonical(seg[k + 1]):
|
|
1001
|
+
return (
|
|
1002
|
+
f"GOVERNANCE: bash 'git checkout ... -- {seg[k + 1]!r}' "
|
|
1003
|
+
"overwrites canonical path. Use sentinel ceremony."
|
|
1004
|
+
)
|
|
1005
|
+
# ---- PLAN-089 Wave B additions ---------------------------------
|
|
1006
|
+
|
|
1007
|
+
# Helper — scan an unparsed body string for any canonical path.
|
|
1008
|
+
# Two-pass: (a) shlex-tokenize and check each token (catches
|
|
1009
|
+
# whitespace-delimited paths) and (b) substring-scan against the
|
|
1010
|
+
# **literal** _CANONICAL_GUARDS entries (no globs) to catch paths
|
|
1011
|
+
# embedded inside punctuation-laden interpreter syntax such as
|
|
1012
|
+
# ``open('PROTOCOL.md','w')`` where shlex glues
|
|
1013
|
+
# ``'PROTOCOL.md','w'`` together into a single token.
|
|
1014
|
+
# False-positive risk is bounded by the guard list — each entry
|
|
1015
|
+
# is a fully-qualified governance path; ``README.md`` is NOT a
|
|
1016
|
+
# guard literal so a body containing the bare string
|
|
1017
|
+
# ``README.md`` does NOT trigger.
|
|
1018
|
+
def _scan_blob(blob): # noqa: ANN001
|
|
1019
|
+
if not blob:
|
|
1020
|
+
return None
|
|
1021
|
+
if len(blob) > _E3_BODY_CAP_BYTES:
|
|
1022
|
+
# Pathological input — fail-CLOSED.
|
|
1023
|
+
return blob[:200]
|
|
1024
|
+
# (a) shlex tokenize + canonical-check each token.
|
|
1025
|
+
try:
|
|
1026
|
+
inner = shlex.split(blob, posix=True)
|
|
1027
|
+
except ValueError:
|
|
1028
|
+
# Malformed inner body — fail-CLOSED.
|
|
1029
|
+
return blob[:200]
|
|
1030
|
+
for sub in inner:
|
|
1031
|
+
if _is_canonical(sub):
|
|
1032
|
+
return sub
|
|
1033
|
+
# (b) substring scan for literal guard entries.
|
|
1034
|
+
# Cheap O(L * len(blob)) where L = ~18 literals; bounded
|
|
1035
|
+
# by _E3_BODY_CAP_BYTES.
|
|
1036
|
+
try:
|
|
1037
|
+
from check_canonical_edit import _CANONICAL_GUARDS
|
|
1038
|
+
except Exception:
|
|
1039
|
+
return None
|
|
1040
|
+
for pattern in _CANONICAL_GUARDS:
|
|
1041
|
+
if not any(c in pattern for c in "*?["):
|
|
1042
|
+
if pattern in blob:
|
|
1043
|
+
return pattern
|
|
1044
|
+
return None
|
|
1045
|
+
|
|
1046
|
+
# 1) Interpreter -c / -e body scan (python/ruby/node/perl).
|
|
1047
|
+
if cmd in _E3_INTERPRETER_C_FLAGS:
|
|
1048
|
+
flags = _E3_INTERPRETER_C_FLAGS[cmd]
|
|
1049
|
+
for j in range(i + 1, n - 1):
|
|
1050
|
+
if tokens[j] in flags:
|
|
1051
|
+
body = tokens[j + 1]
|
|
1052
|
+
hit = _scan_blob(body)
|
|
1053
|
+
if hit is not None:
|
|
1054
|
+
return (
|
|
1055
|
+
f"GOVERNANCE: bash {tok!r} -c/-e body references "
|
|
1056
|
+
f"canonical path {hit!r}. Use Edit/Write with "
|
|
1057
|
+
"sentinel."
|
|
1058
|
+
)
|
|
1059
|
+
break
|
|
1060
|
+
|
|
1061
|
+
# 2) Interpreter -i / -i inplace (perl/ruby/awk) — last positional
|
|
1062
|
+
# argument is the target path.
|
|
1063
|
+
if cmd in _E3_INPLACE_INTERPRETERS:
|
|
1064
|
+
seg = _e3_segment_positionals(tokens, i + 1)
|
|
1065
|
+
has_inplace = any(
|
|
1066
|
+
(t == "-i" or t.startswith("-i.") or t == "inplace") for t in seg
|
|
1067
|
+
)
|
|
1068
|
+
positionals = [a for a in seg if not a.startswith("-")]
|
|
1069
|
+
if has_inplace and positionals and _is_canonical(positionals[-1]):
|
|
1070
|
+
return (
|
|
1071
|
+
f"GOVERNANCE: bash {tok!r} -i inplace edit on canonical "
|
|
1072
|
+
f"path {positionals[-1]!r}. Use Edit/Write with sentinel."
|
|
1073
|
+
)
|
|
1074
|
+
|
|
1075
|
+
# 3) cp/install/rsync/ditto/ln (COPY) + mv (MOVE) — the WRITE target is the
|
|
1076
|
+
# segment-local landing path(s), NOT the global tokens[-1] (chaining-safe).
|
|
1077
|
+
# mv ALSO removes its SOURCE, so a canonical source is a mutation too.
|
|
1078
|
+
if cmd in _E3_COPY_CMDS or cmd in _E3_MOVE_CMDS:
|
|
1079
|
+
args = _e3_segment_positionals(tokens, i + 1)
|
|
1080
|
+
checks = list(_e3_filemover_landing_paths(args))
|
|
1081
|
+
if cmd in _E3_MOVE_CMDS:
|
|
1082
|
+
checks += [a for a in args if not a.startswith("-")] # sources are removed
|
|
1083
|
+
for dest in checks:
|
|
1084
|
+
if _is_canonical(dest):
|
|
1085
|
+
return (
|
|
1086
|
+
f"GOVERNANCE: bash {tok!r} writes/mutates canonical path "
|
|
1087
|
+
f"{dest!r}. Use Edit/Write with sentinel."
|
|
1088
|
+
)
|
|
1089
|
+
# 3b) rm / truncate (DESTROY) — every operand is a destroy target.
|
|
1090
|
+
if cmd in _E3_DESTROY_CMDS:
|
|
1091
|
+
for a in _e3_segment_positionals(tokens, i + 1):
|
|
1092
|
+
if not a.startswith("-") and _is_canonical(a):
|
|
1093
|
+
return (
|
|
1094
|
+
f"GOVERNANCE: bash {tok!r} destroys canonical path "
|
|
1095
|
+
f"{a!r}. Use Edit/Write with sentinel."
|
|
1096
|
+
)
|
|
1097
|
+
# 3c) touch — every operand is a create/modify target, EXCEPT values of
|
|
1098
|
+
# reference/date/time flags (-r/-d/-t) which are reads, not targets.
|
|
1099
|
+
if cmd in _E3_ALL_ARGS_TARGET:
|
|
1100
|
+
seg = _e3_segment_positionals(tokens, i + 1)
|
|
1101
|
+
k = 0
|
|
1102
|
+
while k < len(seg):
|
|
1103
|
+
a = seg[k]
|
|
1104
|
+
if a in _E3_TOUCH_VALUE_FLAGS:
|
|
1105
|
+
k += 2; continue # skip flag + its value (a read)
|
|
1106
|
+
if a.startswith(("--reference=", "--date=", "--time=")) or a.startswith("-"):
|
|
1107
|
+
k += 1; continue
|
|
1108
|
+
if _is_canonical(a):
|
|
1109
|
+
return (
|
|
1110
|
+
f"GOVERNANCE: bash {tok!r} creates/modifies canonical "
|
|
1111
|
+
f"path {a!r}. Use Edit/Write with sentinel."
|
|
1112
|
+
)
|
|
1113
|
+
k += 1
|
|
1114
|
+
|
|
1115
|
+
# 4) dd of=PATH — kv form (segment-bounded).
|
|
1116
|
+
if cmd == "dd":
|
|
1117
|
+
for t in _e3_segment_positionals(tokens, i + 1):
|
|
1118
|
+
if t.startswith("of=") and _is_canonical(t[3:]):
|
|
1119
|
+
return (
|
|
1120
|
+
f"GOVERNANCE: bash 'dd of={t[3:]}' writes canonical "
|
|
1121
|
+
"path. Use Edit/Write with sentinel."
|
|
1122
|
+
)
|
|
1123
|
+
|
|
1124
|
+
# 5) Shell-in-shell — bash/sh/zsh/ksh/dash -c '<body>'.
|
|
1125
|
+
if cmd in _E3_SHELL_C_INTERPRETERS:
|
|
1126
|
+
for j in range(i + 1, n - 1):
|
|
1127
|
+
if tokens[j] == "-c":
|
|
1128
|
+
body = tokens[j + 1]
|
|
1129
|
+
hit = _scan_blob(body)
|
|
1130
|
+
if hit is not None:
|
|
1131
|
+
return (
|
|
1132
|
+
f"GOVERNANCE: bash {tok!r} -c body references "
|
|
1133
|
+
f"canonical path {hit!r}. Re-tokenization "
|
|
1134
|
+
"indirection denied."
|
|
1135
|
+
)
|
|
1136
|
+
break
|
|
1137
|
+
|
|
1138
|
+
# 6) eval / xargs / find body indirection — substring-scan
|
|
1139
|
+
# follow-on token(s) for any canonical path reference.
|
|
1140
|
+
# R2 Codex iter-1 Q3 fold: `find` scans ALL subsequent tokens
|
|
1141
|
+
# (because find -exec / -name positions are variable); eval/xargs
|
|
1142
|
+
# keep single-next-token scan.
|
|
1143
|
+
if cmd in _E3_INDIRECTION_VERBS and i + 1 < n:
|
|
1144
|
+
if cmd == "find":
|
|
1145
|
+
for _follow in tokens[i + 1:]:
|
|
1146
|
+
hit = _scan_blob(_follow)
|
|
1147
|
+
if hit is not None:
|
|
1148
|
+
return (
|
|
1149
|
+
f"GOVERNANCE: bash 'find' invocation references "
|
|
1150
|
+
f"canonical path {hit!r}. -exec sed/-i edit denied. "
|
|
1151
|
+
"Use direct Edit/Write."
|
|
1152
|
+
)
|
|
1153
|
+
else:
|
|
1154
|
+
body = tokens[i + 1]
|
|
1155
|
+
hit = _scan_blob(body)
|
|
1156
|
+
if hit is not None:
|
|
1157
|
+
return (
|
|
1158
|
+
f"GOVERNANCE: bash {tok!r} indirection references "
|
|
1159
|
+
f"canonical path {hit!r}. Use direct Edit/Write."
|
|
1160
|
+
)
|
|
1161
|
+
|
|
1162
|
+
i += 1
|
|
1163
|
+
return None
|
|
1164
|
+
|
|
1165
|
+
|
|
1166
|
+
def decide_command(command: str) -> Decision:
|
|
1167
|
+
"""Pure decision function — no I/O, trivially unit-testable.
|
|
1168
|
+
|
|
1169
|
+
Args:
|
|
1170
|
+
command: The raw `tool_input.command` string.
|
|
1171
|
+
|
|
1172
|
+
Returns:
|
|
1173
|
+
Decision(allow=True) if no rule matches.
|
|
1174
|
+
Decision(allow=False, reason=...) on first rule match.
|
|
1175
|
+
"""
|
|
1176
|
+
if not command or not command.strip():
|
|
1177
|
+
return Decision(allow=True)
|
|
1178
|
+
|
|
1179
|
+
# Credential scan runs BEFORE tokenization — quoted keys must match.
|
|
1180
|
+
cred_hit = _check_credential_leak(command)
|
|
1181
|
+
if cred_hit is not None:
|
|
1182
|
+
return Decision(allow=False, reason=(
|
|
1183
|
+
"GOVERNANCE: bash command contains what appears to be a live "
|
|
1184
|
+
f"API credential. Redact before executing. Pattern: {cred_hit[1]}. "
|
|
1185
|
+
"Export via env var (never inline)."))
|
|
1186
|
+
|
|
1187
|
+
# PLAN-085 Wave E.3 — canonical-path write interceptor (heuristic v1).
|
|
1188
|
+
canonical_reason = _e3_check_canonical_path_write(command)
|
|
1189
|
+
if canonical_reason is not None:
|
|
1190
|
+
return Decision(allow=False, reason=canonical_reason)
|
|
1191
|
+
|
|
1192
|
+
# PLAN-133 A1 — linker/loader/runtime env-hijack denylist. Runs BEFORE the
|
|
1193
|
+
# destructive matchers (a higher-severity class). Default-OFF: only BLOCKS
|
|
1194
|
+
# when CEO_ENV_GUARD_ENFORCE=='1'; otherwise advisory (the emit still fires
|
|
1195
|
+
# in main()). decide_command stays pure (no emit here).
|
|
1196
|
+
if _env_guard_enforced():
|
|
1197
|
+
env_hit = _check_env_hijack(command)
|
|
1198
|
+
if env_hit is not None:
|
|
1199
|
+
_hijack_class, _key, reason = env_hit
|
|
1200
|
+
return Decision(allow=False, reason=reason)
|
|
1201
|
+
|
|
1202
|
+
# PLAN-124 WS-1 — git hook-bypass guard (runs BEFORE the destructive
|
|
1203
|
+
# matchers; an authorized escape-hatch use ALLOWs, an unauthorized bypass
|
|
1204
|
+
# BLOCKs, and the bounded parse_failure is a deliberate fail-CLOSED).
|
|
1205
|
+
git_bypass_hit = _check_git_bypass(command)
|
|
1206
|
+
if git_bypass_hit is not None:
|
|
1207
|
+
kind, _flag_class, reason = git_bypass_hit
|
|
1208
|
+
if kind == "block":
|
|
1209
|
+
return Decision(allow=False, reason=reason)
|
|
1210
|
+
# kind == "escape": dual-auth authorized → ALLOW (emit handled in main).
|
|
1211
|
+
|
|
1212
|
+
for subcommand in _split_subcommands(command):
|
|
1213
|
+
tokens = _tokenize(subcommand)
|
|
1214
|
+
if not tokens:
|
|
1215
|
+
continue
|
|
1216
|
+
for check in (
|
|
1217
|
+
_check_rm_rf,
|
|
1218
|
+
_check_git_reset_hard,
|
|
1219
|
+
_check_git_push_force,
|
|
1220
|
+
):
|
|
1221
|
+
reason = check(tokens)
|
|
1222
|
+
if reason:
|
|
1223
|
+
# PLAN-135 W2 H5 — corrective rewrite for the force-push
|
|
1224
|
+
# pattern ONLY. When the rewrite is enabled AND the command
|
|
1225
|
+
# is the trivially-safe single-subcommand `git push --force`
|
|
1226
|
+
# pilot pattern, REWRITE → `--force-with-lease` and surface
|
|
1227
|
+
# an `ask` (constraint (b)) carrying the new command via
|
|
1228
|
+
# updatedInput, instead of a hard BLOCK. Any failure to
|
|
1229
|
+
# build a clean rewrite (compound command, ambiguity, etc.)
|
|
1230
|
+
# falls through to the existing BLOCK (constraint (a): the
|
|
1231
|
+
# corrective rewrite NEVER degrades a BLOCK into a silent
|
|
1232
|
+
# allow — Doctrine 1 corollary). All OTHER block reasons
|
|
1233
|
+
# (rm -rf, git reset --hard) are unaffected.
|
|
1234
|
+
if check is _check_git_push_force and _force_push_rewrite_enabled():
|
|
1235
|
+
rewrite = _rewrite_git_push_force(command)
|
|
1236
|
+
if rewrite is not None:
|
|
1237
|
+
# allow=True is the contract-layer carrier; main()
|
|
1238
|
+
# translates the attached Rewrite into the `ask` +
|
|
1239
|
+
# updatedInput vendor shape. The permission prompt is
|
|
1240
|
+
# ALWAYS retained — this is never a silent allow.
|
|
1241
|
+
return Decision(allow=True, rewrite=rewrite)
|
|
1242
|
+
return Decision(allow=False, reason=reason)
|
|
1243
|
+
|
|
1244
|
+
return Decision(allow=True)
|
|
1245
|
+
|
|
1246
|
+
|
|
1247
|
+
def _to_contract_decision(
|
|
1248
|
+
d: "Decision",
|
|
1249
|
+
tool_input: "Optional[Dict]" = None,
|
|
1250
|
+
) -> _contract.Decision:
|
|
1251
|
+
"""Translate local Decision → adapter-layer contract.Decision.
|
|
1252
|
+
|
|
1253
|
+
PLAN-135 W2 H5: when the Decision carries a :class:`Rewrite`, build the
|
|
1254
|
+
Claude Code PreToolUse `ask` + `updatedInput` vendor shape via the
|
|
1255
|
+
neutral contract `extra` channel (the claude adapter merges `extra`
|
|
1256
|
+
into the top-level JSON). The output is:
|
|
1257
|
+
|
|
1258
|
+
{"hookSpecificOutput": {
|
|
1259
|
+
"hookEventName": "PreToolUse",
|
|
1260
|
+
"permissionDecision": "ask",
|
|
1261
|
+
"permissionDecisionReason": "<names the rewrite>",
|
|
1262
|
+
"updatedInput": {<original tool_input>, "command": "<rewritten>"}
|
|
1263
|
+
}}
|
|
1264
|
+
|
|
1265
|
+
The ORIGINAL tool_input keys are preserved and only `command` is
|
|
1266
|
+
overridden (constraint (c) — we change the command, nothing else). If
|
|
1267
|
+
`tool_input` is not a dict, `updatedInput` carries just the rewritten
|
|
1268
|
+
command (the executor reads `command`).
|
|
1269
|
+
"""
|
|
1270
|
+
if d.rewrite is not None:
|
|
1271
|
+
rw = d.rewrite
|
|
1272
|
+
updated_input: Dict[str, object] = {}
|
|
1273
|
+
if isinstance(tool_input, dict):
|
|
1274
|
+
updated_input.update(tool_input)
|
|
1275
|
+
updated_input["command"] = rw.new_command
|
|
1276
|
+
dec = _contract.allow()
|
|
1277
|
+
dec.extra["hookSpecificOutput"] = {
|
|
1278
|
+
"hookEventName": "PreToolUse",
|
|
1279
|
+
"permissionDecision": "ask",
|
|
1280
|
+
"permissionDecisionReason": rw.reason,
|
|
1281
|
+
"updatedInput": updated_input,
|
|
1282
|
+
}
|
|
1283
|
+
return dec
|
|
1284
|
+
if d.allow:
|
|
1285
|
+
return _contract.allow()
|
|
1286
|
+
return _contract.block(d.reason or "")
|
|
1287
|
+
|
|
1288
|
+
|
|
1289
|
+
def _emit_git_hook_bypass_event(flag_class: str) -> None:
|
|
1290
|
+
"""Emit git_hook_bypass_blocked(flag_class). Fail-open (PLAN-124 WS-1).
|
|
1291
|
+
|
|
1292
|
+
The ONLY field is the closed-enum flag_class — NEVER the command bytes
|
|
1293
|
+
(MF-G). Emitted on BOTH an unauthorized block AND an authorized
|
|
1294
|
+
escape-hatch use (flag_class=escape_hatch_used). session_id / project are
|
|
1295
|
+
read from the live env (forensic envelope only; not a grant source).
|
|
1296
|
+
"""
|
|
1297
|
+
if _audit_emit is None:
|
|
1298
|
+
return
|
|
1299
|
+
try:
|
|
1300
|
+
import os as _os
|
|
1301
|
+
_audit_emit.emit_git_hook_bypass_blocked(
|
|
1302
|
+
flag_class=flag_class,
|
|
1303
|
+
session_id=_os.environ.get("CLAUDE_SESSION_ID", ""),
|
|
1304
|
+
project=_os.environ.get("CLAUDE_PROJECT_DIR", ""),
|
|
1305
|
+
)
|
|
1306
|
+
except Exception: # pragma: no cover
|
|
1307
|
+
pass
|
|
1308
|
+
|
|
1309
|
+
|
|
1310
|
+
def _emit_env_var_hijack_event(hijack_class: str) -> None:
|
|
1311
|
+
"""Emit env_var_hijack_blocked(hijack_class). Fail-open (PLAN-133 A1).
|
|
1312
|
+
|
|
1313
|
+
The ONLY caller-supplied field is the closed-enum `hijack_class` — NEVER the
|
|
1314
|
+
variable NAME and NEVER the assigned VALUE (the value is the payload surface,
|
|
1315
|
+
MF analogous to git_hook_bypass MF-G). session_id / project are read from the
|
|
1316
|
+
live env (forensic envelope only; not a grant source). Emitted on BOTH an
|
|
1317
|
+
enforced block AND an advisory (default-OFF) detection.
|
|
1318
|
+
"""
|
|
1319
|
+
if _audit_emit is None:
|
|
1320
|
+
return
|
|
1321
|
+
try:
|
|
1322
|
+
import os as _os
|
|
1323
|
+
_audit_emit.emit_env_var_hijack_blocked(
|
|
1324
|
+
hijack_class=hijack_class,
|
|
1325
|
+
session_id=_os.environ.get("CLAUDE_SESSION_ID", ""),
|
|
1326
|
+
project=_os.environ.get("CLAUDE_PROJECT_DIR", ""),
|
|
1327
|
+
)
|
|
1328
|
+
except Exception: # pragma: no cover
|
|
1329
|
+
pass
|
|
1330
|
+
|
|
1331
|
+
|
|
1332
|
+
def _emit_egress_destination_event(egress_class: str, destination: str) -> None:
|
|
1333
|
+
"""Emit egress_destination_detected(egress_class, destination). Fail-open.
|
|
1334
|
+
|
|
1335
|
+
`destination` is ALREADY host-only (egress_taxonomy reduces it); the audit
|
|
1336
|
+
emitter re-truncates defensively. The full URL / path / query / inline
|
|
1337
|
+
credential is NEVER passed here. When egress_class == 'pair_rail' the caller
|
|
1338
|
+
ALSO emits pair_rail_outgoing_redaction_applied (positive proof the outbound
|
|
1339
|
+
redactor ran on the sanctioned channel). session_id / project are forensic
|
|
1340
|
+
envelope only (not a grant source).
|
|
1341
|
+
"""
|
|
1342
|
+
if _audit_emit is None:
|
|
1343
|
+
return
|
|
1344
|
+
try:
|
|
1345
|
+
import os as _os
|
|
1346
|
+
_sid = _os.environ.get("CLAUDE_SESSION_ID", "")
|
|
1347
|
+
_proj = _os.environ.get("CLAUDE_PROJECT_DIR", "")
|
|
1348
|
+
_audit_emit.emit_egress_destination_detected(
|
|
1349
|
+
egress_class=egress_class,
|
|
1350
|
+
destination=destination,
|
|
1351
|
+
session_id=_sid,
|
|
1352
|
+
project=_proj,
|
|
1353
|
+
)
|
|
1354
|
+
if egress_class == "pair_rail":
|
|
1355
|
+
_audit_emit.emit_pair_rail_outgoing_redaction_applied(
|
|
1356
|
+
signal="egress_taxonomy",
|
|
1357
|
+
family="pair_rail",
|
|
1358
|
+
match_count=0,
|
|
1359
|
+
bytes_scanned=0,
|
|
1360
|
+
callsite="check_bash_safety.egress",
|
|
1361
|
+
session_id=_sid,
|
|
1362
|
+
project=_proj,
|
|
1363
|
+
)
|
|
1364
|
+
except Exception: # pragma: no cover
|
|
1365
|
+
pass
|
|
1366
|
+
|
|
1367
|
+
|
|
1368
|
+
def _emit_credential_leak_event(provider: str, redacted: str) -> None:
|
|
1369
|
+
"""Emit veto_triggered(credential_leak). Fail-open."""
|
|
1370
|
+
if _audit_emit is None:
|
|
1371
|
+
return
|
|
1372
|
+
try:
|
|
1373
|
+
_audit_emit.emit_veto_triggered(
|
|
1374
|
+
hook="check_bash_safety", reason_code="credential_leak",
|
|
1375
|
+
reason_preview=f"bash_credential_leak_blocked provider={provider} match={redacted}",
|
|
1376
|
+
blocked_tool="Bash")
|
|
1377
|
+
except Exception: # pragma: no cover
|
|
1378
|
+
pass
|
|
1379
|
+
|
|
1380
|
+
|
|
1381
|
+
def _emit_bash_input_rewritten_event(rewrite: "Rewrite") -> None:
|
|
1382
|
+
"""Emit bash_input_rewritten with the before/after hash PAIR. Fail-open.
|
|
1383
|
+
|
|
1384
|
+
PLAN-135 W2 H5 (mini-ADR-154 §2). The ONLY caller-supplied fields are
|
|
1385
|
+
the closed-enum `rewrite_class` and the two 64-hex sha256 hashes — the
|
|
1386
|
+
command BYTES (before OR after) are NEVER persisted (a force-push line
|
|
1387
|
+
can carry a remote URL with an inline token). The hash pair lets an
|
|
1388
|
+
auditor prove the audited command equals the executed command without
|
|
1389
|
+
seeing either command. session_id / project are forensic envelope only.
|
|
1390
|
+
"""
|
|
1391
|
+
if _audit_emit is None:
|
|
1392
|
+
return
|
|
1393
|
+
try:
|
|
1394
|
+
import os as _os
|
|
1395
|
+
_audit_emit.emit_bash_input_rewritten(
|
|
1396
|
+
rewrite_class=rewrite.rewrite_class,
|
|
1397
|
+
before_sha256=rewrite.before_sha256,
|
|
1398
|
+
after_sha256=rewrite.after_sha256,
|
|
1399
|
+
session_id=_os.environ.get("CLAUDE_SESSION_ID", ""),
|
|
1400
|
+
project=_os.environ.get("CLAUDE_PROJECT_DIR", ""),
|
|
1401
|
+
)
|
|
1402
|
+
except Exception: # pragma: no cover
|
|
1403
|
+
pass
|
|
1404
|
+
|
|
1405
|
+
|
|
1406
|
+
def main() -> int:
|
|
1407
|
+
"""Hook entry point: read stdin via Adapter Layer, decide, write stdout, exit 0.
|
|
1408
|
+
|
|
1409
|
+
PLAN-006 Phase 1 migration (ADR-014). Uses `claude_adapter.read_event()`
|
|
1410
|
+
/ `emit_decision()` instead of direct `_lib.payload` + `print()`.
|
|
1411
|
+
Output is byte-identical to pre-migration (test_hook_byte_fidelity).
|
|
1412
|
+
"""
|
|
1413
|
+
try:
|
|
1414
|
+
event = _claude_adapter.read_event(phase="PreToolUse")
|
|
1415
|
+
if event.parse_error:
|
|
1416
|
+
print(
|
|
1417
|
+
f"[check_bash_safety] WARN: stdin parse error: {event.parse_error}",
|
|
1418
|
+
file=sys.stderr,
|
|
1419
|
+
)
|
|
1420
|
+
_claude_adapter.emit_decision(_contract.allow())
|
|
1421
|
+
return 0
|
|
1422
|
+
|
|
1423
|
+
command = event.command or ""
|
|
1424
|
+
if not command and isinstance(event.tool_input, dict):
|
|
1425
|
+
command = str(event.tool_input.get("command") or "")
|
|
1426
|
+
|
|
1427
|
+
decision = decide_command(command)
|
|
1428
|
+
# Re-run detector on credential blocks to emit audit event.
|
|
1429
|
+
if not decision.allow and decision.reason and "API credential" in decision.reason:
|
|
1430
|
+
hit = _check_credential_leak(command)
|
|
1431
|
+
if hit is not None:
|
|
1432
|
+
_emit_credential_leak_event(hit[0], hit[1])
|
|
1433
|
+
# PLAN-124 WS-1 — emit git_hook_bypass_blocked on a block OR an
|
|
1434
|
+
# authorized escape-hatch use. Re-scan to recover the closed-enum
|
|
1435
|
+
# flag_class (decide_command stays pure / I/O-free). The credential
|
|
1436
|
+
# block above takes precedence, so skip if the reason was a credential.
|
|
1437
|
+
if not (decision.reason and "API credential" in decision.reason):
|
|
1438
|
+
git_hit = _check_git_bypass(command)
|
|
1439
|
+
if git_hit is not None:
|
|
1440
|
+
_kind, _flag_class, _reason = git_hit
|
|
1441
|
+
# block → emit the matched flag_class; escape → escape_hatch_used.
|
|
1442
|
+
_emit_git_hook_bypass_event(_flag_class)
|
|
1443
|
+
# PLAN-133 A1 — emit env_var_hijack_blocked on ANY detected env-hijack
|
|
1444
|
+
# SET (enforced block OR advisory default-OFF detection). Re-scan to
|
|
1445
|
+
# recover the closed-enum hijack_class (decide_command stays pure). Only
|
|
1446
|
+
# the closed-enum class is persisted — never the var name/value.
|
|
1447
|
+
if not (decision.reason and "API credential" in decision.reason):
|
|
1448
|
+
env_hit = _check_env_hijack(command)
|
|
1449
|
+
if env_hit is not None:
|
|
1450
|
+
_hijack_class, _key, _reason = env_hit
|
|
1451
|
+
_emit_env_var_hijack_event(_hijack_class)
|
|
1452
|
+
# PLAN-133 A3 — egress-destination taxonomy. Classify EVERY command
|
|
1453
|
+
# (block OR allow — this emit tail runs on all paths) and emit one
|
|
1454
|
+
# egress_destination_detected per distinct (class, host). Default-OFF
|
|
1455
|
+
# via CEO_EGRESS_TAXONOMY_EMIT (advisory; A3 never blocks). The
|
|
1456
|
+
# destructive/credential/git-bypass blocks above do NOT gate this emit,
|
|
1457
|
+
# so a destructive+egress compound still records the egress.
|
|
1458
|
+
if _egress_emit_enabled():
|
|
1459
|
+
for _eclass, _edest in _classify_egress(command):
|
|
1460
|
+
_emit_egress_destination_event(_eclass, _edest)
|
|
1461
|
+
# PLAN-135 W2 H5 — when decide_command chose the corrective rewrite,
|
|
1462
|
+
# emit the bash_input_rewritten audit event with the before/after
|
|
1463
|
+
# hash PAIR BEFORE emitting the `ask` decision (mini-ADR-154 §2: the
|
|
1464
|
+
# audit records that the rail rewrote the input, so the downstream
|
|
1465
|
+
# audited command provably equals the executed/asked command). The
|
|
1466
|
+
# emit is fail-open (it never gates the decision).
|
|
1467
|
+
if decision.rewrite is not None:
|
|
1468
|
+
_emit_bash_input_rewritten_event(decision.rewrite)
|
|
1469
|
+
_claude_adapter.emit_decision(
|
|
1470
|
+
_to_contract_decision(decision, event.tool_input)
|
|
1471
|
+
)
|
|
1472
|
+
return 0
|
|
1473
|
+
except Exception as e: # pragma: no cover
|
|
1474
|
+
print(
|
|
1475
|
+
f"[check_bash_safety] FATAL: {e.__class__.__name__}: {e}",
|
|
1476
|
+
file=sys.stderr,
|
|
1477
|
+
)
|
|
1478
|
+
_claude_adapter.emit_decision(_contract.allow())
|
|
1479
|
+
return 0
|
|
1480
|
+
|
|
1481
|
+
|
|
1482
|
+
if __name__ == "__main__":
|
|
1483
|
+
sys.exit(main())
|