@jaguilar87/gaia 5.0.0-rc.2
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-plugin/marketplace.json +33 -0
- package/.claude-plugin/plugin.json +26 -0
- package/ARCHITECTURE.md +335 -0
- package/CHANGELOG.md +1298 -0
- package/CODE_OF_CONDUCT.md +11 -0
- package/CONTRIBUTING.md +146 -0
- package/INSTALL.md +436 -0
- package/LICENSE +21 -0
- package/README.md +222 -0
- package/SECURITY.md +47 -0
- package/agents/README.md +78 -0
- package/agents/cloud-troubleshooter.md +73 -0
- package/agents/developer.md +65 -0
- package/agents/gaia-operator.md +64 -0
- package/agents/gaia-orchestrator.md +111 -0
- package/agents/gaia-planner.md +53 -0
- package/agents/gaia-system.md +71 -0
- package/agents/gitops-operator.md +61 -0
- package/agents/terraform-architect.md +63 -0
- package/bin/README.md +106 -0
- package/bin/cli/__init__.py +1 -0
- package/bin/cli/approvals.py +740 -0
- package/bin/cli/cleanup.py +562 -0
- package/bin/cli/context.py +283 -0
- package/bin/cli/doctor.py +651 -0
- package/bin/cli/history.py +305 -0
- package/bin/cli/memory.py +483 -0
- package/bin/cli/metrics.py +1068 -0
- package/bin/cli/plans.py +515 -0
- package/bin/cli/status.py +302 -0
- package/bin/cli/update.py +382 -0
- package/bin/gaia +112 -0
- package/bin/gaia-cleanup.js +531 -0
- package/bin/gaia-doctor.js +635 -0
- package/bin/gaia-evidence +126 -0
- package/bin/gaia-history.js +251 -0
- package/bin/gaia-metrics.js +1278 -0
- package/bin/gaia-review.js +269 -0
- package/bin/gaia-scan +44 -0
- package/bin/gaia-scan.py +589 -0
- package/bin/gaia-skills-diagnose.js +929 -0
- package/bin/gaia-status.js +278 -0
- package/bin/gaia-uninstall.js +111 -0
- package/bin/gaia-update.js +919 -0
- package/bin/pre-publish-validate.js +610 -0
- package/bin/python-detect.js +60 -0
- package/bin/validate-sandbox.sh +601 -0
- package/commands/README.md +64 -0
- package/commands/gaia.md +37 -0
- package/commands/scan-project.md +67 -0
- package/config/README.md +71 -0
- package/config/cloud/aws.json +134 -0
- package/config/cloud/gcp.json +139 -0
- package/config/context-contracts.json +158 -0
- package/config/crons-schema.md +81 -0
- package/config/git_standards.json +72 -0
- package/config/surface-routing.json +417 -0
- package/config/universal-rules.json +102 -0
- package/dist/gaia-ops/.claude-plugin/plugin.json +24 -0
- package/dist/gaia-ops/README.md +80 -0
- package/dist/gaia-ops/agents/cloud-troubleshooter.md +73 -0
- package/dist/gaia-ops/agents/developer.md +65 -0
- package/dist/gaia-ops/agents/gaia-operator.md +64 -0
- package/dist/gaia-ops/agents/gaia-orchestrator.md +111 -0
- package/dist/gaia-ops/agents/gaia-planner.md +53 -0
- package/dist/gaia-ops/agents/gaia-system.md +71 -0
- package/dist/gaia-ops/agents/gitops-operator.md +61 -0
- package/dist/gaia-ops/agents/terraform-architect.md +63 -0
- package/dist/gaia-ops/commands/gaia.md +37 -0
- package/dist/gaia-ops/config/README.md +71 -0
- package/dist/gaia-ops/config/cloud/aws.json +134 -0
- package/dist/gaia-ops/config/cloud/gcp.json +139 -0
- package/dist/gaia-ops/config/context-contracts.json +158 -0
- package/dist/gaia-ops/config/crons-schema.md +81 -0
- package/dist/gaia-ops/config/git_standards.json +72 -0
- package/dist/gaia-ops/config/surface-routing.json +417 -0
- package/dist/gaia-ops/config/universal-rules.json +102 -0
- package/dist/gaia-ops/hooks/adapters/__init__.py +52 -0
- package/dist/gaia-ops/hooks/adapters/base.py +219 -0
- package/dist/gaia-ops/hooks/adapters/channel.py +17 -0
- package/dist/gaia-ops/hooks/adapters/claude_code.py +1890 -0
- package/dist/gaia-ops/hooks/adapters/types.py +194 -0
- package/dist/gaia-ops/hooks/adapters/utils.py +25 -0
- package/dist/gaia-ops/hooks/hooks.json +192 -0
- package/dist/gaia-ops/hooks/modules/__init__.py +15 -0
- package/dist/gaia-ops/hooks/modules/agents/__init__.py +29 -0
- package/dist/gaia-ops/hooks/modules/agents/contract_validator.py +647 -0
- package/dist/gaia-ops/hooks/modules/agents/response_contract.py +496 -0
- package/dist/gaia-ops/hooks/modules/agents/skill_injection_verifier.py +120 -0
- package/dist/gaia-ops/hooks/modules/agents/state_tracker.py +267 -0
- package/dist/gaia-ops/hooks/modules/agents/task_info_builder.py +74 -0
- package/dist/gaia-ops/hooks/modules/agents/transcript_analyzer.py +458 -0
- package/dist/gaia-ops/hooks/modules/agents/transcript_reader.py +152 -0
- package/dist/gaia-ops/hooks/modules/audit/__init__.py +28 -0
- package/dist/gaia-ops/hooks/modules/audit/event_detector.py +168 -0
- package/dist/gaia-ops/hooks/modules/audit/logger.py +131 -0
- package/dist/gaia-ops/hooks/modules/audit/metrics.py +134 -0
- package/dist/gaia-ops/hooks/modules/audit/workflow_auditor.py +611 -0
- package/dist/gaia-ops/hooks/modules/audit/workflow_recorder.py +296 -0
- package/dist/gaia-ops/hooks/modules/context/__init__.py +11 -0
- package/dist/gaia-ops/hooks/modules/context/agentic_loop_detector.py +165 -0
- package/dist/gaia-ops/hooks/modules/context/anchor_tracker.py +317 -0
- package/dist/gaia-ops/hooks/modules/context/compact_context_builder.py +218 -0
- package/dist/gaia-ops/hooks/modules/context/context_freshness.py +145 -0
- package/dist/gaia-ops/hooks/modules/context/context_injector.py +558 -0
- package/dist/gaia-ops/hooks/modules/context/context_writer.py +530 -0
- package/dist/gaia-ops/hooks/modules/context/contracts_loader.py +161 -0
- package/dist/gaia-ops/hooks/modules/core/__init__.py +40 -0
- package/dist/gaia-ops/hooks/modules/core/hook_entry.py +78 -0
- package/dist/gaia-ops/hooks/modules/core/paths.py +160 -0
- package/dist/gaia-ops/hooks/modules/core/plugin_mode.py +149 -0
- package/dist/gaia-ops/hooks/modules/core/plugin_setup.py +577 -0
- package/dist/gaia-ops/hooks/modules/core/state.py +179 -0
- package/dist/gaia-ops/hooks/modules/core/stdin.py +24 -0
- package/dist/gaia-ops/hooks/modules/events/__init__.py +1 -0
- package/dist/gaia-ops/hooks/modules/events/event_writer.py +210 -0
- package/dist/gaia-ops/hooks/modules/memory/__init__.py +8 -0
- package/dist/gaia-ops/hooks/modules/memory/episode_writer.py +216 -0
- package/dist/gaia-ops/hooks/modules/orchestrator/__init__.py +1 -0
- package/dist/gaia-ops/hooks/modules/orchestrator/delegate_mode.py +122 -0
- package/dist/gaia-ops/hooks/modules/scanning/__init__.py +8 -0
- package/dist/gaia-ops/hooks/modules/scanning/scan_trigger.py +84 -0
- package/dist/gaia-ops/hooks/modules/security/__init__.py +120 -0
- package/dist/gaia-ops/hooks/modules/security/approval_cleanup.py +87 -0
- package/dist/gaia-ops/hooks/modules/security/approval_constants.py +23 -0
- package/dist/gaia-ops/hooks/modules/security/approval_grants.py +1638 -0
- package/dist/gaia-ops/hooks/modules/security/approval_messages.py +71 -0
- package/dist/gaia-ops/hooks/modules/security/approval_scopes.py +222 -0
- package/dist/gaia-ops/hooks/modules/security/blocked_commands.py +595 -0
- package/dist/gaia-ops/hooks/modules/security/blocked_message_formatter.py +87 -0
- package/dist/gaia-ops/hooks/modules/security/command_semantics.py +181 -0
- package/dist/gaia-ops/hooks/modules/security/composition_rules.py +547 -0
- package/dist/gaia-ops/hooks/modules/security/flag_classifiers.py +873 -0
- package/dist/gaia-ops/hooks/modules/security/gitops_validator.py +179 -0
- package/dist/gaia-ops/hooks/modules/security/mutative_verbs.py +1131 -0
- package/dist/gaia-ops/hooks/modules/security/network_hosts.py +481 -0
- package/dist/gaia-ops/hooks/modules/security/prompt_validator.py +40 -0
- package/dist/gaia-ops/hooks/modules/security/shell_unwrapper.py +165 -0
- package/dist/gaia-ops/hooks/modules/security/tiers.py +196 -0
- package/dist/gaia-ops/hooks/modules/session/__init__.py +10 -0
- package/dist/gaia-ops/hooks/modules/session/pending_scanner.py +174 -0
- package/dist/gaia-ops/hooks/modules/session/session_context_writer.py +100 -0
- package/dist/gaia-ops/hooks/modules/session/session_event_injector.py +160 -0
- package/dist/gaia-ops/hooks/modules/session/session_manager.py +31 -0
- package/dist/gaia-ops/hooks/modules/session/session_registry.py +333 -0
- package/dist/gaia-ops/hooks/modules/tools/__init__.py +29 -0
- package/dist/gaia-ops/hooks/modules/tools/bash_validator.py +1008 -0
- package/dist/gaia-ops/hooks/modules/tools/cloud_pipe_validator.py +231 -0
- package/dist/gaia-ops/hooks/modules/tools/hook_response.py +55 -0
- package/dist/gaia-ops/hooks/modules/tools/shell_parser.py +227 -0
- package/dist/gaia-ops/hooks/modules/tools/stage_decomposer.py +315 -0
- package/dist/gaia-ops/hooks/modules/tools/task_validator.py +294 -0
- package/dist/gaia-ops/hooks/modules/validation/__init__.py +23 -0
- package/dist/gaia-ops/hooks/modules/validation/commit_validator.py +380 -0
- package/dist/gaia-ops/hooks/post_compact.py +43 -0
- package/dist/gaia-ops/hooks/post_tool_use.py +54 -0
- package/dist/gaia-ops/hooks/pre_compact.py +60 -0
- package/dist/gaia-ops/hooks/pre_tool_use.py +413 -0
- package/dist/gaia-ops/hooks/session_end_hook.py +77 -0
- package/dist/gaia-ops/hooks/session_start.py +81 -0
- package/dist/gaia-ops/hooks/stop_hook.py +70 -0
- package/dist/gaia-ops/hooks/subagent_start.py +71 -0
- package/dist/gaia-ops/hooks/subagent_stop.py +295 -0
- package/dist/gaia-ops/hooks/task_completed.py +70 -0
- package/dist/gaia-ops/hooks/user_prompt_submit.py +246 -0
- package/dist/gaia-ops/settings.json +72 -0
- package/dist/gaia-ops/skills/README.md +158 -0
- package/dist/gaia-ops/skills/agent-creation/SKILL.md +87 -0
- package/dist/gaia-ops/skills/agent-creation/examples.md +170 -0
- package/dist/gaia-ops/skills/agent-creation/reference.md +191 -0
- package/dist/gaia-ops/skills/agent-protocol/SKILL.md +93 -0
- package/dist/gaia-ops/skills/agent-protocol/examples.md +223 -0
- package/dist/gaia-ops/skills/agent-response/SKILL.md +69 -0
- package/dist/gaia-ops/skills/agentic-loop/SKILL.md +80 -0
- package/dist/gaia-ops/skills/agentic-loop/reference.md +378 -0
- package/dist/gaia-ops/skills/blog-writing/SKILL.md +98 -0
- package/dist/gaia-ops/skills/blog-writing/reference.md +130 -0
- package/dist/gaia-ops/skills/brief-spec/SKILL.md +185 -0
- package/dist/gaia-ops/skills/command-execution/SKILL.md +64 -0
- package/dist/gaia-ops/skills/command-execution/reference.md +83 -0
- package/dist/gaia-ops/skills/context-updater/SKILL.md +87 -0
- package/dist/gaia-ops/skills/context-updater/examples.md +71 -0
- package/dist/gaia-ops/skills/developer-patterns/SKILL.md +50 -0
- package/dist/gaia-ops/skills/developer-patterns/reference.md +112 -0
- package/dist/gaia-ops/skills/execution/SKILL.md +99 -0
- package/dist/gaia-ops/skills/fast-queries/SKILL.md +43 -0
- package/dist/gaia-ops/skills/gaia-compact/SKILL.md +74 -0
- package/dist/gaia-ops/skills/gaia-patterns/SKILL.md +108 -0
- package/dist/gaia-ops/skills/gaia-patterns/reference.md +395 -0
- package/dist/gaia-ops/skills/gaia-planner/SKILL.md +37 -0
- package/dist/gaia-ops/skills/gaia-planner/reference.md +107 -0
- package/dist/gaia-ops/skills/gaia-release/SKILL.md +85 -0
- package/dist/gaia-ops/skills/gaia-release/reference.md +92 -0
- package/dist/gaia-ops/skills/gaia-self-check/SKILL.md +114 -0
- package/dist/gaia-ops/skills/gaia-self-check/reference.md +453 -0
- package/dist/gaia-ops/skills/gaia-verify/SKILL.md +77 -0
- package/dist/gaia-ops/skills/gaia-verify/reference.md +80 -0
- package/dist/gaia-ops/skills/git-conventions/SKILL.md +47 -0
- package/dist/gaia-ops/skills/gitops-patterns/SKILL.md +60 -0
- package/dist/gaia-ops/skills/gitops-patterns/reference.md +183 -0
- package/dist/gaia-ops/skills/gmail-policy/SKILL.md +200 -0
- package/dist/gaia-ops/skills/gmail-policy/reference.md +150 -0
- package/dist/gaia-ops/skills/gmail-triage/SKILL.md +100 -0
- package/dist/gaia-ops/skills/gws-setup/SKILL.md +99 -0
- package/dist/gaia-ops/skills/gws-setup/reference.md +73 -0
- package/dist/gaia-ops/skills/investigation/SKILL.md +100 -0
- package/dist/gaia-ops/skills/memory-curation/SKILL.md +83 -0
- package/dist/gaia-ops/skills/memory-search/SKILL.md +88 -0
- package/dist/gaia-ops/skills/orchestrator-approval/SKILL.md +160 -0
- package/dist/gaia-ops/skills/orchestrator-approval/reference.md +174 -0
- package/dist/gaia-ops/skills/pending-approvals/SKILL.md +72 -0
- package/dist/gaia-ops/skills/pending-approvals/reference.md +214 -0
- package/dist/gaia-ops/skills/readme-writing/SKILL.md +71 -0
- package/dist/gaia-ops/skills/readme-writing/reference.md +188 -0
- package/dist/gaia-ops/skills/reference.md +135 -0
- package/dist/gaia-ops/skills/request-approval/SKILL.md +140 -0
- package/dist/gaia-ops/skills/request-approval/examples.md +140 -0
- package/dist/gaia-ops/skills/request-approval/reference.md +57 -0
- package/dist/gaia-ops/skills/schedule-task/SKILL.md +64 -0
- package/dist/gaia-ops/skills/schedule-task/reference.md +233 -0
- package/dist/gaia-ops/skills/security-tiers/SKILL.md +141 -0
- package/dist/gaia-ops/skills/security-tiers/destructive-commands-reference.md +623 -0
- package/dist/gaia-ops/skills/security-tiers/reference.md +39 -0
- package/dist/gaia-ops/skills/session-reflection/SKILL.md +69 -0
- package/dist/gaia-ops/skills/skill-creation/SKILL.md +92 -0
- package/dist/gaia-ops/skills/skill-creation/reference.md +29 -0
- package/dist/gaia-ops/skills/terraform-patterns/SKILL.md +89 -0
- package/dist/gaia-ops/skills/terraform-patterns/reference.md +93 -0
- package/dist/gaia-ops/tools/__init__.py +9 -0
- package/dist/gaia-ops/tools/agentic-loop/decide-status.py +210 -0
- package/dist/gaia-ops/tools/agentic-loop/parse-metric.py +106 -0
- package/dist/gaia-ops/tools/agentic-loop/record-iteration.py +221 -0
- package/dist/gaia-ops/tools/context/README.md +132 -0
- package/dist/gaia-ops/tools/context/__init__.py +42 -0
- package/dist/gaia-ops/tools/context/_paths.py +20 -0
- package/dist/gaia-ops/tools/context/context_provider.py +721 -0
- package/dist/gaia-ops/tools/context/context_section_reader.py +342 -0
- package/dist/gaia-ops/tools/context/deep_merge.py +159 -0
- package/dist/gaia-ops/tools/context/pending_updates.py +760 -0
- package/dist/gaia-ops/tools/context/surface_router.py +278 -0
- package/dist/gaia-ops/tools/fast-queries/README.md +65 -0
- package/dist/gaia-ops/tools/fast-queries/__init__.py +30 -0
- package/dist/gaia-ops/tools/fast-queries/appservices/quicktriage_devops_developer.sh +75 -0
- package/dist/gaia-ops/tools/fast-queries/cloud/aws/quicktriage_aws_troubleshooter.sh +32 -0
- package/dist/gaia-ops/tools/fast-queries/cloud/gcp/quicktriage_gcp_troubleshooter.sh +88 -0
- package/dist/gaia-ops/tools/fast-queries/gitops/quicktriage_gitops_operator.sh +48 -0
- package/dist/gaia-ops/tools/fast-queries/run_triage.sh +59 -0
- package/dist/gaia-ops/tools/fast-queries/terraform/quicktriage_terraform_architect.sh +80 -0
- package/dist/gaia-ops/tools/gaia_simulator/__init__.py +33 -0
- package/dist/gaia-ops/tools/gaia_simulator/cli.py +354 -0
- package/dist/gaia-ops/tools/gaia_simulator/extractor.py +457 -0
- package/dist/gaia-ops/tools/gaia_simulator/reporter.py +258 -0
- package/dist/gaia-ops/tools/gaia_simulator/routing_simulator.py +334 -0
- package/dist/gaia-ops/tools/gaia_simulator/runner.py +539 -0
- package/dist/gaia-ops/tools/gaia_simulator/skills_mapper.py +264 -0
- package/dist/gaia-ops/tools/memory/README.md +0 -0
- package/dist/gaia-ops/tools/memory/__init__.py +20 -0
- package/dist/gaia-ops/tools/memory/backfill_fts5.py +107 -0
- package/dist/gaia-ops/tools/memory/conflict_detector.py +295 -0
- package/dist/gaia-ops/tools/memory/episodic.py +1210 -0
- package/dist/gaia-ops/tools/memory/git_invalidator.py +262 -0
- package/dist/gaia-ops/tools/memory/paths.py +102 -0
- package/dist/gaia-ops/tools/memory/scoring.py +193 -0
- package/dist/gaia-ops/tools/memory/search_store.py +375 -0
- package/dist/gaia-ops/tools/persist_transcript_analysis.py +85 -0
- package/dist/gaia-ops/tools/review/__init__.py +1 -0
- package/dist/gaia-ops/tools/review/review_engine.py +157 -0
- package/dist/gaia-ops/tools/scan/__init__.py +35 -0
- package/dist/gaia-ops/tools/scan/config.py +247 -0
- package/dist/gaia-ops/tools/scan/merge.py +212 -0
- package/dist/gaia-ops/tools/scan/orchestrator.py +549 -0
- package/dist/gaia-ops/tools/scan/registry.py +127 -0
- package/dist/gaia-ops/tools/scan/scanners/__init__.py +18 -0
- package/dist/gaia-ops/tools/scan/scanners/base.py +137 -0
- package/dist/gaia-ops/tools/scan/scanners/environment.py +349 -0
- package/dist/gaia-ops/tools/scan/scanners/git.py +570 -0
- package/dist/gaia-ops/tools/scan/scanners/infrastructure.py +875 -0
- package/dist/gaia-ops/tools/scan/scanners/orchestration.py +600 -0
- package/dist/gaia-ops/tools/scan/scanners/stack.py +1085 -0
- package/dist/gaia-ops/tools/scan/scanners/tools.py +260 -0
- package/dist/gaia-ops/tools/scan/setup.py +686 -0
- package/dist/gaia-ops/tools/scan/tests/__init__.py +1 -0
- package/dist/gaia-ops/tools/scan/tests/conftest.py +796 -0
- package/dist/gaia-ops/tools/scan/tests/test_environment.py +323 -0
- package/dist/gaia-ops/tools/scan/tests/test_git.py +419 -0
- package/dist/gaia-ops/tools/scan/tests/test_infrastructure.py +382 -0
- package/dist/gaia-ops/tools/scan/tests/test_integration.py +920 -0
- package/dist/gaia-ops/tools/scan/tests/test_merge.py +269 -0
- package/dist/gaia-ops/tools/scan/tests/test_orchestration.py +304 -0
- package/dist/gaia-ops/tools/scan/tests/test_stack.py +604 -0
- package/dist/gaia-ops/tools/scan/tests/test_tools.py +349 -0
- package/dist/gaia-ops/tools/scan/ui.py +624 -0
- package/dist/gaia-ops/tools/scan/verify.py +270 -0
- package/dist/gaia-ops/tools/scan/walk.py +118 -0
- package/dist/gaia-ops/tools/scan/workspace.py +85 -0
- package/dist/gaia-ops/tools/validation/README.md +244 -0
- package/dist/gaia-ops/tools/validation/__init__.py +17 -0
- package/dist/gaia-ops/tools/validation/approval_gate.py +321 -0
- package/dist/gaia-ops/tools/validation/validate_skills.py +189 -0
- package/dist/gaia-security/.claude-plugin/plugin.json +24 -0
- package/dist/gaia-security/README.md +90 -0
- package/dist/gaia-security/config/universal-rules.json +102 -0
- package/dist/gaia-security/hooks/adapters/__init__.py +52 -0
- package/dist/gaia-security/hooks/adapters/base.py +219 -0
- package/dist/gaia-security/hooks/adapters/channel.py +17 -0
- package/dist/gaia-security/hooks/adapters/claude_code.py +1890 -0
- package/dist/gaia-security/hooks/adapters/types.py +194 -0
- package/dist/gaia-security/hooks/adapters/utils.py +25 -0
- package/dist/gaia-security/hooks/hooks.json +113 -0
- package/dist/gaia-security/hooks/modules/__init__.py +15 -0
- package/dist/gaia-security/hooks/modules/agents/__init__.py +29 -0
- package/dist/gaia-security/hooks/modules/agents/contract_validator.py +647 -0
- package/dist/gaia-security/hooks/modules/agents/response_contract.py +496 -0
- package/dist/gaia-security/hooks/modules/agents/skill_injection_verifier.py +120 -0
- package/dist/gaia-security/hooks/modules/agents/state_tracker.py +267 -0
- package/dist/gaia-security/hooks/modules/agents/task_info_builder.py +74 -0
- package/dist/gaia-security/hooks/modules/agents/transcript_analyzer.py +458 -0
- package/dist/gaia-security/hooks/modules/agents/transcript_reader.py +152 -0
- package/dist/gaia-security/hooks/modules/audit/__init__.py +28 -0
- package/dist/gaia-security/hooks/modules/audit/event_detector.py +168 -0
- package/dist/gaia-security/hooks/modules/audit/logger.py +131 -0
- package/dist/gaia-security/hooks/modules/audit/metrics.py +134 -0
- package/dist/gaia-security/hooks/modules/audit/workflow_auditor.py +611 -0
- package/dist/gaia-security/hooks/modules/audit/workflow_recorder.py +296 -0
- package/dist/gaia-security/hooks/modules/context/__init__.py +11 -0
- package/dist/gaia-security/hooks/modules/context/agentic_loop_detector.py +165 -0
- package/dist/gaia-security/hooks/modules/context/anchor_tracker.py +317 -0
- package/dist/gaia-security/hooks/modules/context/compact_context_builder.py +218 -0
- package/dist/gaia-security/hooks/modules/context/context_freshness.py +145 -0
- package/dist/gaia-security/hooks/modules/context/context_injector.py +558 -0
- package/dist/gaia-security/hooks/modules/context/context_writer.py +530 -0
- package/dist/gaia-security/hooks/modules/context/contracts_loader.py +161 -0
- package/dist/gaia-security/hooks/modules/core/__init__.py +40 -0
- package/dist/gaia-security/hooks/modules/core/hook_entry.py +78 -0
- package/dist/gaia-security/hooks/modules/core/paths.py +160 -0
- package/dist/gaia-security/hooks/modules/core/plugin_mode.py +149 -0
- package/dist/gaia-security/hooks/modules/core/plugin_setup.py +577 -0
- package/dist/gaia-security/hooks/modules/core/state.py +179 -0
- package/dist/gaia-security/hooks/modules/core/stdin.py +24 -0
- package/dist/gaia-security/hooks/modules/events/__init__.py +1 -0
- package/dist/gaia-security/hooks/modules/events/event_writer.py +210 -0
- package/dist/gaia-security/hooks/modules/memory/__init__.py +8 -0
- package/dist/gaia-security/hooks/modules/memory/episode_writer.py +216 -0
- package/dist/gaia-security/hooks/modules/orchestrator/__init__.py +1 -0
- package/dist/gaia-security/hooks/modules/orchestrator/delegate_mode.py +122 -0
- package/dist/gaia-security/hooks/modules/scanning/__init__.py +8 -0
- package/dist/gaia-security/hooks/modules/scanning/scan_trigger.py +84 -0
- package/dist/gaia-security/hooks/modules/security/__init__.py +120 -0
- package/dist/gaia-security/hooks/modules/security/approval_cleanup.py +87 -0
- package/dist/gaia-security/hooks/modules/security/approval_constants.py +23 -0
- package/dist/gaia-security/hooks/modules/security/approval_grants.py +1638 -0
- package/dist/gaia-security/hooks/modules/security/approval_messages.py +71 -0
- package/dist/gaia-security/hooks/modules/security/approval_scopes.py +222 -0
- package/dist/gaia-security/hooks/modules/security/blocked_commands.py +595 -0
- package/dist/gaia-security/hooks/modules/security/blocked_message_formatter.py +87 -0
- package/dist/gaia-security/hooks/modules/security/command_semantics.py +181 -0
- package/dist/gaia-security/hooks/modules/security/composition_rules.py +547 -0
- package/dist/gaia-security/hooks/modules/security/flag_classifiers.py +873 -0
- package/dist/gaia-security/hooks/modules/security/gitops_validator.py +179 -0
- package/dist/gaia-security/hooks/modules/security/mutative_verbs.py +1131 -0
- package/dist/gaia-security/hooks/modules/security/network_hosts.py +481 -0
- package/dist/gaia-security/hooks/modules/security/prompt_validator.py +40 -0
- package/dist/gaia-security/hooks/modules/security/shell_unwrapper.py +165 -0
- package/dist/gaia-security/hooks/modules/security/tiers.py +196 -0
- package/dist/gaia-security/hooks/modules/session/__init__.py +10 -0
- package/dist/gaia-security/hooks/modules/session/pending_scanner.py +174 -0
- package/dist/gaia-security/hooks/modules/session/session_context_writer.py +100 -0
- package/dist/gaia-security/hooks/modules/session/session_event_injector.py +160 -0
- package/dist/gaia-security/hooks/modules/session/session_manager.py +31 -0
- package/dist/gaia-security/hooks/modules/session/session_registry.py +333 -0
- package/dist/gaia-security/hooks/modules/tools/__init__.py +29 -0
- package/dist/gaia-security/hooks/modules/tools/bash_validator.py +1008 -0
- package/dist/gaia-security/hooks/modules/tools/cloud_pipe_validator.py +231 -0
- package/dist/gaia-security/hooks/modules/tools/hook_response.py +55 -0
- package/dist/gaia-security/hooks/modules/tools/shell_parser.py +227 -0
- package/dist/gaia-security/hooks/modules/tools/stage_decomposer.py +315 -0
- package/dist/gaia-security/hooks/modules/tools/task_validator.py +294 -0
- package/dist/gaia-security/hooks/modules/validation/__init__.py +23 -0
- package/dist/gaia-security/hooks/modules/validation/commit_validator.py +380 -0
- package/dist/gaia-security/hooks/post_tool_use.py +54 -0
- package/dist/gaia-security/hooks/pre_tool_use.py +413 -0
- package/dist/gaia-security/hooks/session_end_hook.py +77 -0
- package/dist/gaia-security/hooks/session_start.py +81 -0
- package/dist/gaia-security/hooks/stop_hook.py +70 -0
- package/dist/gaia-security/hooks/user_prompt_submit.py +246 -0
- package/dist/gaia-security/settings.json +58 -0
- package/git-hooks/commit-msg +41 -0
- package/hooks/README.md +100 -0
- package/hooks/adapters/__init__.py +52 -0
- package/hooks/adapters/base.py +219 -0
- package/hooks/adapters/channel.py +17 -0
- package/hooks/adapters/claude_code.py +1890 -0
- package/hooks/adapters/types.py +194 -0
- package/hooks/adapters/utils.py +25 -0
- package/hooks/elicitation_result.py +179 -0
- package/hooks/hooks.json +84 -0
- package/hooks/modules/README.md +189 -0
- package/hooks/modules/__init__.py +15 -0
- package/hooks/modules/agents/__init__.py +29 -0
- package/hooks/modules/agents/contract_validator.py +647 -0
- package/hooks/modules/agents/response_contract.py +496 -0
- package/hooks/modules/agents/skill_injection_verifier.py +120 -0
- package/hooks/modules/agents/state_tracker.py +267 -0
- package/hooks/modules/agents/task_info_builder.py +74 -0
- package/hooks/modules/agents/transcript_analyzer.py +458 -0
- package/hooks/modules/agents/transcript_reader.py +152 -0
- package/hooks/modules/audit/__init__.py +28 -0
- package/hooks/modules/audit/event_detector.py +168 -0
- package/hooks/modules/audit/logger.py +131 -0
- package/hooks/modules/audit/metrics.py +134 -0
- package/hooks/modules/audit/workflow_auditor.py +611 -0
- package/hooks/modules/audit/workflow_recorder.py +296 -0
- package/hooks/modules/context/__init__.py +11 -0
- package/hooks/modules/context/agentic_loop_detector.py +165 -0
- package/hooks/modules/context/anchor_tracker.py +317 -0
- package/hooks/modules/context/compact_context_builder.py +218 -0
- package/hooks/modules/context/context_freshness.py +145 -0
- package/hooks/modules/context/context_injector.py +558 -0
- package/hooks/modules/context/context_writer.py +530 -0
- package/hooks/modules/context/contracts_loader.py +161 -0
- package/hooks/modules/core/__init__.py +40 -0
- package/hooks/modules/core/hook_entry.py +78 -0
- package/hooks/modules/core/paths.py +160 -0
- package/hooks/modules/core/plugin_mode.py +149 -0
- package/hooks/modules/core/plugin_setup.py +577 -0
- package/hooks/modules/core/state.py +179 -0
- package/hooks/modules/core/stdin.py +24 -0
- package/hooks/modules/events/__init__.py +1 -0
- package/hooks/modules/events/event_writer.py +210 -0
- package/hooks/modules/evidence/__init__.py +34 -0
- package/hooks/modules/evidence/assertions.py +137 -0
- package/hooks/modules/evidence/index_writer.py +57 -0
- package/hooks/modules/evidence/loader.py +126 -0
- package/hooks/modules/evidence/runner.py +241 -0
- package/hooks/modules/memory/__init__.py +8 -0
- package/hooks/modules/memory/episode_writer.py +216 -0
- package/hooks/modules/orchestrator/__init__.py +1 -0
- package/hooks/modules/orchestrator/delegate_mode.py +122 -0
- package/hooks/modules/scanning/__init__.py +8 -0
- package/hooks/modules/scanning/scan_trigger.py +84 -0
- package/hooks/modules/security/__init__.py +120 -0
- package/hooks/modules/security/approval_cleanup.py +87 -0
- package/hooks/modules/security/approval_constants.py +23 -0
- package/hooks/modules/security/approval_grants.py +1638 -0
- package/hooks/modules/security/approval_messages.py +71 -0
- package/hooks/modules/security/approval_scopes.py +222 -0
- package/hooks/modules/security/blocked_commands.py +595 -0
- package/hooks/modules/security/blocked_message_formatter.py +87 -0
- package/hooks/modules/security/command_semantics.py +181 -0
- package/hooks/modules/security/composition_rules.py +547 -0
- package/hooks/modules/security/flag_classifiers.py +873 -0
- package/hooks/modules/security/gitops_validator.py +179 -0
- package/hooks/modules/security/mutative_verbs.py +1131 -0
- package/hooks/modules/security/network_hosts.py +481 -0
- package/hooks/modules/security/prompt_validator.py +40 -0
- package/hooks/modules/security/shell_unwrapper.py +165 -0
- package/hooks/modules/security/tiers.py +196 -0
- package/hooks/modules/session/__init__.py +10 -0
- package/hooks/modules/session/pending_scanner.py +174 -0
- package/hooks/modules/session/session_context_writer.py +100 -0
- package/hooks/modules/session/session_event_injector.py +160 -0
- package/hooks/modules/session/session_manager.py +31 -0
- package/hooks/modules/session/session_registry.py +333 -0
- package/hooks/modules/tools/__init__.py +29 -0
- package/hooks/modules/tools/bash_validator.py +1008 -0
- package/hooks/modules/tools/cloud_pipe_validator.py +231 -0
- package/hooks/modules/tools/hook_response.py +55 -0
- package/hooks/modules/tools/shell_parser.py +227 -0
- package/hooks/modules/tools/stage_decomposer.py +315 -0
- package/hooks/modules/tools/task_validator.py +294 -0
- package/hooks/modules/validation/__init__.py +23 -0
- package/hooks/modules/validation/commit_validator.py +380 -0
- package/hooks/post_compact.py +43 -0
- package/hooks/post_tool_use.py +54 -0
- package/hooks/pre_compact.py +60 -0
- package/hooks/pre_tool_use.py +413 -0
- package/hooks/session_end_hook.py +77 -0
- package/hooks/session_start.py +81 -0
- package/hooks/stop_hook.py +70 -0
- package/hooks/subagent_start.py +71 -0
- package/hooks/subagent_stop.py +295 -0
- package/hooks/task_completed.py +70 -0
- package/hooks/user_prompt_submit.py +246 -0
- package/index.js +83 -0
- package/package.json +103 -0
- package/pyproject.toml +32 -0
- package/skills/README.md +158 -0
- package/skills/agent-creation/SKILL.md +87 -0
- package/skills/agent-creation/examples.md +170 -0
- package/skills/agent-creation/reference.md +191 -0
- package/skills/agent-protocol/SKILL.md +93 -0
- package/skills/agent-protocol/examples.md +223 -0
- package/skills/agent-response/SKILL.md +69 -0
- package/skills/agentic-loop/SKILL.md +80 -0
- package/skills/agentic-loop/reference.md +378 -0
- package/skills/blog-writing/SKILL.md +98 -0
- package/skills/blog-writing/reference.md +130 -0
- package/skills/brief-spec/SKILL.md +185 -0
- package/skills/command-execution/SKILL.md +64 -0
- package/skills/command-execution/reference.md +83 -0
- package/skills/context-updater/SKILL.md +87 -0
- package/skills/context-updater/examples.md +71 -0
- package/skills/developer-patterns/SKILL.md +50 -0
- package/skills/developer-patterns/reference.md +112 -0
- package/skills/execution/SKILL.md +99 -0
- package/skills/fast-queries/SKILL.md +43 -0
- package/skills/gaia-compact/SKILL.md +74 -0
- package/skills/gaia-patterns/SKILL.md +108 -0
- package/skills/gaia-patterns/reference.md +395 -0
- package/skills/gaia-planner/SKILL.md +37 -0
- package/skills/gaia-planner/reference.md +107 -0
- package/skills/gaia-release/SKILL.md +85 -0
- package/skills/gaia-release/reference.md +92 -0
- package/skills/gaia-self-check/SKILL.md +114 -0
- package/skills/gaia-self-check/reference.md +453 -0
- package/skills/gaia-verify/SKILL.md +77 -0
- package/skills/gaia-verify/reference.md +80 -0
- package/skills/git-conventions/SKILL.md +47 -0
- package/skills/gitops-patterns/SKILL.md +60 -0
- package/skills/gitops-patterns/reference.md +183 -0
- package/skills/gmail-policy/SKILL.md +200 -0
- package/skills/gmail-policy/reference.md +150 -0
- package/skills/gmail-triage/SKILL.md +100 -0
- package/skills/gws-setup/SKILL.md +99 -0
- package/skills/gws-setup/reference.md +73 -0
- package/skills/investigation/SKILL.md +100 -0
- package/skills/memory-curation/SKILL.md +83 -0
- package/skills/memory-search/SKILL.md +88 -0
- package/skills/orchestrator-approval/SKILL.md +160 -0
- package/skills/orchestrator-approval/reference.md +174 -0
- package/skills/pending-approvals/SKILL.md +72 -0
- package/skills/pending-approvals/reference.md +214 -0
- package/skills/readme-writing/SKILL.md +71 -0
- package/skills/readme-writing/reference.md +188 -0
- package/skills/reference.md +135 -0
- package/skills/request-approval/SKILL.md +140 -0
- package/skills/request-approval/examples.md +140 -0
- package/skills/request-approval/reference.md +57 -0
- package/skills/schedule-task/SKILL.md +64 -0
- package/skills/schedule-task/reference.md +233 -0
- package/skills/security-tiers/SKILL.md +141 -0
- package/skills/security-tiers/destructive-commands-reference.md +623 -0
- package/skills/security-tiers/reference.md +39 -0
- package/skills/session-reflection/SKILL.md +69 -0
- package/skills/skill-creation/SKILL.md +92 -0
- package/skills/skill-creation/reference.md +29 -0
- package/skills/terraform-patterns/SKILL.md +89 -0
- package/skills/terraform-patterns/reference.md +93 -0
- package/templates/README.md +69 -0
- package/templates/managed-settings.template.json +43 -0
- package/tools/__init__.py +9 -0
- package/tools/agentic-loop/decide-status.py +210 -0
- package/tools/agentic-loop/parse-metric.py +106 -0
- package/tools/agentic-loop/record-iteration.py +221 -0
- package/tools/context/README.md +132 -0
- package/tools/context/__init__.py +42 -0
- package/tools/context/_paths.py +20 -0
- package/tools/context/context_provider.py +721 -0
- package/tools/context/context_section_reader.py +342 -0
- package/tools/context/deep_merge.py +159 -0
- package/tools/context/pending_updates.py +760 -0
- package/tools/context/surface_router.py +278 -0
- package/tools/fast-queries/README.md +65 -0
- package/tools/fast-queries/__init__.py +30 -0
- package/tools/fast-queries/appservices/quicktriage_devops_developer.sh +75 -0
- package/tools/fast-queries/cloud/aws/quicktriage_aws_troubleshooter.sh +32 -0
- package/tools/fast-queries/cloud/gcp/quicktriage_gcp_troubleshooter.sh +88 -0
- package/tools/fast-queries/gitops/quicktriage_gitops_operator.sh +48 -0
- package/tools/fast-queries/run_triage.sh +59 -0
- package/tools/fast-queries/terraform/quicktriage_terraform_architect.sh +80 -0
- package/tools/gaia_simulator/__init__.py +33 -0
- package/tools/gaia_simulator/cli.py +354 -0
- package/tools/gaia_simulator/extractor.py +457 -0
- package/tools/gaia_simulator/reporter.py +258 -0
- package/tools/gaia_simulator/routing_simulator.py +334 -0
- package/tools/gaia_simulator/runner.py +539 -0
- package/tools/gaia_simulator/skills_mapper.py +264 -0
- package/tools/memory/README.md +0 -0
- package/tools/memory/__init__.py +20 -0
- package/tools/memory/backfill_fts5.py +107 -0
- package/tools/memory/conflict_detector.py +295 -0
- package/tools/memory/episodic.py +1210 -0
- package/tools/memory/git_invalidator.py +262 -0
- package/tools/memory/paths.py +102 -0
- package/tools/memory/scoring.py +193 -0
- package/tools/memory/search_store.py +375 -0
- package/tools/persist_transcript_analysis.py +85 -0
- package/tools/review/__init__.py +1 -0
- package/tools/review/review_engine.py +157 -0
- package/tools/scan/__init__.py +35 -0
- package/tools/scan/config.py +247 -0
- package/tools/scan/merge.py +212 -0
- package/tools/scan/orchestrator.py +549 -0
- package/tools/scan/registry.py +127 -0
- package/tools/scan/scanners/__init__.py +18 -0
- package/tools/scan/scanners/base.py +137 -0
- package/tools/scan/scanners/environment.py +349 -0
- package/tools/scan/scanners/git.py +570 -0
- package/tools/scan/scanners/infrastructure.py +875 -0
- package/tools/scan/scanners/orchestration.py +600 -0
- package/tools/scan/scanners/stack.py +1085 -0
- package/tools/scan/scanners/tools.py +260 -0
- package/tools/scan/setup.py +686 -0
- package/tools/scan/tests/__init__.py +1 -0
- package/tools/scan/tests/conftest.py +796 -0
- package/tools/scan/tests/test_environment.py +323 -0
- package/tools/scan/tests/test_git.py +419 -0
- package/tools/scan/tests/test_infrastructure.py +382 -0
- package/tools/scan/tests/test_integration.py +920 -0
- package/tools/scan/tests/test_merge.py +269 -0
- package/tools/scan/tests/test_orchestration.py +304 -0
- package/tools/scan/tests/test_stack.py +604 -0
- package/tools/scan/tests/test_tools.py +349 -0
- package/tools/scan/ui.py +624 -0
- package/tools/scan/verify.py +270 -0
- package/tools/scan/walk.py +118 -0
- package/tools/scan/workspace.py +85 -0
- package/tools/validation/README.md +244 -0
- package/tools/validation/__init__.py +17 -0
- package/tools/validation/approval_gate.py +321 -0
- package/tools/validation/validate_skills.py +189 -0
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Adapter Normalized Types for Gaia-Ops Hooks.
|
|
3
|
+
|
|
4
|
+
CLI-agnostic frozen dataclasses and enums consumed by business logic modules.
|
|
5
|
+
The adapter layer translates between these types and CLI-specific JSON protocols.
|
|
6
|
+
|
|
7
|
+
No dependencies on any existing gaia-ops module -- this is standalone.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import enum
|
|
13
|
+
from dataclasses import dataclass, field
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
from typing import Any, Dict, List, Optional
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class HookEventType(enum.Enum):
|
|
19
|
+
"""All Claude Code hook events as an enumeration."""
|
|
20
|
+
|
|
21
|
+
# P0 - Currently implemented
|
|
22
|
+
PRE_TOOL_USE = "PreToolUse"
|
|
23
|
+
POST_TOOL_USE = "PostToolUse"
|
|
24
|
+
SUBAGENT_STOP = "SubagentStop"
|
|
25
|
+
|
|
26
|
+
# P1
|
|
27
|
+
SESSION_START = "SessionStart"
|
|
28
|
+
USER_PROMPT_SUBMIT = "UserPromptSubmit"
|
|
29
|
+
|
|
30
|
+
# P2
|
|
31
|
+
PERMISSION_REQUEST = "PermissionRequest"
|
|
32
|
+
STOP = "Stop"
|
|
33
|
+
TASK_COMPLETED = "TaskCompleted"
|
|
34
|
+
SUBAGENT_START = "SubagentStart"
|
|
35
|
+
|
|
36
|
+
# P3
|
|
37
|
+
PRE_COMPACT = "PreCompact"
|
|
38
|
+
POST_COMPACT = "PostCompact"
|
|
39
|
+
CONFIG_CHANGE = "ConfigChange"
|
|
40
|
+
SESSION_END = "SessionEnd"
|
|
41
|
+
INSTRUCTIONS_LOADED = "InstructionsLoaded"
|
|
42
|
+
POST_TOOL_USE_FAILURE = "PostToolUseFailure"
|
|
43
|
+
|
|
44
|
+
# P4
|
|
45
|
+
NOTIFICATION = "Notification"
|
|
46
|
+
|
|
47
|
+
# P5 - Additional events
|
|
48
|
+
TEAMMATE_IDLE = "TeammateIdle"
|
|
49
|
+
WORKTREE_CREATE = "WorktreeCreate"
|
|
50
|
+
WORKTREE_REMOVE = "WorktreeRemove"
|
|
51
|
+
PROMPT_SUBMIT = "PromptSubmit" # Deprecated alias for USER_PROMPT_SUBMIT
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class PermissionDecision(enum.Enum):
|
|
55
|
+
"""Hook permission decision values."""
|
|
56
|
+
|
|
57
|
+
ALLOW = "allow"
|
|
58
|
+
DENY = "deny"
|
|
59
|
+
ASK = "ask"
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class DistributionChannel(enum.Enum):
|
|
63
|
+
"""How gaia-ops was installed and is being invoked."""
|
|
64
|
+
|
|
65
|
+
NPM = "npm"
|
|
66
|
+
PLUGIN = "plugin"
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
@dataclass(frozen=True)
|
|
70
|
+
class HookEvent:
|
|
71
|
+
"""Normalized hook event, CLI-agnostic.
|
|
72
|
+
|
|
73
|
+
Produced by the adapter's parse_event() method.
|
|
74
|
+
"""
|
|
75
|
+
|
|
76
|
+
event_type: HookEventType
|
|
77
|
+
session_id: str
|
|
78
|
+
payload: Dict[str, Any]
|
|
79
|
+
channel: DistributionChannel
|
|
80
|
+
plugin_root: Optional[Path] = None
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
@dataclass(frozen=True)
|
|
84
|
+
class ValidationRequest:
|
|
85
|
+
"""Pre-tool-use validation request extracted from a HookEvent."""
|
|
86
|
+
|
|
87
|
+
tool_name: str
|
|
88
|
+
command: str
|
|
89
|
+
tool_input: Dict[str, Any]
|
|
90
|
+
session_id: str
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
@dataclass(frozen=True)
|
|
94
|
+
class ValidationResult:
|
|
95
|
+
"""CLI-agnostic validation result from business logic.
|
|
96
|
+
|
|
97
|
+
Business logic produces this; the adapter formats it for the CLI.
|
|
98
|
+
"""
|
|
99
|
+
|
|
100
|
+
allowed: bool = True
|
|
101
|
+
reason: str = ""
|
|
102
|
+
tier: str = "T0"
|
|
103
|
+
modified_input: Optional[Dict[str, Any]] = None
|
|
104
|
+
suggestions: List[str] = field(default_factory=list)
|
|
105
|
+
nonce: Optional[str] = None
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
@dataclass(frozen=True)
|
|
109
|
+
class ToolResult:
|
|
110
|
+
"""Post-tool-use result data extracted from a HookEvent."""
|
|
111
|
+
|
|
112
|
+
tool_name: str
|
|
113
|
+
command: str
|
|
114
|
+
output: str
|
|
115
|
+
exit_code: int
|
|
116
|
+
session_id: str
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
@dataclass(frozen=True)
|
|
120
|
+
class AgentCompletion:
|
|
121
|
+
"""Subagent completion data extracted from a HookEvent."""
|
|
122
|
+
|
|
123
|
+
agent_type: str
|
|
124
|
+
agent_id: str
|
|
125
|
+
transcript_path: str
|
|
126
|
+
last_message: str
|
|
127
|
+
session_id: str
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
@dataclass(frozen=True)
|
|
131
|
+
class CompletionResult:
|
|
132
|
+
"""Result of processing an agent completion event."""
|
|
133
|
+
|
|
134
|
+
contract_valid: bool = True
|
|
135
|
+
episode_id: Optional[str] = None
|
|
136
|
+
context_updated: bool = False
|
|
137
|
+
anomalies: List[Dict[str, Any]] = field(default_factory=list)
|
|
138
|
+
repair_needed: bool = False
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
@dataclass(frozen=True)
|
|
142
|
+
class ContextResult:
|
|
143
|
+
"""Result of context injection processing."""
|
|
144
|
+
|
|
145
|
+
context_injected: bool = False
|
|
146
|
+
additional_context: Optional[str] = None
|
|
147
|
+
sections_provided: List[str] = field(default_factory=list)
|
|
148
|
+
# Reserved for future adapter use
|
|
149
|
+
prompt_text: str = ""
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
@dataclass(frozen=True)
|
|
153
|
+
class BootstrapResult:
|
|
154
|
+
"""Result of project bootstrap/scanning."""
|
|
155
|
+
|
|
156
|
+
project_scanned: bool = False
|
|
157
|
+
context_path: Optional[Path] = None
|
|
158
|
+
tools_detected: List[str] = field(default_factory=list)
|
|
159
|
+
# P1 fields: SessionStart adapter populates these
|
|
160
|
+
should_scan: bool = False
|
|
161
|
+
should_refresh: bool = False
|
|
162
|
+
session_type: str = "startup"
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
@dataclass(frozen=True)
|
|
166
|
+
class QualityResult:
|
|
167
|
+
"""Result of a Stop event -- whether evidence quality meets threshold."""
|
|
168
|
+
|
|
169
|
+
quality_sufficient: bool = True
|
|
170
|
+
score: float = 1.0
|
|
171
|
+
missing_elements: List[str] = field(default_factory=list)
|
|
172
|
+
recommendation: str = "continue"
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
@dataclass(frozen=True)
|
|
176
|
+
class VerificationResult:
|
|
177
|
+
"""Result of a TaskCompleted event -- whether completion criteria are met."""
|
|
178
|
+
|
|
179
|
+
criteria_met: bool = True
|
|
180
|
+
verified_items: List[str] = field(default_factory=list)
|
|
181
|
+
failed_items: List[str] = field(default_factory=list)
|
|
182
|
+
block_completion: bool = False
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
@dataclass(frozen=True)
|
|
186
|
+
class HookResponse:
|
|
187
|
+
"""CLI-specific hook response. Constructed by adapter, not business logic."""
|
|
188
|
+
|
|
189
|
+
output: Dict[str, Any]
|
|
190
|
+
exit_code: int = 0
|
|
191
|
+
|
|
192
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
193
|
+
"""Serialize to a dictionary suitable for JSON output."""
|
|
194
|
+
return {"output": self.output, "exit_code": self.exit_code}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Shared utility functions for Gaia-Ops hooks.
|
|
3
|
+
|
|
4
|
+
Centralizes common patterns that were previously copy-pasted across all hook
|
|
5
|
+
entry points (has_stdin_data, dual-channel warnings, etc.).
|
|
6
|
+
|
|
7
|
+
``has_stdin_data`` is now defined in ``modules.core.stdin`` and re-exported
|
|
8
|
+
here for backward compatibility with existing imports.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import logging
|
|
12
|
+
|
|
13
|
+
from modules.core.stdin import has_stdin_data # noqa: F401 -- re-export
|
|
14
|
+
|
|
15
|
+
logger = logging.getLogger(__name__)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def warn_if_dual_channel() -> None:
|
|
19
|
+
"""Log a warning if both plugin and npm distribution channels are active."""
|
|
20
|
+
from adapters.channel import is_dual_channel_active
|
|
21
|
+
|
|
22
|
+
if is_dual_channel_active():
|
|
23
|
+
logger.warning(
|
|
24
|
+
"Both plugin and npm channels detected. Plugin channel takes precedence."
|
|
25
|
+
)
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""ElicitationResult hook -- activates T3 approval grants when user approves via AskUserQuestion.
|
|
3
|
+
|
|
4
|
+
This hook fires after the user responds to an AskUserQuestion elicitation.
|
|
5
|
+
It checks if the response indicates approval and, if so, activates all
|
|
6
|
+
pending approval grants for the current session.
|
|
7
|
+
|
|
8
|
+
The hook NEVER blocks (always exits 0). It is purely side-effectful:
|
|
9
|
+
reading the user's answer and activating grants when appropriate.
|
|
10
|
+
"""
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import sys
|
|
14
|
+
import json
|
|
15
|
+
import logging
|
|
16
|
+
import os
|
|
17
|
+
from datetime import datetime
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
|
|
20
|
+
sys.path.insert(0, str(Path(__file__).parent))
|
|
21
|
+
|
|
22
|
+
from modules.core.paths import get_logs_dir
|
|
23
|
+
from modules.core.stdin import has_stdin_data
|
|
24
|
+
|
|
25
|
+
# Configure logging -- file only, no stderr
|
|
26
|
+
_log_file = get_logs_dir() / f"hooks-{datetime.now().strftime('%Y-%m-%d')}.log"
|
|
27
|
+
logging.basicConfig(
|
|
28
|
+
level=logging.INFO,
|
|
29
|
+
format='%(asctime)s [elicitation_result] %(name)s - %(levelname)s - %(message)s',
|
|
30
|
+
handlers=[logging.FileHandler(_log_file)],
|
|
31
|
+
)
|
|
32
|
+
logger = logging.getLogger(__name__)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _extract_response(event: dict) -> str | None:
|
|
36
|
+
"""Extract the user's answer from the ElicitationResult event.
|
|
37
|
+
|
|
38
|
+
The exact schema is not fully documented, so we probe multiple
|
|
39
|
+
possible field names defensively.
|
|
40
|
+
"""
|
|
41
|
+
# Try top-level fields first
|
|
42
|
+
for field in ("result", "answer", "response", "selected", "value",
|
|
43
|
+
"hookEventInput", "elicitation_result"):
|
|
44
|
+
val = event.get(field)
|
|
45
|
+
if val is None:
|
|
46
|
+
continue
|
|
47
|
+
if isinstance(val, str) and val.strip():
|
|
48
|
+
return val
|
|
49
|
+
if isinstance(val, dict):
|
|
50
|
+
# Nested -- look for answer/selected inside
|
|
51
|
+
for inner in ("answer", "selected", "value", "result", "label"):
|
|
52
|
+
inner_val = val.get(inner)
|
|
53
|
+
if inner_val and isinstance(inner_val, str):
|
|
54
|
+
return inner_val
|
|
55
|
+
# Check for answers dict (AskUserQuestion structured format)
|
|
56
|
+
answers = val.get("answers", {})
|
|
57
|
+
if answers and isinstance(answers, dict):
|
|
58
|
+
first_val = next(iter(answers.values()), None)
|
|
59
|
+
if first_val:
|
|
60
|
+
return str(first_val)
|
|
61
|
+
# Check for options list selection
|
|
62
|
+
options = val.get("options", [])
|
|
63
|
+
if options and isinstance(options, list):
|
|
64
|
+
for opt in options:
|
|
65
|
+
if isinstance(opt, dict) and opt.get("selected"):
|
|
66
|
+
return str(opt.get("label", opt.get("value", "")))
|
|
67
|
+
return None
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def _is_approval(response: str) -> bool:
|
|
71
|
+
"""Check if the response indicates approval."""
|
|
72
|
+
normalized = response.lower().strip()
|
|
73
|
+
approval_words = ["approve", "approved", "yes", "accept", "confirm", "allow"]
|
|
74
|
+
return any(word in normalized for word in approval_words)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def _activate_grants(session_id: str, response: str = "") -> None:
|
|
78
|
+
"""Activate approval grants for this session.
|
|
79
|
+
|
|
80
|
+
When *response* contains a ``[P-<nonce>]`` tag (nonce-labeled approval),
|
|
81
|
+
only the specific grant identified by that nonce is activated. When no
|
|
82
|
+
nonce is present (legacy approvals that predate nonce labeling) the
|
|
83
|
+
function falls back to session-wide activation for backward compatibility.
|
|
84
|
+
"""
|
|
85
|
+
from modules.security.approval_grants import (
|
|
86
|
+
activate_grants_for_session,
|
|
87
|
+
activate_pending_approval,
|
|
88
|
+
activate_cross_session_pending,
|
|
89
|
+
extract_nonce_from_label,
|
|
90
|
+
load_pending_by_nonce_prefix,
|
|
91
|
+
get_pending_approvals_for_session,
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
# Try nonce-targeted activation first
|
|
95
|
+
nonce_prefix = extract_nonce_from_label(response) if response else None
|
|
96
|
+
if nonce_prefix:
|
|
97
|
+
logger.info(
|
|
98
|
+
"ElicitationResult: nonce prefix found in response: %s", nonce_prefix,
|
|
99
|
+
)
|
|
100
|
+
pending_data = load_pending_by_nonce_prefix(nonce_prefix)
|
|
101
|
+
if pending_data:
|
|
102
|
+
full_nonce = pending_data.get("nonce", "")
|
|
103
|
+
pending_session = pending_data.get("session_id", "")
|
|
104
|
+
if pending_session == session_id:
|
|
105
|
+
# Same session -- standard targeted activation
|
|
106
|
+
result = activate_pending_approval(
|
|
107
|
+
nonce=full_nonce, session_id=session_id,
|
|
108
|
+
)
|
|
109
|
+
else:
|
|
110
|
+
# Cross-session pending -- approval came from a prior session
|
|
111
|
+
result = activate_cross_session_pending(
|
|
112
|
+
pending_data, session_id=session_id,
|
|
113
|
+
)
|
|
114
|
+
logger.info(
|
|
115
|
+
"ElicitationResult nonce-targeted activation: "
|
|
116
|
+
"nonce=%s success=%s status=%s",
|
|
117
|
+
full_nonce[:12] if full_nonce else nonce_prefix,
|
|
118
|
+
result.success,
|
|
119
|
+
result.status,
|
|
120
|
+
)
|
|
121
|
+
return
|
|
122
|
+
else:
|
|
123
|
+
logger.warning(
|
|
124
|
+
"ElicitationResult: nonce prefix %s not found in pending files, "
|
|
125
|
+
"falling back to session-wide activation",
|
|
126
|
+
nonce_prefix,
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
# Fallback: session-wide activation (backward compat for unlabeled approvals)
|
|
130
|
+
pending = get_pending_approvals_for_session(session_id)
|
|
131
|
+
if not pending:
|
|
132
|
+
logger.info("No pending approvals to activate for session %s", session_id)
|
|
133
|
+
return
|
|
134
|
+
|
|
135
|
+
results = activate_grants_for_session(session_id)
|
|
136
|
+
activated = sum(1 for r in results if r.success)
|
|
137
|
+
logger.info(
|
|
138
|
+
"ElicitationResult activated %d/%d pending approvals for session %s",
|
|
139
|
+
activated, len(results), session_id,
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
if __name__ == "__main__":
|
|
144
|
+
if not has_stdin_data():
|
|
145
|
+
sys.exit(0)
|
|
146
|
+
|
|
147
|
+
try:
|
|
148
|
+
raw = sys.stdin.read()
|
|
149
|
+
if not raw.strip():
|
|
150
|
+
sys.exit(0)
|
|
151
|
+
|
|
152
|
+
event = json.loads(raw)
|
|
153
|
+
|
|
154
|
+
# Extract session_id from event or environment
|
|
155
|
+
session_id = event.get("session_id") or os.environ.get("CLAUDE_SESSION_ID", "")
|
|
156
|
+
|
|
157
|
+
# Extract user's response
|
|
158
|
+
response = _extract_response(event)
|
|
159
|
+
|
|
160
|
+
if not response:
|
|
161
|
+
logger.info("No extractable response in ElicitationResult event")
|
|
162
|
+
sys.exit(0)
|
|
163
|
+
|
|
164
|
+
logger.info("ElicitationResult response: %s", response[:80])
|
|
165
|
+
|
|
166
|
+
# Check if the response indicates approval
|
|
167
|
+
if _is_approval(response):
|
|
168
|
+
if session_id:
|
|
169
|
+
_activate_grants(session_id, response=response)
|
|
170
|
+
else:
|
|
171
|
+
logger.warning("Approval detected but no session_id available")
|
|
172
|
+
else:
|
|
173
|
+
logger.info("ElicitationResult response is not an approval: %s", response[:40])
|
|
174
|
+
|
|
175
|
+
except Exception as e:
|
|
176
|
+
logger.error("Error in elicitation_result hook: %s", e, exc_info=True)
|
|
177
|
+
|
|
178
|
+
# Never block -- always exit 0
|
|
179
|
+
sys.exit(0)
|
package/hooks/hooks.json
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
{
|
|
2
|
+
"hooks": {
|
|
3
|
+
"PreToolUse": [
|
|
4
|
+
{
|
|
5
|
+
"matcher": "Bash",
|
|
6
|
+
"hooks": [{"type": "command", "command": "${CLAUDE_PLUGIN_ROOT}/hooks/pre_tool_use.py"}]
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
"matcher": "Task",
|
|
10
|
+
"hooks": [{"type": "command", "command": "${CLAUDE_PLUGIN_ROOT}/hooks/pre_tool_use.py"}]
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"matcher": "Agent",
|
|
14
|
+
"hooks": [{"type": "command", "command": "${CLAUDE_PLUGIN_ROOT}/hooks/pre_tool_use.py"}]
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"matcher": "SendMessage",
|
|
18
|
+
"hooks": [{"type": "command", "command": "${CLAUDE_PLUGIN_ROOT}/hooks/pre_tool_use.py"}]
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"matcher": "Read|Edit|Write|Glob|Grep|WebSearch|WebFetch|NotebookEdit",
|
|
22
|
+
"hooks": [{"type": "command", "command": "${CLAUDE_PLUGIN_ROOT}/hooks/pre_tool_use.py"}]
|
|
23
|
+
}
|
|
24
|
+
],
|
|
25
|
+
"PostToolUse": [
|
|
26
|
+
{
|
|
27
|
+
"matcher": "Bash",
|
|
28
|
+
"hooks": [{"type": "command", "command": "${CLAUDE_PLUGIN_ROOT}/hooks/post_tool_use.py"}]
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"matcher": "AskUserQuestion",
|
|
32
|
+
"hooks": [{"type": "command", "command": "${CLAUDE_PLUGIN_ROOT}/hooks/post_tool_use.py"}]
|
|
33
|
+
}
|
|
34
|
+
],
|
|
35
|
+
"SubagentStop": [
|
|
36
|
+
{
|
|
37
|
+
"matcher": "*",
|
|
38
|
+
"hooks": [{"type": "command", "command": "${CLAUDE_PLUGIN_ROOT}/hooks/subagent_stop.py"}]
|
|
39
|
+
}
|
|
40
|
+
],
|
|
41
|
+
"SessionStart": [
|
|
42
|
+
{
|
|
43
|
+
"matcher": "startup",
|
|
44
|
+
"hooks": [{"type": "command", "command": "${CLAUDE_PLUGIN_ROOT}/hooks/session_start.py"}]
|
|
45
|
+
}
|
|
46
|
+
],
|
|
47
|
+
"Stop": [
|
|
48
|
+
{
|
|
49
|
+
"hooks": [{"type": "command", "command": "${CLAUDE_PLUGIN_ROOT}/hooks/stop_hook.py"}]
|
|
50
|
+
}
|
|
51
|
+
],
|
|
52
|
+
"TaskCompleted": [
|
|
53
|
+
{
|
|
54
|
+
"hooks": [{"type": "command", "command": "${CLAUDE_PLUGIN_ROOT}/hooks/task_completed.py"}]
|
|
55
|
+
}
|
|
56
|
+
],
|
|
57
|
+
"SubagentStart": [
|
|
58
|
+
{
|
|
59
|
+
"matcher": "*",
|
|
60
|
+
"hooks": [{"type": "command", "command": "${CLAUDE_PLUGIN_ROOT}/hooks/subagent_start.py"}]
|
|
61
|
+
}
|
|
62
|
+
],
|
|
63
|
+
"UserPromptSubmit": [
|
|
64
|
+
{
|
|
65
|
+
"hooks": [{"type": "command", "command": "${CLAUDE_PLUGIN_ROOT}/hooks/user_prompt_submit.py"}]
|
|
66
|
+
}
|
|
67
|
+
],
|
|
68
|
+
"PreCompact": [
|
|
69
|
+
{
|
|
70
|
+
"hooks": [{"type": "command", "command": "${CLAUDE_PLUGIN_ROOT}/hooks/pre_compact.py"}]
|
|
71
|
+
}
|
|
72
|
+
],
|
|
73
|
+
"PostCompact": [
|
|
74
|
+
{
|
|
75
|
+
"hooks": [{"type": "command", "command": "${CLAUDE_PLUGIN_ROOT}/hooks/post_compact.py"}]
|
|
76
|
+
}
|
|
77
|
+
],
|
|
78
|
+
"ElicitationResult": [
|
|
79
|
+
{
|
|
80
|
+
"hooks": [{"type": "command", "command": "${CLAUDE_PLUGIN_ROOT}/hooks/elicitation_result.py"}]
|
|
81
|
+
}
|
|
82
|
+
]
|
|
83
|
+
}
|
|
84
|
+
}
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
# Hooks Modular Architecture
|
|
2
|
+
|
|
3
|
+
This directory contains the modular hook system for gaia-ops.
|
|
4
|
+
|
|
5
|
+
## What is this?
|
|
6
|
+
|
|
7
|
+
A refactored, maintainable architecture for Claude Code hooks. Instead of monolithic 1000+ line files, the logic is split into focused modules that can be tested, maintained, and extended independently.
|
|
8
|
+
|
|
9
|
+
## Where does this fit?
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
Claude Code invokes hook
|
|
13
|
+
|
|
|
14
|
+
v
|
|
15
|
+
[session_start.py] --------> [modules/context/context_freshness] -> Staleness check
|
|
16
|
+
| [modules/scanning/scan_trigger] -> Auto-refresh
|
|
17
|
+
v
|
|
18
|
+
[pre_tool_use.py] ---------> [modules/security/*] -> Tier classification
|
|
19
|
+
| [modules/tools/*] -> Bash/Task validation
|
|
20
|
+
v
|
|
21
|
+
Tool executes
|
|
22
|
+
|
|
|
23
|
+
v
|
|
24
|
+
[post_tool_use.py] --------> [modules/audit/*] -> Logging & metrics
|
|
25
|
+
[modules/session/*] -> Session context updates
|
|
26
|
+
[modules/agents/*] -> Anomaly detection
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Module Structure
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
modules/
|
|
33
|
+
├── __init__.py # Package marker
|
|
34
|
+
├── core/ # Shared utilities
|
|
35
|
+
│ ├── __init__.py
|
|
36
|
+
│ ├── paths.py # find_claude_dir() - single source of truth
|
|
37
|
+
│ └── state.py # Pre/post hook state sharing
|
|
38
|
+
│
|
|
39
|
+
├── security/ # Security classification & approval
|
|
40
|
+
│ ├── __init__.py
|
|
41
|
+
│ ├── tiers.py # SecurityTier enum (T0-T3)
|
|
42
|
+
│ ├── blocked_commands.py # Blocked patterns by category
|
|
43
|
+
│ ├── mutative_verbs.py # CLI-agnostic verb detector, nonce-based deny
|
|
44
|
+
│ ├── approval_grants.py # Nonce-based approval grant management
|
|
45
|
+
│ ├── approval_constants.py # Approval system constants
|
|
46
|
+
│ ├── approval_messages.py # Approval denial message formatting
|
|
47
|
+
│ ├── approval_scopes.py # Approval scope definitions
|
|
48
|
+
│ ├── command_semantics.py # Command semantic analysis
|
|
49
|
+
│ └── gitops_validator.py # kubectl/helm/flux validation
|
|
50
|
+
│
|
|
51
|
+
├── tools/ # Tool-specific validators
|
|
52
|
+
│ ├── __init__.py
|
|
53
|
+
│ ├── shell_parser.py # Parse compound commands
|
|
54
|
+
│ ├── bash_validator.py # Bash command validation (orchestrates pipeline)
|
|
55
|
+
│ ├── task_validator.py # Task tool validation with context enforcement
|
|
56
|
+
│ ├── cloud_pipe_validator.py # Cloud pipe/redirect/chain check
|
|
57
|
+
│ └── hook_response.py # Standardized hook response formatting
|
|
58
|
+
│
|
|
59
|
+
├── context/ # Context management
|
|
60
|
+
│ ├── __init__.py
|
|
61
|
+
│ ├── context_writer.py # Write context updates
|
|
62
|
+
│ └── context_freshness.py # Check staleness for SessionStart
|
|
63
|
+
│
|
|
64
|
+
├── scanning/ # Scan triggering
|
|
65
|
+
│ ├── __init__.py
|
|
66
|
+
│ └── scan_trigger.py # Lightweight scan invocation for SessionStart
|
|
67
|
+
│
|
|
68
|
+
├── session/ # Session context management
|
|
69
|
+
│ ├── __init__.py
|
|
70
|
+
│ └── session_context_writer.py # Write critical events to session context
|
|
71
|
+
│
|
|
72
|
+
├── validation/ # Commit validation
|
|
73
|
+
│ ├── __init__.py
|
|
74
|
+
│ └── commit_validator.py # Conventional Commits enforcement
|
|
75
|
+
│
|
|
76
|
+
├── audit/ # Logging and metrics
|
|
77
|
+
│ ├── __init__.py
|
|
78
|
+
│ ├── logger.py # AuditLogger
|
|
79
|
+
│ ├── metrics.py # MetricsCollector + FUNCTIONAL generate_summary
|
|
80
|
+
│ └── event_detector.py # CriticalEventDetector
|
|
81
|
+
│
|
|
82
|
+
├── identity/ # Orchestrator identity injection
|
|
83
|
+
│ ├── __init__.py
|
|
84
|
+
│ ├── identity_provider.py # Build identity based on installed plugins
|
|
85
|
+
│ ├── ops_identity.py # Ops mode: minimal identity + on-demand skills
|
|
86
|
+
│ └── security_identity.py # Security-only mode identity
|
|
87
|
+
│
|
|
88
|
+
└── agents/ # Subagent support
|
|
89
|
+
├── __init__.py
|
|
90
|
+
└── response_contract.py # Agent response contract validation
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Key Features
|
|
94
|
+
|
|
95
|
+
### Orchestrator Gate
|
|
96
|
+
The orchestrator is restricted to four tools:
|
|
97
|
+
- `Agent` -- dispatch work to specialist agents
|
|
98
|
+
- `SendMessage` -- resume a previously spawned agent
|
|
99
|
+
- `AskUserQuestion` -- get clarification or approval from the user
|
|
100
|
+
- `Skill` -- load on-demand procedures
|
|
101
|
+
|
|
102
|
+
This enforces the principle: "Orchestrator delegates, agents execute."
|
|
103
|
+
|
|
104
|
+
### SendMessage Validation (PreToolUse matcher)
|
|
105
|
+
SendMessage is validated as a PreToolUse event (not a separate hook event):
|
|
106
|
+
- Agent ID format check (must match `/^a[0-9a-f]{5,}$/`)
|
|
107
|
+
- Non-empty message required
|
|
108
|
+
- Grant activation is handled by ElicitationResult hook (user approval via AskUserQuestion)
|
|
109
|
+
|
|
110
|
+
### Context Enforcement
|
|
111
|
+
Task invocations for project agents inject project-context via `context_provider.py`.
|
|
112
|
+
|
|
113
|
+
### State Sharing
|
|
114
|
+
Pre-hook saves state to `.claude/.hooks_state.json`, which post-hook reads to get:
|
|
115
|
+
- Security tier assigned
|
|
116
|
+
- Command executed
|
|
117
|
+
- Timestamp for duration calculation
|
|
118
|
+
|
|
119
|
+
### Functional Metrics
|
|
120
|
+
`generate_summary()` now actually works - reads JSONL metrics files and aggregates:
|
|
121
|
+
- Total executions
|
|
122
|
+
- Success rate
|
|
123
|
+
- Average duration
|
|
124
|
+
- Top command types
|
|
125
|
+
- Tier distribution
|
|
126
|
+
|
|
127
|
+
## Usage
|
|
128
|
+
|
|
129
|
+
### Entry Points
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
# Pre-hook (validation)
|
|
133
|
+
python3 pre_tool_use.py --test
|
|
134
|
+
|
|
135
|
+
# Post-hook (audit)
|
|
136
|
+
python3 post_tool_use.py --test
|
|
137
|
+
|
|
138
|
+
# Metrics (use the JS CLI instead)
|
|
139
|
+
npx gaia-metrics
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Importing Modules
|
|
143
|
+
|
|
144
|
+
```python
|
|
145
|
+
from modules.security import SecurityTier, classify_command_tier, is_blocked_command
|
|
146
|
+
from modules.security import CATEGORY_MUTATIVE, CATEGORY_READ_ONLY
|
|
147
|
+
from modules.tools import BashValidator
|
|
148
|
+
from modules.audit import generate_summary
|
|
149
|
+
|
|
150
|
+
# Check if command is permanently blocked
|
|
151
|
+
result = is_blocked_command("kubectl delete namespace production")
|
|
152
|
+
print(f"Blocked: {result.blocked}, Reason: {result.reason}")
|
|
153
|
+
|
|
154
|
+
# Classify command tier
|
|
155
|
+
tier = classify_command_tier("kubectl get pods")
|
|
156
|
+
print(f"Tier: {tier}") # SecurityTier.T0
|
|
157
|
+
|
|
158
|
+
# Validate Bash command (full pipeline: blocked -> mutative verbs -> safe by elimination)
|
|
159
|
+
validator = BashValidator()
|
|
160
|
+
result = validator.validate("kubectl get pods")
|
|
161
|
+
print(f"Allowed: {result.allowed}, Tier: {result.tier}")
|
|
162
|
+
|
|
163
|
+
# Get metrics summary
|
|
164
|
+
summary = generate_summary(days=7)
|
|
165
|
+
print(f"Success rate: {summary['success_rate']:.1%}")
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
## Architecture Notes
|
|
169
|
+
|
|
170
|
+
The modular architecture maintains full backward compatibility with Claude Code's hook interface (stdin JSON format).
|
|
171
|
+
|
|
172
|
+
All security rules (blocked patterns, mutative verbs, tiers) are hardcoded in the Python modules for performance and simplicity - no external JSON config files needed.
|
|
173
|
+
|
|
174
|
+
### Validation Order (Defense-in-Depth)
|
|
175
|
+
bash_validator checks commands in this order (short-circuit on first match):
|
|
176
|
+
0. **Indirect execution detection** — `bash -c`, `eval`, `python -c` etc. → ask or block
|
|
177
|
+
1. **Blocked commands** (blocked_commands.py) — permanently denied patterns, exit 2
|
|
178
|
+
2. **Claude footer stripping** — transparent via updatedInput
|
|
179
|
+
3. **Commit message validation** — conventional commits enforcement
|
|
180
|
+
4. **Cloud pipe/redirect/chain check** (cloud_pipe_validator.py) — corrective deny
|
|
181
|
+
5. **Mutative verbs** (mutative_verbs.py) — CLI-agnostic verb detector, native `ask` dialog
|
|
182
|
+
6. **GitOps validation** (gitops_validator.py) — kubectl/helm/flux policy enforcement
|
|
183
|
+
7. **Everything else** — SAFE by elimination (auto-approved)
|
|
184
|
+
|
|
185
|
+
### Tier Classification
|
|
186
|
+
- **T0**: Read-only (get, list, describe, show)
|
|
187
|
+
- **T1**: Local validation (validate, lint, fmt, check)
|
|
188
|
+
- **T2**: Simulation (plan, template, diff, --dry-run)
|
|
189
|
+
- **T3**: State-modifying (apply, delete, push, commit)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Gaia-Ops Hooks Modular Architecture
|
|
3
|
+
|
|
4
|
+
This package provides a modular, maintainable hook system for Claude Code.
|
|
5
|
+
|
|
6
|
+
Modules:
|
|
7
|
+
- core: Shared utilities (paths, state, config loading)
|
|
8
|
+
- security: Security tiers, safe commands, blocked patterns
|
|
9
|
+
- tools: Tool-specific validators (Bash, Task)
|
|
10
|
+
- workflow: Phase validation and state tracking
|
|
11
|
+
- audit: Logging, metrics, event detection
|
|
12
|
+
- agents: Subagent metrics and anomaly detection
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
__version__ = "2.0.0"
|