@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,360 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
FTS5-Backed Search Store for GAIA-OPS
|
|
4
|
+
|
|
5
|
+
Provides full-text search over episodic memory using SQLite FTS5 (default)
|
|
6
|
+
with an optional Chroma vector-search backend.
|
|
7
|
+
|
|
8
|
+
Zero external dependencies for core operation — stdlib only (sqlite3, shutil,
|
|
9
|
+
os, pathlib, typing, abc). chromadb is imported lazily and only used if
|
|
10
|
+
available and not suppressed via GAIA_TEST_NO_CHROMA.
|
|
11
|
+
|
|
12
|
+
Architecture:
|
|
13
|
+
- SearchProvider ABC defines the interface
|
|
14
|
+
- FTS5Provider wraps SQLite FTS5 (always available)
|
|
15
|
+
- ChromaProvider stub that activates only when chromadb is importable and
|
|
16
|
+
GAIA_TEST_NO_CHROMA is not set
|
|
17
|
+
- Module-level get_backend() / index_episode() / search() / count()
|
|
18
|
+
delegate to the active provider (resolved once at import time)
|
|
19
|
+
- Lazy init: DB/table created on first FTS5 call
|
|
20
|
+
- Fail-safe: all public functions wrapped in try/except
|
|
21
|
+
|
|
22
|
+
Environment:
|
|
23
|
+
GAIA_SEARCH_DB_PATH: Override the default SQLite DB path.
|
|
24
|
+
GAIA_TEST_NO_CHROMA: Set to any non-empty value to force FTS5 backend.
|
|
25
|
+
|
|
26
|
+
Functions:
|
|
27
|
+
index_episode -- Insert or ignore an episode into the active backend
|
|
28
|
+
search -- Query backend, returns ranked results
|
|
29
|
+
count -- Count indexed episodes
|
|
30
|
+
get_backend -- Returns "chroma" or "fts5"
|
|
31
|
+
has_engram -- Returns True if engram binary is on PATH
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
import abc
|
|
35
|
+
import os
|
|
36
|
+
import shutil
|
|
37
|
+
import sqlite3
|
|
38
|
+
from pathlib import Path
|
|
39
|
+
from typing import Dict, List, Optional
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
# ---------------------------------------------------------------------------
|
|
43
|
+
# DB path resolution (used by FTS5Provider)
|
|
44
|
+
# ---------------------------------------------------------------------------
|
|
45
|
+
|
|
46
|
+
_DEFAULT_RELATIVE_PATH = ".claude/project-context/episodic-memory/search.db"
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _resolve_db_path() -> Path:
|
|
50
|
+
"""Resolve the search DB path.
|
|
51
|
+
|
|
52
|
+
Priority:
|
|
53
|
+
1. GAIA_SEARCH_DB_PATH environment variable
|
|
54
|
+
2. Highest ancestor with a .claude/ directory (closest to HOME),
|
|
55
|
+
so that a nested .claude/ in a sub-repository or dev checkout
|
|
56
|
+
never shadows the real Gaia instance.
|
|
57
|
+
3. Bare relative path fallback (last resort, same as before).
|
|
58
|
+
"""
|
|
59
|
+
env_path = os.environ.get("GAIA_SEARCH_DB_PATH")
|
|
60
|
+
if env_path:
|
|
61
|
+
return Path(env_path)
|
|
62
|
+
|
|
63
|
+
try:
|
|
64
|
+
from memory.paths import find_highest_claude_root
|
|
65
|
+
root = find_highest_claude_root()
|
|
66
|
+
if root is not None:
|
|
67
|
+
return root / _DEFAULT_RELATIVE_PATH
|
|
68
|
+
except ImportError:
|
|
69
|
+
pass
|
|
70
|
+
|
|
71
|
+
# Fallback: original first-match walk (keeps behaviour if paths.py is
|
|
72
|
+
# somehow unavailable, e.g. during isolated unit tests that only add
|
|
73
|
+
# the tools/ root to sys.path after import).
|
|
74
|
+
current = Path.cwd()
|
|
75
|
+
for parent in [current, *current.parents]:
|
|
76
|
+
if (parent / ".claude").is_dir():
|
|
77
|
+
return parent / _DEFAULT_RELATIVE_PATH
|
|
78
|
+
|
|
79
|
+
return Path(_DEFAULT_RELATIVE_PATH)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
# ---------------------------------------------------------------------------
|
|
83
|
+
# SearchProvider ABC
|
|
84
|
+
# ---------------------------------------------------------------------------
|
|
85
|
+
|
|
86
|
+
class SearchProvider(abc.ABC):
|
|
87
|
+
"""Abstract base for search backends."""
|
|
88
|
+
|
|
89
|
+
@abc.abstractmethod
|
|
90
|
+
def index(self, episode_id: str, text: str, **kwargs) -> None:
|
|
91
|
+
"""Insert or update an episode in the index."""
|
|
92
|
+
|
|
93
|
+
@abc.abstractmethod
|
|
94
|
+
def search(self, query: str, max_results: int = 10) -> List[Dict]:
|
|
95
|
+
"""Return a ranked list of dicts with at least 'episode_id' key."""
|
|
96
|
+
|
|
97
|
+
@abc.abstractmethod
|
|
98
|
+
def count(self) -> int:
|
|
99
|
+
"""Return the total number of indexed episodes."""
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
# ---------------------------------------------------------------------------
|
|
103
|
+
# FTS5Provider
|
|
104
|
+
# ---------------------------------------------------------------------------
|
|
105
|
+
|
|
106
|
+
class FTS5Provider(SearchProvider):
|
|
107
|
+
"""SQLite FTS5 backend — always available, zero external dependencies."""
|
|
108
|
+
|
|
109
|
+
def __init__(self) -> None:
|
|
110
|
+
self._connection: Optional[sqlite3.Connection] = None
|
|
111
|
+
|
|
112
|
+
# -- internal helpers ---------------------------------------------------
|
|
113
|
+
|
|
114
|
+
def _get_connection(self) -> sqlite3.Connection:
|
|
115
|
+
if self._connection is not None:
|
|
116
|
+
return self._connection
|
|
117
|
+
|
|
118
|
+
db_path = _resolve_db_path()
|
|
119
|
+
db_path.parent.mkdir(parents=True, exist_ok=True)
|
|
120
|
+
|
|
121
|
+
conn = sqlite3.connect(str(db_path), check_same_thread=False)
|
|
122
|
+
conn.execute("PRAGMA journal_mode=WAL")
|
|
123
|
+
conn.execute(
|
|
124
|
+
"""
|
|
125
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS episodes_fts USING fts5(
|
|
126
|
+
episode_id,
|
|
127
|
+
prompt,
|
|
128
|
+
enriched_prompt,
|
|
129
|
+
tags,
|
|
130
|
+
title
|
|
131
|
+
)
|
|
132
|
+
"""
|
|
133
|
+
)
|
|
134
|
+
conn.commit()
|
|
135
|
+
self._connection = conn
|
|
136
|
+
return self._connection
|
|
137
|
+
|
|
138
|
+
@staticmethod
|
|
139
|
+
def _sanitize_query(query: str) -> str:
|
|
140
|
+
"""Append * wildcard to each word for FTS5 prefix matching.
|
|
141
|
+
|
|
142
|
+
Uses prefix matching instead of exact quoted tokens so that
|
|
143
|
+
"approval" matches "approvals", "approving", etc.
|
|
144
|
+
Special characters that would break FTS5 syntax are stripped.
|
|
145
|
+
|
|
146
|
+
Hyphens are replaced with spaces before tokenisation so that
|
|
147
|
+
queries like "brief-spec" or "context-v5" are treated as two
|
|
148
|
+
separate prefix terms ("brief*" "spec*") rather than a single
|
|
149
|
+
phrase that FTS5 cannot match (FTS5 treats hyphens as token
|
|
150
|
+
separators at index time, so the stored tokens never contain
|
|
151
|
+
hyphens).
|
|
152
|
+
"""
|
|
153
|
+
# Replace hyphens with spaces so "brief-spec" → "brief spec"
|
|
154
|
+
query = query.replace("-", " ")
|
|
155
|
+
words = query.split()
|
|
156
|
+
# Strip characters that break FTS5 syntax, then append wildcard
|
|
157
|
+
safe = [w.replace('"', '').replace("'", '').strip('*') for w in words if w]
|
|
158
|
+
return " ".join(w + "*" for w in safe if w)
|
|
159
|
+
|
|
160
|
+
# -- SearchProvider interface ------------------------------------------
|
|
161
|
+
|
|
162
|
+
def index(self, episode_id: str, text: str, **kwargs) -> None:
|
|
163
|
+
"""Insert episode into FTS5 table (no-op if already present).
|
|
164
|
+
|
|
165
|
+
Keyword arguments are mapped to FTS5 columns:
|
|
166
|
+
enriched_prompt, tags, title
|
|
167
|
+
The ``text`` positional argument maps to the ``prompt`` column.
|
|
168
|
+
"""
|
|
169
|
+
enriched_prompt = kwargs.get("enriched_prompt", "")
|
|
170
|
+
tags = kwargs.get("tags", "")
|
|
171
|
+
title = kwargs.get("title", "")
|
|
172
|
+
try:
|
|
173
|
+
conn = self._get_connection()
|
|
174
|
+
existing = conn.execute(
|
|
175
|
+
"SELECT rowid FROM episodes_fts WHERE episode_id = ?",
|
|
176
|
+
(episode_id,),
|
|
177
|
+
).fetchone()
|
|
178
|
+
if existing is not None:
|
|
179
|
+
return
|
|
180
|
+
conn.execute(
|
|
181
|
+
"INSERT INTO episodes_fts"
|
|
182
|
+
"(episode_id, prompt, enriched_prompt, tags, title) "
|
|
183
|
+
"VALUES (?, ?, ?, ?, ?)",
|
|
184
|
+
(episode_id, text, enriched_prompt, tags, title),
|
|
185
|
+
)
|
|
186
|
+
conn.commit()
|
|
187
|
+
except Exception: # noqa: BLE001
|
|
188
|
+
pass
|
|
189
|
+
|
|
190
|
+
def search(self, query: str, max_results: int = 10) -> List[Dict]:
|
|
191
|
+
if not query or not query.strip():
|
|
192
|
+
return []
|
|
193
|
+
try:
|
|
194
|
+
conn = self._get_connection()
|
|
195
|
+
sanitized = self._sanitize_query(query.strip())
|
|
196
|
+
rows = conn.execute(
|
|
197
|
+
"SELECT episode_id, rank FROM episodes_fts "
|
|
198
|
+
"WHERE episodes_fts MATCH ? "
|
|
199
|
+
"ORDER BY rank "
|
|
200
|
+
"LIMIT ?",
|
|
201
|
+
(sanitized, max_results),
|
|
202
|
+
).fetchall()
|
|
203
|
+
return [{"episode_id": row[0], "rank": row[1]} for row in rows]
|
|
204
|
+
except Exception: # noqa: BLE001
|
|
205
|
+
return []
|
|
206
|
+
|
|
207
|
+
def count(self) -> int:
|
|
208
|
+
try:
|
|
209
|
+
conn = self._get_connection()
|
|
210
|
+
row = conn.execute("SELECT COUNT(*) FROM episodes_fts").fetchone()
|
|
211
|
+
return int(row[0]) if row else 0
|
|
212
|
+
except Exception: # noqa: BLE001
|
|
213
|
+
return 0
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
# ---------------------------------------------------------------------------
|
|
217
|
+
# ChromaProvider (stub)
|
|
218
|
+
# ---------------------------------------------------------------------------
|
|
219
|
+
|
|
220
|
+
class ChromaProvider(SearchProvider):
|
|
221
|
+
"""Chroma vector-search backend.
|
|
222
|
+
|
|
223
|
+
Only instantiated when:
|
|
224
|
+
- ``chromadb`` is importable, AND
|
|
225
|
+
- ``GAIA_TEST_NO_CHROMA`` env var is NOT set
|
|
226
|
+
|
|
227
|
+
Raises ``ImportError`` in __init__ if either condition is not met so
|
|
228
|
+
that the factory can fall back to FTS5Provider transparently.
|
|
229
|
+
"""
|
|
230
|
+
|
|
231
|
+
def __init__(self) -> None:
|
|
232
|
+
if os.environ.get("GAIA_TEST_NO_CHROMA"):
|
|
233
|
+
raise ImportError("GAIA_TEST_NO_CHROMA is set — Chroma disabled")
|
|
234
|
+
import chromadb # noqa: F401 -- intentional optional import
|
|
235
|
+
# Future: initialise a persistent Chroma client and collection here.
|
|
236
|
+
# For now this is a stub; raise to signal not-yet-implemented.
|
|
237
|
+
raise NotImplementedError(
|
|
238
|
+
"ChromaProvider is a stub — not yet fully implemented"
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
def index(self, episode_id: str, text: str, **kwargs) -> None: # pragma: no cover
|
|
242
|
+
raise NotImplementedError
|
|
243
|
+
|
|
244
|
+
def search(self, query: str, max_results: int = 10) -> List[Dict]: # pragma: no cover
|
|
245
|
+
raise NotImplementedError
|
|
246
|
+
|
|
247
|
+
def count(self) -> int: # pragma: no cover
|
|
248
|
+
raise NotImplementedError
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
# ---------------------------------------------------------------------------
|
|
252
|
+
# Provider resolution (module-level singleton)
|
|
253
|
+
# ---------------------------------------------------------------------------
|
|
254
|
+
|
|
255
|
+
def _resolve_provider() -> SearchProvider:
|
|
256
|
+
"""Return the best available SearchProvider.
|
|
257
|
+
|
|
258
|
+
Tries ChromaProvider first; falls back to FTS5Provider silently on any
|
|
259
|
+
ImportError or NotImplementedError.
|
|
260
|
+
"""
|
|
261
|
+
try:
|
|
262
|
+
return ChromaProvider()
|
|
263
|
+
except (ImportError, NotImplementedError):
|
|
264
|
+
return FTS5Provider()
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
_provider: SearchProvider = _resolve_provider()
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
# ---------------------------------------------------------------------------
|
|
271
|
+
# Public API — delegates to active provider
|
|
272
|
+
# ---------------------------------------------------------------------------
|
|
273
|
+
|
|
274
|
+
def index_episode(
|
|
275
|
+
episode_id: str,
|
|
276
|
+
prompt: str,
|
|
277
|
+
enriched_prompt: str = "",
|
|
278
|
+
tags: str = "",
|
|
279
|
+
title: str = "",
|
|
280
|
+
) -> None:
|
|
281
|
+
"""Insert an episode into the active backend (no-op if already present).
|
|
282
|
+
|
|
283
|
+
Parameters
|
|
284
|
+
----------
|
|
285
|
+
episode_id:
|
|
286
|
+
Unique identifier for the episode.
|
|
287
|
+
prompt:
|
|
288
|
+
Original user prompt text.
|
|
289
|
+
enriched_prompt:
|
|
290
|
+
Expanded / enriched version of the prompt (may be empty).
|
|
291
|
+
tags:
|
|
292
|
+
Space- or comma-separated tags string (may be empty).
|
|
293
|
+
title:
|
|
294
|
+
Short title for the episode (may be empty).
|
|
295
|
+
"""
|
|
296
|
+
_provider.index(
|
|
297
|
+
episode_id,
|
|
298
|
+
prompt,
|
|
299
|
+
enriched_prompt=enriched_prompt,
|
|
300
|
+
tags=tags,
|
|
301
|
+
title=title,
|
|
302
|
+
)
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
def search(query: str, max_results: int = 10) -> List[Dict]:
|
|
306
|
+
"""Search the active backend using the configured ranking strategy.
|
|
307
|
+
|
|
308
|
+
Parameters
|
|
309
|
+
----------
|
|
310
|
+
query:
|
|
311
|
+
Free-text search query.
|
|
312
|
+
max_results:
|
|
313
|
+
Maximum number of results to return (default: 10).
|
|
314
|
+
|
|
315
|
+
Returns
|
|
316
|
+
-------
|
|
317
|
+
list of dict
|
|
318
|
+
Each dict contains at minimum ``{"episode_id": str}``. FTS5 backend
|
|
319
|
+
also includes ``{"rank": float}``. Returns empty list on error.
|
|
320
|
+
"""
|
|
321
|
+
return _provider.search(query, max_results)
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
def count() -> int:
|
|
325
|
+
"""Return the total number of episodes indexed in the active backend.
|
|
326
|
+
|
|
327
|
+
Returns
|
|
328
|
+
-------
|
|
329
|
+
int
|
|
330
|
+
Row count, or 0 on any error.
|
|
331
|
+
"""
|
|
332
|
+
return _provider.count()
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
def get_backend() -> str:
|
|
336
|
+
"""Return the active search backend identifier.
|
|
337
|
+
|
|
338
|
+
Returns
|
|
339
|
+
-------
|
|
340
|
+
str
|
|
341
|
+
``"chroma"`` if ChromaProvider is active, ``"fts5"`` otherwise.
|
|
342
|
+
"""
|
|
343
|
+
if isinstance(_provider, ChromaProvider):
|
|
344
|
+
return "chroma"
|
|
345
|
+
return "fts5"
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
def has_engram() -> bool:
|
|
349
|
+
"""Check whether the engram binary is available on PATH.
|
|
350
|
+
|
|
351
|
+
Returns
|
|
352
|
+
-------
|
|
353
|
+
bool
|
|
354
|
+
True if ``engram`` is found via shutil.which, False otherwise.
|
|
355
|
+
Never raises an exception.
|
|
356
|
+
"""
|
|
357
|
+
try:
|
|
358
|
+
return shutil.which("engram") is not None
|
|
359
|
+
except Exception: # noqa: BLE001
|
|
360
|
+
return False
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Retroactive transcript analysis: analyze .output files and persist metrics.
|
|
3
|
+
|
|
4
|
+
Reads all .output transcript files from a session's tasks directory,
|
|
5
|
+
runs analyze() and compute_compliance_score() from transcript_analyzer,
|
|
6
|
+
and appends non-empty results as JSON lines to the episodic-memory metrics file.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import json
|
|
10
|
+
import sys
|
|
11
|
+
from datetime import datetime, timezone
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
|
|
14
|
+
# Ensure the hooks package is importable
|
|
15
|
+
PLUGIN_ROOT = Path(__file__).resolve().parent.parent
|
|
16
|
+
sys.path.insert(0, str(PLUGIN_ROOT))
|
|
17
|
+
|
|
18
|
+
from hooks.modules.agents.transcript_analyzer import analyze, compute_compliance_score
|
|
19
|
+
|
|
20
|
+
SESSION_ID = "5da6ec0a-5471-4af9-b301-794748b21f62"
|
|
21
|
+
TASKS_DIR = Path(
|
|
22
|
+
f"/tmp/claude-1000/-home-jaguilar-aaxis-qxo/{SESSION_ID}/tasks"
|
|
23
|
+
)
|
|
24
|
+
METRICS_FILE = Path(
|
|
25
|
+
"/home/jaguilar/aaxis/qxo/.claude/project-context"
|
|
26
|
+
"/workflow-episodic-memory/metrics.jsonl"
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def main() -> None:
|
|
31
|
+
if not TASKS_DIR.exists():
|
|
32
|
+
print(f"Tasks directory not found: {TASKS_DIR}")
|
|
33
|
+
sys.exit(1)
|
|
34
|
+
|
|
35
|
+
output_files = sorted(TASKS_DIR.glob("*.output"))
|
|
36
|
+
if not output_files:
|
|
37
|
+
print("No .output files found.")
|
|
38
|
+
sys.exit(0)
|
|
39
|
+
|
|
40
|
+
METRICS_FILE.parent.mkdir(parents=True, exist_ok=True)
|
|
41
|
+
|
|
42
|
+
persisted = 0
|
|
43
|
+
|
|
44
|
+
with open(METRICS_FILE, "a") as f:
|
|
45
|
+
for output_path in output_files:
|
|
46
|
+
task_id = output_path.stem # filename without .output
|
|
47
|
+
|
|
48
|
+
analysis = analyze(str(output_path))
|
|
49
|
+
|
|
50
|
+
if analysis.api_call_count == 0:
|
|
51
|
+
continue
|
|
52
|
+
|
|
53
|
+
score = compute_compliance_score(analysis, True, False, 0.5)
|
|
54
|
+
|
|
55
|
+
timestamp = analysis.first_timestamp or datetime.now(
|
|
56
|
+
timezone.utc
|
|
57
|
+
).isoformat()
|
|
58
|
+
|
|
59
|
+
entry = {
|
|
60
|
+
"timestamp": timestamp,
|
|
61
|
+
"session_id": SESSION_ID,
|
|
62
|
+
"task_id": task_id,
|
|
63
|
+
"agent": "retroactive-analysis",
|
|
64
|
+
"source": "transcript_analyzer_retroactive",
|
|
65
|
+
"input_tokens": analysis.input_tokens,
|
|
66
|
+
"cache_creation_tokens": analysis.cache_creation_tokens,
|
|
67
|
+
"cache_read_tokens": analysis.cache_read_tokens,
|
|
68
|
+
"output_tokens": analysis.output_tokens,
|
|
69
|
+
"duration_ms": analysis.duration_ms,
|
|
70
|
+
"tool_call_count": analysis.tool_call_count,
|
|
71
|
+
"skills_injected": analysis.skills_injected,
|
|
72
|
+
"model_used": analysis.model,
|
|
73
|
+
"compliance_score": score.total,
|
|
74
|
+
"compliance_grade": score.grade,
|
|
75
|
+
"api_call_count": analysis.api_call_count,
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
f.write(json.dumps(entry, separators=(",", ":")) + "\n")
|
|
79
|
+
persisted += 1
|
|
80
|
+
|
|
81
|
+
print(f"Persisted {persisted} entries to {METRICS_FILE}")
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
if __name__ == "__main__":
|
|
85
|
+
main()
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Review tools for pending update management
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
"""Review engine for managing pending context update suggestions.
|
|
2
|
+
|
|
3
|
+
This module provides the review logic for pending update suggestions,
|
|
4
|
+
including listing, approving, rejecting, and viewing statistics of
|
|
5
|
+
updates discovered by agents.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import json
|
|
9
|
+
import sys
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from typing import Optional
|
|
12
|
+
|
|
13
|
+
# Import PendingUpdateStore from the context module
|
|
14
|
+
sys.path.insert(0, str(Path(__file__).parent.parent))
|
|
15
|
+
from context.pending_updates import PendingUpdateStore
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def review_pending(
|
|
19
|
+
action: str,
|
|
20
|
+
update_id: Optional[str] = None,
|
|
21
|
+
context_path: Optional[Path] = None,
|
|
22
|
+
store: Optional["PendingUpdateStore"] = None
|
|
23
|
+
) -> dict:
|
|
24
|
+
"""Execute a review action on pending updates.
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
action: One of "list", "approve", "reject", "stats"
|
|
28
|
+
update_id: Required for approve/reject actions
|
|
29
|
+
context_path: Optional path to project-context.json (for apply)
|
|
30
|
+
store: Optional PendingUpdateStore instance (for testing)
|
|
31
|
+
|
|
32
|
+
Returns:
|
|
33
|
+
dict: Action-specific results
|
|
34
|
+
|
|
35
|
+
Raises:
|
|
36
|
+
ValueError: If action is invalid or required parameters are missing
|
|
37
|
+
"""
|
|
38
|
+
valid_actions = {"list", "approve", "reject", "stats"}
|
|
39
|
+
|
|
40
|
+
if action not in valid_actions:
|
|
41
|
+
raise ValueError(
|
|
42
|
+
f"Invalid action: {action}. Must be one of: {', '.join(sorted(valid_actions))}"
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
# Validate update_id requirement for approve/reject
|
|
46
|
+
if action in {"approve", "reject"} and not update_id:
|
|
47
|
+
raise ValueError(f"update_id is required for {action} action")
|
|
48
|
+
|
|
49
|
+
# Use provided store or create default
|
|
50
|
+
if store is None:
|
|
51
|
+
store = PendingUpdateStore()
|
|
52
|
+
|
|
53
|
+
# Execute action
|
|
54
|
+
if action == "list":
|
|
55
|
+
updates = store.list_pending()
|
|
56
|
+
# Convert dataclass instances to dicts for JSON serialization
|
|
57
|
+
updates_dict = [
|
|
58
|
+
{
|
|
59
|
+
"update_id": u.update_id,
|
|
60
|
+
"category": u.category,
|
|
61
|
+
"target_section": u.target_section,
|
|
62
|
+
"summary": u.summary,
|
|
63
|
+
"confidence": u.confidence,
|
|
64
|
+
"source_agent": u.source_agent,
|
|
65
|
+
"status": u.status,
|
|
66
|
+
"created_at": u.created_at,
|
|
67
|
+
"seen_count": u.seen_count,
|
|
68
|
+
}
|
|
69
|
+
for u in updates
|
|
70
|
+
]
|
|
71
|
+
return {
|
|
72
|
+
"action": "list",
|
|
73
|
+
"updates": updates_dict,
|
|
74
|
+
"count": len(updates_dict)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
elif action == "approve":
|
|
78
|
+
# Approve the update
|
|
79
|
+
store.approve(update_id)
|
|
80
|
+
|
|
81
|
+
# Apply the update to project-context.json
|
|
82
|
+
result = store.apply(update_id, context_path)
|
|
83
|
+
|
|
84
|
+
return {
|
|
85
|
+
"action": "approve",
|
|
86
|
+
"update_id": update_id,
|
|
87
|
+
"applied": result.get("success", False),
|
|
88
|
+
"result": result
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
elif action == "reject":
|
|
92
|
+
store.reject(update_id)
|
|
93
|
+
return {
|
|
94
|
+
"action": "reject",
|
|
95
|
+
"update_id": update_id,
|
|
96
|
+
"success": True
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
elif action == "stats":
|
|
100
|
+
statistics = store.get_statistics()
|
|
101
|
+
return {
|
|
102
|
+
"action": "stats",
|
|
103
|
+
"statistics": statistics
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def main():
|
|
108
|
+
"""CLI entry point for review operations."""
|
|
109
|
+
import argparse
|
|
110
|
+
|
|
111
|
+
parser = argparse.ArgumentParser(
|
|
112
|
+
description="Review pending context updates"
|
|
113
|
+
)
|
|
114
|
+
parser.add_argument(
|
|
115
|
+
"action",
|
|
116
|
+
choices=["list", "approve", "reject", "stats"],
|
|
117
|
+
help="Action to perform"
|
|
118
|
+
)
|
|
119
|
+
parser.add_argument(
|
|
120
|
+
"--update-id",
|
|
121
|
+
help="Update ID (required for approve/reject)"
|
|
122
|
+
)
|
|
123
|
+
parser.add_argument(
|
|
124
|
+
"--context-path",
|
|
125
|
+
help="Path to project-context.json"
|
|
126
|
+
)
|
|
127
|
+
parser.add_argument(
|
|
128
|
+
"--json",
|
|
129
|
+
action="store_true",
|
|
130
|
+
help="Output as JSON (default behavior)"
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
args = parser.parse_args()
|
|
134
|
+
|
|
135
|
+
try:
|
|
136
|
+
# Execute review action
|
|
137
|
+
result = review_pending(
|
|
138
|
+
args.action,
|
|
139
|
+
args.update_id,
|
|
140
|
+
Path(args.context_path) if args.context_path else None
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
# Output result as JSON
|
|
144
|
+
print(json.dumps(result, indent=2))
|
|
145
|
+
|
|
146
|
+
except Exception as e:
|
|
147
|
+
# Output error as JSON
|
|
148
|
+
error_result = {
|
|
149
|
+
"error": str(e),
|
|
150
|
+
"action": args.action
|
|
151
|
+
}
|
|
152
|
+
print(json.dumps(error_result, indent=2))
|
|
153
|
+
sys.exit(1)
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
if __name__ == "__main__":
|
|
157
|
+
main()
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Scan Module: Modular project scanner for gaia-ops
|
|
3
|
+
|
|
4
|
+
This module provides a pluggable scanner system that detects project stack,
|
|
5
|
+
infrastructure, git configuration, tools, orchestration, and environment.
|
|
6
|
+
Each scanner is a pure function (filesystem path -> JSON sections) that runs
|
|
7
|
+
independently and in parallel. The system produces an agnostic project-context.json
|
|
8
|
+
schema that works for any project type.
|
|
9
|
+
|
|
10
|
+
Main components:
|
|
11
|
+
- BaseScanner: Abstract base class for scanner modules
|
|
12
|
+
- ScannerRegistry: Auto-discovery registry for scanner modules
|
|
13
|
+
- ScanOrchestrator: Parallel scanner execution and result aggregation
|
|
14
|
+
- ScanConfig: Scanner configuration and tool definitions
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
import json as _json
|
|
18
|
+
from pathlib import Path as _Path
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _read_version() -> str:
|
|
22
|
+
"""Read version from package.json (single source of truth)."""
|
|
23
|
+
try:
|
|
24
|
+
pkg_path = _Path(__file__).resolve().parent.parent.parent / "package.json"
|
|
25
|
+
with open(pkg_path) as f:
|
|
26
|
+
return _json.load(f)["version"]
|
|
27
|
+
except Exception:
|
|
28
|
+
return "unknown"
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
__version__ = _read_version()
|
|
32
|
+
|
|
33
|
+
__all__ = [
|
|
34
|
+
"__version__",
|
|
35
|
+
]
|