@jaguilar87/gaia-ops 4.4.0 → 4.7.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 +1 -1
- package/.claude-plugin/plugin.json +12 -3
- package/ARCHITECTURE.md +9 -8
- package/CHANGELOG.md +34 -0
- package/README.md +43 -11
- package/agents/terraform-architect.md +1 -1
- package/bin/README.md +2 -2
- package/bin/gaia-doctor.js +18 -5
- package/bin/gaia-history.js +0 -1
- package/bin/gaia-metrics.js +2 -2
- package/bin/gaia-scan.py +23 -1
- package/bin/gaia-update.js +346 -54
- package/bin/pre-publish-validate.js +33 -10
- package/commands/gaia.md +37 -0
- package/config/README.md +3 -9
- package/config/context-contracts.json +47 -15
- package/config/surface-routing.json +9 -1
- package/dist/gaia-ops/.claude-plugin/plugin.json +22 -0
- package/dist/gaia-ops/agents/cloud-troubleshooter.md +73 -0
- package/dist/gaia-ops/agents/devops-developer.md +57 -0
- package/dist/gaia-ops/agents/gaia-system.md +58 -0
- package/dist/gaia-ops/agents/gitops-operator.md +60 -0
- package/dist/gaia-ops/agents/speckit-planner.md +71 -0
- package/dist/gaia-ops/agents/terraform-architect.md +60 -0
- package/dist/gaia-ops/commands/gaia.md +37 -0
- package/dist/gaia-ops/config/README.md +58 -0
- package/dist/gaia-ops/config/cloud/aws.json +140 -0
- package/dist/gaia-ops/config/cloud/gcp.json +145 -0
- package/dist/gaia-ops/config/context-contracts.json +131 -0
- package/dist/gaia-ops/config/git_standards.json +72 -0
- package/dist/gaia-ops/config/surface-routing.json +197 -0
- package/dist/gaia-ops/config/universal-rules.json +10 -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 +1477 -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 +126 -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 +124 -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 +576 -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/anchor_tracker.py +317 -0
- package/dist/gaia-ops/hooks/modules/context/compact_context_builder.py +215 -0
- package/dist/gaia-ops/hooks/modules/context/context_cache.py +129 -0
- package/dist/gaia-ops/hooks/modules/context/context_freshness.py +145 -0
- package/dist/gaia-ops/hooks/modules/context/context_injector.py +427 -0
- package/dist/gaia-ops/hooks/modules/context/context_writer.py +518 -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 +558 -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/identity/__init__.py +0 -0
- package/dist/gaia-ops/hooks/modules/identity/identity_provider.py +21 -0
- package/dist/gaia-ops/hooks/modules/identity/ops_identity.py +34 -0
- package/dist/gaia-ops/hooks/modules/identity/security_identity.py +10 -0
- package/dist/gaia-ops/hooks/modules/memory/__init__.py +8 -0
- package/dist/gaia-ops/hooks/modules/memory/episode_writer.py +227 -0
- package/dist/gaia-ops/hooks/modules/orchestrator/__init__.py +1 -0
- package/dist/gaia-ops/hooks/modules/orchestrator/delegate_mode.py +128 -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 +89 -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 +912 -0
- package/dist/gaia-ops/hooks/modules/security/approval_messages.py +71 -0
- package/dist/gaia-ops/hooks/modules/security/approval_scopes.py +153 -0
- package/dist/gaia-ops/hooks/modules/security/blocked_commands.py +584 -0
- package/dist/gaia-ops/hooks/modules/security/blocked_message_formatter.py +86 -0
- package/dist/gaia-ops/hooks/modules/security/command_semantics.py +130 -0
- package/dist/gaia-ops/hooks/modules/security/gitops_validator.py +179 -0
- package/dist/gaia-ops/hooks/modules/security/mutative_verbs.py +850 -0
- package/dist/gaia-ops/hooks/modules/security/prompt_validator.py +40 -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/session_context_writer.py +100 -0
- package/dist/gaia-ops/hooks/modules/session/session_event_injector.py +158 -0
- package/dist/gaia-ops/hooks/modules/session/session_manager.py +31 -0
- package/dist/gaia-ops/hooks/modules/tools/__init__.py +25 -0
- package/dist/gaia-ops/hooks/modules/tools/bash_validator.py +708 -0
- package/dist/gaia-ops/hooks/modules/tools/cloud_pipe_validator.py +181 -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/task_validator.py +283 -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_tool_use.py +383 -0
- package/dist/gaia-ops/hooks/session_start.py +69 -0
- package/dist/gaia-ops/hooks/stop_hook.py +69 -0
- package/dist/gaia-ops/hooks/subagent_start.py +71 -0
- package/dist/gaia-ops/hooks/subagent_stop.py +288 -0
- package/dist/gaia-ops/hooks/task_completed.py +70 -0
- package/dist/gaia-ops/hooks/user_prompt_submit.py +177 -0
- package/dist/gaia-ops/settings.json +72 -0
- package/dist/gaia-ops/skills/README.md +109 -0
- package/dist/gaia-ops/skills/agent-protocol/SKILL.md +105 -0
- package/dist/gaia-ops/skills/agent-protocol/examples.md +170 -0
- package/dist/gaia-ops/skills/agent-response/SKILL.md +53 -0
- package/dist/gaia-ops/skills/approval/SKILL.md +85 -0
- package/dist/gaia-ops/skills/approval/examples.md +140 -0
- package/dist/gaia-ops/skills/approval/reference.md +57 -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 +76 -0
- package/dist/gaia-ops/skills/context-updater/examples.md +71 -0
- package/dist/gaia-ops/skills/developer-patterns/SKILL.md +93 -0
- package/dist/gaia-ops/skills/developer-patterns/reference.md +112 -0
- package/dist/gaia-ops/skills/execution/SKILL.md +66 -0
- package/dist/gaia-ops/skills/fast-queries/SKILL.md +47 -0
- package/dist/gaia-ops/skills/gaia-patterns/SKILL.md +92 -0
- package/dist/gaia-ops/skills/gaia-patterns/reference.md +22 -0
- package/dist/gaia-ops/skills/git-conventions/SKILL.md +48 -0
- package/dist/gaia-ops/skills/gitops-patterns/SKILL.md +73 -0
- package/dist/gaia-ops/skills/gitops-patterns/reference.md +183 -0
- package/dist/gaia-ops/skills/investigation/SKILL.md +77 -0
- package/dist/gaia-ops/skills/orchestrator-approval/SKILL.md +64 -0
- package/dist/gaia-ops/skills/reference.md +134 -0
- package/dist/gaia-ops/skills/security-tiers/SKILL.md +61 -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/skill-creation/SKILL.md +119 -0
- package/dist/gaia-ops/skills/specification/SKILL.md +186 -0
- package/dist/gaia-ops/skills/speckit-workflow/SKILL.md +165 -0
- package/dist/gaia-ops/skills/speckit-workflow/reference.md +117 -0
- package/dist/gaia-ops/skills/terraform-patterns/SKILL.md +63 -0
- package/dist/gaia-ops/skills/terraform-patterns/reference.md +93 -0
- package/dist/gaia-ops/speckit/README.md +516 -0
- package/dist/gaia-ops/speckit/scripts/.gitkeep +0 -0
- package/dist/gaia-ops/speckit/templates/adr-template.md +118 -0
- package/dist/gaia-ops/speckit/templates/agent-file-template.md +23 -0
- package/dist/gaia-ops/speckit/templates/plan-template.md +227 -0
- package/dist/gaia-ops/speckit/templates/spec-template.md +140 -0
- package/dist/gaia-ops/speckit/templates/tasks-template.md +257 -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 +476 -0
- package/dist/gaia-ops/tools/context/context_section_reader.py +330 -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 +262 -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/episodic.py +1196 -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 +324 -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 +753 -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 +266 -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 +22 -0
- package/dist/gaia-security/config/universal-rules.json +10 -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 +1477 -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 +57 -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 +124 -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 +576 -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/anchor_tracker.py +317 -0
- package/dist/gaia-security/hooks/modules/context/compact_context_builder.py +215 -0
- package/dist/gaia-security/hooks/modules/context/context_cache.py +129 -0
- package/dist/gaia-security/hooks/modules/context/context_freshness.py +145 -0
- package/dist/gaia-security/hooks/modules/context/context_injector.py +427 -0
- package/dist/gaia-security/hooks/modules/context/context_writer.py +518 -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 +558 -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/identity/__init__.py +0 -0
- package/dist/gaia-security/hooks/modules/identity/identity_provider.py +21 -0
- package/dist/gaia-security/hooks/modules/identity/ops_identity.py +34 -0
- package/dist/gaia-security/hooks/modules/identity/security_identity.py +10 -0
- package/dist/gaia-security/hooks/modules/memory/__init__.py +8 -0
- package/dist/gaia-security/hooks/modules/memory/episode_writer.py +227 -0
- package/dist/gaia-security/hooks/modules/orchestrator/__init__.py +1 -0
- package/dist/gaia-security/hooks/modules/orchestrator/delegate_mode.py +128 -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 +89 -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 +912 -0
- package/dist/gaia-security/hooks/modules/security/approval_messages.py +71 -0
- package/dist/gaia-security/hooks/modules/security/approval_scopes.py +153 -0
- package/dist/gaia-security/hooks/modules/security/blocked_commands.py +584 -0
- package/dist/gaia-security/hooks/modules/security/blocked_message_formatter.py +86 -0
- package/dist/gaia-security/hooks/modules/security/command_semantics.py +130 -0
- package/dist/gaia-security/hooks/modules/security/gitops_validator.py +179 -0
- package/dist/gaia-security/hooks/modules/security/mutative_verbs.py +850 -0
- package/dist/gaia-security/hooks/modules/security/prompt_validator.py +40 -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/session_context_writer.py +100 -0
- package/dist/gaia-security/hooks/modules/session/session_event_injector.py +158 -0
- package/dist/gaia-security/hooks/modules/session/session_manager.py +31 -0
- package/dist/gaia-security/hooks/modules/tools/__init__.py +25 -0
- package/dist/gaia-security/hooks/modules/tools/bash_validator.py +708 -0
- package/dist/gaia-security/hooks/modules/tools/cloud_pipe_validator.py +181 -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/task_validator.py +283 -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 +383 -0
- package/dist/gaia-security/hooks/session_start.py +69 -0
- package/dist/gaia-security/hooks/stop_hook.py +69 -0
- package/dist/gaia-security/hooks/user_prompt_submit.py +177 -0
- package/dist/gaia-security/settings.json +58 -0
- package/git-hooks/commit-msg +41 -0
- package/hooks/README.md +8 -6
- package/hooks/adapters/channel.py +0 -25
- package/hooks/adapters/claude_code.py +364 -125
- package/hooks/elicitation_result.py +132 -0
- package/hooks/hooks.json +10 -1
- package/hooks/modules/README.md +3 -2
- package/hooks/modules/agents/contract_validator.py +3 -51
- package/hooks/modules/agents/response_contract.py +4 -8
- package/hooks/modules/agents/transcript_reader.py +4 -5
- package/hooks/modules/audit/__init__.py +4 -6
- package/hooks/modules/audit/event_detector.py +0 -2
- package/hooks/modules/audit/metrics.py +108 -187
- package/hooks/modules/audit/workflow_auditor.py +0 -4
- package/hooks/modules/audit/workflow_recorder.py +0 -5
- package/hooks/modules/context/compact_context_builder.py +1 -0
- package/hooks/modules/context/context_cache.py +129 -0
- package/hooks/modules/context/context_injector.py +18 -40
- package/hooks/modules/context/context_writer.py +1 -25
- package/hooks/modules/context/contracts_loader.py +7 -10
- package/hooks/modules/core/hook_entry.py +1 -0
- package/hooks/modules/core/paths.py +12 -13
- package/hooks/modules/core/plugin_mode.py +74 -4
- package/hooks/modules/core/plugin_setup.py +395 -23
- package/hooks/modules/events/__init__.py +1 -0
- package/hooks/modules/events/event_writer.py +210 -0
- package/hooks/modules/identity/ops_identity.py +18 -27
- package/hooks/modules/memory/episode_writer.py +1 -6
- package/hooks/modules/orchestrator/__init__.py +1 -0
- package/hooks/modules/orchestrator/delegate_mode.py +128 -0
- package/hooks/modules/security/__init__.py +2 -4
- package/hooks/modules/security/approval_constants.py +5 -1
- package/hooks/modules/security/approval_grants.py +189 -6
- package/hooks/modules/security/approval_messages.py +9 -21
- package/hooks/modules/security/blocked_commands.py +98 -34
- package/hooks/modules/security/command_semantics.py +0 -4
- package/hooks/modules/security/gitops_validator.py +1 -11
- package/hooks/modules/security/mutative_verbs.py +179 -38
- package/hooks/modules/security/tiers.py +1 -19
- package/hooks/modules/session/session_event_injector.py +1 -25
- package/hooks/modules/tools/bash_validator.py +310 -94
- package/hooks/modules/tools/shell_parser.py +0 -1
- package/hooks/modules/tools/task_validator.py +9 -29
- package/hooks/post_tool_use.py +0 -72
- package/hooks/pre_tool_use.py +42 -102
- package/hooks/session_start.py +4 -2
- package/hooks/subagent_start.py +6 -2
- package/hooks/subagent_stop.py +1 -13
- package/hooks/user_prompt_submit.py +119 -37
- package/index.js +1 -1
- package/package.json +5 -3
- package/skills/README.md +3 -5
- package/skills/agent-protocol/SKILL.md +17 -16
- package/skills/agent-protocol/examples.md +6 -6
- package/skills/agent-response/SKILL.md +11 -14
- package/skills/approval/SKILL.md +28 -13
- package/skills/approval/reference.md +2 -2
- package/skills/execution/SKILL.md +1 -1
- package/skills/gaia-patterns/SKILL.md +2 -3
- package/skills/orchestrator-approval/SKILL.md +22 -50
- package/skills/security-tiers/SKILL.md +1 -1
- package/templates/README.md +9 -9
- package/templates/managed-settings.template.json +43 -0
- package/tools/gaia_simulator/runner.py +34 -1
- package/tools/scan/orchestrator.py +13 -0
- package/tools/scan/scanners/base.py +8 -0
- package/tools/scan/scanners/git.py +78 -0
- package/tools/scan/scanners/infrastructure.py +65 -0
- package/tools/scan/scanners/stack.py +110 -0
- package/tools/scan/setup.py +120 -13
- package/tools/scan/workspace.py +85 -0
- package/config/context-contracts.aws.json +0 -42
- package/config/context-contracts.gcp.json +0 -39
- package/skills/project-dispatch/SKILL.md +0 -34
- package/templates/settings.template.json +0 -226
|
@@ -24,6 +24,15 @@ from typing import Dict, FrozenSet, List, Tuple
|
|
|
24
24
|
from .approval_messages import build_t3_approval_instructions
|
|
25
25
|
from .command_semantics import analyze_command
|
|
26
26
|
|
|
27
|
+
try:
|
|
28
|
+
from .blocked_commands import is_blocked_command as _is_blocked_command
|
|
29
|
+
except ImportError:
|
|
30
|
+
_is_blocked_command = None
|
|
31
|
+
logging.getLogger(__name__).warning(
|
|
32
|
+
"blocked_commands.is_blocked_command not importable; "
|
|
33
|
+
"inline code Layer 1 (shell extraction) disabled"
|
|
34
|
+
)
|
|
35
|
+
|
|
27
36
|
logger = logging.getLogger(__name__)
|
|
28
37
|
|
|
29
38
|
|
|
@@ -157,34 +166,108 @@ VERB_FLAG_READ_ONLY_OVERRIDES: Dict[Tuple[str, str], FrozenSet[str]] = {
|
|
|
157
166
|
|
|
158
167
|
|
|
159
168
|
# ============================================================================
|
|
160
|
-
# Inline Code
|
|
169
|
+
# Inline Code Detection — Language-Agnostic 3-Layer Approach
|
|
161
170
|
# ============================================================================
|
|
162
|
-
# When the base command is a runtime interpreter with inline code
|
|
163
|
-
#
|
|
171
|
+
# When the base command is a runtime interpreter with an inline code flag
|
|
172
|
+
# (e.g., python3 -c, node -e, ruby -e, perl -e), scan the code string
|
|
173
|
+
# using three layers instead of verb-matching tokens:
|
|
174
|
+
# Layer 1: Extract string literals → check against blocked_commands
|
|
175
|
+
# Layer 2: Universal dangerous API keyword patterns
|
|
176
|
+
# Layer 3: Heuristic safety classification (length, paths, encoding)
|
|
164
177
|
import re as _re
|
|
165
178
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
179
|
+
# ---------------------------------------------------------------------------
|
|
180
|
+
# CLI → inline-code flag mapping (Step 1a)
|
|
181
|
+
# ---------------------------------------------------------------------------
|
|
182
|
+
_INLINE_CODE_MAP: Dict[str, FrozenSet[str]] = {
|
|
183
|
+
"python": frozenset({"-c"}),
|
|
184
|
+
"python3": frozenset({"-c"}),
|
|
185
|
+
"python3.10": frozenset({"-c"}),
|
|
186
|
+
"python3.11": frozenset({"-c"}),
|
|
187
|
+
"python3.12": frozenset({"-c"}),
|
|
188
|
+
"python3.13": frozenset({"-c"}),
|
|
189
|
+
"node": frozenset({"-e", "--eval"}),
|
|
190
|
+
"ruby": frozenset({"-e"}),
|
|
191
|
+
"perl": frozenset({"-e", "-E"}),
|
|
192
|
+
"php": frozenset({"-r"}),
|
|
193
|
+
"lua": frozenset({"-e"}),
|
|
194
|
+
"rscript": frozenset({"-e"}),
|
|
195
|
+
}
|
|
196
|
+
_INLINE_CODE_CLIS: FrozenSet[str] = frozenset(_INLINE_CODE_MAP.keys())
|
|
197
|
+
|
|
198
|
+
# ---------------------------------------------------------------------------
|
|
199
|
+
# Layer 1: Shell command extraction from string literals
|
|
200
|
+
# ---------------------------------------------------------------------------
|
|
201
|
+
_STRING_LITERAL_RE = _re.compile(r"""(?:['"])((?:[^'"\\\n]|\\.){3,})(?:['"])""")
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def _extract_embedded_shell_commands(code: str) -> List[str]:
|
|
205
|
+
"""Extract string literals from inline code that may contain shell commands."""
|
|
206
|
+
return [m.group(1) for m in _STRING_LITERAL_RE.finditer(code)]
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
# ---------------------------------------------------------------------------
|
|
210
|
+
# Layer 2: Universal dangerous API keyword patterns (category-based)
|
|
211
|
+
# ---------------------------------------------------------------------------
|
|
212
|
+
_UNIVERSAL_DANGEROUS_PATTERNS: Tuple[Tuple[_re.Pattern, str, str], ...] = (
|
|
213
|
+
# Category: Process Execution
|
|
214
|
+
(_re.compile(r"\b(child_process|subprocess)\b"), "process-module", "PROCESS_EXECUTION"),
|
|
215
|
+
(_re.compile(r"\b(execSync|execFile|execFileSync)\s*\("), "exec-sync", "PROCESS_EXECUTION"),
|
|
216
|
+
(_re.compile(r"\bos\.(system|popen|exec[lv]?[pe]?)\s*\("), "os-exec", "PROCESS_EXECUTION"),
|
|
217
|
+
(_re.compile(r"\b(system|exec)\s*\("), "system-call", "PROCESS_EXECUTION"),
|
|
218
|
+
(_re.compile(r"\bspawn(Sync)?\s*\("), "spawn-call", "PROCESS_EXECUTION"),
|
|
219
|
+
(_re.compile(r"\bPopen\s*\("), "popen-call", "PROCESS_EXECUTION"),
|
|
220
|
+
(_re.compile(r"`[^`]{3,}`"), "backtick-exec", "PROCESS_EXECUTION"),
|
|
221
|
+
|
|
222
|
+
# Category: File Deletion
|
|
223
|
+
(_re.compile(r"\b(os\.remove|os\.unlink|os\.rmdir)\s*\("), "os-delete", "FILE_DELETION"),
|
|
224
|
+
(_re.compile(r"\b(shutil\.rmtree|shutil\.move)\s*\("), "shutil-delete", "FILE_DELETION"),
|
|
225
|
+
(_re.compile(r"\bfs\.(unlink|rmdir|rm)(Sync)?\s*\("), "fs-delete", "FILE_DELETION"),
|
|
226
|
+
# Also match .unlinkSync( / .rmSync( / .rmdirSync( as method calls (e.g., require('fs').unlinkSync())
|
|
227
|
+
(_re.compile(r"\.(unlink|rmdir|rm)(Sync)?\s*\("), "fs-delete", "FILE_DELETION"),
|
|
228
|
+
(_re.compile(r"\bFile\.(delete|unlink)\s*\("), "file-delete", "FILE_DELETION"),
|
|
229
|
+
(_re.compile(r"\bunlink\s*\("), "unlink-call", "FILE_DELETION"),
|
|
230
|
+
(_re.compile(r"\brmtree\s*\("), "rmtree-call", "FILE_DELETION"),
|
|
231
|
+
(_re.compile(r"\bFileUtils\.rm"), "fileutils-rm", "FILE_DELETION"),
|
|
232
|
+
(_re.compile(r"pathlib\.Path\([^)]*\)\.(unlink|rmdir)"), "pathlib-delete", "FILE_DELETION"),
|
|
233
|
+
|
|
234
|
+
# Category: File Write
|
|
235
|
+
(_re.compile(r"open\s*\([^)]*['\"][wWaA]"), "file-write-open", "FILE_WRITE"),
|
|
236
|
+
(_re.compile(r"\bfs\.writeFile(Sync)?\s*\("), "fs-write", "FILE_WRITE"),
|
|
237
|
+
# Also match .writeFileSync( / .appendFileSync( as method calls
|
|
238
|
+
(_re.compile(r"\.writeFile(Sync)?\s*\("), "fs-write", "FILE_WRITE"),
|
|
239
|
+
(_re.compile(r"\bfs\.appendFile(Sync)?\s*\("), "fs-append", "FILE_WRITE"),
|
|
240
|
+
(_re.compile(r"\.appendFile(Sync)?\s*\("), "fs-append", "FILE_WRITE"),
|
|
241
|
+
(_re.compile(r"\bFile\.(write|open)\b.*['\"][wWaA]"), "file-write-ruby", "FILE_WRITE"),
|
|
242
|
+
(_re.compile(r"\.write\s*\("), "file-write", "FILE_WRITE"),
|
|
243
|
+
(_re.compile(r"pathlib\.Path\([^)]*\)\.(rename|write_)"), "pathlib-write", "FILE_WRITE"),
|
|
244
|
+
|
|
245
|
+
# Category: File System Mutation (os.rename, os.makedirs, shutil.copy)
|
|
246
|
+
(_re.compile(r"\bos\.rename\s*\("), "os-rename", "FILE_MUTATION"),
|
|
247
|
+
(_re.compile(r"\bos\.makedirs?\s*\("), "os-makedirs", "FILE_MUTATION"),
|
|
248
|
+
(_re.compile(r"\bshutil\.copy\s*\("), "shutil-copy", "FILE_MUTATION"),
|
|
249
|
+
|
|
250
|
+
# Category: Network
|
|
251
|
+
(_re.compile(r"\bhttps?://\S+"), "url-literal", "NETWORK"),
|
|
252
|
+
(_re.compile(r"\b(fetch|axios|requests\.get|urllib)\s*\("), "http-call", "NETWORK"),
|
|
253
|
+
(_re.compile(r"\bNet::HTTP\b"), "net-http", "NETWORK"),
|
|
254
|
+
|
|
255
|
+
# Category: Permission Modification
|
|
256
|
+
(_re.compile(r"\bos\.chmod\s*\("), "os-chmod", "PERMISSION_MOD"),
|
|
257
|
+
(_re.compile(r"\bfs\.chmod(Sync)?\s*\("), "fs-chmod", "PERMISSION_MOD"),
|
|
182
258
|
)
|
|
183
259
|
|
|
184
|
-
#
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
260
|
+
# ---------------------------------------------------------------------------
|
|
261
|
+
# Layer 3: Heuristic safety classification
|
|
262
|
+
# ---------------------------------------------------------------------------
|
|
263
|
+
_SUSPICIOUS_HEURISTICS: Tuple[Tuple[_re.Pattern, str], ...] = (
|
|
264
|
+
(_re.compile(r"(/etc/|/home/|~/\.ssh|/var/|/usr/|/root/)"), "sensitive-path"),
|
|
265
|
+
(_re.compile(r"\b(base64|b64encode|b64decode|atob|btoa)\b"), "encoding"),
|
|
266
|
+
(_re.compile(r"\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b"), "ip-address"),
|
|
267
|
+
)
|
|
268
|
+
|
|
269
|
+
MAX_SAFE_INLINE_LENGTH = 150
|
|
270
|
+
MAX_NORMAL_INLINE_LENGTH = 500
|
|
188
271
|
|
|
189
272
|
|
|
190
273
|
# ============================================================================
|
|
@@ -458,11 +541,12 @@ def detect_mutative_command(command: str) -> MutativeResult:
|
|
|
458
541
|
reason=f"Simulation flag detected (command has --dry-run or equivalent)",
|
|
459
542
|
)
|
|
460
543
|
|
|
461
|
-
# --- Step 3b: Inline code safety check (python3 -c
|
|
462
|
-
# For runtime interpreters with
|
|
463
|
-
#
|
|
464
|
-
# generic keywords like "import", "create", etc.).
|
|
465
|
-
|
|
544
|
+
# --- Step 3b: Inline code safety check (python3 -c, node -e, etc.) ---
|
|
545
|
+
# For runtime interpreters with inline code flags, scan the code string
|
|
546
|
+
# using the 3-layer approach instead of verb-matching tokens (which would
|
|
547
|
+
# false-positive on generic keywords like "import", "create", etc.).
|
|
548
|
+
cli_flags = _INLINE_CODE_MAP.get(base_cmd, frozenset())
|
|
549
|
+
if base_cmd in _INLINE_CODE_CLIS and cli_flags & set(semantics.flag_tokens):
|
|
466
550
|
return _check_inline_code(command, base_cmd, family)
|
|
467
551
|
|
|
468
552
|
# --- Step 4: Scan semantic non-flag tokens near the command head ---
|
|
@@ -612,21 +696,41 @@ def detect_mutative_command(command: str) -> MutativeResult:
|
|
|
612
696
|
# ============================================================================
|
|
613
697
|
|
|
614
698
|
def _check_inline_code(command: str, base_cmd: str, family: str) -> MutativeResult:
|
|
615
|
-
"""Check inline code
|
|
699
|
+
"""Check inline code for dangerous patterns using a 3-layer approach.
|
|
616
700
|
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
701
|
+
Layer 1: Extract string literals from inline code and check them against
|
|
702
|
+
blocked_commands (catches embedded shell commands like 'rm -rf /').
|
|
703
|
+
Layer 2: Scan for universal dangerous API keywords (language-agnostic).
|
|
704
|
+
Layer 3: Heuristic safety classification (length, sensitive paths, encoding).
|
|
620
705
|
|
|
621
706
|
Args:
|
|
622
707
|
command: Full raw command string.
|
|
623
|
-
base_cmd: The interpreter (e.g., "python3").
|
|
708
|
+
base_cmd: The interpreter (e.g., "python3", "node", "ruby").
|
|
624
709
|
family: CLI family hint.
|
|
625
710
|
|
|
626
711
|
Returns:
|
|
627
|
-
MutativeResult -- MUTATIVE if
|
|
712
|
+
MutativeResult -- MUTATIVE if any layer triggers, else safe.
|
|
628
713
|
"""
|
|
629
|
-
|
|
714
|
+
# ---- Layer 1: Extract string literals → check against blocked_commands ----
|
|
715
|
+
if _is_blocked_command is not None:
|
|
716
|
+
embedded_strings = _extract_embedded_shell_commands(command)
|
|
717
|
+
for literal in embedded_strings:
|
|
718
|
+
blocked = _is_blocked_command(literal)
|
|
719
|
+
if blocked.is_blocked:
|
|
720
|
+
return MutativeResult(
|
|
721
|
+
is_mutative=True,
|
|
722
|
+
category=CATEGORY_MUTATIVE,
|
|
723
|
+
verb="embedded-blocked-cmd",
|
|
724
|
+
cli_family=family,
|
|
725
|
+
confidence="high",
|
|
726
|
+
reason=(
|
|
727
|
+
f"Inline code contains blocked shell command in "
|
|
728
|
+
f"string literal: {blocked.category}"
|
|
729
|
+
),
|
|
730
|
+
)
|
|
731
|
+
|
|
732
|
+
# ---- Layer 2: Universal dangerous API keyword patterns ----
|
|
733
|
+
for pattern, label, category in _UNIVERSAL_DANGEROUS_PATTERNS:
|
|
630
734
|
if pattern.search(command):
|
|
631
735
|
return MutativeResult(
|
|
632
736
|
is_mutative=True,
|
|
@@ -634,17 +738,54 @@ def _check_inline_code(command: str, base_cmd: str, family: str) -> MutativeResu
|
|
|
634
738
|
verb=label,
|
|
635
739
|
cli_family=family,
|
|
636
740
|
confidence="medium",
|
|
637
|
-
reason=f"Inline code contains dangerous pattern: {label}",
|
|
741
|
+
reason=f"Inline code contains dangerous pattern: {label} ({category})",
|
|
638
742
|
)
|
|
639
743
|
|
|
640
|
-
#
|
|
744
|
+
# ---- Layer 3: Heuristic safety classification ----
|
|
745
|
+
# 3a: Check for suspicious indicators (sensitive paths, encoding, IPs)
|
|
746
|
+
for pattern, label in _SUSPICIOUS_HEURISTICS:
|
|
747
|
+
if pattern.search(command):
|
|
748
|
+
return MutativeResult(
|
|
749
|
+
is_mutative=True,
|
|
750
|
+
category=CATEGORY_MUTATIVE,
|
|
751
|
+
verb=f"heuristic-{label}",
|
|
752
|
+
cli_family=family,
|
|
753
|
+
confidence="low",
|
|
754
|
+
reason=f"Inline code flagged by heuristic: {label}",
|
|
755
|
+
)
|
|
756
|
+
|
|
757
|
+
# 3b: Unusually long inline code is suspicious
|
|
758
|
+
# Extract the code portion after the inline flag for length check.
|
|
759
|
+
# Use a rough extraction: everything after the first inline flag.
|
|
760
|
+
code_portion = command
|
|
761
|
+
cli_flag_tokens = _INLINE_CODE_MAP.get(base_cmd, frozenset())
|
|
762
|
+
for flag in cli_flag_tokens:
|
|
763
|
+
idx = command.find(f" {flag} ")
|
|
764
|
+
if idx != -1:
|
|
765
|
+
code_portion = command[idx + len(flag) + 2:]
|
|
766
|
+
break
|
|
767
|
+
|
|
768
|
+
if len(code_portion) > MAX_NORMAL_INLINE_LENGTH:
|
|
769
|
+
return MutativeResult(
|
|
770
|
+
is_mutative=True,
|
|
771
|
+
category=CATEGORY_MUTATIVE,
|
|
772
|
+
verb="heuristic-long-code",
|
|
773
|
+
cli_family=family,
|
|
774
|
+
confidence="low",
|
|
775
|
+
reason=(
|
|
776
|
+
f"Inline code is unusually long ({len(code_portion)} chars > "
|
|
777
|
+
f"{MAX_NORMAL_INLINE_LENGTH} limit)"
|
|
778
|
+
),
|
|
779
|
+
)
|
|
780
|
+
|
|
781
|
+
# ---- No layers triggered -- safe inline code ----
|
|
641
782
|
return MutativeResult(
|
|
642
783
|
is_mutative=False,
|
|
643
784
|
category=CATEGORY_READ_ONLY,
|
|
644
785
|
verb="inline-code",
|
|
645
786
|
cli_family=family,
|
|
646
787
|
confidence="medium",
|
|
647
|
-
reason=f"Inline code ({base_cmd}
|
|
788
|
+
reason=f"Inline code ({base_cmd}) with no dangerous patterns",
|
|
648
789
|
)
|
|
649
790
|
|
|
650
791
|
|
|
@@ -13,6 +13,7 @@ Tiers:
|
|
|
13
13
|
- T3: State-modifying operations (mutative_verbs.py detection,
|
|
14
14
|
nonce-based approval via approval_grants.py)
|
|
15
15
|
"""
|
|
16
|
+
from __future__ import annotations
|
|
16
17
|
|
|
17
18
|
import re
|
|
18
19
|
import logging
|
|
@@ -193,22 +194,3 @@ def classify_command_tier(
|
|
|
193
194
|
|
|
194
195
|
# Use cached classification
|
|
195
196
|
return _classify_command_tier_cached(command, has_blocked)
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
def tier_from_string(tier_str: str) -> SecurityTier:
|
|
199
|
-
"""
|
|
200
|
-
Convert string to SecurityTier.
|
|
201
|
-
|
|
202
|
-
Args:
|
|
203
|
-
tier_str: Tier string like "T0", "T1", "T2", "T3"
|
|
204
|
-
|
|
205
|
-
Returns:
|
|
206
|
-
SecurityTier enum value
|
|
207
|
-
"""
|
|
208
|
-
tier_map = {
|
|
209
|
-
"T0": SecurityTier.T0_READ_ONLY,
|
|
210
|
-
"T1": SecurityTier.T1_VALIDATION,
|
|
211
|
-
"T2": SecurityTier.T2_DRY_RUN,
|
|
212
|
-
"T3": SecurityTier.T3_BLOCKED,
|
|
213
|
-
}
|
|
214
|
-
return tier_map.get(tier_str.upper(), SecurityTier.T3_BLOCKED)
|
|
@@ -5,6 +5,7 @@ Subsystem 4 of the pre_tool_use Task/Agent path.
|
|
|
5
5
|
Filters events by agent domain and injects them into agent prompts.
|
|
6
6
|
Includes the hardcoded agent-to-event mapping.
|
|
7
7
|
"""
|
|
8
|
+
from __future__ import annotations
|
|
8
9
|
|
|
9
10
|
import json
|
|
10
11
|
import logging
|
|
@@ -155,28 +156,3 @@ def build_session_events(
|
|
|
155
156
|
return None
|
|
156
157
|
|
|
157
158
|
|
|
158
|
-
def inject_session_events(
|
|
159
|
-
parameters: dict,
|
|
160
|
-
project_agents: list,
|
|
161
|
-
) -> dict:
|
|
162
|
-
"""
|
|
163
|
-
Legacy wrapper: inject session events by mutating parameters["prompt"].
|
|
164
|
-
|
|
165
|
-
Retained for backward compatibility (tests import this function).
|
|
166
|
-
New code should use build_session_events() with additionalContext instead.
|
|
167
|
-
|
|
168
|
-
Args:
|
|
169
|
-
parameters: Task tool parameters (will be mutated).
|
|
170
|
-
project_agents: List of valid project agent names.
|
|
171
|
-
|
|
172
|
-
Returns:
|
|
173
|
-
Modified parameters with events injected into prompt.
|
|
174
|
-
"""
|
|
175
|
-
events_string = build_session_events(parameters, project_agents)
|
|
176
|
-
if events_string is None:
|
|
177
|
-
return parameters
|
|
178
|
-
|
|
179
|
-
prompt = parameters.get("prompt", "")
|
|
180
|
-
enriched_prompt = f"{prompt}\n\n{events_string}\n"
|
|
181
|
-
parameters["prompt"] = enriched_prompt
|
|
182
|
-
return parameters
|