@jaguilar87/gaia-ops 4.5.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 +1 -1
- package/ARCHITECTURE.md +9 -8
- package/agents/terraform-architect.md +1 -1
- package/bin/gaia-history.js +0 -1
- package/bin/gaia-metrics.js +2 -2
- package/bin/gaia-scan.py +4 -0
- package/bin/gaia-update.js +146 -22
- 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/{templates/settings.template.json → dist/gaia-ops/hooks/hooks.json} +15 -18
- 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/hooks/README.md +3 -2
- 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 +1 -1
- 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/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/paths.py +12 -13
- package/hooks/modules/core/plugin_setup.py +109 -2
- 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 -22
- 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 +0 -2
- package/hooks/modules/security/blocked_commands.py +2 -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 +0 -19
- package/hooks/modules/session/session_event_injector.py +0 -25
- package/hooks/modules/tools/bash_validator.py +219 -91
- 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 +38 -88
- package/hooks/subagent_start.py +6 -2
- package/hooks/subagent_stop.py +1 -13
- package/hooks/user_prompt_submit.py +89 -1
- package/index.js +1 -1
- package/package.json +3 -2
- 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 +3 -13
- 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
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
{
|
|
9
9
|
"name": "gaia-security",
|
|
10
10
|
"description": "Keeps you in the loop only when it matters. Gaia Security analyzes every command and classifies it into risk tiers: read-only queries run freely, simulations and validations pass through, and state-changing operations (create, delete, apply, push) pause for your explicit approval before executing. Irreversible commands like dropping databases or deleting cloud infrastructure are permanently blocked.",
|
|
11
|
-
"version": "4.
|
|
11
|
+
"version": "4.7.2",
|
|
12
12
|
"source": "./dist/gaia-security"
|
|
13
13
|
}
|
|
14
14
|
]
|
package/ARCHITECTURE.md
CHANGED
|
@@ -25,7 +25,8 @@ User request
|
|
|
25
25
|
v
|
|
26
26
|
user_prompt_submit.py (UserPromptSubmit hook)
|
|
27
27
|
| Inject orchestrator identity via ops_identity.py
|
|
28
|
-
|
|
|
28
|
+
| Inject surface routing recommendation (deterministic)
|
|
29
|
+
| Skills loaded on-demand: agent-response
|
|
29
30
|
v
|
|
30
31
|
Orchestrator dispatches to agent
|
|
31
32
|
| Routes by surface classification
|
|
@@ -49,7 +50,7 @@ subagent_stop.py (SubagentStop hook)
|
|
|
49
50
|
v
|
|
50
51
|
Orchestrator processes json:contract (via agent-response skill)
|
|
51
52
|
| COMPLETE -> summarize to user
|
|
52
|
-
|
|
|
53
|
+
| REVIEW (with approval_id) -> get approval -> resume via SendMessage
|
|
53
54
|
| NEEDS_INPUT -> ask user -> resume via SendMessage
|
|
54
55
|
| BLOCKED -> report blocker
|
|
55
56
|
```
|
|
@@ -170,7 +171,7 @@ Nonce-based T3 approval lifecycle:
|
|
|
170
171
|
3. BashValidator generates 128-bit nonce via generate_nonce()
|
|
171
172
|
4. write_pending_approval() saves pending-{nonce}.json to .claude/cache/approvals/
|
|
172
173
|
5. Hook returns corrective deny (exit 0) with NONCE:{hex} in message
|
|
173
|
-
6. Agent includes NONCE:{hex} in
|
|
174
|
+
6. Agent includes NONCE:{hex} in REVIEW status to orchestrator
|
|
174
175
|
7. Orchestrator presents plan to user, asks for approval
|
|
175
176
|
8. User approves -> orchestrator resumes agent with "APPROVE:{nonce}"
|
|
176
177
|
9. pre_tool_use.py detects APPROVE: prefix, calls activate_pending_approval()
|
|
@@ -182,7 +183,7 @@ Nonce-based T3 approval lifecycle:
|
|
|
182
183
|
|
|
183
184
|
Every agent response must end with a `json:contract` block containing `agent_status`. The contract validator (`hooks/modules/agents/contract_validator.py`) enforces:
|
|
184
185
|
|
|
185
|
-
- **AGENT_STATUS**: PLAN_STATUS (from
|
|
186
|
+
- **AGENT_STATUS**: PLAN_STATUS (from 5 valid states: COMPLETE, NEEDS_INPUT, REVIEW, BLOCKED, IN_PROGRESS), PENDING_STEPS, NEXT_ACTION, AGENT_ID
|
|
186
187
|
- **EVIDENCE_REPORT**: required for all valid states. Seven fields: PATTERNS_CHECKED, FILES_CHECKED, COMMANDS_RUN, KEY_OUTPUTS, VERBATIM_OUTPUTS, CROSS_LAYER_IMPACTS, OPEN_GAPS
|
|
187
188
|
- **CONSOLIDATION_REPORT**: required when multi-surface or cross-check. Fields: OWNERSHIP_ASSESSMENT (enum), CONFIRMED_FINDINGS, SUSPECTED_FINDINGS, CONFLICTS, OPEN_GAPS, NEXT_BEST_AGENT
|
|
188
189
|
|
|
@@ -256,12 +257,12 @@ The adapter layer connects Claude Code's hook protocol to gaia-ops business logi
|
|
|
256
257
|
| **Adapter methods called** | `ClaudeCodeAdapter.format_validation_response()` |
|
|
257
258
|
| **Business logic modules** | None (pure formatting bridge) |
|
|
258
259
|
|
|
259
|
-
### CP-5: `
|
|
260
|
+
### CP-5: `hooks/hooks.json` -- Hook Configuration
|
|
260
261
|
|
|
261
262
|
| Attribute | Value |
|
|
262
263
|
|-----------|-------|
|
|
263
|
-
| **File (npm channel)** | `templates/settings.template.json` -- paths use `.claude/hooks/` prefix |
|
|
264
264
|
| **File (plugin channel)** | `hooks/hooks.json` -- paths use `${CLAUDE_PLUGIN_ROOT}/hooks/` prefix |
|
|
265
|
+
| **File (npm channel)** | `hooks/hooks.json` (symlinked into `.claude/hooks/`) |
|
|
265
266
|
| **What it does** | Maps Claude Code hook events to handler scripts. Defines which events fire which entry points, the tool matchers (Bash, Task, Agent, `*`), and permissions (allow/deny lists). |
|
|
266
267
|
| **Events configured** | PreToolUse (Bash, Task, Agent, SendMessage), PostToolUse, SubagentStop, SessionStart, Stop, TaskCompleted, SubagentStart, UserPromptSubmit (identity injection) |
|
|
267
268
|
|
|
@@ -292,7 +293,7 @@ To add support for a new Claude Code hook event (e.g., a future `PreCompact` eve
|
|
|
292
293
|
2. **Add adapter method** to `ClaudeCodeAdapter` in `hooks/adapters/claude_code.py` -- implement `adapt_<event_name>(raw: dict) -> <ResultType>` and the corresponding `format_<result>_response()` if a new result type is needed.
|
|
293
294
|
3. **Add extract/format methods** for the event type -- the extract method pulls typed data from the raw payload, the format method builds the CLI response JSON.
|
|
294
295
|
4. **Create hook script entry point** -- a new `hooks/<event_name>.py` file that reads stdin, calls `adapter.parse_event()`, delegates to business logic, and writes the response to stdout.
|
|
295
|
-
5. **Add entry to `hooks/hooks.json`**
|
|
296
|
+
5. **Add entry to `hooks/hooks.json`** mapping the event name to the new script.
|
|
296
297
|
|
|
297
298
|
**Zero changes to business logic modules required.** The adapter is the only layer that touches CLI-specific JSON.
|
|
298
299
|
|
|
@@ -311,7 +312,7 @@ To support a CLI other than Claude Code (e.g., a hypothetical Cursor or Windsurf
|
|
|
311
312
|
| File | Purpose |
|
|
312
313
|
|------|---------|
|
|
313
314
|
| `hooks/modules/identity/ops_identity.py` | Orchestrator identity (injected by UserPromptSubmit) |
|
|
314
|
-
| `
|
|
315
|
+
| `config/surface-routing.json` | Surface routing config (agent table, signals, dispatch) |
|
|
315
316
|
| `skills/agent-response/SKILL.md` | Contract status handling protocol (on-demand) |
|
|
316
317
|
| `hooks/pre_tool_use.py` | PreToolUse hook entry point |
|
|
317
318
|
| `hooks/subagent_stop.py` | SubagentStop hook entry point |
|
|
@@ -19,7 +19,7 @@ skills:
|
|
|
19
19
|
|
|
20
20
|
1. **Triage first**: When checking infrastructure state, run the fast-queries Terraform or cloud triage script before running plan/apply.
|
|
21
21
|
2. **Deep analysis**: When investigating drift or complex module dependencies, follow the investigation phases.
|
|
22
|
-
3. **Before T3 operations**: When `terragrunt apply` is needed, present a REVIEW plan first. If a hook blocks it,
|
|
22
|
+
3. **Before T3 operations**: When `terragrunt apply` is needed, present a REVIEW plan first. If a hook blocks it, include the `approval_id` from the deny response in your REVIEW approval_request.
|
|
23
23
|
4. **Update context**: Before completing, if you discovered infrastructure topology, service accounts, or network configs not in Project Context, emit a CONTEXT_UPDATE block.
|
|
24
24
|
|
|
25
25
|
## Identity
|
package/bin/gaia-history.js
CHANGED
|
@@ -125,7 +125,6 @@ function colorStatus(status) {
|
|
|
125
125
|
if (s === 'NEEDS_INPUT') return chalk.yellow(s.padEnd(8));
|
|
126
126
|
if (s === 'IN_PROGRESS') return chalk.cyan(s.padEnd(8));
|
|
127
127
|
if (s === 'REVIEW') return chalk.magenta(s.padEnd(8));
|
|
128
|
-
if (s === 'AWAITING_APPROVAL') return chalk.yellow(s.padEnd(8));
|
|
129
128
|
return chalk.gray(s.padEnd(8));
|
|
130
129
|
}
|
|
131
130
|
|
package/bin/gaia-metrics.js
CHANGED
|
@@ -450,7 +450,7 @@ function calculateAgentInvocations(workflowMetrics) {
|
|
|
450
450
|
|
|
451
451
|
/**
|
|
452
452
|
* Agent outcome distribution from plan_status field.
|
|
453
|
-
* Counts COMPLETE, BLOCKED, NEEDS_INPUT, IN_PROGRESS, REVIEW,
|
|
453
|
+
* Counts COMPLETE, BLOCKED, NEEDS_INPUT, IN_PROGRESS, REVIEW, and others.
|
|
454
454
|
* Returns null if no entries have the plan_status field (older data).
|
|
455
455
|
*/
|
|
456
456
|
function calculateAgentOutcomes(workflowMetrics) {
|
|
@@ -874,7 +874,7 @@ function displayMetrics(
|
|
|
874
874
|
// ── Agent Outcomes ───────────────────────────────────
|
|
875
875
|
if (agentOutcomes) {
|
|
876
876
|
console.log(chalk.bold(`\n📋 Agent Outcomes (${agentOutcomes.total} sessions with status)`));
|
|
877
|
-
const outcomeColor = { COMPLETE: chalk.green, BLOCKED: chalk.red, NEEDS_INPUT: chalk.yellow, IN_PROGRESS: chalk.cyan, REVIEW: chalk.magenta
|
|
877
|
+
const outcomeColor = { COMPLETE: chalk.green, BLOCKED: chalk.red, NEEDS_INPUT: chalk.yellow, IN_PROGRESS: chalk.cyan, REVIEW: chalk.magenta };
|
|
878
878
|
for (const { status, count, percentage } of agentOutcomes.distribution) {
|
|
879
879
|
const bar = makeBar(percentage, 10);
|
|
880
880
|
const pct = percentage.toFixed(1).padStart(5);
|
package/bin/gaia-scan.py
CHANGED
|
@@ -205,6 +205,7 @@ def _mode_fresh(project_root: Path, scan_config: ScanConfig, args) -> int:
|
|
|
205
205
|
generate_governance,
|
|
206
206
|
generate_project_context,
|
|
207
207
|
install_git_hooks,
|
|
208
|
+
merge_hooks_to_settings_local,
|
|
208
209
|
)
|
|
209
210
|
from tools.scan.ui import (
|
|
210
211
|
RailUI,
|
|
@@ -246,6 +247,7 @@ def _mode_fresh(project_root: Path, scan_config: ScanConfig, args) -> int:
|
|
|
246
247
|
create_claude_directory(project_root)
|
|
247
248
|
copy_claude_md(project_root)
|
|
248
249
|
copy_settings_json(project_root)
|
|
250
|
+
merge_hooks_to_settings_local(project_root)
|
|
249
251
|
install_git_hooks(project_root)
|
|
250
252
|
generate_project_context(project_root, config, scan_context=output.context)
|
|
251
253
|
generate_governance(project_root, config)
|
|
@@ -287,6 +289,7 @@ def _mode_existing(project_root: Path, scan_config: ScanConfig, args) -> int:
|
|
|
287
289
|
copy_settings_json,
|
|
288
290
|
create_claude_directory,
|
|
289
291
|
install_git_hooks,
|
|
292
|
+
merge_hooks_to_settings_local,
|
|
290
293
|
)
|
|
291
294
|
from tools.scan.ui import (
|
|
292
295
|
RailUI,
|
|
@@ -317,6 +320,7 @@ def _mode_existing(project_root: Path, scan_config: ScanConfig, args) -> int:
|
|
|
317
320
|
# Step 4: SYNC
|
|
318
321
|
copy_claude_md(project_root)
|
|
319
322
|
copy_settings_json(project_root)
|
|
323
|
+
merge_hooks_to_settings_local(project_root)
|
|
320
324
|
create_claude_directory(project_root)
|
|
321
325
|
install_git_hooks(project_root)
|
|
322
326
|
|
package/bin/gaia-update.js
CHANGED
|
@@ -12,12 +12,14 @@
|
|
|
12
12
|
* 2. Run gaia-scan --npm-postinstall to create .claude/, symlinks, settings, project-context
|
|
13
13
|
* 3. Create plugin-registry.json
|
|
14
14
|
* 4. Merge permissions into settings.local.json
|
|
15
|
-
* 5.
|
|
15
|
+
* 5. Merge hooks into settings.local.json
|
|
16
|
+
* 6. Fall through to verification
|
|
16
17
|
* - Update (.claude/ exists):
|
|
17
18
|
* 1. Show version transition (previous → current)
|
|
18
|
-
* 2. settings.json:
|
|
19
|
-
* 3. Merge permissions into settings.local.json (union, preserves user config)
|
|
20
|
-
* 4.
|
|
19
|
+
* 2. settings.json: create only if missing (non-invasive, never overwrites)
|
|
20
|
+
* 3. Merge permissions + env vars into settings.local.json (union, preserves user config)
|
|
21
|
+
* 4. Merge hooks from hooks.json into settings.local.json (npm mode requires this)
|
|
22
|
+
* 5. Symlinks: recreate if missing, fix broken ones
|
|
21
23
|
* 5. Verify: hooks, python, project-context, config files
|
|
22
24
|
* 6. Report: summary with any issues found
|
|
23
25
|
*
|
|
@@ -78,19 +80,25 @@ async function readPackageVersion(path) {
|
|
|
78
80
|
// ============================================================================
|
|
79
81
|
|
|
80
82
|
async function updateSettingsJson() {
|
|
81
|
-
const spinner = ora('
|
|
83
|
+
const spinner = ora('Checking settings.json...').start();
|
|
82
84
|
try {
|
|
83
|
-
const templatePath = join(__dirname, '../templates/settings.template.json');
|
|
84
85
|
const settingsPath = join(CWD, '.claude', 'settings.json');
|
|
85
86
|
|
|
86
|
-
if (!existsSync(
|
|
87
|
-
spinner.info('Skipped');
|
|
87
|
+
if (!existsSync(join(CWD, '.claude'))) {
|
|
88
|
+
spinner.info('Skipped (.claude/ not found)');
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Non-invasive: only create if missing. Never overwrite.
|
|
93
|
+
// Hooks come from hooks.json (auto-discovered via symlink).
|
|
94
|
+
// Env vars and permissions live in settings.local.json.
|
|
95
|
+
if (existsSync(settingsPath)) {
|
|
96
|
+
spinner.succeed('settings.json already exists (not overwriting)');
|
|
88
97
|
return false;
|
|
89
98
|
}
|
|
90
99
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
spinner.succeed('settings.json updated from template (hooks)');
|
|
100
|
+
await fs.writeFile(settingsPath, '{}\n');
|
|
101
|
+
spinner.succeed('settings.json created (minimal — hooks from hooks.json)');
|
|
94
102
|
return true;
|
|
95
103
|
} catch (error) {
|
|
96
104
|
spinner.fail(`settings.json: ${error.message}`);
|
|
@@ -197,8 +205,14 @@ print(json.dumps(ops_perms))
|
|
|
197
205
|
existing.permissions.deny = mergedDeny;
|
|
198
206
|
existing.permissions.ask = existing.permissions.ask || [];
|
|
199
207
|
|
|
208
|
+
// Add env vars (smart merge: add if not present, don't overwrite)
|
|
209
|
+
existing.env = existing.env || {};
|
|
210
|
+
if (!('CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS' in existing.env)) {
|
|
211
|
+
existing.env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS = '1';
|
|
212
|
+
}
|
|
213
|
+
|
|
200
214
|
await fs.writeFile(localPath, JSON.stringify(existing, null, 2) + '\n');
|
|
201
|
-
spinner.succeed('settings.local.json permissions merged');
|
|
215
|
+
spinner.succeed('settings.local.json permissions and env merged');
|
|
202
216
|
return true;
|
|
203
217
|
} catch (error) {
|
|
204
218
|
spinner.fail(`settings.local.json: ${error.message}`);
|
|
@@ -206,6 +220,109 @@ print(json.dumps(ops_perms))
|
|
|
206
220
|
}
|
|
207
221
|
}
|
|
208
222
|
|
|
223
|
+
async function updateLocalHooks() {
|
|
224
|
+
const spinner = ora('Merging hooks into settings.local.json...').start();
|
|
225
|
+
try {
|
|
226
|
+
const claudeDir = join(CWD, '.claude');
|
|
227
|
+
const localPath = join(claudeDir, 'settings.local.json');
|
|
228
|
+
|
|
229
|
+
if (!existsSync(claudeDir)) {
|
|
230
|
+
spinner.info('Skipped (.claude/ not found)');
|
|
231
|
+
return false;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// Read hooks.json from the installed package
|
|
235
|
+
const hooksJsonPath = join(__dirname, '..', 'hooks', 'hooks.json');
|
|
236
|
+
if (!existsSync(hooksJsonPath)) {
|
|
237
|
+
spinner.warn('hooks.json not found in package');
|
|
238
|
+
return false;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
let hooksData;
|
|
242
|
+
try {
|
|
243
|
+
hooksData = JSON.parse(await fs.readFile(hooksJsonPath, 'utf-8'));
|
|
244
|
+
} catch {
|
|
245
|
+
spinner.warn('hooks.json is invalid JSON');
|
|
246
|
+
return false;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// Unwrap outer "hooks" key if present
|
|
250
|
+
const sourceHooks = hooksData.hooks || hooksData;
|
|
251
|
+
|
|
252
|
+
// Convert ${CLAUDE_PLUGIN_ROOT}/hooks/<script> to .claude/hooks/<script> for npm mode
|
|
253
|
+
const convertCommand = (cmd) => {
|
|
254
|
+
return cmd.replace(/\$\{CLAUDE_PLUGIN_ROOT\}\/hooks\//g, '.claude/hooks/');
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
const convertedHooks = {};
|
|
258
|
+
for (const [event, entries] of Object.entries(sourceHooks)) {
|
|
259
|
+
convertedHooks[event] = entries.map(entry => {
|
|
260
|
+
const converted = { ...entry };
|
|
261
|
+
if (converted.hooks) {
|
|
262
|
+
converted.hooks = converted.hooks.map(h => ({
|
|
263
|
+
...h,
|
|
264
|
+
command: h.command ? convertCommand(h.command) : h.command,
|
|
265
|
+
}));
|
|
266
|
+
}
|
|
267
|
+
return converted;
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// Load existing settings.local.json
|
|
272
|
+
let existing = {};
|
|
273
|
+
if (existsSync(localPath)) {
|
|
274
|
+
try {
|
|
275
|
+
existing = JSON.parse(await fs.readFile(localPath, 'utf-8'));
|
|
276
|
+
} catch {
|
|
277
|
+
existing = {};
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// Smart merge: for each hook event, deduplicate by command string
|
|
282
|
+
const existingHooks = existing.hooks || {};
|
|
283
|
+
let changed = false;
|
|
284
|
+
|
|
285
|
+
for (const [event, newEntries] of Object.entries(convertedHooks)) {
|
|
286
|
+
if (!existingHooks[event]) {
|
|
287
|
+
existingHooks[event] = newEntries;
|
|
288
|
+
changed = true;
|
|
289
|
+
continue;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// Collect existing command strings for deduplication
|
|
293
|
+
const existingCommands = new Set();
|
|
294
|
+
for (const entry of existingHooks[event]) {
|
|
295
|
+
for (const h of (entry.hooks || [])) {
|
|
296
|
+
if (h.command) existingCommands.add(h.command);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// Add new entries whose commands are not already present
|
|
301
|
+
for (const newEntry of newEntries) {
|
|
302
|
+
const newCommands = (newEntry.hooks || []).map(h => h.command).filter(Boolean);
|
|
303
|
+
const allPresent = newCommands.length > 0 && newCommands.every(c => existingCommands.has(c));
|
|
304
|
+
if (!allPresent) {
|
|
305
|
+
existingHooks[event].push(newEntry);
|
|
306
|
+
changed = true;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
if (!changed) {
|
|
312
|
+
spinner.succeed('settings.local.json hooks already up to date');
|
|
313
|
+
return false;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
existing.hooks = existingHooks;
|
|
317
|
+
await fs.writeFile(localPath, JSON.stringify(existing, null, 2) + '\n');
|
|
318
|
+
spinner.succeed('settings.local.json hooks merged');
|
|
319
|
+
return true;
|
|
320
|
+
} catch (error) {
|
|
321
|
+
spinner.fail(`hooks merge: ${error.message}`);
|
|
322
|
+
return false;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
209
326
|
async function updateSymlinks() {
|
|
210
327
|
const spinner = ora('Checking symlinks...').start();
|
|
211
328
|
try {
|
|
@@ -340,18 +457,21 @@ async function runVerification() {
|
|
|
340
457
|
checks.push({ name: 'agent definitions', ok: agentsOk === agentFiles.length, detail: `${agentsOk}/${agentFiles.length}` });
|
|
341
458
|
if (agentsOk < agentFiles.length) issues.push(`${agentFiles.length - agentsOk} agent definition(s) missing`);
|
|
342
459
|
|
|
343
|
-
// 6.
|
|
344
|
-
const
|
|
345
|
-
if (existsSync(
|
|
460
|
+
// 6. hooks.json exists (hooks are auto-discovered from hooks directory)
|
|
461
|
+
const hooksJsonPath = join(CWD, '.claude', 'hooks', 'hooks.json');
|
|
462
|
+
if (existsSync(hooksJsonPath)) {
|
|
346
463
|
try {
|
|
347
|
-
const
|
|
348
|
-
const hasHooks =
|
|
349
|
-
checks.push({ name: 'hooks
|
|
350
|
-
if (!hasHooks) issues.push('
|
|
464
|
+
const hooksData = JSON.parse(await fs.readFile(hooksJsonPath, 'utf-8'));
|
|
465
|
+
const hasHooks = hooksData.hooks && Object.keys(hooksData.hooks).length > 0;
|
|
466
|
+
checks.push({ name: 'hooks.json', ok: hasHooks });
|
|
467
|
+
if (!hasHooks) issues.push('hooks.json has no hooks configured');
|
|
351
468
|
} catch {
|
|
352
|
-
checks.push({ name: 'hooks
|
|
353
|
-
issues.push('
|
|
469
|
+
checks.push({ name: 'hooks.json', ok: false });
|
|
470
|
+
issues.push('hooks.json is invalid');
|
|
354
471
|
}
|
|
472
|
+
} else {
|
|
473
|
+
checks.push({ name: 'hooks.json', ok: false });
|
|
474
|
+
issues.push('hooks.json not found (hooks symlink may be broken)');
|
|
355
475
|
}
|
|
356
476
|
|
|
357
477
|
const passed = checks.filter(c => c.ok).length;
|
|
@@ -421,6 +541,9 @@ async function runFreshInstall() {
|
|
|
421
541
|
|
|
422
542
|
// 4. Merge permissions into settings.local.json (same approach as plugin mode)
|
|
423
543
|
await updateLocalPermissions();
|
|
544
|
+
|
|
545
|
+
// 5. Merge hooks into settings.local.json (npm mode — Claude Code reads hooks from settings, not hooks.json)
|
|
546
|
+
await updateLocalHooks();
|
|
424
547
|
}
|
|
425
548
|
|
|
426
549
|
async function main() {
|
|
@@ -439,9 +562,10 @@ async function main() {
|
|
|
439
562
|
|
|
440
563
|
console.log(chalk.cyan(`\n gaia-ops update ${versionLine}\n`));
|
|
441
564
|
|
|
442
|
-
// Step 1-
|
|
565
|
+
// Step 1-4: Update files
|
|
443
566
|
await updateSettingsJson();
|
|
444
567
|
await updateLocalPermissions();
|
|
568
|
+
await updateLocalHooks();
|
|
445
569
|
await updateSymlinks();
|
|
446
570
|
}
|
|
447
571
|
|
|
@@ -46,10 +46,10 @@ function detectGaiaOpsRoot(startPath) {
|
|
|
46
46
|
// Buscar node_modules de múltiples maneras
|
|
47
47
|
function findNodeModulesPath(gaiaOpsRoot) {
|
|
48
48
|
const candidates = [
|
|
49
|
-
path.resolve(gaiaOpsRoot, '
|
|
50
|
-
path.resolve(gaiaOpsRoot, 'node_modules'),
|
|
49
|
+
path.resolve(gaiaOpsRoot, 'node_modules'), // ./node_modules (CI: npm ci in repo root)
|
|
50
|
+
path.resolve(gaiaOpsRoot, '..', 'node_modules'), // ../node_modules (monorepo consumer)
|
|
51
51
|
path.resolve(process.cwd(), 'node_modules'), // cwd/node_modules
|
|
52
|
-
path.join(gaiaOpsRoot, '..', '..', 'node_modules'), // ../../node_modules
|
|
52
|
+
path.join(gaiaOpsRoot, '..', '..', 'node_modules'), // ../../node_modules (deep nesting)
|
|
53
53
|
];
|
|
54
54
|
|
|
55
55
|
for (const candidate of candidates) {
|
|
@@ -59,8 +59,16 @@ function findNodeModulesPath(gaiaOpsRoot) {
|
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
//
|
|
63
|
-
|
|
62
|
+
// In CI, node_modules exists inside the repo root (npm ci) but won't contain
|
|
63
|
+
// the package itself as a nested dependency. Prefer gaiaOpsRoot/node_modules
|
|
64
|
+
// over going up a level (which breaks in CI checkout structures).
|
|
65
|
+
const localNodeModules = path.resolve(gaiaOpsRoot, 'node_modules');
|
|
66
|
+
if (fs.existsSync(localNodeModules)) {
|
|
67
|
+
return localNodeModules;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Fallback: use __dirname-relative path (repo root) instead of process.cwd()
|
|
71
|
+
return path.resolve(gaiaOpsRoot, 'node_modules');
|
|
64
72
|
}
|
|
65
73
|
|
|
66
74
|
const GAIA_OPS_ROOT = detectGaiaOpsRoot(path.resolve(__dirname, '..'));
|
|
@@ -219,14 +227,21 @@ class PrePublishValidator {
|
|
|
219
227
|
}
|
|
220
228
|
|
|
221
229
|
reinstallNodeModules() {
|
|
222
|
-
this.log('Reinstalling node_modules
|
|
230
|
+
this.log('Reinstalling node_modules...', 'info');
|
|
223
231
|
|
|
224
232
|
if (this.dryRun) {
|
|
225
233
|
this.log('[DRY RUN] Would run: npm install', 'info');
|
|
226
234
|
return;
|
|
227
235
|
}
|
|
228
236
|
|
|
229
|
-
|
|
237
|
+
// In CI, MONOREPO_ROOT may resolve incorrectly (one level above checkout).
|
|
238
|
+
// Use GAIA_OPS_ROOT if it contains a package.json (i.e., we ARE the root).
|
|
239
|
+
const installDir = fs.existsSync(path.join(GAIA_OPS_ROOT, 'package-lock.json'))
|
|
240
|
+
? GAIA_OPS_ROOT
|
|
241
|
+
: MONOREPO_ROOT;
|
|
242
|
+
|
|
243
|
+
this.log(`Install directory: ${installDir}`, 'info');
|
|
244
|
+
this.execute('npm install', installDir);
|
|
230
245
|
this.log('✓ npm install completed', 'success');
|
|
231
246
|
}
|
|
232
247
|
|
|
@@ -238,7 +253,6 @@ class PrePublishValidator {
|
|
|
238
253
|
'bin/gaia-scan',
|
|
239
254
|
'tools/context/context_provider.py',
|
|
240
255
|
'hooks/pre_tool_use.py',
|
|
241
|
-
'templates/settings.template.json'
|
|
242
256
|
];
|
|
243
257
|
|
|
244
258
|
let allValid = true;
|
|
@@ -330,7 +344,6 @@ class PrePublishValidator {
|
|
|
330
344
|
// Test 1: Validate JSON files
|
|
331
345
|
this.log('Test 1: Validating JSON configuration files...', 'info');
|
|
332
346
|
const jsonFiles = [
|
|
333
|
-
'templates/settings.template.json',
|
|
334
347
|
'config/clarification_rules.json',
|
|
335
348
|
'config/git_standards.json'
|
|
336
349
|
];
|
|
@@ -505,12 +518,22 @@ class PrePublishValidator {
|
|
|
505
518
|
// Parse command line arguments and run
|
|
506
519
|
async function main() {
|
|
507
520
|
const args = process.argv.slice(2);
|
|
521
|
+
const isCI = process.env.CI === 'true' || process.env.GITHUB_ACTIONS === 'true';
|
|
522
|
+
|
|
508
523
|
const options = {
|
|
509
524
|
dryRun: args.includes('--dry-run'),
|
|
510
|
-
validateOnly: args.includes('--validate-only'),
|
|
525
|
+
validateOnly: args.includes('--validate-only') || isCI,
|
|
511
526
|
versionBump: 'patch'
|
|
512
527
|
};
|
|
513
528
|
|
|
529
|
+
if (isCI && !args.includes('--validate-only')) {
|
|
530
|
+
console.log(chalk.blue(
|
|
531
|
+
'[CI] Auto-enabling --validate-only: ' +
|
|
532
|
+
'self-install validation is not possible during npm publish ' +
|
|
533
|
+
'(package is not yet on the registry).'
|
|
534
|
+
));
|
|
535
|
+
}
|
|
536
|
+
|
|
514
537
|
if (args.includes('major')) options.versionBump = 'major';
|
|
515
538
|
if (args.includes('minor')) options.versionBump = 'minor';
|
|
516
539
|
if (args.includes('patch')) options.versionBump = 'patch';
|
package/commands/gaia.md
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: gaia
|
|
3
|
+
description: Invoke the Gaia meta-agent for system architecture analysis, agent design, skill creation, and orchestration debugging
|
|
4
|
+
allowed-tools:
|
|
5
|
+
- Bash(*)
|
|
6
|
+
- Read
|
|
7
|
+
- Edit
|
|
8
|
+
- Write
|
|
9
|
+
- Glob
|
|
10
|
+
- Grep
|
|
11
|
+
- WebSearch
|
|
12
|
+
- WebFetch
|
|
13
|
+
- Task
|
|
14
|
+
- Agent
|
|
15
|
+
- Skill
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
Invoke the Gaia meta-agent (`gaia-system`) to work on the gaia-ops orchestration
|
|
19
|
+
system itself. This is the entry point for tasks that modify or analyze agents,
|
|
20
|
+
skills, hooks, or system architecture.
|
|
21
|
+
|
|
22
|
+
## When to use
|
|
23
|
+
|
|
24
|
+
- Analyze or improve the gaia-ops architecture
|
|
25
|
+
- Create or update agent definitions (`.md` files)
|
|
26
|
+
- Create or update skills (`SKILL.md` files)
|
|
27
|
+
- Write or debug Python hooks and tools
|
|
28
|
+
- Update `CLAUDE.md` or system configuration
|
|
29
|
+
- Research best practices for agent orchestration
|
|
30
|
+
|
|
31
|
+
## How it works
|
|
32
|
+
|
|
33
|
+
This command delegates to the `gaia-system` agent, which is the meta-agent
|
|
34
|
+
specialized in the orchestration system. It follows the standard agent protocol
|
|
35
|
+
and returns a `json:contract` block with findings and status.
|
|
36
|
+
|
|
37
|
+
$ARGUMENTS
|
package/config/README.md
CHANGED
|
@@ -6,11 +6,9 @@ Central configuration for the orchestration system. Contracts are the SSOT for a
|
|
|
6
6
|
|
|
7
7
|
| File | Purpose | Read by |
|
|
8
8
|
|------|---------|---------|
|
|
9
|
-
| `context-contracts.json` | Base cloud-agnostic contracts: `read`/`write` sections per agent | `context_provider.py`, `context_writer.py`, `pre_tool_use.py` |
|
|
9
|
+
| `context-contracts.json` | Base cloud-agnostic contracts: `read`/`write` sections per agent, `core_sections` list, `workspace_repos` schema | `context_provider.py`, `context_writer.py`, `pre_tool_use.py` |
|
|
10
10
|
| `cloud/gcp.json` | GCP extensions: `gcp_services`, `workload_identity`, `static_ips` | Same trio, merged at runtime |
|
|
11
11
|
| `cloud/aws.json` | AWS extensions: `vpc_mapping`, `load_balancers`, `api_gateway`, `irsa_bindings`, `aws_accounts` | Same trio, merged at runtime |
|
|
12
|
-
| `context-contracts.gcp.json` | **Legacy** -- kept for backward compatibility | Fallback if `context-contracts.json` not found |
|
|
13
|
-
| `context-contracts.aws.json` | **Legacy** -- kept for backward compatibility | Fallback if `context-contracts.json` not found |
|
|
14
12
|
| `git_standards.json` | Commit standards (Conventional Commits), allowed types, forbidden footers | `hooks/modules/validation/commit_validator.py` |
|
|
15
13
|
| `universal-rules.json` | Behavior rules injected into all agents | `context_provider.py` |
|
|
16
14
|
| `surface-routing.json` | Generic surface classification and investigation-brief rules | `surface_router.py`, `context_provider.py`, Spec-Kit |
|
|
@@ -27,18 +25,14 @@ At runtime, `tools/context/context_provider.py` executes the following logic:
|
|
|
27
25
|
5. Result: complete contract for the agent on that cloud
|
|
28
26
|
```
|
|
29
27
|
|
|
30
|
-
Fallback if `context-contracts.json` not found: uses `context-contracts.{provider}.json` (legacy).
|
|
31
|
-
|
|
32
28
|
## Structure
|
|
33
29
|
|
|
34
30
|
```
|
|
35
31
|
config/
|
|
36
|
-
├── context-contracts.json <- agnostic base (all agents)
|
|
32
|
+
├── context-contracts.json <- agnostic base (all agents, v4)
|
|
37
33
|
├── cloud/
|
|
38
34
|
│ ├── gcp.json <- GCP extensions + section_schemas
|
|
39
35
|
│ └── aws.json <- AWS extensions + section_schemas
|
|
40
|
-
├── context-contracts.gcp.json <- legacy (fallback)
|
|
41
|
-
├── context-contracts.aws.json <- legacy (fallback)
|
|
42
36
|
├── surface-routing.json <- generic surface routing + investigation brief config
|
|
43
37
|
├── git_standards.json
|
|
44
38
|
├── universal-rules.json
|
|
@@ -61,4 +55,4 @@ config/
|
|
|
61
55
|
|
|
62
56
|
---
|
|
63
57
|
|
|
64
|
-
**Updated:** 2026-03-
|
|
58
|
+
**Updated:** 2026-03-25 | **Active contracts:** base v4 + 2 clouds (GCP, AWS)
|