claude-mpm 5.4.22__py3-none-any.whl → 5.6.34__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 claude-mpm might be problematic. Click here for more details.
- claude_mpm/VERSION +1 -1
- claude_mpm/agents/BASE_AGENT.md +164 -0
- claude_mpm/agents/BASE_ENGINEER.md +658 -0
- claude_mpm/agents/CLAUDE_MPM_OUTPUT_STYLE.md +66 -241
- claude_mpm/agents/CLAUDE_MPM_RESEARCH_OUTPUT_STYLE.md +413 -0
- claude_mpm/agents/CLAUDE_MPM_TEACHER_OUTPUT_STYLE.md +109 -1925
- claude_mpm/agents/MEMORY.md +1 -1
- claude_mpm/agents/PM_INSTRUCTIONS.md +374 -1257
- claude_mpm/agents/WORKFLOW.md +6 -253
- claude_mpm/agents/agent_loader.py +1 -1
- claude_mpm/agents/base_agent.json +31 -0
- claude_mpm/agents/frontmatter_validator.py +2 -2
- claude_mpm/agents/templates/circuit-breakers.md +26 -17
- claude_mpm/cli/__init__.py +5 -1
- claude_mpm/cli/commands/agent_state_manager.py +10 -10
- claude_mpm/cli/commands/agents.py +11 -13
- claude_mpm/cli/commands/agents_reconcile.py +197 -0
- claude_mpm/cli/commands/auto_configure.py +4 -4
- claude_mpm/cli/commands/autotodos.py +566 -0
- claude_mpm/cli/commands/commander.py +216 -0
- claude_mpm/cli/commands/configure.py +621 -22
- claude_mpm/cli/commands/configure_agent_display.py +12 -0
- claude_mpm/cli/commands/hook_errors.py +60 -60
- claude_mpm/cli/commands/monitor.py +2 -2
- claude_mpm/cli/commands/mpm_init/core.py +72 -0
- claude_mpm/cli/commands/postmortem.py +1 -1
- claude_mpm/cli/commands/profile.py +276 -0
- claude_mpm/cli/commands/run.py +35 -3
- claude_mpm/cli/commands/skill_source.py +51 -2
- claude_mpm/cli/commands/skills.py +182 -32
- claude_mpm/cli/executor.py +130 -16
- claude_mpm/cli/interactive/__init__.py +10 -0
- claude_mpm/cli/interactive/agent_wizard.py +32 -52
- claude_mpm/cli/interactive/questionary_styles.py +65 -0
- claude_mpm/cli/interactive/skill_selector.py +481 -0
- claude_mpm/cli/parsers/base_parser.py +83 -1
- claude_mpm/cli/parsers/commander_parser.py +116 -0
- claude_mpm/cli/parsers/profile_parser.py +147 -0
- claude_mpm/cli/parsers/run_parser.py +10 -0
- claude_mpm/cli/parsers/skill_source_parser.py +4 -0
- claude_mpm/cli/parsers/skills_parser.py +2 -3
- claude_mpm/cli/startup.py +690 -386
- claude_mpm/cli/startup_display.py +74 -6
- claude_mpm/cli/startup_logging.py +2 -2
- claude_mpm/cli/utils.py +7 -3
- claude_mpm/commander/__init__.py +78 -0
- claude_mpm/commander/adapters/__init__.py +60 -0
- claude_mpm/commander/adapters/auggie.py +260 -0
- claude_mpm/commander/adapters/base.py +288 -0
- claude_mpm/commander/adapters/claude_code.py +392 -0
- claude_mpm/commander/adapters/codex.py +237 -0
- claude_mpm/commander/adapters/communication.py +366 -0
- claude_mpm/commander/adapters/example_usage.py +310 -0
- claude_mpm/commander/adapters/mpm.py +389 -0
- claude_mpm/commander/adapters/registry.py +204 -0
- claude_mpm/commander/api/__init__.py +16 -0
- claude_mpm/commander/api/app.py +121 -0
- claude_mpm/commander/api/errors.py +133 -0
- claude_mpm/commander/api/routes/__init__.py +8 -0
- claude_mpm/commander/api/routes/events.py +184 -0
- claude_mpm/commander/api/routes/inbox.py +171 -0
- claude_mpm/commander/api/routes/messages.py +148 -0
- claude_mpm/commander/api/routes/projects.py +271 -0
- claude_mpm/commander/api/routes/sessions.py +226 -0
- claude_mpm/commander/api/routes/work.py +296 -0
- claude_mpm/commander/api/schemas.py +186 -0
- claude_mpm/commander/chat/__init__.py +7 -0
- claude_mpm/commander/chat/cli.py +146 -0
- claude_mpm/commander/chat/commands.py +96 -0
- claude_mpm/commander/chat/repl.py +310 -0
- claude_mpm/commander/config.py +51 -0
- claude_mpm/commander/config_loader.py +115 -0
- claude_mpm/commander/core/__init__.py +10 -0
- claude_mpm/commander/core/block_manager.py +325 -0
- claude_mpm/commander/core/response_manager.py +323 -0
- claude_mpm/commander/daemon.py +603 -0
- claude_mpm/commander/env_loader.py +59 -0
- claude_mpm/commander/events/__init__.py +26 -0
- claude_mpm/commander/events/manager.py +332 -0
- claude_mpm/commander/frameworks/__init__.py +12 -0
- claude_mpm/commander/frameworks/base.py +146 -0
- claude_mpm/commander/frameworks/claude_code.py +58 -0
- claude_mpm/commander/frameworks/mpm.py +62 -0
- claude_mpm/commander/inbox/__init__.py +16 -0
- claude_mpm/commander/inbox/dedup.py +128 -0
- claude_mpm/commander/inbox/inbox.py +224 -0
- claude_mpm/commander/inbox/models.py +70 -0
- claude_mpm/commander/instance_manager.py +450 -0
- claude_mpm/commander/llm/__init__.py +6 -0
- claude_mpm/commander/llm/openrouter_client.py +167 -0
- claude_mpm/commander/llm/summarizer.py +70 -0
- claude_mpm/commander/memory/__init__.py +45 -0
- claude_mpm/commander/memory/compression.py +347 -0
- claude_mpm/commander/memory/embeddings.py +230 -0
- claude_mpm/commander/memory/entities.py +310 -0
- claude_mpm/commander/memory/example_usage.py +290 -0
- claude_mpm/commander/memory/integration.py +325 -0
- claude_mpm/commander/memory/search.py +381 -0
- claude_mpm/commander/memory/store.py +657 -0
- claude_mpm/commander/models/__init__.py +18 -0
- claude_mpm/commander/models/events.py +121 -0
- claude_mpm/commander/models/project.py +162 -0
- claude_mpm/commander/models/work.py +214 -0
- claude_mpm/commander/parsing/__init__.py +20 -0
- claude_mpm/commander/parsing/extractor.py +132 -0
- claude_mpm/commander/parsing/output_parser.py +270 -0
- claude_mpm/commander/parsing/patterns.py +100 -0
- claude_mpm/commander/persistence/__init__.py +11 -0
- claude_mpm/commander/persistence/event_store.py +274 -0
- claude_mpm/commander/persistence/state_store.py +309 -0
- claude_mpm/commander/persistence/work_store.py +164 -0
- claude_mpm/commander/polling/__init__.py +13 -0
- claude_mpm/commander/polling/event_detector.py +104 -0
- claude_mpm/commander/polling/output_buffer.py +49 -0
- claude_mpm/commander/polling/output_poller.py +153 -0
- claude_mpm/commander/project_session.py +268 -0
- claude_mpm/commander/proxy/__init__.py +12 -0
- claude_mpm/commander/proxy/formatter.py +89 -0
- claude_mpm/commander/proxy/output_handler.py +191 -0
- claude_mpm/commander/proxy/relay.py +155 -0
- claude_mpm/commander/registry.py +410 -0
- claude_mpm/commander/runtime/__init__.py +10 -0
- claude_mpm/commander/runtime/executor.py +191 -0
- claude_mpm/commander/runtime/monitor.py +346 -0
- claude_mpm/commander/session/__init__.py +6 -0
- claude_mpm/commander/session/context.py +81 -0
- claude_mpm/commander/session/manager.py +59 -0
- claude_mpm/commander/tmux_orchestrator.py +361 -0
- claude_mpm/commander/web/__init__.py +1 -0
- claude_mpm/commander/work/__init__.py +30 -0
- claude_mpm/commander/work/executor.py +207 -0
- claude_mpm/commander/work/queue.py +405 -0
- claude_mpm/commander/workflow/__init__.py +27 -0
- claude_mpm/commander/workflow/event_handler.py +241 -0
- claude_mpm/commander/workflow/notifier.py +146 -0
- claude_mpm/commands/mpm-config.md +20 -249
- claude_mpm/commands/mpm-doctor.md +16 -21
- claude_mpm/commands/mpm-help.md +12 -205
- claude_mpm/commands/mpm-init.md +88 -506
- claude_mpm/commands/mpm-monitor.md +22 -401
- claude_mpm/commands/mpm-organize.md +70 -442
- claude_mpm/commands/mpm-postmortem.md +13 -107
- claude_mpm/commands/mpm-session-resume.md +20 -363
- claude_mpm/commands/mpm-status.md +13 -69
- claude_mpm/commands/mpm-ticket-view.md +60 -495
- claude_mpm/commands/mpm-version.md +13 -107
- claude_mpm/commands/mpm.md +8 -0
- claude_mpm/config/agent_presets.py +8 -7
- claude_mpm/config/skill_sources.py +16 -0
- claude_mpm/constants.py +1 -0
- claude_mpm/core/claude_runner.py +154 -2
- claude_mpm/core/config.py +37 -26
- claude_mpm/core/config_constants.py +74 -9
- claude_mpm/core/constants.py +56 -12
- claude_mpm/core/framework/loaders/agent_loader.py +1 -1
- claude_mpm/core/framework/loaders/instruction_loader.py +52 -11
- claude_mpm/core/hook_manager.py +51 -3
- claude_mpm/core/interactive_session.py +12 -11
- claude_mpm/core/logger.py +26 -9
- claude_mpm/core/logging_utils.py +39 -13
- claude_mpm/core/network_config.py +148 -0
- claude_mpm/core/oneshot_session.py +7 -6
- claude_mpm/core/optimized_startup.py +61 -0
- claude_mpm/core/output_style_manager.py +66 -18
- claude_mpm/core/shared/config_loader.py +3 -1
- claude_mpm/core/socketio_pool.py +47 -15
- claude_mpm/core/unified_agent_registry.py +1 -1
- claude_mpm/core/unified_config.py +54 -8
- claude_mpm/core/unified_paths.py +95 -90
- claude_mpm/dashboard/static/svelte-build/_app/env.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.C33zOoyM.css +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.CW1J-YuA.css +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/1WZnGYqX.js +24 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/67pF3qNn.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/6RxdMKe4.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/8cZrfX0h.js +60 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/9a6T2nm-.js +7 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/B443AUzu.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/B8AwtY2H.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BF15LAsF.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/BRcwIQNr.js +4 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BSNlmTZj.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BV6nKitt.js +43 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BViJ8lZt.js +128 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BcQ-Q0FE.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Bpyvgze_.js +30 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BzTRqg-z.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C0Fr8dve.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C3rbW_a-.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C8WYN38h.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C9I8FlXH.js +61 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CIQcWgO2.js +36 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CIctN7YN.js +7 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CKrS_JZW.js +145 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CR6P9C4A.js +89 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CRRR9MD_.js +2 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CRcR2DqT.js +334 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CSXtMOf0.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CT-sbxSk.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CWm6DJsp.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CmKTTxBW.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CpqQ1Kzn.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Cu_Erd72.js +261 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D2nGpDRe.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D9iCMida.js +267 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D9ykgMoY.js +10 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DL2Ldur1.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DPfltzjH.js +165 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DR8nis88.js +2 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DUliQN2b.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DVp1hx9R.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DXlhR01x.js +122 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D_lyTybS.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DngoTTgh.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DqkmHtDC.js +220 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DsDh8EYs.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DypDmXgd.js +139 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Gi6I4Gst.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/IPYC-LnN.js +162 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/JTLiF7dt.js +24 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/JpevfAFt.js +68 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/NqQ1dWOy.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/R8CEIRAd.js +2 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Zxy7qc-l.js +64 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/q9Hm6zAU.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/qtd3IeO4.js +15 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/ulBFON_C.js +65 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/wQVh1CoA.js +10 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/app.Dr7t0z2J.js +2 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.BGhZHUS3.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/0.RgBboRvH.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/1.DG-KkbDf.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.D_jnf-x6.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/cli_enhancements.py +2 -1
- claude_mpm/hooks/claude_hooks/INTEGRATION_EXAMPLE.md +243 -0
- claude_mpm/hooks/claude_hooks/README_AUTO_PAUSE.md +403 -0
- claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/auto_pause_handler.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__/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/auto_pause_handler.py +485 -0
- claude_mpm/hooks/claude_hooks/event_handlers.py +527 -136
- claude_mpm/hooks/claude_hooks/hook_handler.py +313 -99
- claude_mpm/hooks/claude_hooks/hook_wrapper.sh +6 -11
- claude_mpm/hooks/claude_hooks/installer.py +206 -36
- claude_mpm/hooks/claude_hooks/memory_integration.py +52 -32
- claude_mpm/hooks/claude_hooks/response_tracking.py +43 -60
- claude_mpm/hooks/claude_hooks/services/__init__.py +21 -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__/container.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__/protocols.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 +67 -32
- claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +38 -105
- claude_mpm/hooks/claude_hooks/services/container.py +310 -0
- claude_mpm/hooks/claude_hooks/services/protocols.py +328 -0
- claude_mpm/hooks/claude_hooks/services/state_manager.py +25 -38
- claude_mpm/hooks/claude_hooks/services/subagent_processor.py +75 -77
- claude_mpm/hooks/kuzu_memory_hook.py +5 -5
- claude_mpm/hooks/session_resume_hook.py +89 -1
- claude_mpm/hooks/templates/pre_tool_use_simple.py +6 -6
- claude_mpm/hooks/templates/pre_tool_use_template.py +16 -8
- claude_mpm/init.py +276 -0
- claude_mpm/models/git_repository.py +3 -3
- claude_mpm/scripts/claude-hook-handler.sh +46 -19
- claude_mpm/services/agents/agent_builder.py +3 -3
- claude_mpm/services/agents/agent_recommendation_service.py +8 -8
- claude_mpm/services/agents/agent_selection_service.py +2 -2
- claude_mpm/services/agents/cache_git_manager.py +7 -7
- claude_mpm/services/agents/deployment/agent_deployment.py +29 -7
- claude_mpm/services/agents/deployment/agent_discovery_service.py +4 -2
- claude_mpm/services/agents/deployment/agent_format_converter.py +25 -13
- claude_mpm/services/agents/deployment/agent_template_builder.py +39 -19
- claude_mpm/services/agents/deployment/agents_directory_resolver.py +2 -2
- claude_mpm/services/agents/deployment/async_agent_deployment.py +31 -27
- claude_mpm/services/agents/deployment/deployment_reconciler.py +577 -0
- claude_mpm/services/agents/deployment/local_template_deployment.py +3 -1
- claude_mpm/services/agents/deployment/multi_source_deployment_service.py +169 -26
- claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +101 -75
- claude_mpm/services/agents/deployment/startup_reconciliation.py +138 -0
- claude_mpm/services/agents/git_source_manager.py +23 -4
- claude_mpm/services/agents/loading/framework_agent_loader.py +75 -2
- claude_mpm/services/agents/recommender.py +5 -3
- claude_mpm/services/agents/single_tier_deployment_service.py +6 -6
- claude_mpm/services/agents/sources/git_source_sync_service.py +121 -10
- claude_mpm/services/agents/startup_sync.py +27 -4
- claude_mpm/services/cli/__init__.py +3 -0
- claude_mpm/services/cli/incremental_pause_manager.py +561 -0
- claude_mpm/services/cli/session_resume_helper.py +10 -2
- claude_mpm/services/command_deployment_service.py +44 -26
- claude_mpm/services/delegation_detector.py +175 -0
- claude_mpm/services/diagnostics/checks/agent_check.py +2 -2
- claude_mpm/services/diagnostics/checks/agent_sources_check.py +31 -1
- claude_mpm/services/diagnostics/checks/configuration_check.py +24 -0
- claude_mpm/services/diagnostics/checks/installation_check.py +22 -0
- claude_mpm/services/diagnostics/checks/mcp_services_check.py +23 -0
- claude_mpm/services/diagnostics/doctor_reporter.py +31 -1
- claude_mpm/services/diagnostics/models.py +14 -1
- claude_mpm/services/event_log.py +325 -0
- claude_mpm/services/git/git_operations_service.py +8 -8
- claude_mpm/services/hook_installer_service.py +77 -8
- claude_mpm/services/infrastructure/__init__.py +4 -0
- claude_mpm/services/infrastructure/context_usage_tracker.py +291 -0
- claude_mpm/services/infrastructure/resume_log_generator.py +24 -5
- claude_mpm/services/monitor/daemon_manager.py +15 -4
- claude_mpm/services/monitor/management/lifecycle.py +15 -3
- claude_mpm/services/monitor/server.py +571 -11
- claude_mpm/services/pm_skills_deployer.py +884 -0
- claude_mpm/services/profile_manager.py +337 -0
- claude_mpm/services/skills/git_skill_source_manager.py +281 -20
- claude_mpm/services/skills/selective_skill_deployer.py +211 -46
- claude_mpm/services/skills/skill_discovery_service.py +74 -4
- claude_mpm/services/skills_deployer.py +192 -70
- claude_mpm/services/socketio/dashboard_server.py +1 -0
- claude_mpm/services/socketio/event_normalizer.py +37 -6
- claude_mpm/services/socketio/handlers/hook.py +14 -7
- claude_mpm/services/socketio/server/core.py +262 -123
- claude_mpm/services/socketio/server/main.py +12 -4
- claude_mpm/skills/__init__.py +2 -1
- claude_mpm/skills/bundled/collaboration/brainstorming/SKILL.md +79 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/SKILL.md +178 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/agent-prompts.md +577 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/coordination-patterns.md +467 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/examples.md +537 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/troubleshooting.md +730 -0
- claude_mpm/skills/bundled/collaboration/git-worktrees.md +317 -0
- claude_mpm/skills/bundled/collaboration/requesting-code-review/SKILL.md +112 -0
- claude_mpm/skills/bundled/collaboration/requesting-code-review/references/code-reviewer-template.md +146 -0
- claude_mpm/skills/bundled/collaboration/requesting-code-review/references/review-examples.md +412 -0
- claude_mpm/skills/bundled/collaboration/stacked-prs.md +251 -0
- claude_mpm/skills/bundled/collaboration/writing-plans/SKILL.md +81 -0
- claude_mpm/skills/bundled/collaboration/writing-plans/references/best-practices.md +362 -0
- claude_mpm/skills/bundled/collaboration/writing-plans/references/plan-structure-templates.md +312 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/SKILL.md +152 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/advanced-techniques.md +668 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/examples.md +587 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/integration.md +438 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/tracing-techniques.md +391 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/CREATION-LOG.md +119 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/SKILL.md +148 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/anti-patterns.md +483 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/examples.md +452 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/troubleshooting.md +449 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/workflow.md +411 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-academic.md +14 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-1.md +58 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-2.md +68 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-3.md +69 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/SKILL.md +131 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/gate-function.md +325 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/integration-and-workflows.md +490 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/red-flags-and-failures.md +425 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/verification-patterns.md +499 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/INTEGRATION.md +611 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/README.md +596 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/SKILL.md +260 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/examples/nextjs-env-structure.md +315 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/references/frameworks.md +436 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/references/security.md +433 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/references/synchronization.md +452 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/references/troubleshooting.md +404 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/references/validation.md +420 -0
- claude_mpm/skills/bundled/main/artifacts-builder/SKILL.md +86 -0
- claude_mpm/skills/bundled/main/internal-comms/SKILL.md +43 -0
- claude_mpm/skills/bundled/main/internal-comms/examples/3p-updates.md +47 -0
- claude_mpm/skills/bundled/main/internal-comms/examples/company-newsletter.md +65 -0
- claude_mpm/skills/bundled/main/internal-comms/examples/faq-answers.md +30 -0
- claude_mpm/skills/bundled/main/internal-comms/examples/general-comms.md +16 -0
- claude_mpm/skills/bundled/main/mcp-builder/SKILL.md +160 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/design_principles.md +412 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/evaluation.md +602 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/mcp_best_practices.md +915 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/node_mcp_server.md +916 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/python_mcp_server.md +752 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/workflow.md +1237 -0
- claude_mpm/skills/bundled/main/skill-creator/SKILL.md +189 -0
- claude_mpm/skills/bundled/main/skill-creator/references/best-practices.md +500 -0
- claude_mpm/skills/bundled/main/skill-creator/references/creation-workflow.md +464 -0
- claude_mpm/skills/bundled/main/skill-creator/references/examples.md +619 -0
- claude_mpm/skills/bundled/main/skill-creator/references/progressive-disclosure.md +437 -0
- claude_mpm/skills/bundled/main/skill-creator/references/skill-structure.md +231 -0
- claude_mpm/skills/bundled/php/espocrm-development/SKILL.md +170 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/architecture.md +602 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/common-tasks.md +821 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/development-workflow.md +742 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/frontend-customization.md +726 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/hooks-and-services.md +764 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/testing-debugging.md +831 -0
- claude_mpm/skills/bundled/pm/mpm/SKILL.md +38 -0
- claude_mpm/skills/bundled/pm/mpm-agent-update-workflow/SKILL.md +75 -0
- claude_mpm/skills/bundled/pm/mpm-bug-reporting/SKILL.md +248 -0
- claude_mpm/skills/bundled/pm/mpm-circuit-breaker-enforcement/SKILL.md +476 -0
- claude_mpm/skills/bundled/pm/mpm-config/SKILL.md +29 -0
- claude_mpm/skills/bundled/pm/mpm-delegation-patterns/SKILL.md +167 -0
- claude_mpm/skills/bundled/pm/mpm-doctor/SKILL.md +53 -0
- claude_mpm/skills/bundled/pm/mpm-git-file-tracking/SKILL.md +113 -0
- claude_mpm/skills/bundled/pm/mpm-help/SKILL.md +35 -0
- claude_mpm/skills/bundled/pm/mpm-init/SKILL.md +125 -0
- claude_mpm/skills/bundled/pm/mpm-monitor/SKILL.md +32 -0
- claude_mpm/skills/bundled/pm/mpm-organize/SKILL.md +121 -0
- claude_mpm/skills/bundled/pm/mpm-postmortem/SKILL.md +22 -0
- claude_mpm/skills/bundled/pm/mpm-pr-workflow/SKILL.md +124 -0
- claude_mpm/skills/bundled/pm/mpm-session-management/SKILL.md +312 -0
- claude_mpm/skills/bundled/pm/mpm-session-pause/SKILL.md +170 -0
- claude_mpm/skills/bundled/pm/mpm-session-resume/SKILL.md +31 -0
- claude_mpm/skills/bundled/pm/mpm-status/SKILL.md +37 -0
- claude_mpm/skills/bundled/pm/mpm-teaching-mode/SKILL.md +657 -0
- claude_mpm/skills/bundled/pm/mpm-ticket-view/SKILL.md +110 -0
- claude_mpm/skills/bundled/pm/mpm-ticketing-integration/SKILL.md +154 -0
- claude_mpm/skills/bundled/pm/mpm-tool-usage-guide/SKILL.md +386 -0
- claude_mpm/skills/bundled/pm/mpm-verification-protocols/SKILL.md +198 -0
- claude_mpm/skills/bundled/pm/mpm-version/SKILL.md +21 -0
- claude_mpm/skills/bundled/react/flexlayout-react.md +742 -0
- claude_mpm/skills/bundled/rust/desktop-applications/SKILL.md +226 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/architecture-patterns.md +901 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/native-gui-frameworks.md +901 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/platform-integration.md +775 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/state-management.md +937 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/tauri-framework.md +770 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/testing-deployment.md +961 -0
- claude_mpm/skills/bundled/security-scanning.md +112 -0
- claude_mpm/skills/bundled/tauri/tauri-async-patterns.md +495 -0
- claude_mpm/skills/bundled/tauri/tauri-build-deploy.md +599 -0
- claude_mpm/skills/bundled/tauri/tauri-command-patterns.md +535 -0
- claude_mpm/skills/bundled/tauri/tauri-error-handling.md +613 -0
- claude_mpm/skills/bundled/tauri/tauri-event-system.md +648 -0
- claude_mpm/skills/bundled/tauri/tauri-file-system.md +673 -0
- claude_mpm/skills/bundled/tauri/tauri-frontend-integration.md +767 -0
- claude_mpm/skills/bundled/tauri/tauri-performance.md +669 -0
- claude_mpm/skills/bundled/tauri/tauri-state-management.md +573 -0
- claude_mpm/skills/bundled/tauri/tauri-testing.md +384 -0
- claude_mpm/skills/bundled/tauri/tauri-window-management.md +628 -0
- claude_mpm/skills/bundled/testing/condition-based-waiting/SKILL.md +119 -0
- claude_mpm/skills/bundled/testing/condition-based-waiting/references/patterns-and-implementation.md +253 -0
- claude_mpm/skills/bundled/testing/test-driven-development/SKILL.md +145 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/anti-patterns.md +543 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/examples.md +741 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/integration.md +470 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/philosophy.md +458 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/workflow.md +639 -0
- claude_mpm/skills/bundled/testing/test-quality-inspector/SKILL.md +458 -0
- claude_mpm/skills/bundled/testing/test-quality-inspector/examples/example-inspection-report.md +411 -0
- claude_mpm/skills/bundled/testing/test-quality-inspector/references/assertion-quality.md +317 -0
- claude_mpm/skills/bundled/testing/test-quality-inspector/references/inspection-checklist.md +270 -0
- claude_mpm/skills/bundled/testing/test-quality-inspector/references/red-flags.md +436 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/SKILL.md +140 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/completeness-anti-patterns.md +572 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/core-anti-patterns.md +411 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/detection-guide.md +569 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/tdd-connection.md +695 -0
- claude_mpm/skills/bundled/testing/webapp-testing/SKILL.md +184 -0
- claude_mpm/skills/bundled/testing/webapp-testing/decision-tree.md +459 -0
- claude_mpm/skills/bundled/testing/webapp-testing/playwright-patterns.md +479 -0
- claude_mpm/skills/bundled/testing/webapp-testing/reconnaissance-pattern.md +687 -0
- claude_mpm/skills/bundled/testing/webapp-testing/server-management.md +758 -0
- claude_mpm/skills/bundled/testing/webapp-testing/troubleshooting.md +868 -0
- claude_mpm/skills/registry.py +295 -90
- claude_mpm/skills/skill_manager.py +98 -3
- claude_mpm/templates/.pre-commit-config.yaml +112 -0
- claude_mpm/utils/agent_dependency_loader.py +115 -4
- claude_mpm/utils/agent_filters.py +1 -1
- claude_mpm/utils/migration.py +4 -4
- claude_mpm/utils/robust_installer.py +86 -21
- claude_mpm-5.6.34.dist-info/METADATA +393 -0
- {claude_mpm-5.4.22.dist-info → claude_mpm-5.6.34.dist-info}/RECORD +486 -145
- claude_mpm-5.4.22.dist-info/METADATA +0 -996
- {claude_mpm-5.4.22.dist-info → claude_mpm-5.6.34.dist-info}/WHEEL +0 -0
- {claude_mpm-5.4.22.dist-info → claude_mpm-5.6.34.dist-info}/entry_points.txt +0 -0
- {claude_mpm-5.4.22.dist-info → claude_mpm-5.6.34.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-5.4.22.dist-info → claude_mpm-5.6.34.dist-info}/licenses/LICENSE-FAQ.md +0 -0
- {claude_mpm-5.4.22.dist-info → claude_mpm-5.6.34.dist-info}/top_level.txt +0 -0
|
@@ -7,16 +7,29 @@ This service manages:
|
|
|
7
7
|
DESIGN DECISION: Use stateless HTTP POST instead of persistent SocketIO
|
|
8
8
|
connections because hook handlers are ephemeral processes (< 1 second lifetime).
|
|
9
9
|
This eliminates disconnection issues and matches the process lifecycle.
|
|
10
|
+
|
|
11
|
+
DESIGN DECISION: Synchronous HTTP POST only (no async)
|
|
12
|
+
Hook handlers are too short-lived (~25ms lifecycle) to benefit from async.
|
|
13
|
+
Using asyncio.run() creates event loops that close before HTTP operations complete,
|
|
14
|
+
causing "Event loop is closed" errors. Synchronous HTTP POST in a thread pool
|
|
15
|
+
is simpler and more reliable for ephemeral processes.
|
|
10
16
|
"""
|
|
11
17
|
|
|
12
|
-
import asyncio
|
|
13
18
|
import os
|
|
14
|
-
import sys
|
|
15
19
|
from concurrent.futures import ThreadPoolExecutor
|
|
16
20
|
from datetime import datetime, timezone
|
|
17
21
|
|
|
18
|
-
#
|
|
19
|
-
|
|
22
|
+
# Try to import _log from hook_handler, fall back to no-op
|
|
23
|
+
try:
|
|
24
|
+
from claude_mpm.hooks.claude_hooks.hook_handler import _log
|
|
25
|
+
except ImportError:
|
|
26
|
+
|
|
27
|
+
def _log(msg: str) -> None:
|
|
28
|
+
pass # Silent fallback
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
# Debug mode - disabled by default to prevent logging overhead in production
|
|
32
|
+
DEBUG = os.environ.get("CLAUDE_MPM_HOOK_DEBUG", "false").lower() == "true"
|
|
20
33
|
|
|
21
34
|
# Import requests for HTTP POST communication
|
|
22
35
|
try:
|
|
@@ -27,9 +40,6 @@ except ImportError:
|
|
|
27
40
|
REQUESTS_AVAILABLE = False
|
|
28
41
|
requests = None
|
|
29
42
|
|
|
30
|
-
# Import high-performance event emitter - lazy loaded in _async_emit()
|
|
31
|
-
# to reduce hook handler initialization time by ~85% (792ms -> minimal)
|
|
32
|
-
|
|
33
43
|
# Import EventNormalizer for consistent event formatting
|
|
34
44
|
try:
|
|
35
45
|
from claude_mpm.services.socketio.event_normalizer import EventNormalizer
|
|
@@ -55,10 +65,6 @@ except ImportError:
|
|
|
55
65
|
)
|
|
56
66
|
|
|
57
67
|
|
|
58
|
-
# EventBus removed - using direct HTTP POST only
|
|
59
|
-
# This eliminates duplicate events and simplifies the architecture
|
|
60
|
-
|
|
61
|
-
|
|
62
68
|
class ConnectionManagerService:
|
|
63
69
|
"""Manages connections for the Claude hook handler using HTTP POST."""
|
|
64
70
|
|
|
@@ -72,35 +78,26 @@ class ConnectionManagerService:
|
|
|
72
78
|
self.server_port = int(os.environ.get("CLAUDE_MPM_SERVER_PORT", "8765"))
|
|
73
79
|
self.http_endpoint = f"http://{self.server_host}:{self.server_port}/api/events"
|
|
74
80
|
|
|
75
|
-
# EventBus removed - using direct HTTP POST only
|
|
76
|
-
|
|
77
|
-
# For backward compatibility with tests
|
|
78
|
-
self.connection_pool = None # No longer used
|
|
79
|
-
|
|
80
|
-
# Track async emit tasks to prevent garbage collection
|
|
81
|
-
self._emit_tasks: set = set()
|
|
82
|
-
|
|
83
81
|
# Thread pool for non-blocking HTTP requests
|
|
84
82
|
# WHY: Prevents HTTP POST from blocking hook processing (2s timeout → 0ms blocking)
|
|
85
|
-
# max_workers=2: Sufficient for low-frequency
|
|
83
|
+
# max_workers=2: Sufficient for low-frequency hook events
|
|
86
84
|
self._http_executor = ThreadPoolExecutor(
|
|
87
85
|
max_workers=2, thread_name_prefix="http-emit"
|
|
88
86
|
)
|
|
89
87
|
|
|
90
88
|
if DEBUG:
|
|
91
|
-
|
|
92
|
-
f"✅ HTTP connection manager initialized - endpoint: {self.http_endpoint}"
|
|
93
|
-
file=sys.stderr,
|
|
89
|
+
_log(
|
|
90
|
+
f"✅ HTTP connection manager initialized - endpoint: {self.http_endpoint}"
|
|
94
91
|
)
|
|
95
92
|
|
|
96
93
|
def emit_event(self, namespace: str, event: str, data: dict):
|
|
97
|
-
"""Emit event using
|
|
94
|
+
"""Emit event using HTTP POST.
|
|
98
95
|
|
|
99
|
-
WHY
|
|
100
|
-
-
|
|
101
|
-
-
|
|
102
|
-
-
|
|
103
|
-
-
|
|
96
|
+
WHY HTTP POST only:
|
|
97
|
+
- Hook handlers are ephemeral (~25ms lifecycle)
|
|
98
|
+
- Async emission causes "Event loop is closed" errors
|
|
99
|
+
- HTTP POST in thread pool is simpler and more reliable
|
|
100
|
+
- Completes in 20-50ms, which is acceptable for hook handlers
|
|
104
101
|
"""
|
|
105
102
|
# Create event data for normalization
|
|
106
103
|
raw_event = {
|
|
@@ -120,74 +117,17 @@ class ConnectionManagerService:
|
|
|
120
117
|
if DEBUG and event in ["subagent_stop", "pre_tool"]:
|
|
121
118
|
if event == "subagent_stop":
|
|
122
119
|
agent_type = data.get("agent_type", "unknown")
|
|
123
|
-
|
|
124
|
-
f"Hook handler: Publishing SubagentStop for agent '{agent_type}'",
|
|
125
|
-
file=sys.stderr,
|
|
126
|
-
)
|
|
120
|
+
_log(f"Hook handler: Publishing SubagentStop for agent '{agent_type}'")
|
|
127
121
|
elif event == "pre_tool" and data.get("tool_name") == "Task":
|
|
128
122
|
delegation = data.get("delegation_details", {})
|
|
129
123
|
agent_type = delegation.get("agent_type", "unknown")
|
|
130
|
-
|
|
131
|
-
f"Hook handler: Publishing Task delegation to agent '{agent_type}'"
|
|
132
|
-
file=sys.stderr,
|
|
124
|
+
_log(
|
|
125
|
+
f"Hook handler: Publishing Task delegation to agent '{agent_type}'"
|
|
133
126
|
)
|
|
134
127
|
|
|
135
|
-
#
|
|
136
|
-
success = self._try_async_emit(namespace, event, claude_event_data)
|
|
137
|
-
if success:
|
|
138
|
-
return
|
|
139
|
-
|
|
140
|
-
# Fallback to HTTP POST for cross-process communication
|
|
128
|
+
# Emit via HTTP POST (non-blocking, runs in thread pool)
|
|
141
129
|
self._try_http_emit(namespace, event, claude_event_data)
|
|
142
130
|
|
|
143
|
-
def _try_async_emit(self, namespace: str, event: str, data: dict) -> bool:
|
|
144
|
-
"""Try to emit event using high-performance async emitter."""
|
|
145
|
-
try:
|
|
146
|
-
# Run async emission in the current event loop or create one
|
|
147
|
-
loop = None
|
|
148
|
-
try:
|
|
149
|
-
loop = asyncio.get_running_loop()
|
|
150
|
-
except RuntimeError:
|
|
151
|
-
# No running loop, create a new one
|
|
152
|
-
pass
|
|
153
|
-
|
|
154
|
-
if loop:
|
|
155
|
-
# We're in an async context, create a task with tracking
|
|
156
|
-
task = loop.create_task(self._async_emit(namespace, event, data))
|
|
157
|
-
self._emit_tasks.add(task)
|
|
158
|
-
task.add_done_callback(self._emit_tasks.discard)
|
|
159
|
-
# Don't wait for completion to maintain low latency
|
|
160
|
-
if DEBUG:
|
|
161
|
-
print(f"✅ Async emit scheduled: {event}", file=sys.stderr)
|
|
162
|
-
return True
|
|
163
|
-
# No event loop, run synchronously
|
|
164
|
-
success = asyncio.run(self._async_emit(namespace, event, data))
|
|
165
|
-
if DEBUG and success:
|
|
166
|
-
print(f"✅ Async emit successful: {event}", file=sys.stderr)
|
|
167
|
-
return success
|
|
168
|
-
|
|
169
|
-
except Exception as e:
|
|
170
|
-
if DEBUG:
|
|
171
|
-
print(f"⚠️ Async emit failed: {e}", file=sys.stderr)
|
|
172
|
-
return False
|
|
173
|
-
|
|
174
|
-
async def _async_emit(self, namespace: str, event: str, data: dict) -> bool:
|
|
175
|
-
"""Async helper for event emission."""
|
|
176
|
-
try:
|
|
177
|
-
# Lazy load event emitter to reduce initialization overhead
|
|
178
|
-
from claude_mpm.services.monitor.event_emitter import get_event_emitter
|
|
179
|
-
|
|
180
|
-
emitter = await get_event_emitter()
|
|
181
|
-
return await emitter.emit_event(namespace, "claude_event", data)
|
|
182
|
-
except ImportError:
|
|
183
|
-
if DEBUG:
|
|
184
|
-
print("⚠️ Event emitter not available", file=sys.stderr)
|
|
185
|
-
return False
|
|
186
|
-
except Exception as e:
|
|
187
|
-
if DEBUG:
|
|
188
|
-
print(f"⚠️ Async emitter error: {e}", file=sys.stderr)
|
|
189
|
-
return False
|
|
190
|
-
|
|
191
131
|
def _try_http_emit(self, namespace: str, event: str, data: dict):
|
|
192
132
|
"""Try to emit event using HTTP POST fallback (non-blocking).
|
|
193
133
|
|
|
@@ -196,10 +136,7 @@ class ConnectionManagerService:
|
|
|
196
136
|
"""
|
|
197
137
|
if not REQUESTS_AVAILABLE:
|
|
198
138
|
if DEBUG:
|
|
199
|
-
|
|
200
|
-
"⚠️ requests module not available - cannot emit via HTTP",
|
|
201
|
-
file=sys.stderr,
|
|
202
|
-
)
|
|
139
|
+
_log("⚠️ requests module not available - cannot emit via HTTP")
|
|
203
140
|
return
|
|
204
141
|
|
|
205
142
|
# Submit to thread pool - don't wait for result (fire-and-forget)
|
|
@@ -225,25 +162,21 @@ class ConnectionManagerService:
|
|
|
225
162
|
|
|
226
163
|
if response.status_code in [200, 204]:
|
|
227
164
|
if DEBUG:
|
|
228
|
-
|
|
165
|
+
_log(f"✅ HTTP POST successful: {event}")
|
|
229
166
|
elif DEBUG:
|
|
230
|
-
|
|
231
|
-
f"⚠️ HTTP POST failed with status {response.status_code}: {event}",
|
|
232
|
-
file=sys.stderr,
|
|
233
|
-
)
|
|
167
|
+
_log(f"⚠️ HTTP POST failed with status {response.status_code}: {event}")
|
|
234
168
|
|
|
235
169
|
except requests.exceptions.Timeout:
|
|
236
170
|
if DEBUG:
|
|
237
|
-
|
|
171
|
+
_log(f"⚠️ HTTP POST timeout for: {event}")
|
|
238
172
|
except requests.exceptions.ConnectionError:
|
|
239
173
|
if DEBUG:
|
|
240
|
-
|
|
241
|
-
f"⚠️ HTTP POST connection failed for: {event} (server not running?)"
|
|
242
|
-
file=sys.stderr,
|
|
174
|
+
_log(
|
|
175
|
+
f"⚠️ HTTP POST connection failed for: {event} (server not running?)"
|
|
243
176
|
)
|
|
244
177
|
except Exception as e:
|
|
245
178
|
if DEBUG:
|
|
246
|
-
|
|
179
|
+
_log(f"⚠️ HTTP POST error for {event}: {e}")
|
|
247
180
|
|
|
248
181
|
def cleanup(self):
|
|
249
182
|
"""Cleanup connections on service destruction."""
|
|
@@ -251,4 +184,4 @@ class ConnectionManagerService:
|
|
|
251
184
|
if hasattr(self, "_http_executor"):
|
|
252
185
|
self._http_executor.shutdown(wait=False)
|
|
253
186
|
if DEBUG:
|
|
254
|
-
|
|
187
|
+
_log("✅ HTTP executor shutdown")
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
"""Dependency Injection container for hook handler services.
|
|
2
|
+
|
|
3
|
+
This module provides a DI container that manages service instantiation,
|
|
4
|
+
lazy initialization, and service overriding for testing.
|
|
5
|
+
|
|
6
|
+
WHY DI Container:
|
|
7
|
+
- Centralized service management
|
|
8
|
+
- Lazy initialization reduces startup overhead
|
|
9
|
+
- Easy testing through service overriding
|
|
10
|
+
- Clear dependency graph
|
|
11
|
+
- Thread-safe singleton pattern
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
import threading
|
|
15
|
+
from typing import Any, Optional, TypeVar
|
|
16
|
+
|
|
17
|
+
# Import service protocols for type hints
|
|
18
|
+
from .protocols import (
|
|
19
|
+
IAutoPauseHandler,
|
|
20
|
+
IConnectionManager,
|
|
21
|
+
IDuplicateDetector,
|
|
22
|
+
IEventHandlers,
|
|
23
|
+
IMemoryHookManager,
|
|
24
|
+
IResponseTrackingManager,
|
|
25
|
+
IStateManager,
|
|
26
|
+
ISubagentProcessor,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
T = TypeVar("T")
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class HookServiceContainer:
|
|
33
|
+
"""Dependency injection container for hook handler services.
|
|
34
|
+
|
|
35
|
+
Features:
|
|
36
|
+
- Lazy initialization of services
|
|
37
|
+
- Thread-safe singleton pattern
|
|
38
|
+
- Service overriding for testing
|
|
39
|
+
- Automatic dependency resolution
|
|
40
|
+
|
|
41
|
+
Usage:
|
|
42
|
+
# Normal usage (services created lazily)
|
|
43
|
+
container = HookServiceContainer()
|
|
44
|
+
state_manager = container.get_state_manager()
|
|
45
|
+
|
|
46
|
+
# Testing usage (override services)
|
|
47
|
+
container = HookServiceContainer()
|
|
48
|
+
container.override_state_manager(mock_state_manager)
|
|
49
|
+
state_manager = container.get_state_manager() # Returns mock
|
|
50
|
+
|
|
51
|
+
# Reset overrides
|
|
52
|
+
container.reset_overrides()
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
# Thread-safe singleton
|
|
56
|
+
_instance: Optional["HookServiceContainer"] = None
|
|
57
|
+
_lock = threading.Lock()
|
|
58
|
+
|
|
59
|
+
def __new__(cls) -> "HookServiceContainer":
|
|
60
|
+
"""Thread-safe singleton pattern."""
|
|
61
|
+
if cls._instance is None:
|
|
62
|
+
with cls._lock:
|
|
63
|
+
# Double-check locking pattern
|
|
64
|
+
if cls._instance is None:
|
|
65
|
+
cls._instance = super().__new__(cls)
|
|
66
|
+
cls._instance._initialized = False
|
|
67
|
+
return cls._instance
|
|
68
|
+
|
|
69
|
+
def __init__(self) -> None:
|
|
70
|
+
"""Initialize container if not already initialized."""
|
|
71
|
+
if getattr(self, "_initialized", False):
|
|
72
|
+
return
|
|
73
|
+
|
|
74
|
+
# Service instances (lazily initialized)
|
|
75
|
+
self._state_manager: Optional[IStateManager] = None
|
|
76
|
+
self._connection_manager: Optional[IConnectionManager] = None
|
|
77
|
+
self._duplicate_detector: Optional[IDuplicateDetector] = None
|
|
78
|
+
self._response_tracking_manager: Optional[IResponseTrackingManager] = None
|
|
79
|
+
self._memory_hook_manager: Optional[IMemoryHookManager] = None
|
|
80
|
+
self._subagent_processor: Optional[ISubagentProcessor] = None
|
|
81
|
+
self._auto_pause_handler: Optional[IAutoPauseHandler] = None
|
|
82
|
+
self._event_handlers: Optional[IEventHandlers] = None
|
|
83
|
+
|
|
84
|
+
# Override factories for testing
|
|
85
|
+
self._overrides: dict[str, Any] = {}
|
|
86
|
+
|
|
87
|
+
# Lock for lazy initialization
|
|
88
|
+
self._init_lock = threading.Lock()
|
|
89
|
+
|
|
90
|
+
self._initialized = True
|
|
91
|
+
|
|
92
|
+
# =========================================================================
|
|
93
|
+
# Lazy Service Getters
|
|
94
|
+
# =========================================================================
|
|
95
|
+
|
|
96
|
+
def get_state_manager(self) -> IStateManager:
|
|
97
|
+
"""Get or create StateManagerService instance."""
|
|
98
|
+
if "state_manager" in self._overrides:
|
|
99
|
+
return self._overrides["state_manager"]
|
|
100
|
+
|
|
101
|
+
if self._state_manager is None:
|
|
102
|
+
with self._init_lock:
|
|
103
|
+
if self._state_manager is None:
|
|
104
|
+
from .state_manager import StateManagerService
|
|
105
|
+
|
|
106
|
+
self._state_manager = StateManagerService()
|
|
107
|
+
return self._state_manager
|
|
108
|
+
|
|
109
|
+
def get_connection_manager(self) -> IConnectionManager:
|
|
110
|
+
"""Get or create ConnectionManagerService instance."""
|
|
111
|
+
if "connection_manager" in self._overrides:
|
|
112
|
+
return self._overrides["connection_manager"]
|
|
113
|
+
|
|
114
|
+
if self._connection_manager is None:
|
|
115
|
+
with self._init_lock:
|
|
116
|
+
if self._connection_manager is None:
|
|
117
|
+
from .connection_manager_http import ConnectionManagerService
|
|
118
|
+
|
|
119
|
+
self._connection_manager = ConnectionManagerService()
|
|
120
|
+
return self._connection_manager
|
|
121
|
+
|
|
122
|
+
def get_duplicate_detector(self) -> IDuplicateDetector:
|
|
123
|
+
"""Get or create DuplicateEventDetector instance."""
|
|
124
|
+
if "duplicate_detector" in self._overrides:
|
|
125
|
+
return self._overrides["duplicate_detector"]
|
|
126
|
+
|
|
127
|
+
if self._duplicate_detector is None:
|
|
128
|
+
with self._init_lock:
|
|
129
|
+
if self._duplicate_detector is None:
|
|
130
|
+
from .duplicate_detector import DuplicateEventDetector
|
|
131
|
+
|
|
132
|
+
self._duplicate_detector = DuplicateEventDetector()
|
|
133
|
+
return self._duplicate_detector
|
|
134
|
+
|
|
135
|
+
def get_response_tracking_manager(self) -> IResponseTrackingManager:
|
|
136
|
+
"""Get or create ResponseTrackingManager instance."""
|
|
137
|
+
if "response_tracking_manager" in self._overrides:
|
|
138
|
+
return self._overrides["response_tracking_manager"]
|
|
139
|
+
|
|
140
|
+
if self._response_tracking_manager is None:
|
|
141
|
+
with self._init_lock:
|
|
142
|
+
if self._response_tracking_manager is None:
|
|
143
|
+
from ..response_tracking import ResponseTrackingManager
|
|
144
|
+
|
|
145
|
+
self._response_tracking_manager = ResponseTrackingManager()
|
|
146
|
+
return self._response_tracking_manager
|
|
147
|
+
|
|
148
|
+
def get_memory_hook_manager(self) -> IMemoryHookManager:
|
|
149
|
+
"""Get or create MemoryHookManager instance."""
|
|
150
|
+
if "memory_hook_manager" in self._overrides:
|
|
151
|
+
return self._overrides["memory_hook_manager"]
|
|
152
|
+
|
|
153
|
+
if self._memory_hook_manager is None:
|
|
154
|
+
with self._init_lock:
|
|
155
|
+
if self._memory_hook_manager is None:
|
|
156
|
+
from ..memory_integration import MemoryHookManager
|
|
157
|
+
|
|
158
|
+
self._memory_hook_manager = MemoryHookManager()
|
|
159
|
+
return self._memory_hook_manager
|
|
160
|
+
|
|
161
|
+
def get_auto_pause_handler(self) -> Optional[IAutoPauseHandler]:
|
|
162
|
+
"""Get or create AutoPauseHandler instance.
|
|
163
|
+
|
|
164
|
+
Returns None if initialization fails (auto-pause is optional).
|
|
165
|
+
"""
|
|
166
|
+
if "auto_pause_handler" in self._overrides:
|
|
167
|
+
return self._overrides["auto_pause_handler"]
|
|
168
|
+
|
|
169
|
+
if self._auto_pause_handler is None:
|
|
170
|
+
with self._init_lock:
|
|
171
|
+
if self._auto_pause_handler is None:
|
|
172
|
+
try:
|
|
173
|
+
from ..auto_pause_handler import AutoPauseHandler
|
|
174
|
+
|
|
175
|
+
self._auto_pause_handler = AutoPauseHandler()
|
|
176
|
+
except Exception:
|
|
177
|
+
# Auto-pause is optional
|
|
178
|
+
self._auto_pause_handler = None
|
|
179
|
+
return self._auto_pause_handler
|
|
180
|
+
|
|
181
|
+
def get_subagent_processor(
|
|
182
|
+
self,
|
|
183
|
+
state_manager: Optional[IStateManager] = None,
|
|
184
|
+
response_tracking_manager: Optional[IResponseTrackingManager] = None,
|
|
185
|
+
connection_manager: Optional[IConnectionManager] = None,
|
|
186
|
+
) -> ISubagentProcessor:
|
|
187
|
+
"""Get or create SubagentResponseProcessor instance.
|
|
188
|
+
|
|
189
|
+
Args:
|
|
190
|
+
state_manager: Optional override for state manager
|
|
191
|
+
response_tracking_manager: Optional override for response tracking
|
|
192
|
+
connection_manager: Optional override for connection manager
|
|
193
|
+
"""
|
|
194
|
+
if "subagent_processor" in self._overrides:
|
|
195
|
+
return self._overrides["subagent_processor"]
|
|
196
|
+
|
|
197
|
+
if self._subagent_processor is None:
|
|
198
|
+
with self._init_lock:
|
|
199
|
+
if self._subagent_processor is None:
|
|
200
|
+
from .subagent_processor import SubagentResponseProcessor
|
|
201
|
+
|
|
202
|
+
# Use provided dependencies or get from container
|
|
203
|
+
sm = state_manager or self.get_state_manager()
|
|
204
|
+
rtm = (
|
|
205
|
+
response_tracking_manager
|
|
206
|
+
or self.get_response_tracking_manager()
|
|
207
|
+
)
|
|
208
|
+
cm = connection_manager or self.get_connection_manager()
|
|
209
|
+
|
|
210
|
+
self._subagent_processor = SubagentResponseProcessor(sm, rtm, cm)
|
|
211
|
+
return self._subagent_processor
|
|
212
|
+
|
|
213
|
+
def get_event_handlers(self, hook_handler: Any = None) -> IEventHandlers:
|
|
214
|
+
"""Get or create EventHandlers instance.
|
|
215
|
+
|
|
216
|
+
Args:
|
|
217
|
+
hook_handler: The ClaudeHookHandler instance for backward compatibility.
|
|
218
|
+
In the future, this will be replaced with proper DI.
|
|
219
|
+
"""
|
|
220
|
+
if "event_handlers" in self._overrides:
|
|
221
|
+
return self._overrides["event_handlers"]
|
|
222
|
+
|
|
223
|
+
if self._event_handlers is None:
|
|
224
|
+
with self._init_lock:
|
|
225
|
+
if self._event_handlers is None:
|
|
226
|
+
from ..event_handlers import EventHandlers
|
|
227
|
+
|
|
228
|
+
if hook_handler is None:
|
|
229
|
+
raise ValueError(
|
|
230
|
+
"hook_handler is required to create EventHandlers"
|
|
231
|
+
)
|
|
232
|
+
self._event_handlers = EventHandlers(hook_handler)
|
|
233
|
+
return self._event_handlers
|
|
234
|
+
|
|
235
|
+
# =========================================================================
|
|
236
|
+
# Service Override Methods (for testing)
|
|
237
|
+
# =========================================================================
|
|
238
|
+
|
|
239
|
+
def override_state_manager(self, service: IStateManager) -> None:
|
|
240
|
+
"""Override state manager with a mock or custom implementation."""
|
|
241
|
+
self._overrides["state_manager"] = service
|
|
242
|
+
|
|
243
|
+
def override_connection_manager(self, service: IConnectionManager) -> None:
|
|
244
|
+
"""Override connection manager with a mock or custom implementation."""
|
|
245
|
+
self._overrides["connection_manager"] = service
|
|
246
|
+
|
|
247
|
+
def override_duplicate_detector(self, service: IDuplicateDetector) -> None:
|
|
248
|
+
"""Override duplicate detector with a mock or custom implementation."""
|
|
249
|
+
self._overrides["duplicate_detector"] = service
|
|
250
|
+
|
|
251
|
+
def override_response_tracking_manager(
|
|
252
|
+
self, service: IResponseTrackingManager
|
|
253
|
+
) -> None:
|
|
254
|
+
"""Override response tracking manager with a mock or custom implementation."""
|
|
255
|
+
self._overrides["response_tracking_manager"] = service
|
|
256
|
+
|
|
257
|
+
def override_memory_hook_manager(self, service: IMemoryHookManager) -> None:
|
|
258
|
+
"""Override memory hook manager with a mock or custom implementation."""
|
|
259
|
+
self._overrides["memory_hook_manager"] = service
|
|
260
|
+
|
|
261
|
+
def override_subagent_processor(self, service: ISubagentProcessor) -> None:
|
|
262
|
+
"""Override subagent processor with a mock or custom implementation."""
|
|
263
|
+
self._overrides["subagent_processor"] = service
|
|
264
|
+
|
|
265
|
+
def override_auto_pause_handler(self, service: Optional[IAutoPauseHandler]) -> None:
|
|
266
|
+
"""Override auto-pause handler with a mock or custom implementation."""
|
|
267
|
+
self._overrides["auto_pause_handler"] = service
|
|
268
|
+
|
|
269
|
+
def override_event_handlers(self, service: IEventHandlers) -> None:
|
|
270
|
+
"""Override event handlers with a mock or custom implementation."""
|
|
271
|
+
self._overrides["event_handlers"] = service
|
|
272
|
+
|
|
273
|
+
def reset_overrides(self) -> None:
|
|
274
|
+
"""Reset all service overrides."""
|
|
275
|
+
self._overrides.clear()
|
|
276
|
+
|
|
277
|
+
def reset_all(self) -> None:
|
|
278
|
+
"""Reset all services and overrides.
|
|
279
|
+
|
|
280
|
+
Useful for testing to ensure clean state between tests.
|
|
281
|
+
"""
|
|
282
|
+
self._state_manager = None
|
|
283
|
+
self._connection_manager = None
|
|
284
|
+
self._duplicate_detector = None
|
|
285
|
+
self._response_tracking_manager = None
|
|
286
|
+
self._memory_hook_manager = None
|
|
287
|
+
self._subagent_processor = None
|
|
288
|
+
self._auto_pause_handler = None
|
|
289
|
+
self._event_handlers = None
|
|
290
|
+
self._overrides.clear()
|
|
291
|
+
|
|
292
|
+
@classmethod
|
|
293
|
+
def reset_singleton(cls) -> None:
|
|
294
|
+
"""Reset the singleton instance.
|
|
295
|
+
|
|
296
|
+
USE WITH CAUTION: This is primarily for testing.
|
|
297
|
+
"""
|
|
298
|
+
with cls._lock:
|
|
299
|
+
if cls._instance is not None:
|
|
300
|
+
cls._instance.reset_all()
|
|
301
|
+
cls._instance = None
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
def get_container() -> HookServiceContainer:
|
|
305
|
+
"""Get the global HookServiceContainer singleton.
|
|
306
|
+
|
|
307
|
+
Returns:
|
|
308
|
+
The singleton HookServiceContainer instance.
|
|
309
|
+
"""
|
|
310
|
+
return HookServiceContainer()
|