claude-mpm 5.4.65__py3-none-any.whl → 5.6.10__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 +107 -1928
- 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 +46 -0
- claude_mpm/cli/commands/configure.py +620 -21
- 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 +2 -2
- 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 +83 -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 +203 -359
- claude_mpm/cli/startup_display.py +72 -5
- claude_mpm/cli/startup_logging.py +2 -2
- claude_mpm/cli/utils.py +7 -3
- claude_mpm/commander/__init__.py +72 -0
- claude_mpm/commander/adapters/__init__.py +31 -0
- claude_mpm/commander/adapters/base.py +191 -0
- claude_mpm/commander/adapters/claude_code.py +361 -0
- claude_mpm/commander/adapters/communication.py +366 -0
- claude_mpm/commander/api/__init__.py +16 -0
- claude_mpm/commander/api/app.py +105 -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 +228 -0
- claude_mpm/commander/api/routes/work.py +260 -0
- claude_mpm/commander/api/schemas.py +182 -0
- claude_mpm/commander/chat/__init__.py +7 -0
- claude_mpm/commander/chat/cli.py +107 -0
- claude_mpm/commander/chat/commands.py +96 -0
- claude_mpm/commander/chat/repl.py +310 -0
- claude_mpm/commander/config.py +49 -0
- claude_mpm/commander/config_loader.py +115 -0
- claude_mpm/commander/daemon.py +398 -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 +143 -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 +337 -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/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 +404 -0
- claude_mpm/commander/runtime/__init__.py +10 -0
- claude_mpm/commander/runtime/executor.py +191 -0
- claude_mpm/commander/runtime/monitor.py +316 -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 +189 -0
- claude_mpm/commander/work/queue.py +405 -0
- claude_mpm/commander/workflow/__init__.py +27 -0
- claude_mpm/commander/workflow/event_handler.py +219 -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 +2 -2
- claude_mpm/core/config.py +32 -19
- claude_mpm/core/hook_manager.py +51 -3
- claude_mpm/core/interactive_session.py +7 -7
- claude_mpm/core/logger.py +26 -9
- claude_mpm/core/logging_utils.py +35 -11
- claude_mpm/core/output_style_manager.py +31 -13
- 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/{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/__pycache__/__init__.cpython-314.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/auto_pause_handler.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/auto_pause_handler.cpython-312.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/auto_pause_handler.cpython-314.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-312.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-314.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-312.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-314.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/installer.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/installer.cpython-314.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-312.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-314.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-312.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-314.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-314.pyc +0 -0
- claude_mpm/hooks/claude_hooks/auto_pause_handler.py +485 -0
- claude_mpm/hooks/claude_hooks/event_handlers.py +283 -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__/__init__.cpython-314.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__/connection_manager_http.cpython-312.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-314.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-314.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-312.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-314.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-312.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-314.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/session_resume_hook.py +89 -1
- claude_mpm/hooks/templates/pre_tool_use_template.py +10 -2
- claude_mpm/init.py +1 -1
- 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/deployment_reconciler.py +577 -0
- claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +3 -0
- claude_mpm/services/agents/deployment/startup_reconciliation.py +138 -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/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 -2
- claude_mpm/services/monitor/server.py +106 -16
- claude_mpm/services/pm_skills_deployer.py +259 -87
- claude_mpm/services/skills/git_skill_source_manager.py +135 -11
- claude_mpm/services/skills/selective_skill_deployer.py +142 -26
- 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/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-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-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-tool-usage-guide/SKILL.md +386 -0
- claude_mpm/skills/bundled/pm/mpm-version/SKILL.md +21 -0
- claude_mpm/skills/skill_manager.py +4 -4
- claude_mpm/utils/agent_dependency_loader.py +4 -2
- claude_mpm/utils/robust_installer.py +10 -6
- claude_mpm-5.6.10.dist-info/METADATA +391 -0
- {claude_mpm-5.4.65.dist-info → claude_mpm-5.6.10.dist-info}/RECORD +303 -181
- 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.65.dist-info/METADATA +0 -999
- /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.65.dist-info → claude_mpm-5.6.10.dist-info}/WHEEL +0 -0
- {claude_mpm-5.4.65.dist-info → claude_mpm-5.6.10.dist-info}/entry_points.txt +0 -0
- {claude_mpm-5.4.65.dist-info → claude_mpm-5.6.10.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-5.4.65.dist-info → claude_mpm-5.6.10.dist-info}/licenses/LICENSE-FAQ.md +0 -0
- {claude_mpm-5.4.65.dist-info → claude_mpm-5.6.10.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
"""Commander chat REPL interface."""
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Optional
|
|
6
|
+
|
|
7
|
+
from prompt_toolkit import PromptSession
|
|
8
|
+
from prompt_toolkit.history import FileHistory
|
|
9
|
+
|
|
10
|
+
from claude_mpm.commander.instance_manager import InstanceManager
|
|
11
|
+
from claude_mpm.commander.llm.openrouter_client import OpenRouterClient
|
|
12
|
+
from claude_mpm.commander.proxy.relay import OutputRelay
|
|
13
|
+
from claude_mpm.commander.session.manager import SessionManager
|
|
14
|
+
|
|
15
|
+
from .commands import Command, CommandParser, CommandType
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class CommanderREPL:
|
|
19
|
+
"""Interactive REPL for Commander mode."""
|
|
20
|
+
|
|
21
|
+
def __init__(
|
|
22
|
+
self,
|
|
23
|
+
instance_manager: InstanceManager,
|
|
24
|
+
session_manager: SessionManager,
|
|
25
|
+
output_relay: Optional[OutputRelay] = None,
|
|
26
|
+
llm_client: Optional[OpenRouterClient] = None,
|
|
27
|
+
):
|
|
28
|
+
"""Initialize REPL.
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
instance_manager: Manages Claude instances.
|
|
32
|
+
session_manager: Manages chat session state.
|
|
33
|
+
output_relay: Optional relay for instance output.
|
|
34
|
+
llm_client: Optional OpenRouter client for chat.
|
|
35
|
+
"""
|
|
36
|
+
self.instances = instance_manager
|
|
37
|
+
self.session = session_manager
|
|
38
|
+
self.relay = output_relay
|
|
39
|
+
self.llm = llm_client
|
|
40
|
+
self.parser = CommandParser()
|
|
41
|
+
self._running = False
|
|
42
|
+
|
|
43
|
+
async def run(self) -> None:
|
|
44
|
+
"""Start the REPL loop."""
|
|
45
|
+
self._running = True
|
|
46
|
+
self._print_welcome()
|
|
47
|
+
|
|
48
|
+
# Setup history file
|
|
49
|
+
history_path = Path.home() / ".claude-mpm" / "commander_history"
|
|
50
|
+
history_path.parent.mkdir(parents=True, exist_ok=True)
|
|
51
|
+
|
|
52
|
+
prompt = PromptSession(history=FileHistory(str(history_path)))
|
|
53
|
+
|
|
54
|
+
while self._running:
|
|
55
|
+
try:
|
|
56
|
+
user_input = await asyncio.to_thread(prompt.prompt, self._get_prompt())
|
|
57
|
+
await self._handle_input(user_input.strip())
|
|
58
|
+
except KeyboardInterrupt:
|
|
59
|
+
continue
|
|
60
|
+
except EOFError:
|
|
61
|
+
break
|
|
62
|
+
|
|
63
|
+
self._print("\nGoodbye!")
|
|
64
|
+
|
|
65
|
+
async def _handle_input(self, input_text: str) -> None:
|
|
66
|
+
"""Handle user input - command or natural language.
|
|
67
|
+
|
|
68
|
+
Args:
|
|
69
|
+
input_text: User input string.
|
|
70
|
+
"""
|
|
71
|
+
if not input_text:
|
|
72
|
+
return
|
|
73
|
+
|
|
74
|
+
# Check if it's a built-in command
|
|
75
|
+
command = self.parser.parse(input_text)
|
|
76
|
+
if command:
|
|
77
|
+
await self._execute_command(command)
|
|
78
|
+
else:
|
|
79
|
+
# Natural language - send to connected instance
|
|
80
|
+
await self._send_to_instance(input_text)
|
|
81
|
+
|
|
82
|
+
async def _execute_command(self, cmd: Command) -> None:
|
|
83
|
+
"""Execute a built-in command.
|
|
84
|
+
|
|
85
|
+
Args:
|
|
86
|
+
cmd: Parsed command.
|
|
87
|
+
"""
|
|
88
|
+
handlers = {
|
|
89
|
+
CommandType.LIST: self._cmd_list,
|
|
90
|
+
CommandType.START: self._cmd_start,
|
|
91
|
+
CommandType.STOP: self._cmd_stop,
|
|
92
|
+
CommandType.CONNECT: self._cmd_connect,
|
|
93
|
+
CommandType.DISCONNECT: self._cmd_disconnect,
|
|
94
|
+
CommandType.STATUS: self._cmd_status,
|
|
95
|
+
CommandType.HELP: self._cmd_help,
|
|
96
|
+
CommandType.EXIT: self._cmd_exit,
|
|
97
|
+
}
|
|
98
|
+
handler = handlers.get(cmd.type)
|
|
99
|
+
if handler:
|
|
100
|
+
await handler(cmd.args)
|
|
101
|
+
|
|
102
|
+
async def _cmd_list(self, args: list[str]) -> None:
|
|
103
|
+
"""List active instances."""
|
|
104
|
+
instances = self.instances.list_instances()
|
|
105
|
+
if not instances:
|
|
106
|
+
self._print("No active instances.")
|
|
107
|
+
else:
|
|
108
|
+
self._print("Active instances:")
|
|
109
|
+
for inst in instances:
|
|
110
|
+
status = (
|
|
111
|
+
"→" if inst.name == self.session.context.connected_instance else " "
|
|
112
|
+
)
|
|
113
|
+
git_info = f" [{inst.git_branch}]" if inst.git_branch else ""
|
|
114
|
+
self._print(
|
|
115
|
+
f" {status} {inst.name} ({inst.framework}){git_info} - {inst.project_path}"
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
async def _cmd_start(self, args: list[str]) -> None:
|
|
119
|
+
"""Start a new instance: start <path> [--framework cc|mpm] [--name name]."""
|
|
120
|
+
if not args:
|
|
121
|
+
self._print("Usage: start <path> [--framework cc|mpm] [--name name]")
|
|
122
|
+
return
|
|
123
|
+
|
|
124
|
+
# Parse arguments
|
|
125
|
+
project_path = Path(args[0]).expanduser().resolve()
|
|
126
|
+
framework = "cc" # default
|
|
127
|
+
name = project_path.name # default
|
|
128
|
+
|
|
129
|
+
# Parse optional flags
|
|
130
|
+
i = 1
|
|
131
|
+
while i < len(args):
|
|
132
|
+
if args[i] == "--framework" and i + 1 < len(args):
|
|
133
|
+
framework = args[i + 1]
|
|
134
|
+
i += 2
|
|
135
|
+
elif args[i] == "--name" and i + 1 < len(args):
|
|
136
|
+
name = args[i + 1]
|
|
137
|
+
i += 2
|
|
138
|
+
else:
|
|
139
|
+
i += 1
|
|
140
|
+
|
|
141
|
+
# Validate path
|
|
142
|
+
if not project_path.exists():
|
|
143
|
+
self._print(f"Error: Path does not exist: {project_path}")
|
|
144
|
+
return
|
|
145
|
+
|
|
146
|
+
if not project_path.is_dir():
|
|
147
|
+
self._print(f"Error: Path is not a directory: {project_path}")
|
|
148
|
+
return
|
|
149
|
+
|
|
150
|
+
# Start instance
|
|
151
|
+
try:
|
|
152
|
+
instance = await self.instances.start_instance(
|
|
153
|
+
name, project_path, framework
|
|
154
|
+
)
|
|
155
|
+
self._print(f"Started instance '{name}' ({framework}) at {project_path}")
|
|
156
|
+
self._print(f"Tmux: {instance.tmux_session}:{instance.pane_target}")
|
|
157
|
+
except Exception as e:
|
|
158
|
+
self._print(f"Error starting instance: {e}")
|
|
159
|
+
|
|
160
|
+
async def _cmd_stop(self, args: list[str]) -> None:
|
|
161
|
+
"""Stop an instance: stop <name>."""
|
|
162
|
+
if not args:
|
|
163
|
+
self._print("Usage: stop <instance-name>")
|
|
164
|
+
return
|
|
165
|
+
|
|
166
|
+
name = args[0]
|
|
167
|
+
|
|
168
|
+
try:
|
|
169
|
+
await self.instances.stop_instance(name)
|
|
170
|
+
self._print(f"Stopped instance '{name}'")
|
|
171
|
+
|
|
172
|
+
# Disconnect if we were connected
|
|
173
|
+
if self.session.context.connected_instance == name:
|
|
174
|
+
self.session.disconnect()
|
|
175
|
+
except Exception as e:
|
|
176
|
+
self._print(f"Error stopping instance: {e}")
|
|
177
|
+
|
|
178
|
+
async def _cmd_connect(self, args: list[str]) -> None:
|
|
179
|
+
"""Connect to an instance: connect <name>."""
|
|
180
|
+
if not args:
|
|
181
|
+
self._print("Usage: connect <instance-name>")
|
|
182
|
+
return
|
|
183
|
+
|
|
184
|
+
name = args[0]
|
|
185
|
+
inst = self.instances.get_instance(name)
|
|
186
|
+
if not inst:
|
|
187
|
+
self._print(f"Instance '{name}' not found")
|
|
188
|
+
return
|
|
189
|
+
|
|
190
|
+
self.session.connect_to(name)
|
|
191
|
+
self._print(f"Connected to {name}")
|
|
192
|
+
|
|
193
|
+
async def _cmd_disconnect(self, args: list[str]) -> None:
|
|
194
|
+
"""Disconnect from current instance."""
|
|
195
|
+
if not self.session.context.is_connected:
|
|
196
|
+
self._print("Not connected to any instance")
|
|
197
|
+
return
|
|
198
|
+
|
|
199
|
+
name = self.session.context.connected_instance
|
|
200
|
+
self.session.disconnect()
|
|
201
|
+
self._print(f"Disconnected from {name}")
|
|
202
|
+
|
|
203
|
+
async def _cmd_status(self, args: list[str]) -> None:
|
|
204
|
+
"""Show status of current session."""
|
|
205
|
+
if self.session.context.is_connected:
|
|
206
|
+
name = self.session.context.connected_instance
|
|
207
|
+
inst = self.instances.get_instance(name)
|
|
208
|
+
if inst:
|
|
209
|
+
self._print(f"Connected to: {name}")
|
|
210
|
+
self._print(f" Framework: {inst.framework}")
|
|
211
|
+
self._print(f" Project: {inst.project_path}")
|
|
212
|
+
if inst.git_branch:
|
|
213
|
+
self._print(f" Git: {inst.git_branch} ({inst.git_status})")
|
|
214
|
+
self._print(f" Tmux: {inst.tmux_session}:{inst.pane_target}")
|
|
215
|
+
else:
|
|
216
|
+
self._print(f"Connected to: {name} (instance no longer exists)")
|
|
217
|
+
else:
|
|
218
|
+
self._print("Not connected to any instance")
|
|
219
|
+
|
|
220
|
+
self._print(f"Messages in history: {len(self.session.context.messages)}")
|
|
221
|
+
|
|
222
|
+
async def _cmd_help(self, args: list[str]) -> None:
|
|
223
|
+
"""Show help message."""
|
|
224
|
+
help_text = """
|
|
225
|
+
Commander Commands:
|
|
226
|
+
list, ls, instances List active instances
|
|
227
|
+
start <path> Start new instance at path
|
|
228
|
+
--framework <cc|mpm> Specify framework (default: cc)
|
|
229
|
+
--name <name> Specify instance name (default: dir name)
|
|
230
|
+
stop <name> Stop an instance
|
|
231
|
+
connect <name> Connect to an instance
|
|
232
|
+
disconnect Disconnect from current instance
|
|
233
|
+
status Show current session status
|
|
234
|
+
help Show this help message
|
|
235
|
+
exit, quit, q Exit Commander
|
|
236
|
+
|
|
237
|
+
Natural Language:
|
|
238
|
+
When connected to an instance, any input that is not a built-in
|
|
239
|
+
command will be sent to the connected instance as a message.
|
|
240
|
+
|
|
241
|
+
Examples:
|
|
242
|
+
start ~/myproject --framework cc --name myapp
|
|
243
|
+
connect myapp
|
|
244
|
+
Fix the authentication bug in login.py
|
|
245
|
+
disconnect
|
|
246
|
+
exit
|
|
247
|
+
"""
|
|
248
|
+
self._print(help_text)
|
|
249
|
+
|
|
250
|
+
async def _cmd_exit(self, args: list[str]) -> None:
|
|
251
|
+
"""Exit the REPL."""
|
|
252
|
+
self._running = False
|
|
253
|
+
|
|
254
|
+
async def _send_to_instance(self, message: str) -> None:
|
|
255
|
+
"""Send natural language to connected instance.
|
|
256
|
+
|
|
257
|
+
Args:
|
|
258
|
+
message: User message to send.
|
|
259
|
+
"""
|
|
260
|
+
if not self.session.context.is_connected:
|
|
261
|
+
self._print("Not connected to any instance. Use 'connect <name>' first.")
|
|
262
|
+
return
|
|
263
|
+
|
|
264
|
+
name = self.session.context.connected_instance
|
|
265
|
+
inst = self.instances.get_instance(name)
|
|
266
|
+
if not inst:
|
|
267
|
+
self._print(f"Instance '{name}' no longer exists")
|
|
268
|
+
self.session.disconnect()
|
|
269
|
+
return
|
|
270
|
+
|
|
271
|
+
self._print(f"[Sending to {name}...]")
|
|
272
|
+
await self.instances.send_to_instance(name, message)
|
|
273
|
+
self.session.add_user_message(message)
|
|
274
|
+
|
|
275
|
+
# Wait for and display response
|
|
276
|
+
if self.relay:
|
|
277
|
+
try:
|
|
278
|
+
output = await self.relay.get_latest_output(
|
|
279
|
+
name, inst.pane_target, context=message
|
|
280
|
+
)
|
|
281
|
+
self._print(f"\n[Response from {name}]:\n{output}")
|
|
282
|
+
self.session.add_assistant_message(output)
|
|
283
|
+
except Exception as e:
|
|
284
|
+
self._print(f"\n[Error getting response: {e}]")
|
|
285
|
+
|
|
286
|
+
def _get_prompt(self) -> str:
|
|
287
|
+
"""Get prompt string based on connection state.
|
|
288
|
+
|
|
289
|
+
Returns:
|
|
290
|
+
Prompt string for input.
|
|
291
|
+
"""
|
|
292
|
+
if self.session.context.is_connected:
|
|
293
|
+
return f"Commander ({self.session.context.connected_instance})> "
|
|
294
|
+
return "Commander> "
|
|
295
|
+
|
|
296
|
+
def _print(self, msg: str) -> None:
|
|
297
|
+
"""Print message to console.
|
|
298
|
+
|
|
299
|
+
Args:
|
|
300
|
+
msg: Message to print.
|
|
301
|
+
"""
|
|
302
|
+
print(msg)
|
|
303
|
+
|
|
304
|
+
def _print_welcome(self) -> None:
|
|
305
|
+
"""Print welcome message."""
|
|
306
|
+
print("╔══════════════════════════════════════════╗")
|
|
307
|
+
print("║ MPM Commander - Interactive Mode ║")
|
|
308
|
+
print("╚══════════════════════════════════════════╝")
|
|
309
|
+
print("Type 'help' for commands, or natural language to chat.")
|
|
310
|
+
print()
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"""Daemon configuration for MPM Commander.
|
|
2
|
+
|
|
3
|
+
This module defines configuration structures for the Commander daemon,
|
|
4
|
+
including server settings, resource limits, and persistence options.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from dataclasses import dataclass
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@dataclass
|
|
12
|
+
class DaemonConfig:
|
|
13
|
+
"""Configuration for Commander daemon.
|
|
14
|
+
|
|
15
|
+
Attributes:
|
|
16
|
+
host: API server bind address
|
|
17
|
+
port: API server port
|
|
18
|
+
log_level: Logging level (DEBUG, INFO, WARNING, ERROR)
|
|
19
|
+
state_dir: Directory for state persistence
|
|
20
|
+
max_projects: Maximum concurrent projects
|
|
21
|
+
healthcheck_interval: Healthcheck interval in seconds
|
|
22
|
+
save_interval: State persistence interval in seconds
|
|
23
|
+
poll_interval: Event polling interval in seconds
|
|
24
|
+
|
|
25
|
+
Example:
|
|
26
|
+
>>> config = DaemonConfig(port=8765, log_level="DEBUG")
|
|
27
|
+
>>> config.state_dir
|
|
28
|
+
PosixPath('/Users/user/.claude-mpm/commander')
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
host: str = "127.0.0.1"
|
|
32
|
+
port: int = 8765
|
|
33
|
+
log_level: str = "INFO"
|
|
34
|
+
state_dir: Path = Path.home() / ".claude-mpm" / "commander"
|
|
35
|
+
max_projects: int = 10
|
|
36
|
+
healthcheck_interval: int = 30
|
|
37
|
+
save_interval: int = 30
|
|
38
|
+
poll_interval: float = 2.0
|
|
39
|
+
|
|
40
|
+
def __post_init__(self):
|
|
41
|
+
"""Ensure state_dir is a Path object and create if needed."""
|
|
42
|
+
if isinstance(self.state_dir, str):
|
|
43
|
+
self.state_dir = Path(self.state_dir)
|
|
44
|
+
|
|
45
|
+
# Expand user home directory
|
|
46
|
+
self.state_dir = self.state_dir.expanduser()
|
|
47
|
+
|
|
48
|
+
# Create state directory if it doesn't exist
|
|
49
|
+
self.state_dir.mkdir(parents=True, exist_ok=True)
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"""Project configuration loading for MPM Commander.
|
|
2
|
+
|
|
3
|
+
This module handles loading configuration from a project's .claude-mpm/
|
|
4
|
+
directory, including YAML config files and directory structure validation.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import logging
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import Any, Dict, Optional
|
|
10
|
+
|
|
11
|
+
import yaml
|
|
12
|
+
|
|
13
|
+
logger = logging.getLogger(__name__)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def load_project_config(project_path: str) -> Optional[Dict[str, Any]]:
|
|
17
|
+
"""Load configuration from project's .claude-mpm/ directory.
|
|
18
|
+
|
|
19
|
+
Looks for:
|
|
20
|
+
- .claude-mpm/configuration.yaml (main config file)
|
|
21
|
+
- .claude-mpm/agents/ (directory exists check)
|
|
22
|
+
- .claude-mpm/skills/ (directory exists check)
|
|
23
|
+
- .claude-mpm/memories/ (directory exists check)
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
project_path: Absolute path to project directory
|
|
27
|
+
|
|
28
|
+
Returns:
|
|
29
|
+
Dict with config data and directory flags, or None if no config found.
|
|
30
|
+
Example structure:
|
|
31
|
+
{
|
|
32
|
+
'configuration': {...}, # Parsed YAML config
|
|
33
|
+
'has_agents': True,
|
|
34
|
+
'has_skills': False,
|
|
35
|
+
'has_memories': True,
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
Raises:
|
|
39
|
+
yaml.YAMLError: If configuration.yaml is malformed
|
|
40
|
+
|
|
41
|
+
Example:
|
|
42
|
+
>>> config = load_project_config("/Users/masa/Projects/my-app")
|
|
43
|
+
>>> if config:
|
|
44
|
+
... print(f"Agents dir: {config['has_agents']}")
|
|
45
|
+
... print(f"Config: {config.get('configuration', {})}")
|
|
46
|
+
Agents dir: True
|
|
47
|
+
Config: {'default_adapter': 'linear', ...}
|
|
48
|
+
"""
|
|
49
|
+
proj_path = Path(project_path)
|
|
50
|
+
config_dir = proj_path / ".claude-mpm"
|
|
51
|
+
|
|
52
|
+
# Check if .claude-mpm/ directory exists
|
|
53
|
+
if not config_dir.exists() or not config_dir.is_dir():
|
|
54
|
+
logger.debug("No .claude-mpm/ directory found in project: %s", project_path)
|
|
55
|
+
return None
|
|
56
|
+
|
|
57
|
+
logger.info("Loading configuration from %s", config_dir)
|
|
58
|
+
|
|
59
|
+
result: Dict[str, Any] = {
|
|
60
|
+
"configuration": {},
|
|
61
|
+
"has_agents": False,
|
|
62
|
+
"has_skills": False,
|
|
63
|
+
"has_memories": False,
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
# Load configuration.yaml if present
|
|
67
|
+
config_file = config_dir / "configuration.yaml"
|
|
68
|
+
if config_file.exists() and config_file.is_file():
|
|
69
|
+
try:
|
|
70
|
+
with open(config_file, encoding="utf-8") as f:
|
|
71
|
+
config_data = yaml.safe_load(f)
|
|
72
|
+
result["configuration"] = config_data or {}
|
|
73
|
+
logger.info(
|
|
74
|
+
"Loaded configuration.yaml with %d top-level keys",
|
|
75
|
+
len(result["configuration"]),
|
|
76
|
+
)
|
|
77
|
+
except yaml.YAMLError as e:
|
|
78
|
+
logger.error(
|
|
79
|
+
"Failed to parse configuration.yaml in %s: %s",
|
|
80
|
+
config_dir,
|
|
81
|
+
e,
|
|
82
|
+
)
|
|
83
|
+
raise
|
|
84
|
+
except Exception as e:
|
|
85
|
+
logger.warning(
|
|
86
|
+
"Failed to read configuration.yaml in %s: %s",
|
|
87
|
+
config_dir,
|
|
88
|
+
e,
|
|
89
|
+
)
|
|
90
|
+
# Continue with empty config
|
|
91
|
+
|
|
92
|
+
# Check for subdirectories
|
|
93
|
+
agents_dir = config_dir / "agents"
|
|
94
|
+
result["has_agents"] = agents_dir.exists() and agents_dir.is_dir()
|
|
95
|
+
if result["has_agents"]:
|
|
96
|
+
logger.debug("Found agents directory: %s", agents_dir)
|
|
97
|
+
|
|
98
|
+
skills_dir = config_dir / "skills"
|
|
99
|
+
result["has_skills"] = skills_dir.exists() and skills_dir.is_dir()
|
|
100
|
+
if result["has_skills"]:
|
|
101
|
+
logger.debug("Found skills directory: %s", skills_dir)
|
|
102
|
+
|
|
103
|
+
memories_dir = config_dir / "memories"
|
|
104
|
+
result["has_memories"] = memories_dir.exists() and memories_dir.is_dir()
|
|
105
|
+
if result["has_memories"]:
|
|
106
|
+
logger.debug("Found memories directory: %s", memories_dir)
|
|
107
|
+
|
|
108
|
+
logger.info(
|
|
109
|
+
"Project config loaded: agents=%s, skills=%s, memories=%s",
|
|
110
|
+
result["has_agents"],
|
|
111
|
+
result["has_skills"],
|
|
112
|
+
result["has_memories"],
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
return result
|