claude-mpm 5.4.41__py3-none-any.whl → 5.6.23__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of claude-mpm might be problematic. Click here for more details.
- claude_mpm/VERSION +1 -1
- claude_mpm/agents/CLAUDE_MPM_OUTPUT_STYLE.md +66 -241
- claude_mpm/agents/CLAUDE_MPM_RESEARCH_OUTPUT_STYLE.md +413 -0
- claude_mpm/agents/CLAUDE_MPM_TEACHER_OUTPUT_STYLE.md +109 -1925
- claude_mpm/agents/PM_INSTRUCTIONS.md +161 -298
- claude_mpm/agents/WORKFLOW.md +2 -0
- claude_mpm/agents/templates/circuit-breakers.md +26 -17
- claude_mpm/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 +182 -32
- 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 +2 -3
- claude_mpm/cli/startup.py +527 -506
- 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 +35 -11
- 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 +63 -18
- claude_mpm/core/shared/config_loader.py +3 -1
- claude_mpm/core/socketio_pool.py +13 -5
- 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 +305 -87
- claude_mpm/hooks/claude_hooks/hook_handler.py +106 -89
- claude_mpm/hooks/claude_hooks/hook_wrapper.sh +6 -11
- claude_mpm/hooks/claude_hooks/installer.py +116 -8
- claude_mpm/hooks/claude_hooks/memory_integration.py +51 -31
- claude_mpm/hooks/claude_hooks/response_tracking.py +42 -59
- claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.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 +39 -24
- claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +36 -103
- claude_mpm/hooks/claude_hooks/services/state_manager.py +23 -36
- claude_mpm/hooks/claude_hooks/services/subagent_processor.py +73 -75
- claude_mpm/hooks/kuzu_memory_hook.py +5 -5
- claude_mpm/hooks/session_resume_hook.py +89 -1
- claude_mpm/hooks/templates/pre_tool_use_template.py +10 -2
- claude_mpm/init.py +215 -2
- claude_mpm/scripts/claude-hook-handler.sh +43 -16
- claude_mpm/services/agents/agent_recommendation_service.py +8 -8
- claude_mpm/services/agents/agent_selection_service.py +2 -2
- claude_mpm/services/agents/cache_git_manager.py +1 -1
- claude_mpm/services/agents/deployment/agent_discovery_service.py +3 -1
- claude_mpm/services/agents/deployment/agent_format_converter.py +25 -13
- claude_mpm/services/agents/deployment/agent_template_builder.py +37 -17
- claude_mpm/services/agents/deployment/async_agent_deployment.py +31 -27
- claude_mpm/services/agents/deployment/deployment_reconciler.py +577 -0
- claude_mpm/services/agents/deployment/local_template_deployment.py +3 -1
- claude_mpm/services/agents/deployment/multi_source_deployment_service.py +36 -8
- claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +50 -26
- claude_mpm/services/agents/deployment/startup_reconciliation.py +138 -0
- claude_mpm/services/agents/git_source_manager.py +21 -2
- claude_mpm/services/agents/loading/framework_agent_loader.py +75 -2
- claude_mpm/services/agents/single_tier_deployment_service.py +4 -4
- claude_mpm/services/agents/sources/git_source_sync_service.py +116 -5
- claude_mpm/services/agents/startup_sync.py +5 -2
- claude_mpm/services/cli/__init__.py +3 -0
- claude_mpm/services/cli/incremental_pause_manager.py +561 -0
- claude_mpm/services/cli/session_resume_helper.py +10 -2
- claude_mpm/services/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/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 +302 -94
- claude_mpm/services/profile_manager.py +10 -4
- claude_mpm/services/skills/git_skill_source_manager.py +192 -29
- claude_mpm/services/skills/selective_skill_deployer.py +211 -46
- claude_mpm/services/skills/skill_discovery_service.py +74 -4
- claude_mpm/services/skills_deployer.py +192 -70
- claude_mpm/services/socketio/handlers/hook.py +14 -7
- claude_mpm/services/socketio/server/main.py +12 -4
- claude_mpm/skills/__init__.py +2 -1
- claude_mpm/skills/bundled/collaboration/brainstorming/SKILL.md +79 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/SKILL.md +178 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/agent-prompts.md +577 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/coordination-patterns.md +467 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/examples.md +537 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/troubleshooting.md +730 -0
- claude_mpm/skills/bundled/collaboration/git-worktrees.md +317 -0
- claude_mpm/skills/bundled/collaboration/requesting-code-review/SKILL.md +112 -0
- claude_mpm/skills/bundled/collaboration/requesting-code-review/references/code-reviewer-template.md +146 -0
- claude_mpm/skills/bundled/collaboration/requesting-code-review/references/review-examples.md +412 -0
- claude_mpm/skills/bundled/collaboration/stacked-prs.md +251 -0
- claude_mpm/skills/bundled/collaboration/writing-plans/SKILL.md +81 -0
- claude_mpm/skills/bundled/collaboration/writing-plans/references/best-practices.md +362 -0
- claude_mpm/skills/bundled/collaboration/writing-plans/references/plan-structure-templates.md +312 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/SKILL.md +152 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/advanced-techniques.md +668 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/examples.md +587 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/integration.md +438 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/tracing-techniques.md +391 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/CREATION-LOG.md +119 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/SKILL.md +148 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/anti-patterns.md +483 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/examples.md +452 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/troubleshooting.md +449 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/workflow.md +411 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-academic.md +14 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-1.md +58 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-2.md +68 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-3.md +69 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/SKILL.md +131 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/gate-function.md +325 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/integration-and-workflows.md +490 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/red-flags-and-failures.md +425 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/verification-patterns.md +499 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/INTEGRATION.md +611 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/README.md +596 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/SKILL.md +260 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/examples/nextjs-env-structure.md +315 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/references/frameworks.md +436 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/references/security.md +433 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/references/synchronization.md +452 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/references/troubleshooting.md +404 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/references/validation.md +420 -0
- claude_mpm/skills/bundled/main/artifacts-builder/SKILL.md +86 -0
- claude_mpm/skills/bundled/main/internal-comms/SKILL.md +43 -0
- claude_mpm/skills/bundled/main/internal-comms/examples/3p-updates.md +47 -0
- claude_mpm/skills/bundled/main/internal-comms/examples/company-newsletter.md +65 -0
- claude_mpm/skills/bundled/main/internal-comms/examples/faq-answers.md +30 -0
- claude_mpm/skills/bundled/main/internal-comms/examples/general-comms.md +16 -0
- claude_mpm/skills/bundled/main/mcp-builder/SKILL.md +160 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/design_principles.md +412 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/evaluation.md +602 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/mcp_best_practices.md +915 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/node_mcp_server.md +916 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/python_mcp_server.md +752 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/workflow.md +1237 -0
- claude_mpm/skills/bundled/main/skill-creator/SKILL.md +189 -0
- claude_mpm/skills/bundled/main/skill-creator/references/best-practices.md +500 -0
- claude_mpm/skills/bundled/main/skill-creator/references/creation-workflow.md +464 -0
- claude_mpm/skills/bundled/main/skill-creator/references/examples.md +619 -0
- claude_mpm/skills/bundled/main/skill-creator/references/progressive-disclosure.md +437 -0
- claude_mpm/skills/bundled/main/skill-creator/references/skill-structure.md +231 -0
- claude_mpm/skills/bundled/php/espocrm-development/SKILL.md +170 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/architecture.md +602 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/common-tasks.md +821 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/development-workflow.md +742 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/frontend-customization.md +726 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/hooks-and-services.md +764 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/testing-debugging.md +831 -0
- claude_mpm/skills/bundled/pm/mpm/SKILL.md +38 -0
- claude_mpm/skills/bundled/pm/mpm-agent-update-workflow/SKILL.md +75 -0
- claude_mpm/skills/bundled/pm/mpm-bug-reporting/SKILL.md +248 -0
- claude_mpm/skills/bundled/pm/mpm-circuit-breaker-enforcement/SKILL.md +476 -0
- claude_mpm/skills/bundled/pm/mpm-config/SKILL.md +29 -0
- claude_mpm/skills/bundled/pm/mpm-delegation-patterns/SKILL.md +167 -0
- claude_mpm/skills/bundled/pm/mpm-doctor/SKILL.md +53 -0
- claude_mpm/skills/bundled/pm/mpm-git-file-tracking/SKILL.md +113 -0
- claude_mpm/skills/bundled/pm/mpm-help/SKILL.md +35 -0
- claude_mpm/skills/bundled/pm/mpm-init/SKILL.md +125 -0
- claude_mpm/skills/bundled/pm/mpm-monitor/SKILL.md +32 -0
- claude_mpm/skills/bundled/pm/mpm-organize/SKILL.md +121 -0
- claude_mpm/skills/bundled/pm/mpm-postmortem/SKILL.md +22 -0
- claude_mpm/skills/bundled/pm/mpm-pr-workflow/SKILL.md +124 -0
- claude_mpm/skills/bundled/pm/mpm-session-management/SKILL.md +312 -0
- claude_mpm/skills/bundled/pm/mpm-session-pause/SKILL.md +170 -0
- claude_mpm/skills/bundled/pm/mpm-session-resume/SKILL.md +31 -0
- claude_mpm/skills/bundled/pm/mpm-status/SKILL.md +37 -0
- claude_mpm/skills/bundled/pm/mpm-teaching-mode/SKILL.md +657 -0
- claude_mpm/skills/bundled/pm/mpm-ticket-view/SKILL.md +110 -0
- claude_mpm/skills/bundled/pm/mpm-ticketing-integration/SKILL.md +154 -0
- claude_mpm/skills/bundled/pm/mpm-tool-usage-guide/SKILL.md +386 -0
- claude_mpm/skills/bundled/pm/mpm-verification-protocols/SKILL.md +198 -0
- claude_mpm/skills/bundled/pm/mpm-version/SKILL.md +21 -0
- claude_mpm/skills/bundled/react/flexlayout-react.md +742 -0
- claude_mpm/skills/bundled/rust/desktop-applications/SKILL.md +226 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/architecture-patterns.md +901 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/native-gui-frameworks.md +901 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/platform-integration.md +775 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/state-management.md +937 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/tauri-framework.md +770 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/testing-deployment.md +961 -0
- claude_mpm/skills/bundled/security-scanning.md +112 -0
- claude_mpm/skills/bundled/tauri/tauri-async-patterns.md +495 -0
- claude_mpm/skills/bundled/tauri/tauri-build-deploy.md +599 -0
- claude_mpm/skills/bundled/tauri/tauri-command-patterns.md +535 -0
- claude_mpm/skills/bundled/tauri/tauri-error-handling.md +613 -0
- claude_mpm/skills/bundled/tauri/tauri-event-system.md +648 -0
- claude_mpm/skills/bundled/tauri/tauri-file-system.md +673 -0
- claude_mpm/skills/bundled/tauri/tauri-frontend-integration.md +767 -0
- claude_mpm/skills/bundled/tauri/tauri-performance.md +669 -0
- claude_mpm/skills/bundled/tauri/tauri-state-management.md +573 -0
- claude_mpm/skills/bundled/tauri/tauri-testing.md +384 -0
- claude_mpm/skills/bundled/tauri/tauri-window-management.md +628 -0
- claude_mpm/skills/bundled/testing/condition-based-waiting/SKILL.md +119 -0
- claude_mpm/skills/bundled/testing/condition-based-waiting/references/patterns-and-implementation.md +253 -0
- claude_mpm/skills/bundled/testing/test-driven-development/SKILL.md +145 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/anti-patterns.md +543 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/examples.md +741 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/integration.md +470 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/philosophy.md +458 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/workflow.md +639 -0
- claude_mpm/skills/bundled/testing/test-quality-inspector/SKILL.md +458 -0
- claude_mpm/skills/bundled/testing/test-quality-inspector/examples/example-inspection-report.md +411 -0
- claude_mpm/skills/bundled/testing/test-quality-inspector/references/assertion-quality.md +317 -0
- claude_mpm/skills/bundled/testing/test-quality-inspector/references/inspection-checklist.md +270 -0
- claude_mpm/skills/bundled/testing/test-quality-inspector/references/red-flags.md +436 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/SKILL.md +140 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/completeness-anti-patterns.md +572 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/core-anti-patterns.md +411 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/detection-guide.md +569 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/tdd-connection.md +695 -0
- claude_mpm/skills/bundled/testing/webapp-testing/SKILL.md +184 -0
- claude_mpm/skills/bundled/testing/webapp-testing/decision-tree.md +459 -0
- claude_mpm/skills/bundled/testing/webapp-testing/playwright-patterns.md +479 -0
- claude_mpm/skills/bundled/testing/webapp-testing/reconnaissance-pattern.md +687 -0
- claude_mpm/skills/bundled/testing/webapp-testing/server-management.md +758 -0
- claude_mpm/skills/bundled/testing/webapp-testing/troubleshooting.md +868 -0
- claude_mpm/skills/registry.py +295 -90
- claude_mpm/skills/skill_manager.py +29 -23
- claude_mpm/templates/.pre-commit-config.yaml +112 -0
- claude_mpm/utils/agent_dependency_loader.py +103 -4
- claude_mpm/utils/robust_installer.py +45 -24
- claude_mpm-5.6.23.dist-info/METADATA +393 -0
- {claude_mpm-5.4.41.dist-info → claude_mpm-5.6.23.dist-info}/RECORD +447 -149
- claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.B_FtCwCQ.css +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.Cl_eSA4x.css +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BgChzWQ1.js +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CIXEwuWe.js +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CWc5urbQ.js +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DMkZpdF2.js +0 -2
- claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/app.DTL5mJO-.js +0 -2
- claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.DzuEhzqh.js +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/1.DFLC8jdE.js +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.DPvEihJJ.js +0 -10
- claude_mpm/hooks/claude_hooks/__pycache__/installer.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager.cpython-311.pyc +0 -0
- claude_mpm-5.4.41.dist-info/METADATA +0 -998
- {claude_mpm-5.4.41.dist-info → claude_mpm-5.6.23.dist-info}/WHEEL +0 -0
- {claude_mpm-5.4.41.dist-info → claude_mpm-5.6.23.dist-info}/entry_points.txt +0 -0
- {claude_mpm-5.4.41.dist-info → claude_mpm-5.6.23.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-5.4.41.dist-info → claude_mpm-5.6.23.dist-info}/licenses/LICENSE-FAQ.md +0 -0
- {claude_mpm-5.4.41.dist-info → claude_mpm-5.6.23.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
"""Session management endpoints for MPM Commander API.
|
|
2
|
+
|
|
3
|
+
This module implements REST endpoints for creating and managing tool sessions
|
|
4
|
+
(Claude Code, Aider, etc.) within projects.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import logging
|
|
8
|
+
import subprocess # nosec B404 - needed for tmux error handling
|
|
9
|
+
import uuid
|
|
10
|
+
from typing import List
|
|
11
|
+
|
|
12
|
+
from fastapi import APIRouter, Request, Response
|
|
13
|
+
|
|
14
|
+
from ...models import ToolSession
|
|
15
|
+
from ..errors import (
|
|
16
|
+
InvalidRuntimeError,
|
|
17
|
+
ProjectNotFoundError,
|
|
18
|
+
SessionNotFoundError,
|
|
19
|
+
TmuxNoSpaceError,
|
|
20
|
+
)
|
|
21
|
+
from ..schemas import CreateSessionRequest, SessionResponse
|
|
22
|
+
|
|
23
|
+
router = APIRouter()
|
|
24
|
+
logger = logging.getLogger(__name__)
|
|
25
|
+
|
|
26
|
+
# Valid runtime adapters (Phase 1: claude-code only)
|
|
27
|
+
VALID_RUNTIMES = {"claude-code"}
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _get_registry(request: Request):
|
|
31
|
+
"""Get registry instance from app.state."""
|
|
32
|
+
if not hasattr(request.app.state, "registry") or request.app.state.registry is None:
|
|
33
|
+
raise RuntimeError("Registry not initialized")
|
|
34
|
+
return request.app.state.registry
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _get_tmux(request: Request):
|
|
38
|
+
"""Get tmux orchestrator instance from app.state."""
|
|
39
|
+
if not hasattr(request.app.state, "tmux") or request.app.state.tmux is None:
|
|
40
|
+
raise RuntimeError("Tmux orchestrator not initialized")
|
|
41
|
+
return request.app.state.tmux
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _session_to_response(session: ToolSession) -> SessionResponse:
|
|
45
|
+
"""Convert ToolSession model to SessionResponse schema.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
session: ToolSession instance
|
|
49
|
+
|
|
50
|
+
Returns:
|
|
51
|
+
SessionResponse with session data
|
|
52
|
+
"""
|
|
53
|
+
return SessionResponse(
|
|
54
|
+
id=session.id,
|
|
55
|
+
project_id=session.project_id,
|
|
56
|
+
runtime=session.runtime,
|
|
57
|
+
tmux_target=session.tmux_target,
|
|
58
|
+
status=session.status,
|
|
59
|
+
created_at=session.created_at,
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
@router.get("/projects/{project_id}/sessions", response_model=List[SessionResponse])
|
|
64
|
+
async def list_sessions(request: Request, project_id: str) -> List[SessionResponse]:
|
|
65
|
+
"""List all sessions for a project.
|
|
66
|
+
|
|
67
|
+
Args:
|
|
68
|
+
project_id: Unique project identifier
|
|
69
|
+
|
|
70
|
+
Returns:
|
|
71
|
+
List of session information (may be empty)
|
|
72
|
+
|
|
73
|
+
Raises:
|
|
74
|
+
ProjectNotFoundError: If project_id doesn't exist
|
|
75
|
+
|
|
76
|
+
Example:
|
|
77
|
+
GET /api/projects/abc-123/sessions
|
|
78
|
+
Response: [
|
|
79
|
+
{
|
|
80
|
+
"id": "sess-456",
|
|
81
|
+
"project_id": "abc-123",
|
|
82
|
+
"runtime": "claude-code",
|
|
83
|
+
"tmux_target": "%1",
|
|
84
|
+
"status": "running",
|
|
85
|
+
"created_at": "2025-01-12T10:00:00Z"
|
|
86
|
+
}
|
|
87
|
+
]
|
|
88
|
+
"""
|
|
89
|
+
registry = _get_registry(request)
|
|
90
|
+
project = registry.get(project_id)
|
|
91
|
+
|
|
92
|
+
if project is None:
|
|
93
|
+
raise ProjectNotFoundError(project_id)
|
|
94
|
+
|
|
95
|
+
# Convert sessions dict to list of responses
|
|
96
|
+
return [_session_to_response(s) for s in project.sessions.values()]
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
@router.post(
|
|
100
|
+
"/projects/{project_id}/sessions", response_model=SessionResponse, status_code=201
|
|
101
|
+
)
|
|
102
|
+
async def create_session(
|
|
103
|
+
request: Request, project_id: str, req: CreateSessionRequest
|
|
104
|
+
) -> SessionResponse:
|
|
105
|
+
"""Create a new session for a project.
|
|
106
|
+
|
|
107
|
+
Creates a new tmux pane and initializes the specified runtime adapter.
|
|
108
|
+
|
|
109
|
+
Args:
|
|
110
|
+
project_id: Unique project identifier
|
|
111
|
+
req: Session creation request
|
|
112
|
+
|
|
113
|
+
Returns:
|
|
114
|
+
Newly created session information
|
|
115
|
+
|
|
116
|
+
Raises:
|
|
117
|
+
ProjectNotFoundError: If project_id doesn't exist
|
|
118
|
+
InvalidRuntimeError: If runtime is not supported
|
|
119
|
+
TmuxNoSpaceError: If tmux has no space for new pane
|
|
120
|
+
|
|
121
|
+
Example:
|
|
122
|
+
POST /api/projects/abc-123/sessions
|
|
123
|
+
Body: {
|
|
124
|
+
"runtime": "claude-code",
|
|
125
|
+
"agent_prompt": "You are a helpful coding assistant"
|
|
126
|
+
}
|
|
127
|
+
Response: {
|
|
128
|
+
"id": "sess-456",
|
|
129
|
+
"project_id": "abc-123",
|
|
130
|
+
"runtime": "claude-code",
|
|
131
|
+
"tmux_target": "%1",
|
|
132
|
+
"status": "initializing",
|
|
133
|
+
"created_at": "2025-01-12T10:00:00Z"
|
|
134
|
+
}
|
|
135
|
+
"""
|
|
136
|
+
registry = _get_registry(request)
|
|
137
|
+
tmux_orch = _get_tmux(request)
|
|
138
|
+
|
|
139
|
+
# Validate project exists
|
|
140
|
+
project = registry.get(project_id)
|
|
141
|
+
if project is None:
|
|
142
|
+
raise ProjectNotFoundError(project_id)
|
|
143
|
+
|
|
144
|
+
# Validate runtime
|
|
145
|
+
if req.runtime not in VALID_RUNTIMES:
|
|
146
|
+
raise InvalidRuntimeError(req.runtime)
|
|
147
|
+
|
|
148
|
+
# Generate session ID
|
|
149
|
+
session_id = str(uuid.uuid4())
|
|
150
|
+
|
|
151
|
+
# Create tmux pane for session
|
|
152
|
+
try:
|
|
153
|
+
tmux_target = tmux_orch.create_pane(
|
|
154
|
+
pane_id=f"{project.name}-{req.runtime}",
|
|
155
|
+
working_dir=project.path,
|
|
156
|
+
)
|
|
157
|
+
except subprocess.CalledProcessError as e:
|
|
158
|
+
stderr = e.stderr.decode() if e.stderr else ""
|
|
159
|
+
if "no space for new pane" in stderr.lower():
|
|
160
|
+
raise TmuxNoSpaceError() from None
|
|
161
|
+
raise # Re-raise other subprocess errors
|
|
162
|
+
|
|
163
|
+
# Create session object
|
|
164
|
+
session = ToolSession(
|
|
165
|
+
id=session_id,
|
|
166
|
+
project_id=project_id,
|
|
167
|
+
runtime=req.runtime,
|
|
168
|
+
tmux_target=tmux_target,
|
|
169
|
+
status="initializing",
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
# Add session to project
|
|
173
|
+
registry.add_session(project_id, session)
|
|
174
|
+
|
|
175
|
+
# TODO: Start runtime adapter in pane (Phase 2)
|
|
176
|
+
# For Phase 1, session stays in "initializing" state
|
|
177
|
+
|
|
178
|
+
return _session_to_response(session)
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
@router.delete("/sessions/{session_id}", status_code=204)
|
|
182
|
+
async def stop_session(request: Request, session_id: str) -> Response:
|
|
183
|
+
"""Stop and remove a session.
|
|
184
|
+
|
|
185
|
+
Kills the tmux pane and removes the session from its project.
|
|
186
|
+
|
|
187
|
+
Args:
|
|
188
|
+
session_id: Unique session identifier
|
|
189
|
+
|
|
190
|
+
Returns:
|
|
191
|
+
Empty response with 204 status
|
|
192
|
+
|
|
193
|
+
Raises:
|
|
194
|
+
SessionNotFoundError: If session_id doesn't exist
|
|
195
|
+
|
|
196
|
+
Example:
|
|
197
|
+
DELETE /api/sessions/sess-456
|
|
198
|
+
Response: 204 No Content
|
|
199
|
+
"""
|
|
200
|
+
registry = _get_registry(request)
|
|
201
|
+
tmux_orch = _get_tmux(request)
|
|
202
|
+
|
|
203
|
+
# Find session across all projects
|
|
204
|
+
session = None
|
|
205
|
+
parent_project_id = None
|
|
206
|
+
|
|
207
|
+
for project in registry.list_all():
|
|
208
|
+
if session_id in project.sessions:
|
|
209
|
+
session = project.sessions[session_id]
|
|
210
|
+
parent_project_id = project.id
|
|
211
|
+
break
|
|
212
|
+
|
|
213
|
+
if session is None or parent_project_id is None:
|
|
214
|
+
raise SessionNotFoundError(session_id)
|
|
215
|
+
|
|
216
|
+
# Kill tmux pane
|
|
217
|
+
try:
|
|
218
|
+
tmux_orch.kill_pane(session.tmux_target)
|
|
219
|
+
except Exception as e:
|
|
220
|
+
# Pane may already be dead, continue with cleanup
|
|
221
|
+
logger.debug("Failed to kill pane (may already be dead): %s", e)
|
|
222
|
+
|
|
223
|
+
# Remove session from project
|
|
224
|
+
registry.remove_session(parent_project_id, session_id)
|
|
225
|
+
|
|
226
|
+
return Response(status_code=204)
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
"""Work queue management endpoints for MPM Commander API.
|
|
2
|
+
|
|
3
|
+
This module implements REST endpoints for managing work items
|
|
4
|
+
in project work queues.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import Dict, List, Optional
|
|
8
|
+
|
|
9
|
+
from fastapi import APIRouter, HTTPException, Query, Request
|
|
10
|
+
|
|
11
|
+
from ...models.work import WorkPriority, WorkState
|
|
12
|
+
from ...work import WorkQueue
|
|
13
|
+
from ..schemas import CreateWorkRequest, WorkItemResponse
|
|
14
|
+
|
|
15
|
+
router = APIRouter()
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _get_registry(request: Request):
|
|
19
|
+
"""Get registry instance from app.state."""
|
|
20
|
+
if not hasattr(request.app.state, "registry") or request.app.state.registry is None:
|
|
21
|
+
raise RuntimeError("Registry not initialized")
|
|
22
|
+
return request.app.state.registry
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _get_work_queues(request: Request) -> Dict:
|
|
26
|
+
"""Get work queues dict from app.state (shared with daemon)."""
|
|
27
|
+
if (
|
|
28
|
+
not hasattr(request.app.state, "work_queues")
|
|
29
|
+
or request.app.state.work_queues is None
|
|
30
|
+
):
|
|
31
|
+
raise RuntimeError("Work queues not initialized")
|
|
32
|
+
return request.app.state.work_queues
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _get_daemon(request: Request):
|
|
36
|
+
"""Get daemon instance from app.state."""
|
|
37
|
+
if not hasattr(request.app.state, "daemon_instance"):
|
|
38
|
+
return None
|
|
39
|
+
return request.app.state.daemon_instance
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _work_item_to_response(work_item) -> WorkItemResponse:
|
|
43
|
+
"""Convert WorkItem model to WorkItemResponse schema.
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
work_item: WorkItem instance
|
|
47
|
+
|
|
48
|
+
Returns:
|
|
49
|
+
WorkItemResponse with all work item data
|
|
50
|
+
"""
|
|
51
|
+
return WorkItemResponse(
|
|
52
|
+
id=work_item.id,
|
|
53
|
+
project_id=work_item.project_id,
|
|
54
|
+
content=work_item.content,
|
|
55
|
+
state=work_item.state.value,
|
|
56
|
+
priority=work_item.priority.value,
|
|
57
|
+
created_at=work_item.created_at,
|
|
58
|
+
started_at=work_item.started_at,
|
|
59
|
+
completed_at=work_item.completed_at,
|
|
60
|
+
result=work_item.result,
|
|
61
|
+
error=work_item.error,
|
|
62
|
+
depends_on=work_item.depends_on,
|
|
63
|
+
metadata=work_item.metadata,
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
@router.post("/projects/{project_id}/work", response_model=WorkItemResponse)
|
|
68
|
+
async def add_work(
|
|
69
|
+
request: Request, project_id: str, work: CreateWorkRequest
|
|
70
|
+
) -> WorkItemResponse:
|
|
71
|
+
"""Add work item to project queue.
|
|
72
|
+
|
|
73
|
+
Args:
|
|
74
|
+
request: FastAPI request (for accessing app.state)
|
|
75
|
+
project_id: Project identifier
|
|
76
|
+
work: Work item creation request
|
|
77
|
+
|
|
78
|
+
Returns:
|
|
79
|
+
Created work item
|
|
80
|
+
|
|
81
|
+
Raises:
|
|
82
|
+
HTTPException: 404 if project not found
|
|
83
|
+
|
|
84
|
+
Example:
|
|
85
|
+
POST /api/projects/proj-123/work
|
|
86
|
+
Request: {
|
|
87
|
+
"content": "Implement OAuth2 authentication",
|
|
88
|
+
"priority": 3,
|
|
89
|
+
"depends_on": ["work-abc"]
|
|
90
|
+
}
|
|
91
|
+
Response: {
|
|
92
|
+
"id": "work-xyz",
|
|
93
|
+
"project_id": "proj-123",
|
|
94
|
+
"content": "Implement OAuth2 authentication",
|
|
95
|
+
"state": "queued",
|
|
96
|
+
"priority": 3,
|
|
97
|
+
...
|
|
98
|
+
}
|
|
99
|
+
"""
|
|
100
|
+
registry = _get_registry(request)
|
|
101
|
+
work_queues = _get_work_queues(request)
|
|
102
|
+
daemon = _get_daemon(request)
|
|
103
|
+
|
|
104
|
+
# Get project
|
|
105
|
+
project = registry.get(project_id)
|
|
106
|
+
if project is None:
|
|
107
|
+
raise HTTPException(status_code=404, detail=f"Project {project_id} not found")
|
|
108
|
+
|
|
109
|
+
# Get or create work queue (shared with daemon)
|
|
110
|
+
import logging
|
|
111
|
+
|
|
112
|
+
logger = logging.getLogger(__name__)
|
|
113
|
+
logger.info(
|
|
114
|
+
f"work_queues dict id: {id(work_queues)}, keys: {list(work_queues.keys())}"
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
if project_id not in work_queues:
|
|
118
|
+
logger.info(f"Creating new work queue for {project_id}")
|
|
119
|
+
work_queues[project_id] = WorkQueue(project_id)
|
|
120
|
+
logger.info(f"After creation, work_queues keys: {list(work_queues.keys())}")
|
|
121
|
+
|
|
122
|
+
queue = work_queues[project_id]
|
|
123
|
+
|
|
124
|
+
# Convert priority int to enum
|
|
125
|
+
priority = WorkPriority(work.priority)
|
|
126
|
+
|
|
127
|
+
# Add work item
|
|
128
|
+
work_item = queue.add(
|
|
129
|
+
content=work.content, priority=priority, depends_on=work.depends_on
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
# Ensure daemon has a session for this project (creates if needed)
|
|
133
|
+
if daemon and not daemon.sessions.get(project_id):
|
|
134
|
+
# Session creation will be handled by daemon's main loop
|
|
135
|
+
# when it detects work in the queue
|
|
136
|
+
pass
|
|
137
|
+
|
|
138
|
+
return _work_item_to_response(work_item)
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
@router.get("/projects/{project_id}/work", response_model=List[WorkItemResponse])
|
|
142
|
+
async def list_work(
|
|
143
|
+
request: Request,
|
|
144
|
+
project_id: str,
|
|
145
|
+
state: Optional[str] = Query(None, description="Filter by state"),
|
|
146
|
+
) -> List[WorkItemResponse]:
|
|
147
|
+
"""List work items for project.
|
|
148
|
+
|
|
149
|
+
Args:
|
|
150
|
+
request: FastAPI request (for accessing app.state)
|
|
151
|
+
project_id: Project identifier
|
|
152
|
+
state: Optional state filter (pending, queued, in_progress, etc.)
|
|
153
|
+
|
|
154
|
+
Returns:
|
|
155
|
+
List of work items (may be empty)
|
|
156
|
+
|
|
157
|
+
Raises:
|
|
158
|
+
HTTPException: 404 if project not found, 400 if invalid state
|
|
159
|
+
|
|
160
|
+
Example:
|
|
161
|
+
GET /api/projects/proj-123/work
|
|
162
|
+
Response: [
|
|
163
|
+
{"id": "work-1", "state": "queued", ...},
|
|
164
|
+
{"id": "work-2", "state": "in_progress", ...}
|
|
165
|
+
]
|
|
166
|
+
|
|
167
|
+
GET /api/projects/proj-123/work?state=queued
|
|
168
|
+
Response: [
|
|
169
|
+
{"id": "work-1", "state": "queued", ...}
|
|
170
|
+
]
|
|
171
|
+
"""
|
|
172
|
+
registry = _get_registry(request)
|
|
173
|
+
work_queues = _get_work_queues(request)
|
|
174
|
+
|
|
175
|
+
# Get project
|
|
176
|
+
project = registry.get(project_id)
|
|
177
|
+
if project is None:
|
|
178
|
+
raise HTTPException(status_code=404, detail=f"Project {project_id} not found")
|
|
179
|
+
|
|
180
|
+
# Get work queue (shared with daemon)
|
|
181
|
+
if project_id not in work_queues:
|
|
182
|
+
# Return empty list if no work queue exists yet
|
|
183
|
+
return []
|
|
184
|
+
|
|
185
|
+
queue = work_queues[project_id]
|
|
186
|
+
|
|
187
|
+
# Parse state filter
|
|
188
|
+
state_filter = None
|
|
189
|
+
if state:
|
|
190
|
+
try:
|
|
191
|
+
state_filter = WorkState(state)
|
|
192
|
+
except ValueError as e:
|
|
193
|
+
raise HTTPException(
|
|
194
|
+
status_code=400,
|
|
195
|
+
detail=f"Invalid state: {state}. "
|
|
196
|
+
f"Valid states: {[s.value for s in WorkState]}",
|
|
197
|
+
) from e
|
|
198
|
+
|
|
199
|
+
# List work items
|
|
200
|
+
items = queue.list(state=state_filter)
|
|
201
|
+
|
|
202
|
+
return [_work_item_to_response(item) for item in items]
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
@router.get("/projects/{project_id}/work/{work_id}", response_model=WorkItemResponse)
|
|
206
|
+
async def get_work(request: Request, project_id: str, work_id: str) -> WorkItemResponse:
|
|
207
|
+
"""Get work item details.
|
|
208
|
+
|
|
209
|
+
Args:
|
|
210
|
+
request: FastAPI request (for accessing app.state)
|
|
211
|
+
project_id: Project identifier
|
|
212
|
+
work_id: Work item identifier
|
|
213
|
+
|
|
214
|
+
Returns:
|
|
215
|
+
Work item details
|
|
216
|
+
|
|
217
|
+
Raises:
|
|
218
|
+
HTTPException: 404 if project or work item not found
|
|
219
|
+
|
|
220
|
+
Example:
|
|
221
|
+
GET /api/projects/proj-123/work/work-xyz
|
|
222
|
+
Response: {
|
|
223
|
+
"id": "work-xyz",
|
|
224
|
+
"project_id": "proj-123",
|
|
225
|
+
"state": "in_progress",
|
|
226
|
+
...
|
|
227
|
+
}
|
|
228
|
+
"""
|
|
229
|
+
registry = _get_registry(request)
|
|
230
|
+
work_queues = _get_work_queues(request)
|
|
231
|
+
|
|
232
|
+
# Get project
|
|
233
|
+
project = registry.get(project_id)
|
|
234
|
+
if project is None:
|
|
235
|
+
raise HTTPException(status_code=404, detail=f"Project {project_id} not found")
|
|
236
|
+
|
|
237
|
+
# Get work queue (shared with daemon)
|
|
238
|
+
if project_id not in work_queues:
|
|
239
|
+
raise HTTPException(status_code=404, detail="Work queue not found")
|
|
240
|
+
|
|
241
|
+
queue = work_queues[project_id]
|
|
242
|
+
|
|
243
|
+
# Get work item
|
|
244
|
+
work_item = queue.get(work_id)
|
|
245
|
+
if not work_item:
|
|
246
|
+
raise HTTPException(status_code=404, detail=f"Work item {work_id} not found")
|
|
247
|
+
|
|
248
|
+
return _work_item_to_response(work_item)
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
@router.post("/projects/{project_id}/work/{work_id}/cancel")
|
|
252
|
+
async def cancel_work(request: Request, project_id: str, work_id: str) -> dict:
|
|
253
|
+
"""Cancel pending work item.
|
|
254
|
+
|
|
255
|
+
Args:
|
|
256
|
+
request: FastAPI request (for accessing app.state)
|
|
257
|
+
project_id: Project identifier
|
|
258
|
+
work_id: Work item identifier
|
|
259
|
+
|
|
260
|
+
Returns:
|
|
261
|
+
Success message
|
|
262
|
+
|
|
263
|
+
Raises:
|
|
264
|
+
HTTPException: 404 if project/work not found, 400 if invalid state
|
|
265
|
+
|
|
266
|
+
Example:
|
|
267
|
+
POST /api/projects/proj-123/work/work-xyz/cancel
|
|
268
|
+
Response: {"status": "cancelled", "id": "work-xyz"}
|
|
269
|
+
"""
|
|
270
|
+
registry = _get_registry(request)
|
|
271
|
+
work_queues = _get_work_queues(request)
|
|
272
|
+
|
|
273
|
+
# Get project
|
|
274
|
+
project = registry.get(project_id)
|
|
275
|
+
if project is None:
|
|
276
|
+
raise HTTPException(status_code=404, detail=f"Project {project_id} not found")
|
|
277
|
+
|
|
278
|
+
# Get work queue (shared with daemon)
|
|
279
|
+
if project_id not in work_queues:
|
|
280
|
+
raise HTTPException(status_code=404, detail="Work queue not found")
|
|
281
|
+
|
|
282
|
+
queue = work_queues[project_id]
|
|
283
|
+
|
|
284
|
+
# Cancel work item
|
|
285
|
+
if not queue.cancel(work_id):
|
|
286
|
+
work_item = queue.get(work_id)
|
|
287
|
+
if not work_item:
|
|
288
|
+
raise HTTPException(
|
|
289
|
+
status_code=404, detail=f"Work item {work_id} not found"
|
|
290
|
+
)
|
|
291
|
+
raise HTTPException(
|
|
292
|
+
status_code=400,
|
|
293
|
+
detail=f"Cannot cancel work item in state {work_item.state.value}",
|
|
294
|
+
)
|
|
295
|
+
|
|
296
|
+
return {"status": "cancelled", "id": work_id}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
"""Pydantic request/response schemas for MPM Commander API.
|
|
2
|
+
|
|
3
|
+
This module defines all request and response models for the REST API,
|
|
4
|
+
providing type safety and automatic validation.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from datetime import datetime
|
|
8
|
+
from typing import List, Optional
|
|
9
|
+
|
|
10
|
+
from pydantic import BaseModel, Field
|
|
11
|
+
|
|
12
|
+
# Request Models
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class RegisterProjectRequest(BaseModel):
|
|
16
|
+
"""Request to register a new project.
|
|
17
|
+
|
|
18
|
+
Attributes:
|
|
19
|
+
path: Filesystem path to project directory
|
|
20
|
+
project_id: Optional project identifier (UUID generated if omitted)
|
|
21
|
+
name: Optional display name (derived from path if omitted)
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
path: str = Field(..., description="Filesystem path to project")
|
|
25
|
+
project_id: Optional[str] = Field(
|
|
26
|
+
None, description="Project identifier (UUID generated if omitted)"
|
|
27
|
+
)
|
|
28
|
+
name: Optional[str] = Field(
|
|
29
|
+
None, description="Display name (derived from path if omitted)"
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class CreateSessionRequest(BaseModel):
|
|
34
|
+
"""Request to create a new tool session.
|
|
35
|
+
|
|
36
|
+
Attributes:
|
|
37
|
+
runtime: Runtime adapter to use (e.g., "claude-code")
|
|
38
|
+
agent_prompt: Optional custom system prompt for the agent
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
runtime: str = Field("claude-code", description="Runtime adapter to use")
|
|
42
|
+
agent_prompt: Optional[str] = Field(None, description="Custom system prompt")
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class SendMessageRequest(BaseModel):
|
|
46
|
+
"""Request to send a message to a project.
|
|
47
|
+
|
|
48
|
+
Attributes:
|
|
49
|
+
content: Message content
|
|
50
|
+
session_id: Target session ID (uses active session if omitted)
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
content: str = Field(..., description="Message content")
|
|
54
|
+
session_id: Optional[str] = Field(
|
|
55
|
+
None, description="Target session (uses active if omitted)"
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
# Response Models
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class SessionResponse(BaseModel):
|
|
63
|
+
"""Session information response.
|
|
64
|
+
|
|
65
|
+
Attributes:
|
|
66
|
+
id: Unique session identifier
|
|
67
|
+
project_id: Parent project ID
|
|
68
|
+
runtime: Runtime adapter name
|
|
69
|
+
tmux_target: Tmux pane target identifier
|
|
70
|
+
status: Current session status
|
|
71
|
+
created_at: Session creation timestamp
|
|
72
|
+
"""
|
|
73
|
+
|
|
74
|
+
id: str
|
|
75
|
+
project_id: str
|
|
76
|
+
runtime: str
|
|
77
|
+
tmux_target: str
|
|
78
|
+
status: str
|
|
79
|
+
created_at: datetime
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
class ProjectResponse(BaseModel):
|
|
83
|
+
"""Project information response.
|
|
84
|
+
|
|
85
|
+
Attributes:
|
|
86
|
+
id: Unique project identifier
|
|
87
|
+
path: Absolute filesystem path
|
|
88
|
+
name: Display name
|
|
89
|
+
state: Current project state
|
|
90
|
+
state_reason: Optional state reason (e.g., error message)
|
|
91
|
+
sessions: List of active sessions
|
|
92
|
+
pending_events_count: Number of pending events
|
|
93
|
+
last_activity: Last activity timestamp
|
|
94
|
+
created_at: Project registration timestamp
|
|
95
|
+
"""
|
|
96
|
+
|
|
97
|
+
id: str
|
|
98
|
+
path: str
|
|
99
|
+
name: str
|
|
100
|
+
state: str
|
|
101
|
+
state_reason: Optional[str]
|
|
102
|
+
sessions: List[SessionResponse]
|
|
103
|
+
pending_events_count: int
|
|
104
|
+
last_activity: datetime
|
|
105
|
+
created_at: datetime
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
class MessageResponse(BaseModel):
|
|
109
|
+
"""Conversation message response.
|
|
110
|
+
|
|
111
|
+
Attributes:
|
|
112
|
+
id: Unique message identifier
|
|
113
|
+
role: Message sender role (user, assistant, system, tool)
|
|
114
|
+
content: Message content
|
|
115
|
+
session_id: Associated session ID (if from tool)
|
|
116
|
+
timestamp: Message creation timestamp
|
|
117
|
+
"""
|
|
118
|
+
|
|
119
|
+
id: str
|
|
120
|
+
role: str
|
|
121
|
+
content: str
|
|
122
|
+
session_id: Optional[str]
|
|
123
|
+
timestamp: datetime
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
class CreateWorkRequest(BaseModel):
|
|
127
|
+
"""Request to create a work item.
|
|
128
|
+
|
|
129
|
+
Attributes:
|
|
130
|
+
content: Task/message to execute
|
|
131
|
+
priority: Priority level (1-4, where 4 is CRITICAL)
|
|
132
|
+
depends_on: Optional list of work item IDs that must complete first
|
|
133
|
+
"""
|
|
134
|
+
|
|
135
|
+
content: str = Field(..., description="Task/message to execute")
|
|
136
|
+
priority: int = Field(
|
|
137
|
+
2,
|
|
138
|
+
description="Priority level (1=LOW, 2=MEDIUM, 3=HIGH, 4=CRITICAL)",
|
|
139
|
+
ge=1,
|
|
140
|
+
le=4,
|
|
141
|
+
)
|
|
142
|
+
depends_on: Optional[List[str]] = Field(
|
|
143
|
+
None, description="Work item IDs that must complete first"
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
class WorkItemResponse(BaseModel):
|
|
148
|
+
"""Work item information response.
|
|
149
|
+
|
|
150
|
+
Attributes:
|
|
151
|
+
id: Unique work item identifier
|
|
152
|
+
project_id: Parent project ID
|
|
153
|
+
content: Task/message content
|
|
154
|
+
state: Current state (pending, queued, in_progress, blocked, completed, failed, cancelled)
|
|
155
|
+
priority: Priority level (1-4)
|
|
156
|
+
created_at: Creation timestamp
|
|
157
|
+
started_at: Execution start timestamp (if started)
|
|
158
|
+
completed_at: Completion timestamp (if completed/failed)
|
|
159
|
+
result: Result message (if completed)
|
|
160
|
+
error: Error message (if failed)
|
|
161
|
+
depends_on: List of dependency work item IDs
|
|
162
|
+
metadata: Additional structured data
|
|
163
|
+
"""
|
|
164
|
+
|
|
165
|
+
id: str
|
|
166
|
+
project_id: str
|
|
167
|
+
content: str
|
|
168
|
+
state: str
|
|
169
|
+
priority: int
|
|
170
|
+
created_at: datetime
|
|
171
|
+
started_at: Optional[datetime]
|
|
172
|
+
completed_at: Optional[datetime]
|
|
173
|
+
result: Optional[str]
|
|
174
|
+
error: Optional[str]
|
|
175
|
+
depends_on: List[str]
|
|
176
|
+
metadata: dict
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
class ErrorResponse(BaseModel):
|
|
180
|
+
"""Error response with structured error information.
|
|
181
|
+
|
|
182
|
+
Attributes:
|
|
183
|
+
error: Error details with code and message
|
|
184
|
+
"""
|
|
185
|
+
|
|
186
|
+
error: dict # {code: str, message: str}
|