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
|
@@ -22,7 +22,7 @@ import os
|
|
|
22
22
|
import re
|
|
23
23
|
import select
|
|
24
24
|
import signal
|
|
25
|
-
import subprocess
|
|
25
|
+
import subprocess # nosec B404
|
|
26
26
|
import sys
|
|
27
27
|
import threading
|
|
28
28
|
from datetime import datetime, timezone
|
|
@@ -31,12 +31,14 @@ from typing import Optional, Tuple
|
|
|
31
31
|
# Import extracted modules with fallback for direct execution
|
|
32
32
|
try:
|
|
33
33
|
# Try relative imports first (when imported as module)
|
|
34
|
+
from .auto_pause_handler import AutoPauseHandler
|
|
34
35
|
from .event_handlers import EventHandlers
|
|
35
36
|
from .memory_integration import MemoryHookManager
|
|
36
37
|
from .response_tracking import ResponseTrackingManager
|
|
37
38
|
from .services import (
|
|
38
39
|
ConnectionManagerService,
|
|
39
40
|
DuplicateEventDetector,
|
|
41
|
+
HookServiceContainer,
|
|
40
42
|
StateManagerService,
|
|
41
43
|
SubagentResponseProcessor,
|
|
42
44
|
)
|
|
@@ -47,27 +49,61 @@ except ImportError:
|
|
|
47
49
|
# Add parent directory to path
|
|
48
50
|
sys.path.insert(0, str(Path(__file__).parent))
|
|
49
51
|
|
|
52
|
+
from auto_pause_handler import AutoPauseHandler
|
|
50
53
|
from event_handlers import EventHandlers
|
|
51
54
|
from memory_integration import MemoryHookManager
|
|
52
55
|
from response_tracking import ResponseTrackingManager
|
|
53
56
|
from services import (
|
|
54
57
|
ConnectionManagerService,
|
|
55
58
|
DuplicateEventDetector,
|
|
59
|
+
HookServiceContainer,
|
|
56
60
|
StateManagerService,
|
|
57
61
|
SubagentResponseProcessor,
|
|
58
62
|
)
|
|
59
63
|
|
|
64
|
+
# Import CorrelationManager with fallback (used in _route_event cleanup)
|
|
65
|
+
# WHY at top level: Runtime relative imports fail with "no known parent package" error
|
|
66
|
+
try:
|
|
67
|
+
from .correlation_manager import CorrelationManager
|
|
68
|
+
except ImportError:
|
|
69
|
+
try:
|
|
70
|
+
from correlation_manager import CorrelationManager
|
|
71
|
+
except ImportError:
|
|
72
|
+
# Fallback: create a no-op class if module unavailable
|
|
73
|
+
class CorrelationManager:
|
|
74
|
+
@staticmethod
|
|
75
|
+
def cleanup_old():
|
|
76
|
+
pass
|
|
77
|
+
|
|
78
|
+
|
|
60
79
|
"""
|
|
61
80
|
Debug mode configuration for hook processing.
|
|
62
81
|
|
|
63
|
-
WHY
|
|
64
|
-
|
|
65
|
-
|
|
82
|
+
WHY disabled by default: Production users should see clean output without debug noise.
|
|
83
|
+
Hook errors appear less confusing when debug output is minimal.
|
|
84
|
+
Development and debugging can enable via CLAUDE_MPM_HOOK_DEBUG=true.
|
|
66
85
|
|
|
67
86
|
Performance Impact: Debug logging adds ~5-10% overhead but provides crucial
|
|
68
|
-
visibility into event flow, timing, and error conditions.
|
|
87
|
+
visibility into event flow, timing, and error conditions when enabled.
|
|
69
88
|
"""
|
|
70
|
-
DEBUG = os.environ.get("CLAUDE_MPM_HOOK_DEBUG", "
|
|
89
|
+
DEBUG = os.environ.get("CLAUDE_MPM_HOOK_DEBUG", "false").lower() == "true"
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def _log(message: str) -> None:
|
|
93
|
+
"""Log message to file if DEBUG enabled. Never write to stderr.
|
|
94
|
+
|
|
95
|
+
WHY: Claude Code interprets ANY stderr output as a hook error.
|
|
96
|
+
Writing to stderr causes confusing "hook error" messages even for debug logs.
|
|
97
|
+
|
|
98
|
+
This helper ensures all debug output goes to a log file instead.
|
|
99
|
+
"""
|
|
100
|
+
if DEBUG:
|
|
101
|
+
try:
|
|
102
|
+
with open("/tmp/claude-mpm-hook.log", "a") as f: # nosec B108
|
|
103
|
+
f.write(f"[{datetime.now(timezone.utc).isoformat()}] {message}\n")
|
|
104
|
+
except Exception: # nosec B110 - intentional silent failure
|
|
105
|
+
pass # Never disrupt hook execution
|
|
106
|
+
|
|
71
107
|
|
|
72
108
|
"""
|
|
73
109
|
Conditional imports with graceful fallbacks for testing and modularity.
|
|
@@ -109,6 +145,8 @@ WHY version checking:
|
|
|
109
145
|
Security: Version checking prevents execution on incompatible environments.
|
|
110
146
|
"""
|
|
111
147
|
MIN_CLAUDE_VERSION = "1.0.92"
|
|
148
|
+
# Minimum version for user-invocable skills support
|
|
149
|
+
MIN_SKILLS_VERSION = "2.1.3"
|
|
112
150
|
|
|
113
151
|
|
|
114
152
|
def check_claude_version() -> Tuple[bool, Optional[str]]:
|
|
@@ -153,7 +191,7 @@ def check_claude_version() -> Tuple[bool, Optional[str]]:
|
|
|
153
191
|
"""
|
|
154
192
|
try:
|
|
155
193
|
# Try to detect Claude Code version
|
|
156
|
-
result = subprocess.run(
|
|
194
|
+
result = subprocess.run( # nosec B603 B607 - Safe: hardcoded claude CLI with --version flag, no user input
|
|
157
195
|
["claude", "--version"],
|
|
158
196
|
capture_output=True,
|
|
159
197
|
text=True,
|
|
@@ -184,22 +222,17 @@ def check_claude_version() -> Tuple[bool, Optional[str]]:
|
|
|
184
222
|
req_part = required[i] if i < len(required) else 0
|
|
185
223
|
|
|
186
224
|
if curr_part < req_part:
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
file=sys.stderr,
|
|
192
|
-
)
|
|
225
|
+
_log(
|
|
226
|
+
f"⚠️ Claude Code {version} does not support matcher-based hooks "
|
|
227
|
+
f"(requires {MIN_CLAUDE_VERSION}+). Hook monitoring disabled."
|
|
228
|
+
)
|
|
193
229
|
return False, version
|
|
194
230
|
if curr_part > req_part:
|
|
195
231
|
return True, version
|
|
196
232
|
|
|
197
233
|
return True, version
|
|
198
234
|
except Exception as e:
|
|
199
|
-
|
|
200
|
-
print(
|
|
201
|
-
f"Warning: Could not detect Claude Code version: {e}", file=sys.stderr
|
|
202
|
-
)
|
|
235
|
+
_log(f"Warning: Could not detect Claude Code version: {e}")
|
|
203
236
|
|
|
204
237
|
return False, None
|
|
205
238
|
|
|
@@ -212,26 +245,73 @@ class ClaudeHookHandler:
|
|
|
212
245
|
- Each service handles a specific responsibility
|
|
213
246
|
- Easier to test, maintain, and extend
|
|
214
247
|
- Reduced complexity in main handler class
|
|
248
|
+
|
|
249
|
+
Supports Dependency Injection:
|
|
250
|
+
- Pass a HookServiceContainer to override default services
|
|
251
|
+
- Useful for testing with mock services
|
|
252
|
+
- Maintains backward compatibility when no container is provided
|
|
215
253
|
"""
|
|
216
254
|
|
|
217
|
-
def __init__(self):
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
255
|
+
def __init__(self, container: Optional[HookServiceContainer] = None):
|
|
256
|
+
"""Initialize hook handler with optional DI container.
|
|
257
|
+
|
|
258
|
+
Args:
|
|
259
|
+
container: Optional HookServiceContainer for dependency injection.
|
|
260
|
+
If None, services are created directly (backward compatible).
|
|
261
|
+
"""
|
|
262
|
+
# Use container if provided, otherwise create services directly
|
|
263
|
+
if container is not None:
|
|
264
|
+
# DI mode: get services from container
|
|
265
|
+
self._container = container
|
|
266
|
+
self.state_manager = container.get_state_manager()
|
|
267
|
+
self.connection_manager = container.get_connection_manager()
|
|
268
|
+
self.duplicate_detector = container.get_duplicate_detector()
|
|
269
|
+
self.memory_hook_manager = container.get_memory_hook_manager()
|
|
270
|
+
self.response_tracking_manager = container.get_response_tracking_manager()
|
|
271
|
+
self.auto_pause_handler = container.get_auto_pause_handler()
|
|
272
|
+
|
|
273
|
+
# Event handlers need reference to this handler (circular, but contained)
|
|
274
|
+
self.event_handlers = EventHandlers(self)
|
|
275
|
+
|
|
276
|
+
# Subagent processor with injected dependencies
|
|
277
|
+
self.subagent_processor = container.get_subagent_processor(
|
|
278
|
+
self.state_manager,
|
|
279
|
+
self.response_tracking_manager,
|
|
280
|
+
self.connection_manager,
|
|
281
|
+
)
|
|
282
|
+
else:
|
|
283
|
+
# Backward compatible mode: create services directly
|
|
284
|
+
self._container = None
|
|
285
|
+
self.state_manager = StateManagerService()
|
|
286
|
+
self.connection_manager = ConnectionManagerService()
|
|
287
|
+
self.duplicate_detector = DuplicateEventDetector()
|
|
288
|
+
|
|
289
|
+
# Initialize extracted managers
|
|
290
|
+
self.memory_hook_manager = MemoryHookManager()
|
|
291
|
+
self.response_tracking_manager = ResponseTrackingManager()
|
|
292
|
+
self.event_handlers = EventHandlers(self)
|
|
293
|
+
|
|
294
|
+
# Initialize subagent processor with dependencies
|
|
295
|
+
self.subagent_processor = SubagentResponseProcessor(
|
|
296
|
+
self.state_manager,
|
|
297
|
+
self.response_tracking_manager,
|
|
298
|
+
self.connection_manager,
|
|
299
|
+
)
|
|
222
300
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
301
|
+
# Initialize auto-pause handler
|
|
302
|
+
try:
|
|
303
|
+
self.auto_pause_handler = AutoPauseHandler()
|
|
304
|
+
except Exception as e:
|
|
305
|
+
self.auto_pause_handler = None
|
|
306
|
+
_log(f"Auto-pause initialization failed: {e}")
|
|
227
307
|
|
|
228
|
-
#
|
|
229
|
-
self.
|
|
230
|
-
self.
|
|
231
|
-
)
|
|
308
|
+
# Link auto-pause handler to response tracking manager
|
|
309
|
+
if self.auto_pause_handler and hasattr(self, "response_tracking_manager"):
|
|
310
|
+
self.response_tracking_manager.auto_pause_handler = self.auto_pause_handler
|
|
232
311
|
|
|
233
312
|
# Backward compatibility properties for tests
|
|
234
|
-
|
|
313
|
+
# Note: HTTP-based connection manager doesn't use connection_pool
|
|
314
|
+
self.connection_pool = None # Deprecated: No longer needed with HTTP emission
|
|
235
315
|
|
|
236
316
|
# Expose state manager properties for backward compatibility
|
|
237
317
|
self.active_delegations = self.state_manager.active_delegations
|
|
@@ -260,8 +340,7 @@ class ClaudeHookHandler:
|
|
|
260
340
|
def timeout_handler(signum, frame):
|
|
261
341
|
"""Handle timeout by forcing exit."""
|
|
262
342
|
nonlocal _continue_sent
|
|
263
|
-
|
|
264
|
-
print(f"Hook handler timeout (pid: {os.getpid()})", file=sys.stderr)
|
|
343
|
+
_log(f"Hook handler timeout (pid: {os.getpid()})")
|
|
265
344
|
if not _continue_sent:
|
|
266
345
|
self._continue_execution()
|
|
267
346
|
_continue_sent = True
|
|
@@ -282,11 +361,9 @@ class ClaudeHookHandler:
|
|
|
282
361
|
|
|
283
362
|
# Check for duplicate events (same event within 100ms)
|
|
284
363
|
if self.duplicate_detector.is_duplicate(event):
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
file=sys.stderr,
|
|
289
|
-
)
|
|
364
|
+
_log(
|
|
365
|
+
f"[{datetime.now(timezone.utc).isoformat()}] Skipping duplicate event: {event.get('hook_event_name', 'unknown')} (PID: {os.getpid()})"
|
|
366
|
+
)
|
|
290
367
|
# Still need to output continue for this invocation
|
|
291
368
|
if not _continue_sent:
|
|
292
369
|
self._continue_execution()
|
|
@@ -294,25 +371,19 @@ class ClaudeHookHandler:
|
|
|
294
371
|
return
|
|
295
372
|
|
|
296
373
|
# Debug: Log that we're processing an event
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
file=sys.stderr,
|
|
302
|
-
)
|
|
374
|
+
hook_type = event.get("hook_event_name", "unknown")
|
|
375
|
+
_log(
|
|
376
|
+
f"\n[{datetime.now(timezone.utc).isoformat()}] Processing hook event: {hook_type} (PID: {os.getpid()})"
|
|
377
|
+
)
|
|
303
378
|
|
|
304
379
|
# Perform periodic cleanup if needed
|
|
305
380
|
if self.state_manager.increment_events_processed():
|
|
306
381
|
self.state_manager.cleanup_old_entries()
|
|
307
382
|
# Also cleanup old correlation files
|
|
308
|
-
from .correlation_manager import CorrelationManager
|
|
309
|
-
|
|
310
383
|
CorrelationManager.cleanup_old()
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
file=sys.stderr,
|
|
315
|
-
)
|
|
384
|
+
_log(
|
|
385
|
+
f"🧹 Performed cleanup after {self.state_manager.events_processed} events"
|
|
386
|
+
)
|
|
316
387
|
|
|
317
388
|
# Route event to appropriate handler
|
|
318
389
|
# Handlers can optionally return modified input for PreToolUse events
|
|
@@ -352,8 +423,7 @@ class ClaudeHookHandler:
|
|
|
352
423
|
ready, _, _ = select.select([sys.stdin], [], [], 1.0)
|
|
353
424
|
if not ready:
|
|
354
425
|
# No data available within timeout
|
|
355
|
-
|
|
356
|
-
print("No hook event data received within timeout", file=sys.stderr)
|
|
426
|
+
_log("No hook event data received within timeout")
|
|
357
427
|
return None
|
|
358
428
|
|
|
359
429
|
# Data is available, read it
|
|
@@ -364,21 +434,16 @@ class ClaudeHookHandler:
|
|
|
364
434
|
|
|
365
435
|
parsed = json.loads(event_data)
|
|
366
436
|
# Debug: Log the actual event format we receive
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
for key in ["hook_event_name", "event", "type", "event_type"]:
|
|
372
|
-
if key in parsed:
|
|
373
|
-
print(f" {key} = '{parsed[key]}'", file=sys.stderr)
|
|
437
|
+
_log(f"Received event with keys: {list(parsed.keys())}")
|
|
438
|
+
for key in ["hook_event_name", "event", "type", "event_type"]:
|
|
439
|
+
if key in parsed:
|
|
440
|
+
_log(f" {key} = '{parsed[key]}'")
|
|
374
441
|
return parsed
|
|
375
442
|
except (json.JSONDecodeError, ValueError) as e:
|
|
376
|
-
|
|
377
|
-
print(f"Failed to parse hook event: {e}", file=sys.stderr)
|
|
443
|
+
_log(f"Failed to parse hook event: {e}")
|
|
378
444
|
return None
|
|
379
445
|
except Exception as e:
|
|
380
|
-
|
|
381
|
-
print(f"Error reading hook event: {e}", file=sys.stderr)
|
|
446
|
+
_log(f"Error reading hook event: {e}")
|
|
382
447
|
return None
|
|
383
448
|
|
|
384
449
|
def _route_event(self, event: dict) -> Optional[dict]:
|
|
@@ -394,6 +459,8 @@ class ClaudeHookHandler:
|
|
|
394
459
|
Returns:
|
|
395
460
|
Modified input for PreToolUse events (v2.0.30+), None otherwise
|
|
396
461
|
"""
|
|
462
|
+
import time
|
|
463
|
+
|
|
397
464
|
# Try multiple field names for compatibility
|
|
398
465
|
hook_type = (
|
|
399
466
|
event.get("hook_event_name")
|
|
@@ -405,9 +472,9 @@ class ClaudeHookHandler:
|
|
|
405
472
|
)
|
|
406
473
|
|
|
407
474
|
# Log the actual event structure for debugging
|
|
408
|
-
if
|
|
409
|
-
|
|
410
|
-
|
|
475
|
+
if hook_type == "unknown":
|
|
476
|
+
_log(f"Unknown event format, keys: {list(event.keys())}")
|
|
477
|
+
_log(f"Event sample: {str(event)[:200]}")
|
|
411
478
|
|
|
412
479
|
# Map event types to handlers
|
|
413
480
|
event_handlers = {
|
|
@@ -417,7 +484,7 @@ class ClaudeHookHandler:
|
|
|
417
484
|
"Notification": self.event_handlers.handle_notification_fast,
|
|
418
485
|
"Stop": self.event_handlers.handle_stop_fast,
|
|
419
486
|
"SubagentStop": self.event_handlers.handle_subagent_stop_fast,
|
|
420
|
-
"SubagentStart": self.event_handlers.
|
|
487
|
+
"SubagentStart": self.event_handlers.handle_subagent_start_fast,
|
|
421
488
|
"SessionStart": self.event_handlers.handle_session_start_fast,
|
|
422
489
|
"AssistantResponse": self.event_handlers.handle_assistant_response,
|
|
423
490
|
}
|
|
@@ -425,15 +492,39 @@ class ClaudeHookHandler:
|
|
|
425
492
|
# Call appropriate handler if exists
|
|
426
493
|
handler = event_handlers.get(hook_type)
|
|
427
494
|
if handler:
|
|
495
|
+
# Track execution timing for hook emission
|
|
496
|
+
start_time = time.time()
|
|
497
|
+
success = False
|
|
498
|
+
error_message = None
|
|
499
|
+
result = None
|
|
500
|
+
|
|
428
501
|
try:
|
|
429
502
|
# Handlers can optionally return modified input
|
|
430
503
|
result = handler(event)
|
|
504
|
+
success = True
|
|
431
505
|
# Only PreToolUse handlers should return modified input
|
|
432
506
|
if hook_type == "PreToolUse" and result is not None:
|
|
433
|
-
|
|
507
|
+
return_value = result
|
|
508
|
+
else:
|
|
509
|
+
return_value = None
|
|
434
510
|
except Exception as e:
|
|
435
|
-
|
|
436
|
-
|
|
511
|
+
error_message = str(e)
|
|
512
|
+
return_value = None
|
|
513
|
+
_log(f"Error handling {hook_type}: {e}")
|
|
514
|
+
finally:
|
|
515
|
+
# Calculate duration
|
|
516
|
+
duration_ms = int((time.time() - start_time) * 1000)
|
|
517
|
+
|
|
518
|
+
# Emit hook execution event
|
|
519
|
+
self._emit_hook_execution_event(
|
|
520
|
+
hook_type=hook_type,
|
|
521
|
+
event=event,
|
|
522
|
+
success=success,
|
|
523
|
+
duration_ms=duration_ms,
|
|
524
|
+
error_message=error_message,
|
|
525
|
+
)
|
|
526
|
+
|
|
527
|
+
return return_value
|
|
437
528
|
|
|
438
529
|
return None
|
|
439
530
|
|
|
@@ -453,9 +544,12 @@ class ClaudeHookHandler:
|
|
|
453
544
|
"""
|
|
454
545
|
if modified_input is not None:
|
|
455
546
|
# Claude Code v2.0.30+ supports modifying PreToolUse tool inputs
|
|
456
|
-
print(
|
|
547
|
+
print(
|
|
548
|
+
json.dumps({"continue": True, "tool_input": modified_input}),
|
|
549
|
+
flush=True,
|
|
550
|
+
)
|
|
457
551
|
else:
|
|
458
|
-
print(json.dumps({"
|
|
552
|
+
print(json.dumps({"continue": True}), flush=True)
|
|
459
553
|
|
|
460
554
|
# Delegation methods for compatibility with event_handlers
|
|
461
555
|
def _track_delegation(self, session_id: str, agent_type: str, request_data=None):
|
|
@@ -478,14 +572,142 @@ class ClaudeHookHandler:
|
|
|
478
572
|
"""Generate event key through duplicate detector (backward compatibility)."""
|
|
479
573
|
return self.duplicate_detector.generate_event_key(event)
|
|
480
574
|
|
|
575
|
+
def _emit_hook_execution_event(
|
|
576
|
+
self,
|
|
577
|
+
hook_type: str,
|
|
578
|
+
event: dict,
|
|
579
|
+
success: bool,
|
|
580
|
+
duration_ms: int,
|
|
581
|
+
error_message: Optional[str] = None,
|
|
582
|
+
):
|
|
583
|
+
"""Emit a structured JSON event for hook execution.
|
|
584
|
+
|
|
585
|
+
This emits a normalized event following the claude_event schema to provide
|
|
586
|
+
visibility into hook processing, timing, and success/failure status.
|
|
587
|
+
|
|
588
|
+
Args:
|
|
589
|
+
hook_type: The type of hook that executed (e.g., "UserPromptSubmit", "PreToolUse")
|
|
590
|
+
event: The original hook event data
|
|
591
|
+
success: Whether the hook executed successfully
|
|
592
|
+
duration_ms: How long the hook took to execute in milliseconds
|
|
593
|
+
error_message: Optional error message if the hook failed
|
|
594
|
+
"""
|
|
595
|
+
# Generate a human-readable summary based on hook type
|
|
596
|
+
summary = self._generate_hook_summary(hook_type, event, success)
|
|
597
|
+
|
|
598
|
+
# Extract common fields
|
|
599
|
+
session_id = event.get("session_id", "")
|
|
600
|
+
working_dir = event.get("cwd", "")
|
|
601
|
+
|
|
602
|
+
# Build hook execution data
|
|
603
|
+
hook_data = {
|
|
604
|
+
"hook_name": hook_type,
|
|
605
|
+
"hook_type": hook_type, # Actual hook type (PreToolUse, UserPromptSubmit, etc.)
|
|
606
|
+
"hook_event_type": hook_type, # Additional field for clarity
|
|
607
|
+
"session_id": session_id,
|
|
608
|
+
"working_directory": working_dir,
|
|
609
|
+
"success": success,
|
|
610
|
+
"duration_ms": duration_ms,
|
|
611
|
+
"result_summary": summary,
|
|
612
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
613
|
+
"source": "claude_hook_handler", # Explicit source identification
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
# Add error information if present
|
|
617
|
+
if error_message:
|
|
618
|
+
hook_data["error_message"] = error_message
|
|
619
|
+
|
|
620
|
+
# Add hook-specific context
|
|
621
|
+
if hook_type == "PreToolUse":
|
|
622
|
+
hook_data["tool_name"] = event.get("tool_name", "")
|
|
623
|
+
elif hook_type == "PostToolUse":
|
|
624
|
+
hook_data["tool_name"] = event.get("tool_name", "")
|
|
625
|
+
hook_data["exit_code"] = event.get("exit_code", 0)
|
|
626
|
+
elif hook_type == "UserPromptSubmit":
|
|
627
|
+
prompt = event.get("prompt", "")
|
|
628
|
+
hook_data["prompt_preview"] = prompt[:100] if len(prompt) > 100 else prompt
|
|
629
|
+
hook_data["prompt_length"] = len(prompt)
|
|
630
|
+
elif hook_type == "SubagentStop":
|
|
631
|
+
hook_data["agent_type"] = event.get("agent_type", "unknown")
|
|
632
|
+
hook_data["reason"] = event.get("reason", "unknown")
|
|
633
|
+
|
|
634
|
+
# Emit through connection manager with proper structure
|
|
635
|
+
# This uses the existing event infrastructure
|
|
636
|
+
self._emit_socketio_event("", "hook_execution", hook_data)
|
|
637
|
+
|
|
638
|
+
_log(
|
|
639
|
+
f"📊 Hook execution event: {hook_type} - {duration_ms}ms - {'✅' if success else '❌'}"
|
|
640
|
+
)
|
|
641
|
+
|
|
642
|
+
def _generate_hook_summary(self, hook_type: str, event: dict, success: bool) -> str:
|
|
643
|
+
"""Generate a human-readable summary of what the hook did.
|
|
644
|
+
|
|
645
|
+
Args:
|
|
646
|
+
hook_type: The type of hook
|
|
647
|
+
event: The hook event data
|
|
648
|
+
success: Whether the hook executed successfully
|
|
649
|
+
|
|
650
|
+
Returns:
|
|
651
|
+
A brief description of what happened
|
|
652
|
+
"""
|
|
653
|
+
if not success:
|
|
654
|
+
return f"Hook {hook_type} failed during processing"
|
|
655
|
+
|
|
656
|
+
# Generate hook-specific summaries
|
|
657
|
+
if hook_type == "UserPromptSubmit":
|
|
658
|
+
prompt = event.get("prompt", "")
|
|
659
|
+
if prompt.startswith("/"):
|
|
660
|
+
return f"Processed command: {prompt.split()[0]}"
|
|
661
|
+
return f"Processed user prompt ({len(prompt)} chars)"
|
|
662
|
+
|
|
663
|
+
if hook_type == "PreToolUse":
|
|
664
|
+
tool_name = event.get("tool_name", "unknown")
|
|
665
|
+
return f"Pre-processing tool call: {tool_name}"
|
|
666
|
+
|
|
667
|
+
if hook_type == "PostToolUse":
|
|
668
|
+
tool_name = event.get("tool_name", "unknown")
|
|
669
|
+
exit_code = event.get("exit_code", 0)
|
|
670
|
+
status = "success" if exit_code == 0 else "failed"
|
|
671
|
+
return f"Completed tool call: {tool_name} ({status})"
|
|
672
|
+
|
|
673
|
+
if hook_type == "SubagentStop":
|
|
674
|
+
agent_type = event.get("agent_type", "unknown")
|
|
675
|
+
reason = event.get("reason", "unknown")
|
|
676
|
+
return f"Subagent {agent_type} stopped: {reason}"
|
|
677
|
+
|
|
678
|
+
if hook_type == "SessionStart":
|
|
679
|
+
return "New session started"
|
|
680
|
+
|
|
681
|
+
if hook_type == "Stop":
|
|
682
|
+
reason = event.get("reason", "unknown")
|
|
683
|
+
return f"Session stopped: {reason}"
|
|
684
|
+
|
|
685
|
+
if hook_type == "Notification":
|
|
686
|
+
notification_type = event.get("notification_type", "unknown")
|
|
687
|
+
return f"Notification received: {notification_type}"
|
|
688
|
+
|
|
689
|
+
if hook_type == "AssistantResponse":
|
|
690
|
+
response_len = len(event.get("response", ""))
|
|
691
|
+
return f"Assistant response generated ({response_len} chars)"
|
|
692
|
+
|
|
693
|
+
# Default summary
|
|
694
|
+
return f"Hook {hook_type} processed successfully"
|
|
695
|
+
|
|
481
696
|
def __del__(self):
|
|
482
697
|
"""Cleanup on handler destruction."""
|
|
698
|
+
# Finalize any active auto-pause session
|
|
699
|
+
if hasattr(self, "auto_pause_handler") and self.auto_pause_handler:
|
|
700
|
+
try:
|
|
701
|
+
self.auto_pause_handler.on_session_end()
|
|
702
|
+
except Exception:
|
|
703
|
+
pass # nosec B110 - Intentionally ignore cleanup errors during handler destruction
|
|
704
|
+
|
|
483
705
|
# Clean up connection manager if it exists
|
|
484
706
|
if hasattr(self, "connection_manager") and self.connection_manager:
|
|
485
707
|
try:
|
|
486
708
|
self.connection_manager.cleanup()
|
|
487
709
|
except Exception:
|
|
488
|
-
pass #
|
|
710
|
+
pass # nosec B110 - Intentionally ignore cleanup errors during handler destruction
|
|
489
711
|
|
|
490
712
|
|
|
491
713
|
def main():
|
|
@@ -498,25 +720,18 @@ def main():
|
|
|
498
720
|
if not is_compatible:
|
|
499
721
|
# Version incompatible - just continue without processing
|
|
500
722
|
# This prevents errors on older Claude Code versions
|
|
501
|
-
if
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
file=sys.stderr,
|
|
505
|
-
)
|
|
506
|
-
print(json.dumps({"action": "continue"}))
|
|
723
|
+
if version:
|
|
724
|
+
_log(f"Skipping hook processing due to version incompatibility ({version})")
|
|
725
|
+
print(json.dumps({"continue": True}), flush=True)
|
|
507
726
|
sys.exit(0)
|
|
508
727
|
|
|
509
728
|
def cleanup_handler(signum=None, frame=None):
|
|
510
729
|
"""Cleanup handler for signals and exit."""
|
|
511
730
|
nonlocal _continue_printed
|
|
512
|
-
|
|
513
|
-
print(
|
|
514
|
-
f"Hook handler cleanup (pid: {os.getpid()}, signal: {signum})",
|
|
515
|
-
file=sys.stderr,
|
|
516
|
-
)
|
|
731
|
+
_log(f"Hook handler cleanup (pid: {os.getpid()}, signal: {signum})")
|
|
517
732
|
# Only output continue if we haven't already (i.e., if interrupted by signal)
|
|
518
733
|
if signum is not None and not _continue_printed:
|
|
519
|
-
print(json.dumps({"
|
|
734
|
+
print(json.dumps({"continue": True}), flush=True)
|
|
520
735
|
_continue_printed = True
|
|
521
736
|
sys.exit(0)
|
|
522
737
|
|
|
@@ -530,15 +745,10 @@ def main():
|
|
|
530
745
|
with _handler_lock:
|
|
531
746
|
if _global_handler is None:
|
|
532
747
|
_global_handler = ClaudeHookHandler()
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
)
|
|
538
|
-
elif DEBUG:
|
|
539
|
-
print(
|
|
540
|
-
f"♻️ Reusing existing ClaudeHookHandler singleton (pid: {os.getpid()})",
|
|
541
|
-
file=sys.stderr,
|
|
748
|
+
_log(f"✅ Created new ClaudeHookHandler singleton (pid: {os.getpid()})")
|
|
749
|
+
else:
|
|
750
|
+
_log(
|
|
751
|
+
f"♻️ Reusing existing ClaudeHookHandler singleton (pid: {os.getpid()})"
|
|
542
752
|
)
|
|
543
753
|
|
|
544
754
|
handler = _global_handler
|
|
@@ -554,13 +764,17 @@ def main():
|
|
|
554
764
|
except Exception as e:
|
|
555
765
|
# Only output continue if not already printed
|
|
556
766
|
if not _continue_printed:
|
|
557
|
-
print(json.dumps({"
|
|
767
|
+
print(json.dumps({"continue": True}), flush=True)
|
|
558
768
|
_continue_printed = True
|
|
559
769
|
# Log error for debugging
|
|
560
|
-
|
|
561
|
-
print(f"Hook handler error: {e}", file=sys.stderr)
|
|
770
|
+
_log(f"Hook handler error: {e}")
|
|
562
771
|
sys.exit(0) # Exit cleanly even on error
|
|
563
772
|
|
|
564
773
|
|
|
565
774
|
if __name__ == "__main__":
|
|
566
|
-
|
|
775
|
+
try:
|
|
776
|
+
main()
|
|
777
|
+
except Exception:
|
|
778
|
+
# Catastrophic failure (import error, etc.) - always output valid JSON
|
|
779
|
+
print(json.dumps({"continue": True}), flush=True)
|
|
780
|
+
sys.exit(0)
|
|
@@ -48,15 +48,10 @@ echo "[$(date -u +%Y-%m-%dT%H:%M:%S.%3NZ)] PYTHONPATH: $PYTHONPATH" >> /tmp/hook
|
|
|
48
48
|
echo "[$(date -u +%Y-%m-%dT%H:%M:%S.%3NZ)] Running: $PYTHON_CMD -m claude_mpm.hooks.claude_hooks.hook_handler" >> /tmp/hook-wrapper.log
|
|
49
49
|
echo "[$(date -u +%Y-%m-%dT%H:%M:%S.%3NZ)] SOCKETIO_PORT: $CLAUDE_MPM_SOCKETIO_PORT" >> /tmp/hook-wrapper.log
|
|
50
50
|
|
|
51
|
-
# Run the Python hook handler as a module
|
|
52
|
-
#
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
echo '{"action": "continue"}'
|
|
56
|
-
# Log the error for debugging
|
|
57
|
-
echo "[$(date -u +%Y-%m-%dT%H:%M:%S.%3NZ)] Hook handler failed, see /tmp/hook-error.log" >> /tmp/hook-wrapper.log
|
|
58
|
-
exit 0
|
|
59
|
-
fi
|
|
51
|
+
# Run the Python hook handler as a module
|
|
52
|
+
# Python handler is responsible for ALL stdout output (including error fallback)
|
|
53
|
+
# Redirect stderr to log file for debugging
|
|
54
|
+
"$PYTHON_CMD" -m claude_mpm.hooks.claude_hooks.hook_handler "$@" 2>/tmp/hook-error.log
|
|
60
55
|
|
|
61
|
-
#
|
|
62
|
-
exit
|
|
56
|
+
# Exit with Python's exit code (should always be 0)
|
|
57
|
+
exit $?
|