claude-mpm 5.4.48__py3-none-any.whl → 5.6.34__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of claude-mpm might be problematic. Click here for more details.
- claude_mpm/VERSION +1 -1
- claude_mpm/agents/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 +119 -689
- claude_mpm/agents/WORKFLOW.md +2 -0
- claude_mpm/agents/templates/circuit-breakers.md +26 -17
- 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/monitor.py +2 -2
- claude_mpm/cli/commands/mpm_init/core.py +15 -8
- 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 +171 -17
- claude_mpm/cli/executor.py +120 -16
- 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 +76 -1
- claude_mpm/cli/parsers/commander_parser.py +116 -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 +5 -0
- claude_mpm/cli/startup.py +544 -511
- claude_mpm/cli/startup_display.py +74 -6
- claude_mpm/cli/startup_logging.py +2 -2
- claude_mpm/cli/utils.py +7 -3
- claude_mpm/commander/__init__.py +78 -0
- claude_mpm/commander/adapters/__init__.py +60 -0
- claude_mpm/commander/adapters/auggie.py +260 -0
- claude_mpm/commander/adapters/base.py +288 -0
- claude_mpm/commander/adapters/claude_code.py +392 -0
- claude_mpm/commander/adapters/codex.py +237 -0
- claude_mpm/commander/adapters/communication.py +366 -0
- claude_mpm/commander/adapters/example_usage.py +310 -0
- claude_mpm/commander/adapters/mpm.py +389 -0
- claude_mpm/commander/adapters/registry.py +204 -0
- claude_mpm/commander/api/__init__.py +16 -0
- claude_mpm/commander/api/app.py +121 -0
- claude_mpm/commander/api/errors.py +133 -0
- claude_mpm/commander/api/routes/__init__.py +8 -0
- claude_mpm/commander/api/routes/events.py +184 -0
- claude_mpm/commander/api/routes/inbox.py +171 -0
- claude_mpm/commander/api/routes/messages.py +148 -0
- claude_mpm/commander/api/routes/projects.py +271 -0
- claude_mpm/commander/api/routes/sessions.py +226 -0
- claude_mpm/commander/api/routes/work.py +296 -0
- claude_mpm/commander/api/schemas.py +186 -0
- claude_mpm/commander/chat/__init__.py +7 -0
- claude_mpm/commander/chat/cli.py +146 -0
- claude_mpm/commander/chat/commands.py +96 -0
- claude_mpm/commander/chat/repl.py +310 -0
- claude_mpm/commander/config.py +51 -0
- claude_mpm/commander/config_loader.py +115 -0
- claude_mpm/commander/core/__init__.py +10 -0
- claude_mpm/commander/core/block_manager.py +325 -0
- claude_mpm/commander/core/response_manager.py +323 -0
- claude_mpm/commander/daemon.py +603 -0
- claude_mpm/commander/env_loader.py +59 -0
- claude_mpm/commander/events/__init__.py +26 -0
- claude_mpm/commander/events/manager.py +332 -0
- claude_mpm/commander/frameworks/__init__.py +12 -0
- claude_mpm/commander/frameworks/base.py +146 -0
- claude_mpm/commander/frameworks/claude_code.py +58 -0
- claude_mpm/commander/frameworks/mpm.py +62 -0
- claude_mpm/commander/inbox/__init__.py +16 -0
- claude_mpm/commander/inbox/dedup.py +128 -0
- claude_mpm/commander/inbox/inbox.py +224 -0
- claude_mpm/commander/inbox/models.py +70 -0
- claude_mpm/commander/instance_manager.py +450 -0
- claude_mpm/commander/llm/__init__.py +6 -0
- claude_mpm/commander/llm/openrouter_client.py +167 -0
- claude_mpm/commander/llm/summarizer.py +70 -0
- claude_mpm/commander/memory/__init__.py +45 -0
- claude_mpm/commander/memory/compression.py +347 -0
- claude_mpm/commander/memory/embeddings.py +230 -0
- claude_mpm/commander/memory/entities.py +310 -0
- claude_mpm/commander/memory/example_usage.py +290 -0
- claude_mpm/commander/memory/integration.py +325 -0
- claude_mpm/commander/memory/search.py +381 -0
- claude_mpm/commander/memory/store.py +657 -0
- claude_mpm/commander/models/__init__.py +18 -0
- claude_mpm/commander/models/events.py +121 -0
- claude_mpm/commander/models/project.py +162 -0
- claude_mpm/commander/models/work.py +214 -0
- claude_mpm/commander/parsing/__init__.py +20 -0
- claude_mpm/commander/parsing/extractor.py +132 -0
- claude_mpm/commander/parsing/output_parser.py +270 -0
- claude_mpm/commander/parsing/patterns.py +100 -0
- claude_mpm/commander/persistence/__init__.py +11 -0
- claude_mpm/commander/persistence/event_store.py +274 -0
- claude_mpm/commander/persistence/state_store.py +309 -0
- claude_mpm/commander/persistence/work_store.py +164 -0
- claude_mpm/commander/polling/__init__.py +13 -0
- claude_mpm/commander/polling/event_detector.py +104 -0
- claude_mpm/commander/polling/output_buffer.py +49 -0
- claude_mpm/commander/polling/output_poller.py +153 -0
- claude_mpm/commander/project_session.py +268 -0
- claude_mpm/commander/proxy/__init__.py +12 -0
- claude_mpm/commander/proxy/formatter.py +89 -0
- claude_mpm/commander/proxy/output_handler.py +191 -0
- claude_mpm/commander/proxy/relay.py +155 -0
- claude_mpm/commander/registry.py +410 -0
- claude_mpm/commander/runtime/__init__.py +10 -0
- claude_mpm/commander/runtime/executor.py +191 -0
- claude_mpm/commander/runtime/monitor.py +346 -0
- claude_mpm/commander/session/__init__.py +6 -0
- claude_mpm/commander/session/context.py +81 -0
- claude_mpm/commander/session/manager.py +59 -0
- claude_mpm/commander/tmux_orchestrator.py +361 -0
- claude_mpm/commander/web/__init__.py +1 -0
- claude_mpm/commander/work/__init__.py +30 -0
- claude_mpm/commander/work/executor.py +207 -0
- claude_mpm/commander/work/queue.py +405 -0
- claude_mpm/commander/workflow/__init__.py +27 -0
- claude_mpm/commander/workflow/event_handler.py +241 -0
- claude_mpm/commander/workflow/notifier.py +146 -0
- claude_mpm/commands/mpm-config.md +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 +1 -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 +51 -3
- claude_mpm/core/interactive_session.py +12 -11
- claude_mpm/core/logger.py +26 -9
- claude_mpm/core/logging_utils.py +39 -13
- claude_mpm/core/network_config.py +148 -0
- claude_mpm/core/oneshot_session.py +7 -6
- claude_mpm/core/optimized_startup.py +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 +527 -136
- claude_mpm/hooks/claude_hooks/hook_handler.py +170 -104
- claude_mpm/hooks/claude_hooks/hook_wrapper.sh +6 -11
- claude_mpm/hooks/claude_hooks/installer.py +206 -36
- claude_mpm/hooks/claude_hooks/memory_integration.py +52 -32
- claude_mpm/hooks/claude_hooks/response_tracking.py +43 -60
- claude_mpm/hooks/claude_hooks/services/__init__.py +21 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/container.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/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 +310 -0
- claude_mpm/hooks/claude_hooks/services/protocols.py +328 -0
- claude_mpm/hooks/claude_hooks/services/state_manager.py +25 -38
- claude_mpm/hooks/claude_hooks/services/subagent_processor.py +75 -77
- claude_mpm/hooks/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 +215 -2
- claude_mpm/scripts/claude-hook-handler.sh +46 -19
- claude_mpm/scripts/start_activity_logging.py +0 -0
- 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 +8 -6
- claude_mpm/services/agents/deployment/agent_template_builder.py +14 -4
- claude_mpm/services/agents/deployment/deployment_reconciler.py +577 -0
- claude_mpm/services/agents/deployment/multi_source_deployment_service.py +4 -4
- claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +4 -1
- claude_mpm/services/agents/deployment/startup_reconciliation.py +138 -0
- claude_mpm/services/agents/git_source_manager.py +6 -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 +10 -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/monitor/daemon_manager.py +15 -4
- claude_mpm/services/monitor/management/lifecycle.py +8 -3
- claude_mpm/services/monitor/server.py +106 -16
- claude_mpm/services/pm_skills_deployer.py +267 -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 +188 -67
- 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.34.dist-info/METADATA +393 -0
- {claude_mpm-5.4.48.dist-info → claude_mpm-5.6.34.dist-info}/RECORD +453 -151
- 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.48.dist-info/METADATA +0 -999
- {claude_mpm-5.4.48.dist-info → claude_mpm-5.6.34.dist-info}/WHEEL +0 -0
- {claude_mpm-5.4.48.dist-info → claude_mpm-5.6.34.dist-info}/entry_points.txt +0 -0
- {claude_mpm-5.4.48.dist-info → claude_mpm-5.6.34.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-5.4.48.dist-info → claude_mpm-5.6.34.dist-info}/licenses/LICENSE-FAQ.md +0 -0
- {claude_mpm-5.4.48.dist-info → claude_mpm-5.6.34.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, Callable, 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,186 @@ 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
|
+
# Autotodos function (for pending todos injection)
|
|
113
|
+
_get_pending_todos_fn: Optional[Callable] = None
|
|
114
|
+
_get_pending_todos_loaded = False
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def _get_pending_todos_func() -> Optional[Callable]:
|
|
118
|
+
"""Get get_pending_todos function with lazy loading."""
|
|
119
|
+
global _get_pending_todos_fn, _get_pending_todos_loaded
|
|
120
|
+
if not _get_pending_todos_loaded:
|
|
121
|
+
try:
|
|
122
|
+
from claude_mpm.cli.commands.autotodos import get_pending_todos
|
|
123
|
+
|
|
124
|
+
_get_pending_todos_fn = get_pending_todos
|
|
125
|
+
except ImportError:
|
|
126
|
+
_get_pending_todos_fn = None
|
|
127
|
+
_get_pending_todos_loaded = True
|
|
128
|
+
return _get_pending_todos_fn
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
# Delegation detector (for anti-pattern detection)
|
|
132
|
+
_delegation_detector: Optional[Any] = None
|
|
133
|
+
_delegation_detector_loaded = False
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def _get_delegation_detector_service() -> Optional[Any]:
|
|
137
|
+
"""Get delegation detector with lazy loading."""
|
|
138
|
+
global _delegation_detector, _delegation_detector_loaded
|
|
139
|
+
if not _delegation_detector_loaded:
|
|
140
|
+
try:
|
|
141
|
+
from claude_mpm.services.delegation_detector import get_delegation_detector
|
|
142
|
+
|
|
143
|
+
_delegation_detector = get_delegation_detector()
|
|
144
|
+
except ImportError:
|
|
145
|
+
_delegation_detector = None
|
|
146
|
+
_delegation_detector_loaded = True
|
|
147
|
+
return _delegation_detector
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
# Event log (for PM violation logging)
|
|
151
|
+
_event_log: Optional[Any] = None
|
|
152
|
+
_event_log_loaded = False
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def _get_event_log_service() -> Optional[Any]:
|
|
156
|
+
"""Get event log with lazy loading."""
|
|
157
|
+
global _event_log, _event_log_loaded
|
|
158
|
+
if not _event_log_loaded:
|
|
159
|
+
try:
|
|
160
|
+
from claude_mpm.services.event_log import get_event_log
|
|
161
|
+
|
|
162
|
+
_event_log = get_event_log()
|
|
163
|
+
except ImportError:
|
|
164
|
+
_event_log = None
|
|
165
|
+
_event_log_loaded = True
|
|
166
|
+
return _event_log
|
|
167
|
+
|
|
168
|
+
|
|
49
169
|
class EventHandlers:
|
|
50
|
-
"""Collection of event handlers for different Claude Code hook events.
|
|
170
|
+
"""Collection of event handlers for different Claude Code hook events.
|
|
171
|
+
|
|
172
|
+
Supports dependency injection for optional services:
|
|
173
|
+
- log_manager: For agent prompt logging
|
|
174
|
+
- config: For autotodos configuration
|
|
175
|
+
- delegation_detector: For anti-pattern detection
|
|
176
|
+
- event_log: For PM violation logging
|
|
51
177
|
|
|
52
|
-
|
|
53
|
-
|
|
178
|
+
If services are not provided, they are loaded lazily on first use.
|
|
179
|
+
"""
|
|
180
|
+
|
|
181
|
+
def __init__(
|
|
182
|
+
self,
|
|
183
|
+
hook_handler,
|
|
184
|
+
*,
|
|
185
|
+
log_manager: Optional[Any] = None,
|
|
186
|
+
config: Optional[Any] = None,
|
|
187
|
+
delegation_detector: Optional[Any] = None,
|
|
188
|
+
event_log: Optional[Any] = None,
|
|
189
|
+
get_pending_todos_fn: Optional[Callable] = None,
|
|
190
|
+
):
|
|
191
|
+
"""Initialize with reference to the main hook handler and optional services.
|
|
192
|
+
|
|
193
|
+
Args:
|
|
194
|
+
hook_handler: The main ClaudeHookHandler instance
|
|
195
|
+
log_manager: Optional LogManager for agent prompt logging
|
|
196
|
+
config: Optional Config for autotodos configuration
|
|
197
|
+
delegation_detector: Optional DelegationDetector for anti-pattern detection
|
|
198
|
+
event_log: Optional EventLog for PM violation logging
|
|
199
|
+
get_pending_todos_fn: Optional function to get pending todos
|
|
200
|
+
"""
|
|
54
201
|
self.hook_handler = hook_handler
|
|
55
202
|
|
|
203
|
+
# Store injected services (None means use lazy loading)
|
|
204
|
+
self._log_manager = log_manager
|
|
205
|
+
self._config = config
|
|
206
|
+
self._delegation_detector = delegation_detector
|
|
207
|
+
self._event_log = event_log
|
|
208
|
+
self._get_pending_todos_fn = get_pending_todos_fn
|
|
209
|
+
|
|
210
|
+
@property
|
|
211
|
+
def log_manager(self) -> Optional[Any]:
|
|
212
|
+
"""Get log manager (injected or lazy loaded)."""
|
|
213
|
+
if self._log_manager is not None:
|
|
214
|
+
return self._log_manager
|
|
215
|
+
return _get_log_manager()
|
|
216
|
+
|
|
217
|
+
@property
|
|
218
|
+
def config(self) -> Optional[Any]:
|
|
219
|
+
"""Get config (injected or lazy loaded)."""
|
|
220
|
+
if self._config is not None:
|
|
221
|
+
return self._config
|
|
222
|
+
return _get_config()
|
|
223
|
+
|
|
224
|
+
@property
|
|
225
|
+
def delegation_detector(self) -> Optional[Any]:
|
|
226
|
+
"""Get delegation detector (injected or lazy loaded)."""
|
|
227
|
+
if self._delegation_detector is not None:
|
|
228
|
+
return self._delegation_detector
|
|
229
|
+
return _get_delegation_detector_service()
|
|
230
|
+
|
|
231
|
+
@property
|
|
232
|
+
def event_log(self) -> Optional[Any]:
|
|
233
|
+
"""Get event log (injected or lazy loaded)."""
|
|
234
|
+
if self._event_log is not None:
|
|
235
|
+
return self._event_log
|
|
236
|
+
return _get_event_log_service()
|
|
237
|
+
|
|
238
|
+
def get_pending_todos(
|
|
239
|
+
self, max_todos: int = 10, working_dir: Optional[Path] = None
|
|
240
|
+
) -> list:
|
|
241
|
+
"""Get pending todos (using injected function or lazy loaded)."""
|
|
242
|
+
fn = self._get_pending_todos_fn or _get_pending_todos_func()
|
|
243
|
+
if fn is None:
|
|
244
|
+
return []
|
|
245
|
+
try:
|
|
246
|
+
return fn(max_todos=max_todos, working_dir=working_dir)
|
|
247
|
+
except Exception:
|
|
248
|
+
return []
|
|
249
|
+
|
|
56
250
|
def handle_user_prompt_fast(self, event):
|
|
57
251
|
"""Handle user prompt with comprehensive data capture.
|
|
58
252
|
|
|
@@ -111,14 +305,22 @@ class EventHandlers:
|
|
|
111
305
|
"working_directory": working_dir,
|
|
112
306
|
}
|
|
113
307
|
if DEBUG:
|
|
114
|
-
|
|
115
|
-
f"Stored prompt for comprehensive tracking: session {session_id[:8]}..."
|
|
116
|
-
file=sys.stderr,
|
|
308
|
+
_log(
|
|
309
|
+
f"Stored prompt for comprehensive tracking: session {session_id[:8]}..."
|
|
117
310
|
)
|
|
118
|
-
except Exception:
|
|
311
|
+
except Exception: # nosec B110
|
|
119
312
|
# Response tracking is optional - silently continue if it fails
|
|
120
313
|
pass
|
|
121
314
|
|
|
315
|
+
# Record user message for auto-pause if active
|
|
316
|
+
auto_pause = getattr(self.hook_handler, "auto_pause_handler", None)
|
|
317
|
+
if auto_pause and auto_pause.is_pause_active():
|
|
318
|
+
try:
|
|
319
|
+
auto_pause.on_user_message(prompt)
|
|
320
|
+
except Exception as e:
|
|
321
|
+
if DEBUG:
|
|
322
|
+
_log(f"Auto-pause user message recording error: {e}")
|
|
323
|
+
|
|
122
324
|
# Emit normalized event (namespace no longer needed with normalized events)
|
|
123
325
|
self.hook_handler._emit_socketio_event("", "user_prompt", prompt_data)
|
|
124
326
|
|
|
@@ -133,11 +335,8 @@ class EventHandlers:
|
|
|
133
335
|
# Enhanced debug logging for session correlation
|
|
134
336
|
session_id = event.get("session_id", "")
|
|
135
337
|
if DEBUG:
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
file=sys.stderr,
|
|
139
|
-
)
|
|
140
|
-
print(f" - event keys: {list(event.keys())}", file=sys.stderr)
|
|
338
|
+
_log(f" - session_id: {session_id[:16] if session_id else 'None'}...")
|
|
339
|
+
_log(f" - event keys: {list(event.keys())}")
|
|
141
340
|
|
|
142
341
|
tool_name = event.get("tool_name", "")
|
|
143
342
|
tool_input = event.get("tool_input", {})
|
|
@@ -176,21 +375,43 @@ class EventHandlers:
|
|
|
176
375
|
|
|
177
376
|
# Store tool_call_id using CorrelationManager for cross-process retrieval
|
|
178
377
|
if session_id:
|
|
179
|
-
from .correlation_manager import CorrelationManager
|
|
180
|
-
|
|
181
378
|
CorrelationManager.store(session_id, tool_call_id, tool_name)
|
|
182
379
|
if DEBUG:
|
|
183
|
-
|
|
184
|
-
f" - Generated tool_call_id: {tool_call_id[:8]}... for session {session_id[:8]}..."
|
|
185
|
-
file=sys.stderr,
|
|
380
|
+
_log(
|
|
381
|
+
f" - Generated tool_call_id: {tool_call_id[:8]}... for session {session_id[:8]}..."
|
|
186
382
|
)
|
|
187
383
|
|
|
188
384
|
# Add delegation-specific data if this is a Task tool
|
|
189
385
|
if tool_name == "Task" and isinstance(tool_input, dict):
|
|
190
386
|
self._handle_task_delegation(tool_input, pre_tool_data, session_id)
|
|
191
387
|
|
|
388
|
+
# Record tool call for auto-pause if active
|
|
389
|
+
auto_pause = getattr(self.hook_handler, "auto_pause_handler", None)
|
|
390
|
+
if auto_pause and auto_pause.is_pause_active():
|
|
391
|
+
try:
|
|
392
|
+
auto_pause.on_tool_call(tool_name, tool_input)
|
|
393
|
+
except Exception as e:
|
|
394
|
+
if DEBUG:
|
|
395
|
+
_log(f"Auto-pause tool recording error: {e}")
|
|
396
|
+
|
|
192
397
|
self.hook_handler._emit_socketio_event("", "pre_tool", pre_tool_data)
|
|
193
398
|
|
|
399
|
+
# Handle TodoWrite specially - emit dedicated todo_updated event
|
|
400
|
+
# WHY: Frontend expects todo_updated events for dashboard display
|
|
401
|
+
# The broadcaster.todo_updated() method exists but was never called
|
|
402
|
+
if tool_name == "TodoWrite" and tool_params.get("todos"):
|
|
403
|
+
todo_data = {
|
|
404
|
+
"todos": tool_params["todos"],
|
|
405
|
+
"total_count": len(tool_params["todos"]),
|
|
406
|
+
"session_id": session_id,
|
|
407
|
+
"timestamp": timestamp,
|
|
408
|
+
}
|
|
409
|
+
self.hook_handler._emit_socketio_event("", "todo_updated", todo_data)
|
|
410
|
+
if DEBUG:
|
|
411
|
+
_log(
|
|
412
|
+
f" - Emitted todo_updated event with {len(tool_params['todos'])} todos for session {session_id[:8]}..."
|
|
413
|
+
)
|
|
414
|
+
|
|
194
415
|
def _handle_task_delegation(
|
|
195
416
|
self, tool_input: dict, pre_tool_data: dict, session_id: str
|
|
196
417
|
):
|
|
@@ -229,12 +450,9 @@ class EventHandlers:
|
|
|
229
450
|
|
|
230
451
|
# Track this delegation for SubagentStop correlation and response tracking
|
|
231
452
|
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)
|
|
453
|
+
_log(f" - session_id: {session_id[:16] if session_id else 'None'}...")
|
|
454
|
+
_log(f" - agent_type: {agent_type}")
|
|
455
|
+
_log(f" - raw_agent_type: {raw_agent_type}")
|
|
238
456
|
|
|
239
457
|
if session_id and agent_type != "unknown":
|
|
240
458
|
# Prepare request data for response tracking correlation
|
|
@@ -246,24 +464,17 @@ class EventHandlers:
|
|
|
246
464
|
self.hook_handler._track_delegation(session_id, agent_type, request_data)
|
|
247
465
|
|
|
248
466
|
if DEBUG:
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
f" - Request data keys: {list(request_data.keys())}",
|
|
252
|
-
file=sys.stderr,
|
|
253
|
-
)
|
|
467
|
+
_log(" - Delegation tracked successfully")
|
|
468
|
+
_log(f" - Request data keys: {list(request_data.keys())}")
|
|
254
469
|
delegation_requests = getattr(
|
|
255
470
|
self.hook_handler, "delegation_requests", {}
|
|
256
471
|
)
|
|
257
|
-
|
|
258
|
-
f" - delegation_requests size: {len(delegation_requests)}",
|
|
259
|
-
file=sys.stderr,
|
|
260
|
-
)
|
|
472
|
+
_log(f" - delegation_requests size: {len(delegation_requests)}")
|
|
261
473
|
|
|
262
474
|
# Log important delegations for debugging
|
|
263
475
|
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,
|
|
476
|
+
_log(
|
|
477
|
+
f"Hook handler: Task delegation started - agent: '{agent_type}', session: '{session_id}'"
|
|
267
478
|
)
|
|
268
479
|
|
|
269
480
|
# Trigger memory pre-delegation hook
|
|
@@ -271,7 +482,7 @@ class EventHandlers:
|
|
|
271
482
|
mhm = getattr(self.hook_handler, "memory_hook_manager", None)
|
|
272
483
|
if mhm and hasattr(mhm, "trigger_pre_delegation_hook"):
|
|
273
484
|
mhm.trigger_pre_delegation_hook(agent_type, tool_input, session_id)
|
|
274
|
-
except Exception:
|
|
485
|
+
except Exception: # nosec B110
|
|
275
486
|
# Memory hooks are optional
|
|
276
487
|
pass
|
|
277
488
|
|
|
@@ -290,53 +501,50 @@ class EventHandlers:
|
|
|
290
501
|
)
|
|
291
502
|
|
|
292
503
|
# 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
|
-
}
|
|
504
|
+
# Uses injected log_manager or lazy-loaded module-level instance
|
|
505
|
+
log_manager = self.log_manager
|
|
506
|
+
if log_manager is not None:
|
|
507
|
+
try:
|
|
508
|
+
# Prepare prompt content
|
|
509
|
+
prompt_content = tool_input.get("prompt", "")
|
|
510
|
+
if not prompt_content:
|
|
511
|
+
prompt_content = tool_input.get("description", "")
|
|
512
|
+
|
|
513
|
+
if prompt_content:
|
|
514
|
+
# Prepare metadata
|
|
515
|
+
metadata = {
|
|
516
|
+
"agent_type": agent_type,
|
|
517
|
+
"agent_id": f"{agent_type}_{session_id}",
|
|
518
|
+
"session_id": session_id,
|
|
519
|
+
"delegation_context": {
|
|
520
|
+
"description": tool_input.get("description", ""),
|
|
521
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
522
|
+
},
|
|
523
|
+
}
|
|
316
524
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
525
|
+
# Log the agent prompt asynchronously
|
|
526
|
+
try:
|
|
527
|
+
loop = asyncio.get_running_loop()
|
|
528
|
+
_task = asyncio.create_task(
|
|
529
|
+
log_manager.log_prompt(
|
|
530
|
+
f"agent_{agent_type}", prompt_content, metadata
|
|
531
|
+
)
|
|
532
|
+
) # Fire-and-forget logging (ephemeral hook process)
|
|
533
|
+
except RuntimeError:
|
|
534
|
+
# No running loop, create one
|
|
535
|
+
loop = asyncio.new_event_loop()
|
|
536
|
+
asyncio.set_event_loop(loop)
|
|
537
|
+
loop.run_until_complete(
|
|
538
|
+
log_manager.log_prompt(
|
|
539
|
+
f"agent_{agent_type}", prompt_content, metadata
|
|
540
|
+
)
|
|
332
541
|
)
|
|
333
|
-
)
|
|
334
542
|
|
|
543
|
+
if DEBUG:
|
|
544
|
+
_log(f" - Agent prompt logged for {agent_type}")
|
|
545
|
+
except Exception as e:
|
|
335
546
|
if DEBUG:
|
|
336
|
-
|
|
337
|
-
except Exception as e:
|
|
338
|
-
if DEBUG:
|
|
339
|
-
print(f" - Could not log agent prompt: {e}", file=sys.stderr)
|
|
547
|
+
_log(f" - Could not log agent prompt: {e}")
|
|
340
548
|
|
|
341
549
|
def _get_git_branch(self, working_dir: Optional[str] = None) -> str:
|
|
342
550
|
"""Get git branch for the given directory with caching."""
|
|
@@ -364,7 +572,7 @@ class EventHandlers:
|
|
|
364
572
|
os.chdir(working_dir)
|
|
365
573
|
|
|
366
574
|
# Run git command to get current branch
|
|
367
|
-
result = subprocess.run(
|
|
575
|
+
result = subprocess.run( # nosec B603 B607
|
|
368
576
|
["git", "branch", "--show-current"],
|
|
369
577
|
capture_output=True,
|
|
370
578
|
text=True,
|
|
@@ -420,13 +628,10 @@ class EventHandlers:
|
|
|
420
628
|
git_branch = self._get_git_branch(working_dir) if working_dir else "Unknown"
|
|
421
629
|
|
|
422
630
|
# Retrieve tool_call_id using CorrelationManager for cross-process correlation
|
|
423
|
-
from .correlation_manager import CorrelationManager
|
|
424
|
-
|
|
425
631
|
tool_call_id = CorrelationManager.retrieve(session_id) if session_id else None
|
|
426
632
|
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,
|
|
633
|
+
_log(
|
|
634
|
+
f" - Retrieved tool_call_id: {tool_call_id[:8]}... for session {session_id[:8]}..."
|
|
430
635
|
)
|
|
431
636
|
|
|
432
637
|
post_tool_data = {
|
|
@@ -474,7 +679,7 @@ class EventHandlers:
|
|
|
474
679
|
mhm = getattr(self.hook_handler, "memory_hook_manager", None)
|
|
475
680
|
if mhm and hasattr(mhm, "trigger_post_delegation_hook"):
|
|
476
681
|
mhm.trigger_post_delegation_hook(agent_type, event, session_id)
|
|
477
|
-
except Exception:
|
|
682
|
+
except Exception: # nosec B110
|
|
478
683
|
# Memory hooks are optional
|
|
479
684
|
pass
|
|
480
685
|
|
|
@@ -488,7 +693,7 @@ class EventHandlers:
|
|
|
488
693
|
rtm.track_agent_response(
|
|
489
694
|
session_id, agent_type, event, delegation_requests
|
|
490
695
|
)
|
|
491
|
-
except Exception:
|
|
696
|
+
except Exception: # nosec B110
|
|
492
697
|
# Response tracking is optional
|
|
493
698
|
pass
|
|
494
699
|
|
|
@@ -550,13 +755,60 @@ class EventHandlers:
|
|
|
550
755
|
if DEBUG:
|
|
551
756
|
self._log_stop_event_debug(event, session_id, metadata)
|
|
552
757
|
|
|
758
|
+
# Auto-pause integration (independent of response tracking)
|
|
759
|
+
# WHY HERE: Auto-pause must work even when response_tracking is disabled
|
|
760
|
+
# Extract usage data directly from event and trigger auto-pause if thresholds crossed
|
|
761
|
+
if "usage" in event:
|
|
762
|
+
auto_pause = getattr(self.hook_handler, "auto_pause_handler", None)
|
|
763
|
+
if auto_pause:
|
|
764
|
+
try:
|
|
765
|
+
usage_data = event["usage"]
|
|
766
|
+
metadata["usage"] = {
|
|
767
|
+
"input_tokens": usage_data.get("input_tokens", 0),
|
|
768
|
+
"output_tokens": usage_data.get("output_tokens", 0),
|
|
769
|
+
"cache_creation_input_tokens": usage_data.get(
|
|
770
|
+
"cache_creation_input_tokens", 0
|
|
771
|
+
),
|
|
772
|
+
"cache_read_input_tokens": usage_data.get(
|
|
773
|
+
"cache_read_input_tokens", 0
|
|
774
|
+
),
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
threshold_crossed = auto_pause.on_usage_update(metadata["usage"])
|
|
778
|
+
if threshold_crossed:
|
|
779
|
+
warning = auto_pause.emit_threshold_warning(threshold_crossed)
|
|
780
|
+
# CRITICAL: Never write to stderr unconditionally - causes hook errors
|
|
781
|
+
# Use _log() instead which only writes to file if DEBUG=true
|
|
782
|
+
_log(f"⚠️ Auto-pause threshold crossed: {warning}")
|
|
783
|
+
|
|
784
|
+
if DEBUG:
|
|
785
|
+
_log(
|
|
786
|
+
f" - Auto-pause threshold crossed: {threshold_crossed}"
|
|
787
|
+
)
|
|
788
|
+
except Exception as e:
|
|
789
|
+
if DEBUG:
|
|
790
|
+
_log(f"Auto-pause error in handle_stop_fast: {e}")
|
|
791
|
+
|
|
792
|
+
# Finalize pause session if active
|
|
793
|
+
try:
|
|
794
|
+
if auto_pause.is_pause_active():
|
|
795
|
+
session_file = auto_pause.on_session_end()
|
|
796
|
+
if session_file:
|
|
797
|
+
if DEBUG:
|
|
798
|
+
_log(
|
|
799
|
+
f"✅ Auto-pause session finalized: {session_file.name}"
|
|
800
|
+
)
|
|
801
|
+
except Exception as e:
|
|
802
|
+
if DEBUG:
|
|
803
|
+
_log(f"❌ Failed to finalize auto-pause session: {e}")
|
|
804
|
+
|
|
553
805
|
# Track response if enabled
|
|
554
806
|
try:
|
|
555
807
|
rtm = getattr(self.hook_handler, "response_tracking_manager", None)
|
|
556
808
|
if rtm and hasattr(rtm, "track_stop_response"):
|
|
557
809
|
pending_prompts = getattr(self.hook_handler, "pending_prompts", {})
|
|
558
810
|
rtm.track_stop_response(event, session_id, metadata, pending_prompts)
|
|
559
|
-
except Exception:
|
|
811
|
+
except Exception: # nosec B110
|
|
560
812
|
# Response tracking is optional
|
|
561
813
|
pass
|
|
562
814
|
|
|
@@ -590,24 +842,15 @@ class EventHandlers:
|
|
|
590
842
|
getattr(rtm, "response_tracker", None) is not None if rtm else False
|
|
591
843
|
)
|
|
592
844
|
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
)
|
|
597
|
-
print(
|
|
598
|
-
f" - response_tracker exists: {tracker_exists}",
|
|
599
|
-
file=sys.stderr,
|
|
600
|
-
)
|
|
601
|
-
except Exception:
|
|
845
|
+
_log(f" - response_tracking_enabled: {tracking_enabled}")
|
|
846
|
+
_log(f" - response_tracker exists: {tracker_exists}")
|
|
847
|
+
except Exception: # nosec B110
|
|
602
848
|
# If debug logging fails, just skip it
|
|
603
849
|
pass
|
|
604
850
|
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
)
|
|
609
|
-
print(f" - reason: {metadata['reason']}", file=sys.stderr)
|
|
610
|
-
print(f" - stop_type: {metadata['stop_type']}", file=sys.stderr)
|
|
851
|
+
_log(f" - session_id: {session_id[:8] if session_id else 'None'}...")
|
|
852
|
+
_log(f" - reason: {metadata['reason']}")
|
|
853
|
+
_log(f" - stop_type: {metadata['stop_type']}")
|
|
611
854
|
|
|
612
855
|
def _emit_stop_event(self, event: dict, session_id: str, metadata: dict) -> None:
|
|
613
856
|
"""Emit stop event data to Socket.IO."""
|
|
@@ -664,15 +907,12 @@ class EventHandlers:
|
|
|
664
907
|
try:
|
|
665
908
|
# Get the original request data (with fuzzy matching fallback)
|
|
666
909
|
delegation_requests = getattr(self.hook_handler, "delegation_requests", {})
|
|
667
|
-
request_info = delegation_requests.get(session_id)
|
|
910
|
+
request_info = delegation_requests.get(session_id) # nosec B113
|
|
668
911
|
|
|
669
912
|
# If exact match fails, try partial matching
|
|
670
913
|
if not request_info and session_id:
|
|
671
914
|
if DEBUG:
|
|
672
|
-
|
|
673
|
-
f" - Trying fuzzy match for session {session_id[:16]}...",
|
|
674
|
-
file=sys.stderr,
|
|
675
|
-
)
|
|
915
|
+
_log(f" - Trying fuzzy match for session {session_id[:16]}...")
|
|
676
916
|
# Try to find a session that matches the first 8-16 characters
|
|
677
917
|
for stored_sid in list(delegation_requests.keys()):
|
|
678
918
|
if (
|
|
@@ -685,11 +925,8 @@ class EventHandlers:
|
|
|
685
925
|
)
|
|
686
926
|
):
|
|
687
927
|
if DEBUG:
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
file=sys.stderr,
|
|
691
|
-
)
|
|
692
|
-
request_info = delegation_requests.get(stored_sid)
|
|
928
|
+
_log(f" - ✅ Fuzzy match found: {stored_sid[:16]}...")
|
|
929
|
+
request_info = delegation_requests.get(stored_sid) # nosec B113
|
|
693
930
|
# Update the key to use the current session_id for consistency
|
|
694
931
|
if request_info:
|
|
695
932
|
delegation_requests[session_id] = request_info
|
|
@@ -757,9 +994,8 @@ class EventHandlers:
|
|
|
757
994
|
)
|
|
758
995
|
|
|
759
996
|
if file_path and DEBUG:
|
|
760
|
-
|
|
761
|
-
f"✅ Tracked {agent_type} agent response on SubagentStop: {file_path.name}"
|
|
762
|
-
file=sys.stderr,
|
|
997
|
+
_log(
|
|
998
|
+
f"✅ Tracked {agent_type} agent response on SubagentStop: {file_path.name}"
|
|
763
999
|
)
|
|
764
1000
|
|
|
765
1001
|
# Clean up the request data
|
|
@@ -770,16 +1006,13 @@ class EventHandlers:
|
|
|
770
1006
|
del delegation_requests[session_id]
|
|
771
1007
|
|
|
772
1008
|
elif DEBUG:
|
|
773
|
-
|
|
774
|
-
f"No request data for SubagentStop session {session_id[:8]}..., agent: {agent_type}"
|
|
775
|
-
file=sys.stderr,
|
|
1009
|
+
_log(
|
|
1010
|
+
f"No request data for SubagentStop session {session_id[:8]}..., agent: {agent_type}"
|
|
776
1011
|
)
|
|
777
1012
|
|
|
778
1013
|
except Exception as e:
|
|
779
1014
|
if DEBUG:
|
|
780
|
-
|
|
781
|
-
f"❌ Failed to track response on SubagentStop: {e}", file=sys.stderr
|
|
782
|
-
)
|
|
1015
|
+
_log(f"❌ Failed to track response on SubagentStop: {e}")
|
|
783
1016
|
|
|
784
1017
|
def handle_assistant_response(self, event):
|
|
785
1018
|
"""Handle assistant response events for comprehensive response tracking.
|
|
@@ -789,6 +1022,7 @@ class EventHandlers:
|
|
|
789
1022
|
- Captures response content and metadata for analysis
|
|
790
1023
|
- Enables tracking of conversation flow and response patterns
|
|
791
1024
|
- Essential for comprehensive monitoring of Claude interactions
|
|
1025
|
+
- Scans for delegation anti-patterns and creates autotodos
|
|
792
1026
|
"""
|
|
793
1027
|
# Track the response for logging
|
|
794
1028
|
try:
|
|
@@ -796,10 +1030,17 @@ class EventHandlers:
|
|
|
796
1030
|
if rtm and hasattr(rtm, "track_assistant_response"):
|
|
797
1031
|
pending_prompts = getattr(self.hook_handler, "pending_prompts", {})
|
|
798
1032
|
rtm.track_assistant_response(event, pending_prompts)
|
|
799
|
-
except Exception:
|
|
1033
|
+
except Exception: # nosec B110
|
|
800
1034
|
# Response tracking is optional
|
|
801
1035
|
pass
|
|
802
1036
|
|
|
1037
|
+
# Scan response for delegation anti-patterns and create autotodos
|
|
1038
|
+
try:
|
|
1039
|
+
self._scan_for_delegation_patterns(event)
|
|
1040
|
+
except Exception as e: # nosec B110
|
|
1041
|
+
if DEBUG:
|
|
1042
|
+
_log(f"Delegation scanning error: {e}")
|
|
1043
|
+
|
|
803
1044
|
# Get working directory and git branch
|
|
804
1045
|
working_dir = event.get("cwd", "")
|
|
805
1046
|
git_branch = self._get_git_branch(working_dir) if working_dir else "Unknown"
|
|
@@ -847,11 +1088,25 @@ class EventHandlers:
|
|
|
847
1088
|
|
|
848
1089
|
# Debug logging
|
|
849
1090
|
if DEBUG:
|
|
850
|
-
|
|
851
|
-
f"Hook handler: Processing AssistantResponse - session: '{session_id}', response_length: {len(response_text)}"
|
|
852
|
-
file=sys.stderr,
|
|
1091
|
+
_log(
|
|
1092
|
+
f"Hook handler: Processing AssistantResponse - session: '{session_id}', response_length: {len(response_text)}"
|
|
853
1093
|
)
|
|
854
1094
|
|
|
1095
|
+
# Record assistant response for auto-pause if active
|
|
1096
|
+
auto_pause = getattr(self.hook_handler, "auto_pause_handler", None)
|
|
1097
|
+
if auto_pause and auto_pause.is_pause_active():
|
|
1098
|
+
try:
|
|
1099
|
+
# Summarize response to first 200 chars
|
|
1100
|
+
summary = (
|
|
1101
|
+
response_text[:200] + "..."
|
|
1102
|
+
if len(response_text) > 200
|
|
1103
|
+
else response_text
|
|
1104
|
+
)
|
|
1105
|
+
auto_pause.on_assistant_response(summary)
|
|
1106
|
+
except Exception as e:
|
|
1107
|
+
if DEBUG:
|
|
1108
|
+
_log(f"Auto-pause response recording error: {e}")
|
|
1109
|
+
|
|
855
1110
|
# Emit normalized event
|
|
856
1111
|
self.hook_handler._emit_socketio_event(
|
|
857
1112
|
"", "assistant_response", assistant_response_data
|
|
@@ -864,6 +1119,7 @@ class EventHandlers:
|
|
|
864
1119
|
- Provides visibility into new conversation sessions
|
|
865
1120
|
- Enables tracking of session lifecycle and duration
|
|
866
1121
|
- Useful for monitoring concurrent sessions and resource usage
|
|
1122
|
+
- Auto-inject pending autotodos if enabled in config
|
|
867
1123
|
"""
|
|
868
1124
|
session_id = event.get("session_id", "")
|
|
869
1125
|
working_dir = event.get("cwd", "")
|
|
@@ -877,12 +1133,147 @@ class EventHandlers:
|
|
|
877
1133
|
"hook_event_name": "SessionStart",
|
|
878
1134
|
}
|
|
879
1135
|
|
|
1136
|
+
# Auto-inject pending autotodos if enabled
|
|
1137
|
+
# Uses injected config and get_pending_todos or lazy-loaded instances
|
|
1138
|
+
config = self.config
|
|
1139
|
+
if config is not None:
|
|
1140
|
+
try:
|
|
1141
|
+
auto_inject_enabled = config.get(
|
|
1142
|
+
"autotodos.auto_inject_on_startup", True
|
|
1143
|
+
)
|
|
1144
|
+
max_todos = config.get("autotodos.max_todos_per_session", 10)
|
|
1145
|
+
|
|
1146
|
+
if auto_inject_enabled:
|
|
1147
|
+
# Pass working directory from event to avoid Path.cwd() issues
|
|
1148
|
+
working_dir_param = None
|
|
1149
|
+
if working_dir:
|
|
1150
|
+
working_dir_param = Path(working_dir)
|
|
1151
|
+
|
|
1152
|
+
pending_todos = self.get_pending_todos(
|
|
1153
|
+
max_todos=max_todos, working_dir=working_dir_param
|
|
1154
|
+
)
|
|
1155
|
+
if pending_todos:
|
|
1156
|
+
session_start_data["pending_autotodos"] = pending_todos
|
|
1157
|
+
session_start_data["autotodos_count"] = len(pending_todos)
|
|
1158
|
+
_log(
|
|
1159
|
+
f" - Auto-injected {len(pending_todos)} pending autotodos"
|
|
1160
|
+
)
|
|
1161
|
+
except Exception as e: # nosec B110
|
|
1162
|
+
# Auto-injection is optional - continue if it fails
|
|
1163
|
+
_log(f" - Failed to auto-inject autotodos: {e}")
|
|
1164
|
+
|
|
880
1165
|
# Debug logging
|
|
881
|
-
|
|
882
|
-
print(
|
|
883
|
-
f"Hook handler: Processing SessionStart - session: '{session_id}'",
|
|
884
|
-
file=sys.stderr,
|
|
885
|
-
)
|
|
1166
|
+
_log(f"Hook handler: Processing SessionStart - session: '{session_id}'")
|
|
886
1167
|
|
|
887
1168
|
# Emit normalized event
|
|
888
1169
|
self.hook_handler._emit_socketio_event("", "session_start", session_start_data)
|
|
1170
|
+
|
|
1171
|
+
def handle_subagent_start_fast(self, event):
|
|
1172
|
+
"""Handle SubagentStart events with proper agent type extraction.
|
|
1173
|
+
|
|
1174
|
+
WHY separate from SessionStart:
|
|
1175
|
+
- SubagentStart contains agent-specific information
|
|
1176
|
+
- Frontend needs agent_type to create distinct agent nodes
|
|
1177
|
+
- Multiple engineers should show as separate nodes in hierarchy
|
|
1178
|
+
- Research agents must appear in the agent hierarchy
|
|
1179
|
+
|
|
1180
|
+
Unlike SessionStart, SubagentStart events contain agent-specific
|
|
1181
|
+
information that must be preserved and emitted to the dashboard.
|
|
1182
|
+
"""
|
|
1183
|
+
session_id = event.get("session_id", "")
|
|
1184
|
+
|
|
1185
|
+
# Extract agent type from event - Claude provides this in SubagentStart
|
|
1186
|
+
# Try multiple possible field names for compatibility
|
|
1187
|
+
agent_type = event.get("agent_type") or event.get("subagent_type") or "unknown"
|
|
1188
|
+
|
|
1189
|
+
# Generate unique agent ID combining type and session
|
|
1190
|
+
agent_id = event.get("agent_id", f"{agent_type}_{session_id[:8]}")
|
|
1191
|
+
|
|
1192
|
+
# Get working directory and git branch
|
|
1193
|
+
working_dir = event.get("cwd", "")
|
|
1194
|
+
git_branch = self._get_git_branch(working_dir) if working_dir else "Unknown"
|
|
1195
|
+
|
|
1196
|
+
# Build subagent start data with all required fields
|
|
1197
|
+
subagent_start_data = {
|
|
1198
|
+
"session_id": session_id,
|
|
1199
|
+
"agent_type": agent_type,
|
|
1200
|
+
"agent_id": agent_id,
|
|
1201
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
1202
|
+
"hook_event_name": "SubagentStart", # Preserve correct hook name
|
|
1203
|
+
"working_directory": working_dir,
|
|
1204
|
+
"git_branch": git_branch,
|
|
1205
|
+
}
|
|
1206
|
+
|
|
1207
|
+
# Debug logging
|
|
1208
|
+
if DEBUG:
|
|
1209
|
+
_log(
|
|
1210
|
+
f"Hook handler: SubagentStart - agent_type='{agent_type}', agent_id='{agent_id}', session_id='{session_id[:16]}...'"
|
|
1211
|
+
)
|
|
1212
|
+
|
|
1213
|
+
# Emit to /hook namespace as subagent_start (NOT session_start!)
|
|
1214
|
+
self.hook_handler._emit_socketio_event(
|
|
1215
|
+
"", "subagent_start", subagent_start_data
|
|
1216
|
+
)
|
|
1217
|
+
|
|
1218
|
+
def _scan_for_delegation_patterns(self, event):
|
|
1219
|
+
"""Scan assistant response for delegation anti-patterns.
|
|
1220
|
+
|
|
1221
|
+
WHY this is needed:
|
|
1222
|
+
- Detect when PM asks user to do something manually instead of delegating
|
|
1223
|
+
- Flag PM behavior violations for immediate correction
|
|
1224
|
+
- Enforce delegation principle in PM workflow
|
|
1225
|
+
- Help PM recognize delegation opportunities
|
|
1226
|
+
|
|
1227
|
+
This method scans the assistant's response text for patterns like:
|
|
1228
|
+
- "Make sure .env.local is in your .gitignore"
|
|
1229
|
+
- "You'll need to run npm install"
|
|
1230
|
+
- "Please run the tests manually"
|
|
1231
|
+
|
|
1232
|
+
When patterns are detected, PM violations are logged as errors/warnings
|
|
1233
|
+
that should be corrected immediately, NOT as todos to delegate.
|
|
1234
|
+
|
|
1235
|
+
DESIGN DECISION: pm.violation vs autotodo.delegation
|
|
1236
|
+
- Delegation patterns = PM doing something WRONG → pm.violation (error)
|
|
1237
|
+
- Script failures = Something BROKEN → autotodo.error (todo)
|
|
1238
|
+
"""
|
|
1239
|
+
# Only scan if delegation detector and event log are available
|
|
1240
|
+
# Uses injected services or lazy-loaded module-level instances
|
|
1241
|
+
detector = self.delegation_detector
|
|
1242
|
+
event_log_service = self.event_log
|
|
1243
|
+
|
|
1244
|
+
if detector is None or event_log_service is None:
|
|
1245
|
+
if DEBUG:
|
|
1246
|
+
_log("Delegation detector or event log not available")
|
|
1247
|
+
return
|
|
1248
|
+
|
|
1249
|
+
response_text = event.get("response", "")
|
|
1250
|
+
if not response_text:
|
|
1251
|
+
return
|
|
1252
|
+
|
|
1253
|
+
# Detect delegation patterns
|
|
1254
|
+
detections = detector.detect_user_delegation(response_text)
|
|
1255
|
+
|
|
1256
|
+
if not detections:
|
|
1257
|
+
return # No patterns detected
|
|
1258
|
+
|
|
1259
|
+
# Create PM violation events (NOT autotodos)
|
|
1260
|
+
for detection in detections:
|
|
1261
|
+
# Create event log entry as pm.violation
|
|
1262
|
+
event_log_service.append_event(
|
|
1263
|
+
event_type="pm.violation",
|
|
1264
|
+
payload={
|
|
1265
|
+
"violation_type": "delegation_anti_pattern",
|
|
1266
|
+
"pattern_type": detection["pattern_type"],
|
|
1267
|
+
"original_text": detection["original_text"],
|
|
1268
|
+
"suggested_action": detection["suggested_todo"],
|
|
1269
|
+
"action": detection["action"],
|
|
1270
|
+
"session_id": event.get("session_id", ""),
|
|
1271
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
1272
|
+
"severity": "warning", # Not critical, but should be fixed
|
|
1273
|
+
"message": f"PM asked user to do something manually: {detection['original_text'][:80]}...",
|
|
1274
|
+
},
|
|
1275
|
+
status="pending",
|
|
1276
|
+
)
|
|
1277
|
+
|
|
1278
|
+
if DEBUG:
|
|
1279
|
+
_log(f"⚠️ PM violation detected: {detection['original_text'][:60]}...")
|