claude-mpm 5.4.85__py3-none-any.whl → 5.6.76__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- claude_mpm/VERSION +1 -1
- claude_mpm/agents/CLAUDE_MPM_OUTPUT_STYLE.md +8 -5
- claude_mpm/agents/{CLAUDE_MPM_FOUNDERS_OUTPUT_STYLE.md → CLAUDE_MPM_RESEARCH_OUTPUT_STYLE.md} +14 -6
- claude_mpm/agents/PM_INSTRUCTIONS.md +109 -706
- claude_mpm/agents/WORKFLOW.md +2 -0
- claude_mpm/agents/templates/circuit-breakers.md +26 -17
- claude_mpm/auth/__init__.py +35 -0
- claude_mpm/auth/callback_server.py +328 -0
- claude_mpm/auth/models.py +104 -0
- claude_mpm/auth/oauth_manager.py +266 -0
- claude_mpm/auth/providers/__init__.py +12 -0
- claude_mpm/auth/providers/base.py +165 -0
- claude_mpm/auth/providers/google.py +261 -0
- claude_mpm/auth/token_storage.py +252 -0
- claude_mpm/cli/commands/autotodos.py +566 -0
- claude_mpm/cli/commands/commander.py +216 -0
- claude_mpm/cli/commands/hook_errors.py +60 -60
- claude_mpm/cli/commands/mcp.py +29 -17
- claude_mpm/cli/commands/mcp_command_router.py +39 -0
- claude_mpm/cli/commands/mcp_service_commands.py +304 -0
- claude_mpm/cli/commands/monitor.py +2 -2
- claude_mpm/cli/commands/mpm_init/core.py +2 -2
- claude_mpm/cli/commands/oauth.py +481 -0
- claude_mpm/cli/commands/run.py +35 -3
- claude_mpm/cli/commands/skill_source.py +51 -2
- claude_mpm/cli/commands/skills.py +5 -3
- claude_mpm/cli/executor.py +128 -16
- claude_mpm/cli/helpers.py +1 -1
- claude_mpm/cli/parsers/base_parser.py +84 -1
- claude_mpm/cli/parsers/commander_parser.py +116 -0
- claude_mpm/cli/parsers/mcp_parser.py +79 -0
- claude_mpm/cli/parsers/oauth_parser.py +165 -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 +5 -0
- claude_mpm/cli/startup.py +345 -40
- claude_mpm/cli/startup_display.py +76 -7
- claude_mpm/cli/startup_logging.py +2 -2
- claude_mpm/cli/startup_migrations.py +236 -0
- 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 +149 -0
- claude_mpm/commander/chat/commands.py +124 -0
- claude_mpm/commander/chat/repl.py +1957 -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 +392 -0
- claude_mpm/commander/frameworks/__init__.py +12 -0
- claude_mpm/commander/frameworks/base.py +233 -0
- claude_mpm/commander/frameworks/claude_code.py +58 -0
- claude_mpm/commander/frameworks/mpm.py +57 -0
- claude_mpm/commander/git/__init__.py +5 -0
- claude_mpm/commander/git/worktree_manager.py +212 -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 +868 -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 +127 -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 +403 -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 +362 -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 +8 -0
- claude_mpm/commands/mpm-doctor.md +8 -0
- claude_mpm/commands/mpm-help.md +8 -0
- claude_mpm/commands/mpm-init.md +8 -0
- claude_mpm/commands/mpm-monitor.md +8 -0
- claude_mpm/commands/mpm-organize.md +8 -0
- claude_mpm/commands/mpm-postmortem.md +8 -0
- claude_mpm/commands/mpm-session-resume.md +9 -1
- claude_mpm/commands/mpm-status.md +8 -0
- claude_mpm/commands/mpm-ticket-view.md +8 -0
- claude_mpm/commands/mpm-version.md +8 -0
- 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 +5 -0
- claude_mpm/core/claude_runner.py +152 -0
- claude_mpm/core/config.py +35 -22
- claude_mpm/core/config_constants.py +74 -9
- claude_mpm/core/constants.py +56 -12
- claude_mpm/core/hook_manager.py +53 -4
- claude_mpm/core/interactive_session.py +5 -4
- 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/output_style_manager.py +52 -12
- claude_mpm/core/socketio_pool.py +47 -15
- claude_mpm/core/unified_config.py +10 -6
- claude_mpm/core/unified_paths.py +68 -80
- 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/{Cs_tUR18.js → 1WZnGYqX.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CDuw-vjf.js → 67pF3qNn.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{bTOqqlTd.js → 6RxdMKe4.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DwBR2MJi.js → 8cZrfX0h.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{ZGh7QtNv.js → 9a6T2nm-.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{D9lljYKQ.js → B443AUzu.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{RJiighC3.js → B8AwtY2H.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{uuIeMWc-.js → BF15LAsF.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{D3k0OPJN.js → BRcwIQNr.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CyWMqx4W.js → BV6nKitt.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CiIAseT4.js → BViJ8lZt.js} +5 -5
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CBBdVcY8.js → BcQ-Q0FE.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{BovzEFCE.js → Bpyvgze_.js} +1 -1
- 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/{eNVUfhuA.js → C3rbW_a-.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{GYwsonyD.js → C8WYN38h.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{BIF9m_hv.js → C9I8FlXH.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{B0uc0UOD.js → CIQcWgO2.js} +3 -3
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Be7GpZd6.js → CIctN7YN.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Bh0LDWpI.js → CKrS_JZW.js} +2 -2
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DUrLdbGD.js → CR6P9C4A.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{B7xVLGWV.js → CRRR9MD_.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CRcR2DqT.js +334 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Dhb8PKl3.js → CSXtMOf0.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{BPYeabCQ.js → CT-sbxSk.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{sQeU3Y1z.js → CWm6DJsp.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CnA0NrzZ.js → CpqQ1Kzn.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{C4B-KCzX.js → D2nGpDRe.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DGkLK5U1.js → D9iCMida.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{BofRWZRR.js → D9ykgMoY.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DmxopI1J.js → DL2Ldur1.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{C30mlcqg.js → DPfltzjH.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Vzk33B_K.js → DR8nis88.js} +2 -2
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DI7hHRFL.js → DUliQN2b.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{C4JcI4KD.js → DXlhR01x.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{bT1r9zLR.js → D_lyTybS.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DZX00Y4g.js → DngoTTgh.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CzZX-COe.js → DqkmHtDC.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{B7RN905-.js → DsDh8EYs.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DLVjFsZ3.js → DypDmXgd.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{iEWssX7S.js → IPYC-LnN.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/JTLiF7dt.js +24 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DaimHw_p.js → JpevfAFt.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DY1XQ8fi.js → R8CEIRAd.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Dle-35c7.js → Zxy7qc-l.js} +2 -2
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/q9Hm6zAU.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{C_Usid8X.js → qtd3IeO4.js} +2 -2
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CzeYkLYB.js → ulBFON_C.js} +2 -2
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Cfqx1Qun.js → wQVh1CoA.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/{app.D6-I5TpK.js → app.Dr7t0z2J.js} +2 -2
- claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.BGhZHUS3.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/{0.m1gL8KXf.js → 0.RgBboRvH.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/{1.CgNOuw-d.js → 1.DG-KkbDf.js} +1 -1
- 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 -1
- claude_mpm/dashboard/static/svelte-build/index.html +9 -9
- 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/auto_pause_handler.py +485 -0
- claude_mpm/hooks/claude_hooks/event_handlers.py +466 -136
- claude_mpm/hooks/claude_hooks/hook_handler.py +204 -104
- claude_mpm/hooks/claude_hooks/hook_wrapper.sh +6 -11
- claude_mpm/hooks/claude_hooks/installer.py +291 -59
- 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/connection_manager.py +41 -26
- claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +38 -105
- claude_mpm/hooks/claude_hooks/services/container.py +326 -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/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 +22 -15
- claude_mpm/mcp/__init__.py +9 -0
- claude_mpm/mcp/google_workspace_server.py +610 -0
- claude_mpm/scripts/claude-hook-handler.sh +46 -19
- 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 +1 -1
- claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +3 -0
- claude_mpm/services/agents/loading/framework_agent_loader.py +75 -2
- claude_mpm/services/agents/single_tier_deployment_service.py +4 -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_sources_check.py +30 -0
- 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/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/mcp_config_manager.py +99 -19
- claude_mpm/services/mcp_service_registry.py +294 -0
- claude_mpm/services/monitor/daemon_manager.py +15 -4
- claude_mpm/services/monitor/management/lifecycle.py +8 -2
- claude_mpm/services/monitor/server.py +111 -16
- claude_mpm/services/pm_skills_deployer.py +261 -87
- claude_mpm/services/skills/git_skill_source_manager.py +130 -10
- claude_mpm/services/skills/selective_skill_deployer.py +142 -16
- claude_mpm/services/skills/skill_discovery_service.py +74 -4
- claude_mpm/services/skills_deployer.py +31 -5
- claude_mpm/services/socketio/handlers/hook.py +14 -7
- claude_mpm/services/socketio/server/main.py +12 -4
- claude_mpm/skills/__init__.py +2 -1
- 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-circuit-breaker-enforcement/SKILL.md +476 -0
- claude_mpm/skills/bundled/pm/mpm-config/SKILL.md +29 -0
- claude_mpm/skills/bundled/pm/mpm-doctor/SKILL.md +53 -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-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/{pm-teaching-mode → mpm-teaching-mode}/SKILL.md +2 -2
- claude_mpm/skills/bundled/pm/mpm-ticket-view/SKILL.md +110 -0
- claude_mpm/skills/bundled/pm/mpm-tool-usage-guide/SKILL.md +386 -0
- claude_mpm/skills/bundled/pm/mpm-version/SKILL.md +21 -0
- claude_mpm/skills/registry.py +295 -90
- claude_mpm/skills/skill_manager.py +4 -4
- claude_mpm-5.6.76.dist-info/METADATA +416 -0
- {claude_mpm-5.4.85.dist-info → claude_mpm-5.6.76.dist-info}/RECORD +312 -175
- {claude_mpm-5.4.85.dist-info → claude_mpm-5.6.76.dist-info}/WHEEL +1 -1
- {claude_mpm-5.4.85.dist-info → claude_mpm-5.6.76.dist-info}/entry_points.txt +2 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.DWzvg0-y.css +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.ThTw9_ym.css +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/4TdZjIqw.js +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/5shd3_w0.js +0 -24
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BKjSRqUr.js +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Da0KfYnO.js +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Dfy6j1xT.js +0 -323
- claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.NWzMBYRp.js +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.C0GcWctS.js +0 -1
- claude_mpm-5.4.85.dist-info/METADATA +0 -1023
- /claude_mpm/skills/bundled/pm/{pm-bug-reporting/pm-bug-reporting.md → mpm-bug-reporting/SKILL.md} +0 -0
- /claude_mpm/skills/bundled/pm/{pm-delegation-patterns → mpm-delegation-patterns}/SKILL.md +0 -0
- /claude_mpm/skills/bundled/pm/{pm-git-file-tracking → mpm-git-file-tracking}/SKILL.md +0 -0
- /claude_mpm/skills/bundled/pm/{pm-pr-workflow → mpm-pr-workflow}/SKILL.md +0 -0
- /claude_mpm/skills/bundled/pm/{pm-ticketing-integration → mpm-ticketing-integration}/SKILL.md +0 -0
- /claude_mpm/skills/bundled/pm/{pm-verification-protocols → mpm-verification-protocols}/SKILL.md +0 -0
- {claude_mpm-5.4.85.dist-info → claude_mpm-5.6.76.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-5.4.85.dist-info → claude_mpm-5.6.76.dist-info}/licenses/LICENSE-FAQ.md +0 -0
- {claude_mpm-5.4.85.dist-info → claude_mpm-5.6.76.dist-info}/top_level.txt +0 -0
|
@@ -1,4 +1,32 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
|
+
# ==============================================================================
|
|
3
|
+
# CRITICAL: EARLY LOGGING SUPPRESSION - MUST BE FIRST
|
|
4
|
+
# ==============================================================================
|
|
5
|
+
# Suppress ALL logging before any other imports to prevent REPL pollution.
|
|
6
|
+
# The StreamingHandler in logger.py writes carriage returns (\r) and spaces
|
|
7
|
+
# to stderr which pollutes Claude Code's REPL output.
|
|
8
|
+
#
|
|
9
|
+
# This MUST be before any imports that could trigger module-level loggers.
|
|
10
|
+
# ==============================================================================
|
|
11
|
+
import logging as _early_logging
|
|
12
|
+
import sys as _early_sys
|
|
13
|
+
|
|
14
|
+
# Force redirect all logging to NullHandler before any module imports
|
|
15
|
+
# This prevents ANY log output from polluting stdout/stderr during hook execution
|
|
16
|
+
_early_logging.basicConfig(handlers=[_early_logging.NullHandler()], force=True)
|
|
17
|
+
# Also ensure root logger has no handlers that write to stderr
|
|
18
|
+
_early_logging.getLogger().handlers = [_early_logging.NullHandler()]
|
|
19
|
+
# Suppress all loggers by setting a very high level initially
|
|
20
|
+
_early_logging.getLogger().setLevel(_early_logging.CRITICAL + 1)
|
|
21
|
+
|
|
22
|
+
# Clean up namespace to avoid polluting module scope
|
|
23
|
+
del _early_logging
|
|
24
|
+
del _early_sys
|
|
25
|
+
|
|
26
|
+
# ==============================================================================
|
|
27
|
+
# END EARLY LOGGING SUPPRESSION
|
|
28
|
+
# ==============================================================================
|
|
29
|
+
|
|
2
30
|
"""Refactored Claude Code hook handler with modular service architecture.
|
|
3
31
|
|
|
4
32
|
This handler uses a service-oriented architecture with:
|
|
@@ -17,12 +45,18 @@ NOTE: Requires Claude Code version 1.0.92 or higher for proper hook support.
|
|
|
17
45
|
Earlier versions do not support matcher-based hook configuration.
|
|
18
46
|
"""
|
|
19
47
|
|
|
48
|
+
# Suppress RuntimeWarning from frozen runpy (prevents REPL pollution in Claude Code)
|
|
49
|
+
# Must be before other imports to suppress warnings during import
|
|
50
|
+
import warnings
|
|
51
|
+
|
|
52
|
+
warnings.filterwarnings("ignore", category=RuntimeWarning)
|
|
53
|
+
|
|
20
54
|
import json
|
|
21
55
|
import os
|
|
22
56
|
import re
|
|
23
57
|
import select
|
|
24
58
|
import signal
|
|
25
|
-
import subprocess
|
|
59
|
+
import subprocess # nosec B404
|
|
26
60
|
import sys
|
|
27
61
|
import threading
|
|
28
62
|
from datetime import datetime, timezone
|
|
@@ -31,12 +65,14 @@ from typing import Optional, Tuple
|
|
|
31
65
|
# Import extracted modules with fallback for direct execution
|
|
32
66
|
try:
|
|
33
67
|
# Try relative imports first (when imported as module)
|
|
68
|
+
from .auto_pause_handler import AutoPauseHandler
|
|
34
69
|
from .event_handlers import EventHandlers
|
|
35
70
|
from .memory_integration import MemoryHookManager
|
|
36
71
|
from .response_tracking import ResponseTrackingManager
|
|
37
72
|
from .services import (
|
|
38
73
|
ConnectionManagerService,
|
|
39
74
|
DuplicateEventDetector,
|
|
75
|
+
HookServiceContainer,
|
|
40
76
|
StateManagerService,
|
|
41
77
|
SubagentResponseProcessor,
|
|
42
78
|
)
|
|
@@ -47,27 +83,61 @@ except ImportError:
|
|
|
47
83
|
# Add parent directory to path
|
|
48
84
|
sys.path.insert(0, str(Path(__file__).parent))
|
|
49
85
|
|
|
86
|
+
from auto_pause_handler import AutoPauseHandler
|
|
50
87
|
from event_handlers import EventHandlers
|
|
51
88
|
from memory_integration import MemoryHookManager
|
|
52
89
|
from response_tracking import ResponseTrackingManager
|
|
53
90
|
from services import (
|
|
54
91
|
ConnectionManagerService,
|
|
55
92
|
DuplicateEventDetector,
|
|
93
|
+
HookServiceContainer,
|
|
56
94
|
StateManagerService,
|
|
57
95
|
SubagentResponseProcessor,
|
|
58
96
|
)
|
|
59
97
|
|
|
98
|
+
# Import CorrelationManager with fallback (used in _route_event cleanup)
|
|
99
|
+
# WHY at top level: Runtime relative imports fail with "no known parent package" error
|
|
100
|
+
try:
|
|
101
|
+
from .correlation_manager import CorrelationManager
|
|
102
|
+
except ImportError:
|
|
103
|
+
try:
|
|
104
|
+
from correlation_manager import CorrelationManager
|
|
105
|
+
except ImportError:
|
|
106
|
+
# Fallback: create a no-op class if module unavailable
|
|
107
|
+
class CorrelationManager:
|
|
108
|
+
@staticmethod
|
|
109
|
+
def cleanup_old():
|
|
110
|
+
pass
|
|
111
|
+
|
|
112
|
+
|
|
60
113
|
"""
|
|
61
114
|
Debug mode configuration for hook processing.
|
|
62
115
|
|
|
63
|
-
WHY
|
|
64
|
-
|
|
65
|
-
|
|
116
|
+
WHY disabled by default: Production users should see clean output without debug noise.
|
|
117
|
+
Hook errors appear less confusing when debug output is minimal.
|
|
118
|
+
Development and debugging can enable via CLAUDE_MPM_HOOK_DEBUG=true.
|
|
66
119
|
|
|
67
120
|
Performance Impact: Debug logging adds ~5-10% overhead but provides crucial
|
|
68
|
-
visibility into event flow, timing, and error conditions.
|
|
121
|
+
visibility into event flow, timing, and error conditions when enabled.
|
|
69
122
|
"""
|
|
70
|
-
DEBUG = os.environ.get("CLAUDE_MPM_HOOK_DEBUG", "
|
|
123
|
+
DEBUG = os.environ.get("CLAUDE_MPM_HOOK_DEBUG", "false").lower() == "true"
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def _log(message: str) -> None:
|
|
127
|
+
"""Log message to file if DEBUG enabled. Never write to stderr.
|
|
128
|
+
|
|
129
|
+
WHY: Claude Code interprets ANY stderr output as a hook error.
|
|
130
|
+
Writing to stderr causes confusing "hook error" messages even for debug logs.
|
|
131
|
+
|
|
132
|
+
This helper ensures all debug output goes to a log file instead.
|
|
133
|
+
"""
|
|
134
|
+
if DEBUG:
|
|
135
|
+
try:
|
|
136
|
+
with open("/tmp/claude-mpm-hook.log", "a") as f: # nosec B108
|
|
137
|
+
f.write(f"[{datetime.now(timezone.utc).isoformat()}] {message}\n")
|
|
138
|
+
except Exception: # nosec B110 - intentional silent failure
|
|
139
|
+
pass # Never disrupt hook execution
|
|
140
|
+
|
|
71
141
|
|
|
72
142
|
"""
|
|
73
143
|
Conditional imports with graceful fallbacks for testing and modularity.
|
|
@@ -109,6 +179,8 @@ WHY version checking:
|
|
|
109
179
|
Security: Version checking prevents execution on incompatible environments.
|
|
110
180
|
"""
|
|
111
181
|
MIN_CLAUDE_VERSION = "1.0.92"
|
|
182
|
+
# Minimum version for user-invocable skills support
|
|
183
|
+
MIN_SKILLS_VERSION = "2.1.3"
|
|
112
184
|
|
|
113
185
|
|
|
114
186
|
def check_claude_version() -> Tuple[bool, Optional[str]]:
|
|
@@ -153,7 +225,7 @@ def check_claude_version() -> Tuple[bool, Optional[str]]:
|
|
|
153
225
|
"""
|
|
154
226
|
try:
|
|
155
227
|
# Try to detect Claude Code version
|
|
156
|
-
result = subprocess.run(
|
|
228
|
+
result = subprocess.run( # nosec B603 B607 - Safe: hardcoded claude CLI with --version flag, no user input
|
|
157
229
|
["claude", "--version"],
|
|
158
230
|
capture_output=True,
|
|
159
231
|
text=True,
|
|
@@ -184,22 +256,17 @@ def check_claude_version() -> Tuple[bool, Optional[str]]:
|
|
|
184
256
|
req_part = required[i] if i < len(required) else 0
|
|
185
257
|
|
|
186
258
|
if curr_part < req_part:
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
file=sys.stderr,
|
|
192
|
-
)
|
|
259
|
+
_log(
|
|
260
|
+
f"⚠️ Claude Code {version} does not support matcher-based hooks "
|
|
261
|
+
f"(requires {MIN_CLAUDE_VERSION}+). Hook monitoring disabled."
|
|
262
|
+
)
|
|
193
263
|
return False, version
|
|
194
264
|
if curr_part > req_part:
|
|
195
265
|
return True, version
|
|
196
266
|
|
|
197
267
|
return True, version
|
|
198
268
|
except Exception as e:
|
|
199
|
-
|
|
200
|
-
print(
|
|
201
|
-
f"Warning: Could not detect Claude Code version: {e}", file=sys.stderr
|
|
202
|
-
)
|
|
269
|
+
_log(f"Warning: Could not detect Claude Code version: {e}")
|
|
203
270
|
|
|
204
271
|
return False, None
|
|
205
272
|
|
|
@@ -212,26 +279,73 @@ class ClaudeHookHandler:
|
|
|
212
279
|
- Each service handles a specific responsibility
|
|
213
280
|
- Easier to test, maintain, and extend
|
|
214
281
|
- Reduced complexity in main handler class
|
|
282
|
+
|
|
283
|
+
Supports Dependency Injection:
|
|
284
|
+
- Pass a HookServiceContainer to override default services
|
|
285
|
+
- Useful for testing with mock services
|
|
286
|
+
- Maintains backward compatibility when no container is provided
|
|
215
287
|
"""
|
|
216
288
|
|
|
217
|
-
def __init__(self):
|
|
218
|
-
|
|
219
|
-
self.state_manager = StateManagerService()
|
|
220
|
-
self.connection_manager = ConnectionManagerService()
|
|
221
|
-
self.duplicate_detector = DuplicateEventDetector()
|
|
289
|
+
def __init__(self, container: Optional[HookServiceContainer] = None):
|
|
290
|
+
"""Initialize hook handler with optional DI container.
|
|
222
291
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
292
|
+
Args:
|
|
293
|
+
container: Optional HookServiceContainer for dependency injection.
|
|
294
|
+
If None, services are created directly (backward compatible).
|
|
295
|
+
"""
|
|
296
|
+
# Use container if provided, otherwise create services directly
|
|
297
|
+
if container is not None:
|
|
298
|
+
# DI mode: get services from container
|
|
299
|
+
self._container = container
|
|
300
|
+
self.state_manager = container.get_state_manager()
|
|
301
|
+
self.connection_manager = container.get_connection_manager()
|
|
302
|
+
self.duplicate_detector = container.get_duplicate_detector()
|
|
303
|
+
self.memory_hook_manager = container.get_memory_hook_manager()
|
|
304
|
+
self.response_tracking_manager = container.get_response_tracking_manager()
|
|
305
|
+
self.auto_pause_handler = container.get_auto_pause_handler()
|
|
306
|
+
|
|
307
|
+
# Event handlers need reference to this handler (circular, but contained)
|
|
308
|
+
self.event_handlers = EventHandlers(self)
|
|
309
|
+
|
|
310
|
+
# Subagent processor with injected dependencies
|
|
311
|
+
self.subagent_processor = container.get_subagent_processor(
|
|
312
|
+
self.state_manager,
|
|
313
|
+
self.response_tracking_manager,
|
|
314
|
+
self.connection_manager,
|
|
315
|
+
)
|
|
316
|
+
else:
|
|
317
|
+
# Backward compatible mode: create services directly
|
|
318
|
+
self._container = None
|
|
319
|
+
self.state_manager = StateManagerService()
|
|
320
|
+
self.connection_manager = ConnectionManagerService()
|
|
321
|
+
self.duplicate_detector = DuplicateEventDetector()
|
|
322
|
+
|
|
323
|
+
# Initialize extracted managers
|
|
324
|
+
self.memory_hook_manager = MemoryHookManager()
|
|
325
|
+
self.response_tracking_manager = ResponseTrackingManager()
|
|
326
|
+
self.event_handlers = EventHandlers(self)
|
|
327
|
+
|
|
328
|
+
# Initialize subagent processor with dependencies
|
|
329
|
+
self.subagent_processor = SubagentResponseProcessor(
|
|
330
|
+
self.state_manager,
|
|
331
|
+
self.response_tracking_manager,
|
|
332
|
+
self.connection_manager,
|
|
333
|
+
)
|
|
227
334
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
335
|
+
# Initialize auto-pause handler
|
|
336
|
+
try:
|
|
337
|
+
self.auto_pause_handler = AutoPauseHandler()
|
|
338
|
+
except Exception as e:
|
|
339
|
+
self.auto_pause_handler = None
|
|
340
|
+
_log(f"Auto-pause initialization failed: {e}")
|
|
341
|
+
|
|
342
|
+
# Link auto-pause handler to response tracking manager
|
|
343
|
+
if self.auto_pause_handler and hasattr(self, "response_tracking_manager"):
|
|
344
|
+
self.response_tracking_manager.auto_pause_handler = self.auto_pause_handler
|
|
232
345
|
|
|
233
346
|
# Backward compatibility properties for tests
|
|
234
|
-
|
|
347
|
+
# Note: HTTP-based connection manager doesn't use connection_pool
|
|
348
|
+
self.connection_pool = None # Deprecated: No longer needed with HTTP emission
|
|
235
349
|
|
|
236
350
|
# Expose state manager properties for backward compatibility
|
|
237
351
|
self.active_delegations = self.state_manager.active_delegations
|
|
@@ -260,8 +374,7 @@ class ClaudeHookHandler:
|
|
|
260
374
|
def timeout_handler(signum, frame):
|
|
261
375
|
"""Handle timeout by forcing exit."""
|
|
262
376
|
nonlocal _continue_sent
|
|
263
|
-
|
|
264
|
-
print(f"Hook handler timeout (pid: {os.getpid()})", file=sys.stderr)
|
|
377
|
+
_log(f"Hook handler timeout (pid: {os.getpid()})")
|
|
265
378
|
if not _continue_sent:
|
|
266
379
|
self._continue_execution()
|
|
267
380
|
_continue_sent = True
|
|
@@ -282,11 +395,9 @@ class ClaudeHookHandler:
|
|
|
282
395
|
|
|
283
396
|
# Check for duplicate events (same event within 100ms)
|
|
284
397
|
if self.duplicate_detector.is_duplicate(event):
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
file=sys.stderr,
|
|
289
|
-
)
|
|
398
|
+
_log(
|
|
399
|
+
f"[{datetime.now(timezone.utc).isoformat()}] Skipping duplicate event: {event.get('hook_event_name', 'unknown')} (PID: {os.getpid()})"
|
|
400
|
+
)
|
|
290
401
|
# Still need to output continue for this invocation
|
|
291
402
|
if not _continue_sent:
|
|
292
403
|
self._continue_execution()
|
|
@@ -294,25 +405,19 @@ class ClaudeHookHandler:
|
|
|
294
405
|
return
|
|
295
406
|
|
|
296
407
|
# Debug: Log that we're processing an event
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
file=sys.stderr,
|
|
302
|
-
)
|
|
408
|
+
hook_type = event.get("hook_event_name", "unknown")
|
|
409
|
+
_log(
|
|
410
|
+
f"\n[{datetime.now(timezone.utc).isoformat()}] Processing hook event: {hook_type} (PID: {os.getpid()})"
|
|
411
|
+
)
|
|
303
412
|
|
|
304
413
|
# Perform periodic cleanup if needed
|
|
305
414
|
if self.state_manager.increment_events_processed():
|
|
306
415
|
self.state_manager.cleanup_old_entries()
|
|
307
416
|
# Also cleanup old correlation files
|
|
308
|
-
from .correlation_manager import CorrelationManager
|
|
309
|
-
|
|
310
417
|
CorrelationManager.cleanup_old()
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
file=sys.stderr,
|
|
315
|
-
)
|
|
418
|
+
_log(
|
|
419
|
+
f"🧹 Performed cleanup after {self.state_manager.events_processed} events"
|
|
420
|
+
)
|
|
316
421
|
|
|
317
422
|
# Route event to appropriate handler
|
|
318
423
|
# Handlers can optionally return modified input for PreToolUse events
|
|
@@ -352,8 +457,7 @@ class ClaudeHookHandler:
|
|
|
352
457
|
ready, _, _ = select.select([sys.stdin], [], [], 1.0)
|
|
353
458
|
if not ready:
|
|
354
459
|
# No data available within timeout
|
|
355
|
-
|
|
356
|
-
print("No hook event data received within timeout", file=sys.stderr)
|
|
460
|
+
_log("No hook event data received within timeout")
|
|
357
461
|
return None
|
|
358
462
|
|
|
359
463
|
# Data is available, read it
|
|
@@ -364,21 +468,16 @@ class ClaudeHookHandler:
|
|
|
364
468
|
|
|
365
469
|
parsed = json.loads(event_data)
|
|
366
470
|
# 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)
|
|
471
|
+
_log(f"Received event with keys: {list(parsed.keys())}")
|
|
472
|
+
for key in ["hook_event_name", "event", "type", "event_type"]:
|
|
473
|
+
if key in parsed:
|
|
474
|
+
_log(f" {key} = '{parsed[key]}'")
|
|
374
475
|
return parsed
|
|
375
476
|
except (json.JSONDecodeError, ValueError) as e:
|
|
376
|
-
|
|
377
|
-
print(f"Failed to parse hook event: {e}", file=sys.stderr)
|
|
477
|
+
_log(f"Failed to parse hook event: {e}")
|
|
378
478
|
return None
|
|
379
479
|
except Exception as e:
|
|
380
|
-
|
|
381
|
-
print(f"Error reading hook event: {e}", file=sys.stderr)
|
|
480
|
+
_log(f"Error reading hook event: {e}")
|
|
382
481
|
return None
|
|
383
482
|
|
|
384
483
|
def _route_event(self, event: dict) -> Optional[dict]:
|
|
@@ -407,9 +506,9 @@ class ClaudeHookHandler:
|
|
|
407
506
|
)
|
|
408
507
|
|
|
409
508
|
# Log the actual event structure for debugging
|
|
410
|
-
if
|
|
411
|
-
|
|
412
|
-
|
|
509
|
+
if hook_type == "unknown":
|
|
510
|
+
_log(f"Unknown event format, keys: {list(event.keys())}")
|
|
511
|
+
_log(f"Event sample: {str(event)[:200]}")
|
|
413
512
|
|
|
414
513
|
# Map event types to handlers
|
|
415
514
|
event_handlers = {
|
|
@@ -419,7 +518,7 @@ class ClaudeHookHandler:
|
|
|
419
518
|
"Notification": self.event_handlers.handle_notification_fast,
|
|
420
519
|
"Stop": self.event_handlers.handle_stop_fast,
|
|
421
520
|
"SubagentStop": self.event_handlers.handle_subagent_stop_fast,
|
|
422
|
-
"SubagentStart": self.event_handlers.
|
|
521
|
+
"SubagentStart": self.event_handlers.handle_subagent_start_fast,
|
|
423
522
|
"SessionStart": self.event_handlers.handle_session_start_fast,
|
|
424
523
|
"AssistantResponse": self.event_handlers.handle_assistant_response,
|
|
425
524
|
}
|
|
@@ -445,8 +544,7 @@ class ClaudeHookHandler:
|
|
|
445
544
|
except Exception as e:
|
|
446
545
|
error_message = str(e)
|
|
447
546
|
return_value = None
|
|
448
|
-
|
|
449
|
-
print(f"Error handling {hook_type}: {e}", file=sys.stderr)
|
|
547
|
+
_log(f"Error handling {hook_type}: {e}")
|
|
450
548
|
finally:
|
|
451
549
|
# Calculate duration
|
|
452
550
|
duration_ms = int((time.time() - start_time) * 1000)
|
|
@@ -480,9 +578,12 @@ class ClaudeHookHandler:
|
|
|
480
578
|
"""
|
|
481
579
|
if modified_input is not None:
|
|
482
580
|
# Claude Code v2.0.30+ supports modifying PreToolUse tool inputs
|
|
483
|
-
print(
|
|
581
|
+
print(
|
|
582
|
+
json.dumps({"continue": True, "tool_input": modified_input}),
|
|
583
|
+
flush=True,
|
|
584
|
+
)
|
|
484
585
|
else:
|
|
485
|
-
print(json.dumps({"
|
|
586
|
+
print(json.dumps({"continue": True}), flush=True)
|
|
486
587
|
|
|
487
588
|
# Delegation methods for compatibility with event_handlers
|
|
488
589
|
def _track_delegation(self, session_id: str, agent_type: str, request_data=None):
|
|
@@ -535,13 +636,15 @@ class ClaudeHookHandler:
|
|
|
535
636
|
# Build hook execution data
|
|
536
637
|
hook_data = {
|
|
537
638
|
"hook_name": hook_type,
|
|
538
|
-
"hook_type": hook_type,
|
|
639
|
+
"hook_type": hook_type, # Actual hook type (PreToolUse, UserPromptSubmit, etc.)
|
|
640
|
+
"hook_event_type": hook_type, # Additional field for clarity
|
|
539
641
|
"session_id": session_id,
|
|
540
642
|
"working_directory": working_dir,
|
|
541
643
|
"success": success,
|
|
542
644
|
"duration_ms": duration_ms,
|
|
543
645
|
"result_summary": summary,
|
|
544
646
|
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
647
|
+
"source": "claude_hook_handler", # Explicit source identification
|
|
545
648
|
}
|
|
546
649
|
|
|
547
650
|
# Add error information if present
|
|
@@ -566,11 +669,9 @@ class ClaudeHookHandler:
|
|
|
566
669
|
# This uses the existing event infrastructure
|
|
567
670
|
self._emit_socketio_event("", "hook_execution", hook_data)
|
|
568
671
|
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
file=sys.stderr,
|
|
573
|
-
)
|
|
672
|
+
_log(
|
|
673
|
+
f"📊 Hook execution event: {hook_type} - {duration_ms}ms - {'✅' if success else '❌'}"
|
|
674
|
+
)
|
|
574
675
|
|
|
575
676
|
def _generate_hook_summary(self, hook_type: str, event: dict, success: bool) -> str:
|
|
576
677
|
"""Generate a human-readable summary of what the hook did.
|
|
@@ -628,12 +729,19 @@ class ClaudeHookHandler:
|
|
|
628
729
|
|
|
629
730
|
def __del__(self):
|
|
630
731
|
"""Cleanup on handler destruction."""
|
|
732
|
+
# Finalize any active auto-pause session
|
|
733
|
+
if hasattr(self, "auto_pause_handler") and self.auto_pause_handler:
|
|
734
|
+
try:
|
|
735
|
+
self.auto_pause_handler.on_session_end()
|
|
736
|
+
except Exception:
|
|
737
|
+
pass # nosec B110 - Intentionally ignore cleanup errors during handler destruction
|
|
738
|
+
|
|
631
739
|
# Clean up connection manager if it exists
|
|
632
740
|
if hasattr(self, "connection_manager") and self.connection_manager:
|
|
633
741
|
try:
|
|
634
742
|
self.connection_manager.cleanup()
|
|
635
743
|
except Exception:
|
|
636
|
-
pass #
|
|
744
|
+
pass # nosec B110 - Intentionally ignore cleanup errors during handler destruction
|
|
637
745
|
|
|
638
746
|
|
|
639
747
|
def main():
|
|
@@ -646,25 +754,18 @@ def main():
|
|
|
646
754
|
if not is_compatible:
|
|
647
755
|
# Version incompatible - just continue without processing
|
|
648
756
|
# This prevents errors on older Claude Code versions
|
|
649
|
-
if
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
file=sys.stderr,
|
|
653
|
-
)
|
|
654
|
-
print(json.dumps({"action": "continue"}))
|
|
757
|
+
if version:
|
|
758
|
+
_log(f"Skipping hook processing due to version incompatibility ({version})")
|
|
759
|
+
print(json.dumps({"continue": True}), flush=True)
|
|
655
760
|
sys.exit(0)
|
|
656
761
|
|
|
657
762
|
def cleanup_handler(signum=None, frame=None):
|
|
658
763
|
"""Cleanup handler for signals and exit."""
|
|
659
764
|
nonlocal _continue_printed
|
|
660
|
-
|
|
661
|
-
print(
|
|
662
|
-
f"Hook handler cleanup (pid: {os.getpid()}, signal: {signum})",
|
|
663
|
-
file=sys.stderr,
|
|
664
|
-
)
|
|
765
|
+
_log(f"Hook handler cleanup (pid: {os.getpid()}, signal: {signum})")
|
|
665
766
|
# Only output continue if we haven't already (i.e., if interrupted by signal)
|
|
666
767
|
if signum is not None and not _continue_printed:
|
|
667
|
-
print(json.dumps({"
|
|
768
|
+
print(json.dumps({"continue": True}), flush=True)
|
|
668
769
|
_continue_printed = True
|
|
669
770
|
sys.exit(0)
|
|
670
771
|
|
|
@@ -678,15 +779,10 @@ def main():
|
|
|
678
779
|
with _handler_lock:
|
|
679
780
|
if _global_handler is None:
|
|
680
781
|
_global_handler = ClaudeHookHandler()
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
)
|
|
686
|
-
elif DEBUG:
|
|
687
|
-
print(
|
|
688
|
-
f"♻️ Reusing existing ClaudeHookHandler singleton (pid: {os.getpid()})",
|
|
689
|
-
file=sys.stderr,
|
|
782
|
+
_log(f"✅ Created new ClaudeHookHandler singleton (pid: {os.getpid()})")
|
|
783
|
+
else:
|
|
784
|
+
_log(
|
|
785
|
+
f"♻️ Reusing existing ClaudeHookHandler singleton (pid: {os.getpid()})"
|
|
690
786
|
)
|
|
691
787
|
|
|
692
788
|
handler = _global_handler
|
|
@@ -702,13 +798,17 @@ def main():
|
|
|
702
798
|
except Exception as e:
|
|
703
799
|
# Only output continue if not already printed
|
|
704
800
|
if not _continue_printed:
|
|
705
|
-
print(json.dumps({"
|
|
801
|
+
print(json.dumps({"continue": True}), flush=True)
|
|
706
802
|
_continue_printed = True
|
|
707
803
|
# Log error for debugging
|
|
708
|
-
|
|
709
|
-
print(f"Hook handler error: {e}", file=sys.stderr)
|
|
804
|
+
_log(f"Hook handler error: {e}")
|
|
710
805
|
sys.exit(0) # Exit cleanly even on error
|
|
711
806
|
|
|
712
807
|
|
|
713
808
|
if __name__ == "__main__":
|
|
714
|
-
|
|
809
|
+
try:
|
|
810
|
+
main()
|
|
811
|
+
except Exception:
|
|
812
|
+
# Catastrophic failure (import error, etc.) - always output valid JSON
|
|
813
|
+
print(json.dumps({"continue": True}), flush=True)
|
|
814
|
+
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 $?
|