claude-mpm 5.4.41__py3-none-any.whl → 5.6.72__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/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/PM_INSTRUCTIONS.md +161 -298
- 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/__init__.py +5 -1
- claude_mpm/cli/commands/agents.py +2 -4
- claude_mpm/cli/commands/agents_reconcile.py +197 -0
- claude_mpm/cli/commands/autotodos.py +566 -0
- claude_mpm/cli/commands/commander.py +216 -0
- claude_mpm/cli/commands/configure.py +620 -21
- claude_mpm/cli/commands/configure_agent_display.py +3 -1
- 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 +15 -8
- claude_mpm/cli/commands/oauth.py +481 -0
- claude_mpm/cli/commands/profile.py +9 -10
- 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 +129 -16
- claude_mpm/cli/helpers.py +1 -1
- claude_mpm/cli/interactive/__init__.py +10 -0
- claude_mpm/cli/interactive/agent_wizard.py +30 -50
- 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 +89 -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/profile_parser.py +0 -1
- 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 +662 -524
- claude_mpm/cli/startup_display.py +76 -7
- 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 +149 -0
- claude_mpm/commander/chat/commands.py +122 -0
- claude_mpm/commander/chat/repl.py +1821 -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 +865 -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 +6 -0
- claude_mpm/core/claude_runner.py +154 -2
- 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 +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 +3 -1
- 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_config.py +54 -8
- claude_mpm/core/unified_paths.py +95 -90
- 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/{uj46x2Wr.js → BSNlmTZj.js} +1 -1
- 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/{N4qtv3Hx.js → DR8nis88.js} +2 -2
- 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/{DjhvlsAc.js → NqQ1dWOy.js} +1 -1
- 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.CAGBuiOw.js → 0.RgBboRvH.js} +1 -1
- 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 -1
- claude_mpm/dashboard/static/svelte-build/index.html +11 -11
- 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__/auto_pause_handler.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/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/__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__/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 +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/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 +224 -4
- 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/agent_discovery_service.py +3 -1
- claude_mpm/services/agents/deployment/agent_format_converter.py +25 -13
- claude_mpm/services/agents/deployment/agent_template_builder.py +37 -17
- 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 +36 -8
- claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +50 -26
- claude_mpm/services/agents/deployment/startup_reconciliation.py +138 -0
- claude_mpm/services/agents/git_source_manager.py +21 -2
- 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/agents/sources/git_source_sync_service.py +116 -5
- claude_mpm/services/agents/startup_sync.py +5 -2
- 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 -3
- claude_mpm/services/monitor/server.py +111 -16
- claude_mpm/services/pm_skills_deployer.py +302 -94
- claude_mpm/services/profile_manager.py +10 -4
- claude_mpm/services/skills/git_skill_source_manager.py +192 -29
- 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/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/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 +29 -23
- claude_mpm/templates/.pre-commit-config.yaml +112 -0
- claude_mpm/utils/agent_dependency_loader.py +103 -4
- claude_mpm/utils/robust_installer.py +45 -24
- claude_mpm-5.6.72.dist-info/METADATA +416 -0
- {claude_mpm-5.4.41.dist-info → claude_mpm-5.6.72.dist-info}/RECORD +477 -159
- {claude_mpm-5.4.41.dist-info → claude_mpm-5.6.72.dist-info}/WHEEL +1 -1
- {claude_mpm-5.4.41.dist-info → claude_mpm-5.6.72.dist-info}/entry_points.txt +2 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.B_FtCwCQ.css +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.Cl_eSA4x.css +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BgChzWQ1.js +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CIXEwuWe.js +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CWc5urbQ.js +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DMkZpdF2.js +0 -2
- claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/app.DTL5mJO-.js +0 -2
- claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.DzuEhzqh.js +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/1.DFLC8jdE.js +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.DPvEihJJ.js +0 -10
- claude_mpm/hooks/claude_hooks/__pycache__/installer.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager.cpython-311.pyc +0 -0
- claude_mpm-5.4.41.dist-info/METADATA +0 -998
- {claude_mpm-5.4.41.dist-info → claude_mpm-5.6.72.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-5.4.41.dist-info → claude_mpm-5.6.72.dist-info}/licenses/LICENSE-FAQ.md +0 -0
- {claude_mpm-5.4.41.dist-info → claude_mpm-5.6.72.dist-info}/top_level.txt +0 -0
|
@@ -3,16 +3,30 @@
|
|
|
3
3
|
|
|
4
4
|
This module provides individual event handlers for different types of
|
|
5
5
|
Claude Code hook events.
|
|
6
|
+
|
|
7
|
+
Supports Dependency Injection:
|
|
8
|
+
- Optional services can be passed via constructor
|
|
9
|
+
- Lazy loading fallback for services not provided
|
|
10
|
+
- Eliminates runtime imports inside methods
|
|
6
11
|
"""
|
|
7
12
|
|
|
13
|
+
import asyncio
|
|
8
14
|
import os
|
|
9
15
|
import re
|
|
10
|
-
import subprocess
|
|
11
|
-
import sys
|
|
16
|
+
import subprocess # nosec B404 - subprocess used for safe claude CLI version checking only
|
|
12
17
|
import uuid
|
|
13
18
|
from datetime import datetime, timezone
|
|
14
19
|
from pathlib import Path
|
|
15
|
-
from typing import Optional
|
|
20
|
+
from typing import Any, Optional
|
|
21
|
+
|
|
22
|
+
# Import _log helper to avoid stderr writes (which cause hook errors)
|
|
23
|
+
try:
|
|
24
|
+
from .hook_handler import _log
|
|
25
|
+
except ImportError:
|
|
26
|
+
# Fallback for direct execution
|
|
27
|
+
def _log(message: str) -> None:
|
|
28
|
+
"""Fallback logger when hook_handler not available."""
|
|
29
|
+
|
|
16
30
|
|
|
17
31
|
# Import tool analysis with fallback for direct execution
|
|
18
32
|
try:
|
|
@@ -34,8 +48,15 @@ except ImportError:
|
|
|
34
48
|
extract_tool_results,
|
|
35
49
|
)
|
|
36
50
|
|
|
37
|
-
#
|
|
38
|
-
|
|
51
|
+
# Import correlation manager with fallback for direct execution
|
|
52
|
+
# WHY at top level: Runtime relative imports fail with "no known parent package" error
|
|
53
|
+
try:
|
|
54
|
+
from .correlation_manager import CorrelationManager
|
|
55
|
+
except ImportError:
|
|
56
|
+
from correlation_manager import CorrelationManager
|
|
57
|
+
|
|
58
|
+
# Debug mode - MUST match hook_handler.py default (false) to prevent stderr writes
|
|
59
|
+
DEBUG = os.environ.get("CLAUDE_MPM_HOOK_DEBUG", "false").lower() == "true"
|
|
39
60
|
|
|
40
61
|
# Import constants for configuration
|
|
41
62
|
try:
|
|
@@ -46,13 +67,152 @@ except ImportError:
|
|
|
46
67
|
QUICK_TIMEOUT = 2.0
|
|
47
68
|
|
|
48
69
|
|
|
70
|
+
# ============================================================================
|
|
71
|
+
# Optional Dependencies - loaded once at module level for DI
|
|
72
|
+
# ============================================================================
|
|
73
|
+
|
|
74
|
+
# Log manager (for agent prompt logging)
|
|
75
|
+
_log_manager: Optional[Any] = None
|
|
76
|
+
_log_manager_loaded = False
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def _get_log_manager() -> Optional[Any]:
|
|
80
|
+
"""Get log manager with lazy loading."""
|
|
81
|
+
global _log_manager, _log_manager_loaded
|
|
82
|
+
if not _log_manager_loaded:
|
|
83
|
+
try:
|
|
84
|
+
from claude_mpm.core.log_manager import get_log_manager
|
|
85
|
+
|
|
86
|
+
_log_manager = get_log_manager()
|
|
87
|
+
except ImportError:
|
|
88
|
+
_log_manager = None
|
|
89
|
+
_log_manager_loaded = True
|
|
90
|
+
return _log_manager
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
# Config service (for autotodos configuration)
|
|
94
|
+
_config: Optional[Any] = None
|
|
95
|
+
_config_loaded = False
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def _get_config() -> Optional[Any]:
|
|
99
|
+
"""Get Config with lazy loading."""
|
|
100
|
+
global _config, _config_loaded
|
|
101
|
+
if not _config_loaded:
|
|
102
|
+
try:
|
|
103
|
+
from claude_mpm.core.config import Config
|
|
104
|
+
|
|
105
|
+
_config = Config()
|
|
106
|
+
except ImportError:
|
|
107
|
+
_config = None
|
|
108
|
+
_config_loaded = True
|
|
109
|
+
return _config
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
# Delegation detector (for anti-pattern detection)
|
|
113
|
+
_delegation_detector: Optional[Any] = None
|
|
114
|
+
_delegation_detector_loaded = False
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def _get_delegation_detector_service() -> Optional[Any]:
|
|
118
|
+
"""Get delegation detector with lazy loading."""
|
|
119
|
+
global _delegation_detector, _delegation_detector_loaded
|
|
120
|
+
if not _delegation_detector_loaded:
|
|
121
|
+
try:
|
|
122
|
+
from claude_mpm.services.delegation_detector import get_delegation_detector
|
|
123
|
+
|
|
124
|
+
_delegation_detector = get_delegation_detector()
|
|
125
|
+
except ImportError:
|
|
126
|
+
_delegation_detector = None
|
|
127
|
+
_delegation_detector_loaded = True
|
|
128
|
+
return _delegation_detector
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
# Event log (for PM violation logging)
|
|
132
|
+
_event_log: Optional[Any] = None
|
|
133
|
+
_event_log_loaded = False
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def _get_event_log_service() -> Optional[Any]:
|
|
137
|
+
"""Get event log with lazy loading."""
|
|
138
|
+
global _event_log, _event_log_loaded
|
|
139
|
+
if not _event_log_loaded:
|
|
140
|
+
try:
|
|
141
|
+
from claude_mpm.services.event_log import get_event_log
|
|
142
|
+
|
|
143
|
+
_event_log = get_event_log()
|
|
144
|
+
except ImportError:
|
|
145
|
+
_event_log = None
|
|
146
|
+
_event_log_loaded = True
|
|
147
|
+
return _event_log
|
|
148
|
+
|
|
149
|
+
|
|
49
150
|
class EventHandlers:
|
|
50
|
-
"""Collection of event handlers for different Claude Code hook events.
|
|
151
|
+
"""Collection of event handlers for different Claude Code hook events.
|
|
152
|
+
|
|
153
|
+
Supports dependency injection for optional services:
|
|
154
|
+
- log_manager: For agent prompt logging
|
|
155
|
+
- config: For autotodos configuration
|
|
156
|
+
- delegation_detector: For anti-pattern detection
|
|
157
|
+
- event_log: For PM violation logging
|
|
51
158
|
|
|
52
|
-
|
|
53
|
-
|
|
159
|
+
If services are not provided, they are loaded lazily on first use.
|
|
160
|
+
"""
|
|
161
|
+
|
|
162
|
+
def __init__(
|
|
163
|
+
self,
|
|
164
|
+
hook_handler,
|
|
165
|
+
*,
|
|
166
|
+
log_manager: Optional[Any] = None,
|
|
167
|
+
config: Optional[Any] = None,
|
|
168
|
+
delegation_detector: Optional[Any] = None,
|
|
169
|
+
event_log: Optional[Any] = None,
|
|
170
|
+
):
|
|
171
|
+
"""Initialize with reference to the main hook handler and optional services.
|
|
172
|
+
|
|
173
|
+
Args:
|
|
174
|
+
hook_handler: The main ClaudeHookHandler instance
|
|
175
|
+
log_manager: Optional LogManager for agent prompt logging
|
|
176
|
+
config: Optional Config for autotodos configuration
|
|
177
|
+
delegation_detector: Optional DelegationDetector for anti-pattern detection
|
|
178
|
+
event_log: Optional EventLog for PM violation logging
|
|
179
|
+
"""
|
|
54
180
|
self.hook_handler = hook_handler
|
|
55
181
|
|
|
182
|
+
# Store injected services (None means use lazy loading)
|
|
183
|
+
self._log_manager = log_manager
|
|
184
|
+
self._config = config
|
|
185
|
+
self._delegation_detector = delegation_detector
|
|
186
|
+
self._event_log = event_log
|
|
187
|
+
|
|
188
|
+
@property
|
|
189
|
+
def log_manager(self) -> Optional[Any]:
|
|
190
|
+
"""Get log manager (injected or lazy loaded)."""
|
|
191
|
+
if self._log_manager is not None:
|
|
192
|
+
return self._log_manager
|
|
193
|
+
return _get_log_manager()
|
|
194
|
+
|
|
195
|
+
@property
|
|
196
|
+
def config(self) -> Optional[Any]:
|
|
197
|
+
"""Get config (injected or lazy loaded)."""
|
|
198
|
+
if self._config is not None:
|
|
199
|
+
return self._config
|
|
200
|
+
return _get_config()
|
|
201
|
+
|
|
202
|
+
@property
|
|
203
|
+
def delegation_detector(self) -> Optional[Any]:
|
|
204
|
+
"""Get delegation detector (injected or lazy loaded)."""
|
|
205
|
+
if self._delegation_detector is not None:
|
|
206
|
+
return self._delegation_detector
|
|
207
|
+
return _get_delegation_detector_service()
|
|
208
|
+
|
|
209
|
+
@property
|
|
210
|
+
def event_log(self) -> Optional[Any]:
|
|
211
|
+
"""Get event log (injected or lazy loaded)."""
|
|
212
|
+
if self._event_log is not None:
|
|
213
|
+
return self._event_log
|
|
214
|
+
return _get_event_log_service()
|
|
215
|
+
|
|
56
216
|
def handle_user_prompt_fast(self, event):
|
|
57
217
|
"""Handle user prompt with comprehensive data capture.
|
|
58
218
|
|
|
@@ -111,14 +271,22 @@ class EventHandlers:
|
|
|
111
271
|
"working_directory": working_dir,
|
|
112
272
|
}
|
|
113
273
|
if DEBUG:
|
|
114
|
-
|
|
115
|
-
f"Stored prompt for comprehensive tracking: session {session_id[:8]}..."
|
|
116
|
-
file=sys.stderr,
|
|
274
|
+
_log(
|
|
275
|
+
f"Stored prompt for comprehensive tracking: session {session_id[:8]}..."
|
|
117
276
|
)
|
|
118
|
-
except Exception:
|
|
277
|
+
except Exception: # nosec B110
|
|
119
278
|
# Response tracking is optional - silently continue if it fails
|
|
120
279
|
pass
|
|
121
280
|
|
|
281
|
+
# Record user message for auto-pause if active
|
|
282
|
+
auto_pause = getattr(self.hook_handler, "auto_pause_handler", None)
|
|
283
|
+
if auto_pause and auto_pause.is_pause_active():
|
|
284
|
+
try:
|
|
285
|
+
auto_pause.on_user_message(prompt)
|
|
286
|
+
except Exception as e:
|
|
287
|
+
if DEBUG:
|
|
288
|
+
_log(f"Auto-pause user message recording error: {e}")
|
|
289
|
+
|
|
122
290
|
# Emit normalized event (namespace no longer needed with normalized events)
|
|
123
291
|
self.hook_handler._emit_socketio_event("", "user_prompt", prompt_data)
|
|
124
292
|
|
|
@@ -133,11 +301,8 @@ class EventHandlers:
|
|
|
133
301
|
# Enhanced debug logging for session correlation
|
|
134
302
|
session_id = event.get("session_id", "")
|
|
135
303
|
if DEBUG:
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
file=sys.stderr,
|
|
139
|
-
)
|
|
140
|
-
print(f" - event keys: {list(event.keys())}", file=sys.stderr)
|
|
304
|
+
_log(f" - session_id: {session_id[:16] if session_id else 'None'}...")
|
|
305
|
+
_log(f" - event keys: {list(event.keys())}")
|
|
141
306
|
|
|
142
307
|
tool_name = event.get("tool_name", "")
|
|
143
308
|
tool_input = event.get("tool_input", {})
|
|
@@ -176,21 +341,43 @@ class EventHandlers:
|
|
|
176
341
|
|
|
177
342
|
# Store tool_call_id using CorrelationManager for cross-process retrieval
|
|
178
343
|
if session_id:
|
|
179
|
-
from .correlation_manager import CorrelationManager
|
|
180
|
-
|
|
181
344
|
CorrelationManager.store(session_id, tool_call_id, tool_name)
|
|
182
345
|
if DEBUG:
|
|
183
|
-
|
|
184
|
-
f" - Generated tool_call_id: {tool_call_id[:8]}... for session {session_id[:8]}..."
|
|
185
|
-
file=sys.stderr,
|
|
346
|
+
_log(
|
|
347
|
+
f" - Generated tool_call_id: {tool_call_id[:8]}... for session {session_id[:8]}..."
|
|
186
348
|
)
|
|
187
349
|
|
|
188
350
|
# Add delegation-specific data if this is a Task tool
|
|
189
351
|
if tool_name == "Task" and isinstance(tool_input, dict):
|
|
190
352
|
self._handle_task_delegation(tool_input, pre_tool_data, session_id)
|
|
191
353
|
|
|
354
|
+
# Record tool call for auto-pause if active
|
|
355
|
+
auto_pause = getattr(self.hook_handler, "auto_pause_handler", None)
|
|
356
|
+
if auto_pause and auto_pause.is_pause_active():
|
|
357
|
+
try:
|
|
358
|
+
auto_pause.on_tool_call(tool_name, tool_input)
|
|
359
|
+
except Exception as e:
|
|
360
|
+
if DEBUG:
|
|
361
|
+
_log(f"Auto-pause tool recording error: {e}")
|
|
362
|
+
|
|
192
363
|
self.hook_handler._emit_socketio_event("", "pre_tool", pre_tool_data)
|
|
193
364
|
|
|
365
|
+
# Handle TodoWrite specially - emit dedicated todo_updated event
|
|
366
|
+
# WHY: Frontend expects todo_updated events for dashboard display
|
|
367
|
+
# The broadcaster.todo_updated() method exists but was never called
|
|
368
|
+
if tool_name == "TodoWrite" and tool_params.get("todos"):
|
|
369
|
+
todo_data = {
|
|
370
|
+
"todos": tool_params["todos"],
|
|
371
|
+
"total_count": len(tool_params["todos"]),
|
|
372
|
+
"session_id": session_id,
|
|
373
|
+
"timestamp": timestamp,
|
|
374
|
+
}
|
|
375
|
+
self.hook_handler._emit_socketio_event("", "todo_updated", todo_data)
|
|
376
|
+
if DEBUG:
|
|
377
|
+
_log(
|
|
378
|
+
f" - Emitted todo_updated event with {len(tool_params['todos'])} todos for session {session_id[:8]}..."
|
|
379
|
+
)
|
|
380
|
+
|
|
194
381
|
def _handle_task_delegation(
|
|
195
382
|
self, tool_input: dict, pre_tool_data: dict, session_id: str
|
|
196
383
|
):
|
|
@@ -229,12 +416,9 @@ class EventHandlers:
|
|
|
229
416
|
|
|
230
417
|
# Track this delegation for SubagentStop correlation and response tracking
|
|
231
418
|
if DEBUG:
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
)
|
|
236
|
-
print(f" - agent_type: {agent_type}", file=sys.stderr)
|
|
237
|
-
print(f" - raw_agent_type: {raw_agent_type}", file=sys.stderr)
|
|
419
|
+
_log(f" - session_id: {session_id[:16] if session_id else 'None'}...")
|
|
420
|
+
_log(f" - agent_type: {agent_type}")
|
|
421
|
+
_log(f" - raw_agent_type: {raw_agent_type}")
|
|
238
422
|
|
|
239
423
|
if session_id and agent_type != "unknown":
|
|
240
424
|
# Prepare request data for response tracking correlation
|
|
@@ -246,24 +430,17 @@ class EventHandlers:
|
|
|
246
430
|
self.hook_handler._track_delegation(session_id, agent_type, request_data)
|
|
247
431
|
|
|
248
432
|
if DEBUG:
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
f" - Request data keys: {list(request_data.keys())}",
|
|
252
|
-
file=sys.stderr,
|
|
253
|
-
)
|
|
433
|
+
_log(" - Delegation tracked successfully")
|
|
434
|
+
_log(f" - Request data keys: {list(request_data.keys())}")
|
|
254
435
|
delegation_requests = getattr(
|
|
255
436
|
self.hook_handler, "delegation_requests", {}
|
|
256
437
|
)
|
|
257
|
-
|
|
258
|
-
f" - delegation_requests size: {len(delegation_requests)}",
|
|
259
|
-
file=sys.stderr,
|
|
260
|
-
)
|
|
438
|
+
_log(f" - delegation_requests size: {len(delegation_requests)}")
|
|
261
439
|
|
|
262
440
|
# Log important delegations for debugging
|
|
263
441
|
if DEBUG or agent_type in ["research", "engineer", "qa", "documentation"]:
|
|
264
|
-
|
|
265
|
-
f"Hook handler: Task delegation started - agent: '{agent_type}', session: '{session_id}'"
|
|
266
|
-
file=sys.stderr,
|
|
442
|
+
_log(
|
|
443
|
+
f"Hook handler: Task delegation started - agent: '{agent_type}', session: '{session_id}'"
|
|
267
444
|
)
|
|
268
445
|
|
|
269
446
|
# Trigger memory pre-delegation hook
|
|
@@ -271,7 +448,7 @@ class EventHandlers:
|
|
|
271
448
|
mhm = getattr(self.hook_handler, "memory_hook_manager", None)
|
|
272
449
|
if mhm and hasattr(mhm, "trigger_pre_delegation_hook"):
|
|
273
450
|
mhm.trigger_pre_delegation_hook(agent_type, tool_input, session_id)
|
|
274
|
-
except Exception:
|
|
451
|
+
except Exception: # nosec B110
|
|
275
452
|
# Memory hooks are optional
|
|
276
453
|
pass
|
|
277
454
|
|
|
@@ -290,53 +467,50 @@ class EventHandlers:
|
|
|
290
467
|
)
|
|
291
468
|
|
|
292
469
|
# Log agent prompt if LogManager is available
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
314
|
-
},
|
|
315
|
-
}
|
|
470
|
+
# Uses injected log_manager or lazy-loaded module-level instance
|
|
471
|
+
log_manager = self.log_manager
|
|
472
|
+
if log_manager is not None:
|
|
473
|
+
try:
|
|
474
|
+
# Prepare prompt content
|
|
475
|
+
prompt_content = tool_input.get("prompt", "")
|
|
476
|
+
if not prompt_content:
|
|
477
|
+
prompt_content = tool_input.get("description", "")
|
|
478
|
+
|
|
479
|
+
if prompt_content:
|
|
480
|
+
# Prepare metadata
|
|
481
|
+
metadata = {
|
|
482
|
+
"agent_type": agent_type,
|
|
483
|
+
"agent_id": f"{agent_type}_{session_id}",
|
|
484
|
+
"session_id": session_id,
|
|
485
|
+
"delegation_context": {
|
|
486
|
+
"description": tool_input.get("description", ""),
|
|
487
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
488
|
+
},
|
|
489
|
+
}
|
|
316
490
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
491
|
+
# Log the agent prompt asynchronously
|
|
492
|
+
try:
|
|
493
|
+
loop = asyncio.get_running_loop()
|
|
494
|
+
_task = asyncio.create_task(
|
|
495
|
+
log_manager.log_prompt(
|
|
496
|
+
f"agent_{agent_type}", prompt_content, metadata
|
|
497
|
+
)
|
|
498
|
+
) # Fire-and-forget logging (ephemeral hook process)
|
|
499
|
+
except RuntimeError:
|
|
500
|
+
# No running loop, create one
|
|
501
|
+
loop = asyncio.new_event_loop()
|
|
502
|
+
asyncio.set_event_loop(loop)
|
|
503
|
+
loop.run_until_complete(
|
|
504
|
+
log_manager.log_prompt(
|
|
505
|
+
f"agent_{agent_type}", prompt_content, metadata
|
|
506
|
+
)
|
|
332
507
|
)
|
|
333
|
-
)
|
|
334
508
|
|
|
509
|
+
if DEBUG:
|
|
510
|
+
_log(f" - Agent prompt logged for {agent_type}")
|
|
511
|
+
except Exception as e:
|
|
335
512
|
if DEBUG:
|
|
336
|
-
|
|
337
|
-
except Exception as e:
|
|
338
|
-
if DEBUG:
|
|
339
|
-
print(f" - Could not log agent prompt: {e}", file=sys.stderr)
|
|
513
|
+
_log(f" - Could not log agent prompt: {e}")
|
|
340
514
|
|
|
341
515
|
def _get_git_branch(self, working_dir: Optional[str] = None) -> str:
|
|
342
516
|
"""Get git branch for the given directory with caching."""
|
|
@@ -364,7 +538,7 @@ class EventHandlers:
|
|
|
364
538
|
os.chdir(working_dir)
|
|
365
539
|
|
|
366
540
|
# Run git command to get current branch
|
|
367
|
-
result = subprocess.run(
|
|
541
|
+
result = subprocess.run( # nosec B603 B607
|
|
368
542
|
["git", "branch", "--show-current"],
|
|
369
543
|
capture_output=True,
|
|
370
544
|
text=True,
|
|
@@ -420,13 +594,10 @@ class EventHandlers:
|
|
|
420
594
|
git_branch = self._get_git_branch(working_dir) if working_dir else "Unknown"
|
|
421
595
|
|
|
422
596
|
# Retrieve tool_call_id using CorrelationManager for cross-process correlation
|
|
423
|
-
from .correlation_manager import CorrelationManager
|
|
424
|
-
|
|
425
597
|
tool_call_id = CorrelationManager.retrieve(session_id) if session_id else None
|
|
426
598
|
if DEBUG and tool_call_id:
|
|
427
|
-
|
|
428
|
-
f" - Retrieved tool_call_id: {tool_call_id[:8]}... for session {session_id[:8]}..."
|
|
429
|
-
file=sys.stderr,
|
|
599
|
+
_log(
|
|
600
|
+
f" - Retrieved tool_call_id: {tool_call_id[:8]}... for session {session_id[:8]}..."
|
|
430
601
|
)
|
|
431
602
|
|
|
432
603
|
post_tool_data = {
|
|
@@ -474,7 +645,7 @@ class EventHandlers:
|
|
|
474
645
|
mhm = getattr(self.hook_handler, "memory_hook_manager", None)
|
|
475
646
|
if mhm and hasattr(mhm, "trigger_post_delegation_hook"):
|
|
476
647
|
mhm.trigger_post_delegation_hook(agent_type, event, session_id)
|
|
477
|
-
except Exception:
|
|
648
|
+
except Exception: # nosec B110
|
|
478
649
|
# Memory hooks are optional
|
|
479
650
|
pass
|
|
480
651
|
|
|
@@ -488,7 +659,7 @@ class EventHandlers:
|
|
|
488
659
|
rtm.track_agent_response(
|
|
489
660
|
session_id, agent_type, event, delegation_requests
|
|
490
661
|
)
|
|
491
|
-
except Exception:
|
|
662
|
+
except Exception: # nosec B110
|
|
492
663
|
# Response tracking is optional
|
|
493
664
|
pass
|
|
494
665
|
|
|
@@ -550,13 +721,60 @@ class EventHandlers:
|
|
|
550
721
|
if DEBUG:
|
|
551
722
|
self._log_stop_event_debug(event, session_id, metadata)
|
|
552
723
|
|
|
724
|
+
# Auto-pause integration (independent of response tracking)
|
|
725
|
+
# WHY HERE: Auto-pause must work even when response_tracking is disabled
|
|
726
|
+
# Extract usage data directly from event and trigger auto-pause if thresholds crossed
|
|
727
|
+
if "usage" in event:
|
|
728
|
+
auto_pause = getattr(self.hook_handler, "auto_pause_handler", None)
|
|
729
|
+
if auto_pause:
|
|
730
|
+
try:
|
|
731
|
+
usage_data = event["usage"]
|
|
732
|
+
metadata["usage"] = {
|
|
733
|
+
"input_tokens": usage_data.get("input_tokens", 0),
|
|
734
|
+
"output_tokens": usage_data.get("output_tokens", 0),
|
|
735
|
+
"cache_creation_input_tokens": usage_data.get(
|
|
736
|
+
"cache_creation_input_tokens", 0
|
|
737
|
+
),
|
|
738
|
+
"cache_read_input_tokens": usage_data.get(
|
|
739
|
+
"cache_read_input_tokens", 0
|
|
740
|
+
),
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
threshold_crossed = auto_pause.on_usage_update(metadata["usage"])
|
|
744
|
+
if threshold_crossed:
|
|
745
|
+
warning = auto_pause.emit_threshold_warning(threshold_crossed)
|
|
746
|
+
# CRITICAL: Never write to stderr unconditionally - causes hook errors
|
|
747
|
+
# Use _log() instead which only writes to file if DEBUG=true
|
|
748
|
+
_log(f"⚠️ Auto-pause threshold crossed: {warning}")
|
|
749
|
+
|
|
750
|
+
if DEBUG:
|
|
751
|
+
_log(
|
|
752
|
+
f" - Auto-pause threshold crossed: {threshold_crossed}"
|
|
753
|
+
)
|
|
754
|
+
except Exception as e:
|
|
755
|
+
if DEBUG:
|
|
756
|
+
_log(f"Auto-pause error in handle_stop_fast: {e}")
|
|
757
|
+
|
|
758
|
+
# Finalize pause session if active
|
|
759
|
+
try:
|
|
760
|
+
if auto_pause.is_pause_active():
|
|
761
|
+
session_file = auto_pause.on_session_end()
|
|
762
|
+
if session_file:
|
|
763
|
+
if DEBUG:
|
|
764
|
+
_log(
|
|
765
|
+
f"✅ Auto-pause session finalized: {session_file.name}"
|
|
766
|
+
)
|
|
767
|
+
except Exception as e:
|
|
768
|
+
if DEBUG:
|
|
769
|
+
_log(f"❌ Failed to finalize auto-pause session: {e}")
|
|
770
|
+
|
|
553
771
|
# Track response if enabled
|
|
554
772
|
try:
|
|
555
773
|
rtm = getattr(self.hook_handler, "response_tracking_manager", None)
|
|
556
774
|
if rtm and hasattr(rtm, "track_stop_response"):
|
|
557
775
|
pending_prompts = getattr(self.hook_handler, "pending_prompts", {})
|
|
558
776
|
rtm.track_stop_response(event, session_id, metadata, pending_prompts)
|
|
559
|
-
except Exception:
|
|
777
|
+
except Exception: # nosec B110
|
|
560
778
|
# Response tracking is optional
|
|
561
779
|
pass
|
|
562
780
|
|
|
@@ -590,24 +808,15 @@ class EventHandlers:
|
|
|
590
808
|
getattr(rtm, "response_tracker", None) is not None if rtm else False
|
|
591
809
|
)
|
|
592
810
|
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
)
|
|
597
|
-
print(
|
|
598
|
-
f" - response_tracker exists: {tracker_exists}",
|
|
599
|
-
file=sys.stderr,
|
|
600
|
-
)
|
|
601
|
-
except Exception:
|
|
811
|
+
_log(f" - response_tracking_enabled: {tracking_enabled}")
|
|
812
|
+
_log(f" - response_tracker exists: {tracker_exists}")
|
|
813
|
+
except Exception: # nosec B110
|
|
602
814
|
# If debug logging fails, just skip it
|
|
603
815
|
pass
|
|
604
816
|
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
)
|
|
609
|
-
print(f" - reason: {metadata['reason']}", file=sys.stderr)
|
|
610
|
-
print(f" - stop_type: {metadata['stop_type']}", file=sys.stderr)
|
|
817
|
+
_log(f" - session_id: {session_id[:8] if session_id else 'None'}...")
|
|
818
|
+
_log(f" - reason: {metadata['reason']}")
|
|
819
|
+
_log(f" - stop_type: {metadata['stop_type']}")
|
|
611
820
|
|
|
612
821
|
def _emit_stop_event(self, event: dict, session_id: str, metadata: dict) -> None:
|
|
613
822
|
"""Emit stop event data to Socket.IO."""
|
|
@@ -664,15 +873,12 @@ class EventHandlers:
|
|
|
664
873
|
try:
|
|
665
874
|
# Get the original request data (with fuzzy matching fallback)
|
|
666
875
|
delegation_requests = getattr(self.hook_handler, "delegation_requests", {})
|
|
667
|
-
request_info = delegation_requests.get(session_id)
|
|
876
|
+
request_info = delegation_requests.get(session_id) # nosec B113
|
|
668
877
|
|
|
669
878
|
# If exact match fails, try partial matching
|
|
670
879
|
if not request_info and session_id:
|
|
671
880
|
if DEBUG:
|
|
672
|
-
|
|
673
|
-
f" - Trying fuzzy match for session {session_id[:16]}...",
|
|
674
|
-
file=sys.stderr,
|
|
675
|
-
)
|
|
881
|
+
_log(f" - Trying fuzzy match for session {session_id[:16]}...")
|
|
676
882
|
# Try to find a session that matches the first 8-16 characters
|
|
677
883
|
for stored_sid in list(delegation_requests.keys()):
|
|
678
884
|
if (
|
|
@@ -685,11 +891,8 @@ class EventHandlers:
|
|
|
685
891
|
)
|
|
686
892
|
):
|
|
687
893
|
if DEBUG:
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
file=sys.stderr,
|
|
691
|
-
)
|
|
692
|
-
request_info = delegation_requests.get(stored_sid)
|
|
894
|
+
_log(f" - ✅ Fuzzy match found: {stored_sid[:16]}...")
|
|
895
|
+
request_info = delegation_requests.get(stored_sid) # nosec B113
|
|
693
896
|
# Update the key to use the current session_id for consistency
|
|
694
897
|
if request_info:
|
|
695
898
|
delegation_requests[session_id] = request_info
|
|
@@ -757,9 +960,8 @@ class EventHandlers:
|
|
|
757
960
|
)
|
|
758
961
|
|
|
759
962
|
if file_path and DEBUG:
|
|
760
|
-
|
|
761
|
-
f"✅ Tracked {agent_type} agent response on SubagentStop: {file_path.name}"
|
|
762
|
-
file=sys.stderr,
|
|
963
|
+
_log(
|
|
964
|
+
f"✅ Tracked {agent_type} agent response on SubagentStop: {file_path.name}"
|
|
763
965
|
)
|
|
764
966
|
|
|
765
967
|
# Clean up the request data
|
|
@@ -770,16 +972,13 @@ class EventHandlers:
|
|
|
770
972
|
del delegation_requests[session_id]
|
|
771
973
|
|
|
772
974
|
elif DEBUG:
|
|
773
|
-
|
|
774
|
-
f"No request data for SubagentStop session {session_id[:8]}..., agent: {agent_type}"
|
|
775
|
-
file=sys.stderr,
|
|
975
|
+
_log(
|
|
976
|
+
f"No request data for SubagentStop session {session_id[:8]}..., agent: {agent_type}"
|
|
776
977
|
)
|
|
777
978
|
|
|
778
979
|
except Exception as e:
|
|
779
980
|
if DEBUG:
|
|
780
|
-
|
|
781
|
-
f"❌ Failed to track response on SubagentStop: {e}", file=sys.stderr
|
|
782
|
-
)
|
|
981
|
+
_log(f"❌ Failed to track response on SubagentStop: {e}")
|
|
783
982
|
|
|
784
983
|
def handle_assistant_response(self, event):
|
|
785
984
|
"""Handle assistant response events for comprehensive response tracking.
|
|
@@ -789,6 +988,7 @@ class EventHandlers:
|
|
|
789
988
|
- Captures response content and metadata for analysis
|
|
790
989
|
- Enables tracking of conversation flow and response patterns
|
|
791
990
|
- Essential for comprehensive monitoring of Claude interactions
|
|
991
|
+
- Scans for delegation anti-patterns and creates autotodos
|
|
792
992
|
"""
|
|
793
993
|
# Track the response for logging
|
|
794
994
|
try:
|
|
@@ -796,10 +996,17 @@ class EventHandlers:
|
|
|
796
996
|
if rtm and hasattr(rtm, "track_assistant_response"):
|
|
797
997
|
pending_prompts = getattr(self.hook_handler, "pending_prompts", {})
|
|
798
998
|
rtm.track_assistant_response(event, pending_prompts)
|
|
799
|
-
except Exception:
|
|
999
|
+
except Exception: # nosec B110
|
|
800
1000
|
# Response tracking is optional
|
|
801
1001
|
pass
|
|
802
1002
|
|
|
1003
|
+
# Scan response for delegation anti-patterns and create autotodos
|
|
1004
|
+
try:
|
|
1005
|
+
self._scan_for_delegation_patterns(event)
|
|
1006
|
+
except Exception as e: # nosec B110
|
|
1007
|
+
if DEBUG:
|
|
1008
|
+
_log(f"Delegation scanning error: {e}")
|
|
1009
|
+
|
|
803
1010
|
# Get working directory and git branch
|
|
804
1011
|
working_dir = event.get("cwd", "")
|
|
805
1012
|
git_branch = self._get_git_branch(working_dir) if working_dir else "Unknown"
|
|
@@ -847,11 +1054,25 @@ class EventHandlers:
|
|
|
847
1054
|
|
|
848
1055
|
# Debug logging
|
|
849
1056
|
if DEBUG:
|
|
850
|
-
|
|
851
|
-
f"Hook handler: Processing AssistantResponse - session: '{session_id}', response_length: {len(response_text)}"
|
|
852
|
-
file=sys.stderr,
|
|
1057
|
+
_log(
|
|
1058
|
+
f"Hook handler: Processing AssistantResponse - session: '{session_id}', response_length: {len(response_text)}"
|
|
853
1059
|
)
|
|
854
1060
|
|
|
1061
|
+
# Record assistant response for auto-pause if active
|
|
1062
|
+
auto_pause = getattr(self.hook_handler, "auto_pause_handler", None)
|
|
1063
|
+
if auto_pause and auto_pause.is_pause_active():
|
|
1064
|
+
try:
|
|
1065
|
+
# Summarize response to first 200 chars
|
|
1066
|
+
summary = (
|
|
1067
|
+
response_text[:200] + "..."
|
|
1068
|
+
if len(response_text) > 200
|
|
1069
|
+
else response_text
|
|
1070
|
+
)
|
|
1071
|
+
auto_pause.on_assistant_response(summary)
|
|
1072
|
+
except Exception as e:
|
|
1073
|
+
if DEBUG:
|
|
1074
|
+
_log(f"Auto-pause response recording error: {e}")
|
|
1075
|
+
|
|
855
1076
|
# Emit normalized event
|
|
856
1077
|
self.hook_handler._emit_socketio_event(
|
|
857
1078
|
"", "assistant_response", assistant_response_data
|
|
@@ -864,6 +1085,9 @@ class EventHandlers:
|
|
|
864
1085
|
- Provides visibility into new conversation sessions
|
|
865
1086
|
- Enables tracking of session lifecycle and duration
|
|
866
1087
|
- Useful for monitoring concurrent sessions and resource usage
|
|
1088
|
+
|
|
1089
|
+
NOTE: This handler is intentionally lightweight - only event monitoring.
|
|
1090
|
+
All initialization/deployment logic runs in MPM CLI startup, not here.
|
|
867
1091
|
"""
|
|
868
1092
|
session_id = event.get("session_id", "")
|
|
869
1093
|
working_dir = event.get("cwd", "")
|
|
@@ -878,11 +1102,117 @@ class EventHandlers:
|
|
|
878
1102
|
}
|
|
879
1103
|
|
|
880
1104
|
# Debug logging
|
|
881
|
-
|
|
882
|
-
print(
|
|
883
|
-
f"Hook handler: Processing SessionStart - session: '{session_id}'",
|
|
884
|
-
file=sys.stderr,
|
|
885
|
-
)
|
|
1105
|
+
_log(f"Hook handler: Processing SessionStart - session: '{session_id}'")
|
|
886
1106
|
|
|
887
1107
|
# Emit normalized event
|
|
888
1108
|
self.hook_handler._emit_socketio_event("", "session_start", session_start_data)
|
|
1109
|
+
|
|
1110
|
+
def handle_subagent_start_fast(self, event):
|
|
1111
|
+
"""Handle SubagentStart events with proper agent type extraction.
|
|
1112
|
+
|
|
1113
|
+
WHY separate from SessionStart:
|
|
1114
|
+
- SubagentStart contains agent-specific information
|
|
1115
|
+
- Frontend needs agent_type to create distinct agent nodes
|
|
1116
|
+
- Multiple engineers should show as separate nodes in hierarchy
|
|
1117
|
+
- Research agents must appear in the agent hierarchy
|
|
1118
|
+
|
|
1119
|
+
Unlike SessionStart, SubagentStart events contain agent-specific
|
|
1120
|
+
information that must be preserved and emitted to the dashboard.
|
|
1121
|
+
"""
|
|
1122
|
+
session_id = event.get("session_id", "")
|
|
1123
|
+
|
|
1124
|
+
# Extract agent type from event - Claude provides this in SubagentStart
|
|
1125
|
+
# Try multiple possible field names for compatibility
|
|
1126
|
+
agent_type = event.get("agent_type") or event.get("subagent_type") or "unknown"
|
|
1127
|
+
|
|
1128
|
+
# Generate unique agent ID combining type and session
|
|
1129
|
+
agent_id = event.get("agent_id", f"{agent_type}_{session_id[:8]}")
|
|
1130
|
+
|
|
1131
|
+
# Get working directory and git branch
|
|
1132
|
+
working_dir = event.get("cwd", "")
|
|
1133
|
+
git_branch = self._get_git_branch(working_dir) if working_dir else "Unknown"
|
|
1134
|
+
|
|
1135
|
+
# Build subagent start data with all required fields
|
|
1136
|
+
subagent_start_data = {
|
|
1137
|
+
"session_id": session_id,
|
|
1138
|
+
"agent_type": agent_type,
|
|
1139
|
+
"agent_id": agent_id,
|
|
1140
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
1141
|
+
"hook_event_name": "SubagentStart", # Preserve correct hook name
|
|
1142
|
+
"working_directory": working_dir,
|
|
1143
|
+
"git_branch": git_branch,
|
|
1144
|
+
}
|
|
1145
|
+
|
|
1146
|
+
# Debug logging
|
|
1147
|
+
if DEBUG:
|
|
1148
|
+
_log(
|
|
1149
|
+
f"Hook handler: SubagentStart - agent_type='{agent_type}', agent_id='{agent_id}', session_id='{session_id[:16]}...'"
|
|
1150
|
+
)
|
|
1151
|
+
|
|
1152
|
+
# Emit to /hook namespace as subagent_start (NOT session_start!)
|
|
1153
|
+
self.hook_handler._emit_socketio_event(
|
|
1154
|
+
"", "subagent_start", subagent_start_data
|
|
1155
|
+
)
|
|
1156
|
+
|
|
1157
|
+
def _scan_for_delegation_patterns(self, event):
|
|
1158
|
+
"""Scan assistant response for delegation anti-patterns.
|
|
1159
|
+
|
|
1160
|
+
WHY this is needed:
|
|
1161
|
+
- Detect when PM asks user to do something manually instead of delegating
|
|
1162
|
+
- Flag PM behavior violations for immediate correction
|
|
1163
|
+
- Enforce delegation principle in PM workflow
|
|
1164
|
+
- Help PM recognize delegation opportunities
|
|
1165
|
+
|
|
1166
|
+
This method scans the assistant's response text for patterns like:
|
|
1167
|
+
- "Make sure .env.local is in your .gitignore"
|
|
1168
|
+
- "You'll need to run npm install"
|
|
1169
|
+
- "Please run the tests manually"
|
|
1170
|
+
|
|
1171
|
+
When patterns are detected, PM violations are logged as errors/warnings
|
|
1172
|
+
that should be corrected immediately, NOT as todos to delegate.
|
|
1173
|
+
|
|
1174
|
+
DESIGN DECISION: pm.violation vs autotodo.delegation
|
|
1175
|
+
- Delegation patterns = PM doing something WRONG → pm.violation (error)
|
|
1176
|
+
- Script failures = Something BROKEN → autotodo.error (todo)
|
|
1177
|
+
"""
|
|
1178
|
+
# Only scan if delegation detector and event log are available
|
|
1179
|
+
# Uses injected services or lazy-loaded module-level instances
|
|
1180
|
+
detector = self.delegation_detector
|
|
1181
|
+
event_log_service = self.event_log
|
|
1182
|
+
|
|
1183
|
+
if detector is None or event_log_service is None:
|
|
1184
|
+
if DEBUG:
|
|
1185
|
+
_log("Delegation detector or event log not available")
|
|
1186
|
+
return
|
|
1187
|
+
|
|
1188
|
+
response_text = event.get("response", "")
|
|
1189
|
+
if not response_text:
|
|
1190
|
+
return
|
|
1191
|
+
|
|
1192
|
+
# Detect delegation patterns
|
|
1193
|
+
detections = detector.detect_user_delegation(response_text)
|
|
1194
|
+
|
|
1195
|
+
if not detections:
|
|
1196
|
+
return # No patterns detected
|
|
1197
|
+
|
|
1198
|
+
# Create PM violation events (NOT autotodos)
|
|
1199
|
+
for detection in detections:
|
|
1200
|
+
# Create event log entry as pm.violation
|
|
1201
|
+
event_log_service.append_event(
|
|
1202
|
+
event_type="pm.violation",
|
|
1203
|
+
payload={
|
|
1204
|
+
"violation_type": "delegation_anti_pattern",
|
|
1205
|
+
"pattern_type": detection["pattern_type"],
|
|
1206
|
+
"original_text": detection["original_text"],
|
|
1207
|
+
"suggested_action": detection["suggested_todo"],
|
|
1208
|
+
"action": detection["action"],
|
|
1209
|
+
"session_id": event.get("session_id", ""),
|
|
1210
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
1211
|
+
"severity": "warning", # Not critical, but should be fixed
|
|
1212
|
+
"message": f"PM asked user to do something manually: {detection['original_text'][:80]}...",
|
|
1213
|
+
},
|
|
1214
|
+
status="pending",
|
|
1215
|
+
)
|
|
1216
|
+
|
|
1217
|
+
if DEBUG:
|
|
1218
|
+
_log(f"⚠️ PM violation detected: {detection['original_text'][:60]}...")
|