claude-mpm 5.4.85__py3-none-any.whl → 5.6.76__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- claude_mpm/VERSION +1 -1
- claude_mpm/agents/CLAUDE_MPM_OUTPUT_STYLE.md +8 -5
- claude_mpm/agents/{CLAUDE_MPM_FOUNDERS_OUTPUT_STYLE.md → CLAUDE_MPM_RESEARCH_OUTPUT_STYLE.md} +14 -6
- claude_mpm/agents/PM_INSTRUCTIONS.md +109 -706
- claude_mpm/agents/WORKFLOW.md +2 -0
- claude_mpm/agents/templates/circuit-breakers.md +26 -17
- claude_mpm/auth/__init__.py +35 -0
- claude_mpm/auth/callback_server.py +328 -0
- claude_mpm/auth/models.py +104 -0
- claude_mpm/auth/oauth_manager.py +266 -0
- claude_mpm/auth/providers/__init__.py +12 -0
- claude_mpm/auth/providers/base.py +165 -0
- claude_mpm/auth/providers/google.py +261 -0
- claude_mpm/auth/token_storage.py +252 -0
- claude_mpm/cli/commands/autotodos.py +566 -0
- claude_mpm/cli/commands/commander.py +216 -0
- claude_mpm/cli/commands/hook_errors.py +60 -60
- claude_mpm/cli/commands/mcp.py +29 -17
- claude_mpm/cli/commands/mcp_command_router.py +39 -0
- claude_mpm/cli/commands/mcp_service_commands.py +304 -0
- claude_mpm/cli/commands/monitor.py +2 -2
- claude_mpm/cli/commands/mpm_init/core.py +2 -2
- claude_mpm/cli/commands/oauth.py +481 -0
- claude_mpm/cli/commands/run.py +35 -3
- claude_mpm/cli/commands/skill_source.py +51 -2
- claude_mpm/cli/commands/skills.py +5 -3
- claude_mpm/cli/executor.py +128 -16
- claude_mpm/cli/helpers.py +1 -1
- claude_mpm/cli/parsers/base_parser.py +84 -1
- claude_mpm/cli/parsers/commander_parser.py +116 -0
- claude_mpm/cli/parsers/mcp_parser.py +79 -0
- claude_mpm/cli/parsers/oauth_parser.py +165 -0
- claude_mpm/cli/parsers/run_parser.py +10 -0
- claude_mpm/cli/parsers/skill_source_parser.py +4 -0
- claude_mpm/cli/parsers/skills_parser.py +5 -0
- claude_mpm/cli/startup.py +345 -40
- claude_mpm/cli/startup_display.py +76 -7
- claude_mpm/cli/startup_logging.py +2 -2
- claude_mpm/cli/startup_migrations.py +236 -0
- claude_mpm/cli/utils.py +7 -3
- claude_mpm/commander/__init__.py +78 -0
- claude_mpm/commander/adapters/__init__.py +60 -0
- claude_mpm/commander/adapters/auggie.py +260 -0
- claude_mpm/commander/adapters/base.py +288 -0
- claude_mpm/commander/adapters/claude_code.py +392 -0
- claude_mpm/commander/adapters/codex.py +237 -0
- claude_mpm/commander/adapters/communication.py +366 -0
- claude_mpm/commander/adapters/example_usage.py +310 -0
- claude_mpm/commander/adapters/mpm.py +389 -0
- claude_mpm/commander/adapters/registry.py +204 -0
- claude_mpm/commander/api/__init__.py +16 -0
- claude_mpm/commander/api/app.py +121 -0
- claude_mpm/commander/api/errors.py +133 -0
- claude_mpm/commander/api/routes/__init__.py +8 -0
- claude_mpm/commander/api/routes/events.py +184 -0
- claude_mpm/commander/api/routes/inbox.py +171 -0
- claude_mpm/commander/api/routes/messages.py +148 -0
- claude_mpm/commander/api/routes/projects.py +271 -0
- claude_mpm/commander/api/routes/sessions.py +226 -0
- claude_mpm/commander/api/routes/work.py +296 -0
- claude_mpm/commander/api/schemas.py +186 -0
- claude_mpm/commander/chat/__init__.py +7 -0
- claude_mpm/commander/chat/cli.py +149 -0
- claude_mpm/commander/chat/commands.py +124 -0
- claude_mpm/commander/chat/repl.py +1957 -0
- claude_mpm/commander/config.py +51 -0
- claude_mpm/commander/config_loader.py +115 -0
- claude_mpm/commander/core/__init__.py +10 -0
- claude_mpm/commander/core/block_manager.py +325 -0
- claude_mpm/commander/core/response_manager.py +323 -0
- claude_mpm/commander/daemon.py +603 -0
- claude_mpm/commander/env_loader.py +59 -0
- claude_mpm/commander/events/__init__.py +26 -0
- claude_mpm/commander/events/manager.py +392 -0
- claude_mpm/commander/frameworks/__init__.py +12 -0
- claude_mpm/commander/frameworks/base.py +233 -0
- claude_mpm/commander/frameworks/claude_code.py +58 -0
- claude_mpm/commander/frameworks/mpm.py +57 -0
- claude_mpm/commander/git/__init__.py +5 -0
- claude_mpm/commander/git/worktree_manager.py +212 -0
- claude_mpm/commander/inbox/__init__.py +16 -0
- claude_mpm/commander/inbox/dedup.py +128 -0
- claude_mpm/commander/inbox/inbox.py +224 -0
- claude_mpm/commander/inbox/models.py +70 -0
- claude_mpm/commander/instance_manager.py +868 -0
- claude_mpm/commander/llm/__init__.py +6 -0
- claude_mpm/commander/llm/openrouter_client.py +167 -0
- claude_mpm/commander/llm/summarizer.py +70 -0
- claude_mpm/commander/memory/__init__.py +45 -0
- claude_mpm/commander/memory/compression.py +347 -0
- claude_mpm/commander/memory/embeddings.py +230 -0
- claude_mpm/commander/memory/entities.py +310 -0
- claude_mpm/commander/memory/example_usage.py +290 -0
- claude_mpm/commander/memory/integration.py +325 -0
- claude_mpm/commander/memory/search.py +381 -0
- claude_mpm/commander/memory/store.py +657 -0
- claude_mpm/commander/models/__init__.py +18 -0
- claude_mpm/commander/models/events.py +127 -0
- claude_mpm/commander/models/project.py +162 -0
- claude_mpm/commander/models/work.py +214 -0
- claude_mpm/commander/parsing/__init__.py +20 -0
- claude_mpm/commander/parsing/extractor.py +132 -0
- claude_mpm/commander/parsing/output_parser.py +270 -0
- claude_mpm/commander/parsing/patterns.py +100 -0
- claude_mpm/commander/persistence/__init__.py +11 -0
- claude_mpm/commander/persistence/event_store.py +274 -0
- claude_mpm/commander/persistence/state_store.py +403 -0
- claude_mpm/commander/persistence/work_store.py +164 -0
- claude_mpm/commander/polling/__init__.py +13 -0
- claude_mpm/commander/polling/event_detector.py +104 -0
- claude_mpm/commander/polling/output_buffer.py +49 -0
- claude_mpm/commander/polling/output_poller.py +153 -0
- claude_mpm/commander/project_session.py +268 -0
- claude_mpm/commander/proxy/__init__.py +12 -0
- claude_mpm/commander/proxy/formatter.py +89 -0
- claude_mpm/commander/proxy/output_handler.py +191 -0
- claude_mpm/commander/proxy/relay.py +155 -0
- claude_mpm/commander/registry.py +410 -0
- claude_mpm/commander/runtime/__init__.py +10 -0
- claude_mpm/commander/runtime/executor.py +191 -0
- claude_mpm/commander/runtime/monitor.py +346 -0
- claude_mpm/commander/session/__init__.py +6 -0
- claude_mpm/commander/session/context.py +81 -0
- claude_mpm/commander/session/manager.py +59 -0
- claude_mpm/commander/tmux_orchestrator.py +362 -0
- claude_mpm/commander/web/__init__.py +1 -0
- claude_mpm/commander/work/__init__.py +30 -0
- claude_mpm/commander/work/executor.py +207 -0
- claude_mpm/commander/work/queue.py +405 -0
- claude_mpm/commander/workflow/__init__.py +27 -0
- claude_mpm/commander/workflow/event_handler.py +241 -0
- claude_mpm/commander/workflow/notifier.py +146 -0
- claude_mpm/commands/mpm-config.md +8 -0
- claude_mpm/commands/mpm-doctor.md +8 -0
- claude_mpm/commands/mpm-help.md +8 -0
- claude_mpm/commands/mpm-init.md +8 -0
- claude_mpm/commands/mpm-monitor.md +8 -0
- claude_mpm/commands/mpm-organize.md +8 -0
- claude_mpm/commands/mpm-postmortem.md +8 -0
- claude_mpm/commands/mpm-session-resume.md +9 -1
- claude_mpm/commands/mpm-status.md +8 -0
- claude_mpm/commands/mpm-ticket-view.md +8 -0
- claude_mpm/commands/mpm-version.md +8 -0
- claude_mpm/commands/mpm.md +8 -0
- claude_mpm/config/agent_presets.py +8 -7
- claude_mpm/config/skill_sources.py +16 -0
- claude_mpm/constants.py +5 -0
- claude_mpm/core/claude_runner.py +152 -0
- claude_mpm/core/config.py +35 -22
- claude_mpm/core/config_constants.py +74 -9
- claude_mpm/core/constants.py +56 -12
- claude_mpm/core/hook_manager.py +53 -4
- claude_mpm/core/interactive_session.py +5 -4
- claude_mpm/core/logger.py +26 -9
- claude_mpm/core/logging_utils.py +39 -13
- claude_mpm/core/network_config.py +148 -0
- claude_mpm/core/oneshot_session.py +7 -6
- claude_mpm/core/output_style_manager.py +52 -12
- claude_mpm/core/socketio_pool.py +47 -15
- claude_mpm/core/unified_config.py +10 -6
- claude_mpm/core/unified_paths.py +68 -80
- claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.C33zOoyM.css +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.CW1J-YuA.css +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Cs_tUR18.js → 1WZnGYqX.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CDuw-vjf.js → 67pF3qNn.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{bTOqqlTd.js → 6RxdMKe4.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DwBR2MJi.js → 8cZrfX0h.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{ZGh7QtNv.js → 9a6T2nm-.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{D9lljYKQ.js → B443AUzu.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{RJiighC3.js → B8AwtY2H.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{uuIeMWc-.js → BF15LAsF.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{D3k0OPJN.js → BRcwIQNr.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CyWMqx4W.js → BV6nKitt.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CiIAseT4.js → BViJ8lZt.js} +5 -5
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CBBdVcY8.js → BcQ-Q0FE.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{BovzEFCE.js → Bpyvgze_.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BzTRqg-z.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C0Fr8dve.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{eNVUfhuA.js → C3rbW_a-.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{GYwsonyD.js → C8WYN38h.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{BIF9m_hv.js → C9I8FlXH.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{B0uc0UOD.js → CIQcWgO2.js} +3 -3
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Be7GpZd6.js → CIctN7YN.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Bh0LDWpI.js → CKrS_JZW.js} +2 -2
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DUrLdbGD.js → CR6P9C4A.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{B7xVLGWV.js → CRRR9MD_.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CRcR2DqT.js +334 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Dhb8PKl3.js → CSXtMOf0.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{BPYeabCQ.js → CT-sbxSk.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{sQeU3Y1z.js → CWm6DJsp.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CnA0NrzZ.js → CpqQ1Kzn.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{C4B-KCzX.js → D2nGpDRe.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DGkLK5U1.js → D9iCMida.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{BofRWZRR.js → D9ykgMoY.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DmxopI1J.js → DL2Ldur1.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{C30mlcqg.js → DPfltzjH.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Vzk33B_K.js → DR8nis88.js} +2 -2
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DI7hHRFL.js → DUliQN2b.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{C4JcI4KD.js → DXlhR01x.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{bT1r9zLR.js → D_lyTybS.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DZX00Y4g.js → DngoTTgh.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CzZX-COe.js → DqkmHtDC.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{B7RN905-.js → DsDh8EYs.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DLVjFsZ3.js → DypDmXgd.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{iEWssX7S.js → IPYC-LnN.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/JTLiF7dt.js +24 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DaimHw_p.js → JpevfAFt.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DY1XQ8fi.js → R8CEIRAd.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Dle-35c7.js → Zxy7qc-l.js} +2 -2
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/q9Hm6zAU.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{C_Usid8X.js → qtd3IeO4.js} +2 -2
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CzeYkLYB.js → ulBFON_C.js} +2 -2
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Cfqx1Qun.js → wQVh1CoA.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/{app.D6-I5TpK.js → app.Dr7t0z2J.js} +2 -2
- claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.BGhZHUS3.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/{0.m1gL8KXf.js → 0.RgBboRvH.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/{1.CgNOuw-d.js → 1.DG-KkbDf.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.D_jnf-x6.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/version.json +1 -1
- claude_mpm/dashboard/static/svelte-build/index.html +9 -9
- claude_mpm/experimental/cli_enhancements.py +2 -1
- claude_mpm/hooks/claude_hooks/INTEGRATION_EXAMPLE.md +243 -0
- claude_mpm/hooks/claude_hooks/README_AUTO_PAUSE.md +403 -0
- claude_mpm/hooks/claude_hooks/auto_pause_handler.py +485 -0
- claude_mpm/hooks/claude_hooks/event_handlers.py +466 -136
- claude_mpm/hooks/claude_hooks/hook_handler.py +204 -104
- claude_mpm/hooks/claude_hooks/hook_wrapper.sh +6 -11
- claude_mpm/hooks/claude_hooks/installer.py +291 -59
- claude_mpm/hooks/claude_hooks/memory_integration.py +52 -32
- claude_mpm/hooks/claude_hooks/response_tracking.py +43 -60
- claude_mpm/hooks/claude_hooks/services/__init__.py +21 -0
- claude_mpm/hooks/claude_hooks/services/connection_manager.py +41 -26
- claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +38 -105
- claude_mpm/hooks/claude_hooks/services/container.py +326 -0
- claude_mpm/hooks/claude_hooks/services/protocols.py +328 -0
- claude_mpm/hooks/claude_hooks/services/state_manager.py +25 -38
- claude_mpm/hooks/claude_hooks/services/subagent_processor.py +75 -77
- claude_mpm/hooks/session_resume_hook.py +89 -1
- claude_mpm/hooks/templates/pre_tool_use_simple.py +6 -6
- claude_mpm/hooks/templates/pre_tool_use_template.py +16 -8
- claude_mpm/init.py +22 -15
- claude_mpm/mcp/__init__.py +9 -0
- claude_mpm/mcp/google_workspace_server.py +610 -0
- claude_mpm/scripts/claude-hook-handler.sh +46 -19
- claude_mpm/services/agents/agent_recommendation_service.py +8 -8
- claude_mpm/services/agents/agent_selection_service.py +2 -2
- claude_mpm/services/agents/cache_git_manager.py +1 -1
- claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +3 -0
- claude_mpm/services/agents/loading/framework_agent_loader.py +75 -2
- claude_mpm/services/agents/single_tier_deployment_service.py +4 -4
- claude_mpm/services/cli/__init__.py +3 -0
- claude_mpm/services/cli/incremental_pause_manager.py +561 -0
- claude_mpm/services/cli/session_resume_helper.py +10 -2
- claude_mpm/services/command_deployment_service.py +44 -26
- claude_mpm/services/delegation_detector.py +175 -0
- claude_mpm/services/diagnostics/checks/agent_sources_check.py +30 -0
- claude_mpm/services/diagnostics/checks/configuration_check.py +24 -0
- claude_mpm/services/diagnostics/checks/installation_check.py +22 -0
- claude_mpm/services/diagnostics/checks/mcp_services_check.py +23 -0
- claude_mpm/services/diagnostics/doctor_reporter.py +31 -1
- claude_mpm/services/diagnostics/models.py +14 -1
- claude_mpm/services/event_log.py +325 -0
- claude_mpm/services/hook_installer_service.py +77 -8
- claude_mpm/services/infrastructure/__init__.py +4 -0
- claude_mpm/services/infrastructure/context_usage_tracker.py +291 -0
- claude_mpm/services/infrastructure/resume_log_generator.py +24 -5
- claude_mpm/services/mcp_config_manager.py +99 -19
- claude_mpm/services/mcp_service_registry.py +294 -0
- claude_mpm/services/monitor/daemon_manager.py +15 -4
- claude_mpm/services/monitor/management/lifecycle.py +8 -2
- claude_mpm/services/monitor/server.py +111 -16
- claude_mpm/services/pm_skills_deployer.py +261 -87
- claude_mpm/services/skills/git_skill_source_manager.py +130 -10
- claude_mpm/services/skills/selective_skill_deployer.py +142 -16
- claude_mpm/services/skills/skill_discovery_service.py +74 -4
- claude_mpm/services/skills_deployer.py +31 -5
- claude_mpm/services/socketio/handlers/hook.py +14 -7
- claude_mpm/services/socketio/server/main.py +12 -4
- claude_mpm/skills/__init__.py +2 -1
- claude_mpm/skills/bundled/pm/mpm/SKILL.md +38 -0
- claude_mpm/skills/bundled/pm/mpm-agent-update-workflow/SKILL.md +75 -0
- claude_mpm/skills/bundled/pm/mpm-circuit-breaker-enforcement/SKILL.md +476 -0
- claude_mpm/skills/bundled/pm/mpm-config/SKILL.md +29 -0
- claude_mpm/skills/bundled/pm/mpm-doctor/SKILL.md +53 -0
- claude_mpm/skills/bundled/pm/mpm-help/SKILL.md +35 -0
- claude_mpm/skills/bundled/pm/mpm-init/SKILL.md +125 -0
- claude_mpm/skills/bundled/pm/mpm-monitor/SKILL.md +32 -0
- claude_mpm/skills/bundled/pm/mpm-organize/SKILL.md +121 -0
- claude_mpm/skills/bundled/pm/mpm-postmortem/SKILL.md +22 -0
- claude_mpm/skills/bundled/pm/mpm-session-management/SKILL.md +312 -0
- claude_mpm/skills/bundled/pm/mpm-session-pause/SKILL.md +170 -0
- claude_mpm/skills/bundled/pm/mpm-session-resume/SKILL.md +31 -0
- claude_mpm/skills/bundled/pm/mpm-status/SKILL.md +37 -0
- claude_mpm/skills/bundled/pm/{pm-teaching-mode → mpm-teaching-mode}/SKILL.md +2 -2
- claude_mpm/skills/bundled/pm/mpm-ticket-view/SKILL.md +110 -0
- claude_mpm/skills/bundled/pm/mpm-tool-usage-guide/SKILL.md +386 -0
- claude_mpm/skills/bundled/pm/mpm-version/SKILL.md +21 -0
- claude_mpm/skills/registry.py +295 -90
- claude_mpm/skills/skill_manager.py +4 -4
- claude_mpm-5.6.76.dist-info/METADATA +416 -0
- {claude_mpm-5.4.85.dist-info → claude_mpm-5.6.76.dist-info}/RECORD +312 -175
- {claude_mpm-5.4.85.dist-info → claude_mpm-5.6.76.dist-info}/WHEEL +1 -1
- {claude_mpm-5.4.85.dist-info → claude_mpm-5.6.76.dist-info}/entry_points.txt +2 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.DWzvg0-y.css +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.ThTw9_ym.css +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/4TdZjIqw.js +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/5shd3_w0.js +0 -24
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BKjSRqUr.js +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Da0KfYnO.js +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Dfy6j1xT.js +0 -323
- claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.NWzMBYRp.js +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.C0GcWctS.js +0 -1
- claude_mpm-5.4.85.dist-info/METADATA +0 -1023
- /claude_mpm/skills/bundled/pm/{pm-bug-reporting/pm-bug-reporting.md → mpm-bug-reporting/SKILL.md} +0 -0
- /claude_mpm/skills/bundled/pm/{pm-delegation-patterns → mpm-delegation-patterns}/SKILL.md +0 -0
- /claude_mpm/skills/bundled/pm/{pm-git-file-tracking → mpm-git-file-tracking}/SKILL.md +0 -0
- /claude_mpm/skills/bundled/pm/{pm-pr-workflow → mpm-pr-workflow}/SKILL.md +0 -0
- /claude_mpm/skills/bundled/pm/{pm-ticketing-integration → mpm-ticketing-integration}/SKILL.md +0 -0
- /claude_mpm/skills/bundled/pm/{pm-verification-protocols → mpm-verification-protocols}/SKILL.md +0 -0
- {claude_mpm-5.4.85.dist-info → claude_mpm-5.6.76.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-5.4.85.dist-info → claude_mpm-5.6.76.dist-info}/licenses/LICENSE-FAQ.md +0 -0
- {claude_mpm-5.4.85.dist-info → claude_mpm-5.6.76.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
"""Handles output from Claude Code instances."""
|
|
2
|
+
|
|
3
|
+
import hashlib
|
|
4
|
+
import logging
|
|
5
|
+
from dataclasses import dataclass, field
|
|
6
|
+
from datetime import datetime
|
|
7
|
+
|
|
8
|
+
from claude_mpm.commander.llm.summarizer import OutputSummarizer
|
|
9
|
+
from claude_mpm.commander.tmux_orchestrator import TmuxOrchestrator
|
|
10
|
+
|
|
11
|
+
logger = logging.getLogger(__name__)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@dataclass
|
|
15
|
+
class OutputChunk:
|
|
16
|
+
"""Represents a chunk of output from an instance."""
|
|
17
|
+
|
|
18
|
+
instance_name: str
|
|
19
|
+
raw_output: str
|
|
20
|
+
summary: str | None = None
|
|
21
|
+
timestamp: datetime = field(default_factory=datetime.utcnow)
|
|
22
|
+
is_complete: bool = False
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class OutputHandler:
|
|
26
|
+
"""Captures and summarizes output from Claude Code instances."""
|
|
27
|
+
|
|
28
|
+
# Patterns that indicate Claude Code has finished responding
|
|
29
|
+
COMPLETION_PATTERNS = [
|
|
30
|
+
"> ", # Default prompt
|
|
31
|
+
"$ ", # Shell prompt
|
|
32
|
+
"\n> ", # Prompt on new line
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
def __init__(
|
|
36
|
+
self,
|
|
37
|
+
orchestrator: TmuxOrchestrator,
|
|
38
|
+
summarizer: OutputSummarizer | None = None,
|
|
39
|
+
):
|
|
40
|
+
"""Initialize OutputHandler.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
orchestrator: TmuxOrchestrator for capturing output from panes.
|
|
44
|
+
summarizer: Optional OutputSummarizer for long output.
|
|
45
|
+
"""
|
|
46
|
+
self.orchestrator = orchestrator
|
|
47
|
+
self.summarizer = summarizer
|
|
48
|
+
self._output_buffers: dict[str, str] = {}
|
|
49
|
+
self._last_output_hash: dict[str, str] = {}
|
|
50
|
+
|
|
51
|
+
async def capture_output(self, pane_target: str, lines: int = 100) -> str:
|
|
52
|
+
"""Capture raw output from a pane.
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
pane_target: Tmux pane target.
|
|
56
|
+
lines: Number of lines to capture from history.
|
|
57
|
+
|
|
58
|
+
Returns:
|
|
59
|
+
Captured output as string.
|
|
60
|
+
"""
|
|
61
|
+
logger.debug(f"Capturing {lines} lines from pane {pane_target}")
|
|
62
|
+
return self.orchestrator.capture_output(pane_target, lines=lines)
|
|
63
|
+
|
|
64
|
+
def _hash_output(self, output: str) -> str:
|
|
65
|
+
"""Generate hash of output for change detection.
|
|
66
|
+
|
|
67
|
+
Args:
|
|
68
|
+
output: Output text to hash.
|
|
69
|
+
|
|
70
|
+
Returns:
|
|
71
|
+
MD5 hash of the output.
|
|
72
|
+
"""
|
|
73
|
+
# MD5 is sufficient for non-security change detection
|
|
74
|
+
return hashlib.md5(output.encode(), usedforsecurity=False).hexdigest() # nosec B324
|
|
75
|
+
|
|
76
|
+
async def get_new_output(self, instance_name: str, pane_target: str) -> str | None:
|
|
77
|
+
"""Get only new output since last capture (diff-based).
|
|
78
|
+
|
|
79
|
+
Args:
|
|
80
|
+
instance_name: Name of the instance.
|
|
81
|
+
pane_target: Tmux pane target.
|
|
82
|
+
|
|
83
|
+
Returns:
|
|
84
|
+
New output since last capture, or None if no change.
|
|
85
|
+
"""
|
|
86
|
+
current_output = await self.capture_output(pane_target)
|
|
87
|
+
current_hash = self._hash_output(current_output)
|
|
88
|
+
|
|
89
|
+
# Check if output has changed
|
|
90
|
+
last_hash = self._last_output_hash.get(instance_name)
|
|
91
|
+
if last_hash == current_hash:
|
|
92
|
+
logger.debug(f"No new output for {instance_name}")
|
|
93
|
+
return None
|
|
94
|
+
|
|
95
|
+
# Update hash
|
|
96
|
+
self._last_output_hash[instance_name] = current_hash
|
|
97
|
+
|
|
98
|
+
# For first capture, return full output
|
|
99
|
+
if last_hash is None:
|
|
100
|
+
logger.debug(f"First capture for {instance_name}")
|
|
101
|
+
return current_output
|
|
102
|
+
|
|
103
|
+
# Extract new lines by comparing with buffered output
|
|
104
|
+
last_output = self._output_buffers.get(instance_name, "")
|
|
105
|
+
|
|
106
|
+
# Simple diff: if current output contains last output as prefix,
|
|
107
|
+
# return the difference
|
|
108
|
+
if current_output.startswith(last_output):
|
|
109
|
+
new_output = current_output[len(last_output) :]
|
|
110
|
+
logger.debug(f"New output for {instance_name}: {len(new_output)} chars")
|
|
111
|
+
return new_output
|
|
112
|
+
|
|
113
|
+
# If not a simple append, return full current output
|
|
114
|
+
# (pane may have been cleared or output wrapped)
|
|
115
|
+
logger.debug(f"Output changed significantly for {instance_name}")
|
|
116
|
+
return current_output
|
|
117
|
+
|
|
118
|
+
async def process_output(
|
|
119
|
+
self, instance_name: str, pane_target: str, context: str | None = None
|
|
120
|
+
) -> OutputChunk | None:
|
|
121
|
+
"""Capture new output and optionally summarize.
|
|
122
|
+
|
|
123
|
+
Args:
|
|
124
|
+
instance_name: Name of the instance.
|
|
125
|
+
pane_target: Tmux pane target.
|
|
126
|
+
context: Optional context (e.g., what command was sent).
|
|
127
|
+
|
|
128
|
+
Returns:
|
|
129
|
+
OutputChunk with raw and summarized output, or None if no new output.
|
|
130
|
+
"""
|
|
131
|
+
# Get new output
|
|
132
|
+
new_output = await self.get_new_output(instance_name, pane_target)
|
|
133
|
+
if new_output is None:
|
|
134
|
+
return None
|
|
135
|
+
|
|
136
|
+
# Update buffer with full current output
|
|
137
|
+
current_output = await self.capture_output(pane_target)
|
|
138
|
+
self._output_buffers[instance_name] = current_output
|
|
139
|
+
|
|
140
|
+
# Create chunk
|
|
141
|
+
chunk = OutputChunk(
|
|
142
|
+
instance_name=instance_name,
|
|
143
|
+
raw_output=new_output,
|
|
144
|
+
is_complete=self.detect_completion(new_output),
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
# Summarize if needed and summarizer is available
|
|
148
|
+
if self.summarizer and self.summarizer.needs_summarization(new_output):
|
|
149
|
+
try:
|
|
150
|
+
logger.debug(f"Summarizing output for {instance_name}")
|
|
151
|
+
chunk.summary = await self.summarizer.summarize(new_output, context)
|
|
152
|
+
except Exception as e:
|
|
153
|
+
logger.error(f"Failed to summarize output: {e}")
|
|
154
|
+
# Continue without summary
|
|
155
|
+
|
|
156
|
+
return chunk
|
|
157
|
+
|
|
158
|
+
def detect_completion(self, output: str) -> bool:
|
|
159
|
+
"""Detect if Claude Code has finished responding (prompt returned).
|
|
160
|
+
|
|
161
|
+
Args:
|
|
162
|
+
output: Output text to check.
|
|
163
|
+
|
|
164
|
+
Returns:
|
|
165
|
+
True if output ends with a completion pattern.
|
|
166
|
+
"""
|
|
167
|
+
if not output:
|
|
168
|
+
return False
|
|
169
|
+
|
|
170
|
+
# Strip only trailing newlines/tabs/carriage returns, keep spaces
|
|
171
|
+
output_check = output.rstrip("\n\t\r")
|
|
172
|
+
|
|
173
|
+
for pattern in self.COMPLETION_PATTERNS:
|
|
174
|
+
# Check if output ends with the exact pattern
|
|
175
|
+
if output_check.endswith(pattern):
|
|
176
|
+
return True
|
|
177
|
+
|
|
178
|
+
# Special handling for trailing whitespace:
|
|
179
|
+
# If pattern has trailing space and output has extra trailing spaces,
|
|
180
|
+
# still match (e.g., "> " should match "> " pattern)
|
|
181
|
+
if pattern.endswith(" "):
|
|
182
|
+
pattern_base = pattern.rstrip(" ")
|
|
183
|
+
# Check if after stripping spaces, we have pattern_base followed by at least one space
|
|
184
|
+
output_stripped_spaces = output_check.rstrip(" ")
|
|
185
|
+
# Check: output must end with pattern_base + at least one space
|
|
186
|
+
if output_stripped_spaces.endswith(pattern_base) and len(
|
|
187
|
+
output_check
|
|
188
|
+
) > len(output_stripped_spaces):
|
|
189
|
+
return True
|
|
190
|
+
|
|
191
|
+
return False
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
"""Relays output from instances to user."""
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
import logging
|
|
5
|
+
from typing import Awaitable, Callable
|
|
6
|
+
|
|
7
|
+
from .formatter import OutputFormatter
|
|
8
|
+
from .output_handler import OutputHandler
|
|
9
|
+
|
|
10
|
+
logger = logging.getLogger(__name__)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class OutputRelay:
|
|
14
|
+
"""Relays instance output to user with summarization."""
|
|
15
|
+
|
|
16
|
+
def __init__(
|
|
17
|
+
self,
|
|
18
|
+
handler: OutputHandler,
|
|
19
|
+
formatter: OutputFormatter,
|
|
20
|
+
on_output: Callable[[str], Awaitable[None]] | None = None,
|
|
21
|
+
):
|
|
22
|
+
"""Initialize OutputRelay.
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
handler: OutputHandler for capturing output.
|
|
26
|
+
formatter: OutputFormatter for display formatting.
|
|
27
|
+
on_output: Optional callback to display output.
|
|
28
|
+
"""
|
|
29
|
+
self.handler = handler
|
|
30
|
+
self.formatter = formatter
|
|
31
|
+
self.on_output = on_output
|
|
32
|
+
self._monitoring: dict[str, asyncio.Task] = {}
|
|
33
|
+
|
|
34
|
+
async def _monitor_output(
|
|
35
|
+
self, instance_name: str, pane_target: str, poll_interval: float
|
|
36
|
+
) -> None:
|
|
37
|
+
"""Monitor output from an instance continuously.
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
instance_name: Name of the instance.
|
|
41
|
+
pane_target: Tmux pane target.
|
|
42
|
+
poll_interval: Seconds between polls.
|
|
43
|
+
"""
|
|
44
|
+
logger.info(f"Starting output relay for {instance_name}")
|
|
45
|
+
|
|
46
|
+
try:
|
|
47
|
+
while True:
|
|
48
|
+
# Process output
|
|
49
|
+
chunk = await self.handler.process_output(instance_name, pane_target)
|
|
50
|
+
|
|
51
|
+
# If we got new output, format and display
|
|
52
|
+
if chunk and self.on_output:
|
|
53
|
+
# Use summary format if available, otherwise raw
|
|
54
|
+
if chunk.summary:
|
|
55
|
+
output = self.formatter.format_summary(chunk)
|
|
56
|
+
else:
|
|
57
|
+
output = self.formatter.format_raw(chunk)
|
|
58
|
+
|
|
59
|
+
await self.on_output(output)
|
|
60
|
+
|
|
61
|
+
# Wait before next poll
|
|
62
|
+
await asyncio.sleep(poll_interval)
|
|
63
|
+
|
|
64
|
+
except asyncio.CancelledError:
|
|
65
|
+
logger.info(f"Output relay cancelled for {instance_name}")
|
|
66
|
+
raise
|
|
67
|
+
except Exception as e:
|
|
68
|
+
logger.error(f"Error in output relay for {instance_name}: {e}")
|
|
69
|
+
if self.on_output:
|
|
70
|
+
error_msg = self.formatter.format_error(instance_name, str(e))
|
|
71
|
+
try:
|
|
72
|
+
await self.on_output(error_msg)
|
|
73
|
+
except Exception: # nosec B110
|
|
74
|
+
# Intentionally ignore errors in error reporting to avoid cascading failures
|
|
75
|
+
pass
|
|
76
|
+
raise
|
|
77
|
+
|
|
78
|
+
async def start_relay(
|
|
79
|
+
self, instance_name: str, pane_target: str, poll_interval: float = 0.5
|
|
80
|
+
) -> None:
|
|
81
|
+
"""Start relaying output from an instance.
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
instance_name: Name of the instance.
|
|
85
|
+
pane_target: Tmux pane target.
|
|
86
|
+
poll_interval: Seconds between polls (default: 0.5).
|
|
87
|
+
"""
|
|
88
|
+
# Stop existing relay if any
|
|
89
|
+
if instance_name in self._monitoring:
|
|
90
|
+
await self.stop_relay(instance_name)
|
|
91
|
+
|
|
92
|
+
# Start monitoring task
|
|
93
|
+
task = asyncio.create_task(
|
|
94
|
+
self._monitor_output(instance_name, pane_target, poll_interval)
|
|
95
|
+
)
|
|
96
|
+
self._monitoring[instance_name] = task
|
|
97
|
+
|
|
98
|
+
logger.info(f"Started output relay for {instance_name}")
|
|
99
|
+
|
|
100
|
+
async def stop_relay(self, instance_name: str) -> None:
|
|
101
|
+
"""Stop relaying output from an instance.
|
|
102
|
+
|
|
103
|
+
Args:
|
|
104
|
+
instance_name: Name of the instance.
|
|
105
|
+
"""
|
|
106
|
+
task = self._monitoring.pop(instance_name, None)
|
|
107
|
+
if task:
|
|
108
|
+
task.cancel()
|
|
109
|
+
try:
|
|
110
|
+
await task
|
|
111
|
+
except asyncio.CancelledError:
|
|
112
|
+
pass
|
|
113
|
+
|
|
114
|
+
logger.info(f"Stopped output relay for {instance_name}")
|
|
115
|
+
|
|
116
|
+
async def stop_all(self) -> None:
|
|
117
|
+
"""Stop all output relays."""
|
|
118
|
+
logger.info("Stopping all output relays")
|
|
119
|
+
|
|
120
|
+
# Cancel all tasks
|
|
121
|
+
tasks = list(self._monitoring.values())
|
|
122
|
+
for task in tasks:
|
|
123
|
+
task.cancel()
|
|
124
|
+
|
|
125
|
+
# Wait for cancellation
|
|
126
|
+
await asyncio.gather(*tasks, return_exceptions=True)
|
|
127
|
+
|
|
128
|
+
self._monitoring.clear()
|
|
129
|
+
|
|
130
|
+
async def get_latest_output(
|
|
131
|
+
self, instance_name: str, pane_target: str, context: str | None = None
|
|
132
|
+
) -> str:
|
|
133
|
+
"""Get and format latest output from instance.
|
|
134
|
+
|
|
135
|
+
Args:
|
|
136
|
+
instance_name: Name of the instance.
|
|
137
|
+
pane_target: Tmux pane target.
|
|
138
|
+
context: Optional context for summarization.
|
|
139
|
+
|
|
140
|
+
Returns:
|
|
141
|
+
Formatted output string.
|
|
142
|
+
"""
|
|
143
|
+
# Process output once
|
|
144
|
+
chunk = await self.handler.process_output(
|
|
145
|
+
instance_name, pane_target, context=context
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
if chunk is None:
|
|
149
|
+
return self.formatter.format_status(instance_name, "No new output")
|
|
150
|
+
|
|
151
|
+
# Format with summary if available
|
|
152
|
+
if chunk.summary:
|
|
153
|
+
return self.formatter.format_summary(chunk)
|
|
154
|
+
|
|
155
|
+
return self.formatter.format_raw(chunk)
|