@jaguilar87/gaia 5.0.0-rc1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +33 -0
- package/.claude-plugin/plugin.json +26 -0
- package/ARCHITECTURE.md +335 -0
- package/CHANGELOG.md +1212 -0
- package/CODE_OF_CONDUCT.md +11 -0
- package/CONTRIBUTING.md +146 -0
- package/INSTALL.md +436 -0
- package/LICENSE +21 -0
- package/README.md +222 -0
- package/SECURITY.md +47 -0
- package/agents/README.md +78 -0
- package/agents/cloud-troubleshooter.md +73 -0
- package/agents/developer.md +65 -0
- package/agents/gaia-operator.md +64 -0
- package/agents/gaia-orchestrator.md +237 -0
- package/agents/gaia-planner.md +53 -0
- package/agents/gaia-system.md +70 -0
- package/agents/gitops-operator.md +61 -0
- package/agents/terraform-architect.md +63 -0
- package/bin/README.md +106 -0
- package/bin/cli/__init__.py +1 -0
- package/bin/cli/approvals.py +740 -0
- package/bin/cli/cleanup.py +562 -0
- package/bin/cli/context.py +283 -0
- package/bin/cli/doctor.py +628 -0
- package/bin/cli/history.py +305 -0
- package/bin/cli/memory.py +464 -0
- package/bin/cli/metrics.py +1068 -0
- package/bin/cli/plans.py +515 -0
- package/bin/cli/status.py +302 -0
- package/bin/cli/update.py +382 -0
- package/bin/gaia +112 -0
- package/bin/gaia-cleanup.js +531 -0
- package/bin/gaia-doctor.js +635 -0
- package/bin/gaia-evidence +126 -0
- package/bin/gaia-history.js +251 -0
- package/bin/gaia-metrics.js +1278 -0
- package/bin/gaia-review.js +269 -0
- package/bin/gaia-scan +44 -0
- package/bin/gaia-scan.py +589 -0
- package/bin/gaia-skills-diagnose.js +929 -0
- package/bin/gaia-status.js +278 -0
- package/bin/gaia-uninstall.js +111 -0
- package/bin/gaia-update.js +816 -0
- package/bin/pre-publish-validate.js +610 -0
- package/bin/python-detect.js +60 -0
- package/commands/README.md +64 -0
- package/commands/gaia.md +37 -0
- package/commands/scan-project.md +67 -0
- package/config/README.md +71 -0
- package/config/cloud/aws.json +134 -0
- package/config/cloud/gcp.json +139 -0
- package/config/context-contracts.json +158 -0
- package/config/crons-schema.md +81 -0
- package/config/git_standards.json +72 -0
- package/config/surface-routing.json +421 -0
- package/config/universal-rules.json +102 -0
- package/dist/gaia-ops/.claude-plugin/plugin.json +24 -0
- package/dist/gaia-ops/README.md +80 -0
- package/dist/gaia-ops/agents/cloud-troubleshooter.md +73 -0
- package/dist/gaia-ops/agents/developer.md +65 -0
- package/dist/gaia-ops/agents/gaia-operator.md +64 -0
- package/dist/gaia-ops/agents/gaia-orchestrator.md +237 -0
- package/dist/gaia-ops/agents/gaia-planner.md +53 -0
- package/dist/gaia-ops/agents/gaia-system.md +70 -0
- package/dist/gaia-ops/agents/gitops-operator.md +61 -0
- package/dist/gaia-ops/agents/terraform-architect.md +63 -0
- package/dist/gaia-ops/commands/gaia.md +37 -0
- package/dist/gaia-ops/config/README.md +71 -0
- package/dist/gaia-ops/config/cloud/aws.json +134 -0
- package/dist/gaia-ops/config/cloud/gcp.json +139 -0
- package/dist/gaia-ops/config/context-contracts.json +158 -0
- package/dist/gaia-ops/config/crons-schema.md +81 -0
- package/dist/gaia-ops/config/git_standards.json +72 -0
- package/dist/gaia-ops/config/surface-routing.json +421 -0
- package/dist/gaia-ops/config/universal-rules.json +102 -0
- package/dist/gaia-ops/hooks/adapters/__init__.py +52 -0
- package/dist/gaia-ops/hooks/adapters/base.py +219 -0
- package/dist/gaia-ops/hooks/adapters/channel.py +17 -0
- package/dist/gaia-ops/hooks/adapters/claude_code.py +1890 -0
- package/dist/gaia-ops/hooks/adapters/types.py +194 -0
- package/dist/gaia-ops/hooks/adapters/utils.py +25 -0
- package/dist/gaia-ops/hooks/hooks.json +163 -0
- package/dist/gaia-ops/hooks/modules/__init__.py +15 -0
- package/dist/gaia-ops/hooks/modules/agents/__init__.py +29 -0
- package/dist/gaia-ops/hooks/modules/agents/contract_validator.py +647 -0
- package/dist/gaia-ops/hooks/modules/agents/response_contract.py +496 -0
- package/dist/gaia-ops/hooks/modules/agents/skill_injection_verifier.py +120 -0
- package/dist/gaia-ops/hooks/modules/agents/state_tracker.py +267 -0
- package/dist/gaia-ops/hooks/modules/agents/task_info_builder.py +74 -0
- package/dist/gaia-ops/hooks/modules/agents/transcript_analyzer.py +458 -0
- package/dist/gaia-ops/hooks/modules/agents/transcript_reader.py +152 -0
- package/dist/gaia-ops/hooks/modules/audit/__init__.py +28 -0
- package/dist/gaia-ops/hooks/modules/audit/event_detector.py +168 -0
- package/dist/gaia-ops/hooks/modules/audit/logger.py +131 -0
- package/dist/gaia-ops/hooks/modules/audit/metrics.py +134 -0
- package/dist/gaia-ops/hooks/modules/audit/workflow_auditor.py +611 -0
- package/dist/gaia-ops/hooks/modules/audit/workflow_recorder.py +296 -0
- package/dist/gaia-ops/hooks/modules/context/__init__.py +11 -0
- package/dist/gaia-ops/hooks/modules/context/agentic_loop_detector.py +165 -0
- package/dist/gaia-ops/hooks/modules/context/anchor_tracker.py +317 -0
- package/dist/gaia-ops/hooks/modules/context/compact_context_builder.py +218 -0
- package/dist/gaia-ops/hooks/modules/context/context_freshness.py +145 -0
- package/dist/gaia-ops/hooks/modules/context/context_injector.py +558 -0
- package/dist/gaia-ops/hooks/modules/context/context_writer.py +530 -0
- package/dist/gaia-ops/hooks/modules/context/contracts_loader.py +161 -0
- package/dist/gaia-ops/hooks/modules/core/__init__.py +40 -0
- package/dist/gaia-ops/hooks/modules/core/hook_entry.py +78 -0
- package/dist/gaia-ops/hooks/modules/core/paths.py +160 -0
- package/dist/gaia-ops/hooks/modules/core/plugin_mode.py +149 -0
- package/dist/gaia-ops/hooks/modules/core/plugin_setup.py +577 -0
- package/dist/gaia-ops/hooks/modules/core/state.py +179 -0
- package/dist/gaia-ops/hooks/modules/core/stdin.py +24 -0
- package/dist/gaia-ops/hooks/modules/events/__init__.py +1 -0
- package/dist/gaia-ops/hooks/modules/events/event_writer.py +210 -0
- package/dist/gaia-ops/hooks/modules/memory/__init__.py +8 -0
- package/dist/gaia-ops/hooks/modules/memory/episode_writer.py +216 -0
- package/dist/gaia-ops/hooks/modules/orchestrator/__init__.py +1 -0
- package/dist/gaia-ops/hooks/modules/orchestrator/delegate_mode.py +122 -0
- package/dist/gaia-ops/hooks/modules/scanning/__init__.py +8 -0
- package/dist/gaia-ops/hooks/modules/scanning/scan_trigger.py +84 -0
- package/dist/gaia-ops/hooks/modules/security/__init__.py +120 -0
- package/dist/gaia-ops/hooks/modules/security/approval_cleanup.py +87 -0
- package/dist/gaia-ops/hooks/modules/security/approval_constants.py +23 -0
- package/dist/gaia-ops/hooks/modules/security/approval_grants.py +1638 -0
- package/dist/gaia-ops/hooks/modules/security/approval_messages.py +71 -0
- package/dist/gaia-ops/hooks/modules/security/approval_scopes.py +222 -0
- package/dist/gaia-ops/hooks/modules/security/blocked_commands.py +595 -0
- package/dist/gaia-ops/hooks/modules/security/blocked_message_formatter.py +87 -0
- package/dist/gaia-ops/hooks/modules/security/command_semantics.py +181 -0
- package/dist/gaia-ops/hooks/modules/security/composition_rules.py +547 -0
- package/dist/gaia-ops/hooks/modules/security/flag_classifiers.py +873 -0
- package/dist/gaia-ops/hooks/modules/security/gitops_validator.py +179 -0
- package/dist/gaia-ops/hooks/modules/security/mutative_verbs.py +1131 -0
- package/dist/gaia-ops/hooks/modules/security/network_hosts.py +481 -0
- package/dist/gaia-ops/hooks/modules/security/prompt_validator.py +40 -0
- package/dist/gaia-ops/hooks/modules/security/shell_unwrapper.py +165 -0
- package/dist/gaia-ops/hooks/modules/security/tiers.py +196 -0
- package/dist/gaia-ops/hooks/modules/session/__init__.py +10 -0
- package/dist/gaia-ops/hooks/modules/session/pending_scanner.py +174 -0
- package/dist/gaia-ops/hooks/modules/session/session_context_writer.py +100 -0
- package/dist/gaia-ops/hooks/modules/session/session_event_injector.py +160 -0
- package/dist/gaia-ops/hooks/modules/session/session_manager.py +31 -0
- package/dist/gaia-ops/hooks/modules/session/session_registry.py +232 -0
- package/dist/gaia-ops/hooks/modules/tools/__init__.py +29 -0
- package/dist/gaia-ops/hooks/modules/tools/bash_validator.py +1008 -0
- package/dist/gaia-ops/hooks/modules/tools/cloud_pipe_validator.py +231 -0
- package/dist/gaia-ops/hooks/modules/tools/hook_response.py +55 -0
- package/dist/gaia-ops/hooks/modules/tools/shell_parser.py +227 -0
- package/dist/gaia-ops/hooks/modules/tools/stage_decomposer.py +315 -0
- package/dist/gaia-ops/hooks/modules/tools/task_validator.py +294 -0
- package/dist/gaia-ops/hooks/modules/validation/__init__.py +23 -0
- package/dist/gaia-ops/hooks/modules/validation/commit_validator.py +380 -0
- package/dist/gaia-ops/hooks/post_compact.py +43 -0
- package/dist/gaia-ops/hooks/post_tool_use.py +54 -0
- package/dist/gaia-ops/hooks/pre_compact.py +60 -0
- package/dist/gaia-ops/hooks/pre_tool_use.py +413 -0
- package/dist/gaia-ops/hooks/session_start.py +81 -0
- package/dist/gaia-ops/hooks/stop_hook.py +82 -0
- package/dist/gaia-ops/hooks/subagent_start.py +71 -0
- package/dist/gaia-ops/hooks/subagent_stop.py +295 -0
- package/dist/gaia-ops/hooks/task_completed.py +70 -0
- package/dist/gaia-ops/hooks/user_prompt_submit.py +246 -0
- package/dist/gaia-ops/settings.json +72 -0
- package/dist/gaia-ops/skills/README.md +154 -0
- package/dist/gaia-ops/skills/agent-protocol/SKILL.md +93 -0
- package/dist/gaia-ops/skills/agent-protocol/examples.md +223 -0
- package/dist/gaia-ops/skills/agent-response/SKILL.md +69 -0
- package/dist/gaia-ops/skills/agentic-loop/SKILL.md +80 -0
- package/dist/gaia-ops/skills/agentic-loop/reference.md +378 -0
- package/dist/gaia-ops/skills/blog-writing/SKILL.md +98 -0
- package/dist/gaia-ops/skills/blog-writing/reference.md +130 -0
- package/dist/gaia-ops/skills/brief-spec/SKILL.md +182 -0
- package/dist/gaia-ops/skills/command-execution/SKILL.md +64 -0
- package/dist/gaia-ops/skills/command-execution/reference.md +83 -0
- package/dist/gaia-ops/skills/context-updater/SKILL.md +87 -0
- package/dist/gaia-ops/skills/context-updater/examples.md +71 -0
- package/dist/gaia-ops/skills/developer-patterns/SKILL.md +50 -0
- package/dist/gaia-ops/skills/developer-patterns/reference.md +112 -0
- package/dist/gaia-ops/skills/execution/SKILL.md +99 -0
- package/dist/gaia-ops/skills/fast-queries/SKILL.md +43 -0
- package/dist/gaia-ops/skills/gaia-compact/SKILL.md +74 -0
- package/dist/gaia-ops/skills/gaia-patterns/SKILL.md +108 -0
- package/dist/gaia-ops/skills/gaia-patterns/reference.md +395 -0
- package/dist/gaia-ops/skills/gaia-planner/SKILL.md +37 -0
- package/dist/gaia-ops/skills/gaia-planner/reference.md +107 -0
- package/dist/gaia-ops/skills/gaia-release/SKILL.md +82 -0
- package/dist/gaia-ops/skills/gaia-release/reference.md +102 -0
- package/dist/gaia-ops/skills/gaia-self-check/SKILL.md +114 -0
- package/dist/gaia-ops/skills/gaia-self-check/reference.md +453 -0
- package/dist/gaia-ops/skills/gaia-verify/SKILL.md +77 -0
- package/dist/gaia-ops/skills/gaia-verify/reference.md +80 -0
- package/dist/gaia-ops/skills/git-conventions/SKILL.md +47 -0
- package/dist/gaia-ops/skills/gitops-patterns/SKILL.md +60 -0
- package/dist/gaia-ops/skills/gitops-patterns/reference.md +183 -0
- package/dist/gaia-ops/skills/gmail-policy/SKILL.md +200 -0
- package/dist/gaia-ops/skills/gmail-policy/reference.md +150 -0
- package/dist/gaia-ops/skills/gmail-triage/SKILL.md +100 -0
- package/dist/gaia-ops/skills/gws-setup/SKILL.md +99 -0
- package/dist/gaia-ops/skills/gws-setup/reference.md +73 -0
- package/dist/gaia-ops/skills/investigation/SKILL.md +100 -0
- package/dist/gaia-ops/skills/memory-curation/SKILL.md +83 -0
- package/dist/gaia-ops/skills/memory-search/SKILL.md +88 -0
- package/dist/gaia-ops/skills/orchestrator-approval/SKILL.md +160 -0
- package/dist/gaia-ops/skills/orchestrator-approval/reference.md +174 -0
- package/dist/gaia-ops/skills/pending-approvals/SKILL.md +72 -0
- package/dist/gaia-ops/skills/pending-approvals/reference.md +214 -0
- package/dist/gaia-ops/skills/readme-writing/SKILL.md +71 -0
- package/dist/gaia-ops/skills/readme-writing/reference.md +188 -0
- package/dist/gaia-ops/skills/reference.md +135 -0
- package/dist/gaia-ops/skills/request-approval/SKILL.md +140 -0
- package/dist/gaia-ops/skills/request-approval/examples.md +140 -0
- package/dist/gaia-ops/skills/request-approval/reference.md +57 -0
- package/dist/gaia-ops/skills/schedule-task/SKILL.md +64 -0
- package/dist/gaia-ops/skills/schedule-task/reference.md +233 -0
- package/dist/gaia-ops/skills/security-tiers/SKILL.md +141 -0
- package/dist/gaia-ops/skills/security-tiers/destructive-commands-reference.md +623 -0
- package/dist/gaia-ops/skills/security-tiers/reference.md +39 -0
- package/dist/gaia-ops/skills/skill-creation/SKILL.md +92 -0
- package/dist/gaia-ops/skills/skill-creation/reference.md +29 -0
- package/dist/gaia-ops/skills/terraform-patterns/SKILL.md +89 -0
- package/dist/gaia-ops/skills/terraform-patterns/reference.md +93 -0
- package/dist/gaia-ops/tools/__init__.py +9 -0
- package/dist/gaia-ops/tools/agentic-loop/decide-status.py +210 -0
- package/dist/gaia-ops/tools/agentic-loop/parse-metric.py +106 -0
- package/dist/gaia-ops/tools/agentic-loop/record-iteration.py +221 -0
- package/dist/gaia-ops/tools/context/README.md +132 -0
- package/dist/gaia-ops/tools/context/__init__.py +42 -0
- package/dist/gaia-ops/tools/context/_paths.py +20 -0
- package/dist/gaia-ops/tools/context/context_provider.py +721 -0
- package/dist/gaia-ops/tools/context/context_section_reader.py +342 -0
- package/dist/gaia-ops/tools/context/deep_merge.py +159 -0
- package/dist/gaia-ops/tools/context/pending_updates.py +760 -0
- package/dist/gaia-ops/tools/context/surface_router.py +278 -0
- package/dist/gaia-ops/tools/fast-queries/README.md +65 -0
- package/dist/gaia-ops/tools/fast-queries/__init__.py +30 -0
- package/dist/gaia-ops/tools/fast-queries/appservices/quicktriage_devops_developer.sh +75 -0
- package/dist/gaia-ops/tools/fast-queries/cloud/aws/quicktriage_aws_troubleshooter.sh +32 -0
- package/dist/gaia-ops/tools/fast-queries/cloud/gcp/quicktriage_gcp_troubleshooter.sh +88 -0
- package/dist/gaia-ops/tools/fast-queries/gitops/quicktriage_gitops_operator.sh +48 -0
- package/dist/gaia-ops/tools/fast-queries/run_triage.sh +59 -0
- package/dist/gaia-ops/tools/fast-queries/terraform/quicktriage_terraform_architect.sh +80 -0
- package/dist/gaia-ops/tools/gaia_simulator/__init__.py +33 -0
- package/dist/gaia-ops/tools/gaia_simulator/cli.py +354 -0
- package/dist/gaia-ops/tools/gaia_simulator/extractor.py +457 -0
- package/dist/gaia-ops/tools/gaia_simulator/reporter.py +258 -0
- package/dist/gaia-ops/tools/gaia_simulator/routing_simulator.py +334 -0
- package/dist/gaia-ops/tools/gaia_simulator/runner.py +539 -0
- package/dist/gaia-ops/tools/gaia_simulator/skills_mapper.py +264 -0
- package/dist/gaia-ops/tools/memory/README.md +0 -0
- package/dist/gaia-ops/tools/memory/__init__.py +20 -0
- package/dist/gaia-ops/tools/memory/backfill_fts5.py +107 -0
- package/dist/gaia-ops/tools/memory/conflict_detector.py +295 -0
- package/dist/gaia-ops/tools/memory/episodic.py +1210 -0
- package/dist/gaia-ops/tools/memory/git_invalidator.py +262 -0
- package/dist/gaia-ops/tools/memory/paths.py +102 -0
- package/dist/gaia-ops/tools/memory/scoring.py +193 -0
- package/dist/gaia-ops/tools/memory/search_store.py +360 -0
- package/dist/gaia-ops/tools/persist_transcript_analysis.py +85 -0
- package/dist/gaia-ops/tools/review/__init__.py +1 -0
- package/dist/gaia-ops/tools/review/review_engine.py +157 -0
- package/dist/gaia-ops/tools/scan/__init__.py +35 -0
- package/dist/gaia-ops/tools/scan/config.py +247 -0
- package/dist/gaia-ops/tools/scan/merge.py +212 -0
- package/dist/gaia-ops/tools/scan/orchestrator.py +549 -0
- package/dist/gaia-ops/tools/scan/registry.py +127 -0
- package/dist/gaia-ops/tools/scan/scanners/__init__.py +18 -0
- package/dist/gaia-ops/tools/scan/scanners/base.py +137 -0
- package/dist/gaia-ops/tools/scan/scanners/environment.py +349 -0
- package/dist/gaia-ops/tools/scan/scanners/git.py +570 -0
- package/dist/gaia-ops/tools/scan/scanners/infrastructure.py +875 -0
- package/dist/gaia-ops/tools/scan/scanners/orchestration.py +600 -0
- package/dist/gaia-ops/tools/scan/scanners/stack.py +1085 -0
- package/dist/gaia-ops/tools/scan/scanners/tools.py +260 -0
- package/dist/gaia-ops/tools/scan/setup.py +686 -0
- package/dist/gaia-ops/tools/scan/tests/__init__.py +1 -0
- package/dist/gaia-ops/tools/scan/tests/conftest.py +796 -0
- package/dist/gaia-ops/tools/scan/tests/test_environment.py +323 -0
- package/dist/gaia-ops/tools/scan/tests/test_git.py +419 -0
- package/dist/gaia-ops/tools/scan/tests/test_infrastructure.py +382 -0
- package/dist/gaia-ops/tools/scan/tests/test_integration.py +920 -0
- package/dist/gaia-ops/tools/scan/tests/test_merge.py +269 -0
- package/dist/gaia-ops/tools/scan/tests/test_orchestration.py +304 -0
- package/dist/gaia-ops/tools/scan/tests/test_stack.py +604 -0
- package/dist/gaia-ops/tools/scan/tests/test_tools.py +349 -0
- package/dist/gaia-ops/tools/scan/ui.py +624 -0
- package/dist/gaia-ops/tools/scan/verify.py +270 -0
- package/dist/gaia-ops/tools/scan/walk.py +118 -0
- package/dist/gaia-ops/tools/scan/workspace.py +85 -0
- package/dist/gaia-ops/tools/validation/README.md +244 -0
- package/dist/gaia-ops/tools/validation/__init__.py +17 -0
- package/dist/gaia-ops/tools/validation/approval_gate.py +321 -0
- package/dist/gaia-ops/tools/validation/validate_skills.py +189 -0
- package/dist/gaia-security/.claude-plugin/plugin.json +24 -0
- package/dist/gaia-security/README.md +90 -0
- package/dist/gaia-security/config/universal-rules.json +102 -0
- package/dist/gaia-security/hooks/adapters/__init__.py +52 -0
- package/dist/gaia-security/hooks/adapters/base.py +219 -0
- package/dist/gaia-security/hooks/adapters/channel.py +17 -0
- package/dist/gaia-security/hooks/adapters/claude_code.py +1890 -0
- package/dist/gaia-security/hooks/adapters/types.py +194 -0
- package/dist/gaia-security/hooks/adapters/utils.py +25 -0
- package/dist/gaia-security/hooks/hooks.json +84 -0
- package/dist/gaia-security/hooks/modules/__init__.py +15 -0
- package/dist/gaia-security/hooks/modules/agents/__init__.py +29 -0
- package/dist/gaia-security/hooks/modules/agents/contract_validator.py +647 -0
- package/dist/gaia-security/hooks/modules/agents/response_contract.py +496 -0
- package/dist/gaia-security/hooks/modules/agents/skill_injection_verifier.py +120 -0
- package/dist/gaia-security/hooks/modules/agents/state_tracker.py +267 -0
- package/dist/gaia-security/hooks/modules/agents/task_info_builder.py +74 -0
- package/dist/gaia-security/hooks/modules/agents/transcript_analyzer.py +458 -0
- package/dist/gaia-security/hooks/modules/agents/transcript_reader.py +152 -0
- package/dist/gaia-security/hooks/modules/audit/__init__.py +28 -0
- package/dist/gaia-security/hooks/modules/audit/event_detector.py +168 -0
- package/dist/gaia-security/hooks/modules/audit/logger.py +131 -0
- package/dist/gaia-security/hooks/modules/audit/metrics.py +134 -0
- package/dist/gaia-security/hooks/modules/audit/workflow_auditor.py +611 -0
- package/dist/gaia-security/hooks/modules/audit/workflow_recorder.py +296 -0
- package/dist/gaia-security/hooks/modules/context/__init__.py +11 -0
- package/dist/gaia-security/hooks/modules/context/agentic_loop_detector.py +165 -0
- package/dist/gaia-security/hooks/modules/context/anchor_tracker.py +317 -0
- package/dist/gaia-security/hooks/modules/context/compact_context_builder.py +218 -0
- package/dist/gaia-security/hooks/modules/context/context_freshness.py +145 -0
- package/dist/gaia-security/hooks/modules/context/context_injector.py +558 -0
- package/dist/gaia-security/hooks/modules/context/context_writer.py +530 -0
- package/dist/gaia-security/hooks/modules/context/contracts_loader.py +161 -0
- package/dist/gaia-security/hooks/modules/core/__init__.py +40 -0
- package/dist/gaia-security/hooks/modules/core/hook_entry.py +78 -0
- package/dist/gaia-security/hooks/modules/core/paths.py +160 -0
- package/dist/gaia-security/hooks/modules/core/plugin_mode.py +149 -0
- package/dist/gaia-security/hooks/modules/core/plugin_setup.py +577 -0
- package/dist/gaia-security/hooks/modules/core/state.py +179 -0
- package/dist/gaia-security/hooks/modules/core/stdin.py +24 -0
- package/dist/gaia-security/hooks/modules/events/__init__.py +1 -0
- package/dist/gaia-security/hooks/modules/events/event_writer.py +210 -0
- package/dist/gaia-security/hooks/modules/memory/__init__.py +8 -0
- package/dist/gaia-security/hooks/modules/memory/episode_writer.py +216 -0
- package/dist/gaia-security/hooks/modules/orchestrator/__init__.py +1 -0
- package/dist/gaia-security/hooks/modules/orchestrator/delegate_mode.py +122 -0
- package/dist/gaia-security/hooks/modules/scanning/__init__.py +8 -0
- package/dist/gaia-security/hooks/modules/scanning/scan_trigger.py +84 -0
- package/dist/gaia-security/hooks/modules/security/__init__.py +120 -0
- package/dist/gaia-security/hooks/modules/security/approval_cleanup.py +87 -0
- package/dist/gaia-security/hooks/modules/security/approval_constants.py +23 -0
- package/dist/gaia-security/hooks/modules/security/approval_grants.py +1638 -0
- package/dist/gaia-security/hooks/modules/security/approval_messages.py +71 -0
- package/dist/gaia-security/hooks/modules/security/approval_scopes.py +222 -0
- package/dist/gaia-security/hooks/modules/security/blocked_commands.py +595 -0
- package/dist/gaia-security/hooks/modules/security/blocked_message_formatter.py +87 -0
- package/dist/gaia-security/hooks/modules/security/command_semantics.py +181 -0
- package/dist/gaia-security/hooks/modules/security/composition_rules.py +547 -0
- package/dist/gaia-security/hooks/modules/security/flag_classifiers.py +873 -0
- package/dist/gaia-security/hooks/modules/security/gitops_validator.py +179 -0
- package/dist/gaia-security/hooks/modules/security/mutative_verbs.py +1131 -0
- package/dist/gaia-security/hooks/modules/security/network_hosts.py +481 -0
- package/dist/gaia-security/hooks/modules/security/prompt_validator.py +40 -0
- package/dist/gaia-security/hooks/modules/security/shell_unwrapper.py +165 -0
- package/dist/gaia-security/hooks/modules/security/tiers.py +196 -0
- package/dist/gaia-security/hooks/modules/session/__init__.py +10 -0
- package/dist/gaia-security/hooks/modules/session/pending_scanner.py +174 -0
- package/dist/gaia-security/hooks/modules/session/session_context_writer.py +100 -0
- package/dist/gaia-security/hooks/modules/session/session_event_injector.py +160 -0
- package/dist/gaia-security/hooks/modules/session/session_manager.py +31 -0
- package/dist/gaia-security/hooks/modules/session/session_registry.py +232 -0
- package/dist/gaia-security/hooks/modules/tools/__init__.py +29 -0
- package/dist/gaia-security/hooks/modules/tools/bash_validator.py +1008 -0
- package/dist/gaia-security/hooks/modules/tools/cloud_pipe_validator.py +231 -0
- package/dist/gaia-security/hooks/modules/tools/hook_response.py +55 -0
- package/dist/gaia-security/hooks/modules/tools/shell_parser.py +227 -0
- package/dist/gaia-security/hooks/modules/tools/stage_decomposer.py +315 -0
- package/dist/gaia-security/hooks/modules/tools/task_validator.py +294 -0
- package/dist/gaia-security/hooks/modules/validation/__init__.py +23 -0
- package/dist/gaia-security/hooks/modules/validation/commit_validator.py +380 -0
- package/dist/gaia-security/hooks/post_tool_use.py +54 -0
- package/dist/gaia-security/hooks/pre_tool_use.py +413 -0
- package/dist/gaia-security/hooks/session_start.py +81 -0
- package/dist/gaia-security/hooks/stop_hook.py +82 -0
- package/dist/gaia-security/hooks/user_prompt_submit.py +246 -0
- package/dist/gaia-security/settings.json +58 -0
- package/git-hooks/commit-msg +41 -0
- package/hooks/README.md +100 -0
- package/hooks/adapters/__init__.py +52 -0
- package/hooks/adapters/base.py +219 -0
- package/hooks/adapters/channel.py +17 -0
- package/hooks/adapters/claude_code.py +1890 -0
- package/hooks/adapters/types.py +194 -0
- package/hooks/adapters/utils.py +25 -0
- package/hooks/elicitation_result.py +179 -0
- package/hooks/hooks.json +84 -0
- package/hooks/modules/README.md +189 -0
- package/hooks/modules/__init__.py +15 -0
- package/hooks/modules/agents/__init__.py +29 -0
- package/hooks/modules/agents/contract_validator.py +647 -0
- package/hooks/modules/agents/response_contract.py +496 -0
- package/hooks/modules/agents/skill_injection_verifier.py +120 -0
- package/hooks/modules/agents/state_tracker.py +267 -0
- package/hooks/modules/agents/task_info_builder.py +74 -0
- package/hooks/modules/agents/transcript_analyzer.py +458 -0
- package/hooks/modules/agents/transcript_reader.py +152 -0
- package/hooks/modules/audit/__init__.py +28 -0
- package/hooks/modules/audit/event_detector.py +168 -0
- package/hooks/modules/audit/logger.py +131 -0
- package/hooks/modules/audit/metrics.py +134 -0
- package/hooks/modules/audit/workflow_auditor.py +611 -0
- package/hooks/modules/audit/workflow_recorder.py +296 -0
- package/hooks/modules/context/__init__.py +11 -0
- package/hooks/modules/context/agentic_loop_detector.py +165 -0
- package/hooks/modules/context/anchor_tracker.py +317 -0
- package/hooks/modules/context/compact_context_builder.py +218 -0
- package/hooks/modules/context/context_freshness.py +145 -0
- package/hooks/modules/context/context_injector.py +558 -0
- package/hooks/modules/context/context_writer.py +530 -0
- package/hooks/modules/context/contracts_loader.py +161 -0
- package/hooks/modules/core/__init__.py +40 -0
- package/hooks/modules/core/hook_entry.py +78 -0
- package/hooks/modules/core/paths.py +160 -0
- package/hooks/modules/core/plugin_mode.py +149 -0
- package/hooks/modules/core/plugin_setup.py +577 -0
- package/hooks/modules/core/state.py +179 -0
- package/hooks/modules/core/stdin.py +24 -0
- package/hooks/modules/events/__init__.py +1 -0
- package/hooks/modules/events/event_writer.py +210 -0
- package/hooks/modules/evidence/__init__.py +34 -0
- package/hooks/modules/evidence/assertions.py +137 -0
- package/hooks/modules/evidence/index_writer.py +57 -0
- package/hooks/modules/evidence/loader.py +126 -0
- package/hooks/modules/evidence/runner.py +241 -0
- package/hooks/modules/memory/__init__.py +8 -0
- package/hooks/modules/memory/episode_writer.py +216 -0
- package/hooks/modules/orchestrator/__init__.py +1 -0
- package/hooks/modules/orchestrator/delegate_mode.py +122 -0
- package/hooks/modules/scanning/__init__.py +8 -0
- package/hooks/modules/scanning/scan_trigger.py +84 -0
- package/hooks/modules/security/__init__.py +120 -0
- package/hooks/modules/security/approval_cleanup.py +87 -0
- package/hooks/modules/security/approval_constants.py +23 -0
- package/hooks/modules/security/approval_grants.py +1638 -0
- package/hooks/modules/security/approval_messages.py +71 -0
- package/hooks/modules/security/approval_scopes.py +222 -0
- package/hooks/modules/security/blocked_commands.py +595 -0
- package/hooks/modules/security/blocked_message_formatter.py +87 -0
- package/hooks/modules/security/command_semantics.py +181 -0
- package/hooks/modules/security/composition_rules.py +547 -0
- package/hooks/modules/security/flag_classifiers.py +873 -0
- package/hooks/modules/security/gitops_validator.py +179 -0
- package/hooks/modules/security/mutative_verbs.py +1131 -0
- package/hooks/modules/security/network_hosts.py +481 -0
- package/hooks/modules/security/prompt_validator.py +40 -0
- package/hooks/modules/security/shell_unwrapper.py +165 -0
- package/hooks/modules/security/tiers.py +196 -0
- package/hooks/modules/session/__init__.py +10 -0
- package/hooks/modules/session/pending_scanner.py +174 -0
- package/hooks/modules/session/session_context_writer.py +100 -0
- package/hooks/modules/session/session_event_injector.py +160 -0
- package/hooks/modules/session/session_manager.py +31 -0
- package/hooks/modules/session/session_registry.py +232 -0
- package/hooks/modules/tools/__init__.py +29 -0
- package/hooks/modules/tools/bash_validator.py +1008 -0
- package/hooks/modules/tools/cloud_pipe_validator.py +231 -0
- package/hooks/modules/tools/hook_response.py +55 -0
- package/hooks/modules/tools/shell_parser.py +227 -0
- package/hooks/modules/tools/stage_decomposer.py +315 -0
- package/hooks/modules/tools/task_validator.py +294 -0
- package/hooks/modules/validation/__init__.py +23 -0
- package/hooks/modules/validation/commit_validator.py +380 -0
- package/hooks/post_compact.py +43 -0
- package/hooks/post_tool_use.py +54 -0
- package/hooks/pre_compact.py +60 -0
- package/hooks/pre_tool_use.py +413 -0
- package/hooks/session_start.py +81 -0
- package/hooks/stop_hook.py +82 -0
- package/hooks/subagent_start.py +71 -0
- package/hooks/subagent_stop.py +295 -0
- package/hooks/task_completed.py +70 -0
- package/hooks/user_prompt_submit.py +246 -0
- package/index.js +83 -0
- package/package.json +99 -0
- package/pyproject.toml +32 -0
- package/skills/README.md +154 -0
- package/skills/agent-protocol/SKILL.md +93 -0
- package/skills/agent-protocol/examples.md +223 -0
- package/skills/agent-response/SKILL.md +69 -0
- package/skills/agentic-loop/SKILL.md +80 -0
- package/skills/agentic-loop/reference.md +378 -0
- package/skills/blog-writing/SKILL.md +98 -0
- package/skills/blog-writing/reference.md +130 -0
- package/skills/brief-spec/SKILL.md +182 -0
- package/skills/command-execution/SKILL.md +64 -0
- package/skills/command-execution/reference.md +83 -0
- package/skills/context-updater/SKILL.md +87 -0
- package/skills/context-updater/examples.md +71 -0
- package/skills/developer-patterns/SKILL.md +50 -0
- package/skills/developer-patterns/reference.md +112 -0
- package/skills/execution/SKILL.md +99 -0
- package/skills/fast-queries/SKILL.md +43 -0
- package/skills/gaia-compact/SKILL.md +74 -0
- package/skills/gaia-patterns/SKILL.md +108 -0
- package/skills/gaia-patterns/reference.md +395 -0
- package/skills/gaia-planner/SKILL.md +37 -0
- package/skills/gaia-planner/reference.md +107 -0
- package/skills/gaia-release/SKILL.md +82 -0
- package/skills/gaia-release/reference.md +102 -0
- package/skills/gaia-self-check/SKILL.md +114 -0
- package/skills/gaia-self-check/reference.md +453 -0
- package/skills/gaia-verify/SKILL.md +77 -0
- package/skills/gaia-verify/reference.md +80 -0
- package/skills/git-conventions/SKILL.md +47 -0
- package/skills/gitops-patterns/SKILL.md +60 -0
- package/skills/gitops-patterns/reference.md +183 -0
- package/skills/gmail-policy/SKILL.md +200 -0
- package/skills/gmail-policy/reference.md +150 -0
- package/skills/gmail-triage/SKILL.md +100 -0
- package/skills/gws-setup/SKILL.md +99 -0
- package/skills/gws-setup/reference.md +73 -0
- package/skills/investigation/SKILL.md +100 -0
- package/skills/memory-curation/SKILL.md +83 -0
- package/skills/memory-search/SKILL.md +88 -0
- package/skills/orchestrator-approval/SKILL.md +160 -0
- package/skills/orchestrator-approval/reference.md +174 -0
- package/skills/pending-approvals/SKILL.md +72 -0
- package/skills/pending-approvals/reference.md +214 -0
- package/skills/readme-writing/SKILL.md +71 -0
- package/skills/readme-writing/reference.md +188 -0
- package/skills/reference.md +135 -0
- package/skills/request-approval/SKILL.md +140 -0
- package/skills/request-approval/examples.md +140 -0
- package/skills/request-approval/reference.md +57 -0
- package/skills/schedule-task/SKILL.md +64 -0
- package/skills/schedule-task/reference.md +233 -0
- package/skills/security-tiers/SKILL.md +141 -0
- package/skills/security-tiers/destructive-commands-reference.md +623 -0
- package/skills/security-tiers/reference.md +39 -0
- package/skills/skill-creation/SKILL.md +92 -0
- package/skills/skill-creation/reference.md +29 -0
- package/skills/terraform-patterns/SKILL.md +89 -0
- package/skills/terraform-patterns/reference.md +93 -0
- package/templates/README.md +69 -0
- package/templates/managed-settings.template.json +43 -0
- package/tools/__init__.py +9 -0
- package/tools/agentic-loop/decide-status.py +210 -0
- package/tools/agentic-loop/parse-metric.py +106 -0
- package/tools/agentic-loop/record-iteration.py +221 -0
- package/tools/context/README.md +132 -0
- package/tools/context/__init__.py +42 -0
- package/tools/context/_paths.py +20 -0
- package/tools/context/context_provider.py +721 -0
- package/tools/context/context_section_reader.py +342 -0
- package/tools/context/deep_merge.py +159 -0
- package/tools/context/pending_updates.py +760 -0
- package/tools/context/surface_router.py +278 -0
- package/tools/fast-queries/README.md +65 -0
- package/tools/fast-queries/__init__.py +30 -0
- package/tools/fast-queries/appservices/quicktriage_devops_developer.sh +75 -0
- package/tools/fast-queries/cloud/aws/quicktriage_aws_troubleshooter.sh +32 -0
- package/tools/fast-queries/cloud/gcp/quicktriage_gcp_troubleshooter.sh +88 -0
- package/tools/fast-queries/gitops/quicktriage_gitops_operator.sh +48 -0
- package/tools/fast-queries/run_triage.sh +59 -0
- package/tools/fast-queries/terraform/quicktriage_terraform_architect.sh +80 -0
- package/tools/gaia_simulator/__init__.py +33 -0
- package/tools/gaia_simulator/cli.py +354 -0
- package/tools/gaia_simulator/extractor.py +457 -0
- package/tools/gaia_simulator/reporter.py +258 -0
- package/tools/gaia_simulator/routing_simulator.py +334 -0
- package/tools/gaia_simulator/runner.py +539 -0
- package/tools/gaia_simulator/skills_mapper.py +264 -0
- package/tools/memory/README.md +0 -0
- package/tools/memory/__init__.py +20 -0
- package/tools/memory/backfill_fts5.py +107 -0
- package/tools/memory/conflict_detector.py +295 -0
- package/tools/memory/episodic.py +1210 -0
- package/tools/memory/git_invalidator.py +262 -0
- package/tools/memory/paths.py +102 -0
- package/tools/memory/scoring.py +193 -0
- package/tools/memory/search_store.py +360 -0
- package/tools/persist_transcript_analysis.py +85 -0
- package/tools/review/__init__.py +1 -0
- package/tools/review/review_engine.py +157 -0
- package/tools/scan/__init__.py +35 -0
- package/tools/scan/config.py +247 -0
- package/tools/scan/merge.py +212 -0
- package/tools/scan/orchestrator.py +549 -0
- package/tools/scan/registry.py +127 -0
- package/tools/scan/scanners/__init__.py +18 -0
- package/tools/scan/scanners/base.py +137 -0
- package/tools/scan/scanners/environment.py +349 -0
- package/tools/scan/scanners/git.py +570 -0
- package/tools/scan/scanners/infrastructure.py +875 -0
- package/tools/scan/scanners/orchestration.py +600 -0
- package/tools/scan/scanners/stack.py +1085 -0
- package/tools/scan/scanners/tools.py +260 -0
- package/tools/scan/setup.py +686 -0
- package/tools/scan/tests/__init__.py +1 -0
- package/tools/scan/tests/conftest.py +796 -0
- package/tools/scan/tests/test_environment.py +323 -0
- package/tools/scan/tests/test_git.py +419 -0
- package/tools/scan/tests/test_infrastructure.py +382 -0
- package/tools/scan/tests/test_integration.py +920 -0
- package/tools/scan/tests/test_merge.py +269 -0
- package/tools/scan/tests/test_orchestration.py +304 -0
- package/tools/scan/tests/test_stack.py +604 -0
- package/tools/scan/tests/test_tools.py +349 -0
- package/tools/scan/ui.py +624 -0
- package/tools/scan/verify.py +270 -0
- package/tools/scan/walk.py +118 -0
- package/tools/scan/workspace.py +85 -0
- package/tools/validation/README.md +244 -0
- package/tools/validation/__init__.py +17 -0
- package/tools/validation/approval_gate.py +321 -0
- package/tools/validation/validate_skills.py +189 -0
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Git Commit Message Validator
|
|
3
|
+
|
|
4
|
+
Validates commit messages against project standards before execution.
|
|
5
|
+
This prevents commits with forbidden footers or incorrect format from
|
|
6
|
+
being pushed to the repository.
|
|
7
|
+
|
|
8
|
+
Usage:
|
|
9
|
+
from commit_validator import CommitMessageValidator
|
|
10
|
+
|
|
11
|
+
validator = CommitMessageValidator()
|
|
12
|
+
validation = validator.validate(commit_message)
|
|
13
|
+
|
|
14
|
+
if not validation.valid:
|
|
15
|
+
for error in validation.errors:
|
|
16
|
+
print(f"Error: {error['message']}")
|
|
17
|
+
# Do not proceed with commit
|
|
18
|
+
else:
|
|
19
|
+
# Safe to commit
|
|
20
|
+
git commit -m "$commit_message"
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
import json
|
|
24
|
+
import os
|
|
25
|
+
import re
|
|
26
|
+
from typing import Dict, List, Any, Optional
|
|
27
|
+
from datetime import datetime
|
|
28
|
+
from dataclasses import dataclass
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@dataclass
|
|
32
|
+
class ValidationResult:
|
|
33
|
+
"""Result of commit message validation."""
|
|
34
|
+
valid: bool
|
|
35
|
+
errors: List[Dict[str, str]]
|
|
36
|
+
warnings: List[Dict[str, str]] = None
|
|
37
|
+
|
|
38
|
+
def __post_init__(self):
|
|
39
|
+
if self.warnings is None:
|
|
40
|
+
self.warnings = []
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class CommitMessageValidator:
|
|
44
|
+
"""
|
|
45
|
+
Validates git commit messages against project standards.
|
|
46
|
+
|
|
47
|
+
Standards are defined in .claude/config/git_standards.json
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
def __init__(self, config_path: Optional[str] = None):
|
|
51
|
+
"""
|
|
52
|
+
Initialize validator with configuration.
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
config_path: Optional path to git_standards.json
|
|
56
|
+
If None, uses default location
|
|
57
|
+
"""
|
|
58
|
+
if config_path is None:
|
|
59
|
+
# Default path relative to this file
|
|
60
|
+
# From hooks/modules/validation/ go up to gaia-ops root
|
|
61
|
+
# __file__ -> hooks/modules/validation/commit_validator.py
|
|
62
|
+
# dirname(dirname(dirname(dirname(__file__)))) -> gaia-ops root
|
|
63
|
+
base_path = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
|
|
64
|
+
config_path = os.path.join(base_path, 'config', 'git_standards.json')
|
|
65
|
+
else:
|
|
66
|
+
# If config_path provided, derive base_path from it
|
|
67
|
+
base_path = os.path.dirname(os.path.dirname(config_path))
|
|
68
|
+
|
|
69
|
+
self.base_path = base_path
|
|
70
|
+
self.config_path = config_path
|
|
71
|
+
self.config = self._load_config()
|
|
72
|
+
self.standards = self.config.get('commit_message', {})
|
|
73
|
+
self.enforcement = self.config.get('enforcement', {})
|
|
74
|
+
|
|
75
|
+
def _load_config(self) -> Dict[str, Any]:
|
|
76
|
+
"""Load git standards configuration from JSON file."""
|
|
77
|
+
if not os.path.exists(self.config_path):
|
|
78
|
+
raise FileNotFoundError(
|
|
79
|
+
f"Git standards configuration not found at: {self.config_path}"
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
with open(self.config_path, 'r') as f:
|
|
83
|
+
return json.load(f)
|
|
84
|
+
|
|
85
|
+
def validate(self, message: str) -> ValidationResult:
|
|
86
|
+
"""
|
|
87
|
+
Validate a commit message against all standards.
|
|
88
|
+
|
|
89
|
+
Args:
|
|
90
|
+
message: The commit message to validate
|
|
91
|
+
|
|
92
|
+
Returns:
|
|
93
|
+
ValidationResult with valid status and any errors/warnings
|
|
94
|
+
"""
|
|
95
|
+
errors = []
|
|
96
|
+
warnings = []
|
|
97
|
+
|
|
98
|
+
# 1. Check for forbidden footers (CRITICAL)
|
|
99
|
+
footer_errors = self._check_forbidden_footers(message)
|
|
100
|
+
errors.extend(footer_errors)
|
|
101
|
+
|
|
102
|
+
# 2. Check conventional commits format
|
|
103
|
+
format_errors = self._check_conventional_format(message)
|
|
104
|
+
errors.extend(format_errors)
|
|
105
|
+
|
|
106
|
+
# 3. Check subject line rules
|
|
107
|
+
subject_errors = self._check_subject_rules(message)
|
|
108
|
+
errors.extend(subject_errors)
|
|
109
|
+
|
|
110
|
+
# 4. Check body rules (warnings only)
|
|
111
|
+
body_warnings = self._check_body_rules(message)
|
|
112
|
+
warnings.extend(body_warnings)
|
|
113
|
+
|
|
114
|
+
# Log violations if configured
|
|
115
|
+
if errors and self.enforcement.get('log_violations', False):
|
|
116
|
+
self._log_violation(message, errors)
|
|
117
|
+
|
|
118
|
+
return ValidationResult(
|
|
119
|
+
valid=len(errors) == 0,
|
|
120
|
+
errors=errors,
|
|
121
|
+
warnings=warnings
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
def _check_forbidden_footers(self, message: str) -> List[Dict[str, str]]:
|
|
125
|
+
"""Check for forbidden footers in commit message."""
|
|
126
|
+
errors = []
|
|
127
|
+
forbidden = self.standards.get('footer_forbidden', [])
|
|
128
|
+
|
|
129
|
+
for forbidden_text in forbidden:
|
|
130
|
+
if forbidden_text.lower() in message.lower():
|
|
131
|
+
errors.append({
|
|
132
|
+
'type': 'FORBIDDEN_FOOTER',
|
|
133
|
+
'message': f"Commit message contains forbidden footer: '{forbidden_text}'",
|
|
134
|
+
'fix': f"Remove all occurrences of '{forbidden_text}'",
|
|
135
|
+
'severity': 'error'
|
|
136
|
+
})
|
|
137
|
+
|
|
138
|
+
return errors
|
|
139
|
+
|
|
140
|
+
def _check_conventional_format(self, message: str) -> List[Dict[str, str]]:
|
|
141
|
+
"""Check if message follows Conventional Commits format."""
|
|
142
|
+
errors = []
|
|
143
|
+
|
|
144
|
+
# Get first line (subject)
|
|
145
|
+
lines = message.split('\n')
|
|
146
|
+
subject = lines[0].strip()
|
|
147
|
+
|
|
148
|
+
# Pattern: type(scope)?: description
|
|
149
|
+
# Examples: feat: add feature, fix(api): correct bug
|
|
150
|
+
allowed_types = '|'.join(self.standards.get('type_allowed', []))
|
|
151
|
+
pattern = rf'^({allowed_types})(\(.+?\))?: .+$'
|
|
152
|
+
|
|
153
|
+
if not re.match(pattern, subject):
|
|
154
|
+
errors.append({
|
|
155
|
+
'type': 'INVALID_FORMAT',
|
|
156
|
+
'message': 'Commit message does not follow Conventional Commits format',
|
|
157
|
+
'fix': f"Use format: type(scope): description\nAllowed types: {', '.join(self.standards.get('type_allowed', []))}",
|
|
158
|
+
'severity': 'error',
|
|
159
|
+
'examples': self.standards.get('examples_valid', [])
|
|
160
|
+
})
|
|
161
|
+
|
|
162
|
+
return errors
|
|
163
|
+
|
|
164
|
+
def _check_subject_rules(self, message: str) -> List[Dict[str, str]]:
|
|
165
|
+
"""Check subject line specific rules."""
|
|
166
|
+
errors = []
|
|
167
|
+
|
|
168
|
+
lines = message.split('\n')
|
|
169
|
+
subject = lines[0].strip()
|
|
170
|
+
|
|
171
|
+
# Extract description part (after type and scope)
|
|
172
|
+
# Example: "feat(scope): description" -> "description"
|
|
173
|
+
match = re.match(r'^[a-z]+(\(.+?\))?: (.+)$', subject)
|
|
174
|
+
if match:
|
|
175
|
+
description = match.group(2)
|
|
176
|
+
|
|
177
|
+
# Check max length
|
|
178
|
+
max_length = self.standards.get('subject_max_length', 72)
|
|
179
|
+
if len(subject) > max_length:
|
|
180
|
+
errors.append({
|
|
181
|
+
'type': 'SUBJECT_TOO_LONG',
|
|
182
|
+
'message': f'Subject line exceeds {max_length} characters (current: {len(subject)})',
|
|
183
|
+
'fix': f'Shorten subject to {max_length} characters or less',
|
|
184
|
+
'severity': 'error'
|
|
185
|
+
})
|
|
186
|
+
|
|
187
|
+
# Check for period at end
|
|
188
|
+
rules = self.standards.get('subject_rules', {})
|
|
189
|
+
if rules.get('no_period_at_end', True) and description.endswith('.'):
|
|
190
|
+
errors.append({
|
|
191
|
+
'type': 'SUBJECT_ENDS_WITH_PERIOD',
|
|
192
|
+
'message': 'Subject line should not end with a period',
|
|
193
|
+
'fix': 'Remove the period at the end of the subject',
|
|
194
|
+
'severity': 'error'
|
|
195
|
+
})
|
|
196
|
+
|
|
197
|
+
# Check for emojis in subject line
|
|
198
|
+
if rules.get('no_emoji', False):
|
|
199
|
+
emoji_pattern = re.compile(
|
|
200
|
+
"["
|
|
201
|
+
"\U0001F600-\U0001F64F" # emoticons
|
|
202
|
+
"\U0001F300-\U0001F5FF" # symbols & pictographs
|
|
203
|
+
"\U0001F680-\U0001F6FF" # transport & map symbols
|
|
204
|
+
"\U0001F700-\U0001F77F" # alchemical symbols
|
|
205
|
+
"\U0001F780-\U0001F7FF" # Geometric Shapes Extended
|
|
206
|
+
"\U0001F800-\U0001F8FF" # Supplemental Arrows-C
|
|
207
|
+
"\U0001F900-\U0001F9FF" # Supplemental Symbols and Pictographs
|
|
208
|
+
"\U0001FA00-\U0001FA6F" # Chess Symbols
|
|
209
|
+
"\U0001FA70-\U0001FAFF" # Symbols and Pictographs Extended-A
|
|
210
|
+
"\U00002702-\U000027B0" # Dingbats
|
|
211
|
+
"\U000024C2-\U0001F251" # Enclosed characters
|
|
212
|
+
"]+", flags=re.UNICODE
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
if emoji_pattern.search(subject):
|
|
216
|
+
errors.append({
|
|
217
|
+
'type': 'SUBJECT_CONTAINS_EMOJI',
|
|
218
|
+
'message': 'Subject line contains emojis which are not allowed',
|
|
219
|
+
'fix': 'Remove all emojis from the subject line',
|
|
220
|
+
'severity': 'error'
|
|
221
|
+
})
|
|
222
|
+
|
|
223
|
+
return errors
|
|
224
|
+
|
|
225
|
+
def _check_body_rules(self, message: str) -> List[Dict[str, str]]:
|
|
226
|
+
"""Check body rules (returns warnings, not errors)."""
|
|
227
|
+
warnings = []
|
|
228
|
+
|
|
229
|
+
lines = message.split('\n')
|
|
230
|
+
|
|
231
|
+
# Check if there's a body (more than just subject)
|
|
232
|
+
if len(lines) <= 1:
|
|
233
|
+
return warnings
|
|
234
|
+
|
|
235
|
+
# Check blank line after subject
|
|
236
|
+
if len(lines) > 1 and lines[1].strip() != '':
|
|
237
|
+
warnings.append({
|
|
238
|
+
'type': 'MISSING_BLANK_LINE',
|
|
239
|
+
'message': 'Missing blank line between subject and body',
|
|
240
|
+
'fix': 'Add a blank line after the subject line',
|
|
241
|
+
'severity': 'warning'
|
|
242
|
+
})
|
|
243
|
+
|
|
244
|
+
# Check body line length
|
|
245
|
+
max_length = self.standards.get('body_max_line_length', 72)
|
|
246
|
+
for i, line in enumerate(lines[2:], start=3): # Skip subject and blank line
|
|
247
|
+
if len(line) > max_length and not line.startswith('http'):
|
|
248
|
+
warnings.append({
|
|
249
|
+
'type': 'BODY_LINE_TOO_LONG',
|
|
250
|
+
'message': f'Body line {i} exceeds {max_length} characters',
|
|
251
|
+
'fix': f'Wrap line to {max_length} characters',
|
|
252
|
+
'severity': 'warning'
|
|
253
|
+
})
|
|
254
|
+
|
|
255
|
+
return warnings
|
|
256
|
+
|
|
257
|
+
def _log_violation(self, message: str, errors: List[Dict[str, str]]):
|
|
258
|
+
"""Log commit message violation for audit trail."""
|
|
259
|
+
log_path = self.enforcement.get('log_path', '.claude/logs/commit-violations.jsonl')
|
|
260
|
+
|
|
261
|
+
# If log_path is relative, resolve from base_path (not cwd)
|
|
262
|
+
if not os.path.isabs(log_path):
|
|
263
|
+
# Remove leading ./ if present
|
|
264
|
+
log_path = log_path.lstrip('./')
|
|
265
|
+
# If starts with 'claude/', remove it since base_path already points to .claude/
|
|
266
|
+
if log_path.startswith('claude/'):
|
|
267
|
+
log_path = log_path[7:] # Remove 'claude/' prefix
|
|
268
|
+
log_path = os.path.join(self.base_path, log_path)
|
|
269
|
+
|
|
270
|
+
# Ensure log directory exists
|
|
271
|
+
log_dir = os.path.dirname(log_path)
|
|
272
|
+
if log_dir and not os.path.exists(log_dir):
|
|
273
|
+
os.makedirs(log_dir, exist_ok=True)
|
|
274
|
+
|
|
275
|
+
log_entry = {
|
|
276
|
+
'timestamp': datetime.now().isoformat(),
|
|
277
|
+
'message': message[:100] + ('...' if len(message) > 100 else ''),
|
|
278
|
+
'errors': errors,
|
|
279
|
+
'error_count': len(errors)
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
with open(log_path, 'a') as f:
|
|
283
|
+
f.write(json.dumps(log_entry) + '\n')
|
|
284
|
+
|
|
285
|
+
def get_examples(self) -> Dict[str, List[str]]:
|
|
286
|
+
"""Get example commit messages (valid and invalid)."""
|
|
287
|
+
return {
|
|
288
|
+
'valid': self.standards.get('examples_valid', []),
|
|
289
|
+
'invalid': self.standards.get('examples_invalid', [])
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
def get_allowed_types(self) -> List[str]:
|
|
293
|
+
"""Get list of allowed commit types."""
|
|
294
|
+
return self.standards.get('type_allowed', [])
|
|
295
|
+
|
|
296
|
+
def format_error_message(self, validation: ValidationResult) -> str:
|
|
297
|
+
"""
|
|
298
|
+
Format validation errors into human-readable message.
|
|
299
|
+
|
|
300
|
+
Args:
|
|
301
|
+
validation: ValidationResult from validate()
|
|
302
|
+
|
|
303
|
+
Returns:
|
|
304
|
+
Formatted error message string
|
|
305
|
+
"""
|
|
306
|
+
if validation.valid:
|
|
307
|
+
return "[OK] Commit message is valid"
|
|
308
|
+
|
|
309
|
+
lines = ["[ERROR] Commit message validation failed:\n"]
|
|
310
|
+
|
|
311
|
+
for error in validation.errors:
|
|
312
|
+
lines.append(f" [{error['type']}]")
|
|
313
|
+
lines.append(f" {error['message']}")
|
|
314
|
+
lines.append(f" Fix: {error['fix']}")
|
|
315
|
+
|
|
316
|
+
if 'examples' in error:
|
|
317
|
+
lines.append(f" Examples:")
|
|
318
|
+
for example in error['examples'][:3]:
|
|
319
|
+
lines.append(f" - {example}")
|
|
320
|
+
|
|
321
|
+
lines.append("")
|
|
322
|
+
|
|
323
|
+
if validation.warnings:
|
|
324
|
+
lines.append("[WARNING] Warnings:")
|
|
325
|
+
for warning in validation.warnings:
|
|
326
|
+
lines.append(f" - {warning['message']}")
|
|
327
|
+
lines.append("")
|
|
328
|
+
|
|
329
|
+
return "\n".join(lines)
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+
# Convenience function for quick validation
|
|
333
|
+
def validate_commit_message(message: str) -> ValidationResult:
|
|
334
|
+
"""
|
|
335
|
+
Quick validation function.
|
|
336
|
+
|
|
337
|
+
Args:
|
|
338
|
+
message: Commit message to validate
|
|
339
|
+
|
|
340
|
+
Returns:
|
|
341
|
+
ValidationResult
|
|
342
|
+
|
|
343
|
+
Example:
|
|
344
|
+
validation = validate_commit_message("feat: add new feature")
|
|
345
|
+
if not validation.valid:
|
|
346
|
+
print("Invalid commit message")
|
|
347
|
+
"""
|
|
348
|
+
validator = CommitMessageValidator()
|
|
349
|
+
return validator.validate(message)
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
# Function for use in git commit workflow
|
|
353
|
+
def safe_validate_before_commit(message: str) -> bool:
|
|
354
|
+
"""
|
|
355
|
+
Validate commit message and print errors if invalid.
|
|
356
|
+
|
|
357
|
+
This is the primary function that agents should call before git commit.
|
|
358
|
+
|
|
359
|
+
Args:
|
|
360
|
+
message: Commit message to validate
|
|
361
|
+
|
|
362
|
+
Returns:
|
|
363
|
+
True if valid, False if invalid (with errors printed)
|
|
364
|
+
|
|
365
|
+
Example:
|
|
366
|
+
if not safe_validate_before_commit(commit_message):
|
|
367
|
+
return {"status": "failed", "reason": "commit_validation_failed"}
|
|
368
|
+
|
|
369
|
+
# Safe to commit
|
|
370
|
+
Bash(f'git commit -m "{commit_message}"')
|
|
371
|
+
"""
|
|
372
|
+
validator = CommitMessageValidator()
|
|
373
|
+
validation = validator.validate(message)
|
|
374
|
+
|
|
375
|
+
if not validation.valid:
|
|
376
|
+
error_message = validator.format_error_message(validation)
|
|
377
|
+
print(error_message)
|
|
378
|
+
return False
|
|
379
|
+
|
|
380
|
+
return True
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""PostCompact hook — re-injects compact context after conversation compaction."""
|
|
3
|
+
|
|
4
|
+
import sys
|
|
5
|
+
import json
|
|
6
|
+
import logging
|
|
7
|
+
from datetime import datetime
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
sys.path.insert(0, str(Path(__file__).parent))
|
|
11
|
+
|
|
12
|
+
from modules.core.hook_entry import run_hook
|
|
13
|
+
from modules.core.paths import get_logs_dir
|
|
14
|
+
from modules.context.compact_context_builder import build_compact_context
|
|
15
|
+
|
|
16
|
+
# Configure logging
|
|
17
|
+
_log_file = get_logs_dir() / f"hooks-{datetime.now().strftime('%Y-%m-%d')}.log"
|
|
18
|
+
logging.basicConfig(
|
|
19
|
+
level=logging.INFO,
|
|
20
|
+
format='%(asctime)s [post_compact] %(name)s - %(levelname)s - %(message)s',
|
|
21
|
+
handlers=[logging.FileHandler(_log_file)],
|
|
22
|
+
)
|
|
23
|
+
logger = logging.getLogger(__name__)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _handle_post_compact(event) -> None:
|
|
27
|
+
"""Re-inject compact context after compaction."""
|
|
28
|
+
context = build_compact_context()
|
|
29
|
+
|
|
30
|
+
logger.info("PostCompact: injecting %d chars of context", len(context))
|
|
31
|
+
|
|
32
|
+
response = {
|
|
33
|
+
"hookSpecificOutput": {
|
|
34
|
+
"additionalContext": context,
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
print(json.dumps(response))
|
|
39
|
+
sys.exit(0)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
if __name__ == "__main__":
|
|
43
|
+
run_hook(_handle_post_compact, hook_name="post_compact")
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Post-tool use hook - Thin gate.
|
|
4
|
+
|
|
5
|
+
Architecture:
|
|
6
|
+
- Uses adapter layer to parse and process the full PostToolUse lifecycle
|
|
7
|
+
- All business logic lives in ClaudeCodeAdapter.adapt_post_tool_use()
|
|
8
|
+
- This file is stdin/stdout glue only
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import sys
|
|
12
|
+
import json
|
|
13
|
+
import logging
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
from datetime import datetime
|
|
16
|
+
|
|
17
|
+
sys.path.insert(0, str(Path(__file__).parent))
|
|
18
|
+
|
|
19
|
+
from modules.core.paths import get_logs_dir
|
|
20
|
+
from adapters.claude_code import ClaudeCodeAdapter
|
|
21
|
+
from modules.core.hook_entry import run_hook
|
|
22
|
+
|
|
23
|
+
# Configure logging
|
|
24
|
+
log_file = get_logs_dir() / f"hooks-{datetime.now().strftime('%Y-%m-%d')}.log"
|
|
25
|
+
logging.basicConfig(
|
|
26
|
+
level=logging.INFO,
|
|
27
|
+
format='%(asctime)s [post_tool_use] %(name)s - %(levelname)s - %(message)s',
|
|
28
|
+
handlers=[logging.FileHandler(log_file)],
|
|
29
|
+
)
|
|
30
|
+
logger = logging.getLogger(__name__)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _handle_post_tool_use(event) -> None:
|
|
34
|
+
"""Process a PostToolUse event.
|
|
35
|
+
|
|
36
|
+
Delegates all business logic to the adapter.
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
event: Parsed HookEvent from the adapter layer.
|
|
40
|
+
"""
|
|
41
|
+
adapter = ClaudeCodeAdapter()
|
|
42
|
+
response = adapter.adapt_post_tool_use(event)
|
|
43
|
+
|
|
44
|
+
if response.output:
|
|
45
|
+
print(json.dumps(response.output))
|
|
46
|
+
sys.exit(response.exit_code)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
# ============================================================================
|
|
50
|
+
# STDIN HANDLER (Claude Code integration)
|
|
51
|
+
# ============================================================================
|
|
52
|
+
|
|
53
|
+
if __name__ == "__main__":
|
|
54
|
+
run_hook(_handle_post_tool_use, hook_name="post_tool_use")
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""PreCompact hook — injects agentic-loop checkpoint instructions before context compaction.
|
|
3
|
+
|
|
4
|
+
When an agentic-loop is active, the agent needs to save its state before
|
|
5
|
+
compaction wipes context. This hook detects the loop and injects a prompt
|
|
6
|
+
telling the agent to write continue.md + update state.json + worklog.md.
|
|
7
|
+
|
|
8
|
+
If no loop is active, this hook is a no-op (returns empty additionalContext).
|
|
9
|
+
All errors are caught and logged — this hook never blocks compaction.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
import sys
|
|
13
|
+
import json
|
|
14
|
+
import logging
|
|
15
|
+
from datetime import datetime
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
|
|
18
|
+
sys.path.insert(0, str(Path(__file__).parent))
|
|
19
|
+
|
|
20
|
+
from modules.core.hook_entry import run_hook
|
|
21
|
+
from modules.core.paths import get_logs_dir
|
|
22
|
+
from modules.core.plugin_mode import is_ops_mode
|
|
23
|
+
|
|
24
|
+
# Configure logging
|
|
25
|
+
_log_file = get_logs_dir() / f"hooks-{datetime.now().strftime('%Y-%m-%d')}.log"
|
|
26
|
+
logging.basicConfig(
|
|
27
|
+
level=logging.INFO,
|
|
28
|
+
format='%(asctime)s [pre_compact] %(name)s - %(levelname)s - %(message)s',
|
|
29
|
+
handlers=[logging.FileHandler(_log_file)],
|
|
30
|
+
)
|
|
31
|
+
logger = logging.getLogger(__name__)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _handle_pre_compact(event) -> None:
|
|
35
|
+
"""Inject agentic-loop checkpoint instructions before compaction."""
|
|
36
|
+
context = ""
|
|
37
|
+
|
|
38
|
+
if is_ops_mode():
|
|
39
|
+
try:
|
|
40
|
+
from modules.context.agentic_loop_detector import build_precompact_prompt
|
|
41
|
+
context = build_precompact_prompt()
|
|
42
|
+
if context:
|
|
43
|
+
logger.info("PreCompact: injecting agentic-loop checkpoint prompt (%d chars)", len(context))
|
|
44
|
+
else:
|
|
45
|
+
logger.info("PreCompact: no active agentic loop, skipping")
|
|
46
|
+
except Exception as e:
|
|
47
|
+
logger.debug("PreCompact: agentic-loop detection failed (non-fatal): %s", e)
|
|
48
|
+
|
|
49
|
+
response = {
|
|
50
|
+
"hookSpecificOutput": {
|
|
51
|
+
"additionalContext": context,
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
print(json.dumps(response))
|
|
56
|
+
sys.exit(0)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
if __name__ == "__main__":
|
|
60
|
+
run_hook(_handle_pre_compact, hook_name="pre_compact")
|