moai-adk 0.15.1__py3-none-any.whl โ 0.32.8__py3-none-any.whl
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.
Potentially problematic release.
This version of moai-adk might be problematic. Click here for more details.
- moai_adk/__init__.py +2 -6
- moai_adk/__main__.py +136 -21
- moai_adk/cli/__init__.py +6 -2
- moai_adk/cli/commands/__init__.py +1 -4
- moai_adk/cli/commands/analyze.py +116 -0
- moai_adk/cli/commands/doctor.py +17 -5
- moai_adk/cli/commands/init.py +105 -47
- moai_adk/cli/commands/language.py +248 -0
- moai_adk/cli/commands/status.py +8 -13
- moai_adk/cli/commands/update.py +1734 -65
- moai_adk/cli/main.py +3 -2
- moai_adk/cli/prompts/init_prompts.py +144 -91
- moai_adk/cli/spec_status.py +263 -0
- moai_adk/cli/ui/__init__.py +44 -0
- moai_adk/cli/ui/progress.py +422 -0
- moai_adk/cli/ui/prompts.py +389 -0
- moai_adk/cli/ui/theme.py +129 -0
- moai_adk/cli/worktree/__init__.py +27 -0
- moai_adk/cli/worktree/__main__.py +31 -0
- moai_adk/cli/worktree/cli.py +672 -0
- moai_adk/cli/worktree/exceptions.py +89 -0
- moai_adk/cli/worktree/manager.py +490 -0
- moai_adk/cli/worktree/models.py +65 -0
- moai_adk/cli/worktree/registry.py +128 -0
- moai_adk/core/PHASE2_OPTIMIZATIONS.md +467 -0
- moai_adk/core/__init__.py +0 -1
- moai_adk/core/analysis/__init__.py +9 -0
- moai_adk/core/analysis/session_analyzer.py +400 -0
- moai_adk/core/claude_integration.py +393 -0
- moai_adk/core/command_helpers.py +270 -0
- moai_adk/core/comprehensive_monitoring_system.py +1183 -0
- moai_adk/core/config/__init__.py +6 -0
- moai_adk/core/config/auto_spec_config.py +340 -0
- moai_adk/core/config/migration.py +147 -16
- moai_adk/core/config/unified.py +436 -0
- moai_adk/core/context_manager.py +273 -0
- moai_adk/core/diagnostics/slash_commands.py +0 -1
- moai_adk/core/enterprise_features.py +1404 -0
- moai_adk/core/error_recovery_system.py +1902 -0
- moai_adk/core/event_driven_hook_system.py +1371 -0
- moai_adk/core/git/__init__.py +8 -1
- moai_adk/core/git/branch.py +0 -1
- moai_adk/core/git/branch_manager.py +2 -10
- moai_adk/core/git/checkpoint.py +1 -7
- moai_adk/core/git/commit.py +0 -1
- moai_adk/core/git/conflict_detector.py +413 -0
- moai_adk/core/git/event_detector.py +3 -5
- moai_adk/core/git/manager.py +91 -2
- moai_adk/core/hooks/post_tool_auto_spec_completion.py +901 -0
- moai_adk/core/input_validation_middleware.py +1006 -0
- moai_adk/core/integration/__init__.py +22 -0
- moai_adk/core/integration/engine.py +157 -0
- moai_adk/core/integration/integration_tester.py +226 -0
- moai_adk/core/integration/models.py +88 -0
- moai_adk/core/integration/utils.py +211 -0
- moai_adk/core/issue_creator.py +20 -28
- moai_adk/core/jit_context_loader.py +956 -0
- moai_adk/core/jit_enhanced_hook_manager.py +1987 -0
- moai_adk/core/language_config.py +202 -0
- moai_adk/core/language_config_resolver.py +485 -0
- moai_adk/core/language_validator.py +543 -0
- moai_adk/core/mcp/setup.py +116 -0
- moai_adk/core/merge/__init__.py +9 -0
- moai_adk/core/merge/analyzer.py +481 -0
- moai_adk/core/migration/__init__.py +18 -0
- moai_adk/core/migration/alfred_to_moai_migrator.py +383 -0
- moai_adk/core/migration/backup_manager.py +277 -0
- moai_adk/core/migration/custom_element_scanner.py +358 -0
- moai_adk/core/migration/file_migrator.py +209 -0
- moai_adk/core/migration/interactive_checkbox_ui.py +488 -0
- moai_adk/core/migration/selective_restorer.py +470 -0
- moai_adk/core/migration/template_utils.py +74 -0
- moai_adk/core/migration/user_selection_ui.py +338 -0
- moai_adk/core/migration/version_detector.py +139 -0
- moai_adk/core/migration/version_migrator.py +228 -0
- moai_adk/core/performance/__init__.py +6 -0
- moai_adk/core/performance/cache_system.py +316 -0
- moai_adk/core/performance/parallel_processor.py +116 -0
- moai_adk/core/phase_optimized_hook_scheduler.py +879 -0
- moai_adk/core/project/__init__.py +0 -1
- moai_adk/core/project/backup_utils.py +2 -7
- moai_adk/core/project/checker.py +2 -4
- moai_adk/core/project/detector.py +17 -39
- moai_adk/core/project/initializer.py +170 -33
- moai_adk/core/project/phase_executor.py +398 -68
- moai_adk/core/project/validator.py +7 -32
- moai_adk/core/quality/__init__.py +1 -1
- moai_adk/core/quality/trust_checker.py +37 -101
- moai_adk/core/quality/validators/__init__.py +1 -1
- moai_adk/core/quality/validators/base_validator.py +1 -1
- moai_adk/core/realtime_monitoring_dashboard.py +1724 -0
- moai_adk/core/robust_json_parser.py +611 -0
- moai_adk/core/rollback_manager.py +918 -0
- moai_adk/core/session_manager.py +651 -0
- moai_adk/core/skill_loading_system.py +579 -0
- moai_adk/core/spec/confidence_scoring.py +680 -0
- moai_adk/core/spec/ears_template_engine.py +1247 -0
- moai_adk/core/spec/quality_validator.py +687 -0
- moai_adk/core/spec_status_manager.py +478 -0
- moai_adk/core/template/__init__.py +0 -1
- moai_adk/core/template/backup.py +82 -17
- moai_adk/core/template/config.py +112 -40
- moai_adk/core/template/languages.py +0 -1
- moai_adk/core/template/merger.py +75 -26
- moai_adk/core/template/processor.py +750 -72
- moai_adk/core/template_engine.py +90 -48
- moai_adk/core/template_variable_synchronizer.py +417 -0
- moai_adk/core/unified_permission_manager.py +745 -0
- moai_adk/core/user_behavior_analytics.py +851 -0
- moai_adk/core/version_sync.py +429 -0
- moai_adk/foundation/__init__.py +56 -0
- moai_adk/foundation/backend.py +1027 -0
- moai_adk/foundation/database.py +1115 -0
- moai_adk/foundation/devops.py +1585 -0
- moai_adk/foundation/ears.py +431 -0
- moai_adk/foundation/frontend.py +870 -0
- moai_adk/foundation/git/commit_templates.py +557 -0
- moai_adk/foundation/git.py +376 -0
- moai_adk/foundation/langs.py +484 -0
- moai_adk/foundation/ml_ops.py +1162 -0
- moai_adk/foundation/testing.py +1524 -0
- moai_adk/foundation/trust/trust_principles.py +676 -0
- moai_adk/foundation/trust/validation_checklist.py +1573 -0
- moai_adk/project/__init__.py +0 -0
- moai_adk/project/configuration.py +1084 -0
- moai_adk/project/documentation.py +566 -0
- moai_adk/project/schema.py +447 -0
- moai_adk/statusline/__init__.py +38 -0
- moai_adk/statusline/alfred_detector.py +105 -0
- moai_adk/statusline/config.py +373 -0
- moai_adk/statusline/enhanced_output_style_detector.py +372 -0
- moai_adk/statusline/git_collector.py +190 -0
- moai_adk/statusline/main.py +264 -0
- moai_adk/statusline/metrics_tracker.py +78 -0
- moai_adk/statusline/renderer.py +383 -0
- moai_adk/statusline/update_checker.py +129 -0
- moai_adk/statusline/version_reader.py +741 -0
- moai_adk/templates/.claude/agents/moai/ai-nano-banana.md +549 -0
- moai_adk/templates/.claude/agents/moai/builder-agent.md +445 -0
- moai_adk/templates/.claude/agents/moai/builder-command.md +1132 -0
- moai_adk/templates/.claude/agents/moai/builder-skill.md +601 -0
- moai_adk/templates/.claude/agents/moai/expert-backend.md +831 -0
- moai_adk/templates/.claude/agents/moai/expert-database.md +774 -0
- moai_adk/templates/.claude/agents/moai/expert-debug.md +396 -0
- moai_adk/templates/.claude/agents/moai/expert-devops.md +711 -0
- moai_adk/templates/.claude/agents/moai/expert-frontend.md +666 -0
- moai_adk/templates/.claude/agents/moai/expert-security.md +474 -0
- moai_adk/templates/.claude/agents/moai/expert-uiux.md +1038 -0
- moai_adk/templates/.claude/agents/moai/manager-claude-code.md +429 -0
- moai_adk/templates/.claude/agents/moai/manager-docs.md +570 -0
- moai_adk/templates/.claude/agents/moai/manager-git.md +937 -0
- moai_adk/templates/.claude/agents/moai/manager-project.md +891 -0
- moai_adk/templates/.claude/agents/moai/manager-quality.md +598 -0
- moai_adk/templates/.claude/agents/moai/manager-spec.md +713 -0
- moai_adk/templates/.claude/agents/moai/manager-strategy.md +600 -0
- moai_adk/templates/.claude/agents/moai/manager-tdd.md +603 -0
- moai_adk/templates/.claude/agents/moai/mcp-context7.md +369 -0
- moai_adk/templates/.claude/agents/moai/mcp-figma.md +1567 -0
- moai_adk/templates/.claude/agents/moai/mcp-notion.md +749 -0
- moai_adk/templates/.claude/agents/moai/mcp-playwright.md +427 -0
- moai_adk/templates/.claude/agents/moai/mcp-sequential-thinking.md +994 -0
- moai_adk/templates/.claude/commands/moai/0-project.md +1143 -0
- moai_adk/templates/.claude/commands/moai/1-plan.md +1435 -0
- moai_adk/templates/.claude/commands/moai/2-run.md +883 -0
- moai_adk/templates/.claude/commands/moai/3-sync.md +993 -0
- moai_adk/templates/.claude/commands/moai/9-feedback.md +314 -0
- moai_adk/templates/.claude/hooks/__init__.py +8 -0
- moai_adk/templates/.claude/hooks/moai/__init__.py +8 -0
- moai_adk/templates/.claude/hooks/moai/lib/__init__.py +85 -0
- moai_adk/templates/.claude/hooks/{alfred/shared/core โ moai/lib}/checkpoint.py +9 -36
- moai_adk/templates/.claude/hooks/moai/lib/common.py +131 -0
- moai_adk/templates/.claude/hooks/moai/lib/config_manager.py +446 -0
- moai_adk/templates/.claude/hooks/moai/lib/config_validator.py +639 -0
- moai_adk/templates/.claude/hooks/moai/lib/example_config.json +104 -0
- moai_adk/templates/.claude/hooks/moai/lib/git_operations_manager.py +590 -0
- moai_adk/templates/.claude/hooks/moai/lib/language_validator.py +317 -0
- moai_adk/templates/.claude/hooks/moai/lib/models.py +102 -0
- moai_adk/templates/.claude/hooks/moai/lib/path_utils.py +28 -0
- moai_adk/templates/.claude/hooks/{alfred/shared/core โ moai/lib}/project.py +63 -44
- moai_adk/templates/.claude/hooks/moai/lib/test_hooks_improvements.py +443 -0
- moai_adk/templates/.claude/hooks/{alfred/core โ moai/lib}/timeout.py +40 -16
- moai_adk/templates/.claude/hooks/moai/lib/unified_timeout_manager.py +530 -0
- moai_adk/templates/.claude/hooks/moai/session_end__auto_cleanup.py +862 -0
- moai_adk/templates/.claude/hooks/moai/session_start__show_project_info.py +921 -0
- moai_adk/templates/.claude/output-styles/moai/r2d2.md +380 -0
- moai_adk/templates/.claude/output-styles/moai/yoda.md +338 -0
- moai_adk/templates/.claude/settings.json +78 -50
- moai_adk/templates/.claude/skills/moai-docs-generation/SKILL.md +247 -0
- moai_adk/templates/.claude/skills/moai-docs-generation/modules/README.md +44 -0
- moai_adk/templates/.claude/skills/moai-docs-generation/modules/api-documentation.md +130 -0
- moai_adk/templates/.claude/skills/moai-docs-generation/modules/code-documentation.md +152 -0
- moai_adk/templates/.claude/skills/moai-docs-generation/modules/multi-format-output.md +178 -0
- moai_adk/templates/.claude/skills/moai-docs-generation/modules/user-guides.md +147 -0
- moai_adk/templates/.claude/skills/moai-domain-backend/SKILL.md +312 -283
- moai_adk/templates/.claude/skills/moai-domain-database/SKILL.md +291 -94
- moai_adk/templates/.claude/skills/moai-domain-database/modules/README.md +53 -0
- moai_adk/templates/.claude/skills/moai-domain-database/modules/mongodb.md +231 -0
- moai_adk/templates/.claude/skills/moai-domain-database/modules/postgresql.md +169 -0
- moai_adk/templates/.claude/skills/moai-domain-database/modules/redis.md +262 -0
- moai_adk/templates/.claude/skills/moai-domain-frontend/SKILL.md +469 -101
- moai_adk/templates/.claude/skills/moai-domain-uiux/SKILL.md +453 -0
- moai_adk/templates/.claude/skills/moai-domain-uiux/examples.md +560 -0
- moai_adk/templates/.claude/skills/moai-domain-uiux/modules/accessibility-wcag.md +260 -0
- moai_adk/templates/.claude/skills/moai-domain-uiux/modules/component-architecture.md +228 -0
- moai_adk/templates/.claude/skills/moai-domain-uiux/modules/design-system-tokens.md +405 -0
- moai_adk/templates/.claude/skills/moai-domain-uiux/modules/icon-libraries.md +401 -0
- moai_adk/templates/.claude/skills/moai-domain-uiux/modules/theming-system.md +373 -0
- moai_adk/templates/.claude/skills/moai-domain-uiux/reference.md +243 -0
- moai_adk/templates/.claude/skills/moai-formats-data/SKILL.md +491 -0
- moai_adk/templates/.claude/skills/moai-formats-data/modules/README.md +98 -0
- moai_adk/templates/.claude/skills/moai-formats-data/modules/SKILL-MODULARIZATION-TEMPLATE.md +278 -0
- moai_adk/templates/.claude/skills/moai-formats-data/modules/caching-performance.md +459 -0
- moai_adk/templates/.claude/skills/moai-formats-data/modules/data-validation.md +485 -0
- moai_adk/templates/.claude/skills/moai-formats-data/modules/json-optimization.md +374 -0
- moai_adk/templates/.claude/skills/moai-formats-data/modules/toon-encoding.md +308 -0
- moai_adk/templates/.claude/skills/moai-foundation-claude/SKILL.md +201 -0
- moai_adk/templates/.claude/skills/moai-foundation-claude/reference/best-practices-checklist.md +616 -0
- moai_adk/templates/.claude/skills/moai-foundation-claude/reference/claude-code-custom-slash-commands-official.md +729 -0
- moai_adk/templates/.claude/skills/moai-foundation-claude/reference/claude-code-hooks-official.md +560 -0
- moai_adk/templates/.claude/skills/moai-foundation-claude/reference/claude-code-iam-official.md +635 -0
- moai_adk/templates/.claude/skills/moai-foundation-claude/reference/claude-code-memory-official.md +543 -0
- moai_adk/templates/.claude/skills/moai-foundation-claude/reference/claude-code-settings-official.md +663 -0
- moai_adk/templates/.claude/skills/moai-foundation-claude/reference/claude-code-skills-official.md +113 -0
- moai_adk/templates/.claude/skills/moai-foundation-claude/reference/claude-code-sub-agents-official.md +238 -0
- moai_adk/templates/.claude/skills/moai-foundation-claude/reference/complete-configuration-guide.md +175 -0
- moai_adk/templates/.claude/skills/moai-foundation-claude/reference/skill-examples.md +1674 -0
- moai_adk/templates/.claude/skills/moai-foundation-claude/reference/skill-formatting-guide.md +729 -0
- moai_adk/templates/.claude/skills/moai-foundation-claude/reference/sub-agents/sub-agent-examples.md +1513 -0
- moai_adk/templates/.claude/skills/moai-foundation-claude/reference/sub-agents/sub-agent-formatting-guide.md +1086 -0
- moai_adk/templates/.claude/skills/moai-foundation-claude/reference/sub-agents/sub-agent-integration-patterns.md +1100 -0
- moai_adk/templates/.claude/skills/moai-foundation-context/SKILL.md +438 -0
- moai_adk/templates/.claude/skills/moai-foundation-core/SKILL.md +515 -0
- moai_adk/templates/.claude/skills/moai-foundation-core/modules/README.md +296 -0
- moai_adk/templates/.claude/skills/moai-foundation-core/modules/agents-reference.md +346 -0
- moai_adk/templates/.claude/skills/moai-foundation-core/modules/commands-reference.md +432 -0
- moai_adk/templates/.claude/skills/moai-foundation-core/modules/delegation-patterns.md +757 -0
- moai_adk/templates/.claude/skills/moai-foundation-core/modules/execution-rules.md +687 -0
- moai_adk/templates/.claude/skills/moai-foundation-core/modules/modular-system.md +665 -0
- moai_adk/templates/.claude/skills/moai-foundation-core/modules/progressive-disclosure.md +649 -0
- moai_adk/templates/.claude/skills/moai-foundation-core/modules/spec-first-tdd.md +864 -0
- moai_adk/templates/.claude/skills/moai-foundation-core/modules/token-optimization.md +708 -0
- moai_adk/templates/.claude/skills/moai-foundation-core/modules/trust-5-framework.md +981 -0
- moai_adk/templates/.claude/skills/moai-foundation-quality/SKILL.md +362 -0
- moai_adk/templates/.claude/skills/moai-foundation-quality/examples.md +1232 -0
- moai_adk/templates/.claude/skills/moai-foundation-quality/modules/best-practices.md +261 -0
- moai_adk/templates/.claude/skills/moai-foundation-quality/modules/integration-patterns.md +194 -0
- moai_adk/templates/.claude/skills/moai-foundation-quality/modules/proactive-analysis.md +229 -0
- moai_adk/templates/.claude/skills/moai-foundation-quality/modules/trust5-validation.md +169 -0
- moai_adk/templates/.claude/skills/moai-foundation-quality/reference.md +1266 -0
- moai_adk/templates/.claude/skills/moai-foundation-quality/scripts/quality-gate.sh +668 -0
- moai_adk/templates/.claude/skills/moai-foundation-quality/templates/github-actions-quality.yml +481 -0
- moai_adk/templates/.claude/skills/moai-foundation-quality/templates/quality-config.yaml +519 -0
- moai_adk/templates/.claude/skills/moai-integration-mcp/SKILL.md +352 -0
- moai_adk/templates/.claude/skills/moai-integration-mcp/modules/README.md +52 -0
- moai_adk/templates/.claude/skills/moai-integration-mcp/modules/error-handling.md +334 -0
- moai_adk/templates/.claude/skills/moai-integration-mcp/modules/integration-patterns.md +310 -0
- moai_adk/templates/.claude/skills/moai-integration-mcp/modules/security-authentication.md +256 -0
- moai_adk/templates/.claude/skills/moai-integration-mcp/modules/server-architecture.md +253 -0
- moai_adk/templates/.claude/skills/moai-lang-unified/README.md +133 -0
- moai_adk/templates/.claude/skills/moai-lang-unified/SKILL.md +296 -0
- moai_adk/templates/.claude/skills/moai-lang-unified/examples.md +1269 -0
- moai_adk/templates/.claude/skills/moai-lang-unified/reference.md +331 -0
- moai_adk/templates/.claude/skills/moai-library-mermaid/SKILL.md +298 -0
- moai_adk/templates/.claude/skills/moai-library-mermaid/advanced-patterns.md +465 -0
- moai_adk/templates/.claude/skills/moai-library-mermaid/examples.md +270 -0
- moai_adk/templates/.claude/skills/moai-library-mermaid/optimization.md +440 -0
- moai_adk/templates/.claude/skills/moai-library-mermaid/reference.md +228 -0
- moai_adk/templates/.claude/skills/moai-library-nextra/SKILL.md +316 -0
- moai_adk/templates/.claude/skills/moai-library-nextra/advanced-patterns.md +336 -0
- moai_adk/templates/.claude/skills/moai-library-nextra/modules/advanced-deployment-patterns.md +182 -0
- moai_adk/templates/.claude/skills/moai-library-nextra/modules/advanced-patterns.md +17 -0
- moai_adk/templates/.claude/skills/moai-library-nextra/modules/configuration.md +57 -0
- moai_adk/templates/.claude/skills/moai-library-nextra/modules/content-architecture-optimization.md +162 -0
- moai_adk/templates/.claude/skills/moai-library-nextra/modules/deployment.md +52 -0
- moai_adk/templates/.claude/skills/moai-library-nextra/modules/framework-core-configuration.md +186 -0
- moai_adk/templates/.claude/skills/moai-library-nextra/modules/i18n-setup.md +55 -0
- moai_adk/templates/.claude/skills/moai-library-nextra/modules/mdx-components.md +52 -0
- moai_adk/templates/.claude/skills/moai-library-nextra/optimization.md +303 -0
- moai_adk/templates/.claude/skills/moai-library-shadcn/SKILL.md +370 -0
- moai_adk/templates/.claude/skills/moai-library-shadcn/examples.md +575 -0
- moai_adk/templates/.claude/skills/moai-library-shadcn/modules/advanced-patterns.md +394 -0
- moai_adk/templates/.claude/skills/moai-library-shadcn/modules/optimization.md +278 -0
- moai_adk/templates/.claude/skills/moai-library-shadcn/modules/shadcn-components.md +457 -0
- moai_adk/templates/.claude/skills/moai-library-shadcn/modules/shadcn-theming.md +373 -0
- moai_adk/templates/.claude/skills/moai-library-shadcn/reference.md +74 -0
- moai_adk/templates/.claude/skills/moai-platform-baas/README.md +186 -0
- moai_adk/templates/.claude/skills/moai-platform-baas/SKILL.md +290 -0
- moai_adk/templates/.claude/skills/moai-platform-baas/examples.md +1225 -0
- moai_adk/templates/.claude/skills/moai-platform-baas/reference.md +567 -0
- moai_adk/templates/.claude/skills/moai-platform-baas/scripts/provider-selector.py +323 -0
- moai_adk/templates/.claude/skills/moai-platform-baas/templates/stack-config.yaml +204 -0
- moai_adk/templates/.claude/skills/moai-workflow-jit-docs/SKILL.md +446 -0
- moai_adk/templates/.claude/skills/moai-workflow-jit-docs/advanced-patterns.md +379 -0
- moai_adk/templates/.claude/skills/moai-workflow-jit-docs/optimization.md +286 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/README.md +190 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/SKILL.md +387 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/__init__.py +520 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/complete_workflow_demo_fixed.py +574 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/examples/complete_project_setup.py +317 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/examples/complete_workflow_demo.py +663 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/examples/config-migration-example.json +190 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/examples/question-examples.json +135 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/examples/quick_start.py +196 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/modules/__init__.py +17 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/modules/advanced-patterns.md +158 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/modules/ask_user_integration.py +340 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/modules/batch_questions.py +713 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/modules/config_manager.py +538 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/modules/documentation_manager.py +1336 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/modules/language_initializer.py +730 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/modules/migration_manager.py +608 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/modules/template_optimizer.py +1005 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/schemas/config-schema.json +316 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/schemas/tab_schema.json +1362 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/templates/config-template.json +71 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/templates/doc-templates/product-template.md +44 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/templates/doc-templates/structure-template.md +48 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/templates/doc-templates/tech-template.md +71 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/templates/question-templates/config-manager-setup.json +109 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/templates/question-templates/language-initializer.json +228 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/templates/question-templates/menu-project-config.json +130 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/templates/question-templates/project-batch-questions.json +97 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/templates/question-templates/spec-workflow-setup.json +150 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/test_integration_simple.py +436 -0
- moai_adk/templates/.claude/skills/moai-workflow-templates/SKILL.md +374 -0
- moai_adk/templates/.claude/skills/moai-workflow-templates/modules/code-templates.md +124 -0
- moai_adk/templates/.claude/skills/moai-workflow-templates/modules/feedback-templates.md +100 -0
- moai_adk/templates/.claude/skills/moai-workflow-templates/modules/template-optimizer.md +138 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/LICENSE.txt +202 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/SKILL.md +453 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/advanced-patterns.md +576 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/examples/ai-powered-testing.py +294 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/examples/console_logging.py +35 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/examples/element_discovery.py +40 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/examples/static_html_automation.py +34 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/README.md +220 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/ai-debugging.md +845 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/automated-code-review.md +1416 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/performance-optimization.md +1234 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/smart-refactoring.md +1243 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/tdd-context7.md +1260 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/optimization.md +505 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/reference/playwright-best-practices.md +57 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/scripts/with_server.py +218 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/templates/alfred-integration.md +376 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/workflows/enterprise-testing-workflow.py +571 -0
- moai_adk/templates/.claude/skills/moai-worktree/SKILL.md +410 -0
- moai_adk/templates/.claude/skills/moai-worktree/examples.md +606 -0
- moai_adk/templates/.claude/skills/moai-worktree/modules/integration-patterns.md +982 -0
- moai_adk/templates/.claude/skills/moai-worktree/modules/parallel-development.md +778 -0
- moai_adk/templates/.claude/skills/moai-worktree/modules/worktree-commands.md +646 -0
- moai_adk/templates/.claude/skills/moai-worktree/modules/worktree-management.md +782 -0
- moai_adk/templates/.claude/skills/moai-worktree/reference.md +357 -0
- moai_adk/templates/.git-hooks/pre-commit +128 -0
- moai_adk/templates/.git-hooks/pre-push +220 -13
- moai_adk/templates/.github/workflows/ci-universal.yml +513 -0
- moai_adk/templates/.github/workflows/security-secrets-check.yml +179 -0
- moai_adk/templates/.github/workflows/spec-issue-sync.yml +0 -1
- moai_adk/templates/.gitignore +197 -13
- moai_adk/templates/.mcp.json +20 -0
- moai_adk/templates/.moai/cache/personalization.json +10 -0
- moai_adk/templates/.moai/config/config.yaml +344 -0
- moai_adk/templates/.moai/config/presets/manual.yaml +28 -0
- moai_adk/templates/.moai/config/presets/personal.yaml +30 -0
- moai_adk/templates/.moai/config/presets/team.yaml +33 -0
- moai_adk/templates/.moai/config/questions/_schema.yaml +79 -0
- moai_adk/templates/.moai/config/questions/tab1-user.yaml +108 -0
- moai_adk/templates/.moai/config/questions/tab2-project.yaml +122 -0
- moai_adk/templates/.moai/config/questions/tab3-git.yaml +542 -0
- moai_adk/templates/.moai/config/questions/tab4-quality.yaml +167 -0
- moai_adk/templates/.moai/config/questions/tab5-system.yaml +152 -0
- moai_adk/templates/.moai/config/sections/git-strategy.yaml +40 -0
- moai_adk/templates/.moai/config/sections/language.yaml +11 -0
- moai_adk/templates/.moai/config/sections/project.yaml +13 -0
- moai_adk/templates/.moai/config/sections/quality.yaml +15 -0
- moai_adk/templates/.moai/config/sections/system.yaml +14 -0
- moai_adk/templates/.moai/config/sections/user.yaml +5 -0
- moai_adk/templates/.moai/config/statusline-config.yaml +86 -0
- moai_adk/templates/.moai/scripts/setup-glm.py +136 -0
- moai_adk/templates/CLAUDE.md +310 -1050
- moai_adk/utils/__init__.py +24 -2
- moai_adk/utils/banner.py +7 -11
- moai_adk/utils/common.py +294 -0
- moai_adk/utils/link_validator.py +241 -0
- moai_adk/utils/logger.py +4 -9
- moai_adk/utils/safe_file_reader.py +206 -0
- moai_adk/{templates/.claude/hooks/alfred/utils โ utils}/timeout.py +8 -9
- moai_adk/utils/toon_utils.py +256 -0
- moai_adk/version.py +22 -0
- moai_adk-0.32.8.dist-info/METADATA +2478 -0
- moai_adk-0.32.8.dist-info/RECORD +396 -0
- {moai_adk-0.15.1.dist-info โ moai_adk-0.32.8.dist-info}/WHEEL +1 -1
- {moai_adk-0.15.1.dist-info โ moai_adk-0.32.8.dist-info}/entry_points.txt +1 -0
- moai_adk/cli/commands/backup.py +0 -80
- moai_adk/core/tags/__init__.py +0 -86
- moai_adk/core/tags/ci_validator.py +0 -463
- moai_adk/core/tags/cli.py +0 -283
- moai_adk/core/tags/generator.py +0 -109
- moai_adk/core/tags/inserter.py +0 -99
- moai_adk/core/tags/mapper.py +0 -126
- moai_adk/core/tags/parser.py +0 -76
- moai_adk/core/tags/pre_commit_validator.py +0 -393
- moai_adk/core/tags/reporter.py +0 -956
- moai_adk/core/tags/tags.py +0 -149
- moai_adk/core/tags/validator.py +0 -897
- moai_adk/templates/.claude/agents/alfred/backend-expert.md +0 -319
- moai_adk/templates/.claude/agents/alfred/cc-manager.md +0 -316
- moai_adk/templates/.claude/agents/alfred/debug-helper.md +0 -208
- moai_adk/templates/.claude/agents/alfred/devops-expert.md +0 -464
- moai_adk/templates/.claude/agents/alfred/doc-syncer.md +0 -214
- moai_adk/templates/.claude/agents/alfred/frontend-expert.md +0 -357
- moai_adk/templates/.claude/agents/alfred/git-manager.md +0 -406
- moai_adk/templates/.claude/agents/alfred/implementation-planner.md +0 -423
- moai_adk/templates/.claude/agents/alfred/project-manager.md +0 -312
- moai_adk/templates/.claude/agents/alfred/quality-gate.md +0 -343
- moai_adk/templates/.claude/agents/alfred/skill-factory.md +0 -865
- moai_adk/templates/.claude/agents/alfred/spec-builder.md +0 -426
- moai_adk/templates/.claude/agents/alfred/tag-agent.md +0 -361
- moai_adk/templates/.claude/agents/alfred/tdd-implementer.md +0 -428
- moai_adk/templates/.claude/agents/alfred/trust-checker.md +0 -375
- moai_adk/templates/.claude/agents/alfred/ui-ux-expert.md +0 -571
- moai_adk/templates/.claude/commands/alfred/0-project.md +0 -1854
- moai_adk/templates/.claude/commands/alfred/1-plan.md +0 -880
- moai_adk/templates/.claude/commands/alfred/2-run.md +0 -793
- moai_adk/templates/.claude/commands/alfred/3-sync.md +0 -1084
- moai_adk/templates/.claude/commands/alfred/9-feedback.md +0 -149
- moai_adk/templates/.claude/hooks/alfred/core/project.py +0 -748
- moai_adk/templates/.claude/hooks/alfred/core/ttl_cache.py +0 -108
- moai_adk/templates/.claude/hooks/alfred/core/version_cache.py +0 -198
- moai_adk/templates/.claude/hooks/alfred/handlers/__init__.py +0 -29
- moai_adk/templates/.claude/hooks/alfred/post_tool__log_changes.py +0 -94
- moai_adk/templates/.claude/hooks/alfred/pre_tool__auto_checkpoint.py +0 -100
- moai_adk/templates/.claude/hooks/alfred/session_end__cleanup.py +0 -94
- moai_adk/templates/.claude/hooks/alfred/session_start__show_project_info.py +0 -94
- moai_adk/templates/.claude/hooks/alfred/shared/core/__init__.py +0 -170
- moai_adk/templates/.claude/hooks/alfred/shared/core/context.py +0 -67
- moai_adk/templates/.claude/hooks/alfred/shared/core/tags.py +0 -230
- moai_adk/templates/.claude/hooks/alfred/shared/core/version_cache.py +0 -198
- moai_adk/templates/.claude/hooks/alfred/shared/handlers/__init__.py +0 -21
- moai_adk/templates/.claude/hooks/alfred/shared/handlers/notification.py +0 -154
- moai_adk/templates/.claude/hooks/alfred/shared/handlers/session.py +0 -174
- moai_adk/templates/.claude/hooks/alfred/shared/handlers/tool.py +0 -87
- moai_adk/templates/.claude/hooks/alfred/shared/handlers/user.py +0 -61
- moai_adk/templates/.claude/hooks/alfred/user_prompt__jit_load_docs.py +0 -112
- moai_adk/templates/.claude/hooks/alfred/utils/__init__.py +0 -1
- moai_adk/templates/.claude/skills/moai-alfred-agent-guide/SKILL.md +0 -70
- moai_adk/templates/.claude/skills/moai-alfred-agent-guide/examples.md +0 -62
- moai_adk/templates/.claude/skills/moai-alfred-agent-guide/reference.md +0 -242
- moai_adk/templates/.claude/skills/moai-alfred-config-schema/SKILL.md +0 -56
- moai_adk/templates/.claude/skills/moai-alfred-config-schema/examples.md +0 -28
- moai_adk/templates/.claude/skills/moai-alfred-config-schema/reference.md +0 -444
- moai_adk/templates/.claude/skills/moai-alfred-context-budget/SKILL.md +0 -62
- moai_adk/templates/.claude/skills/moai-alfred-context-budget/examples.md +0 -28
- moai_adk/templates/.claude/skills/moai-alfred-context-budget/reference.md +0 -405
- moai_adk/templates/.claude/skills/moai-alfred-dev-guide/SKILL.md +0 -51
- moai_adk/templates/.claude/skills/moai-alfred-dev-guide/examples.md +0 -355
- moai_adk/templates/.claude/skills/moai-alfred-dev-guide/reference.md +0 -239
- moai_adk/templates/.claude/skills/moai-alfred-ears-authoring/SKILL.md +0 -113
- moai_adk/templates/.claude/skills/moai-alfred-ears-authoring/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-alfred-ears-authoring/reference.md +0 -28
- moai_adk/templates/.claude/skills/moai-alfred-expertise-detection/SKILL.md +0 -323
- moai_adk/templates/.claude/skills/moai-alfred-expertise-detection/examples.md +0 -286
- moai_adk/templates/.claude/skills/moai-alfred-expertise-detection/reference.md +0 -126
- moai_adk/templates/.claude/skills/moai-alfred-git-workflow/SKILL.md +0 -122
- moai_adk/templates/.claude/skills/moai-alfred-git-workflow/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-alfred-git-workflow/reference.md +0 -29
- moai_adk/templates/.claude/skills/moai-alfred-gitflow-policy/SKILL.md +0 -74
- moai_adk/templates/.claude/skills/moai-alfred-gitflow-policy/examples.md +0 -4
- moai_adk/templates/.claude/skills/moai-alfred-gitflow-policy/reference.md +0 -269
- moai_adk/templates/.claude/skills/moai-alfred-interactive-questions/SKILL.md +0 -237
- moai_adk/templates/.claude/skills/moai-alfred-interactive-questions/examples.md +0 -615
- moai_adk/templates/.claude/skills/moai-alfred-interactive-questions/reference.md +0 -653
- moai_adk/templates/.claude/skills/moai-alfred-issue-labels/SKILL.md +0 -19
- moai_adk/templates/.claude/skills/moai-alfred-issue-labels/examples.md +0 -4
- moai_adk/templates/.claude/skills/moai-alfred-issue-labels/reference.md +0 -150
- moai_adk/templates/.claude/skills/moai-alfred-language-detection/SKILL.md +0 -113
- moai_adk/templates/.claude/skills/moai-alfred-language-detection/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-alfred-language-detection/reference.md +0 -28
- moai_adk/templates/.claude/skills/moai-alfred-persona-roles/SKILL.md +0 -198
- moai_adk/templates/.claude/skills/moai-alfred-persona-roles/examples.md +0 -431
- moai_adk/templates/.claude/skills/moai-alfred-persona-roles/reference.md +0 -141
- moai_adk/templates/.claude/skills/moai-alfred-practices/SKILL.md +0 -89
- moai_adk/templates/.claude/skills/moai-alfred-practices/examples.md +0 -122
- moai_adk/templates/.claude/skills/moai-alfred-practices/reference.md +0 -369
- moai_adk/templates/.claude/skills/moai-alfred-proactive-suggestions/SKILL.md +0 -508
- moai_adk/templates/.claude/skills/moai-alfred-proactive-suggestions/examples.md +0 -481
- moai_adk/templates/.claude/skills/moai-alfred-proactive-suggestions/reference.md +0 -100
- moai_adk/templates/.claude/skills/moai-alfred-reporting/SKILL.md +0 -273
- moai_adk/templates/.claude/skills/moai-alfred-rules/SKILL.md +0 -77
- moai_adk/templates/.claude/skills/moai-alfred-rules/examples.md +0 -265
- moai_adk/templates/.claude/skills/moai-alfred-rules/reference.md +0 -539
- moai_adk/templates/.claude/skills/moai-alfred-session-state/SKILL.md +0 -19
- moai_adk/templates/.claude/skills/moai-alfred-session-state/examples.md +0 -4
- moai_adk/templates/.claude/skills/moai-alfred-session-state/reference.md +0 -84
- moai_adk/templates/.claude/skills/moai-alfred-spec-authoring/README.md +0 -137
- moai_adk/templates/.claude/skills/moai-alfred-spec-authoring/SKILL.md +0 -219
- moai_adk/templates/.claude/skills/moai-alfred-spec-authoring/examples/validate-spec.sh +0 -161
- moai_adk/templates/.claude/skills/moai-alfred-spec-authoring/examples.md +0 -541
- moai_adk/templates/.claude/skills/moai-alfred-spec-authoring/reference.md +0 -622
- moai_adk/templates/.claude/skills/moai-alfred-spec-metadata-extended/SKILL.md +0 -115
- moai_adk/templates/.claude/skills/moai-alfred-spec-metadata-extended/examples.md +0 -4
- moai_adk/templates/.claude/skills/moai-alfred-spec-metadata-extended/reference.md +0 -348
- moai_adk/templates/.claude/skills/moai-alfred-spec-metadata-validation/SKILL.md +0 -113
- moai_adk/templates/.claude/skills/moai-alfred-spec-metadata-validation/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-alfred-spec-metadata-validation/reference.md +0 -28
- moai_adk/templates/.claude/skills/moai-alfred-tag-scanning/SKILL.md +0 -113
- moai_adk/templates/.claude/skills/moai-alfred-tag-scanning/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-alfred-tag-scanning/reference.md +0 -28
- moai_adk/templates/.claude/skills/moai-alfred-todowrite-pattern/SKILL.md +0 -19
- moai_adk/templates/.claude/skills/moai-alfred-todowrite-pattern/examples.md +0 -4
- moai_adk/templates/.claude/skills/moai-alfred-todowrite-pattern/reference.md +0 -211
- moai_adk/templates/.claude/skills/moai-alfred-trust-validation/SKILL.md +0 -113
- moai_adk/templates/.claude/skills/moai-alfred-trust-validation/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-alfred-trust-validation/reference.md +0 -28
- moai_adk/templates/.claude/skills/moai-alfred-workflow/SKILL.md +0 -288
- moai_adk/templates/.claude/skills/moai-cc-agents/SKILL.md +0 -269
- moai_adk/templates/.claude/skills/moai-cc-agents/templates/agent-template.md +0 -32
- moai_adk/templates/.claude/skills/moai-cc-claude-md/SKILL.md +0 -298
- moai_adk/templates/.claude/skills/moai-cc-claude-md/templates/CLAUDE-template.md +0 -26
- moai_adk/templates/.claude/skills/moai-cc-commands/SKILL.md +0 -307
- moai_adk/templates/.claude/skills/moai-cc-commands/templates/command-template.md +0 -21
- moai_adk/templates/.claude/skills/moai-cc-hooks/SKILL.md +0 -252
- moai_adk/templates/.claude/skills/moai-cc-hooks/scripts/pre-bash-check.sh +0 -19
- moai_adk/templates/.claude/skills/moai-cc-hooks/scripts/preserve-permissions.sh +0 -19
- moai_adk/templates/.claude/skills/moai-cc-hooks/scripts/validate-bash-command.py +0 -24
- moai_adk/templates/.claude/skills/moai-cc-mcp-plugins/SKILL.md +0 -199
- moai_adk/templates/.claude/skills/moai-cc-mcp-plugins/templates/settings-mcp-template.json +0 -39
- moai_adk/templates/.claude/skills/moai-cc-memory/SKILL.md +0 -316
- moai_adk/templates/.claude/skills/moai-cc-memory/templates/session-summary-template.md +0 -18
- moai_adk/templates/.claude/skills/moai-cc-settings/SKILL.md +0 -263
- moai_adk/templates/.claude/skills/moai-cc-settings/templates/settings-complete-template.json +0 -30
- moai_adk/templates/.claude/skills/moai-cc-skill-descriptions/SKILL.md +0 -19
- moai_adk/templates/.claude/skills/moai-cc-skill-descriptions/examples.md +0 -4
- moai_adk/templates/.claude/skills/moai-cc-skill-descriptions/reference.md +0 -218
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/CHECKLIST.md +0 -482
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/EXAMPLES.md +0 -278
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/INTERACTIVE-DISCOVERY.md +0 -524
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/METADATA.md +0 -477
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/PARALLEL-ANALYSIS-REPORT.md +0 -429
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/PYTHON-VERSION-MATRIX.md +0 -391
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/SKILL-FACTORY-WORKFLOW.md +0 -431
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/SKILL-UPDATE-ADVISOR.md +0 -577
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/SKILL.md +0 -271
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/STEP-BY-STEP-GUIDE.md +0 -466
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/STRUCTURE.md +0 -583
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/WEB-RESEARCH.md +0 -526
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/reference.md +0 -465
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/scripts/generate-structure.sh +0 -328
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/scripts/validate-skill.sh +0 -312
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/templates/SKILL_TEMPLATE.md +0 -245
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/templates/examples-template.md +0 -285
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/templates/reference-template.md +0 -278
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/templates/scripts-template.sh +0 -303
- moai_adk/templates/.claude/skills/moai-cc-skills/SKILL.md +0 -291
- moai_adk/templates/.claude/skills/moai-cc-skills/templates/SKILL-template.md +0 -15
- moai_adk/templates/.claude/skills/moai-design-systems/SKILL.md +0 -802
- moai_adk/templates/.claude/skills/moai-design-systems/examples.md +0 -1238
- moai_adk/templates/.claude/skills/moai-design-systems/reference.md +0 -673
- moai_adk/templates/.claude/skills/moai-domain-backend/examples.md +0 -1633
- moai_adk/templates/.claude/skills/moai-domain-backend/reference.md +0 -660
- moai_adk/templates/.claude/skills/moai-domain-cli-tool/SKILL.md +0 -123
- moai_adk/templates/.claude/skills/moai-domain-cli-tool/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-domain-cli-tool/reference.md +0 -30
- moai_adk/templates/.claude/skills/moai-domain-data-science/SKILL.md +0 -123
- moai_adk/templates/.claude/skills/moai-domain-data-science/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-domain-data-science/reference.md +0 -30
- moai_adk/templates/.claude/skills/moai-domain-database/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-domain-database/reference.md +0 -30
- moai_adk/templates/.claude/skills/moai-domain-devops/SKILL.md +0 -124
- moai_adk/templates/.claude/skills/moai-domain-devops/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-domain-devops/reference.md +0 -31
- moai_adk/templates/.claude/skills/moai-domain-frontend/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-domain-frontend/reference.md +0 -31
- moai_adk/templates/.claude/skills/moai-domain-ml/SKILL.md +0 -123
- moai_adk/templates/.claude/skills/moai-domain-ml/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-domain-ml/reference.md +0 -30
- moai_adk/templates/.claude/skills/moai-domain-mobile-app/SKILL.md +0 -123
- moai_adk/templates/.claude/skills/moai-domain-mobile-app/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-domain-mobile-app/reference.md +0 -30
- moai_adk/templates/.claude/skills/moai-domain-security/SKILL.md +0 -123
- moai_adk/templates/.claude/skills/moai-domain-security/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-domain-security/reference.md +0 -30
- moai_adk/templates/.claude/skills/moai-domain-web-api/SKILL.md +0 -123
- moai_adk/templates/.claude/skills/moai-domain-web-api/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-domain-web-api/reference.md +0 -30
- moai_adk/templates/.claude/skills/moai-essentials-debug/SKILL.md +0 -303
- moai_adk/templates/.claude/skills/moai-essentials-debug/examples.md +0 -1064
- moai_adk/templates/.claude/skills/moai-essentials-debug/reference.md +0 -1047
- moai_adk/templates/.claude/skills/moai-essentials-perf/SKILL.md +0 -113
- moai_adk/templates/.claude/skills/moai-essentials-perf/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-essentials-perf/reference.md +0 -28
- moai_adk/templates/.claude/skills/moai-essentials-refactor/SKILL.md +0 -113
- moai_adk/templates/.claude/skills/moai-essentials-refactor/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-essentials-refactor/reference.md +0 -28
- moai_adk/templates/.claude/skills/moai-essentials-review/SKILL.md +0 -113
- moai_adk/templates/.claude/skills/moai-essentials-review/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-essentials-review/reference.md +0 -28
- moai_adk/templates/.claude/skills/moai-foundation-ears/SKILL.md +0 -116
- moai_adk/templates/.claude/skills/moai-foundation-ears/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-foundation-ears/reference.md +0 -28
- moai_adk/templates/.claude/skills/moai-foundation-git/SKILL.md +0 -122
- moai_adk/templates/.claude/skills/moai-foundation-git/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-foundation-git/reference.md +0 -29
- moai_adk/templates/.claude/skills/moai-foundation-langs/SKILL.md +0 -113
- moai_adk/templates/.claude/skills/moai-foundation-langs/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-foundation-langs/reference.md +0 -28
- moai_adk/templates/.claude/skills/moai-foundation-specs/SKILL.md +0 -113
- moai_adk/templates/.claude/skills/moai-foundation-specs/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-foundation-specs/reference.md +0 -28
- moai_adk/templates/.claude/skills/moai-foundation-tags/SKILL.md +0 -113
- moai_adk/templates/.claude/skills/moai-foundation-tags/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-foundation-tags/reference.md +0 -28
- moai_adk/templates/.claude/skills/moai-foundation-trust/SKILL.md +0 -307
- moai_adk/templates/.claude/skills/moai-foundation-trust/examples.md +0 -0
- moai_adk/templates/.claude/skills/moai-foundation-trust/reference.md +0 -1099
- moai_adk/templates/.claude/skills/moai-lang-c/SKILL.md +0 -124
- moai_adk/templates/.claude/skills/moai-lang-c/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-lang-c/reference.md +0 -31
- moai_adk/templates/.claude/skills/moai-lang-cpp/SKILL.md +0 -124
- moai_adk/templates/.claude/skills/moai-lang-cpp/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-lang-cpp/reference.md +0 -31
- moai_adk/templates/.claude/skills/moai-lang-csharp/SKILL.md +0 -123
- moai_adk/templates/.claude/skills/moai-lang-csharp/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-lang-csharp/reference.md +0 -30
- moai_adk/templates/.claude/skills/moai-lang-dart/SKILL.md +0 -123
- moai_adk/templates/.claude/skills/moai-lang-dart/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-lang-dart/reference.md +0 -30
- moai_adk/templates/.claude/skills/moai-lang-go/SKILL.md +0 -127
- moai_adk/templates/.claude/skills/moai-lang-go/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-lang-go/reference.md +0 -31
- moai_adk/templates/.claude/skills/moai-lang-java/SKILL.md +0 -126
- moai_adk/templates/.claude/skills/moai-lang-java/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-lang-java/reference.md +0 -31
- moai_adk/templates/.claude/skills/moai-lang-javascript/SKILL.md +0 -125
- moai_adk/templates/.claude/skills/moai-lang-javascript/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-lang-javascript/reference.md +0 -32
- moai_adk/templates/.claude/skills/moai-lang-kotlin/SKILL.md +0 -124
- moai_adk/templates/.claude/skills/moai-lang-kotlin/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-lang-kotlin/reference.md +0 -31
- moai_adk/templates/.claude/skills/moai-lang-php/SKILL.md +0 -126
- moai_adk/templates/.claude/skills/moai-lang-php/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-lang-php/reference.md +0 -30
- moai_adk/templates/.claude/skills/moai-lang-python/SKILL.md +0 -433
- moai_adk/templates/.claude/skills/moai-lang-python/examples.md +0 -624
- moai_adk/templates/.claude/skills/moai-lang-python/reference.md +0 -316
- moai_adk/templates/.claude/skills/moai-lang-r/SKILL.md +0 -123
- moai_adk/templates/.claude/skills/moai-lang-r/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-lang-r/reference.md +0 -30
- moai_adk/templates/.claude/skills/moai-lang-ruby/SKILL.md +0 -124
- moai_adk/templates/.claude/skills/moai-lang-ruby/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-lang-ruby/reference.md +0 -31
- moai_adk/templates/.claude/skills/moai-lang-rust/SKILL.md +0 -127
- moai_adk/templates/.claude/skills/moai-lang-rust/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-lang-rust/reference.md +0 -31
- moai_adk/templates/.claude/skills/moai-lang-scala/SKILL.md +0 -125
- moai_adk/templates/.claude/skills/moai-lang-scala/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-lang-scala/reference.md +0 -30
- moai_adk/templates/.claude/skills/moai-lang-shell/SKILL.md +0 -123
- moai_adk/templates/.claude/skills/moai-lang-shell/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-lang-shell/reference.md +0 -30
- moai_adk/templates/.claude/skills/moai-lang-sql/SKILL.md +0 -124
- moai_adk/templates/.claude/skills/moai-lang-sql/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-lang-sql/reference.md +0 -31
- moai_adk/templates/.claude/skills/moai-lang-swift/SKILL.md +0 -123
- moai_adk/templates/.claude/skills/moai-lang-swift/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-lang-swift/reference.md +0 -30
- moai_adk/templates/.claude/skills/moai-lang-typescript/SKILL.md +0 -133
- moai_adk/templates/.claude/skills/moai-lang-typescript/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-lang-typescript/reference.md +0 -34
- moai_adk/templates/.claude/skills/moai-project-documentation.md +0 -622
- moai_adk/templates/.github/workflows/c-tag-validation.yml +0 -11
- moai_adk/templates/.github/workflows/cpp-tag-validation.yml +0 -11
- moai_adk/templates/.github/workflows/csharp-tag-validation.yml +0 -11
- moai_adk/templates/.github/workflows/dart-tag-validation.yml +0 -11
- moai_adk/templates/.github/workflows/go-tag-validation.yml +0 -130
- moai_adk/templates/.github/workflows/java-tag-validation.yml +0 -11
- moai_adk/templates/.github/workflows/javascript-tag-validation.yml +0 -135
- moai_adk/templates/.github/workflows/kotlin-tag-validation.yml +0 -11
- moai_adk/templates/.github/workflows/moai-gitflow.yml +0 -419
- moai_adk/templates/.github/workflows/moai-release-create.yml +0 -100
- moai_adk/templates/.github/workflows/moai-release-pipeline.yml +0 -188
- moai_adk/templates/.github/workflows/php-tag-validation.yml +0 -11
- moai_adk/templates/.github/workflows/python-tag-validation.yml +0 -118
- moai_adk/templates/.github/workflows/release.yml +0 -118
- moai_adk/templates/.github/workflows/ruby-tag-validation.yml +0 -11
- moai_adk/templates/.github/workflows/rust-tag-validation.yml +0 -11
- moai_adk/templates/.github/workflows/shell-tag-validation.yml +0 -11
- moai_adk/templates/.github/workflows/swift-tag-validation.yml +0 -11
- moai_adk/templates/.github/workflows/tag-report.yml +0 -269
- moai_adk/templates/.github/workflows/tag-validation.yml +0 -186
- moai_adk/templates/.github/workflows/typescript-tag-validation.yml +0 -154
- moai_adk/templates/.moai/config.json +0 -115
- moai_adk/templates/workflows/go-tag-validation.yml +0 -30
- moai_adk/templates/workflows/javascript-tag-validation.yml +0 -41
- moai_adk/templates/workflows/python-tag-validation.yml +0 -42
- moai_adk/templates/workflows/typescript-tag-validation.yml +0 -31
- moai_adk-0.15.1.dist-info/METADATA +0 -3094
- moai_adk-0.15.1.dist-info/RECORD +0 -365
- {moai_adk-0.15.1.dist-info โ moai_adk-0.32.8.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,1987 @@
|
|
|
1
|
+
"""
|
|
2
|
+
JIT-Enhanced Hook Manager
|
|
3
|
+
|
|
4
|
+
Integrates Phase 2 JIT Context Loading System with Claude Code hook infrastructure
|
|
5
|
+
to provide intelligent, phase-aware hook execution with optimal performance.
|
|
6
|
+
|
|
7
|
+
Key Features:
|
|
8
|
+
- Phase-based hook optimization
|
|
9
|
+
- JIT context loading for hooks
|
|
10
|
+
- Intelligent skill filtering for hook operations
|
|
11
|
+
- Dynamic token budget management
|
|
12
|
+
- Real-time performance monitoring
|
|
13
|
+
- Smart caching and invalidation
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
import asyncio
|
|
17
|
+
import inspect
|
|
18
|
+
import json
|
|
19
|
+
import logging
|
|
20
|
+
import threading
|
|
21
|
+
import time
|
|
22
|
+
from collections import defaultdict
|
|
23
|
+
from dataclasses import dataclass, field
|
|
24
|
+
from datetime import datetime, timedelta
|
|
25
|
+
from enum import Enum
|
|
26
|
+
from pathlib import Path
|
|
27
|
+
from typing import Any, Callable, Dict, List, Optional, Set, Tuple
|
|
28
|
+
|
|
29
|
+
# Import JIT Context Loading System from Phase 2
|
|
30
|
+
try:
|
|
31
|
+
from .jit_context_loader import (
|
|
32
|
+
ContextCache as _ImportedContextCache,
|
|
33
|
+
)
|
|
34
|
+
from .jit_context_loader import (
|
|
35
|
+
JITContextLoader as _ImportedJITContextLoader,
|
|
36
|
+
)
|
|
37
|
+
from .jit_context_loader import (
|
|
38
|
+
Phase as _ImportedPhase,
|
|
39
|
+
)
|
|
40
|
+
from .jit_context_loader import (
|
|
41
|
+
TokenBudgetManager as _ImportedTokenBudgetManager,
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
JITContextLoader = _ImportedJITContextLoader
|
|
45
|
+
ContextCache = _ImportedContextCache
|
|
46
|
+
TokenBudgetManager = _ImportedTokenBudgetManager
|
|
47
|
+
Phase = _ImportedPhase
|
|
48
|
+
_JIT_AVAILABLE = True
|
|
49
|
+
except ImportError:
|
|
50
|
+
_JIT_AVAILABLE = False
|
|
51
|
+
|
|
52
|
+
# Fallback for environments where JIT system might not be available
|
|
53
|
+
class JITContextLoader: # type: ignore[no-redef]
|
|
54
|
+
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
|
55
|
+
pass
|
|
56
|
+
|
|
57
|
+
class ContextCache: # type: ignore[no-redef]
|
|
58
|
+
def __init__(self, max_size: int = 100, max_memory_mb: int = 50) -> None:
|
|
59
|
+
self.max_size = max_size
|
|
60
|
+
self.max_memory_mb = max_memory_mb
|
|
61
|
+
self.hits = 0
|
|
62
|
+
self.misses = 0
|
|
63
|
+
self.cache: dict[Any, Any] = {}
|
|
64
|
+
|
|
65
|
+
def get(self, key: Any) -> Any:
|
|
66
|
+
self.misses += 1
|
|
67
|
+
return None
|
|
68
|
+
|
|
69
|
+
def put(self, key: Any, value: Any, token_count: int = 0) -> None:
|
|
70
|
+
pass
|
|
71
|
+
|
|
72
|
+
def clear(self) -> None:
|
|
73
|
+
pass
|
|
74
|
+
|
|
75
|
+
def get_stats(self) -> dict[str, Any]:
|
|
76
|
+
return {"hits": self.hits, "misses": self.misses}
|
|
77
|
+
|
|
78
|
+
class TokenBudgetManager: # type: ignore[no-redef]
|
|
79
|
+
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
|
80
|
+
pass
|
|
81
|
+
|
|
82
|
+
# Create Phase enum for hook system (fallback)
|
|
83
|
+
class Phase(Enum): # type: ignore[no-redef]
|
|
84
|
+
SPEC = "SPEC"
|
|
85
|
+
RED = "RED"
|
|
86
|
+
GREEN = "GREEN"
|
|
87
|
+
REFACTOR = "REFACTOR"
|
|
88
|
+
SYNC = "SYNC"
|
|
89
|
+
DEBUG = "DEBUG"
|
|
90
|
+
PLANNING = "PLANNING"
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
class HookEvent(Enum):
|
|
94
|
+
"""Hook event types from Claude Code"""
|
|
95
|
+
|
|
96
|
+
SESSION_START = "SessionStart"
|
|
97
|
+
SESSION_END = "SessionEnd"
|
|
98
|
+
USER_PROMPT_SUBMIT = "UserPromptSubmit"
|
|
99
|
+
PRE_TOOL_USE = "PreToolUse"
|
|
100
|
+
POST_TOOL_USE = "PostToolUse"
|
|
101
|
+
SUBAGENT_START = "SubagentStart"
|
|
102
|
+
SUBAGENT_STOP = "SubagentStop"
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
class HookPriority(Enum):
|
|
106
|
+
"""Hook execution priority levels"""
|
|
107
|
+
|
|
108
|
+
CRITICAL = 1 # System-critical hooks (security, validation)
|
|
109
|
+
HIGH = 2 # High-impact hooks (performance optimization)
|
|
110
|
+
NORMAL = 3 # Standard hooks (logging, cleanup)
|
|
111
|
+
LOW = 4 # Optional hooks (analytics, metrics)
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
@dataclass
|
|
115
|
+
class HookMetadata:
|
|
116
|
+
"""Metadata for a hook execution"""
|
|
117
|
+
|
|
118
|
+
hook_path: str
|
|
119
|
+
event_type: HookEvent
|
|
120
|
+
priority: HookPriority
|
|
121
|
+
estimated_execution_time_ms: float = 0.0
|
|
122
|
+
last_execution_time: Optional[datetime] = None
|
|
123
|
+
success_rate: float = 1.0
|
|
124
|
+
phase_relevance: Dict[Phase, float] = field(default_factory=dict)
|
|
125
|
+
token_cost_estimate: int = 0
|
|
126
|
+
dependencies: Set[str] = field(default_factory=set)
|
|
127
|
+
parallel_safe: bool = True
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
@dataclass
|
|
131
|
+
class HookExecutionResult:
|
|
132
|
+
"""Result of hook execution"""
|
|
133
|
+
|
|
134
|
+
hook_path: str
|
|
135
|
+
success: bool
|
|
136
|
+
execution_time_ms: float
|
|
137
|
+
token_usage: int
|
|
138
|
+
output: Any
|
|
139
|
+
error_message: Optional[str] = None
|
|
140
|
+
metadata: Dict[str, Any] = field(default_factory=dict)
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
@dataclass
|
|
144
|
+
class CircuitBreakerState:
|
|
145
|
+
"""Circuit breaker state for hook resilience"""
|
|
146
|
+
|
|
147
|
+
failure_count: int = 0
|
|
148
|
+
last_failure_time: Optional[datetime] = None
|
|
149
|
+
state: str = "CLOSED" # CLOSED, OPEN, HALF_OPEN
|
|
150
|
+
success_threshold: int = 5
|
|
151
|
+
failure_threshold: int = 3
|
|
152
|
+
timeout_seconds: int = 60
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
class CircuitBreaker:
|
|
156
|
+
"""Circuit breaker pattern for failing hooks"""
|
|
157
|
+
|
|
158
|
+
def __init__(
|
|
159
|
+
self,
|
|
160
|
+
failure_threshold: int = 3,
|
|
161
|
+
timeout_seconds: int = 60,
|
|
162
|
+
success_threshold: int = 5,
|
|
163
|
+
):
|
|
164
|
+
self.failure_threshold = failure_threshold
|
|
165
|
+
self.timeout_seconds = timeout_seconds
|
|
166
|
+
self.success_threshold = success_threshold
|
|
167
|
+
self.state = CircuitBreakerState(
|
|
168
|
+
failure_threshold=failure_threshold,
|
|
169
|
+
timeout_seconds=timeout_seconds,
|
|
170
|
+
success_threshold=success_threshold,
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
async def call(self, func: Callable, *args, **kwargs) -> Any:
|
|
174
|
+
"""Execute function with circuit breaker protection"""
|
|
175
|
+
if self.state.state == "OPEN":
|
|
176
|
+
if self._should_attempt_reset():
|
|
177
|
+
self.state.state = "HALF_OPEN"
|
|
178
|
+
else:
|
|
179
|
+
raise Exception("Circuit breaker is OPEN - call blocked")
|
|
180
|
+
|
|
181
|
+
try:
|
|
182
|
+
result = await func(*args, **kwargs) if inspect.iscoroutinefunction(func) else func(*args, **kwargs)
|
|
183
|
+
self._on_success()
|
|
184
|
+
return result
|
|
185
|
+
except Exception as e:
|
|
186
|
+
self._on_failure()
|
|
187
|
+
raise e
|
|
188
|
+
|
|
189
|
+
def _should_attempt_reset(self) -> bool:
|
|
190
|
+
"""Check if circuit breaker should attempt reset"""
|
|
191
|
+
if self.state.last_failure_time is None:
|
|
192
|
+
return False
|
|
193
|
+
return datetime.now() - self.state.last_failure_time > timedelta(seconds=self.timeout_seconds)
|
|
194
|
+
|
|
195
|
+
def _on_success(self) -> None:
|
|
196
|
+
"""Handle successful call"""
|
|
197
|
+
self.state.failure_count = 0
|
|
198
|
+
if self.state.state == "HALF_OPEN":
|
|
199
|
+
self.state.success_threshold -= 1
|
|
200
|
+
if self.state.success_threshold <= 0:
|
|
201
|
+
self.state.state = "CLOSED"
|
|
202
|
+
self.state.success_threshold = 5
|
|
203
|
+
|
|
204
|
+
def _on_failure(self) -> None:
|
|
205
|
+
"""Handle failed call"""
|
|
206
|
+
self.state.failure_count += 1
|
|
207
|
+
self.state.last_failure_time = datetime.now()
|
|
208
|
+
|
|
209
|
+
if self.state.failure_count >= self.failure_threshold:
|
|
210
|
+
self.state.state = "OPEN"
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
class HookResultCache:
|
|
214
|
+
"""Advanced result caching with TTL and invalidation"""
|
|
215
|
+
|
|
216
|
+
def __init__(self, max_size: int = 1000, default_ttl_seconds: int = 300):
|
|
217
|
+
self.max_size = max_size
|
|
218
|
+
self.default_ttl_seconds = default_ttl_seconds
|
|
219
|
+
self._cache: Dict[str, Tuple[Any, datetime, int]] = {} # key -> (value, expiry, access_count)
|
|
220
|
+
self._access_times: Dict[str, datetime] = {}
|
|
221
|
+
self._lock = threading.RLock()
|
|
222
|
+
|
|
223
|
+
def get(self, key: str) -> Optional[Any]:
|
|
224
|
+
"""Get cached value if valid"""
|
|
225
|
+
with self._lock:
|
|
226
|
+
if key not in self._cache:
|
|
227
|
+
return None
|
|
228
|
+
|
|
229
|
+
value, expiry, access_count = self._cache[key]
|
|
230
|
+
|
|
231
|
+
# Check TTL
|
|
232
|
+
if datetime.now() > expiry:
|
|
233
|
+
del self._cache[key]
|
|
234
|
+
if key in self._access_times:
|
|
235
|
+
del self._access_times[key]
|
|
236
|
+
return None
|
|
237
|
+
|
|
238
|
+
# Update access
|
|
239
|
+
self._cache[key] = (value, expiry, access_count + 1)
|
|
240
|
+
self._access_times[key] = datetime.now()
|
|
241
|
+
|
|
242
|
+
return value
|
|
243
|
+
|
|
244
|
+
def put(self, key: str, value: Any, ttl_seconds: Optional[int] = None) -> None:
|
|
245
|
+
"""Cache value with TTL"""
|
|
246
|
+
with self._lock:
|
|
247
|
+
# Enforce size limit
|
|
248
|
+
if len(self._cache) >= self.max_size:
|
|
249
|
+
self._evict_lru()
|
|
250
|
+
|
|
251
|
+
ttl = ttl_seconds or self.default_ttl_seconds
|
|
252
|
+
expiry = datetime.now() + timedelta(seconds=ttl)
|
|
253
|
+
self._cache[key] = (value, expiry, 1)
|
|
254
|
+
self._access_times[key] = datetime.now()
|
|
255
|
+
|
|
256
|
+
def invalidate(self, pattern: Optional[str] = None) -> None:
|
|
257
|
+
"""Invalidate cache entries"""
|
|
258
|
+
with self._lock:
|
|
259
|
+
if pattern is None:
|
|
260
|
+
self._cache.clear()
|
|
261
|
+
self._access_times.clear()
|
|
262
|
+
else:
|
|
263
|
+
keys_to_remove = [key for key in self._cache.keys() if pattern in key]
|
|
264
|
+
for key in keys_to_remove:
|
|
265
|
+
del self._cache[key]
|
|
266
|
+
if key in self._access_times:
|
|
267
|
+
del self._access_times[key]
|
|
268
|
+
|
|
269
|
+
def _evict_lru(self) -> None:
|
|
270
|
+
"""Evict least recently used item"""
|
|
271
|
+
if not self._access_times:
|
|
272
|
+
return
|
|
273
|
+
|
|
274
|
+
lru_key = min(self._access_times.keys(), key=lambda k: self._access_times[k])
|
|
275
|
+
del self._cache[lru_key]
|
|
276
|
+
del self._access_times[lru_key]
|
|
277
|
+
|
|
278
|
+
def get_stats(self) -> Dict[str, Any]:
|
|
279
|
+
"""Get cache statistics"""
|
|
280
|
+
with self._lock:
|
|
281
|
+
return {
|
|
282
|
+
"size": len(self._cache),
|
|
283
|
+
"max_size": self.max_size,
|
|
284
|
+
"utilization": len(self._cache) / self.max_size,
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
class ConnectionPool:
|
|
289
|
+
"""Connection pooling for MCP servers and external resources"""
|
|
290
|
+
|
|
291
|
+
def __init__(self, max_connections: int = 10, connection_timeout_seconds: int = 30):
|
|
292
|
+
self.max_connections = max_connections
|
|
293
|
+
self.connection_timeout_seconds = connection_timeout_seconds
|
|
294
|
+
self._pools: Dict[str, List] = defaultdict(list)
|
|
295
|
+
self._active_connections: Dict[str, int] = defaultdict(int)
|
|
296
|
+
self._lock = threading.Lock()
|
|
297
|
+
|
|
298
|
+
async def get_connection(self, pool_name: str, connection_factory: Callable) -> Any:
|
|
299
|
+
"""Get connection from pool or create new one"""
|
|
300
|
+
with self._lock:
|
|
301
|
+
# Check pool for available connection
|
|
302
|
+
pool = self._pools[pool_name]
|
|
303
|
+
if pool:
|
|
304
|
+
connection = pool.pop()
|
|
305
|
+
self._active_connections[pool_name] += 1
|
|
306
|
+
return connection
|
|
307
|
+
|
|
308
|
+
# Check if we can create new connection
|
|
309
|
+
if self._active_connections[pool_name] >= self.max_connections:
|
|
310
|
+
raise Exception(f"Connection pool '{pool_name}' is full")
|
|
311
|
+
|
|
312
|
+
self._active_connections[pool_name] += 1
|
|
313
|
+
|
|
314
|
+
# Create new connection outside of lock
|
|
315
|
+
try:
|
|
316
|
+
connection = (
|
|
317
|
+
await connection_factory() if inspect.iscoroutinefunction(connection_factory) else connection_factory()
|
|
318
|
+
)
|
|
319
|
+
return connection
|
|
320
|
+
except Exception:
|
|
321
|
+
with self._lock:
|
|
322
|
+
self._active_connections[pool_name] -= 1
|
|
323
|
+
raise
|
|
324
|
+
|
|
325
|
+
def return_connection(self, pool_name: str, connection: Any) -> None:
|
|
326
|
+
"""Return connection to pool"""
|
|
327
|
+
with self._lock:
|
|
328
|
+
pool = self._pools[pool_name]
|
|
329
|
+
if len(pool) < self.max_connections and connection is not None:
|
|
330
|
+
pool.append(connection)
|
|
331
|
+
self._active_connections[pool_name] -= 1
|
|
332
|
+
|
|
333
|
+
def get_pool_stats(self) -> Dict[str, Any]:
|
|
334
|
+
"""Get connection pool statistics"""
|
|
335
|
+
with self._lock:
|
|
336
|
+
return {
|
|
337
|
+
"pools": {
|
|
338
|
+
name: {
|
|
339
|
+
"available": len(pool),
|
|
340
|
+
"active": self._active_connections[name],
|
|
341
|
+
"total": len(pool) + self._active_connections[name],
|
|
342
|
+
}
|
|
343
|
+
for name, pool in self._pools.items()
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
class RetryPolicy:
|
|
349
|
+
"""Exponential backoff retry policy"""
|
|
350
|
+
|
|
351
|
+
def __init__(
|
|
352
|
+
self,
|
|
353
|
+
max_retries: int = 3,
|
|
354
|
+
base_delay_ms: float = 100,
|
|
355
|
+
max_delay_ms: float = 5000,
|
|
356
|
+
backoff_factor: float = 2.0,
|
|
357
|
+
):
|
|
358
|
+
self.max_retries = max_retries
|
|
359
|
+
self.base_delay_ms = base_delay_ms
|
|
360
|
+
self.max_delay_ms = max_delay_ms
|
|
361
|
+
self.backoff_factor = backoff_factor
|
|
362
|
+
|
|
363
|
+
async def execute_with_retry(self, func: Callable, *args, **kwargs) -> Any:
|
|
364
|
+
"""Execute function with retry policy"""
|
|
365
|
+
last_exception = None
|
|
366
|
+
|
|
367
|
+
for attempt in range(self.max_retries + 1):
|
|
368
|
+
try:
|
|
369
|
+
result = await func(*args, **kwargs) if inspect.iscoroutinefunction(func) else func(*args, **kwargs)
|
|
370
|
+
return result
|
|
371
|
+
except Exception as e:
|
|
372
|
+
last_exception = e
|
|
373
|
+
|
|
374
|
+
if attempt < self.max_retries:
|
|
375
|
+
delay_ms = min(
|
|
376
|
+
self.base_delay_ms * (self.backoff_factor**attempt),
|
|
377
|
+
self.max_delay_ms,
|
|
378
|
+
)
|
|
379
|
+
await asyncio.sleep(delay_ms / 1000.0)
|
|
380
|
+
else:
|
|
381
|
+
break
|
|
382
|
+
|
|
383
|
+
raise last_exception
|
|
384
|
+
|
|
385
|
+
|
|
386
|
+
@dataclass
|
|
387
|
+
class ResourceUsageMetrics:
|
|
388
|
+
"""Resource usage metrics for monitoring"""
|
|
389
|
+
|
|
390
|
+
cpu_usage_percent: float = 0.0
|
|
391
|
+
memory_usage_mb: float = 0.0
|
|
392
|
+
disk_io_mb: float = 0.0
|
|
393
|
+
network_io_mb: float = 0.0
|
|
394
|
+
open_files: int = 0
|
|
395
|
+
thread_count: int = 0
|
|
396
|
+
|
|
397
|
+
|
|
398
|
+
@dataclass
|
|
399
|
+
class HookPerformanceMetrics:
|
|
400
|
+
"""Performance metrics for hook system"""
|
|
401
|
+
|
|
402
|
+
total_executions: int = 0
|
|
403
|
+
successful_executions: int = 0
|
|
404
|
+
average_execution_time_ms: float = 0.0
|
|
405
|
+
total_token_usage: int = 0
|
|
406
|
+
cache_hits: int = 0
|
|
407
|
+
cache_misses: int = 0
|
|
408
|
+
phase_distribution: Dict[Phase, int] = field(default_factory=dict)
|
|
409
|
+
event_type_distribution: Dict[HookEvent, int] = field(default_factory=dict)
|
|
410
|
+
circuit_breaker_trips: int = 0
|
|
411
|
+
retry_attempts: int = 0
|
|
412
|
+
resource_usage: ResourceUsageMetrics = field(default_factory=ResourceUsageMetrics)
|
|
413
|
+
|
|
414
|
+
|
|
415
|
+
class ResourceMonitor:
|
|
416
|
+
"""Resource usage monitoring for hook system"""
|
|
417
|
+
|
|
418
|
+
def __init__(self):
|
|
419
|
+
self._baseline_metrics = self._get_current_metrics()
|
|
420
|
+
self._peak_usage = ResourceUsageMetrics()
|
|
421
|
+
|
|
422
|
+
def get_current_metrics(self) -> ResourceUsageMetrics:
|
|
423
|
+
"""Get current resource usage metrics"""
|
|
424
|
+
import os
|
|
425
|
+
|
|
426
|
+
import psutil
|
|
427
|
+
|
|
428
|
+
try:
|
|
429
|
+
process = psutil.Process(os.getpid())
|
|
430
|
+
|
|
431
|
+
# Memory usage
|
|
432
|
+
memory_info = process.memory_info()
|
|
433
|
+
memory_mb = memory_info.rss / 1024 / 1024
|
|
434
|
+
|
|
435
|
+
# CPU usage (average across all cores)
|
|
436
|
+
cpu_percent = process.cpu_percent()
|
|
437
|
+
|
|
438
|
+
# Thread count
|
|
439
|
+
thread_count = process.num_threads()
|
|
440
|
+
|
|
441
|
+
# Open file descriptors
|
|
442
|
+
try:
|
|
443
|
+
open_files = process.num_fds()
|
|
444
|
+
except (AttributeError, psutil.AccessDenied):
|
|
445
|
+
open_files = 0
|
|
446
|
+
|
|
447
|
+
# Update peak usage
|
|
448
|
+
self._peak_usage.memory_usage_mb = max(self._peak_usage.memory_usage_mb, memory_mb)
|
|
449
|
+
self._peak_usage.cpu_usage_percent = max(self._peak_usage.cpu_usage_percent, cpu_percent)
|
|
450
|
+
self._peak_usage.thread_count = max(self._peak_usage.thread_count, thread_count)
|
|
451
|
+
self._peak_usage.open_files = max(self._peak_usage.open_files, open_files)
|
|
452
|
+
|
|
453
|
+
return ResourceUsageMetrics(
|
|
454
|
+
cpu_usage_percent=cpu_percent,
|
|
455
|
+
memory_usage_mb=memory_mb,
|
|
456
|
+
thread_count=thread_count,
|
|
457
|
+
open_files=open_files,
|
|
458
|
+
)
|
|
459
|
+
except Exception:
|
|
460
|
+
return ResourceUsageMetrics()
|
|
461
|
+
|
|
462
|
+
def _get_current_metrics(self) -> ResourceUsageMetrics:
|
|
463
|
+
"""Get baseline metrics for comparison"""
|
|
464
|
+
return self.get_current_metrics()
|
|
465
|
+
|
|
466
|
+
def get_peak_metrics(self) -> ResourceUsageMetrics:
|
|
467
|
+
"""Get peak resource usage metrics"""
|
|
468
|
+
return self._peak_usage
|
|
469
|
+
|
|
470
|
+
|
|
471
|
+
class HealthChecker:
|
|
472
|
+
"""Health monitoring and check endpoints for hook system"""
|
|
473
|
+
|
|
474
|
+
def __init__(self, hook_manager: "JITEnhancedHookManager"):
|
|
475
|
+
self.hook_manager = hook_manager
|
|
476
|
+
self._last_health_check = datetime.now()
|
|
477
|
+
self._health_status = "healthy"
|
|
478
|
+
|
|
479
|
+
async def check_system_health(self) -> Dict[str, Any]:
|
|
480
|
+
"""Perform comprehensive health check"""
|
|
481
|
+
checks: Dict[str, Dict[str, Any]] = {}
|
|
482
|
+
health_report: Dict[str, Any] = {
|
|
483
|
+
"status": "healthy",
|
|
484
|
+
"timestamp": datetime.now().isoformat(),
|
|
485
|
+
"checks": checks,
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
try:
|
|
489
|
+
# Check hook registry
|
|
490
|
+
checks["hook_registry"] = {
|
|
491
|
+
"status": ("healthy" if len(self.hook_manager._hook_registry) > 0 else "warning"),
|
|
492
|
+
"registered_hooks": len(self.hook_manager._hook_registry),
|
|
493
|
+
"events_supported": len(self.hook_manager._hooks_by_event),
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
# Check cache health
|
|
497
|
+
cache_stats = self.hook_manager._advanced_cache.get_stats()
|
|
498
|
+
checks["cache"] = {
|
|
499
|
+
"status": "healthy",
|
|
500
|
+
"size": cache_stats["size"],
|
|
501
|
+
"utilization": cache_stats["utilization"],
|
|
502
|
+
"max_size": cache_stats["max_size"],
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
# Check connection pools
|
|
506
|
+
pool_stats = self.hook_manager._connection_pool.get_pool_stats()
|
|
507
|
+
checks["connection_pools"] = {
|
|
508
|
+
"status": "healthy",
|
|
509
|
+
"pools": pool_stats["pools"],
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
# Check circuit breakers
|
|
513
|
+
tripped_breakers = [
|
|
514
|
+
name for name, cb in self.hook_manager._circuit_breakers.items() if cb.state.state == "OPEN"
|
|
515
|
+
]
|
|
516
|
+
|
|
517
|
+
checks["circuit_breakers"] = {
|
|
518
|
+
"status": "healthy" if len(tripped_breakers) == 0 else "degraded",
|
|
519
|
+
"total_breakers": len(self.hook_manager._circuit_breakers),
|
|
520
|
+
"tripped_breakers": len(tripped_breakers),
|
|
521
|
+
"tripped_breaker_names": tripped_breakers,
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
# Check resource usage
|
|
525
|
+
resource_metrics = self.hook_manager._resource_monitor.get_current_metrics()
|
|
526
|
+
checks["resource_usage"] = {
|
|
527
|
+
"status": "healthy",
|
|
528
|
+
"memory_mb": resource_metrics.memory_usage_mb,
|
|
529
|
+
"cpu_percent": resource_metrics.cpu_usage_percent,
|
|
530
|
+
"thread_count": resource_metrics.thread_count,
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
# Overall status determination
|
|
534
|
+
statuses = [check["status"] for check in checks.values()]
|
|
535
|
+
if "unhealthy" in statuses:
|
|
536
|
+
health_report["status"] = "unhealthy"
|
|
537
|
+
elif "degraded" in statuses or "warning" in statuses:
|
|
538
|
+
health_report["status"] = "degraded"
|
|
539
|
+
|
|
540
|
+
self._health_status = health_report["status"]
|
|
541
|
+
self._last_health_check = datetime.now()
|
|
542
|
+
|
|
543
|
+
except Exception as e:
|
|
544
|
+
health_report["status"] = "unhealthy"
|
|
545
|
+
health_report["error"] = str(e)
|
|
546
|
+
|
|
547
|
+
return health_report
|
|
548
|
+
|
|
549
|
+
def get_health_status(self) -> str:
|
|
550
|
+
"""Get current health status"""
|
|
551
|
+
return self._health_status
|
|
552
|
+
|
|
553
|
+
|
|
554
|
+
class PerformanceAnomalyDetector:
|
|
555
|
+
"""Detect performance anomalies in hook execution"""
|
|
556
|
+
|
|
557
|
+
def __init__(self, sensitivity_factor: float = 2.0):
|
|
558
|
+
self.sensitivity_factor = sensitivity_factor
|
|
559
|
+
self._performance_history: Dict[str, List[float]] = defaultdict(list)
|
|
560
|
+
|
|
561
|
+
def detect_anomaly(self, hook_path: str, execution_time_ms: float) -> Optional[Dict[str, Any]]:
|
|
562
|
+
"""Detect if execution time is anomalous"""
|
|
563
|
+
history = self._performance_history[hook_path]
|
|
564
|
+
|
|
565
|
+
if len(history) < 5:
|
|
566
|
+
# Not enough data for detection
|
|
567
|
+
self._performance_history[hook_path].append(execution_time_ms)
|
|
568
|
+
return None
|
|
569
|
+
|
|
570
|
+
# Calculate statistics
|
|
571
|
+
mean_time = sum(history) / len(history)
|
|
572
|
+
variance = sum((x - mean_time) ** 2 for x in history) / len(history)
|
|
573
|
+
std_dev = variance**0.5
|
|
574
|
+
|
|
575
|
+
# Check for anomaly
|
|
576
|
+
if abs(execution_time_ms - mean_time) > (self.sensitivity_factor * std_dev):
|
|
577
|
+
anomaly_type = "slow" if execution_time_ms > mean_time else "fast"
|
|
578
|
+
return {
|
|
579
|
+
"hook_path": hook_path,
|
|
580
|
+
"anomaly_type": anomaly_type,
|
|
581
|
+
"execution_time_ms": execution_time_ms,
|
|
582
|
+
"mean_time_ms": mean_time,
|
|
583
|
+
"std_dev_ms": std_dev,
|
|
584
|
+
"deviation_factor": abs(execution_time_ms - mean_time) / std_dev,
|
|
585
|
+
"severity": ("high" if abs(execution_time_ms - mean_time) > (3 * std_dev) else "medium"),
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
# Update history (keep last 50 entries)
|
|
589
|
+
history.append(execution_time_ms)
|
|
590
|
+
if len(history) > 50:
|
|
591
|
+
history.pop(0)
|
|
592
|
+
|
|
593
|
+
return None
|
|
594
|
+
|
|
595
|
+
|
|
596
|
+
class JITEnhancedHookManager:
|
|
597
|
+
"""
|
|
598
|
+
Enhanced Hook Manager with JIT Context Loading System integration
|
|
599
|
+
|
|
600
|
+
Provides intelligent hook execution with phase-aware optimization,
|
|
601
|
+
token budget management, performance monitoring, and reliability patterns.
|
|
602
|
+
"""
|
|
603
|
+
|
|
604
|
+
def __init__(
|
|
605
|
+
self,
|
|
606
|
+
hooks_directory: Optional[Path] = None,
|
|
607
|
+
cache_directory: Optional[Path] = None,
|
|
608
|
+
max_concurrent_hooks: int = 5,
|
|
609
|
+
enable_performance_monitoring: bool = True,
|
|
610
|
+
cache_ttl_seconds: int = 300,
|
|
611
|
+
circuit_breaker_threshold: int = 3,
|
|
612
|
+
max_retries: int = 3,
|
|
613
|
+
connection_pool_size: int = 10,
|
|
614
|
+
):
|
|
615
|
+
"""Initialize JIT-Enhanced Hook Manager with Phase 2 optimizations
|
|
616
|
+
|
|
617
|
+
Args:
|
|
618
|
+
hooks_directory: Directory containing hook files
|
|
619
|
+
cache_directory: Directory for hook cache and performance data
|
|
620
|
+
max_concurrent_hooks: Maximum number of hooks to execute concurrently
|
|
621
|
+
enable_performance_monitoring: Enable detailed performance tracking
|
|
622
|
+
cache_ttl_seconds: Default TTL for cached results
|
|
623
|
+
circuit_breaker_threshold: Failure threshold for circuit breaker
|
|
624
|
+
max_retries: Maximum retry attempts for failed hooks
|
|
625
|
+
connection_pool_size: Size of connection pool for external resources
|
|
626
|
+
"""
|
|
627
|
+
self.hooks_directory = hooks_directory or Path.cwd() / ".claude" / "hooks"
|
|
628
|
+
self.cache_directory = cache_directory or Path.cwd() / ".moai" / "cache" / "hooks"
|
|
629
|
+
self.max_concurrent_hooks = max_concurrent_hooks
|
|
630
|
+
self.enable_performance_monitoring = enable_performance_monitoring
|
|
631
|
+
|
|
632
|
+
# Initialize JIT Context Loading System
|
|
633
|
+
self.jit_loader = JITContextLoader()
|
|
634
|
+
|
|
635
|
+
# Initialize Phase 2 optimizations
|
|
636
|
+
self._initialize_phase2_optimizations(
|
|
637
|
+
cache_ttl_seconds,
|
|
638
|
+
circuit_breaker_threshold,
|
|
639
|
+
max_retries,
|
|
640
|
+
connection_pool_size,
|
|
641
|
+
)
|
|
642
|
+
|
|
643
|
+
# Initialize caches and metadata storage
|
|
644
|
+
self._initialize_caches()
|
|
645
|
+
|
|
646
|
+
# Performance tracking
|
|
647
|
+
self.metrics = HookPerformanceMetrics()
|
|
648
|
+
self._performance_lock = threading.Lock()
|
|
649
|
+
self._resource_monitor = ResourceMonitor()
|
|
650
|
+
|
|
651
|
+
# Hook registry with metadata
|
|
652
|
+
self._hook_registry: Dict[str, HookMetadata] = {}
|
|
653
|
+
self._hooks_by_event: Dict[HookEvent, List[str]] = {}
|
|
654
|
+
self._circuit_breakers: Dict[str, CircuitBreaker] = {}
|
|
655
|
+
self._retry_policies: Dict[str, RetryPolicy] = {}
|
|
656
|
+
|
|
657
|
+
# Initialize hook registry
|
|
658
|
+
self._discover_hooks()
|
|
659
|
+
|
|
660
|
+
# Setup health monitoring
|
|
661
|
+
self._health_checker = HealthChecker(self)
|
|
662
|
+
self._logger = logging.getLogger(__name__)
|
|
663
|
+
|
|
664
|
+
def _initialize_phase2_optimizations(
|
|
665
|
+
self,
|
|
666
|
+
cache_ttl_seconds: int,
|
|
667
|
+
circuit_breaker_threshold: int,
|
|
668
|
+
max_retries: int,
|
|
669
|
+
connection_pool_size: int,
|
|
670
|
+
) -> None:
|
|
671
|
+
"""Initialize Phase 2 optimization components"""
|
|
672
|
+
# Advanced result cache with TTL
|
|
673
|
+
self._advanced_cache = HookResultCache(max_size=1000, default_ttl_seconds=cache_ttl_seconds)
|
|
674
|
+
|
|
675
|
+
# Connection pooling for MCP servers and external resources
|
|
676
|
+
self._connection_pool = ConnectionPool(max_connections=connection_pool_size)
|
|
677
|
+
|
|
678
|
+
# Circuit breaker and retry policies
|
|
679
|
+
self.circuit_breaker_threshold = circuit_breaker_threshold
|
|
680
|
+
self.max_retries = max_retries
|
|
681
|
+
|
|
682
|
+
# Performance profiling
|
|
683
|
+
self._execution_profiles: Dict[str, List[float]] = defaultdict(list)
|
|
684
|
+
self._anomaly_detector = PerformanceAnomalyDetector()
|
|
685
|
+
|
|
686
|
+
def _initialize_caches(self) -> None:
|
|
687
|
+
"""Initialize cache directories and data structures"""
|
|
688
|
+
self.cache_directory.mkdir(parents=True, exist_ok=True)
|
|
689
|
+
|
|
690
|
+
# Initialize hook result cache
|
|
691
|
+
self._result_cache = ContextCache(max_size=100, max_memory_mb=50)
|
|
692
|
+
|
|
693
|
+
# Initialize metadata cache
|
|
694
|
+
self._metadata_cache: Dict[str, Dict[str, Any]] = {}
|
|
695
|
+
|
|
696
|
+
# Performance log file
|
|
697
|
+
self._performance_log_path = self.cache_directory / "performance.jsonl"
|
|
698
|
+
|
|
699
|
+
def _discover_hooks(self) -> None:
|
|
700
|
+
"""Discover and register all available hooks"""
|
|
701
|
+
if not self.hooks_directory.exists():
|
|
702
|
+
return
|
|
703
|
+
|
|
704
|
+
for hook_file in self.hooks_directory.rglob("*.py"):
|
|
705
|
+
if hook_file.name.startswith("__") or hook_file.name.startswith("lib/"):
|
|
706
|
+
continue
|
|
707
|
+
|
|
708
|
+
hook_path_str = str(hook_file.relative_to(self.hooks_directory))
|
|
709
|
+
|
|
710
|
+
# Extract event type from filename
|
|
711
|
+
event_type = self._extract_event_type_from_filename(hook_file.name)
|
|
712
|
+
if event_type:
|
|
713
|
+
self._register_hook(hook_path_str, event_type)
|
|
714
|
+
|
|
715
|
+
def _extract_event_type_from_filename(self, filename: str) -> Optional[HookEvent]:
|
|
716
|
+
"""Extract hook event type from filename pattern"""
|
|
717
|
+
filename_lower = filename.lower()
|
|
718
|
+
|
|
719
|
+
if "session_start" in filename_lower:
|
|
720
|
+
return HookEvent.SESSION_START
|
|
721
|
+
elif "session_end" in filename_lower:
|
|
722
|
+
return HookEvent.SESSION_END
|
|
723
|
+
elif "pre_tool" in filename_lower or "pretool" in filename_lower:
|
|
724
|
+
return HookEvent.PRE_TOOL_USE
|
|
725
|
+
elif "post_tool" in filename_lower or "posttool" in filename_lower:
|
|
726
|
+
return HookEvent.POST_TOOL_USE
|
|
727
|
+
elif "subagent_start" in filename_lower:
|
|
728
|
+
return HookEvent.SUBAGENT_START
|
|
729
|
+
elif "subagent_stop" in filename_lower:
|
|
730
|
+
return HookEvent.SUBAGENT_STOP
|
|
731
|
+
else:
|
|
732
|
+
return None
|
|
733
|
+
|
|
734
|
+
def _register_hook(self, hook_path: str, event_type: HookEvent) -> None:
|
|
735
|
+
"""Register a hook with metadata"""
|
|
736
|
+
# Generate metadata based on hook characteristics
|
|
737
|
+
metadata = HookMetadata(
|
|
738
|
+
hook_path=hook_path,
|
|
739
|
+
event_type=event_type,
|
|
740
|
+
priority=self._determine_hook_priority(hook_path, event_type),
|
|
741
|
+
estimated_execution_time_ms=self._estimate_execution_time(hook_path),
|
|
742
|
+
phase_relevance=self._determine_phase_relevance(hook_path, event_type),
|
|
743
|
+
token_cost_estimate=self._estimate_token_cost(hook_path),
|
|
744
|
+
parallel_safe=self._is_parallel_safe(hook_path),
|
|
745
|
+
)
|
|
746
|
+
|
|
747
|
+
self._hook_registry[hook_path] = metadata
|
|
748
|
+
|
|
749
|
+
if event_type not in self._hooks_by_event:
|
|
750
|
+
self._hooks_by_event[event_type] = []
|
|
751
|
+
self._hooks_by_event[event_type].append(hook_path)
|
|
752
|
+
|
|
753
|
+
def _determine_hook_priority(self, hook_path: str, event_type: HookEvent) -> HookPriority:
|
|
754
|
+
"""Determine hook priority based on its characteristics"""
|
|
755
|
+
filename = hook_path.lower()
|
|
756
|
+
|
|
757
|
+
# Security and validation hooks are critical
|
|
758
|
+
if any(keyword in filename for keyword in ["security", "validation", "health_check"]):
|
|
759
|
+
return HookPriority.CRITICAL
|
|
760
|
+
|
|
761
|
+
# Performance optimization hooks are high priority
|
|
762
|
+
if any(keyword in filename for keyword in ["performance", "optimizer", "jit"]):
|
|
763
|
+
return HookPriority.HIGH
|
|
764
|
+
|
|
765
|
+
# Cleanup and logging hooks are normal priority
|
|
766
|
+
if any(keyword in filename for keyword in ["cleanup", "log", "tracker"]):
|
|
767
|
+
return HookPriority.NORMAL
|
|
768
|
+
|
|
769
|
+
# Analytics and metrics are low priority
|
|
770
|
+
if any(keyword in filename for keyword in ["analytics", "metrics", "stats"]):
|
|
771
|
+
return HookPriority.LOW
|
|
772
|
+
|
|
773
|
+
# Default priority based on event type
|
|
774
|
+
if event_type == HookEvent.PRE_TOOL_USE:
|
|
775
|
+
return HookPriority.HIGH # Pre-execution validation is important
|
|
776
|
+
elif event_type == HookEvent.SESSION_START:
|
|
777
|
+
return HookPriority.NORMAL
|
|
778
|
+
else:
|
|
779
|
+
return HookPriority.NORMAL
|
|
780
|
+
|
|
781
|
+
def _estimate_execution_time(self, hook_path: str) -> float:
|
|
782
|
+
"""Estimate hook execution time based on historical data and characteristics"""
|
|
783
|
+
# Check cache for historical execution time
|
|
784
|
+
cache_key = f"exec_time:{hook_path}"
|
|
785
|
+
if cache_key in self._metadata_cache:
|
|
786
|
+
cached_time = self._metadata_cache[cache_key].get("avg_time_ms")
|
|
787
|
+
if cached_time:
|
|
788
|
+
return cached_time
|
|
789
|
+
|
|
790
|
+
# Estimate based on hook characteristics
|
|
791
|
+
filename = hook_path.lower()
|
|
792
|
+
|
|
793
|
+
# Hooks with git operations tend to be slower
|
|
794
|
+
if "git" in filename:
|
|
795
|
+
return 200.0 # 200ms estimate for git operations
|
|
796
|
+
|
|
797
|
+
# Hooks with network operations are slower
|
|
798
|
+
if any(keyword in filename for keyword in ["fetch", "api", "network"]):
|
|
799
|
+
return 500.0 # 500ms estimate for network operations
|
|
800
|
+
|
|
801
|
+
# Hooks with file I/O are moderate
|
|
802
|
+
if any(keyword in filename for keyword in ["read", "write", "parse"]):
|
|
803
|
+
return 50.0 # 50ms estimate for file I/O
|
|
804
|
+
|
|
805
|
+
# Simple hooks are fast
|
|
806
|
+
return 10.0 # 10ms estimate for simple operations
|
|
807
|
+
|
|
808
|
+
def _determine_phase_relevance(self, hook_path: str, event_type: HookEvent) -> Dict[Phase, float]:
|
|
809
|
+
"""Determine hook relevance to different development phases"""
|
|
810
|
+
filename = hook_path.lower()
|
|
811
|
+
relevance = {}
|
|
812
|
+
|
|
813
|
+
# Default relevance for all phases
|
|
814
|
+
default_relevance = 0.5
|
|
815
|
+
|
|
816
|
+
# SPEC phase relevance
|
|
817
|
+
if any(keyword in filename for keyword in ["spec", "plan", "design", "requirement"]):
|
|
818
|
+
relevance[Phase.SPEC] = 1.0
|
|
819
|
+
else:
|
|
820
|
+
relevance[Phase.SPEC] = default_relevance
|
|
821
|
+
|
|
822
|
+
# RED phase relevance (testing)
|
|
823
|
+
if any(keyword in filename for keyword in ["test", "red", "tdd", "assert"]):
|
|
824
|
+
relevance[Phase.RED] = 1.0
|
|
825
|
+
else:
|
|
826
|
+
relevance[Phase.RED] = default_relevance
|
|
827
|
+
|
|
828
|
+
# GREEN phase relevance (implementation)
|
|
829
|
+
if any(keyword in filename for keyword in ["implement", "code", "green", "build"]):
|
|
830
|
+
relevance[Phase.GREEN] = 1.0
|
|
831
|
+
else:
|
|
832
|
+
relevance[Phase.GREEN] = default_relevance
|
|
833
|
+
|
|
834
|
+
# REFACTOR phase relevance
|
|
835
|
+
if any(keyword in filename for keyword in ["refactor", "optimize", "improve", "clean"]):
|
|
836
|
+
relevance[Phase.REFACTOR] = 1.0
|
|
837
|
+
else:
|
|
838
|
+
relevance[Phase.REFACTOR] = default_relevance
|
|
839
|
+
|
|
840
|
+
# SYNC phase relevance (documentation)
|
|
841
|
+
if any(keyword in filename for keyword in ["sync", "doc", "document", "deploy"]):
|
|
842
|
+
relevance[Phase.SYNC] = 1.0
|
|
843
|
+
else:
|
|
844
|
+
relevance[Phase.SYNC] = default_relevance
|
|
845
|
+
|
|
846
|
+
# DEBUG phase relevance
|
|
847
|
+
if any(keyword in filename for keyword in ["debug", "error", "troubleshoot", "log"]):
|
|
848
|
+
relevance[Phase.DEBUG] = 1.0
|
|
849
|
+
else:
|
|
850
|
+
relevance[Phase.DEBUG] = default_relevance
|
|
851
|
+
|
|
852
|
+
# PLANNING phase relevance
|
|
853
|
+
if any(keyword in filename for keyword in ["plan", "analysis", "strategy"]):
|
|
854
|
+
relevance[Phase.PLANNING] = 1.0
|
|
855
|
+
else:
|
|
856
|
+
relevance[Phase.PLANNING] = default_relevance
|
|
857
|
+
|
|
858
|
+
return relevance
|
|
859
|
+
|
|
860
|
+
def _estimate_token_cost(self, hook_path: str) -> int:
|
|
861
|
+
"""Estimate token cost for hook execution"""
|
|
862
|
+
# Base token cost for any hook
|
|
863
|
+
base_cost = 100
|
|
864
|
+
|
|
865
|
+
# Additional cost based on hook characteristics
|
|
866
|
+
filename = hook_path.lower()
|
|
867
|
+
|
|
868
|
+
if any(keyword in filename for keyword in ["analysis", "report", "generate"]):
|
|
869
|
+
base_cost += 500 # Higher cost for analysis/generation
|
|
870
|
+
elif any(keyword in filename for keyword in ["log", "simple", "basic"]):
|
|
871
|
+
base_cost += 50 # Lower cost for simple operations
|
|
872
|
+
|
|
873
|
+
return base_cost
|
|
874
|
+
|
|
875
|
+
def _is_parallel_safe(self, hook_path: str) -> bool:
|
|
876
|
+
"""Determine if hook can be executed in parallel"""
|
|
877
|
+
filename = hook_path.lower()
|
|
878
|
+
|
|
879
|
+
# Hooks that modify shared state are not parallel safe
|
|
880
|
+
if any(keyword in filename for keyword in ["write", "modify", "update", "delete"]):
|
|
881
|
+
return False
|
|
882
|
+
|
|
883
|
+
# Hooks with external dependencies might not be parallel safe
|
|
884
|
+
if any(keyword in filename for keyword in ["database", "network", "api"]):
|
|
885
|
+
return False
|
|
886
|
+
|
|
887
|
+
# Most hooks are parallel safe by default
|
|
888
|
+
return True
|
|
889
|
+
|
|
890
|
+
async def execute_hooks(
|
|
891
|
+
self,
|
|
892
|
+
event_type: HookEvent,
|
|
893
|
+
context: Dict[str, Any],
|
|
894
|
+
user_input: Optional[str] = None,
|
|
895
|
+
phase: Optional[Phase] = None,
|
|
896
|
+
max_total_execution_time_ms: float = 15000.0,
|
|
897
|
+
) -> List[HookExecutionResult]:
|
|
898
|
+
"""Execute hooks for a specific event with JIT optimization
|
|
899
|
+
|
|
900
|
+
Args:
|
|
901
|
+
event_type: Type of hook event
|
|
902
|
+
context: Execution context data
|
|
903
|
+
user_input: User input for phase detection
|
|
904
|
+
phase: Current development phase (if known)
|
|
905
|
+
max_total_execution_time_ms: Maximum total execution time for all hooks
|
|
906
|
+
|
|
907
|
+
Returns:
|
|
908
|
+
List of hook execution results
|
|
909
|
+
"""
|
|
910
|
+
start_time = time.time()
|
|
911
|
+
|
|
912
|
+
# Detect phase if not provided
|
|
913
|
+
if phase is None and user_input:
|
|
914
|
+
try:
|
|
915
|
+
phase = self.jit_loader.phase_detector.detect_phase(user_input)
|
|
916
|
+
except AttributeError:
|
|
917
|
+
# Fallback if JIT loader doesn't have phase detector
|
|
918
|
+
phase = Phase.SPEC
|
|
919
|
+
|
|
920
|
+
# Get relevant hooks for this event
|
|
921
|
+
hook_paths = self._hooks_by_event.get(event_type, [])
|
|
922
|
+
|
|
923
|
+
# Filter and prioritize hooks based on phase and performance
|
|
924
|
+
prioritized_hooks = self._prioritize_hooks(hook_paths, phase)
|
|
925
|
+
|
|
926
|
+
# Load optimized context using JIT system
|
|
927
|
+
optimized_context = await self._load_optimized_context(event_type, context, phase, prioritized_hooks)
|
|
928
|
+
|
|
929
|
+
# Execute hooks with optimization
|
|
930
|
+
results = await self._execute_hooks_optimized(prioritized_hooks, optimized_context, max_total_execution_time_ms)
|
|
931
|
+
|
|
932
|
+
# Update performance metrics
|
|
933
|
+
if self.enable_performance_monitoring:
|
|
934
|
+
self._update_performance_metrics(event_type, phase, results, start_time)
|
|
935
|
+
|
|
936
|
+
return results
|
|
937
|
+
|
|
938
|
+
def _prioritize_hooks(self, hook_paths: List[str], phase: Optional[Phase]) -> List[Tuple[str, float]]:
|
|
939
|
+
"""Prioritize hooks based on phase relevance and performance characteristics
|
|
940
|
+
|
|
941
|
+
Args:
|
|
942
|
+
hook_paths: List of hook file paths
|
|
943
|
+
phase: Current development phase
|
|
944
|
+
|
|
945
|
+
Returns:
|
|
946
|
+
List of (hook_path, priority_score) tuples sorted by priority
|
|
947
|
+
"""
|
|
948
|
+
hook_priorities = []
|
|
949
|
+
|
|
950
|
+
for hook_path in hook_paths:
|
|
951
|
+
metadata = self._hook_registry.get(hook_path)
|
|
952
|
+
if not metadata:
|
|
953
|
+
continue
|
|
954
|
+
|
|
955
|
+
# Calculate priority score
|
|
956
|
+
priority_score = 0.0
|
|
957
|
+
|
|
958
|
+
# Base priority (lower number = higher priority)
|
|
959
|
+
priority_score += metadata.priority.value * 10
|
|
960
|
+
|
|
961
|
+
# Phase relevance bonus
|
|
962
|
+
if phase and phase in metadata.phase_relevance:
|
|
963
|
+
relevance = metadata.phase_relevance[phase]
|
|
964
|
+
priority_score -= relevance * 5 # Higher relevance = lower score (higher priority)
|
|
965
|
+
|
|
966
|
+
# Performance penalty (slower hooks get lower priority)
|
|
967
|
+
priority_score += metadata.estimated_execution_time_ms / 100
|
|
968
|
+
|
|
969
|
+
# Success rate bonus (more reliable hooks get higher priority)
|
|
970
|
+
if metadata.success_rate < 0.9:
|
|
971
|
+
priority_score += 5 # Penalize unreliable hooks
|
|
972
|
+
|
|
973
|
+
hook_priorities.append((hook_path, priority_score))
|
|
974
|
+
|
|
975
|
+
# Sort by priority score (lower is better)
|
|
976
|
+
hook_priorities.sort(key=lambda x: x[1])
|
|
977
|
+
|
|
978
|
+
return hook_priorities
|
|
979
|
+
|
|
980
|
+
async def _load_optimized_context(
|
|
981
|
+
self,
|
|
982
|
+
event_type: HookEvent,
|
|
983
|
+
context: Dict[str, Any],
|
|
984
|
+
phase: Optional[Phase],
|
|
985
|
+
prioritized_hooks: List[Tuple[str, float]],
|
|
986
|
+
) -> Dict[str, Any]:
|
|
987
|
+
"""Load optimized context using JIT system for hook execution
|
|
988
|
+
|
|
989
|
+
Args:
|
|
990
|
+
event_type: Hook event type
|
|
991
|
+
context: Original context
|
|
992
|
+
phase: Current development phase
|
|
993
|
+
prioritized_hooks: List of prioritized hooks
|
|
994
|
+
|
|
995
|
+
Returns:
|
|
996
|
+
Optimized context with relevant information
|
|
997
|
+
"""
|
|
998
|
+
# Create synthetic user input for context loading
|
|
999
|
+
synthetic_input = f"Hook execution for {event_type.value}"
|
|
1000
|
+
if phase:
|
|
1001
|
+
synthetic_input += f" during {phase.value} phase"
|
|
1002
|
+
|
|
1003
|
+
# Load context using JIT system
|
|
1004
|
+
try:
|
|
1005
|
+
jit_context, context_metrics = await self.jit_loader.load_context(
|
|
1006
|
+
user_input=synthetic_input, context=context
|
|
1007
|
+
)
|
|
1008
|
+
except (TypeError, AttributeError):
|
|
1009
|
+
# Fallback to basic context if JIT loader interface is different
|
|
1010
|
+
jit_context = context.copy()
|
|
1011
|
+
|
|
1012
|
+
# Add hook-specific context
|
|
1013
|
+
optimized_context = jit_context.copy()
|
|
1014
|
+
optimized_context.update(
|
|
1015
|
+
{
|
|
1016
|
+
"hook_event_type": event_type.value,
|
|
1017
|
+
"hook_phase": phase.value if phase else None,
|
|
1018
|
+
"hook_execution_mode": "optimized",
|
|
1019
|
+
"prioritized_hooks": [hook_path for hook_path, _ in prioritized_hooks[:5]], # Top 5 hooks
|
|
1020
|
+
}
|
|
1021
|
+
)
|
|
1022
|
+
|
|
1023
|
+
return optimized_context
|
|
1024
|
+
|
|
1025
|
+
async def _execute_hooks_optimized(
|
|
1026
|
+
self,
|
|
1027
|
+
prioritized_hooks: List[Tuple[str, float]],
|
|
1028
|
+
context: Dict[str, Any],
|
|
1029
|
+
max_total_execution_time_ms: float,
|
|
1030
|
+
) -> List[HookExecutionResult]:
|
|
1031
|
+
"""Execute hooks with optimization and time management
|
|
1032
|
+
|
|
1033
|
+
Args:
|
|
1034
|
+
prioritized_hooks: List of (hook_path, priority_score) tuples
|
|
1035
|
+
context: Optimized execution context
|
|
1036
|
+
max_total_execution_time_ms: Maximum total execution time
|
|
1037
|
+
|
|
1038
|
+
Returns:
|
|
1039
|
+
List of hook execution results
|
|
1040
|
+
"""
|
|
1041
|
+
results = []
|
|
1042
|
+
remaining_time = max_total_execution_time_ms
|
|
1043
|
+
|
|
1044
|
+
# Separate hooks into parallel-safe and sequential
|
|
1045
|
+
parallel_hooks = []
|
|
1046
|
+
sequential_hooks = []
|
|
1047
|
+
|
|
1048
|
+
for hook_path, _ in prioritized_hooks:
|
|
1049
|
+
metadata = self._hook_registry.get(hook_path)
|
|
1050
|
+
if metadata and metadata.parallel_safe:
|
|
1051
|
+
parallel_hooks.append(hook_path)
|
|
1052
|
+
else:
|
|
1053
|
+
sequential_hooks.append(hook_path)
|
|
1054
|
+
|
|
1055
|
+
# Execute parallel hooks first (faster)
|
|
1056
|
+
if parallel_hooks and remaining_time > 0:
|
|
1057
|
+
parallel_results = await self._execute_hooks_parallel(parallel_hooks, context, remaining_time)
|
|
1058
|
+
results.extend(parallel_results)
|
|
1059
|
+
|
|
1060
|
+
# Update remaining time
|
|
1061
|
+
total_parallel_time = sum(r.execution_time_ms for r in parallel_results)
|
|
1062
|
+
remaining_time -= total_parallel_time
|
|
1063
|
+
|
|
1064
|
+
# Execute sequential hooks with remaining time
|
|
1065
|
+
if sequential_hooks and remaining_time > 0:
|
|
1066
|
+
sequential_results = await self._execute_hooks_sequential(sequential_hooks, context, remaining_time)
|
|
1067
|
+
results.extend(sequential_results)
|
|
1068
|
+
|
|
1069
|
+
return results
|
|
1070
|
+
|
|
1071
|
+
async def _execute_hooks_parallel(
|
|
1072
|
+
self, hook_paths: List[str], context: Dict[str, Any], max_total_time_ms: float
|
|
1073
|
+
) -> List[HookExecutionResult]:
|
|
1074
|
+
"""Execute hooks in parallel with time management"""
|
|
1075
|
+
results = []
|
|
1076
|
+
|
|
1077
|
+
# Create semaphore to limit concurrent executions
|
|
1078
|
+
semaphore = asyncio.Semaphore(self.max_concurrent_hooks)
|
|
1079
|
+
|
|
1080
|
+
async def execute_single_hook(hook_path: str) -> Optional[HookExecutionResult]:
|
|
1081
|
+
async with semaphore:
|
|
1082
|
+
try:
|
|
1083
|
+
return await self._execute_single_hook(hook_path, context)
|
|
1084
|
+
except Exception as e:
|
|
1085
|
+
return HookExecutionResult(
|
|
1086
|
+
hook_path=hook_path,
|
|
1087
|
+
success=False,
|
|
1088
|
+
execution_time_ms=0.0,
|
|
1089
|
+
token_usage=0,
|
|
1090
|
+
output=None,
|
|
1091
|
+
error_message=str(e),
|
|
1092
|
+
)
|
|
1093
|
+
|
|
1094
|
+
# Execute hooks with timeout
|
|
1095
|
+
tasks = [execute_single_hook(hook_path) for hook_path in hook_paths]
|
|
1096
|
+
|
|
1097
|
+
try:
|
|
1098
|
+
# Wait for all hooks with total timeout
|
|
1099
|
+
completed_results = await asyncio.wait_for(
|
|
1100
|
+
asyncio.gather(*tasks, return_exceptions=True),
|
|
1101
|
+
timeout=max_total_time_ms / 1000.0,
|
|
1102
|
+
)
|
|
1103
|
+
|
|
1104
|
+
for result in completed_results:
|
|
1105
|
+
if isinstance(result, HookExecutionResult):
|
|
1106
|
+
results.append(result)
|
|
1107
|
+
elif isinstance(result, Exception):
|
|
1108
|
+
# Handle exceptions
|
|
1109
|
+
error_result = HookExecutionResult(
|
|
1110
|
+
hook_path="unknown",
|
|
1111
|
+
success=False,
|
|
1112
|
+
execution_time_ms=0.0,
|
|
1113
|
+
token_usage=0,
|
|
1114
|
+
output=None,
|
|
1115
|
+
error_message=str(result),
|
|
1116
|
+
)
|
|
1117
|
+
results.append(error_result)
|
|
1118
|
+
|
|
1119
|
+
except asyncio.TimeoutError:
|
|
1120
|
+
# Some hooks didn't complete in time
|
|
1121
|
+
pass
|
|
1122
|
+
|
|
1123
|
+
return results
|
|
1124
|
+
|
|
1125
|
+
async def _execute_hooks_sequential(
|
|
1126
|
+
self, hook_paths: List[str], context: Dict[str, Any], max_total_time_ms: float
|
|
1127
|
+
) -> List[HookExecutionResult]:
|
|
1128
|
+
"""Execute hooks sequentially with time management"""
|
|
1129
|
+
results = []
|
|
1130
|
+
remaining_time = max_total_time_ms
|
|
1131
|
+
|
|
1132
|
+
for hook_path in hook_paths:
|
|
1133
|
+
if remaining_time <= 0:
|
|
1134
|
+
break
|
|
1135
|
+
|
|
1136
|
+
try:
|
|
1137
|
+
result = await self._execute_single_hook(hook_path, context)
|
|
1138
|
+
results.append(result)
|
|
1139
|
+
|
|
1140
|
+
# Update remaining time
|
|
1141
|
+
execution_time = result.execution_time_ms
|
|
1142
|
+
remaining_time -= execution_time
|
|
1143
|
+
|
|
1144
|
+
except Exception as e:
|
|
1145
|
+
error_result = HookExecutionResult(
|
|
1146
|
+
hook_path=hook_path,
|
|
1147
|
+
success=False,
|
|
1148
|
+
execution_time_ms=0.0,
|
|
1149
|
+
token_usage=0,
|
|
1150
|
+
output=None,
|
|
1151
|
+
error_message=str(e),
|
|
1152
|
+
)
|
|
1153
|
+
results.append(error_result)
|
|
1154
|
+
|
|
1155
|
+
return results
|
|
1156
|
+
|
|
1157
|
+
async def _execute_single_hook(self, hook_path: str, context: Dict[str, Any]) -> HookExecutionResult:
|
|
1158
|
+
"""Execute a single hook with Phase 2 optimizations
|
|
1159
|
+
|
|
1160
|
+
Args:
|
|
1161
|
+
hook_path: Path to hook file
|
|
1162
|
+
context: Execution context
|
|
1163
|
+
|
|
1164
|
+
Returns:
|
|
1165
|
+
Hook execution result with enhanced monitoring and reliability
|
|
1166
|
+
"""
|
|
1167
|
+
start_time = time.time()
|
|
1168
|
+
full_hook_path = self.hooks_directory / hook_path
|
|
1169
|
+
|
|
1170
|
+
try:
|
|
1171
|
+
# Get metadata for the hook
|
|
1172
|
+
metadata = self._hook_registry.get(hook_path)
|
|
1173
|
+
if not metadata:
|
|
1174
|
+
raise ValueError(f"Hook metadata not found for {hook_path}")
|
|
1175
|
+
|
|
1176
|
+
# Initialize circuit breaker and retry policy for this hook if needed
|
|
1177
|
+
if hook_path not in self._circuit_breakers:
|
|
1178
|
+
self._circuit_breakers[hook_path] = CircuitBreaker(
|
|
1179
|
+
failure_threshold=self.circuit_breaker_threshold,
|
|
1180
|
+
timeout_seconds=60,
|
|
1181
|
+
success_threshold=5,
|
|
1182
|
+
)
|
|
1183
|
+
self._retry_policies[hook_path] = RetryPolicy(
|
|
1184
|
+
max_retries=self.max_retries, base_delay_ms=100, max_delay_ms=5000
|
|
1185
|
+
)
|
|
1186
|
+
|
|
1187
|
+
circuit_breaker = self._circuit_breakers[hook_path]
|
|
1188
|
+
retry_policy = self._retry_policies[hook_path]
|
|
1189
|
+
|
|
1190
|
+
# Check advanced cache first
|
|
1191
|
+
cache_key = f"hook_result:{hook_path}:{hash(str(context))}"
|
|
1192
|
+
cached_result = self._advanced_cache.get(cache_key)
|
|
1193
|
+
if cached_result:
|
|
1194
|
+
if cached_result.success:
|
|
1195
|
+
with self._performance_lock:
|
|
1196
|
+
self.metrics.cache_hits += 1
|
|
1197
|
+
return cached_result
|
|
1198
|
+
|
|
1199
|
+
# Execute with circuit breaker protection and retry logic
|
|
1200
|
+
async def execute_hook_with_retry():
|
|
1201
|
+
return await self._execute_hook_subprocess(full_hook_path, context, metadata)
|
|
1202
|
+
|
|
1203
|
+
# Apply circuit breaker and retry pattern
|
|
1204
|
+
try:
|
|
1205
|
+
result = await circuit_breaker.call(retry_policy.execute_with_retry, execute_hook_with_retry)
|
|
1206
|
+
except Exception as e:
|
|
1207
|
+
# Circuit breaker is OPEN or all retries exhausted
|
|
1208
|
+
execution_time = (time.time() - start_time) * 1000
|
|
1209
|
+
with self._performance_lock:
|
|
1210
|
+
if circuit_breaker.state.state == "OPEN":
|
|
1211
|
+
self.metrics.circuit_breaker_trips += 1
|
|
1212
|
+
|
|
1213
|
+
self._logger.warning(f"Hook {hook_path} failed due to circuit breaker: {str(e)}")
|
|
1214
|
+
|
|
1215
|
+
return HookExecutionResult(
|
|
1216
|
+
hook_path=hook_path,
|
|
1217
|
+
success=False,
|
|
1218
|
+
execution_time_ms=execution_time,
|
|
1219
|
+
token_usage=0,
|
|
1220
|
+
output=None,
|
|
1221
|
+
error_message=f"Circuit breaker OPEN: {str(e)}",
|
|
1222
|
+
metadata={"circuit_breaker_state": circuit_breaker.state.state},
|
|
1223
|
+
)
|
|
1224
|
+
|
|
1225
|
+
# Update resource usage metrics
|
|
1226
|
+
current_resources = self._resource_monitor.get_current_metrics()
|
|
1227
|
+
with self._performance_lock:
|
|
1228
|
+
self.metrics.resource_usage = current_resources
|
|
1229
|
+
|
|
1230
|
+
# Performance anomaly detection
|
|
1231
|
+
anomaly = self._anomaly_detector.detect_anomaly(hook_path, result.execution_time_ms)
|
|
1232
|
+
if anomaly:
|
|
1233
|
+
self._logger.warning(f"Performance anomaly detected for {hook_path}: {anomaly}")
|
|
1234
|
+
result.metadata["performance_anomaly"] = anomaly
|
|
1235
|
+
|
|
1236
|
+
# Cache successful results with TTL based on hook characteristics
|
|
1237
|
+
if result.success:
|
|
1238
|
+
cache_ttl = self._determine_cache_ttl(hook_path, metadata)
|
|
1239
|
+
self._advanced_cache.put(cache_key, result, ttl_seconds=cache_ttl)
|
|
1240
|
+
|
|
1241
|
+
# Update cache statistics
|
|
1242
|
+
with self._performance_lock:
|
|
1243
|
+
self.metrics.cache_misses += 1
|
|
1244
|
+
|
|
1245
|
+
# Update execution profile for performance monitoring
|
|
1246
|
+
self._execution_profiles[hook_path].append(result.execution_time_ms)
|
|
1247
|
+
if len(self._execution_profiles[hook_path]) > 100:
|
|
1248
|
+
self._execution_profiles[hook_path].pop(0)
|
|
1249
|
+
|
|
1250
|
+
# Update metadata
|
|
1251
|
+
self._update_hook_metadata(hook_path, result)
|
|
1252
|
+
|
|
1253
|
+
return result
|
|
1254
|
+
|
|
1255
|
+
except Exception as e:
|
|
1256
|
+
execution_time = (time.time() - start_time) * 1000
|
|
1257
|
+
self._logger.error(f"Unexpected error executing hook {hook_path}: {str(e)}")
|
|
1258
|
+
|
|
1259
|
+
return HookExecutionResult(
|
|
1260
|
+
hook_path=hook_path,
|
|
1261
|
+
success=False,
|
|
1262
|
+
execution_time_ms=execution_time,
|
|
1263
|
+
token_usage=0,
|
|
1264
|
+
output=None,
|
|
1265
|
+
error_message=f"Unexpected error: {str(e)}",
|
|
1266
|
+
)
|
|
1267
|
+
|
|
1268
|
+
def _determine_cache_ttl(self, hook_path: str, metadata: HookMetadata) -> int:
|
|
1269
|
+
"""Determine optimal cache TTL based on hook characteristics"""
|
|
1270
|
+
filename = hook_path.lower()
|
|
1271
|
+
|
|
1272
|
+
# Hooks that fetch external data should have shorter TTL
|
|
1273
|
+
if any(keyword in filename for keyword in ["fetch", "api", "network", "git"]):
|
|
1274
|
+
return 60 # 1 minute
|
|
1275
|
+
|
|
1276
|
+
# Hooks that read static files can have longer TTL
|
|
1277
|
+
if any(keyword in filename for keyword in ["read", "parse", "analyze"]):
|
|
1278
|
+
return 1800 # 30 minutes
|
|
1279
|
+
|
|
1280
|
+
# Hooks that write or modify data should have very short TTL
|
|
1281
|
+
if any(keyword in filename for keyword in ["write", "modify", "update", "create"]):
|
|
1282
|
+
return 30 # 30 seconds
|
|
1283
|
+
|
|
1284
|
+
# Default TTL
|
|
1285
|
+
return 300 # 5 minutes
|
|
1286
|
+
|
|
1287
|
+
async def _execute_hook_subprocess(
|
|
1288
|
+
self, hook_path: Path, context: Dict[str, Any], metadata: HookMetadata
|
|
1289
|
+
) -> HookExecutionResult:
|
|
1290
|
+
"""Execute hook in isolated subprocess
|
|
1291
|
+
|
|
1292
|
+
Args:
|
|
1293
|
+
hook_path: Full path to hook file
|
|
1294
|
+
context: Execution context
|
|
1295
|
+
metadata: Hook metadata
|
|
1296
|
+
|
|
1297
|
+
Returns:
|
|
1298
|
+
Hook execution result
|
|
1299
|
+
"""
|
|
1300
|
+
start_time = time.time()
|
|
1301
|
+
|
|
1302
|
+
try:
|
|
1303
|
+
# Prepare input for hook
|
|
1304
|
+
hook_input = json.dumps(context)
|
|
1305
|
+
|
|
1306
|
+
# Execute hook with timeout
|
|
1307
|
+
timeout_seconds = max(1.0, metadata.estimated_execution_time_ms / 1000.0)
|
|
1308
|
+
|
|
1309
|
+
process = await asyncio.create_subprocess_exec(
|
|
1310
|
+
"uv",
|
|
1311
|
+
"run",
|
|
1312
|
+
str(hook_path),
|
|
1313
|
+
stdin=asyncio.subprocess.PIPE,
|
|
1314
|
+
stdout=asyncio.subprocess.PIPE,
|
|
1315
|
+
stderr=asyncio.subprocess.PIPE,
|
|
1316
|
+
cwd=Path.cwd(),
|
|
1317
|
+
)
|
|
1318
|
+
|
|
1319
|
+
try:
|
|
1320
|
+
stdout, stderr = await asyncio.wait_for(
|
|
1321
|
+
process.communicate(input=hook_input.encode()),
|
|
1322
|
+
timeout=timeout_seconds,
|
|
1323
|
+
)
|
|
1324
|
+
except asyncio.TimeoutError:
|
|
1325
|
+
process.kill()
|
|
1326
|
+
await process.wait()
|
|
1327
|
+
raise TimeoutError(f"Hook execution timed out after {timeout_seconds}s")
|
|
1328
|
+
|
|
1329
|
+
execution_time_ms = (time.time() - start_time) * 1000
|
|
1330
|
+
success = process.returncode == 0
|
|
1331
|
+
|
|
1332
|
+
# Parse output
|
|
1333
|
+
output = None
|
|
1334
|
+
if stdout:
|
|
1335
|
+
try:
|
|
1336
|
+
output = json.loads(stdout.decode())
|
|
1337
|
+
except json.JSONDecodeError:
|
|
1338
|
+
output = stdout.decode()
|
|
1339
|
+
|
|
1340
|
+
error_message = None
|
|
1341
|
+
if stderr:
|
|
1342
|
+
error_message = stderr.decode().strip()
|
|
1343
|
+
elif process.returncode != 0:
|
|
1344
|
+
error_message = f"Hook exited with code {process.returncode}"
|
|
1345
|
+
|
|
1346
|
+
return HookExecutionResult(
|
|
1347
|
+
hook_path=str(hook_path.relative_to(self.hooks_directory)),
|
|
1348
|
+
success=success,
|
|
1349
|
+
execution_time_ms=execution_time_ms,
|
|
1350
|
+
token_usage=metadata.token_cost_estimate,
|
|
1351
|
+
output=output,
|
|
1352
|
+
error_message=error_message,
|
|
1353
|
+
)
|
|
1354
|
+
|
|
1355
|
+
except Exception as e:
|
|
1356
|
+
execution_time_ms = (time.time() - start_time) * 1000
|
|
1357
|
+
|
|
1358
|
+
return HookExecutionResult(
|
|
1359
|
+
hook_path=str(hook_path.relative_to(self.hooks_directory)),
|
|
1360
|
+
success=False,
|
|
1361
|
+
execution_time_ms=execution_time_ms,
|
|
1362
|
+
token_usage=metadata.token_cost_estimate,
|
|
1363
|
+
output=None,
|
|
1364
|
+
error_message=str(e),
|
|
1365
|
+
)
|
|
1366
|
+
|
|
1367
|
+
def _update_hook_metadata(self, hook_path: str, result: HookExecutionResult) -> None:
|
|
1368
|
+
"""Update hook metadata based on execution result"""
|
|
1369
|
+
metadata = self._hook_registry.get(hook_path)
|
|
1370
|
+
if not metadata:
|
|
1371
|
+
return
|
|
1372
|
+
|
|
1373
|
+
# Update execution time estimate
|
|
1374
|
+
cache_key = f"exec_time:{hook_path}"
|
|
1375
|
+
if cache_key not in self._metadata_cache:
|
|
1376
|
+
self._metadata_cache[cache_key] = {"count": 0, "total_time": 0.0}
|
|
1377
|
+
|
|
1378
|
+
cache_entry = self._metadata_cache[cache_key]
|
|
1379
|
+
cache_entry["count"] += 1
|
|
1380
|
+
cache_entry["total_time"] += result.execution_time_ms
|
|
1381
|
+
cache_entry["avg_time_ms"] = cache_entry["total_time"] / cache_entry["count"]
|
|
1382
|
+
|
|
1383
|
+
# Update success rate
|
|
1384
|
+
metadata.success_rate = (metadata.success_rate * 0.8) + (1.0 if result.success else 0.0) * 0.2
|
|
1385
|
+
metadata.last_execution_time = datetime.now()
|
|
1386
|
+
|
|
1387
|
+
def _update_performance_metrics(
|
|
1388
|
+
self,
|
|
1389
|
+
event_type: HookEvent,
|
|
1390
|
+
phase: Optional[Phase],
|
|
1391
|
+
results: List[HookExecutionResult],
|
|
1392
|
+
start_time: float,
|
|
1393
|
+
) -> None:
|
|
1394
|
+
"""Update performance metrics"""
|
|
1395
|
+
with self._performance_lock:
|
|
1396
|
+
self.metrics.total_executions += len(results)
|
|
1397
|
+
self.metrics.successful_executions += sum(1 for r in results if r.success)
|
|
1398
|
+
|
|
1399
|
+
total_execution_time = sum(r.execution_time_ms for r in results)
|
|
1400
|
+
self.metrics.average_execution_time_ms = (self.metrics.average_execution_time_ms * 0.9) + (
|
|
1401
|
+
total_execution_time / len(results) * 0.1
|
|
1402
|
+
)
|
|
1403
|
+
|
|
1404
|
+
self.metrics.total_token_usage += sum(r.token_usage for r in results)
|
|
1405
|
+
|
|
1406
|
+
if phase:
|
|
1407
|
+
self.metrics.phase_distribution[phase] = self.metrics.phase_distribution.get(phase, 0) + 1
|
|
1408
|
+
|
|
1409
|
+
self.metrics.event_type_distribution[event_type] = (
|
|
1410
|
+
self.metrics.event_type_distribution.get(event_type, 0) + 1
|
|
1411
|
+
)
|
|
1412
|
+
|
|
1413
|
+
# Log performance data
|
|
1414
|
+
self._log_performance_data(event_type, phase, results, start_time)
|
|
1415
|
+
|
|
1416
|
+
def _log_performance_data(
|
|
1417
|
+
self,
|
|
1418
|
+
event_type: HookEvent,
|
|
1419
|
+
phase: Optional[Phase],
|
|
1420
|
+
results: List[HookExecutionResult],
|
|
1421
|
+
start_time: float,
|
|
1422
|
+
) -> None:
|
|
1423
|
+
"""Log performance data to file"""
|
|
1424
|
+
log_entry = {
|
|
1425
|
+
"timestamp": datetime.now().isoformat(),
|
|
1426
|
+
"event_type": event_type.value,
|
|
1427
|
+
"phase": phase.value if phase else None,
|
|
1428
|
+
"total_hooks": len(results),
|
|
1429
|
+
"successful_hooks": sum(1 for r in results if r.success),
|
|
1430
|
+
"total_execution_time_ms": sum(r.execution_time_ms for r in results),
|
|
1431
|
+
"total_token_usage": sum(r.token_usage for r in results),
|
|
1432
|
+
"system_time_ms": (time.time() - start_time) * 1000,
|
|
1433
|
+
"results": [
|
|
1434
|
+
{
|
|
1435
|
+
"hook_path": r.hook_path,
|
|
1436
|
+
"success": r.success,
|
|
1437
|
+
"execution_time_ms": r.execution_time_ms,
|
|
1438
|
+
"token_usage": r.token_usage,
|
|
1439
|
+
"error_message": r.error_message,
|
|
1440
|
+
}
|
|
1441
|
+
for r in results
|
|
1442
|
+
],
|
|
1443
|
+
}
|
|
1444
|
+
|
|
1445
|
+
try:
|
|
1446
|
+
with open(self._performance_log_path, "a") as f:
|
|
1447
|
+
f.write(json.dumps(log_entry) + "\n")
|
|
1448
|
+
except Exception:
|
|
1449
|
+
pass # Silently fail on logging
|
|
1450
|
+
|
|
1451
|
+
def get_performance_metrics(self) -> HookPerformanceMetrics:
|
|
1452
|
+
"""Get comprehensive performance metrics with Phase 2 enhancements"""
|
|
1453
|
+
with self._performance_lock:
|
|
1454
|
+
# Get advanced cache stats
|
|
1455
|
+
self._advanced_cache.get_stats()
|
|
1456
|
+
|
|
1457
|
+
# Calculate performance profiles summary
|
|
1458
|
+
self._calculate_performance_summary()
|
|
1459
|
+
|
|
1460
|
+
# Get peak resource usage
|
|
1461
|
+
self._resource_monitor.get_peak_metrics()
|
|
1462
|
+
|
|
1463
|
+
return HookPerformanceMetrics(
|
|
1464
|
+
total_executions=self.metrics.total_executions,
|
|
1465
|
+
successful_executions=self.metrics.successful_executions,
|
|
1466
|
+
average_execution_time_ms=self.metrics.average_execution_time_ms,
|
|
1467
|
+
total_token_usage=self.metrics.total_token_usage,
|
|
1468
|
+
cache_hits=self.metrics.cache_hits,
|
|
1469
|
+
cache_misses=self.metrics.cache_misses,
|
|
1470
|
+
phase_distribution=self.metrics.phase_distribution.copy(),
|
|
1471
|
+
event_type_distribution=self.metrics.event_type_distribution.copy(),
|
|
1472
|
+
circuit_breaker_trips=self.metrics.circuit_breaker_trips,
|
|
1473
|
+
retry_attempts=self.metrics.retry_attempts,
|
|
1474
|
+
resource_usage=ResourceUsageMetrics(
|
|
1475
|
+
cpu_usage_percent=self.metrics.resource_usage.cpu_usage_percent,
|
|
1476
|
+
memory_usage_mb=self.metrics.resource_usage.memory_usage_mb,
|
|
1477
|
+
disk_io_mb=self.metrics.resource_usage.disk_io_mb,
|
|
1478
|
+
network_io_mb=self.metrics.resource_usage.network_io_mb,
|
|
1479
|
+
open_files=self.metrics.resource_usage.open_files,
|
|
1480
|
+
thread_count=self.metrics.resource_usage.thread_count,
|
|
1481
|
+
),
|
|
1482
|
+
)
|
|
1483
|
+
|
|
1484
|
+
def _calculate_performance_summary(self) -> Dict[str, Any]:
|
|
1485
|
+
"""Calculate detailed performance summary"""
|
|
1486
|
+
hook_performance: Dict[str, Dict[str, Any]] = {}
|
|
1487
|
+
summary: Dict[str, Any] = {
|
|
1488
|
+
"hook_performance": hook_performance,
|
|
1489
|
+
"cache_efficiency": 0.0,
|
|
1490
|
+
"overall_health": "healthy",
|
|
1491
|
+
}
|
|
1492
|
+
|
|
1493
|
+
# Calculate cache efficiency
|
|
1494
|
+
total_cache_requests = self.metrics.cache_hits + self.metrics.cache_misses
|
|
1495
|
+
if total_cache_requests > 0:
|
|
1496
|
+
summary["cache_efficiency"] = self.metrics.cache_hits / total_cache_requests
|
|
1497
|
+
|
|
1498
|
+
# Calculate per-hook performance statistics
|
|
1499
|
+
for hook_path, execution_times in self._execution_profiles.items():
|
|
1500
|
+
if execution_times:
|
|
1501
|
+
hook_performance[hook_path] = {
|
|
1502
|
+
"avg_time_ms": sum(execution_times) / len(execution_times),
|
|
1503
|
+
"min_time_ms": min(execution_times),
|
|
1504
|
+
"max_time_ms": max(execution_times),
|
|
1505
|
+
"execution_count": len(execution_times),
|
|
1506
|
+
"std_dev_ms": self._calculate_std_dev(execution_times),
|
|
1507
|
+
}
|
|
1508
|
+
|
|
1509
|
+
# Determine overall health
|
|
1510
|
+
success_rate = self.metrics.successful_executions / max(self.metrics.total_executions, 1)
|
|
1511
|
+
if success_rate < 0.9:
|
|
1512
|
+
summary["overall_health"] = "degraded"
|
|
1513
|
+
elif success_rate < 0.7:
|
|
1514
|
+
summary["overall_health"] = "unhealthy"
|
|
1515
|
+
|
|
1516
|
+
return summary
|
|
1517
|
+
|
|
1518
|
+
def _calculate_std_dev(self, values: List[float]) -> float:
|
|
1519
|
+
"""Calculate standard deviation"""
|
|
1520
|
+
if len(values) < 2:
|
|
1521
|
+
return 0.0
|
|
1522
|
+
mean = sum(values) / len(values)
|
|
1523
|
+
variance = sum((x - mean) ** 2 for x in values) / len(values)
|
|
1524
|
+
return variance**0.5
|
|
1525
|
+
|
|
1526
|
+
async def get_system_health_report(self) -> Dict[str, Any]:
|
|
1527
|
+
"""Get comprehensive health report"""
|
|
1528
|
+
return await self._health_checker.check_system_health()
|
|
1529
|
+
|
|
1530
|
+
def get_connection_pool_stats(self) -> Dict[str, Any]:
|
|
1531
|
+
"""Get connection pool statistics"""
|
|
1532
|
+
return self._connection_pool.get_pool_stats()
|
|
1533
|
+
|
|
1534
|
+
def get_advanced_cache_stats(self) -> Dict[str, Any]:
|
|
1535
|
+
"""Get advanced cache statistics"""
|
|
1536
|
+
return self._advanced_cache.get_stats()
|
|
1537
|
+
|
|
1538
|
+
def get_circuit_breaker_status(self) -> Dict[str, Any]:
|
|
1539
|
+
"""Get circuit breaker status for all hooks"""
|
|
1540
|
+
return {
|
|
1541
|
+
hook_path: {
|
|
1542
|
+
"state": cb.state.state,
|
|
1543
|
+
"failure_count": cb.state.failure_count,
|
|
1544
|
+
"last_failure_time": (cb.state.last_failure_time.isoformat() if cb.state.last_failure_time else None),
|
|
1545
|
+
"success_threshold": cb.state.success_threshold,
|
|
1546
|
+
}
|
|
1547
|
+
for hook_path, cb in self._circuit_breakers.items()
|
|
1548
|
+
}
|
|
1549
|
+
|
|
1550
|
+
def get_hook_recommendations(
|
|
1551
|
+
self, event_type: Optional[HookEvent] = None, phase: Optional[Phase] = None
|
|
1552
|
+
) -> Dict[str, Any]:
|
|
1553
|
+
"""Get recommendations for hook optimization
|
|
1554
|
+
|
|
1555
|
+
Args:
|
|
1556
|
+
event_type: Specific event type to analyze
|
|
1557
|
+
phase: Specific phase to analyze
|
|
1558
|
+
|
|
1559
|
+
Returns:
|
|
1560
|
+
Dictionary with optimization recommendations
|
|
1561
|
+
"""
|
|
1562
|
+
recommendations: Dict[str, List[Any]] = {
|
|
1563
|
+
"slow_hooks": [],
|
|
1564
|
+
"unreliable_hooks": [],
|
|
1565
|
+
"phase_mismatched_hooks": [],
|
|
1566
|
+
"optimization_suggestions": [],
|
|
1567
|
+
}
|
|
1568
|
+
|
|
1569
|
+
# Analyze hook performance
|
|
1570
|
+
for hook_path, metadata in self._hook_registry.items():
|
|
1571
|
+
if event_type and metadata.event_type != event_type:
|
|
1572
|
+
continue
|
|
1573
|
+
|
|
1574
|
+
# Check for slow hooks
|
|
1575
|
+
if metadata.estimated_execution_time_ms > 200:
|
|
1576
|
+
recommendations["slow_hooks"].append(
|
|
1577
|
+
{
|
|
1578
|
+
"hook_path": hook_path,
|
|
1579
|
+
"estimated_time_ms": metadata.estimated_execution_time_ms,
|
|
1580
|
+
"suggestion": "Consider optimizing or making this hook parallel-safe",
|
|
1581
|
+
}
|
|
1582
|
+
)
|
|
1583
|
+
|
|
1584
|
+
# Check for unreliable hooks
|
|
1585
|
+
if metadata.success_rate < 0.8:
|
|
1586
|
+
recommendations["unreliable_hooks"].append(
|
|
1587
|
+
{
|
|
1588
|
+
"hook_path": hook_path,
|
|
1589
|
+
"success_rate": metadata.success_rate,
|
|
1590
|
+
"suggestion": "Review error handling and improve reliability",
|
|
1591
|
+
}
|
|
1592
|
+
)
|
|
1593
|
+
|
|
1594
|
+
# Check for phase mismatch
|
|
1595
|
+
if phase:
|
|
1596
|
+
relevance = metadata.phase_relevance.get(phase, 0.0)
|
|
1597
|
+
if relevance < 0.3:
|
|
1598
|
+
recommendations["phase_mismatched_hooks"].append(
|
|
1599
|
+
{
|
|
1600
|
+
"hook_path": hook_path,
|
|
1601
|
+
"phase": phase.value,
|
|
1602
|
+
"relevance": relevance,
|
|
1603
|
+
"suggestion": "This hook may not be relevant for the current phase",
|
|
1604
|
+
}
|
|
1605
|
+
)
|
|
1606
|
+
|
|
1607
|
+
# Generate optimization suggestions
|
|
1608
|
+
if recommendations["slow_hooks"]:
|
|
1609
|
+
recommendations["optimization_suggestions"].append(
|
|
1610
|
+
"Consider implementing caching for frequently executed slow hooks"
|
|
1611
|
+
)
|
|
1612
|
+
|
|
1613
|
+
if recommendations["unreliable_hooks"]:
|
|
1614
|
+
recommendations["optimization_suggestions"].append(
|
|
1615
|
+
"Add retry logic and better error handling for unreliable hooks"
|
|
1616
|
+
)
|
|
1617
|
+
|
|
1618
|
+
if recommendations["phase_mismatched_hooks"]:
|
|
1619
|
+
recommendations["optimization_suggestions"].append(
|
|
1620
|
+
"Use phase-based hook filtering to skip irrelevant hooks"
|
|
1621
|
+
)
|
|
1622
|
+
|
|
1623
|
+
return recommendations
|
|
1624
|
+
|
|
1625
|
+
async def cleanup(self) -> None:
|
|
1626
|
+
"""Enhanced cleanup with Phase 2 resource management"""
|
|
1627
|
+
try:
|
|
1628
|
+
# Save comprehensive performance metrics and state
|
|
1629
|
+
metrics_file = self.cache_directory / "metrics.json"
|
|
1630
|
+
state_file = self.cache_directory / "state.json"
|
|
1631
|
+
|
|
1632
|
+
# Get current metrics
|
|
1633
|
+
current_metrics = self.get_performance_metrics()
|
|
1634
|
+
health_report = await self.get_system_health_report()
|
|
1635
|
+
|
|
1636
|
+
metrics_data = {
|
|
1637
|
+
"timestamp": datetime.now().isoformat(),
|
|
1638
|
+
"phase": "phase_2_optimized",
|
|
1639
|
+
"metrics": {
|
|
1640
|
+
"total_executions": current_metrics.total_executions,
|
|
1641
|
+
"successful_executions": current_metrics.successful_executions,
|
|
1642
|
+
"average_execution_time_ms": current_metrics.average_execution_time_ms,
|
|
1643
|
+
"total_token_usage": current_metrics.total_token_usage,
|
|
1644
|
+
"cache_hits": current_metrics.cache_hits,
|
|
1645
|
+
"cache_misses": current_metrics.cache_misses,
|
|
1646
|
+
"circuit_breaker_trips": current_metrics.circuit_breaker_trips,
|
|
1647
|
+
"retry_attempts": current_metrics.retry_attempts,
|
|
1648
|
+
"resource_usage": current_metrics.resource_usage.__dict__,
|
|
1649
|
+
"phase_distribution": {k.value: v for k, v in current_metrics.phase_distribution.items()},
|
|
1650
|
+
"event_type_distribution": {k.value: v for k, v in current_metrics.event_type_distribution.items()},
|
|
1651
|
+
},
|
|
1652
|
+
"health_status": health_report,
|
|
1653
|
+
"cache_stats": self.get_advanced_cache_stats(),
|
|
1654
|
+
"connection_pool_stats": self.get_connection_pool_stats(),
|
|
1655
|
+
"circuit_breaker_status": self.get_circuit_breaker_status(),
|
|
1656
|
+
"hook_metadata": {
|
|
1657
|
+
hook_path: {
|
|
1658
|
+
"estimated_execution_time_ms": metadata.estimated_execution_time_ms,
|
|
1659
|
+
"success_rate": metadata.success_rate,
|
|
1660
|
+
"last_execution_time": (
|
|
1661
|
+
metadata.last_execution_time.isoformat() if metadata.last_execution_time else None
|
|
1662
|
+
),
|
|
1663
|
+
"priority": metadata.priority.value,
|
|
1664
|
+
"parallel_safe": metadata.parallel_safe,
|
|
1665
|
+
"token_cost_estimate": metadata.token_cost_estimate,
|
|
1666
|
+
}
|
|
1667
|
+
for hook_path, metadata in self._hook_registry.items()
|
|
1668
|
+
},
|
|
1669
|
+
"performance_profiles": {
|
|
1670
|
+
hook_path: {
|
|
1671
|
+
"execution_times": times[-10:], # Keep last 10 execution times
|
|
1672
|
+
"avg_time_ms": sum(times) / len(times) if times else 0,
|
|
1673
|
+
"count": len(times),
|
|
1674
|
+
}
|
|
1675
|
+
for hook_path, times in self._execution_profiles.items()
|
|
1676
|
+
if times
|
|
1677
|
+
},
|
|
1678
|
+
}
|
|
1679
|
+
|
|
1680
|
+
# Save metrics
|
|
1681
|
+
with open(metrics_file, "w") as f:
|
|
1682
|
+
json.dump(metrics_data, f, indent=2)
|
|
1683
|
+
|
|
1684
|
+
# Save state for recovery
|
|
1685
|
+
state_data = {
|
|
1686
|
+
"timestamp": datetime.now().isoformat(),
|
|
1687
|
+
"circuit_breaker_states": self.get_circuit_breaker_status(),
|
|
1688
|
+
"cache_config": {
|
|
1689
|
+
"max_size": self._advanced_cache.max_size,
|
|
1690
|
+
"default_ttl_seconds": self._advanced_cache.default_ttl_seconds,
|
|
1691
|
+
},
|
|
1692
|
+
"connection_pool_config": {
|
|
1693
|
+
"max_connections": self._connection_pool.max_connections,
|
|
1694
|
+
"connection_timeout_seconds": self._connection_pool.connection_timeout_seconds,
|
|
1695
|
+
},
|
|
1696
|
+
"optimization_config": {
|
|
1697
|
+
"circuit_breaker_threshold": self.circuit_breaker_threshold,
|
|
1698
|
+
"max_retries": self.max_retries,
|
|
1699
|
+
},
|
|
1700
|
+
}
|
|
1701
|
+
|
|
1702
|
+
with open(state_file, "w") as f:
|
|
1703
|
+
json.dump(state_data, f, indent=2)
|
|
1704
|
+
|
|
1705
|
+
except Exception as e:
|
|
1706
|
+
if hasattr(self, "_logger"):
|
|
1707
|
+
self._logger.error(f"Error during cleanup: {str(e)}")
|
|
1708
|
+
|
|
1709
|
+
finally:
|
|
1710
|
+
# Clear all caches and resources
|
|
1711
|
+
try:
|
|
1712
|
+
self._advanced_cache.invalidate() # Clear all cache entries
|
|
1713
|
+
self._metadata_cache.clear()
|
|
1714
|
+
|
|
1715
|
+
# Reset circuit breakers
|
|
1716
|
+
for circuit_breaker in self._circuit_breakers.values():
|
|
1717
|
+
circuit_breaker.state.state = "CLOSED"
|
|
1718
|
+
circuit_breaker.state.failure_count = 0
|
|
1719
|
+
circuit_breaker.state.last_failure_time = None
|
|
1720
|
+
|
|
1721
|
+
# Clear execution profiles
|
|
1722
|
+
self._execution_profiles.clear()
|
|
1723
|
+
|
|
1724
|
+
except Exception as e:
|
|
1725
|
+
if hasattr(self, "_logger"):
|
|
1726
|
+
self._logger.error(f"Error during cache cleanup: {str(e)}")
|
|
1727
|
+
|
|
1728
|
+
# Log peak resource usage for monitoring
|
|
1729
|
+
try:
|
|
1730
|
+
peak_resources = self._resource_monitor.get_peak_metrics()
|
|
1731
|
+
if hasattr(self, "_logger"):
|
|
1732
|
+
self._logger.info(
|
|
1733
|
+
f"Peak resource usage - Memory: {peak_resources.memory_usage_mb:.1f}MB, "
|
|
1734
|
+
f"CPU: {peak_resources.cpu_usage_percent:.1f}%, "
|
|
1735
|
+
f"Threads: {peak_resources.thread_count}"
|
|
1736
|
+
)
|
|
1737
|
+
except Exception:
|
|
1738
|
+
pass # Ignore cleanup logging errors
|
|
1739
|
+
|
|
1740
|
+
|
|
1741
|
+
# Global instance for easy access
|
|
1742
|
+
_jit_hook_manager: Optional[JITEnhancedHookManager] = None
|
|
1743
|
+
|
|
1744
|
+
|
|
1745
|
+
def get_jit_hook_manager() -> JITEnhancedHookManager:
|
|
1746
|
+
"""Get or create global JIT hook manager instance"""
|
|
1747
|
+
global _jit_hook_manager
|
|
1748
|
+
if _jit_hook_manager is None:
|
|
1749
|
+
_jit_hook_manager = JITEnhancedHookManager()
|
|
1750
|
+
return _jit_hook_manager
|
|
1751
|
+
|
|
1752
|
+
|
|
1753
|
+
# Convenience functions for common hook operations
|
|
1754
|
+
async def execute_session_start_hooks(
|
|
1755
|
+
context: Dict[str, Any], user_input: Optional[str] = None
|
|
1756
|
+
) -> List[HookExecutionResult]:
|
|
1757
|
+
"""Execute SessionStart hooks with JIT optimization"""
|
|
1758
|
+
manager = get_jit_hook_manager()
|
|
1759
|
+
return await manager.execute_hooks(HookEvent.SESSION_START, context, user_input=user_input)
|
|
1760
|
+
|
|
1761
|
+
|
|
1762
|
+
async def execute_pre_tool_hooks(
|
|
1763
|
+
context: Dict[str, Any], user_input: Optional[str] = None
|
|
1764
|
+
) -> List[HookExecutionResult]:
|
|
1765
|
+
"""Execute PreToolUse hooks with JIT optimization"""
|
|
1766
|
+
manager = get_jit_hook_manager()
|
|
1767
|
+
return await manager.execute_hooks(HookEvent.PRE_TOOL_USE, context, user_input=user_input)
|
|
1768
|
+
|
|
1769
|
+
|
|
1770
|
+
async def execute_session_end_hooks(
|
|
1771
|
+
context: Dict[str, Any], user_input: Optional[str] = None
|
|
1772
|
+
) -> List[HookExecutionResult]:
|
|
1773
|
+
"""Execute SessionEnd hooks with JIT optimization"""
|
|
1774
|
+
manager = get_jit_hook_manager()
|
|
1775
|
+
return await manager.execute_hooks(HookEvent.SESSION_END, context, user_input=user_input)
|
|
1776
|
+
|
|
1777
|
+
|
|
1778
|
+
def get_hook_performance_metrics() -> HookPerformanceMetrics:
|
|
1779
|
+
"""Get current hook performance metrics"""
|
|
1780
|
+
manager = get_jit_hook_manager()
|
|
1781
|
+
return manager.get_performance_metrics()
|
|
1782
|
+
|
|
1783
|
+
|
|
1784
|
+
def get_hook_optimization_recommendations(
|
|
1785
|
+
event_type: Optional[HookEvent] = None, phase: Optional[Phase] = None
|
|
1786
|
+
) -> Dict[str, Any]:
|
|
1787
|
+
"""Get hook optimization recommendations"""
|
|
1788
|
+
manager = get_jit_hook_manager()
|
|
1789
|
+
return manager.get_hook_recommendations(event_type, phase)
|
|
1790
|
+
|
|
1791
|
+
|
|
1792
|
+
# Phase 2 convenience functions for enhanced monitoring and control
|
|
1793
|
+
|
|
1794
|
+
|
|
1795
|
+
async def get_system_health() -> Dict[str, Any]:
|
|
1796
|
+
"""Get comprehensive system health report"""
|
|
1797
|
+
manager = get_jit_hook_manager()
|
|
1798
|
+
return await manager.get_system_health_report()
|
|
1799
|
+
|
|
1800
|
+
|
|
1801
|
+
def get_connection_pool_info() -> Dict[str, Any]:
|
|
1802
|
+
"""Get connection pool statistics and status"""
|
|
1803
|
+
manager = get_jit_hook_manager()
|
|
1804
|
+
return manager.get_connection_pool_stats()
|
|
1805
|
+
|
|
1806
|
+
|
|
1807
|
+
def get_cache_performance() -> Dict[str, Any]:
|
|
1808
|
+
"""Get advanced cache performance metrics"""
|
|
1809
|
+
manager = get_jit_hook_manager()
|
|
1810
|
+
return manager.get_advanced_cache_stats()
|
|
1811
|
+
|
|
1812
|
+
|
|
1813
|
+
def get_circuit_breaker_info() -> Dict[str, Any]:
|
|
1814
|
+
"""Get circuit breaker status for all hooks"""
|
|
1815
|
+
manager = get_jit_hook_manager()
|
|
1816
|
+
return manager.get_circuit_breaker_status()
|
|
1817
|
+
|
|
1818
|
+
|
|
1819
|
+
def invalidate_hook_cache(pattern: Optional[str] = None) -> None:
|
|
1820
|
+
"""Invalidate hook cache entries"""
|
|
1821
|
+
manager = get_jit_hook_manager()
|
|
1822
|
+
manager._advanced_cache.invalidate(pattern)
|
|
1823
|
+
|
|
1824
|
+
|
|
1825
|
+
def reset_circuit_breakers(hook_path: Optional[str] = None) -> None:
|
|
1826
|
+
"""Reset circuit breakers (specific hook or all)"""
|
|
1827
|
+
manager = get_jit_hook_manager()
|
|
1828
|
+
|
|
1829
|
+
if hook_path:
|
|
1830
|
+
if hook_path in manager._circuit_breakers:
|
|
1831
|
+
cb = manager._circuit_breakers[hook_path]
|
|
1832
|
+
cb.state.state = "CLOSED"
|
|
1833
|
+
cb.state.failure_count = 0
|
|
1834
|
+
cb.state.last_failure_time = None
|
|
1835
|
+
else:
|
|
1836
|
+
for cb in manager._circuit_breakers.values():
|
|
1837
|
+
cb.state.state = "CLOSED"
|
|
1838
|
+
cb.state.failure_count = 0
|
|
1839
|
+
cb.state.last_failure_time = None
|
|
1840
|
+
|
|
1841
|
+
|
|
1842
|
+
async def optimize_hook_system() -> Dict[str, Any]:
|
|
1843
|
+
"""Run system optimization and return recommendations"""
|
|
1844
|
+
manager = get_jit_hook_manager()
|
|
1845
|
+
|
|
1846
|
+
# Get current health and metrics
|
|
1847
|
+
health_report = await manager.get_system_health_report()
|
|
1848
|
+
metrics = manager.get_performance_metrics()
|
|
1849
|
+
manager.get_advanced_cache_stats()
|
|
1850
|
+
|
|
1851
|
+
# Generate optimization recommendations
|
|
1852
|
+
optimization_report = {
|
|
1853
|
+
"timestamp": datetime.now().isoformat(),
|
|
1854
|
+
"health_status": health_report["status"],
|
|
1855
|
+
"performance_summary": {
|
|
1856
|
+
"success_rate": metrics.successful_executions / max(metrics.total_executions, 1),
|
|
1857
|
+
"average_execution_time_ms": metrics.average_execution_time_ms,
|
|
1858
|
+
"cache_efficiency": metrics.cache_hits / max(metrics.cache_hits + metrics.cache_misses, 1),
|
|
1859
|
+
"circuit_breaker_trips": metrics.circuit_breaker_trips,
|
|
1860
|
+
},
|
|
1861
|
+
"recommendations": [],
|
|
1862
|
+
}
|
|
1863
|
+
|
|
1864
|
+
# Performance recommendations
|
|
1865
|
+
if metrics.average_execution_time_ms > 500:
|
|
1866
|
+
optimization_report["recommendations"].append("Consider optimizing slow hooks or increasing parallel execution")
|
|
1867
|
+
|
|
1868
|
+
if metrics.cache_hits / max(metrics.cache_hits + metrics.cache_misses, 1) < 0.3:
|
|
1869
|
+
optimization_report["recommendations"].append(
|
|
1870
|
+
"Cache hit rate is low - consider increasing TTL or reviewing cache strategy"
|
|
1871
|
+
)
|
|
1872
|
+
|
|
1873
|
+
if metrics.circuit_breaker_trips > 5:
|
|
1874
|
+
optimization_report["recommendations"].append(
|
|
1875
|
+
"High circuit breaker activity detected - review hook reliability"
|
|
1876
|
+
)
|
|
1877
|
+
|
|
1878
|
+
# Resource recommendations
|
|
1879
|
+
if metrics.resource_usage.memory_usage_mb > 500:
|
|
1880
|
+
optimization_report["recommendations"].append(
|
|
1881
|
+
"High memory usage - consider reducing cache size or optimizing resource usage"
|
|
1882
|
+
)
|
|
1883
|
+
|
|
1884
|
+
if health_report["status"] != "healthy":
|
|
1885
|
+
optimization_report["recommendations"].append(
|
|
1886
|
+
f"System health is {health_report['status']} - review health checks"
|
|
1887
|
+
)
|
|
1888
|
+
|
|
1889
|
+
return optimization_report
|
|
1890
|
+
|
|
1891
|
+
|
|
1892
|
+
if __name__ == "__main__":
|
|
1893
|
+
# Example usage and testing with Phase 2 optimizations
|
|
1894
|
+
async def test_phase2_optimizations():
|
|
1895
|
+
"""Test Phase 2 performance optimizations and reliability features"""
|
|
1896
|
+
print("๐ Testing Phase 2 JIT-Enhanced Hook Manager Optimizations")
|
|
1897
|
+
print("=" * 60)
|
|
1898
|
+
|
|
1899
|
+
# Initialize with Phase 2 optimizations
|
|
1900
|
+
manager = JITEnhancedHookManager(
|
|
1901
|
+
cache_ttl_seconds=300,
|
|
1902
|
+
circuit_breaker_threshold=3,
|
|
1903
|
+
max_retries=2,
|
|
1904
|
+
connection_pool_size=5,
|
|
1905
|
+
)
|
|
1906
|
+
|
|
1907
|
+
try:
|
|
1908
|
+
# Test hook execution with advanced features
|
|
1909
|
+
context = {"test": True, "user": "test_user", "session_id": "test_session"}
|
|
1910
|
+
|
|
1911
|
+
print("\n๐ Testing Hook Execution with Phase 2 Optimizations:")
|
|
1912
|
+
results = await manager.execute_hooks(
|
|
1913
|
+
HookEvent.SESSION_START,
|
|
1914
|
+
context,
|
|
1915
|
+
user_input="Testing Phase 2 JIT enhanced hook system",
|
|
1916
|
+
)
|
|
1917
|
+
|
|
1918
|
+
print(f"Executed {len(results)} hooks")
|
|
1919
|
+
for result in results:
|
|
1920
|
+
status = "โ" if result.success else "โ"
|
|
1921
|
+
print(f" {result.hook_path}: {status} ({result.execution_time_ms:.1f}ms)")
|
|
1922
|
+
if result.metadata.get("performance_anomaly"):
|
|
1923
|
+
anomaly = result.metadata["performance_anomaly"]
|
|
1924
|
+
print(f" โ ๏ธ Performance anomaly: {anomaly['anomaly_type']} ({anomaly['severity']})")
|
|
1925
|
+
|
|
1926
|
+
# Show Phase 2 enhanced metrics
|
|
1927
|
+
print("\n๐ Phase 2 Performance Metrics:")
|
|
1928
|
+
metrics = manager.get_performance_metrics()
|
|
1929
|
+
print(f" Total executions: {metrics.total_executions}")
|
|
1930
|
+
print(f" Success rate: {metrics.successful_executions}/{metrics.total_executions}")
|
|
1931
|
+
print(f" Avg execution time: {metrics.average_execution_time_ms:.1f}ms")
|
|
1932
|
+
print(f" Cache hits: {metrics.cache_hits}, misses: {metrics.cache_misses}")
|
|
1933
|
+
print(f" Circuit breaker trips: {metrics.circuit_breaker_trips}")
|
|
1934
|
+
print(f" Retry attempts: {metrics.retry_attempts}")
|
|
1935
|
+
print(f" Memory usage: {metrics.resource_usage.memory_usage_mb:.1f}MB")
|
|
1936
|
+
print(f" CPU usage: {metrics.resource_usage.cpu_usage_percent:.1f}%")
|
|
1937
|
+
|
|
1938
|
+
# Test health monitoring
|
|
1939
|
+
print("\n๐ฅ System Health Check:")
|
|
1940
|
+
health_report = await manager.get_system_health_report()
|
|
1941
|
+
print(f" Overall status: {health_report['status']}")
|
|
1942
|
+
for check_name, check_data in health_report["checks"].items():
|
|
1943
|
+
status_icon = "โ" if check_data["status"] == "healthy" else "โ ๏ธ"
|
|
1944
|
+
print(f" {check_name}: {status_icon} {check_data['status']}")
|
|
1945
|
+
|
|
1946
|
+
# Test cache performance
|
|
1947
|
+
print("\n๐พ Cache Performance:")
|
|
1948
|
+
cache_stats = manager.get_advanced_cache_stats()
|
|
1949
|
+
print(f" Cache size: {cache_stats['size']}/{cache_stats['max_size']}")
|
|
1950
|
+
print(f" Utilization: {cache_stats['utilization']:.1%}")
|
|
1951
|
+
|
|
1952
|
+
# Test circuit breaker status
|
|
1953
|
+
print("\nโก Circuit Breaker Status:")
|
|
1954
|
+
cb_status = manager.get_circuit_breaker_status()
|
|
1955
|
+
for hook_name, cb_data in cb_status.items():
|
|
1956
|
+
print(f" {hook_name}: {cb_data['state']} ({cb_data['failure_count']} failures)")
|
|
1957
|
+
|
|
1958
|
+
# Test system optimization
|
|
1959
|
+
print("\n๐ง System Optimization:")
|
|
1960
|
+
optimization_report = await optimize_hook_system()
|
|
1961
|
+
print(f" Health status: {optimization_report['health_status']}")
|
|
1962
|
+
print(f" Success rate: {optimization_report['performance_summary']['success_rate']:.1%}")
|
|
1963
|
+
print(f" Cache efficiency: {optimization_report['performance_summary']['cache_efficiency']:.1%}")
|
|
1964
|
+
|
|
1965
|
+
if optimization_report["recommendations"]:
|
|
1966
|
+
print(" Recommendations:")
|
|
1967
|
+
for rec in optimization_report["recommendations"]:
|
|
1968
|
+
print(f" โข {rec}")
|
|
1969
|
+
else:
|
|
1970
|
+
print(" โ No optimization recommendations needed")
|
|
1971
|
+
|
|
1972
|
+
print("\nโ
Phase 2 optimizations test completed successfully!")
|
|
1973
|
+
|
|
1974
|
+
except Exception as e:
|
|
1975
|
+
print(f"\nโ Test failed: {str(e)}")
|
|
1976
|
+
import traceback
|
|
1977
|
+
|
|
1978
|
+
traceback.print_exc()
|
|
1979
|
+
|
|
1980
|
+
finally:
|
|
1981
|
+
# Enhanced cleanup with Phase 2 features
|
|
1982
|
+
print("\n๐งน Cleaning up Phase 2 resources...")
|
|
1983
|
+
await manager.cleanup()
|
|
1984
|
+
print("โ
Cleanup completed")
|
|
1985
|
+
|
|
1986
|
+
# Run Phase 2 test
|
|
1987
|
+
asyncio.run(test_phase2_optimizations())
|