@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
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
# Validation Module
|
|
2
|
+
|
|
3
|
+
**Purpose:** Approval gates and commit validation for T3 operations
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
This module provides two critical validation components for the gaia-ops system:
|
|
8
|
+
|
|
9
|
+
1. **Commit Message Validator** - Enforces Conventional Commits format
|
|
10
|
+
2. **Approval Gate** - Manages T3 approval workflow with audit trail
|
|
11
|
+
|
|
12
|
+
## Core Components
|
|
13
|
+
|
|
14
|
+
### 1. Commit Message Validator
|
|
15
|
+
|
|
16
|
+
**MOVED:** Commit validation has been moved to `hooks/modules/validation/commit_validator.py`
|
|
17
|
+
and is now only used internally by `hooks/modules/tools/bash_validator.py`.
|
|
18
|
+
|
|
19
|
+
This ensures commit validation is enforced automatically during git commit commands
|
|
20
|
+
without requiring explicit imports in agent code.
|
|
21
|
+
|
|
22
|
+
**What it validates:**
|
|
23
|
+
- ✅ Conventional Commits format (`type(scope): description`)
|
|
24
|
+
- ✅ Allowed types (feat, fix, refactor, docs, test, chore, ci, perf, style, build)
|
|
25
|
+
- ✅ Subject line rules (max 72 chars, no period at end)
|
|
26
|
+
- ✅ Forbidden footers (no "Generated with" footers)
|
|
27
|
+
|
|
28
|
+
**Configuration:** `.claude/config/git_standards.json` (SSOT)
|
|
29
|
+
**Logs:** `.claude/logs/commit-violations.jsonl`
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
### 2. Approval Gate
|
|
34
|
+
|
|
35
|
+
Manages T3 operation approval workflow with structured questions and audit trail.
|
|
36
|
+
|
|
37
|
+
**Files:**
|
|
38
|
+
- `approval_gate.py` - Main approval gate
|
|
39
|
+
- `test_approval_gate.py` - Test suite
|
|
40
|
+
|
|
41
|
+
**Usage:**
|
|
42
|
+
```python
|
|
43
|
+
from tools.validation import request_approval, process_approval_response
|
|
44
|
+
|
|
45
|
+
# Generate approval question
|
|
46
|
+
approval = request_approval(
|
|
47
|
+
realization_package,
|
|
48
|
+
agent_name="gitops-operator",
|
|
49
|
+
phase="Phase 4"
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
# Show summary to user
|
|
53
|
+
print(approval["summary"])
|
|
54
|
+
|
|
55
|
+
# Ask for approval
|
|
56
|
+
response = AskUserQuestion(**approval["question_config"])
|
|
57
|
+
|
|
58
|
+
# Process response
|
|
59
|
+
result = process_approval_response(
|
|
60
|
+
approval["gate_instance"],
|
|
61
|
+
response,
|
|
62
|
+
realization_package,
|
|
63
|
+
agent_name,
|
|
64
|
+
phase
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
if result["approved"]:
|
|
68
|
+
# Proceed to execution
|
|
69
|
+
execute_plan()
|
|
70
|
+
else:
|
|
71
|
+
# Halt workflow
|
|
72
|
+
return {"status": "rejected"}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
**Features:**
|
|
76
|
+
- 📊 Visual summary of realization package
|
|
77
|
+
- 🔍 Counts operations and resources
|
|
78
|
+
- 📝 Audit trail of all approval decisions
|
|
79
|
+
- ✅ Structured approval questions for AskUserQuestion
|
|
80
|
+
|
|
81
|
+
**Logs:** `.claude/logs/approvals.jsonl`
|
|
82
|
+
|
|
83
|
+
**Testing:**
|
|
84
|
+
```bash
|
|
85
|
+
python3 .claude/tools/validation/test_approval_gate.py
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## Integration with Skills
|
|
91
|
+
|
|
92
|
+
This validation module works with skills in a **hybrid model**:
|
|
93
|
+
|
|
94
|
+
- **Skills** (`.claude/skills/`) - Document patterns and guide agents
|
|
95
|
+
- **Code** (this module) - Enforce rules and ensure consistency
|
|
96
|
+
|
|
97
|
+
**Skills updated:**
|
|
98
|
+
- `approval/SKILL.md` - References automatic validation
|
|
99
|
+
- `execution/SKILL.md` - Documents commit validation integration
|
|
100
|
+
|
|
101
|
+
**Division of responsibility:**
|
|
102
|
+
- **Skills guide:** Show examples, explain context, teach patterns
|
|
103
|
+
- **Code enforces:** Block invalid commits, log decisions, ensure compliance
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## Architecture
|
|
108
|
+
|
|
109
|
+
```
|
|
110
|
+
┌──────────────────────────────────────────────────────────┐
|
|
111
|
+
│ config/git_standards.json (SSOT) │
|
|
112
|
+
│ - Conventional commit types │
|
|
113
|
+
│ - Forbidden footers │
|
|
114
|
+
│ - Max lengths │
|
|
115
|
+
└──────────────────────────────────────────────────────────┘
|
|
116
|
+
│
|
|
117
|
+
▼
|
|
118
|
+
┌──────────────────────────────────────────────────────────┐
|
|
119
|
+
│ hooks/modules/validation/ (Commit Validation) │
|
|
120
|
+
│ └─ commit_validator.py │
|
|
121
|
+
│ └─ Used by bash_validator.py only │
|
|
122
|
+
└──────────────────────────────────────────────────────────┘
|
|
123
|
+
│
|
|
124
|
+
▼
|
|
125
|
+
┌──────────────────────────────────────────────────────────┐
|
|
126
|
+
│ tools/validation/ (Approval Enforcement) │
|
|
127
|
+
│ └─ approval_gate.py │
|
|
128
|
+
│ └─ Manages T3 approval workflow │
|
|
129
|
+
└──────────────────────────────────────────────────────────┘
|
|
130
|
+
│
|
|
131
|
+
▼
|
|
132
|
+
┌──────────────────────────────────────────────────────────┐
|
|
133
|
+
│ skills/ (Guidance) │
|
|
134
|
+
│ ├─ approval/SKILL.md │
|
|
135
|
+
│ │ └─ How to present plans │
|
|
136
|
+
│ └─ execution/SKILL.md │
|
|
137
|
+
│ └─ How to execute safely │
|
|
138
|
+
└──────────────────────────────────────────────────────────┘
|
|
139
|
+
│
|
|
140
|
+
▼
|
|
141
|
+
┌──────────────────────────────────────────────────────────┐
|
|
142
|
+
│ logs/ (Audit Trail) │
|
|
143
|
+
│ ├─ commit-violations.jsonl │
|
|
144
|
+
│ └─ approvals.jsonl │
|
|
145
|
+
└──────────────────────────────────────────────────────────┘
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## Security Tiers
|
|
151
|
+
|
|
152
|
+
| Tier | Operations | Validation | Approval Gate |
|
|
153
|
+
|------|-----------|-----------|---------------|
|
|
154
|
+
| T0 | Read-only | No | No |
|
|
155
|
+
| T1 | Local changes | Yes | No |
|
|
156
|
+
| T2 | Reversible remote | Yes | No |
|
|
157
|
+
| T3 | Irreversible | **Yes** | **Yes** ⚠️ |
|
|
158
|
+
|
|
159
|
+
**T3 operations require:**
|
|
160
|
+
1. ✅ Commit message validation (enforced by commit_validator.py)
|
|
161
|
+
2. ✅ Approval gate (enforced by approval_gate.py)
|
|
162
|
+
3. ✅ Audit trail (logged automatically)
|
|
163
|
+
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
## Files
|
|
167
|
+
|
|
168
|
+
```
|
|
169
|
+
validation/
|
|
170
|
+
├── __init__.py # Module exports
|
|
171
|
+
├── README.md # This file
|
|
172
|
+
└── approval_gate.py # T3 approval workflow
|
|
173
|
+
|
|
174
|
+
Note: commit_validator.py moved to hooks/modules/validation/
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
## Configuration
|
|
180
|
+
|
|
181
|
+
**Git Standards:** `.claude/config/git_standards.json`
|
|
182
|
+
|
|
183
|
+
Example:
|
|
184
|
+
```json
|
|
185
|
+
{
|
|
186
|
+
"commit_message": {
|
|
187
|
+
"type_allowed": ["feat", "fix", "refactor", "docs", "test", "chore"],
|
|
188
|
+
"subject_max_length": 72,
|
|
189
|
+
"footer_forbidden": ["Generated with Claude Code"]
|
|
190
|
+
},
|
|
191
|
+
"enforcement": {
|
|
192
|
+
"enabled": true,
|
|
193
|
+
"block_on_failure": true,
|
|
194
|
+
"log_violations": true
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
## Logs
|
|
202
|
+
|
|
203
|
+
**Commit Violations:** `.claude/logs/commit-violations.jsonl`
|
|
204
|
+
|
|
205
|
+
Example entry:
|
|
206
|
+
```json
|
|
207
|
+
{
|
|
208
|
+
"timestamp": "2026-01-15T19:34:12.345678",
|
|
209
|
+
"message": "Added new feature...",
|
|
210
|
+
"errors": [{"type": "INVALID_FORMAT", "message": "..."}],
|
|
211
|
+
"error_count": 1
|
|
212
|
+
}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
**Approvals:** `.claude/logs/approvals.jsonl`
|
|
216
|
+
|
|
217
|
+
Example entry:
|
|
218
|
+
```json
|
|
219
|
+
{
|
|
220
|
+
"timestamp": "2026-01-15T19:35:00.123456",
|
|
221
|
+
"agent": "gitops-operator",
|
|
222
|
+
"phase": "Phase 4",
|
|
223
|
+
"approved": true,
|
|
224
|
+
"user_response": "✅ Aprobar y ejecutar",
|
|
225
|
+
"files_count": 2,
|
|
226
|
+
"operations": "git push origin main",
|
|
227
|
+
"git_commit": "feat(graphql): update image to v1.0.180"
|
|
228
|
+
}
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
---
|
|
232
|
+
|
|
233
|
+
## See Also
|
|
234
|
+
|
|
235
|
+
- `.claude/config/git_standards.json` - Git standards configuration
|
|
236
|
+
- `.claude/skills/approval/SKILL.md` - Approval workflow patterns
|
|
237
|
+
- `.claude/skills/execution/SKILL.md` - Execution workflow patterns
|
|
238
|
+
- `CLAUDE.md` - Orchestrator protocol with T3 workflow
|
|
239
|
+
|
|
240
|
+
---
|
|
241
|
+
|
|
242
|
+
**Version:** 4.2.0
|
|
243
|
+
**Last Updated:** 2026-03-11
|
|
244
|
+
**Maintained by:** gaia-ops validation team
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Validation Module: Approval gates for T3 operations
|
|
3
|
+
|
|
4
|
+
This module provides T3 approval gate enforcement.
|
|
5
|
+
Ensures infrastructure changes and critical operations follow proper governance.
|
|
6
|
+
|
|
7
|
+
Note: commit_validator.py has been moved to hooks/modules/validation/
|
|
8
|
+
and is now only used by bash_validator.py
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from .approval_gate import ApprovalGate, request_approval, process_approval_response
|
|
12
|
+
|
|
13
|
+
__all__ = [
|
|
14
|
+
"ApprovalGate",
|
|
15
|
+
"request_approval",
|
|
16
|
+
"process_approval_response",
|
|
17
|
+
]
|
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Approval Gate Enforcement
|
|
3
|
+
|
|
4
|
+
Ensures that no realization occurs without explicit user approval.
|
|
5
|
+
This is a CRITICAL component of the Two-Phase Workflow.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import json
|
|
9
|
+
import os
|
|
10
|
+
from typing import Dict, Any, Optional
|
|
11
|
+
from datetime import datetime
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class ApprovalGate:
|
|
15
|
+
"""
|
|
16
|
+
Enforces approval gate before any realization actions.
|
|
17
|
+
|
|
18
|
+
CRITICAL: This gate is MANDATORY in the workflow. No realization
|
|
19
|
+
can proceed without explicit user approval via AskUserQuestion.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
def __init__(self):
|
|
23
|
+
# Calculate base path (.claude/) from this file location
|
|
24
|
+
# From .claude/tools/validation/ go up to .claude/
|
|
25
|
+
base_path = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
26
|
+
self.approval_log_path = os.path.join(base_path, "logs", "approvals.jsonl")
|
|
27
|
+
self._ensure_log_directory()
|
|
28
|
+
|
|
29
|
+
def _ensure_log_directory(self):
|
|
30
|
+
"""Ensure the logs directory exists."""
|
|
31
|
+
log_dir = os.path.dirname(self.approval_log_path)
|
|
32
|
+
os.makedirs(log_dir, exist_ok=True)
|
|
33
|
+
|
|
34
|
+
def generate_approval_question(
|
|
35
|
+
self,
|
|
36
|
+
realization_package: Dict[str, Any],
|
|
37
|
+
agent_name: str,
|
|
38
|
+
phase: str
|
|
39
|
+
) -> Dict[str, Any]:
|
|
40
|
+
"""
|
|
41
|
+
Generate the approval question configuration for AskUserQuestion tool.
|
|
42
|
+
|
|
43
|
+
Args:
|
|
44
|
+
realization_package: The plan to be realized
|
|
45
|
+
agent_name: Name of the agent that generated the plan
|
|
46
|
+
phase: Current phase (e.g., "Phase 3.3")
|
|
47
|
+
|
|
48
|
+
Returns:
|
|
49
|
+
Dict with AskUserQuestion configuration
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
critical_ops = self._get_critical_operations(realization_package)
|
|
53
|
+
operation_count = self._get_operation_count(realization_package)
|
|
54
|
+
|
|
55
|
+
return {
|
|
56
|
+
"questions": [{
|
|
57
|
+
"question": f"¿Apruebas la realización de este plan? Se ejecutará: {critical_ops}",
|
|
58
|
+
"header": "Approval",
|
|
59
|
+
"multiSelect": False,
|
|
60
|
+
"options": [
|
|
61
|
+
{
|
|
62
|
+
"label": "✅ Aprobar y ejecutar",
|
|
63
|
+
"description": f"Proceder con {operation_count} operaciones: {critical_ops}"
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"label": "❌ Rechazar",
|
|
67
|
+
"description": "Cancelar la realización. No se harán cambios."
|
|
68
|
+
}
|
|
69
|
+
]
|
|
70
|
+
}]
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
def generate_summary(self, realization_package: Dict[str, Any]) -> str:
|
|
74
|
+
"""
|
|
75
|
+
Generate human-readable summary of the realization package.
|
|
76
|
+
|
|
77
|
+
This summary should be presented to the user BEFORE calling
|
|
78
|
+
AskUserQuestion so they have full context for their decision.
|
|
79
|
+
"""
|
|
80
|
+
|
|
81
|
+
summary_parts = []
|
|
82
|
+
summary_parts.append("="*60)
|
|
83
|
+
summary_parts.append("📦 REALIZATION PACKAGE - APPROVAL REQUIRED")
|
|
84
|
+
summary_parts.append("="*60)
|
|
85
|
+
|
|
86
|
+
# Files
|
|
87
|
+
if "files" in realization_package:
|
|
88
|
+
files = realization_package["files"]
|
|
89
|
+
summary_parts.append(f"\n**Archivos a crear/modificar:** {len(files)}")
|
|
90
|
+
for file_info in files[:10]: # Show first 10
|
|
91
|
+
action = file_info.get('action', 'create')
|
|
92
|
+
summary_parts.append(f" [{action}] {file_info['path']}")
|
|
93
|
+
if len(files) > 10:
|
|
94
|
+
summary_parts.append(f" ... y {len(files) - 10} archivos más")
|
|
95
|
+
|
|
96
|
+
# Git operations
|
|
97
|
+
if "git_operations" in realization_package:
|
|
98
|
+
git_ops = realization_package["git_operations"]
|
|
99
|
+
summary_parts.append(f"\n**Git Operations:**")
|
|
100
|
+
summary_parts.append(f" Commit: {git_ops.get('commit_message', 'N/A')}")
|
|
101
|
+
summary_parts.append(f" Branch: {git_ops.get('branch', 'main')}")
|
|
102
|
+
summary_parts.append(f" Remote: {git_ops.get('remote', 'origin')}")
|
|
103
|
+
summary_parts.append(f" Operation: git push")
|
|
104
|
+
|
|
105
|
+
# Resources affected
|
|
106
|
+
if "resources_affected" in realization_package:
|
|
107
|
+
resources = realization_package["resources_affected"]
|
|
108
|
+
summary_parts.append(f"\n**Recursos Afectados en el Cluster:**")
|
|
109
|
+
for resource_type, items in resources.items():
|
|
110
|
+
if isinstance(items, list):
|
|
111
|
+
summary_parts.append(f" {resource_type}: {len(items)}")
|
|
112
|
+
for item in items[:5]:
|
|
113
|
+
summary_parts.append(f" - {item}")
|
|
114
|
+
if len(items) > 5:
|
|
115
|
+
summary_parts.append(f" ... y {len(items) - 5} más")
|
|
116
|
+
else:
|
|
117
|
+
summary_parts.append(f" {resource_type}: {items}")
|
|
118
|
+
|
|
119
|
+
# Terraform operations
|
|
120
|
+
if "terraform_operations" in realization_package:
|
|
121
|
+
tf_ops = realization_package["terraform_operations"]
|
|
122
|
+
summary_parts.append(f"\n**Terraform Operations:**")
|
|
123
|
+
summary_parts.append(f" Command: {tf_ops.get('command', 'N/A')}")
|
|
124
|
+
summary_parts.append(f" Path: {tf_ops.get('path', 'N/A')}")
|
|
125
|
+
if "resources" in tf_ops:
|
|
126
|
+
summary_parts.append(f" Resources to change: {len(tf_ops['resources'])}")
|
|
127
|
+
|
|
128
|
+
# Validation results (if present)
|
|
129
|
+
if "validation_results" in realization_package:
|
|
130
|
+
validation = realization_package["validation_results"]
|
|
131
|
+
summary_parts.append(f"\n**Pre-Deployment Validation:**")
|
|
132
|
+
summary_parts.append(f" Status: {validation.get('status', 'N/A')}")
|
|
133
|
+
if validation.get('warnings'):
|
|
134
|
+
summary_parts.append(f" ⚠️ Warnings: {len(validation['warnings'])}")
|
|
135
|
+
for warning in validation['warnings'][:3]:
|
|
136
|
+
summary_parts.append(f" - {warning}")
|
|
137
|
+
|
|
138
|
+
# Estimated impact
|
|
139
|
+
if "estimated_impact" in realization_package:
|
|
140
|
+
impact = realization_package["estimated_impact"]
|
|
141
|
+
summary_parts.append(f"\n**Estimated Impact:**")
|
|
142
|
+
summary_parts.append(f" Downtime: {impact.get('downtime', 'None expected')}")
|
|
143
|
+
summary_parts.append(f" Risk Level: {impact.get('risk_level', 'Medium')}")
|
|
144
|
+
|
|
145
|
+
summary_parts.append("\n" + "="*60)
|
|
146
|
+
|
|
147
|
+
return "\n".join(summary_parts)
|
|
148
|
+
|
|
149
|
+
def _get_critical_operations(self, realization_package: Dict[str, Any]) -> str:
|
|
150
|
+
"""Extract critical operations for the approval question."""
|
|
151
|
+
operations = []
|
|
152
|
+
|
|
153
|
+
if "git_operations" in realization_package:
|
|
154
|
+
git_ops = realization_package["git_operations"]
|
|
155
|
+
branch = git_ops.get('branch', 'main')
|
|
156
|
+
operations.append(f"git push origin {branch}")
|
|
157
|
+
|
|
158
|
+
if "kubectl_operations" in realization_package:
|
|
159
|
+
operations.append("kubectl apply")
|
|
160
|
+
|
|
161
|
+
if "terraform_operations" in realization_package:
|
|
162
|
+
tf_ops = realization_package["terraform_operations"]
|
|
163
|
+
command = tf_ops.get('command', 'apply')
|
|
164
|
+
operations.append(f"terraform {command}")
|
|
165
|
+
|
|
166
|
+
if "flux_operations" in realization_package:
|
|
167
|
+
operations.append("flux reconcile")
|
|
168
|
+
|
|
169
|
+
return ", ".join(operations) if operations else "cambios al repositorio"
|
|
170
|
+
|
|
171
|
+
def _get_operation_count(self, realization_package: Dict[str, Any]) -> int:
|
|
172
|
+
"""Count total operations in the package."""
|
|
173
|
+
count = 0
|
|
174
|
+
|
|
175
|
+
if "files" in realization_package:
|
|
176
|
+
count += len(realization_package["files"])
|
|
177
|
+
|
|
178
|
+
if "git_operations" in realization_package:
|
|
179
|
+
count += 2 # commit + push
|
|
180
|
+
|
|
181
|
+
if "kubectl_operations" in realization_package:
|
|
182
|
+
kubectl_ops = realization_package["kubectl_operations"]
|
|
183
|
+
count += len(kubectl_ops) if isinstance(kubectl_ops, list) else 1
|
|
184
|
+
|
|
185
|
+
if "terraform_operations" in realization_package:
|
|
186
|
+
count += 1
|
|
187
|
+
|
|
188
|
+
return count
|
|
189
|
+
|
|
190
|
+
def validate_approval_response(self, user_response: str) -> Dict[str, Any]:
|
|
191
|
+
"""
|
|
192
|
+
Validate the user's approval response.
|
|
193
|
+
|
|
194
|
+
Args:
|
|
195
|
+
user_response: The response from AskUserQuestion
|
|
196
|
+
|
|
197
|
+
Returns:
|
|
198
|
+
Dict with validation result and action to take
|
|
199
|
+
"""
|
|
200
|
+
|
|
201
|
+
if user_response == "✅ Aprobar y ejecutar":
|
|
202
|
+
return {
|
|
203
|
+
"approved": True,
|
|
204
|
+
"action": "proceed_to_realization",
|
|
205
|
+
"message": "✅ Aprobación recibida. Procediendo a Fase 5 (Realization)..."
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
elif user_response == "❌ Rechazar":
|
|
209
|
+
return {
|
|
210
|
+
"approved": False,
|
|
211
|
+
"action": "halt_workflow",
|
|
212
|
+
"message": "❌ Realización rechazada por el usuario. Workflow detenido."
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
else:
|
|
216
|
+
# User selected "Other" or provided custom response
|
|
217
|
+
return {
|
|
218
|
+
"approved": False,
|
|
219
|
+
"action": "clarify_with_user",
|
|
220
|
+
"message": f"⚠️ Respuesta no estándar recibida: '{user_response}'. Se requiere clarificación.",
|
|
221
|
+
"user_input": user_response
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
def log_approval(
|
|
225
|
+
self,
|
|
226
|
+
realization_package: Dict[str, Any],
|
|
227
|
+
user_response: str,
|
|
228
|
+
approved: bool,
|
|
229
|
+
agent_name: str,
|
|
230
|
+
phase: str
|
|
231
|
+
):
|
|
232
|
+
"""
|
|
233
|
+
Log the approval decision for audit trail.
|
|
234
|
+
|
|
235
|
+
This creates a permanent record of all approval decisions
|
|
236
|
+
for compliance and troubleshooting purposes.
|
|
237
|
+
"""
|
|
238
|
+
|
|
239
|
+
log_entry = {
|
|
240
|
+
"timestamp": datetime.now().isoformat(),
|
|
241
|
+
"agent": agent_name,
|
|
242
|
+
"phase": phase,
|
|
243
|
+
"approved": approved,
|
|
244
|
+
"user_response": user_response,
|
|
245
|
+
"files_count": len(realization_package.get("files", [])),
|
|
246
|
+
"operations": self._get_critical_operations(realization_package),
|
|
247
|
+
"git_commit": realization_package.get("git_operations", {}).get("commit_message", "N/A")
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
# Append to JSONL log file
|
|
251
|
+
with open(self.approval_log_path, "a") as f:
|
|
252
|
+
f.write(json.dumps(log_entry) + "\n")
|
|
253
|
+
|
|
254
|
+
return log_entry
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
# Convenience function for orchestrator to use
|
|
258
|
+
def request_approval(
|
|
259
|
+
realization_package: Dict[str, Any],
|
|
260
|
+
agent_name: str,
|
|
261
|
+
phase: str
|
|
262
|
+
) -> Dict[str, Any]:
|
|
263
|
+
"""
|
|
264
|
+
Main function to request approval from user.
|
|
265
|
+
|
|
266
|
+
This should be called by the orchestrator in Phase 4 (Approval Gate).
|
|
267
|
+
|
|
268
|
+
Args:
|
|
269
|
+
realization_package: The complete realization package from the agent
|
|
270
|
+
agent_name: Name of the agent that generated the plan
|
|
271
|
+
phase: Current phase identifier
|
|
272
|
+
|
|
273
|
+
Returns:
|
|
274
|
+
Dict with:
|
|
275
|
+
- summary: String to present to user
|
|
276
|
+
- question_config: Dict to pass to AskUserQuestion tool
|
|
277
|
+
"""
|
|
278
|
+
|
|
279
|
+
gate = ApprovalGate()
|
|
280
|
+
|
|
281
|
+
return {
|
|
282
|
+
"summary": gate.generate_summary(realization_package),
|
|
283
|
+
"question_config": gate.generate_approval_question(realization_package, agent_name, phase),
|
|
284
|
+
"gate_instance": gate
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
def process_approval_response(
|
|
289
|
+
gate_instance: ApprovalGate,
|
|
290
|
+
user_response: str,
|
|
291
|
+
realization_package: Dict[str, Any],
|
|
292
|
+
agent_name: str,
|
|
293
|
+
phase: str
|
|
294
|
+
) -> Dict[str, Any]:
|
|
295
|
+
"""
|
|
296
|
+
Process the user's approval response.
|
|
297
|
+
|
|
298
|
+
Args:
|
|
299
|
+
gate_instance: The ApprovalGate instance from request_approval
|
|
300
|
+
user_response: The user's response from AskUserQuestion
|
|
301
|
+
realization_package: The realization package
|
|
302
|
+
agent_name: Name of the agent
|
|
303
|
+
phase: Current phase
|
|
304
|
+
|
|
305
|
+
Returns:
|
|
306
|
+
Dict with validation result and action to take
|
|
307
|
+
"""
|
|
308
|
+
|
|
309
|
+
# Validate response
|
|
310
|
+
validation = gate_instance.validate_approval_response(user_response)
|
|
311
|
+
|
|
312
|
+
# Log the decision
|
|
313
|
+
gate_instance.log_approval(
|
|
314
|
+
realization_package,
|
|
315
|
+
user_response,
|
|
316
|
+
validation["approved"],
|
|
317
|
+
agent_name,
|
|
318
|
+
phase
|
|
319
|
+
)
|
|
320
|
+
|
|
321
|
+
return validation
|