@jaguilar87/gaia 5.0.0-rc.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +33 -0
- package/.claude-plugin/plugin.json +26 -0
- package/ARCHITECTURE.md +335 -0
- package/CHANGELOG.md +1298 -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 +111 -0
- package/agents/gaia-planner.md +53 -0
- package/agents/gaia-system.md +71 -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 +651 -0
- package/bin/cli/history.py +305 -0
- package/bin/cli/memory.py +483 -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 +919 -0
- package/bin/pre-publish-validate.js +610 -0
- package/bin/python-detect.js +60 -0
- package/bin/validate-sandbox.sh +601 -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 +417 -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 +111 -0
- package/dist/gaia-ops/agents/gaia-planner.md +53 -0
- package/dist/gaia-ops/agents/gaia-system.md +71 -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 +417 -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 +192 -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 +333 -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_end_hook.py +77 -0
- package/dist/gaia-ops/hooks/session_start.py +81 -0
- package/dist/gaia-ops/hooks/stop_hook.py +70 -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 +158 -0
- package/dist/gaia-ops/skills/agent-creation/SKILL.md +87 -0
- package/dist/gaia-ops/skills/agent-creation/examples.md +170 -0
- package/dist/gaia-ops/skills/agent-creation/reference.md +191 -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 +185 -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 +85 -0
- package/dist/gaia-ops/skills/gaia-release/reference.md +92 -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/session-reflection/SKILL.md +69 -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 +375 -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 +113 -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 +333 -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_end_hook.py +77 -0
- package/dist/gaia-security/hooks/session_start.py +81 -0
- package/dist/gaia-security/hooks/stop_hook.py +70 -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 +333 -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_end_hook.py +77 -0
- package/hooks/session_start.py +81 -0
- package/hooks/stop_hook.py +70 -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 +103 -0
- package/pyproject.toml +32 -0
- package/skills/README.md +158 -0
- package/skills/agent-creation/SKILL.md +87 -0
- package/skills/agent-creation/examples.md +170 -0
- package/skills/agent-creation/reference.md +191 -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 +185 -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 +85 -0
- package/skills/gaia-release/reference.md +92 -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/session-reflection/SKILL.md +69 -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 +375 -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,333 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Session Registry — track active Claude sessions by CLAUDE_SESSION_ID.
|
|
3
|
+
|
|
4
|
+
Provides a user-scoped JSON registry at ~/.claude/session_registry.json
|
|
5
|
+
that records which sessions are currently alive. This is the base
|
|
6
|
+
infrastructure for liveness filters (T12/T13).
|
|
7
|
+
|
|
8
|
+
Storage format:
|
|
9
|
+
{
|
|
10
|
+
"sessions": {
|
|
11
|
+
"<session_id>": {
|
|
12
|
+
"pid": <int or null>,
|
|
13
|
+
"pid_create_time": <float or null>,
|
|
14
|
+
"started_at": "<ISO-8601 string or null>"
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
pid_create_time is the process creation time (from /proc/<pid>/stat
|
|
20
|
+
field 22 on Linux) used to disambiguate recycled PIDs during liveness
|
|
21
|
+
checks. When the OS reuses a PID for a different process, the create
|
|
22
|
+
time will differ and the session is treated as dead.
|
|
23
|
+
|
|
24
|
+
Concurrency:
|
|
25
|
+
All writes are atomic via os.rename() after writing to a .tmp file.
|
|
26
|
+
Reads are best-effort; a corrupt or absent file returns an empty set.
|
|
27
|
+
|
|
28
|
+
Public API:
|
|
29
|
+
register_session(session_id, pid=None, started_at=None) -> None
|
|
30
|
+
unregister_session(session_id) -> None
|
|
31
|
+
is_session_alive(session_id) -> bool
|
|
32
|
+
get_live_sessions() -> set[str]
|
|
33
|
+
get_pid_create_time(pid) -> Optional[float]
|
|
34
|
+
|
|
35
|
+
Errors:
|
|
36
|
+
SessionRegistryError — raised for expected failure modes (e.g., bad path).
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
import json
|
|
40
|
+
import logging
|
|
41
|
+
import os
|
|
42
|
+
from datetime import datetime, timezone
|
|
43
|
+
from pathlib import Path
|
|
44
|
+
from typing import Optional
|
|
45
|
+
|
|
46
|
+
logger = logging.getLogger(__name__)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
# ---------------------------------------------------------------------------
|
|
50
|
+
# Public exception
|
|
51
|
+
# ---------------------------------------------------------------------------
|
|
52
|
+
|
|
53
|
+
class SessionRegistryError(Exception):
|
|
54
|
+
"""Raised for expected failure modes in session registry operations."""
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
# ---------------------------------------------------------------------------
|
|
58
|
+
# Registry path
|
|
59
|
+
# ---------------------------------------------------------------------------
|
|
60
|
+
|
|
61
|
+
def _get_registry_path() -> Path:
|
|
62
|
+
"""Return the path to session_registry.json under ~/.claude/.
|
|
63
|
+
|
|
64
|
+
Returns:
|
|
65
|
+
Path to ~/.claude/session_registry.json
|
|
66
|
+
"""
|
|
67
|
+
return Path.home() / ".claude" / "session_registry.json"
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
# ---------------------------------------------------------------------------
|
|
71
|
+
# Low-level I/O helpers
|
|
72
|
+
# ---------------------------------------------------------------------------
|
|
73
|
+
|
|
74
|
+
def _load_registry() -> dict:
|
|
75
|
+
"""Load the registry from disk.
|
|
76
|
+
|
|
77
|
+
Returns:
|
|
78
|
+
Registry dict with a "sessions" key. Returns {"sessions": {}} when
|
|
79
|
+
the file is absent or corrupt (logs a warning on corrupt).
|
|
80
|
+
"""
|
|
81
|
+
path = _get_registry_path()
|
|
82
|
+
if not path.exists():
|
|
83
|
+
return {"sessions": {}}
|
|
84
|
+
try:
|
|
85
|
+
text = path.read_text(encoding="utf-8")
|
|
86
|
+
data = json.loads(text)
|
|
87
|
+
if not isinstance(data, dict) or "sessions" not in data:
|
|
88
|
+
raise ValueError("Missing 'sessions' key")
|
|
89
|
+
if not isinstance(data["sessions"], dict):
|
|
90
|
+
raise ValueError("'sessions' must be a dict")
|
|
91
|
+
return data
|
|
92
|
+
except Exception as exc:
|
|
93
|
+
logger.warning(
|
|
94
|
+
"session_registry: corrupt registry at %s (%s) — resetting to empty",
|
|
95
|
+
path,
|
|
96
|
+
exc,
|
|
97
|
+
)
|
|
98
|
+
return {"sessions": {}}
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def _save_registry(data: dict) -> None:
|
|
102
|
+
"""Save the registry atomically using os.rename.
|
|
103
|
+
|
|
104
|
+
Writes to a sibling .tmp file first, then renames to the target path
|
|
105
|
+
so readers never see a partial write.
|
|
106
|
+
|
|
107
|
+
Args:
|
|
108
|
+
data: Registry dict to persist.
|
|
109
|
+
|
|
110
|
+
Raises:
|
|
111
|
+
SessionRegistryError: If the directory cannot be created or the
|
|
112
|
+
write/rename fails.
|
|
113
|
+
"""
|
|
114
|
+
path = _get_registry_path()
|
|
115
|
+
try:
|
|
116
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
117
|
+
except OSError as exc:
|
|
118
|
+
raise SessionRegistryError(
|
|
119
|
+
f"session_registry: cannot create directory {path.parent}: {exc}"
|
|
120
|
+
) from exc
|
|
121
|
+
|
|
122
|
+
# Use a unique tmp suffix per call so concurrent writers don't stomp
|
|
123
|
+
# on each other's tmp file before rename. os.rename is atomic on POSIX.
|
|
124
|
+
tmp_path = path.with_suffix(f".tmp.{os.getpid()}.{os.urandom(4).hex()}")
|
|
125
|
+
try:
|
|
126
|
+
tmp_path.write_text(json.dumps(data, indent=2), encoding="utf-8")
|
|
127
|
+
os.rename(str(tmp_path), str(path))
|
|
128
|
+
except OSError as exc:
|
|
129
|
+
# Best-effort cleanup of the per-call tmp file
|
|
130
|
+
try:
|
|
131
|
+
if tmp_path.exists():
|
|
132
|
+
tmp_path.unlink()
|
|
133
|
+
except OSError:
|
|
134
|
+
pass
|
|
135
|
+
raise SessionRegistryError(
|
|
136
|
+
f"session_registry: write failed for {path}: {exc}"
|
|
137
|
+
) from exc
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
# ---------------------------------------------------------------------------
|
|
141
|
+
# PID liveness helpers
|
|
142
|
+
# ---------------------------------------------------------------------------
|
|
143
|
+
|
|
144
|
+
def get_pid_create_time(pid: int) -> Optional[float]:
|
|
145
|
+
"""Return the creation time of a process, or None if unavailable.
|
|
146
|
+
|
|
147
|
+
Reads /proc/<pid>/stat field 22 (starttime) on Linux. The value is in
|
|
148
|
+
clock ticks since boot; the raw number is sufficient for equality
|
|
149
|
+
comparison to detect PID recycling (we do not need wall-clock time).
|
|
150
|
+
|
|
151
|
+
Args:
|
|
152
|
+
pid: OS process ID to inspect. Non-positive values return None.
|
|
153
|
+
|
|
154
|
+
Returns:
|
|
155
|
+
Starttime as a float, or None when the process does not exist,
|
|
156
|
+
/proc is not available, or parsing fails.
|
|
157
|
+
"""
|
|
158
|
+
if not pid or pid <= 0:
|
|
159
|
+
return None
|
|
160
|
+
try:
|
|
161
|
+
stat_path = Path("/proc") / str(pid) / "stat"
|
|
162
|
+
text = stat_path.read_text(encoding="utf-8")
|
|
163
|
+
except (OSError, ValueError):
|
|
164
|
+
return None
|
|
165
|
+
# The comm field (field 2) may contain spaces and parentheses; parse
|
|
166
|
+
# from the last ')' to avoid splitting on them.
|
|
167
|
+
try:
|
|
168
|
+
rparen = text.rindex(")")
|
|
169
|
+
except ValueError:
|
|
170
|
+
return None
|
|
171
|
+
rest = text[rparen + 1 :].split()
|
|
172
|
+
# After the closing paren the remaining fields are 3..N, so starttime
|
|
173
|
+
# (field 22) is at index 22 - 3 = 19.
|
|
174
|
+
if len(rest) < 20:
|
|
175
|
+
return None
|
|
176
|
+
try:
|
|
177
|
+
return float(rest[19])
|
|
178
|
+
except ValueError:
|
|
179
|
+
return None
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def _is_pid_alive(pid: Optional[int], pid_create_time: Optional[float]) -> bool:
|
|
183
|
+
"""Return True when pid names a live process with a matching create time.
|
|
184
|
+
|
|
185
|
+
When pid is None we cannot verify liveness and fall back to True
|
|
186
|
+
(presence-only behaviour — sessions registered without a pid remain
|
|
187
|
+
live). When pid_create_time is provided we require it to match the
|
|
188
|
+
current process create time; a mismatch indicates PID recycling and
|
|
189
|
+
we treat the session as dead.
|
|
190
|
+
|
|
191
|
+
Args:
|
|
192
|
+
pid: Recorded process ID, may be None.
|
|
193
|
+
pid_create_time: Recorded create time for the pid, may be None.
|
|
194
|
+
|
|
195
|
+
Returns:
|
|
196
|
+
True if the session should be considered alive.
|
|
197
|
+
"""
|
|
198
|
+
if pid is None:
|
|
199
|
+
return True
|
|
200
|
+
current = get_pid_create_time(pid)
|
|
201
|
+
if current is None:
|
|
202
|
+
return False
|
|
203
|
+
if pid_create_time is None:
|
|
204
|
+
# Legacy entry without create time — trust the pid lookup.
|
|
205
|
+
return True
|
|
206
|
+
return current == pid_create_time
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
# ---------------------------------------------------------------------------
|
|
210
|
+
# Public API
|
|
211
|
+
# ---------------------------------------------------------------------------
|
|
212
|
+
|
|
213
|
+
def register_session(
|
|
214
|
+
session_id: str,
|
|
215
|
+
pid: Optional[int] = None,
|
|
216
|
+
started_at: Optional[str] = None,
|
|
217
|
+
) -> None:
|
|
218
|
+
"""Register a session as active in the user-scoped registry.
|
|
219
|
+
|
|
220
|
+
Creates or updates the entry for session_id. If started_at is not
|
|
221
|
+
provided, the current UTC time in ISO-8601 format is used. When pid
|
|
222
|
+
is provided the process create time is captured alongside so that
|
|
223
|
+
later liveness checks can detect PID recycling.
|
|
224
|
+
|
|
225
|
+
Args:
|
|
226
|
+
session_id: The CLAUDE_SESSION_ID for the session to register.
|
|
227
|
+
Must be a non-empty string.
|
|
228
|
+
pid: OS process ID of the hook process (optional but recommended
|
|
229
|
+
for liveness checks in T12/T13).
|
|
230
|
+
started_at: ISO-8601 timestamp string for when the session started.
|
|
231
|
+
Defaults to datetime.now(timezone.utc).isoformat() if absent.
|
|
232
|
+
|
|
233
|
+
Raises:
|
|
234
|
+
SessionRegistryError: If session_id is empty or saving fails.
|
|
235
|
+
"""
|
|
236
|
+
if not session_id:
|
|
237
|
+
raise SessionRegistryError("register_session: session_id must be non-empty")
|
|
238
|
+
|
|
239
|
+
if started_at is None:
|
|
240
|
+
started_at = datetime.now(timezone.utc).isoformat()
|
|
241
|
+
|
|
242
|
+
pid_create_time: Optional[float] = None
|
|
243
|
+
if pid is not None:
|
|
244
|
+
pid_create_time = get_pid_create_time(pid)
|
|
245
|
+
|
|
246
|
+
data = _load_registry()
|
|
247
|
+
data["sessions"][session_id] = {
|
|
248
|
+
"pid": pid,
|
|
249
|
+
"pid_create_time": pid_create_time,
|
|
250
|
+
"started_at": started_at,
|
|
251
|
+
}
|
|
252
|
+
_save_registry(data)
|
|
253
|
+
logger.debug(
|
|
254
|
+
"session_registry: registered session=%s pid=%s create_time=%s",
|
|
255
|
+
session_id,
|
|
256
|
+
pid,
|
|
257
|
+
pid_create_time,
|
|
258
|
+
)
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
def unregister_session(session_id: str) -> None:
|
|
262
|
+
"""Remove a session from the registry when it stops.
|
|
263
|
+
|
|
264
|
+
Silently ignores the case where session_id is not found — this is
|
|
265
|
+
normal during shutdown (hook may fire more than once or the entry
|
|
266
|
+
may already have been cleaned up).
|
|
267
|
+
|
|
268
|
+
Args:
|
|
269
|
+
session_id: The CLAUDE_SESSION_ID to remove. Empty string is a
|
|
270
|
+
no-op with a warning log.
|
|
271
|
+
|
|
272
|
+
Raises:
|
|
273
|
+
SessionRegistryError: If saving the updated registry fails.
|
|
274
|
+
"""
|
|
275
|
+
if not session_id:
|
|
276
|
+
logger.warning("unregister_session: called with empty session_id — no-op")
|
|
277
|
+
return
|
|
278
|
+
|
|
279
|
+
data = _load_registry()
|
|
280
|
+
if session_id not in data["sessions"]:
|
|
281
|
+
logger.debug(
|
|
282
|
+
"session_registry: unregister called for unknown session=%s (no-op)",
|
|
283
|
+
session_id,
|
|
284
|
+
)
|
|
285
|
+
return
|
|
286
|
+
|
|
287
|
+
del data["sessions"][session_id]
|
|
288
|
+
_save_registry(data)
|
|
289
|
+
logger.debug("session_registry: unregistered session=%s", session_id)
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
def is_session_alive(session_id: str) -> bool:
|
|
293
|
+
"""Return True if session_id is present in the registry.
|
|
294
|
+
|
|
295
|
+
This is a presence check only — it does not verify that the recorded
|
|
296
|
+
PID is actually running. Full liveness probing (kill -0) is implemented
|
|
297
|
+
in T12/T13.
|
|
298
|
+
|
|
299
|
+
Args:
|
|
300
|
+
session_id: The CLAUDE_SESSION_ID to check. Empty string always
|
|
301
|
+
returns False.
|
|
302
|
+
|
|
303
|
+
Returns:
|
|
304
|
+
True if the session is in the registry, False otherwise.
|
|
305
|
+
"""
|
|
306
|
+
if not session_id:
|
|
307
|
+
return False
|
|
308
|
+
data = _load_registry()
|
|
309
|
+
return session_id in data["sessions"]
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
def get_live_sessions() -> set:
|
|
313
|
+
"""Return the set of session IDs whose recorded pid is still alive.
|
|
314
|
+
|
|
315
|
+
Entries registered without a pid are kept (presence-only liveness).
|
|
316
|
+
Entries with a pid are filtered via _is_pid_alive so that PID
|
|
317
|
+
recycling — OS reusing a PID for a different process — is detected
|
|
318
|
+
by comparing the recorded create time with the current one.
|
|
319
|
+
|
|
320
|
+
Returns:
|
|
321
|
+
set[str] of session IDs considered live. Empty set when the
|
|
322
|
+
registry is absent or corrupt (after logging a warning).
|
|
323
|
+
"""
|
|
324
|
+
data = _load_registry()
|
|
325
|
+
live: set = set()
|
|
326
|
+
for session_id, entry in data["sessions"].items():
|
|
327
|
+
if not isinstance(entry, dict):
|
|
328
|
+
continue
|
|
329
|
+
pid = entry.get("pid")
|
|
330
|
+
pid_create_time = entry.get("pid_create_time")
|
|
331
|
+
if _is_pid_alive(pid, pid_create_time):
|
|
332
|
+
live.add(session_id)
|
|
333
|
+
return live
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Tools module - Tool-specific validators.
|
|
3
|
+
|
|
4
|
+
Provides:
|
|
5
|
+
- bash_validator: Bash command validation
|
|
6
|
+
- task_validator: Task tool validation with context enforcement
|
|
7
|
+
- shell_parser: Shell command parsing (pipes, chains, etc.)
|
|
8
|
+
- stage_decomposer: Operator-preserving command decomposition
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from .shell_parser import ShellCommandParser, get_shell_parser, parse_command
|
|
12
|
+
from .bash_validator import BashValidator, validate_bash_command
|
|
13
|
+
from .task_validator import TaskValidator, validate_task_invocation
|
|
14
|
+
from .stage_decomposer import StageDecomposer
|
|
15
|
+
|
|
16
|
+
__all__ = [
|
|
17
|
+
# Shell parser
|
|
18
|
+
"ShellCommandParser",
|
|
19
|
+
"get_shell_parser",
|
|
20
|
+
"parse_command",
|
|
21
|
+
# Bash validator
|
|
22
|
+
"BashValidator",
|
|
23
|
+
"validate_bash_command",
|
|
24
|
+
# Task validator
|
|
25
|
+
"TaskValidator",
|
|
26
|
+
"validate_task_invocation",
|
|
27
|
+
# Stage decomposer
|
|
28
|
+
"StageDecomposer",
|
|
29
|
+
]
|