claude-mpm 3.4.10__py3-none-any.whl → 5.4.55__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.
- claude_mpm/BUILD_NUMBER +1 -0
- claude_mpm/VERSION +1 -0
- claude_mpm/__init__.py +50 -12
- claude_mpm/__main__.py +7 -2
- claude_mpm/agents/BASE_AGENT.md +164 -0
- claude_mpm/agents/BASE_ENGINEER.md +658 -0
- claude_mpm/agents/CLAUDE_MPM_OUTPUT_STYLE.md +290 -0
- claude_mpm/agents/CLAUDE_MPM_TEACHER_OUTPUT_STYLE.md +2002 -0
- claude_mpm/agents/MEMORY.md +72 -0
- claude_mpm/agents/PM_INSTRUCTIONS.md +1402 -0
- claude_mpm/agents/WORKFLOW.md +111 -0
- claude_mpm/agents/__init__.py +92 -80
- claude_mpm/agents/agent-template.yaml +83 -0
- claude_mpm/agents/agent_loader.py +560 -745
- claude_mpm/agents/agent_loader_integration.py +53 -55
- claude_mpm/agents/agents_metadata.py +186 -27
- claude_mpm/agents/async_agent_loader.py +436 -0
- claude_mpm/agents/base_agent.json +8 -4
- claude_mpm/agents/frontmatter_validator.py +754 -0
- claude_mpm/agents/system_agent_config.py +222 -155
- claude_mpm/agents/templates/README.md +465 -0
- claude_mpm/agents/templates/__init__.py +17 -13
- claude_mpm/agents/templates/circuit-breakers.md +1391 -0
- claude_mpm/agents/templates/context-management-examples.md +544 -0
- claude_mpm/agents/templates/git-file-tracking.md +584 -0
- claude_mpm/agents/templates/pm-examples.md +474 -0
- claude_mpm/agents/templates/pm-red-flags.md +310 -0
- claude_mpm/agents/templates/pr-workflow-examples.md +427 -0
- claude_mpm/agents/templates/research-gate-examples.md +669 -0
- claude_mpm/agents/templates/response-format.md +583 -0
- claude_mpm/agents/templates/structured-questions-examples.md +615 -0
- claude_mpm/agents/templates/ticket-completeness-examples.md +139 -0
- claude_mpm/agents/templates/ticketing-examples.md +277 -0
- claude_mpm/agents/templates/validation-templates.md +312 -0
- claude_mpm/cli/__init__.py +90 -128
- claude_mpm/cli/__main__.py +33 -0
- claude_mpm/cli/chrome_devtools_installer.py +175 -0
- claude_mpm/cli/commands/__init__.py +36 -12
- claude_mpm/cli/commands/agent_manager.py +1403 -0
- claude_mpm/cli/commands/agent_source.py +774 -0
- claude_mpm/cli/commands/agent_state_manager.py +335 -0
- claude_mpm/cli/commands/agents.py +2503 -168
- claude_mpm/cli/commands/agents_cleanup.py +210 -0
- claude_mpm/cli/commands/agents_discover.py +338 -0
- claude_mpm/cli/commands/aggregate.py +540 -0
- claude_mpm/cli/commands/analyze.py +553 -0
- claude_mpm/cli/commands/analyze_code.py +528 -0
- claude_mpm/cli/commands/auto_configure.py +1053 -0
- claude_mpm/cli/commands/cleanup.py +588 -0
- claude_mpm/cli/commands/cleanup_orphaned_agents.py +150 -0
- claude_mpm/cli/commands/config.py +586 -0
- claude_mpm/cli/commands/configure.py +2654 -0
- claude_mpm/cli/commands/configure_agent_display.py +282 -0
- claude_mpm/cli/commands/configure_behavior_manager.py +204 -0
- claude_mpm/cli/commands/configure_hook_manager.py +225 -0
- claude_mpm/cli/commands/configure_models.py +18 -0
- claude_mpm/cli/commands/configure_navigation.py +184 -0
- claude_mpm/cli/commands/configure_paths.py +104 -0
- claude_mpm/cli/commands/configure_persistence.py +254 -0
- claude_mpm/cli/commands/configure_startup_manager.py +646 -0
- claude_mpm/cli/commands/configure_template_editor.py +497 -0
- claude_mpm/cli/commands/configure_validators.py +73 -0
- claude_mpm/cli/commands/dashboard.py +286 -0
- claude_mpm/cli/commands/debug.py +1386 -0
- claude_mpm/cli/commands/doctor.py +243 -0
- claude_mpm/cli/commands/hook_errors.py +277 -0
- claude_mpm/cli/commands/info.py +195 -74
- claude_mpm/cli/commands/local_deploy.py +534 -0
- claude_mpm/cli/commands/mcp.py +205 -0
- claude_mpm/cli/commands/mcp_command_router.py +161 -0
- claude_mpm/cli/commands/mcp_config.py +154 -0
- claude_mpm/cli/commands/mcp_config_commands.py +20 -0
- claude_mpm/cli/commands/mcp_external_commands.py +249 -0
- claude_mpm/cli/commands/mcp_install_commands.py +346 -0
- claude_mpm/cli/commands/mcp_pipx_config.py +208 -0
- claude_mpm/cli/commands/mcp_server_commands.py +155 -0
- claude_mpm/cli/commands/mcp_setup_external.py +868 -0
- claude_mpm/cli/commands/mcp_tool_commands.py +34 -0
- claude_mpm/cli/commands/memory.py +585 -846
- claude_mpm/cli/commands/monitor.py +228 -310
- claude_mpm/cli/commands/mpm_init/__init__.py +73 -0
- claude_mpm/cli/commands/mpm_init/core.py +759 -0
- claude_mpm/cli/commands/mpm_init/display.py +341 -0
- claude_mpm/cli/commands/mpm_init/git_activity.py +427 -0
- claude_mpm/cli/commands/mpm_init/knowledge_extractor.py +481 -0
- claude_mpm/cli/commands/mpm_init/modes.py +397 -0
- claude_mpm/cli/commands/mpm_init/prompts.py +722 -0
- claude_mpm/cli/commands/mpm_init_cli.py +396 -0
- claude_mpm/cli/commands/mpm_init_handler.py +195 -0
- claude_mpm/cli/commands/postmortem.py +401 -0
- claude_mpm/cli/commands/profile.py +276 -0
- claude_mpm/cli/commands/run.py +910 -488
- claude_mpm/cli/commands/search.py +458 -0
- claude_mpm/cli/commands/skill_source.py +694 -0
- claude_mpm/cli/commands/skills.py +1246 -0
- claude_mpm/cli/commands/summarize.py +413 -0
- claude_mpm/cli/commands/tickets.py +536 -53
- claude_mpm/cli/commands/uninstall.py +176 -0
- claude_mpm/cli/commands/upgrade.py +152 -0
- claude_mpm/cli/commands/verify.py +119 -0
- claude_mpm/cli/executor.py +297 -0
- claude_mpm/cli/helpers.py +105 -0
- claude_mpm/cli/interactive/__init__.py +21 -0
- claude_mpm/cli/interactive/agent_wizard.py +1947 -0
- claude_mpm/cli/interactive/skills_wizard.py +491 -0
- claude_mpm/cli/parser.py +87 -563
- claude_mpm/cli/parsers/__init__.py +35 -0
- claude_mpm/cli/parsers/agent_manager_parser.py +393 -0
- claude_mpm/cli/parsers/agent_source_parser.py +171 -0
- claude_mpm/cli/parsers/agents_parser.py +575 -0
- claude_mpm/cli/parsers/analyze_code_parser.py +170 -0
- claude_mpm/cli/parsers/analyze_parser.py +135 -0
- claude_mpm/cli/parsers/auto_configure_parser.py +120 -0
- claude_mpm/cli/parsers/base_parser.py +644 -0
- claude_mpm/cli/parsers/config_parser.py +208 -0
- claude_mpm/cli/parsers/configure_parser.py +138 -0
- claude_mpm/cli/parsers/dashboard_parser.py +113 -0
- claude_mpm/cli/parsers/debug_parser.py +319 -0
- claude_mpm/cli/parsers/local_deploy_parser.py +227 -0
- claude_mpm/cli/parsers/mcp_parser.py +195 -0
- claude_mpm/cli/parsers/memory_parser.py +138 -0
- claude_mpm/cli/parsers/monitor_parser.py +142 -0
- claude_mpm/cli/parsers/mpm_init_parser.py +311 -0
- claude_mpm/cli/parsers/profile_parser.py +147 -0
- claude_mpm/cli/parsers/run_parser.py +157 -0
- claude_mpm/cli/parsers/search_parser.py +245 -0
- claude_mpm/cli/parsers/skill_source_parser.py +169 -0
- claude_mpm/cli/parsers/skills_parser.py +277 -0
- claude_mpm/cli/parsers/source_parser.py +138 -0
- claude_mpm/cli/parsers/tickets_parser.py +203 -0
- claude_mpm/cli/shared/__init__.py +40 -0
- claude_mpm/cli/shared/argument_patterns.py +205 -0
- claude_mpm/cli/shared/base_command.py +242 -0
- claude_mpm/cli/shared/error_handling.py +242 -0
- claude_mpm/cli/shared/output_formatters.py +241 -0
- claude_mpm/cli/startup.py +1743 -0
- claude_mpm/cli/startup_display.py +480 -0
- claude_mpm/cli/startup_logging.py +839 -0
- claude_mpm/cli/utils.py +136 -47
- claude_mpm/cli_module/__init__.py +6 -6
- claude_mpm/cli_module/args.py +188 -140
- claude_mpm/cli_module/commands.py +79 -70
- claude_mpm/cli_module/migration_example.py +42 -64
- claude_mpm/commands/__init__.py +14 -0
- claude_mpm/commands/mpm-config.md +28 -0
- claude_mpm/commands/mpm-doctor.md +20 -0
- claude_mpm/commands/mpm-help.md +20 -0
- claude_mpm/commands/mpm-init.md +120 -0
- claude_mpm/commands/mpm-monitor.md +31 -0
- claude_mpm/commands/mpm-organize.md +120 -0
- claude_mpm/commands/mpm-postmortem.md +21 -0
- claude_mpm/commands/mpm-session-resume.md +30 -0
- claude_mpm/commands/mpm-status.md +20 -0
- claude_mpm/commands/mpm-ticket-view.md +109 -0
- claude_mpm/commands/mpm-version.md +20 -0
- claude_mpm/commands/mpm.md +31 -0
- claude_mpm/config/__init__.py +42 -2
- claude_mpm/config/agent_config.py +402 -0
- claude_mpm/config/agent_presets.py +488 -0
- claude_mpm/config/agent_sources.py +352 -0
- claude_mpm/config/experimental_features.py +217 -0
- claude_mpm/config/model_config.py +428 -0
- claude_mpm/config/paths.py +258 -0
- claude_mpm/config/skill_presets.py +392 -0
- claude_mpm/config/skill_sources.py +590 -0
- claude_mpm/config/socketio_config.py +125 -83
- claude_mpm/constants.py +132 -22
- claude_mpm/core/__init__.py +62 -36
- claude_mpm/core/agent_name_normalizer.py +71 -73
- claude_mpm/core/agent_registry.py +385 -492
- claude_mpm/core/agent_session_manager.py +81 -70
- claude_mpm/core/api_validator.py +330 -0
- claude_mpm/core/base_service.py +159 -122
- claude_mpm/core/cache.py +560 -0
- claude_mpm/core/claude_runner.py +696 -916
- claude_mpm/core/config.py +613 -122
- claude_mpm/core/config_aliases.py +74 -73
- claude_mpm/core/config_constants.py +314 -0
- claude_mpm/core/constants.py +361 -0
- claude_mpm/core/container.py +646 -104
- claude_mpm/core/enums.py +452 -0
- claude_mpm/core/error_handler.py +623 -0
- claude_mpm/core/exceptions.py +536 -0
- claude_mpm/core/factories.py +105 -109
- claude_mpm/core/file_utils.py +764 -0
- claude_mpm/core/framework/__init__.py +25 -0
- claude_mpm/core/framework/formatters/__init__.py +11 -0
- claude_mpm/core/framework/formatters/capability_generator.py +367 -0
- claude_mpm/core/framework/formatters/content_formatter.py +278 -0
- claude_mpm/core/framework/formatters/context_generator.py +185 -0
- claude_mpm/core/framework/loaders/__init__.py +13 -0
- claude_mpm/core/framework/loaders/agent_loader.py +213 -0
- claude_mpm/core/framework/loaders/file_loader.py +176 -0
- claude_mpm/core/framework/loaders/instruction_loader.py +222 -0
- claude_mpm/core/framework/loaders/packaged_loader.py +232 -0
- claude_mpm/core/framework/processors/__init__.py +11 -0
- claude_mpm/core/framework/processors/memory_processor.py +230 -0
- claude_mpm/core/framework/processors/metadata_processor.py +146 -0
- claude_mpm/core/framework/processors/template_processor.py +244 -0
- claude_mpm/core/framework_loader.py +485 -414
- claude_mpm/core/hook_error_memory.py +381 -0
- claude_mpm/core/hook_manager.py +246 -86
- claude_mpm/core/hook_performance_config.py +147 -0
- claude_mpm/core/injectable_service.py +72 -63
- claude_mpm/core/instruction_reinforcement_hook.py +267 -0
- claude_mpm/core/interactive_session.py +670 -0
- claude_mpm/core/interfaces.py +570 -164
- claude_mpm/core/lazy.py +467 -0
- claude_mpm/core/log_manager.py +707 -0
- claude_mpm/core/logger.py +295 -134
- claude_mpm/core/logging_config.py +474 -0
- claude_mpm/core/logging_utils.py +520 -0
- claude_mpm/core/minimal_framework_loader.py +24 -22
- claude_mpm/core/mixins.py +30 -29
- claude_mpm/core/oneshot_session.py +594 -0
- claude_mpm/core/optimized_agent_loader.py +479 -0
- claude_mpm/core/optimized_startup.py +554 -0
- claude_mpm/core/output_style_manager.py +483 -0
- claude_mpm/core/pm_hook_interceptor.py +197 -82
- claude_mpm/core/protocols/__init__.py +23 -0
- claude_mpm/core/protocols/runner_protocol.py +103 -0
- claude_mpm/core/protocols/session_protocol.py +131 -0
- claude_mpm/core/service_registry.py +153 -116
- claude_mpm/core/session_manager.py +179 -64
- claude_mpm/core/shared/__init__.py +17 -0
- claude_mpm/core/shared/config_loader.py +326 -0
- claude_mpm/core/shared/path_resolver.py +281 -0
- claude_mpm/core/shared/singleton_manager.py +221 -0
- claude_mpm/core/socketio_pool.py +400 -137
- claude_mpm/core/system_context.py +38 -0
- claude_mpm/core/tool_access_control.py +64 -57
- claude_mpm/core/types.py +307 -0
- claude_mpm/core/typing_utils.py +553 -0
- claude_mpm/core/unified_agent_registry.py +969 -0
- claude_mpm/core/unified_config.py +570 -0
- claude_mpm/core/unified_paths.py +941 -0
- claude_mpm/dashboard/__init__.py +12 -0
- claude_mpm/dashboard/api/simple_directory.py +261 -0
- claude_mpm/dashboard/static/svelte-build/_app/env.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.DWzvg0-y.css +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.ThTw9_ym.css +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/4TdZjIqw.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/5shd3_w0.js +24 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/B0uc0UOD.js +36 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/B7RN905-.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/B7xVLGWV.js +2 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BIF9m_hv.js +61 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BKjSRqUr.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BPYeabCQ.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BQaXIfA_.js +331 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BSNlmTZj.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Be7GpZd6.js +7 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Bh0LDWpI.js +145 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BofRWZRR.js +10 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BovzEFCE.js +30 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C30mlcqg.js +165 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C4B-KCzX.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C4JcI4KD.js +122 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CBBdVcY8.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CDuw-vjf.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C_Usid8X.js +15 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Cfqx1Qun.js +10 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CiIAseT4.js +128 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CmKTTxBW.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CnA0NrzZ.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Cs_tUR18.js +24 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Cu_Erd72.js +261 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CyWMqx4W.js +43 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CzZX-COe.js +220 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CzeYkLYB.js +65 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D3k0OPJN.js +4 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D9lljYKQ.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DGkLK5U1.js +267 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DI7hHRFL.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DLVjFsZ3.js +139 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DUrLdbGD.js +89 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DVp1hx9R.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DY1XQ8fi.js +2 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DZX00Y4g.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Da0KfYnO.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DaimHw_p.js +68 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Dfy6j1xT.js +323 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Dhb8PKl3.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Dle-35c7.js +64 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DmxopI1J.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DwBR2MJi.js +60 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/GYwsonyD.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Gi6I4Gst.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/NqQ1dWOy.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/RJiighC3.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Vzk33B_K.js +2 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/ZGh7QtNv.js +7 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/bT1r9zLR.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/bTOqqlTd.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/eNVUfhuA.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/iEWssX7S.js +162 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/sQeU3Y1z.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/uuIeMWc-.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/app.D6-I5TpK.js +2 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.NWzMBYRp.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/0.m1gL8KXf.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/1.CgNOuw-d.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.C0GcWctS.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/version.json +1 -0
- claude_mpm/dashboard/static/svelte-build/favicon.svg +7 -0
- claude_mpm/dashboard/static/svelte-build/index.html +36 -0
- claude_mpm/dashboard-svelte/node_modules/katex/src/fonts/generate_fonts.py +58 -0
- claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/extract_tfms.py +114 -0
- claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/extract_ttfs.py +122 -0
- claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/format_json.py +28 -0
- claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/parse_tfm.py +211 -0
- claude_mpm/experimental/__init__.py +10 -0
- claude_mpm/experimental/cli_enhancements.py +104 -89
- claude_mpm/generators/__init__.py +1 -1
- claude_mpm/generators/agent_profile_generator.py +76 -66
- claude_mpm/hooks/__init__.py +37 -1
- claude_mpm/hooks/base_hook.py +37 -32
- claude_mpm/hooks/claude_hooks/__init__.py +1 -1
- claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/correlation_manager.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/installer.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/connection_pool.py +250 -0
- claude_mpm/hooks/claude_hooks/correlation_manager.py +60 -0
- claude_mpm/hooks/claude_hooks/event_handlers.py +888 -0
- claude_mpm/hooks/claude_hooks/hook_handler.py +652 -875
- claude_mpm/hooks/claude_hooks/hook_wrapper.sh +10 -7
- claude_mpm/hooks/claude_hooks/installer.py +806 -0
- claude_mpm/hooks/claude_hooks/memory_integration.py +249 -0
- claude_mpm/hooks/claude_hooks/response_tracking.py +412 -0
- claude_mpm/hooks/claude_hooks/services/__init__.py +15 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/connection_manager.py +229 -0
- claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +254 -0
- claude_mpm/hooks/claude_hooks/services/duplicate_detector.py +106 -0
- claude_mpm/hooks/claude_hooks/services/state_manager.py +284 -0
- claude_mpm/hooks/claude_hooks/services/subagent_processor.py +374 -0
- claude_mpm/hooks/claude_hooks/tool_analysis.py +224 -0
- claude_mpm/hooks/failure_learning/__init__.py +54 -0
- claude_mpm/hooks/failure_learning/failure_detection_hook.py +230 -0
- claude_mpm/hooks/failure_learning/fix_detection_hook.py +212 -0
- claude_mpm/hooks/failure_learning/learning_extraction_hook.py +281 -0
- claude_mpm/hooks/instruction_reinforcement.py +301 -0
- claude_mpm/hooks/kuzu_enrichment_hook.py +263 -0
- claude_mpm/hooks/kuzu_memory_hook.py +386 -0
- claude_mpm/hooks/kuzu_response_hook.py +179 -0
- claude_mpm/hooks/memory_integration_hook.py +201 -107
- claude_mpm/hooks/session_resume_hook.py +121 -0
- claude_mpm/hooks/templates/pre_tool_use_simple.py +78 -0
- claude_mpm/hooks/templates/pre_tool_use_template.py +323 -0
- claude_mpm/hooks/tool_call_interceptor.py +92 -76
- claude_mpm/hooks/validation_hooks.py +62 -54
- claude_mpm/init.py +518 -83
- claude_mpm/models/__init__.py +9 -9
- claude_mpm/models/agent_definition.py +40 -23
- claude_mpm/models/agent_session.py +538 -0
- claude_mpm/models/git_repository.py +198 -0
- claude_mpm/models/resume_log.py +340 -0
- claude_mpm/schemas/__init__.py +12 -0
- claude_mpm/scripts/__init__.py +15 -0
- claude_mpm/scripts/claude-hook-handler.sh +227 -0
- claude_mpm/scripts/launch_monitor.py +165 -0
- claude_mpm/scripts/mpm_doctor.py +322 -0
- claude_mpm/scripts/socketio_daemon.py +189 -200
- claude_mpm/scripts/start_activity_logging.py +91 -0
- claude_mpm/services/__init__.py +208 -39
- claude_mpm/services/agent_capabilities_service.py +266 -0
- claude_mpm/services/agents/__init__.py +89 -0
- claude_mpm/services/agents/agent_builder.py +514 -0
- claude_mpm/services/agents/agent_preset_service.py +238 -0
- claude_mpm/services/agents/agent_recommendation_service.py +278 -0
- claude_mpm/services/agents/agent_review_service.py +280 -0
- claude_mpm/services/agents/agent_selection_service.py +484 -0
- claude_mpm/services/agents/auto_config_manager.py +796 -0
- claude_mpm/services/agents/auto_deploy_index_parser.py +569 -0
- claude_mpm/services/agents/cache_git_manager.py +621 -0
- claude_mpm/services/agents/deployment/__init__.py +21 -0
- claude_mpm/services/agents/deployment/agent_config_provider.py +410 -0
- claude_mpm/services/agents/deployment/agent_configuration_manager.py +358 -0
- claude_mpm/services/agents/deployment/agent_definition_factory.py +80 -0
- claude_mpm/services/agents/deployment/agent_deployment.py +1037 -0
- claude_mpm/services/agents/deployment/agent_discovery_service.py +546 -0
- claude_mpm/services/agents/deployment/agent_environment_manager.py +288 -0
- claude_mpm/services/agents/deployment/agent_filesystem_manager.py +383 -0
- claude_mpm/services/agents/deployment/agent_format_converter.py +505 -0
- claude_mpm/services/agents/deployment/agent_frontmatter_validator.py +160 -0
- claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +957 -0
- claude_mpm/services/agents/deployment/agent_metrics_collector.py +273 -0
- claude_mpm/services/agents/deployment/agent_operation_service.py +573 -0
- claude_mpm/services/agents/deployment/agent_record_service.py +418 -0
- claude_mpm/services/agents/deployment/agent_restore_handler.py +84 -0
- claude_mpm/services/agents/deployment/agent_state_service.py +381 -0
- claude_mpm/services/agents/deployment/agent_template_builder.py +1369 -0
- claude_mpm/services/agents/deployment/agent_validator.py +376 -0
- claude_mpm/services/agents/deployment/agent_version_manager.py +322 -0
- claude_mpm/services/{agent_versioning.py → agents/deployment/agent_versioning.py} +10 -13
- claude_mpm/services/agents/deployment/agents_directory_resolver.py +149 -0
- claude_mpm/services/agents/deployment/async_agent_deployment.py +768 -0
- claude_mpm/services/agents/deployment/base_agent_locator.py +132 -0
- claude_mpm/services/agents/deployment/config/__init__.py +13 -0
- claude_mpm/services/agents/deployment/config/deployment_config.py +181 -0
- claude_mpm/services/agents/deployment/config/deployment_config_manager.py +200 -0
- claude_mpm/services/agents/deployment/deployment_config_loader.py +178 -0
- claude_mpm/services/agents/deployment/deployment_results_manager.py +185 -0
- claude_mpm/services/agents/deployment/deployment_type_detector.py +120 -0
- claude_mpm/services/agents/deployment/deployment_wrapper.py +129 -0
- claude_mpm/services/agents/deployment/facade/__init__.py +18 -0
- claude_mpm/services/agents/deployment/facade/async_deployment_executor.py +159 -0
- claude_mpm/services/agents/deployment/facade/deployment_executor.py +70 -0
- claude_mpm/services/agents/deployment/facade/deployment_facade.py +269 -0
- claude_mpm/services/agents/deployment/facade/sync_deployment_executor.py +178 -0
- claude_mpm/services/agents/deployment/interface_adapter.py +226 -0
- claude_mpm/services/agents/deployment/lifecycle_health_checker.py +85 -0
- claude_mpm/services/agents/deployment/lifecycle_performance_tracker.py +100 -0
- claude_mpm/services/agents/deployment/local_template_deployment.py +362 -0
- claude_mpm/services/agents/deployment/multi_source_deployment_service.py +1478 -0
- claude_mpm/services/agents/deployment/pipeline/__init__.py +32 -0
- claude_mpm/services/agents/deployment/pipeline/pipeline_builder.py +158 -0
- claude_mpm/services/agents/deployment/pipeline/pipeline_context.py +162 -0
- claude_mpm/services/agents/deployment/pipeline/pipeline_executor.py +169 -0
- claude_mpm/services/agents/deployment/pipeline/steps/__init__.py +19 -0
- claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +240 -0
- claude_mpm/services/agents/deployment/pipeline/steps/base_step.py +110 -0
- claude_mpm/services/agents/deployment/pipeline/steps/configuration_step.py +80 -0
- claude_mpm/services/agents/deployment/pipeline/steps/target_directory_step.py +92 -0
- claude_mpm/services/agents/deployment/pipeline/steps/validation_step.py +101 -0
- claude_mpm/services/agents/deployment/processors/__init__.py +15 -0
- claude_mpm/services/agents/deployment/processors/agent_deployment_context.py +102 -0
- claude_mpm/services/agents/deployment/processors/agent_deployment_result.py +235 -0
- claude_mpm/services/agents/deployment/processors/agent_processor.py +269 -0
- claude_mpm/services/agents/deployment/refactored_agent_deployment_service.py +311 -0
- claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +862 -0
- claude_mpm/services/agents/deployment/results/__init__.py +13 -0
- claude_mpm/services/agents/deployment/results/deployment_metrics.py +200 -0
- claude_mpm/services/agents/deployment/results/deployment_result_builder.py +249 -0
- claude_mpm/services/agents/deployment/single_agent_deployer.py +315 -0
- claude_mpm/services/agents/deployment/strategies/__init__.py +25 -0
- claude_mpm/services/agents/deployment/strategies/base_strategy.py +113 -0
- claude_mpm/services/agents/deployment/strategies/project_strategy.py +148 -0
- claude_mpm/services/agents/deployment/strategies/strategy_selector.py +117 -0
- claude_mpm/services/agents/deployment/strategies/system_strategy.py +131 -0
- claude_mpm/services/agents/deployment/strategies/user_strategy.py +130 -0
- claude_mpm/services/agents/deployment/system_instructions_deployer.py +228 -0
- claude_mpm/services/agents/deployment/validation/__init__.py +21 -0
- claude_mpm/services/agents/deployment/validation/agent_validator.py +323 -0
- claude_mpm/services/agents/deployment/validation/deployment_validator.py +238 -0
- claude_mpm/services/agents/deployment/validation/template_validator.py +319 -0
- claude_mpm/services/agents/deployment/validation/validation_result.py +214 -0
- claude_mpm/services/agents/git_source_manager.py +682 -0
- claude_mpm/services/agents/loading/__init__.py +11 -0
- claude_mpm/services/{agent_profile_loader.py → agents/loading/agent_profile_loader.py} +306 -228
- claude_mpm/services/{base_agent_manager.py → agents/loading/base_agent_manager.py} +106 -91
- claude_mpm/services/agents/loading/framework_agent_loader.py +433 -0
- claude_mpm/services/agents/local_template_manager.py +784 -0
- claude_mpm/services/agents/management/__init__.py +9 -0
- claude_mpm/services/{agent_capabilities_generator.py → agents/management/agent_capabilities_generator.py} +92 -69
- claude_mpm/services/{agent_management_service.py → agents/management/agent_management_service.py} +219 -168
- claude_mpm/services/agents/memory/__init__.py +22 -0
- claude_mpm/services/agents/memory/agent_memory_manager.py +784 -0
- claude_mpm/services/{agent_persistence_service.py → agents/memory/agent_persistence_service.py} +20 -18
- claude_mpm/services/agents/memory/content_manager.py +470 -0
- claude_mpm/services/agents/memory/memory_categorization_service.py +167 -0
- claude_mpm/services/agents/memory/memory_file_service.py +129 -0
- claude_mpm/services/agents/memory/memory_format_service.py +201 -0
- claude_mpm/services/agents/memory/memory_limits_service.py +101 -0
- claude_mpm/services/agents/memory/template_generator.py +83 -0
- claude_mpm/services/agents/observers.py +547 -0
- claude_mpm/services/agents/recommender.py +617 -0
- claude_mpm/services/agents/registry/__init__.py +30 -0
- claude_mpm/services/agents/registry/deployed_agent_discovery.py +273 -0
- claude_mpm/services/{agent_modification_tracker.py → agents/registry/modification_tracker.py} +370 -295
- claude_mpm/services/agents/single_tier_deployment_service.py +696 -0
- claude_mpm/services/agents/sources/__init__.py +13 -0
- claude_mpm/services/agents/sources/agent_sync_state.py +516 -0
- claude_mpm/services/agents/sources/git_source_sync_service.py +1202 -0
- claude_mpm/services/agents/startup_sync.py +259 -0
- claude_mpm/services/agents/toolchain_detector.py +478 -0
- claude_mpm/services/analysis/__init__.py +35 -0
- claude_mpm/services/analysis/clone_detector.py +1030 -0
- claude_mpm/services/analysis/postmortem_reporter.py +474 -0
- claude_mpm/services/analysis/postmortem_service.py +765 -0
- claude_mpm/services/async_session_logger.py +665 -0
- claude_mpm/services/claude_session_logger.py +321 -0
- claude_mpm/services/cli/__init__.py +18 -0
- claude_mpm/services/cli/agent_cleanup_service.py +408 -0
- claude_mpm/services/cli/agent_dependency_service.py +395 -0
- claude_mpm/services/cli/agent_listing_service.py +463 -0
- claude_mpm/services/cli/agent_output_formatter.py +605 -0
- claude_mpm/services/cli/agent_validation_service.py +590 -0
- claude_mpm/services/cli/memory_crud_service.py +622 -0
- claude_mpm/services/cli/memory_output_formatter.py +604 -0
- claude_mpm/services/cli/resume_service.py +617 -0
- claude_mpm/services/cli/session_manager.py +604 -0
- claude_mpm/services/cli/session_pause_manager.py +504 -0
- claude_mpm/services/cli/session_resume_helper.py +372 -0
- claude_mpm/services/cli/startup_checker.py +362 -0
- claude_mpm/services/cli/unified_dashboard_manager.py +439 -0
- claude_mpm/services/command_deployment_service.py +446 -0
- claude_mpm/services/command_handler_service.py +221 -0
- claude_mpm/services/communication/__init__.py +22 -0
- claude_mpm/services/core/__init__.py +108 -0
- claude_mpm/services/core/base.py +269 -0
- claude_mpm/services/core/cache_manager.py +309 -0
- claude_mpm/services/core/interfaces/__init__.py +273 -0
- claude_mpm/services/core/interfaces/agent.py +514 -0
- claude_mpm/services/core/interfaces/communication.py +316 -0
- claude_mpm/services/core/interfaces/health.py +169 -0
- claude_mpm/services/core/interfaces/infrastructure.py +357 -0
- claude_mpm/services/core/interfaces/model.py +281 -0
- claude_mpm/services/core/interfaces/process.py +372 -0
- claude_mpm/services/core/interfaces/project.py +121 -0
- claude_mpm/services/core/interfaces/restart.py +307 -0
- claude_mpm/services/core/interfaces/service.py +405 -0
- claude_mpm/services/core/interfaces/stability.py +260 -0
- claude_mpm/services/core/interfaces.py +81 -0
- claude_mpm/services/core/memory_manager.py +682 -0
- claude_mpm/services/core/models/__init__.py +70 -0
- claude_mpm/services/core/models/agent_config.py +384 -0
- claude_mpm/services/core/models/health.py +162 -0
- claude_mpm/services/core/models/process.py +239 -0
- claude_mpm/services/core/models/restart.py +302 -0
- claude_mpm/services/core/models/stability.py +264 -0
- claude_mpm/services/core/models/toolchain.py +306 -0
- claude_mpm/services/core/path_resolver.py +517 -0
- claude_mpm/services/core/service_container.py +520 -0
- claude_mpm/services/core/service_interfaces.py +436 -0
- claude_mpm/services/diagnostics/__init__.py +18 -0
- claude_mpm/services/diagnostics/checks/__init__.py +38 -0
- claude_mpm/services/diagnostics/checks/agent_check.py +370 -0
- claude_mpm/services/diagnostics/checks/agent_sources_check.py +577 -0
- claude_mpm/services/diagnostics/checks/base_check.py +60 -0
- claude_mpm/services/diagnostics/checks/claude_code_check.py +270 -0
- claude_mpm/services/diagnostics/checks/common_issues_check.py +363 -0
- claude_mpm/services/diagnostics/checks/configuration_check.py +306 -0
- claude_mpm/services/diagnostics/checks/filesystem_check.py +233 -0
- claude_mpm/services/diagnostics/checks/installation_check.py +520 -0
- claude_mpm/services/diagnostics/checks/instructions_check.py +415 -0
- claude_mpm/services/diagnostics/checks/mcp_check.py +330 -0
- claude_mpm/services/diagnostics/checks/mcp_services_check.py +1058 -0
- claude_mpm/services/diagnostics/checks/monitor_check.py +281 -0
- claude_mpm/services/diagnostics/checks/skill_sources_check.py +587 -0
- claude_mpm/services/diagnostics/checks/startup_log_check.py +319 -0
- claude_mpm/services/diagnostics/diagnostic_runner.py +286 -0
- claude_mpm/services/diagnostics/doctor_reporter.py +578 -0
- claude_mpm/services/diagnostics/models.py +138 -0
- claude_mpm/services/event_aggregator.py +582 -0
- claude_mpm/services/event_bus/__init__.py +18 -0
- claude_mpm/services/event_bus/config.py +186 -0
- claude_mpm/services/event_bus/direct_relay.py +312 -0
- claude_mpm/services/event_bus/event_bus.py +396 -0
- claude_mpm/services/event_bus/relay.py +326 -0
- claude_mpm/services/events/__init__.py +44 -0
- claude_mpm/services/events/consumers/__init__.py +18 -0
- claude_mpm/services/events/consumers/dead_letter.py +306 -0
- claude_mpm/services/events/consumers/logging.py +184 -0
- claude_mpm/services/events/consumers/metrics.py +241 -0
- claude_mpm/services/events/consumers/socketio.py +377 -0
- claude_mpm/services/events/core.py +480 -0
- claude_mpm/services/events/interfaces.py +214 -0
- claude_mpm/services/events/producers/__init__.py +14 -0
- claude_mpm/services/events/producers/hook.py +269 -0
- claude_mpm/services/events/producers/system.py +329 -0
- claude_mpm/services/exceptions.py +433 -353
- claude_mpm/services/framework_claude_md_generator/__init__.py +81 -80
- claude_mpm/services/framework_claude_md_generator/content_assembler.py +74 -67
- claude_mpm/services/framework_claude_md_generator/content_validator.py +66 -62
- claude_mpm/services/framework_claude_md_generator/deployment_manager.py +82 -60
- claude_mpm/services/framework_claude_md_generator/section_generators/__init__.py +36 -37
- claude_mpm/services/framework_claude_md_generator/section_generators/agents.py +41 -40
- claude_mpm/services/framework_claude_md_generator/section_generators/claude_pm_init.py +15 -15
- claude_mpm/services/framework_claude_md_generator/section_generators/core_responsibilities.py +5 -4
- claude_mpm/services/framework_claude_md_generator/section_generators/delegation_constraints.py +4 -3
- claude_mpm/services/framework_claude_md_generator/section_generators/environment_config.py +4 -3
- claude_mpm/services/framework_claude_md_generator/section_generators/footer.py +6 -5
- claude_mpm/services/framework_claude_md_generator/section_generators/header.py +8 -7
- claude_mpm/services/framework_claude_md_generator/section_generators/orchestration_principles.py +5 -4
- claude_mpm/services/framework_claude_md_generator/section_generators/role_designation.py +6 -5
- claude_mpm/services/framework_claude_md_generator/section_generators/subprocess_validation.py +9 -8
- claude_mpm/services/framework_claude_md_generator/section_generators/todo_task_tools.py +26 -30
- claude_mpm/services/framework_claude_md_generator/section_generators/troubleshooting.py +6 -5
- claude_mpm/services/framework_claude_md_generator/section_manager.py +28 -27
- claude_mpm/services/framework_claude_md_generator/version_manager.py +31 -30
- claude_mpm/services/git/__init__.py +21 -0
- claude_mpm/services/git/git_operations_service.py +579 -0
- claude_mpm/services/github/__init__.py +21 -0
- claude_mpm/services/github/github_cli_service.py +397 -0
- claude_mpm/services/hook_installer_service.py +506 -0
- claude_mpm/services/hook_service.py +159 -111
- claude_mpm/services/infrastructure/__init__.py +52 -0
- claude_mpm/services/infrastructure/context_preservation.py +569 -0
- claude_mpm/services/infrastructure/daemon_manager.py +279 -0
- claude_mpm/services/infrastructure/logging.py +209 -0
- claude_mpm/services/infrastructure/monitoring/__init__.py +39 -0
- claude_mpm/services/infrastructure/monitoring/aggregator.py +432 -0
- claude_mpm/services/infrastructure/monitoring/base.py +122 -0
- claude_mpm/services/infrastructure/monitoring/legacy.py +203 -0
- claude_mpm/services/infrastructure/monitoring/network.py +219 -0
- claude_mpm/services/infrastructure/monitoring/process.py +343 -0
- claude_mpm/services/infrastructure/monitoring/resources.py +244 -0
- claude_mpm/services/infrastructure/monitoring/service.py +368 -0
- claude_mpm/services/infrastructure/monitoring.py +71 -0
- claude_mpm/services/infrastructure/resume_log_generator.py +439 -0
- claude_mpm/services/instructions/__init__.py +9 -0
- claude_mpm/services/instructions/instruction_cache_service.py +374 -0
- claude_mpm/services/local_ops/__init__.py +155 -0
- claude_mpm/services/local_ops/crash_detector.py +257 -0
- claude_mpm/services/local_ops/health_checks/__init__.py +26 -0
- claude_mpm/services/local_ops/health_checks/http_check.py +224 -0
- claude_mpm/services/local_ops/health_checks/process_check.py +236 -0
- claude_mpm/services/local_ops/health_checks/resource_check.py +255 -0
- claude_mpm/services/local_ops/health_manager.py +427 -0
- claude_mpm/services/local_ops/log_monitor.py +396 -0
- claude_mpm/services/local_ops/memory_leak_detector.py +294 -0
- claude_mpm/services/local_ops/process_manager.py +595 -0
- claude_mpm/services/local_ops/resource_monitor.py +331 -0
- claude_mpm/services/local_ops/restart_manager.py +401 -0
- claude_mpm/services/local_ops/restart_policy.py +387 -0
- claude_mpm/services/local_ops/state_manager.py +372 -0
- claude_mpm/services/local_ops/unified_manager.py +600 -0
- claude_mpm/services/mcp_config_manager.py +1542 -0
- claude_mpm/services/mcp_service_verifier.py +732 -0
- claude_mpm/services/memory/__init__.py +19 -0
- claude_mpm/services/{memory_builder.py → memory/builder.py} +465 -373
- claude_mpm/services/memory/cache/__init__.py +14 -0
- claude_mpm/services/{shared_prompt_cache.py → memory/cache/shared_prompt_cache.py} +237 -200
- claude_mpm/services/memory/cache/simple_cache.py +331 -0
- claude_mpm/services/memory/failure_tracker.py +578 -0
- claude_mpm/services/memory/indexed_memory.py +648 -0
- claude_mpm/services/{memory_optimizer.py → memory/optimizer.py} +272 -243
- claude_mpm/services/memory/router.py +951 -0
- claude_mpm/services/memory_hook_service.py +470 -0
- claude_mpm/services/model/__init__.py +147 -0
- claude_mpm/services/model/base_provider.py +365 -0
- claude_mpm/services/model/claude_provider.py +412 -0
- claude_mpm/services/model/model_router.py +452 -0
- claude_mpm/services/model/ollama_provider.py +415 -0
- claude_mpm/services/monitor/__init__.py +20 -0
- claude_mpm/services/monitor/daemon.py +698 -0
- claude_mpm/services/monitor/daemon_manager.py +1076 -0
- claude_mpm/services/monitor/event_emitter.py +350 -0
- claude_mpm/services/monitor/handlers/__init__.py +21 -0
- claude_mpm/services/monitor/handlers/code_analysis.py +332 -0
- claude_mpm/services/monitor/handlers/dashboard.py +299 -0
- claude_mpm/services/monitor/handlers/file.py +264 -0
- claude_mpm/services/monitor/handlers/hooks.py +512 -0
- claude_mpm/services/monitor/management/__init__.py +18 -0
- claude_mpm/services/monitor/management/health.py +124 -0
- claude_mpm/services/monitor/management/lifecycle.py +730 -0
- claude_mpm/services/monitor/server.py +1493 -0
- claude_mpm/services/monitor_build_service.py +349 -0
- claude_mpm/services/native_agent_converter.py +356 -0
- claude_mpm/services/orphan_detection.py +786 -0
- claude_mpm/services/pm_skills_deployer.py +707 -0
- claude_mpm/services/port_manager.py +597 -0
- claude_mpm/services/pr/__init__.py +14 -0
- claude_mpm/services/pr/pr_template_service.py +329 -0
- claude_mpm/services/profile_manager.py +337 -0
- claude_mpm/services/project/__init__.py +44 -0
- claude_mpm/services/{project_analyzer.py → project/analyzer.py} +541 -291
- claude_mpm/services/project/analyzer_v2.py +566 -0
- claude_mpm/services/project/architecture_analyzer.py +461 -0
- claude_mpm/services/project/archive_manager.py +1045 -0
- claude_mpm/services/project/dependency_analyzer.py +462 -0
- claude_mpm/services/project/detection_strategies.py +719 -0
- claude_mpm/services/project/documentation_manager.py +554 -0
- claude_mpm/services/project/enhanced_analyzer.py +572 -0
- claude_mpm/services/project/language_analyzer.py +265 -0
- claude_mpm/services/project/metrics_collector.py +407 -0
- claude_mpm/services/project/project_organizer.py +1009 -0
- claude_mpm/services/project/registry.py +636 -0
- claude_mpm/services/project/toolchain_analyzer.py +583 -0
- claude_mpm/services/project_port_allocator.py +596 -0
- claude_mpm/services/recovery_manager.py +293 -240
- claude_mpm/services/response_tracker.py +267 -0
- claude_mpm/services/runner_configuration_service.py +605 -0
- claude_mpm/services/self_upgrade_service.py +608 -0
- claude_mpm/services/session_management_service.py +314 -0
- claude_mpm/services/session_manager.py +380 -0
- claude_mpm/services/shared/__init__.py +21 -0
- claude_mpm/services/shared/async_service_base.py +216 -0
- claude_mpm/services/shared/config_service_base.py +301 -0
- claude_mpm/services/shared/lifecycle_service_base.py +308 -0
- claude_mpm/services/shared/manager_base.py +315 -0
- claude_mpm/services/shared/service_factory.py +309 -0
- claude_mpm/services/skills/__init__.py +21 -0
- claude_mpm/services/skills/git_skill_source_manager.py +1324 -0
- claude_mpm/services/skills/selective_skill_deployer.py +744 -0
- claude_mpm/services/skills/skill_discovery_service.py +568 -0
- claude_mpm/services/skills/skill_to_agent_mapper.py +406 -0
- claude_mpm/services/skills_config.py +547 -0
- claude_mpm/services/skills_deployer.py +1168 -0
- claude_mpm/services/socketio/__init__.py +25 -0
- claude_mpm/services/socketio/client_proxy.py +229 -0
- claude_mpm/services/socketio/dashboard_server.py +362 -0
- claude_mpm/services/socketio/event_normalizer.py +798 -0
- claude_mpm/services/socketio/handlers/__init__.py +30 -0
- claude_mpm/services/socketio/handlers/base.py +136 -0
- claude_mpm/services/socketio/handlers/code_analysis.py +682 -0
- claude_mpm/services/socketio/handlers/connection.py +643 -0
- claude_mpm/services/socketio/handlers/connection_handler.py +333 -0
- claude_mpm/services/socketio/handlers/file.py +263 -0
- claude_mpm/services/socketio/handlers/git.py +962 -0
- claude_mpm/services/socketio/handlers/hook.py +211 -0
- claude_mpm/services/socketio/handlers/memory.py +26 -0
- claude_mpm/services/socketio/handlers/project.py +24 -0
- claude_mpm/services/socketio/handlers/registry.py +214 -0
- claude_mpm/services/socketio/migration_utils.py +343 -0
- claude_mpm/services/socketio/monitor_client.py +364 -0
- claude_mpm/services/socketio/server/__init__.py +18 -0
- claude_mpm/services/socketio/server/broadcaster.py +569 -0
- claude_mpm/services/socketio/server/connection_manager.py +579 -0
- claude_mpm/services/socketio/server/core.py +1079 -0
- claude_mpm/services/socketio/server/eventbus_integration.py +245 -0
- claude_mpm/services/socketio/server/main.py +501 -0
- claude_mpm/services/socketio_client_manager.py +173 -143
- claude_mpm/services/socketio_server.py +38 -1657
- claude_mpm/services/subprocess_launcher_service.py +322 -0
- claude_mpm/services/system_instructions_service.py +270 -0
- claude_mpm/services/ticket_manager.py +25 -209
- claude_mpm/services/ticket_services/__init__.py +26 -0
- claude_mpm/services/ticket_services/crud_service.py +328 -0
- claude_mpm/services/ticket_services/formatter_service.py +290 -0
- claude_mpm/services/ticket_services/search_service.py +324 -0
- claude_mpm/services/ticket_services/validation_service.py +303 -0
- claude_mpm/services/ticket_services/workflow_service.py +244 -0
- claude_mpm/services/unified/__init__.py +65 -0
- claude_mpm/services/unified/analyzer_strategies/__init__.py +44 -0
- claude_mpm/services/unified/analyzer_strategies/code_analyzer.py +518 -0
- claude_mpm/services/unified/analyzer_strategies/dependency_analyzer.py +680 -0
- claude_mpm/services/unified/analyzer_strategies/performance_analyzer.py +900 -0
- claude_mpm/services/unified/analyzer_strategies/security_analyzer.py +745 -0
- claude_mpm/services/unified/analyzer_strategies/structure_analyzer.py +733 -0
- claude_mpm/services/unified/config_strategies/__init__.py +175 -0
- claude_mpm/services/unified/config_strategies/config_schema.py +731 -0
- claude_mpm/services/unified/config_strategies/context_strategy.py +747 -0
- claude_mpm/services/unified/config_strategies/error_handling_strategy.py +1005 -0
- claude_mpm/services/unified/config_strategies/file_loader_strategy.py +881 -0
- claude_mpm/services/unified/config_strategies/unified_config_service.py +823 -0
- claude_mpm/services/unified/config_strategies/validation_strategy.py +1148 -0
- claude_mpm/services/unified/deployment_strategies/__init__.py +97 -0
- claude_mpm/services/unified/deployment_strategies/base.py +553 -0
- claude_mpm/services/unified/deployment_strategies/cloud_strategies.py +573 -0
- claude_mpm/services/unified/deployment_strategies/local.py +607 -0
- claude_mpm/services/unified/deployment_strategies/utils.py +667 -0
- claude_mpm/services/unified/deployment_strategies/vercel.py +471 -0
- claude_mpm/services/unified/interfaces.py +475 -0
- claude_mpm/services/unified/migration.py +509 -0
- claude_mpm/services/unified/strategies.py +534 -0
- claude_mpm/services/unified/unified_analyzer.py +542 -0
- claude_mpm/services/unified/unified_config.py +691 -0
- claude_mpm/services/unified/unified_deployment.py +466 -0
- claude_mpm/services/utility_service.py +280 -0
- claude_mpm/services/version_control/__init__.py +34 -37
- claude_mpm/services/version_control/branch_strategy.py +26 -17
- claude_mpm/services/version_control/conflict_resolution.py +52 -36
- claude_mpm/services/version_control/git_operations.py +183 -49
- claude_mpm/services/version_control/semantic_versioning.py +172 -61
- claude_mpm/services/version_control/version_parser.py +546 -0
- claude_mpm/services/version_service.py +379 -0
- claude_mpm/services/visualization/__init__.py +15 -0
- claude_mpm/services/visualization/mermaid_generator.py +937 -0
- claude_mpm/skills/__init__.py +42 -0
- claude_mpm/skills/agent_skills_injector.py +324 -0
- claude_mpm/skills/bundled/LICENSE_ATTRIBUTIONS.md +79 -0
- claude_mpm/skills/bundled/__init__.py +6 -0
- claude_mpm/skills/bundled/api-documentation.md +393 -0
- claude_mpm/skills/bundled/async-testing.md +571 -0
- claude_mpm/skills/bundled/code-review.md +143 -0
- claude_mpm/skills/bundled/database-migration.md +199 -0
- claude_mpm/skills/bundled/docker-containerization.md +194 -0
- claude_mpm/skills/bundled/express-local-dev.md +1429 -0
- claude_mpm/skills/bundled/fastapi-local-dev.md +1199 -0
- claude_mpm/skills/bundled/git-workflow.md +414 -0
- claude_mpm/skills/bundled/imagemagick.md +204 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/scripts/validate_env.py +576 -0
- claude_mpm/skills/bundled/json-data-handling.md +223 -0
- claude_mpm/skills/bundled/main/mcp-builder/scripts/connections.py +157 -0
- claude_mpm/skills/bundled/main/mcp-builder/scripts/evaluation.py +425 -0
- claude_mpm/skills/bundled/main/skill-creator/scripts/init_skill.py +303 -0
- claude_mpm/skills/bundled/main/skill-creator/scripts/package_skill.py +113 -0
- claude_mpm/skills/bundled/main/skill-creator/scripts/quick_validate.py +72 -0
- claude_mpm/skills/bundled/nextjs-local-dev.md +807 -0
- claude_mpm/skills/bundled/pdf.md +141 -0
- claude_mpm/skills/bundled/performance-profiling.md +573 -0
- claude_mpm/skills/bundled/refactoring-patterns.md +180 -0
- claude_mpm/skills/bundled/security-scanning.md +439 -0
- claude_mpm/skills/bundled/systematic-debugging.md +473 -0
- claude_mpm/skills/bundled/test-driven-development.md +378 -0
- claude_mpm/skills/bundled/testing/webapp-testing/examples/console_logging.py +35 -0
- claude_mpm/skills/bundled/testing/webapp-testing/examples/element_discovery.py +44 -0
- claude_mpm/skills/bundled/testing/webapp-testing/examples/static_html_automation.py +34 -0
- claude_mpm/skills/bundled/testing/webapp-testing/scripts/with_server.py +129 -0
- claude_mpm/skills/bundled/vite-local-dev.md +1061 -0
- claude_mpm/skills/bundled/web-performance-optimization.md +2305 -0
- claude_mpm/skills/bundled/xlsx.md +157 -0
- claude_mpm/skills/registry.py +286 -0
- claude_mpm/skills/skill_manager.py +405 -0
- claude_mpm/skills/skills_registry.py +347 -0
- claude_mpm/skills/skills_service.py +739 -0
- claude_mpm/storage/__init__.py +9 -0
- claude_mpm/storage/state_storage.py +546 -0
- claude_mpm/templates/.pre-commit-config.yaml +112 -0
- claude_mpm/templates/questions/__init__.py +38 -0
- claude_mpm/templates/questions/base.py +193 -0
- claude_mpm/templates/questions/pr_strategy.py +311 -0
- claude_mpm/templates/questions/project_init.py +385 -0
- claude_mpm/templates/questions/ticket_mgmt.py +394 -0
- claude_mpm/ticket_wrapper.py +2 -2
- claude_mpm/tools/__init__.py +10 -0
- claude_mpm/tools/__main__.py +208 -0
- claude_mpm/tools/code_tree_analyzer/__init__.py +45 -0
- claude_mpm/tools/code_tree_analyzer/analysis.py +299 -0
- claude_mpm/tools/code_tree_analyzer/cache.py +131 -0
- claude_mpm/tools/code_tree_analyzer/core.py +380 -0
- claude_mpm/tools/code_tree_analyzer/discovery.py +403 -0
- claude_mpm/tools/code_tree_analyzer/events.py +168 -0
- claude_mpm/tools/code_tree_analyzer/gitignore.py +308 -0
- claude_mpm/tools/code_tree_analyzer/models.py +39 -0
- claude_mpm/tools/code_tree_analyzer/multilang_analyzer.py +224 -0
- claude_mpm/tools/code_tree_analyzer/python_analyzer.py +284 -0
- claude_mpm/tools/code_tree_builder.py +631 -0
- claude_mpm/tools/code_tree_events.py +420 -0
- claude_mpm/tools/socketio_debug.py +671 -0
- claude_mpm/utils/__init__.py +8 -8
- claude_mpm/utils/agent_dependency_loader.py +1090 -0
- claude_mpm/utils/agent_filters.py +261 -0
- claude_mpm/utils/common.py +544 -0
- claude_mpm/utils/config_manager.py +168 -126
- claude_mpm/utils/console.py +11 -0
- claude_mpm/utils/database_connector.py +298 -0
- claude_mpm/utils/dependency_cache.py +373 -0
- claude_mpm/utils/dependency_manager.py +60 -59
- claude_mpm/utils/dependency_strategies.py +381 -0
- claude_mpm/utils/display_helper.py +260 -0
- claude_mpm/utils/environment_context.py +313 -0
- claude_mpm/utils/error_handler.py +78 -66
- claude_mpm/utils/file_utils.py +305 -0
- claude_mpm/utils/framework_detection.py +12 -11
- claude_mpm/utils/git_analyzer.py +407 -0
- claude_mpm/utils/gitignore.py +244 -0
- claude_mpm/utils/import_migration_example.py +12 -60
- claude_mpm/utils/imports.py +48 -45
- claude_mpm/utils/log_cleanup.py +627 -0
- claude_mpm/utils/migration.py +372 -0
- claude_mpm/utils/path_operations.py +110 -104
- claude_mpm/utils/progress.py +387 -0
- claude_mpm/utils/robust_installer.py +823 -0
- claude_mpm/utils/session_logging.py +121 -0
- claude_mpm/utils/structured_questions.py +619 -0
- claude_mpm/utils/subprocess_utils.py +343 -0
- claude_mpm/validation/__init__.py +1 -1
- claude_mpm/validation/agent_validator.py +214 -108
- claude_mpm/validation/frontmatter_validator.py +252 -0
- claude_mpm-5.4.55.dist-info/METADATA +999 -0
- claude_mpm-5.4.55.dist-info/RECORD +868 -0
- {claude_mpm-3.4.10.dist-info → claude_mpm-5.4.55.dist-info}/entry_points.txt +1 -3
- claude_mpm-5.4.55.dist-info/licenses/LICENSE +94 -0
- claude_mpm-5.4.55.dist-info/licenses/LICENSE-FAQ.md +153 -0
- claude_mpm/agents/BASE_AGENT_TEMPLATE.md +0 -88
- claude_mpm/agents/INSTRUCTIONS.md +0 -352
- claude_mpm/agents/backups/INSTRUCTIONS.md +0 -352
- claude_mpm/agents/base_agent_loader.py +0 -529
- claude_mpm/agents/schema/agent_schema.json +0 -314
- claude_mpm/agents/templates/.claude-mpm/memories/README.md +0 -36
- claude_mpm/agents/templates/backup/data_engineer_agent_20250726_234551.json +0 -46
- claude_mpm/agents/templates/backup/documentation_agent_20250726_234551.json +0 -45
- claude_mpm/agents/templates/backup/engineer_agent_20250726_234551.json +0 -49
- claude_mpm/agents/templates/backup/ops_agent_20250726_234551.json +0 -46
- claude_mpm/agents/templates/backup/qa_agent_20250726_234551.json +0 -45
- claude_mpm/agents/templates/backup/research_agent_20250726_234551.json +0 -49
- claude_mpm/agents/templates/backup/security_agent_20250726_234551.json +0 -46
- claude_mpm/agents/templates/backup/version_control_agent_20250726_234551.json +0 -46
- claude_mpm/agents/templates/data_engineer.json +0 -110
- claude_mpm/agents/templates/documentation.json +0 -109
- claude_mpm/agents/templates/engineer.json +0 -113
- claude_mpm/agents/templates/ops.json +0 -109
- claude_mpm/agents/templates/pm.json +0 -25
- claude_mpm/agents/templates/qa.json +0 -111
- claude_mpm/agents/templates/research.json +0 -65
- claude_mpm/agents/templates/security.json +0 -113
- claude_mpm/agents/templates/test_integration.json +0 -112
- claude_mpm/agents/templates/version_control.json +0 -107
- claude_mpm/cli/commands/ui.py +0 -57
- claude_mpm/core/simple_runner.py +0 -1046
- claude_mpm/dashboard/open_dashboard.py +0 -34
- claude_mpm/deployment_paths.py +0 -261
- claude_mpm/hooks/builtin/__init__.py +0 -1
- claude_mpm/hooks/builtin/logging_hook_example.py +0 -165
- claude_mpm/hooks/builtin/memory_hooks_example.py +0 -67
- claude_mpm/hooks/builtin/mpm_command_hook.py +0 -125
- claude_mpm/hooks/builtin/post_delegation_hook_example.py +0 -124
- claude_mpm/hooks/builtin/pre_delegation_hook_example.py +0 -125
- claude_mpm/hooks/builtin/submit_hook_example.py +0 -100
- claude_mpm/hooks/builtin/ticket_extraction_hook_example.py +0 -237
- claude_mpm/hooks/builtin/todo_agent_prefix_hook.py +0 -240
- claude_mpm/hooks/builtin/workflow_start_hook.py +0 -181
- claude_mpm/orchestration/__init__.py +0 -6
- claude_mpm/orchestration/archive/direct_orchestrator.py +0 -195
- claude_mpm/orchestration/archive/factory.py +0 -215
- claude_mpm/orchestration/archive/hook_enabled_orchestrator.py +0 -188
- claude_mpm/orchestration/archive/hook_integration_example.py +0 -178
- claude_mpm/orchestration/archive/interactive_subprocess_orchestrator.py +0 -826
- claude_mpm/orchestration/archive/orchestrator.py +0 -501
- claude_mpm/orchestration/archive/pexpect_orchestrator.py +0 -252
- claude_mpm/orchestration/archive/pty_orchestrator.py +0 -270
- claude_mpm/orchestration/archive/simple_orchestrator.py +0 -82
- claude_mpm/orchestration/archive/subprocess_orchestrator.py +0 -801
- claude_mpm/orchestration/archive/system_prompt_orchestrator.py +0 -278
- claude_mpm/orchestration/archive/wrapper_orchestrator.py +0 -187
- claude_mpm/schemas/workflow_validator.py +0 -411
- claude_mpm/services/agent_deployment.py +0 -1534
- claude_mpm/services/agent_lifecycle_manager.py +0 -1169
- claude_mpm/services/agent_memory_manager.py +0 -1415
- claude_mpm/services/agent_registry.py +0 -676
- claude_mpm/services/deployed_agent_discovery.py +0 -226
- claude_mpm/services/framework_agent_loader.py +0 -337
- claude_mpm/services/framework_claude_md_generator.py +0 -621
- claude_mpm/services/health_monitor.py +0 -892
- claude_mpm/services/memory_router.py +0 -538
- claude_mpm/services/parent_directory_manager/__init__.py +0 -577
- claude_mpm/services/parent_directory_manager/backup_manager.py +0 -258
- claude_mpm/services/parent_directory_manager/config_manager.py +0 -210
- claude_mpm/services/parent_directory_manager/deduplication_manager.py +0 -279
- claude_mpm/services/parent_directory_manager/framework_protector.py +0 -143
- claude_mpm/services/parent_directory_manager/operations.py +0 -186
- claude_mpm/services/parent_directory_manager/state_manager.py +0 -624
- claude_mpm/services/parent_directory_manager/template_deployer.py +0 -579
- claude_mpm/services/parent_directory_manager/validation_manager.py +0 -378
- claude_mpm/services/parent_directory_manager/version_control_helper.py +0 -339
- claude_mpm/services/parent_directory_manager/version_manager.py +0 -222
- claude_mpm/services/standalone_socketio_server.py +0 -1300
- claude_mpm/services/ticket_manager_di.py +0 -318
- claude_mpm/services/ticketing_service_original.py +0 -508
- claude_mpm/ui/__init__.py +0 -1
- claude_mpm/ui/rich_terminal_ui.py +0 -295
- claude_mpm/ui/terminal_ui.py +0 -328
- claude_mpm/utils/paths.py +0 -289
- claude_mpm-3.4.10.dist-info/METADATA +0 -183
- claude_mpm-3.4.10.dist-info/RECORD +0 -201
- claude_mpm-3.4.10.dist-info/licenses/LICENSE +0 -21
- {claude_mpm-3.4.10.dist-info → claude_mpm-5.4.55.dist-info}/WHEEL +0 -0
- {claude_mpm-3.4.10.dist-info → claude_mpm-5.4.55.dist-info}/top_level.txt +0 -0
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
"""Agent-specific session management for performance optimization."""
|
|
2
2
|
|
|
3
|
-
import uuid
|
|
4
|
-
from typing import Dict, Optional, Tuple
|
|
5
|
-
from datetime import datetime, timedelta
|
|
6
|
-
from pathlib import Path
|
|
7
3
|
import json
|
|
4
|
+
import uuid
|
|
8
5
|
from collections import defaultdict
|
|
6
|
+
from datetime import datetime, timedelta, timezone
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Dict, Optional
|
|
9
9
|
|
|
10
10
|
from ..core.logger import get_logger
|
|
11
11
|
|
|
@@ -14,10 +14,12 @@ logger = get_logger(__name__)
|
|
|
14
14
|
|
|
15
15
|
class AgentSessionManager:
|
|
16
16
|
"""Manages separate sessions for each agent type to avoid context pollution."""
|
|
17
|
-
|
|
18
|
-
def __init__(
|
|
17
|
+
|
|
18
|
+
def __init__(
|
|
19
|
+
self, session_dir: Optional[Path] = None, max_sessions_per_agent: int = 3
|
|
20
|
+
):
|
|
19
21
|
"""Initialize agent session manager.
|
|
20
|
-
|
|
22
|
+
|
|
21
23
|
Args:
|
|
22
24
|
session_dir: Directory to store session metadata
|
|
23
25
|
max_sessions_per_agent: Maximum concurrent sessions per agent type
|
|
@@ -25,129 +27,136 @@ class AgentSessionManager:
|
|
|
25
27
|
self.session_dir = session_dir or Path.home() / ".claude-mpm" / "agent_sessions"
|
|
26
28
|
self.session_dir.mkdir(parents=True, exist_ok=True)
|
|
27
29
|
self.max_sessions_per_agent = max_sessions_per_agent
|
|
28
|
-
|
|
30
|
+
|
|
29
31
|
# Sessions organized by agent type
|
|
30
32
|
self.agent_sessions: Dict[str, Dict[str, Dict]] = defaultdict(dict)
|
|
31
33
|
self.session_locks: Dict[str, bool] = {} # Track which sessions are in use
|
|
32
|
-
|
|
34
|
+
|
|
33
35
|
self._load_sessions()
|
|
34
|
-
|
|
35
|
-
def get_agent_session(
|
|
36
|
+
|
|
37
|
+
def get_agent_session(
|
|
38
|
+
self, agent_type: str, create_if_missing: bool = True
|
|
39
|
+
) -> Optional[str]:
|
|
36
40
|
"""Get or create a session for a specific agent type.
|
|
37
|
-
|
|
41
|
+
|
|
38
42
|
Args:
|
|
39
43
|
agent_type: Type of agent (e.g., "engineer", "qa", "documentation")
|
|
40
44
|
create_if_missing: Whether to create a new session if none available
|
|
41
|
-
|
|
45
|
+
|
|
42
46
|
Returns:
|
|
43
47
|
Session ID or None
|
|
44
48
|
"""
|
|
45
49
|
agent_type = agent_type.lower()
|
|
46
|
-
|
|
50
|
+
|
|
47
51
|
# Find an available session for this agent
|
|
48
52
|
for session_id, session_data in self.agent_sessions[agent_type].items():
|
|
49
53
|
if not self.session_locks.get(session_id, False):
|
|
50
54
|
# Check if session is still fresh (not too old)
|
|
51
55
|
created = datetime.fromisoformat(session_data["created_at"])
|
|
52
|
-
if datetime.now() - created < timedelta(hours=1):
|
|
56
|
+
if datetime.now(timezone.utc) - created < timedelta(hours=1):
|
|
53
57
|
# Use this session
|
|
54
58
|
self.session_locks[session_id] = True
|
|
55
|
-
session_data["last_used"] = datetime.now().isoformat()
|
|
59
|
+
session_data["last_used"] = datetime.now(timezone.utc).isoformat()
|
|
56
60
|
session_data["use_count"] += 1
|
|
57
61
|
logger.info(f"Reusing session {session_id} for {agent_type} agent")
|
|
58
62
|
return session_id
|
|
59
|
-
|
|
63
|
+
|
|
60
64
|
# No available session, create new one if allowed
|
|
61
|
-
if
|
|
65
|
+
if (
|
|
66
|
+
create_if_missing
|
|
67
|
+
and len(self.agent_sessions[agent_type]) < self.max_sessions_per_agent
|
|
68
|
+
):
|
|
62
69
|
return self.create_agent_session(agent_type)
|
|
63
|
-
|
|
70
|
+
|
|
64
71
|
return None
|
|
65
|
-
|
|
72
|
+
|
|
66
73
|
def create_agent_session(self, agent_type: str) -> str:
|
|
67
74
|
"""Create a new session for a specific agent type.
|
|
68
|
-
|
|
75
|
+
|
|
69
76
|
Args:
|
|
70
77
|
agent_type: Type of agent
|
|
71
|
-
|
|
78
|
+
|
|
72
79
|
Returns:
|
|
73
80
|
New session ID
|
|
74
81
|
"""
|
|
75
82
|
session_id = str(uuid.uuid4())
|
|
76
83
|
agent_type = agent_type.lower()
|
|
77
|
-
|
|
84
|
+
|
|
78
85
|
session_data = {
|
|
79
86
|
"id": session_id,
|
|
80
87
|
"agent_type": agent_type,
|
|
81
|
-
"created_at": datetime.now().isoformat(),
|
|
82
|
-
"last_used": datetime.now().isoformat(),
|
|
88
|
+
"created_at": datetime.now(timezone.utc).isoformat(),
|
|
89
|
+
"last_used": datetime.now(timezone.utc).isoformat(),
|
|
83
90
|
"use_count": 0,
|
|
84
|
-
"tasks_completed": []
|
|
91
|
+
"tasks_completed": [],
|
|
85
92
|
}
|
|
86
|
-
|
|
93
|
+
|
|
87
94
|
self.agent_sessions[agent_type][session_id] = session_data
|
|
88
95
|
self.session_locks[session_id] = True
|
|
89
96
|
self._save_sessions()
|
|
90
|
-
|
|
97
|
+
|
|
91
98
|
logger.info(f"Created new session {session_id} for {agent_type} agent")
|
|
92
99
|
return session_id
|
|
93
|
-
|
|
100
|
+
|
|
94
101
|
def release_session(self, session_id: str):
|
|
95
102
|
"""Release a session back to the pool.
|
|
96
|
-
|
|
103
|
+
|
|
97
104
|
Args:
|
|
98
105
|
session_id: Session to release
|
|
99
106
|
"""
|
|
100
107
|
if session_id in self.session_locks:
|
|
101
108
|
self.session_locks[session_id] = False
|
|
102
109
|
logger.debug(f"Released session {session_id}")
|
|
103
|
-
|
|
110
|
+
|
|
104
111
|
def record_task(self, session_id: str, task: str, success: bool = True):
|
|
105
112
|
"""Record a task completion for a session.
|
|
106
|
-
|
|
113
|
+
|
|
107
114
|
Args:
|
|
108
115
|
session_id: Session ID
|
|
109
116
|
task: Task description
|
|
110
117
|
success: Whether task completed successfully
|
|
111
118
|
"""
|
|
112
119
|
# Find which agent this session belongs to
|
|
113
|
-
for
|
|
120
|
+
for _agent_type, sessions in self.agent_sessions.items():
|
|
114
121
|
if session_id in sessions:
|
|
115
|
-
sessions[session_id]["tasks_completed"].append(
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
122
|
+
sessions[session_id]["tasks_completed"].append(
|
|
123
|
+
{
|
|
124
|
+
"task": task[:100], # Truncate long tasks
|
|
125
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
126
|
+
"success": success,
|
|
127
|
+
}
|
|
128
|
+
)
|
|
120
129
|
self._save_sessions()
|
|
121
130
|
break
|
|
122
|
-
|
|
131
|
+
|
|
123
132
|
def cleanup_old_sessions(self, max_age_hours: int = 4):
|
|
124
133
|
"""Remove sessions older than max_age_hours.
|
|
125
|
-
|
|
134
|
+
|
|
126
135
|
Args:
|
|
127
136
|
max_age_hours: Maximum age in hours
|
|
128
137
|
"""
|
|
129
|
-
now = datetime.now()
|
|
138
|
+
now = datetime.now(timezone.utc)
|
|
130
139
|
max_age = timedelta(hours=max_age_hours)
|
|
131
|
-
|
|
140
|
+
|
|
132
141
|
for agent_type in list(self.agent_sessions.keys()):
|
|
133
142
|
expired = []
|
|
134
143
|
for session_id, session_data in self.agent_sessions[agent_type].items():
|
|
135
144
|
created = datetime.fromisoformat(session_data["created_at"])
|
|
136
145
|
if now - created > max_age:
|
|
137
146
|
expired.append(session_id)
|
|
138
|
-
|
|
147
|
+
|
|
139
148
|
for session_id in expired:
|
|
140
149
|
del self.agent_sessions[agent_type][session_id]
|
|
141
150
|
if session_id in self.session_locks:
|
|
142
151
|
del self.session_locks[session_id]
|
|
143
152
|
logger.info(f"Cleaned up expired {agent_type} session: {session_id}")
|
|
144
|
-
|
|
153
|
+
|
|
145
154
|
if any(self.agent_sessions.values()):
|
|
146
155
|
self._save_sessions()
|
|
147
|
-
|
|
156
|
+
|
|
148
157
|
def get_session_stats(self) -> Dict[str, Dict]:
|
|
149
158
|
"""Get statistics about current sessions.
|
|
150
|
-
|
|
159
|
+
|
|
151
160
|
Returns:
|
|
152
161
|
Stats by agent type
|
|
153
162
|
"""
|
|
@@ -155,23 +164,23 @@ class AgentSessionManager:
|
|
|
155
164
|
for agent_type, sessions in self.agent_sessions.items():
|
|
156
165
|
active = sum(1 for sid in sessions if self.session_locks.get(sid, False))
|
|
157
166
|
total_tasks = sum(len(s["tasks_completed"]) for s in sessions.values())
|
|
158
|
-
|
|
167
|
+
|
|
159
168
|
stats[agent_type] = {
|
|
160
169
|
"total_sessions": len(sessions),
|
|
161
170
|
"active_sessions": active,
|
|
162
171
|
"available_sessions": len(sessions) - active,
|
|
163
|
-
"total_tasks_completed": total_tasks
|
|
172
|
+
"total_tasks_completed": total_tasks,
|
|
164
173
|
}
|
|
165
|
-
|
|
174
|
+
|
|
166
175
|
return stats
|
|
167
|
-
|
|
176
|
+
|
|
168
177
|
def initialize_agent_session(self, agent_type: str, session_id: str) -> str:
|
|
169
178
|
"""Initialize a session with agent-specific context.
|
|
170
|
-
|
|
179
|
+
|
|
171
180
|
Args:
|
|
172
181
|
agent_type: Type of agent
|
|
173
182
|
session_id: Session ID to initialize
|
|
174
|
-
|
|
183
|
+
|
|
175
184
|
Returns:
|
|
176
185
|
Initialization prompt for the agent
|
|
177
186
|
"""
|
|
@@ -184,36 +193,38 @@ class AgentSessionManager:
|
|
|
184
193
|
"security": "You are the Security Agent. Your role is security analysis and protection. Confirm with 'Security Agent ready.'",
|
|
185
194
|
"ops": "You are the Ops Agent. Your role is deployment and operations. Confirm with 'Ops Agent ready.'",
|
|
186
195
|
"data_engineer": "You are the Data Engineer Agent. Your role is data management and processing. Confirm with 'Data Engineer Agent ready.'",
|
|
187
|
-
"version_control": "You are the Version Control Agent. Your role is Git operations and version management. Confirm with 'Version Control Agent ready.'"
|
|
196
|
+
"version_control": "You are the Version Control Agent. Your role is Git operations and version management. Confirm with 'Version Control Agent ready.'",
|
|
188
197
|
}
|
|
189
|
-
|
|
198
|
+
|
|
190
199
|
return initialization_prompts.get(
|
|
191
|
-
agent_type.lower(),
|
|
192
|
-
f"You are the {agent_type} Agent. Confirm with '{agent_type} Agent ready.'"
|
|
200
|
+
agent_type.lower(),
|
|
201
|
+
f"You are the {agent_type} Agent. Confirm with '{agent_type} Agent ready.'",
|
|
193
202
|
)
|
|
194
|
-
|
|
203
|
+
|
|
195
204
|
def _save_sessions(self):
|
|
196
205
|
"""Save sessions to disk."""
|
|
197
206
|
session_file = self.session_dir / "agent_sessions.json"
|
|
198
207
|
try:
|
|
199
208
|
data = {
|
|
200
209
|
"agent_sessions": dict(self.agent_sessions),
|
|
201
|
-
"updated_at": datetime.now().isoformat()
|
|
210
|
+
"updated_at": datetime.now(timezone.utc).isoformat(),
|
|
202
211
|
}
|
|
203
|
-
with open(
|
|
212
|
+
with session_file.open("w") as f:
|
|
204
213
|
json.dump(data, f, indent=2)
|
|
205
214
|
except Exception as e:
|
|
206
215
|
logger.error(f"Failed to save agent sessions: {e}")
|
|
207
|
-
|
|
216
|
+
|
|
208
217
|
def _load_sessions(self):
|
|
209
218
|
"""Load sessions from disk."""
|
|
210
219
|
session_file = self.session_dir / "agent_sessions.json"
|
|
211
220
|
if session_file.exists():
|
|
212
221
|
try:
|
|
213
|
-
with open(
|
|
222
|
+
with session_file.open() as f:
|
|
214
223
|
data = json.load(f)
|
|
215
|
-
self.agent_sessions = defaultdict(
|
|
216
|
-
|
|
224
|
+
self.agent_sessions = defaultdict(
|
|
225
|
+
dict, data.get("agent_sessions", {})
|
|
226
|
+
)
|
|
227
|
+
|
|
217
228
|
# Clean up old sessions on load
|
|
218
229
|
self.cleanup_old_sessions()
|
|
219
230
|
except Exception as e:
|
|
@@ -228,7 +239,7 @@ class SubprocessOrchestrator:
|
|
|
228
239
|
self.agent_session_manager = AgentSessionManager()
|
|
229
240
|
# Pre-warm common agent sessions on startup
|
|
230
241
|
self._prewarm_agent_sessions()
|
|
231
|
-
|
|
242
|
+
|
|
232
243
|
def _prewarm_agent_sessions(self):
|
|
233
244
|
'''Pre-warm sessions for common agents.'''
|
|
234
245
|
common_agents = ['engineer', 'qa', 'documentation']
|
|
@@ -242,11 +253,11 @@ class SubprocessOrchestrator:
|
|
|
242
253
|
timeout=10
|
|
243
254
|
)
|
|
244
255
|
self.agent_session_manager.release_session(session_id)
|
|
245
|
-
|
|
256
|
+
|
|
246
257
|
def run_subprocess(self, agent: str, task: str) -> Tuple[str, float, int]:
|
|
247
258
|
# Get a session for this agent type
|
|
248
259
|
session_id = self.agent_session_manager.get_agent_session(agent)
|
|
249
|
-
|
|
260
|
+
|
|
250
261
|
try:
|
|
251
262
|
# Create agent prompt (without role definition since session knows)
|
|
252
263
|
prompt = f'''
|
|
@@ -256,18 +267,18 @@ class SubprocessOrchestrator:
|
|
|
256
267
|
## Response Format
|
|
257
268
|
Provide a clear, structured response that completes the requested task.
|
|
258
269
|
'''
|
|
259
|
-
|
|
270
|
+
|
|
260
271
|
# Run with agent-specific session
|
|
261
272
|
stdout, stderr, returncode = self.launcher.launch_oneshot(
|
|
262
273
|
message=prompt,
|
|
263
274
|
session_id=session_id, # Reuses agent-specific context!
|
|
264
275
|
timeout=60
|
|
265
276
|
)
|
|
266
|
-
|
|
277
|
+
|
|
267
278
|
# Record task completion
|
|
268
279
|
self.agent_session_manager.record_task(session_id, task, returncode == 0)
|
|
269
|
-
|
|
280
|
+
|
|
270
281
|
finally:
|
|
271
282
|
# Release session back to pool
|
|
272
283
|
self.agent_session_manager.release_session(session_id)
|
|
273
|
-
"""
|
|
284
|
+
"""
|
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
"""API Key Validation Module for Claude MPM.
|
|
2
|
+
|
|
3
|
+
This module validates API keys for various services on startup to ensure
|
|
4
|
+
proper configuration and prevent runtime failures. It follows the principle
|
|
5
|
+
of failing fast with clear error messages rather than degrading gracefully.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import os
|
|
9
|
+
from typing import Dict, List, Optional, Tuple
|
|
10
|
+
|
|
11
|
+
import requests
|
|
12
|
+
|
|
13
|
+
from claude_mpm.core.logger import get_logger
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class APIKeyValidator:
|
|
17
|
+
"""Validates API keys for various services on framework startup."""
|
|
18
|
+
|
|
19
|
+
def __init__(self, config: Optional[Dict] = None):
|
|
20
|
+
"""Initialize the API validator.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
config: Optional configuration dictionary
|
|
24
|
+
"""
|
|
25
|
+
self.logger = get_logger("api_validator")
|
|
26
|
+
self.config = config or {}
|
|
27
|
+
self.errors: List[str] = []
|
|
28
|
+
self.warnings: List[str] = []
|
|
29
|
+
|
|
30
|
+
def validate_all_keys(
|
|
31
|
+
self, strict: bool = True
|
|
32
|
+
) -> Tuple[bool, List[str], List[str]]:
|
|
33
|
+
"""Validate all configured API keys.
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
strict: If True, validation failures raise exceptions.
|
|
37
|
+
If False, failures are logged as warnings.
|
|
38
|
+
|
|
39
|
+
Returns:
|
|
40
|
+
Tuple of (success, errors, warnings)
|
|
41
|
+
"""
|
|
42
|
+
self.errors = []
|
|
43
|
+
self.warnings = []
|
|
44
|
+
|
|
45
|
+
# Check if validation is enabled
|
|
46
|
+
if not self.config.get("validate_api_keys", True):
|
|
47
|
+
self.logger.info("API key validation disabled in config")
|
|
48
|
+
return True, [], []
|
|
49
|
+
|
|
50
|
+
# Validate OpenAI key if configured
|
|
51
|
+
openai_key = os.getenv("OPENAI_API_KEY")
|
|
52
|
+
if openai_key:
|
|
53
|
+
self._validate_openai_key(openai_key)
|
|
54
|
+
|
|
55
|
+
# Validate Anthropic key if configured
|
|
56
|
+
anthropic_key = os.getenv("ANTHROPIC_API_KEY")
|
|
57
|
+
if anthropic_key:
|
|
58
|
+
self._validate_anthropic_key(anthropic_key)
|
|
59
|
+
|
|
60
|
+
# Validate GitHub token if configured
|
|
61
|
+
github_token = os.getenv("GITHUB_TOKEN")
|
|
62
|
+
if github_token:
|
|
63
|
+
self._validate_github_token(github_token)
|
|
64
|
+
|
|
65
|
+
# Validate custom API keys from config
|
|
66
|
+
custom_apis = self.config.get("custom_api_validations", {})
|
|
67
|
+
for api_name, validation_config in custom_apis.items():
|
|
68
|
+
self._validate_custom_api(api_name, validation_config)
|
|
69
|
+
|
|
70
|
+
# Report results
|
|
71
|
+
if self.errors:
|
|
72
|
+
error_msg = "API Key Validation Failed:\n" + "\n".join(self.errors)
|
|
73
|
+
if strict:
|
|
74
|
+
self.logger.error(error_msg)
|
|
75
|
+
raise ValueError(error_msg)
|
|
76
|
+
self.logger.warning(error_msg)
|
|
77
|
+
|
|
78
|
+
if self.warnings:
|
|
79
|
+
for warning in self.warnings:
|
|
80
|
+
self.logger.warning(warning)
|
|
81
|
+
|
|
82
|
+
if not self.errors:
|
|
83
|
+
self.logger.info("✅ All configured API keys validated successfully")
|
|
84
|
+
|
|
85
|
+
return not bool(self.errors), self.errors, self.warnings
|
|
86
|
+
|
|
87
|
+
def _validate_openai_key(self, api_key: str) -> bool:
|
|
88
|
+
"""Validate OpenAI API key.
|
|
89
|
+
|
|
90
|
+
Args:
|
|
91
|
+
api_key: The OpenAI API key to validate
|
|
92
|
+
|
|
93
|
+
Returns:
|
|
94
|
+
True if valid, False otherwise
|
|
95
|
+
"""
|
|
96
|
+
try:
|
|
97
|
+
# Make a lightweight request to validate the key
|
|
98
|
+
response = requests.get(
|
|
99
|
+
"https://api.openai.com/v1/models",
|
|
100
|
+
headers={"Authorization": f"Bearer {api_key}"},
|
|
101
|
+
timeout=10,
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
if response.status_code == 401:
|
|
105
|
+
self.errors.append("❌ OpenAI API key is invalid (401 Unauthorized)")
|
|
106
|
+
return False
|
|
107
|
+
if response.status_code == 403:
|
|
108
|
+
self.errors.append(
|
|
109
|
+
"❌ OpenAI API key lacks required permissions (403 Forbidden)"
|
|
110
|
+
)
|
|
111
|
+
return False
|
|
112
|
+
if response.status_code == 429:
|
|
113
|
+
# Rate limited but key is valid
|
|
114
|
+
self.warnings.append("⚠️ OpenAI API key is valid but rate limited")
|
|
115
|
+
return True
|
|
116
|
+
if response.status_code == 200:
|
|
117
|
+
self.logger.debug("✅ OpenAI API key validated successfully")
|
|
118
|
+
return True
|
|
119
|
+
self.warnings.append(
|
|
120
|
+
f"⚠️ OpenAI API returned unexpected status: {response.status_code}"
|
|
121
|
+
)
|
|
122
|
+
return True # Assume valid for unexpected status codes
|
|
123
|
+
|
|
124
|
+
except requests.exceptions.Timeout:
|
|
125
|
+
self.warnings.append(
|
|
126
|
+
"⚠️ OpenAI API validation timed out - assuming key is valid"
|
|
127
|
+
)
|
|
128
|
+
return True
|
|
129
|
+
except requests.exceptions.ConnectionError as e:
|
|
130
|
+
self.warnings.append(f"⚠️ Could not connect to OpenAI API: {e}")
|
|
131
|
+
return True
|
|
132
|
+
except Exception as e:
|
|
133
|
+
self.errors.append(f"❌ OpenAI API validation failed with error: {e}")
|
|
134
|
+
return False
|
|
135
|
+
|
|
136
|
+
def _validate_anthropic_key(self, api_key: str) -> bool:
|
|
137
|
+
"""Validate Anthropic API key.
|
|
138
|
+
|
|
139
|
+
Args:
|
|
140
|
+
api_key: The Anthropic API key to validate
|
|
141
|
+
|
|
142
|
+
Returns:
|
|
143
|
+
True if valid, False otherwise
|
|
144
|
+
"""
|
|
145
|
+
try:
|
|
146
|
+
# Make a minimal request to validate the key
|
|
147
|
+
# Using a very small max_tokens to minimize cost
|
|
148
|
+
response = requests.post(
|
|
149
|
+
"https://api.anthropic.com/v1/messages",
|
|
150
|
+
headers={
|
|
151
|
+
"x-api-key": api_key,
|
|
152
|
+
"anthropic-version": "2023-06-01",
|
|
153
|
+
"content-type": "application/json",
|
|
154
|
+
},
|
|
155
|
+
json={
|
|
156
|
+
"model": "claude-3-haiku-20240307", # Use cheapest model
|
|
157
|
+
"messages": [{"role": "user", "content": "test"}],
|
|
158
|
+
"max_tokens": 1,
|
|
159
|
+
},
|
|
160
|
+
timeout=10,
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
if response.status_code == 401:
|
|
164
|
+
self.errors.append("❌ Anthropic API key is invalid (401 Unauthorized)")
|
|
165
|
+
return False
|
|
166
|
+
if response.status_code == 403:
|
|
167
|
+
self.errors.append(
|
|
168
|
+
"❌ Anthropic API key lacks required permissions (403 Forbidden)"
|
|
169
|
+
)
|
|
170
|
+
return False
|
|
171
|
+
if response.status_code == 400:
|
|
172
|
+
# Bad request but key is valid (we sent minimal request on purpose)
|
|
173
|
+
self.logger.debug("✅ Anthropic API key validated successfully")
|
|
174
|
+
return True
|
|
175
|
+
if response.status_code == 429:
|
|
176
|
+
# Rate limited but key is valid
|
|
177
|
+
self.warnings.append("⚠️ Anthropic API key is valid but rate limited")
|
|
178
|
+
return True
|
|
179
|
+
if response.status_code == 200:
|
|
180
|
+
self.logger.debug("✅ Anthropic API key validated successfully")
|
|
181
|
+
return True
|
|
182
|
+
self.warnings.append(
|
|
183
|
+
f"⚠️ Anthropic API returned unexpected status: {response.status_code}"
|
|
184
|
+
)
|
|
185
|
+
return True
|
|
186
|
+
|
|
187
|
+
except requests.exceptions.Timeout:
|
|
188
|
+
self.warnings.append(
|
|
189
|
+
"⚠️ Anthropic API validation timed out - assuming key is valid"
|
|
190
|
+
)
|
|
191
|
+
return True
|
|
192
|
+
except requests.exceptions.ConnectionError as e:
|
|
193
|
+
self.warnings.append(f"⚠️ Could not connect to Anthropic API: {e}")
|
|
194
|
+
return True
|
|
195
|
+
except Exception as e:
|
|
196
|
+
self.errors.append(f"❌ Anthropic API validation failed with error: {e}")
|
|
197
|
+
return False
|
|
198
|
+
|
|
199
|
+
def _validate_github_token(self, token: str) -> bool:
|
|
200
|
+
"""Validate GitHub personal access token.
|
|
201
|
+
|
|
202
|
+
Args:
|
|
203
|
+
token: The GitHub token to validate
|
|
204
|
+
|
|
205
|
+
Returns:
|
|
206
|
+
True if valid, False otherwise
|
|
207
|
+
"""
|
|
208
|
+
try:
|
|
209
|
+
# Check token validity with minimal request
|
|
210
|
+
response = requests.get(
|
|
211
|
+
"https://api.github.com/user",
|
|
212
|
+
headers={
|
|
213
|
+
"Authorization": f"token {token}",
|
|
214
|
+
"Accept": "application/vnd.github.v3+json",
|
|
215
|
+
},
|
|
216
|
+
timeout=10,
|
|
217
|
+
)
|
|
218
|
+
|
|
219
|
+
if response.status_code == 401:
|
|
220
|
+
self.errors.append("❌ GitHub token is invalid (401 Unauthorized)")
|
|
221
|
+
return False
|
|
222
|
+
if response.status_code == 403:
|
|
223
|
+
self.errors.append(
|
|
224
|
+
"❌ GitHub token lacks required permissions (403 Forbidden)"
|
|
225
|
+
)
|
|
226
|
+
return False
|
|
227
|
+
if response.status_code == 200:
|
|
228
|
+
self.logger.debug("✅ GitHub token validated successfully")
|
|
229
|
+
return True
|
|
230
|
+
self.warnings.append(
|
|
231
|
+
f"⚠️ GitHub API returned unexpected status: {response.status_code}"
|
|
232
|
+
)
|
|
233
|
+
return True
|
|
234
|
+
|
|
235
|
+
except requests.exceptions.Timeout:
|
|
236
|
+
self.warnings.append(
|
|
237
|
+
"⚠️ GitHub API validation timed out - assuming token is valid"
|
|
238
|
+
)
|
|
239
|
+
return True
|
|
240
|
+
except requests.exceptions.ConnectionError as e:
|
|
241
|
+
self.warnings.append(f"⚠️ Could not connect to GitHub API: {e}")
|
|
242
|
+
return True
|
|
243
|
+
except Exception as e:
|
|
244
|
+
self.errors.append(f"❌ GitHub token validation failed with error: {e}")
|
|
245
|
+
return False
|
|
246
|
+
|
|
247
|
+
def _validate_custom_api(self, api_name: str, validation_config: Dict) -> bool:
|
|
248
|
+
"""Validate a custom API key based on configuration.
|
|
249
|
+
|
|
250
|
+
Args:
|
|
251
|
+
api_name: Name of the API
|
|
252
|
+
validation_config: Configuration for validating this API
|
|
253
|
+
|
|
254
|
+
Returns:
|
|
255
|
+
True if valid, False otherwise
|
|
256
|
+
"""
|
|
257
|
+
try:
|
|
258
|
+
env_var = validation_config.get("env_var")
|
|
259
|
+
if not env_var:
|
|
260
|
+
return True
|
|
261
|
+
|
|
262
|
+
api_key = os.getenv(env_var)
|
|
263
|
+
if not api_key:
|
|
264
|
+
return True # Not configured, skip validation
|
|
265
|
+
|
|
266
|
+
# Get validation endpoint and method
|
|
267
|
+
endpoint = validation_config.get("endpoint")
|
|
268
|
+
method = validation_config.get("method", "GET").upper()
|
|
269
|
+
headers = validation_config.get("headers", {})
|
|
270
|
+
|
|
271
|
+
# Replace {API_KEY} placeholder in headers
|
|
272
|
+
for key, value in headers.items():
|
|
273
|
+
if isinstance(value, str):
|
|
274
|
+
headers[key] = value.replace("{API_KEY}", api_key)
|
|
275
|
+
|
|
276
|
+
# Make validation request
|
|
277
|
+
if method == "GET":
|
|
278
|
+
response = requests.get(endpoint, headers=headers, timeout=10)
|
|
279
|
+
elif method == "POST":
|
|
280
|
+
body = validation_config.get("body", {})
|
|
281
|
+
response = requests.post(
|
|
282
|
+
endpoint, headers=headers, json=body, timeout=10
|
|
283
|
+
)
|
|
284
|
+
else:
|
|
285
|
+
self.warnings.append(
|
|
286
|
+
f"⚠️ Unsupported validation method for {api_name}: {method}"
|
|
287
|
+
)
|
|
288
|
+
return True
|
|
289
|
+
|
|
290
|
+
# Check expected status codes
|
|
291
|
+
valid_status_codes = validation_config.get("valid_status_codes", [200])
|
|
292
|
+
if response.status_code in valid_status_codes:
|
|
293
|
+
self.logger.debug(f"✅ {api_name} API key validated successfully")
|
|
294
|
+
return True
|
|
295
|
+
if response.status_code == 401:
|
|
296
|
+
self.errors.append(
|
|
297
|
+
f"❌ {api_name} API key is invalid (401 Unauthorized)"
|
|
298
|
+
)
|
|
299
|
+
return False
|
|
300
|
+
if response.status_code == 403:
|
|
301
|
+
self.errors.append(
|
|
302
|
+
f"❌ {api_name} API key lacks permissions (403 Forbidden)"
|
|
303
|
+
)
|
|
304
|
+
return False
|
|
305
|
+
self.warnings.append(
|
|
306
|
+
f"⚠️ {api_name} API returned status: {response.status_code}"
|
|
307
|
+
)
|
|
308
|
+
return True
|
|
309
|
+
|
|
310
|
+
except Exception as e:
|
|
311
|
+
self.warnings.append(f"⚠️ {api_name} API validation failed: {e}")
|
|
312
|
+
return True
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
def validate_api_keys(config: Optional[Dict] = None, strict: bool = True) -> bool:
|
|
316
|
+
"""Convenience function to validate all API keys.
|
|
317
|
+
|
|
318
|
+
Args:
|
|
319
|
+
config: Optional configuration dictionary
|
|
320
|
+
strict: If True, raise exception on validation failure
|
|
321
|
+
|
|
322
|
+
Returns:
|
|
323
|
+
True if all validations passed, False otherwise
|
|
324
|
+
|
|
325
|
+
Raises:
|
|
326
|
+
ValueError: If strict=True and any validation fails
|
|
327
|
+
"""
|
|
328
|
+
validator = APIKeyValidator(config)
|
|
329
|
+
success, _errors, _warnings = validator.validate_all_keys(strict=strict)
|
|
330
|
+
return success
|