claude-mpm 5.4.41__py3-none-any.whl → 5.6.72__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of claude-mpm might be problematic. Click here for more details.
- claude_mpm/VERSION +1 -1
- claude_mpm/agents/CLAUDE_MPM_OUTPUT_STYLE.md +66 -241
- claude_mpm/agents/CLAUDE_MPM_RESEARCH_OUTPUT_STYLE.md +413 -0
- claude_mpm/agents/CLAUDE_MPM_TEACHER_OUTPUT_STYLE.md +109 -1925
- claude_mpm/agents/PM_INSTRUCTIONS.md +161 -298
- claude_mpm/agents/WORKFLOW.md +2 -0
- claude_mpm/agents/templates/circuit-breakers.md +26 -17
- claude_mpm/auth/__init__.py +35 -0
- claude_mpm/auth/callback_server.py +328 -0
- claude_mpm/auth/models.py +104 -0
- claude_mpm/auth/oauth_manager.py +266 -0
- claude_mpm/auth/providers/__init__.py +12 -0
- claude_mpm/auth/providers/base.py +165 -0
- claude_mpm/auth/providers/google.py +261 -0
- claude_mpm/auth/token_storage.py +252 -0
- claude_mpm/cli/__init__.py +5 -1
- claude_mpm/cli/commands/agents.py +2 -4
- claude_mpm/cli/commands/agents_reconcile.py +197 -0
- claude_mpm/cli/commands/autotodos.py +566 -0
- claude_mpm/cli/commands/commander.py +216 -0
- claude_mpm/cli/commands/configure.py +620 -21
- claude_mpm/cli/commands/configure_agent_display.py +3 -1
- claude_mpm/cli/commands/hook_errors.py +60 -60
- claude_mpm/cli/commands/mcp.py +29 -17
- claude_mpm/cli/commands/mcp_command_router.py +39 -0
- claude_mpm/cli/commands/mcp_service_commands.py +304 -0
- claude_mpm/cli/commands/monitor.py +2 -2
- claude_mpm/cli/commands/mpm_init/core.py +15 -8
- claude_mpm/cli/commands/oauth.py +481 -0
- claude_mpm/cli/commands/profile.py +9 -10
- claude_mpm/cli/commands/run.py +35 -3
- claude_mpm/cli/commands/skill_source.py +51 -2
- claude_mpm/cli/commands/skills.py +182 -32
- claude_mpm/cli/executor.py +129 -16
- claude_mpm/cli/helpers.py +1 -1
- claude_mpm/cli/interactive/__init__.py +10 -0
- claude_mpm/cli/interactive/agent_wizard.py +30 -50
- claude_mpm/cli/interactive/questionary_styles.py +65 -0
- claude_mpm/cli/interactive/skill_selector.py +481 -0
- claude_mpm/cli/parsers/base_parser.py +89 -1
- claude_mpm/cli/parsers/commander_parser.py +116 -0
- claude_mpm/cli/parsers/mcp_parser.py +79 -0
- claude_mpm/cli/parsers/oauth_parser.py +165 -0
- claude_mpm/cli/parsers/profile_parser.py +0 -1
- claude_mpm/cli/parsers/run_parser.py +10 -0
- claude_mpm/cli/parsers/skill_source_parser.py +4 -0
- claude_mpm/cli/parsers/skills_parser.py +2 -3
- claude_mpm/cli/startup.py +662 -524
- claude_mpm/cli/startup_display.py +76 -7
- claude_mpm/cli/startup_logging.py +2 -2
- claude_mpm/cli/utils.py +7 -3
- claude_mpm/commander/__init__.py +78 -0
- claude_mpm/commander/adapters/__init__.py +60 -0
- claude_mpm/commander/adapters/auggie.py +260 -0
- claude_mpm/commander/adapters/base.py +288 -0
- claude_mpm/commander/adapters/claude_code.py +392 -0
- claude_mpm/commander/adapters/codex.py +237 -0
- claude_mpm/commander/adapters/communication.py +366 -0
- claude_mpm/commander/adapters/example_usage.py +310 -0
- claude_mpm/commander/adapters/mpm.py +389 -0
- claude_mpm/commander/adapters/registry.py +204 -0
- claude_mpm/commander/api/__init__.py +16 -0
- claude_mpm/commander/api/app.py +121 -0
- claude_mpm/commander/api/errors.py +133 -0
- claude_mpm/commander/api/routes/__init__.py +8 -0
- claude_mpm/commander/api/routes/events.py +184 -0
- claude_mpm/commander/api/routes/inbox.py +171 -0
- claude_mpm/commander/api/routes/messages.py +148 -0
- claude_mpm/commander/api/routes/projects.py +271 -0
- claude_mpm/commander/api/routes/sessions.py +226 -0
- claude_mpm/commander/api/routes/work.py +296 -0
- claude_mpm/commander/api/schemas.py +186 -0
- claude_mpm/commander/chat/__init__.py +7 -0
- claude_mpm/commander/chat/cli.py +149 -0
- claude_mpm/commander/chat/commands.py +122 -0
- claude_mpm/commander/chat/repl.py +1821 -0
- claude_mpm/commander/config.py +51 -0
- claude_mpm/commander/config_loader.py +115 -0
- claude_mpm/commander/core/__init__.py +10 -0
- claude_mpm/commander/core/block_manager.py +325 -0
- claude_mpm/commander/core/response_manager.py +323 -0
- claude_mpm/commander/daemon.py +603 -0
- claude_mpm/commander/env_loader.py +59 -0
- claude_mpm/commander/events/__init__.py +26 -0
- claude_mpm/commander/events/manager.py +392 -0
- claude_mpm/commander/frameworks/__init__.py +12 -0
- claude_mpm/commander/frameworks/base.py +233 -0
- claude_mpm/commander/frameworks/claude_code.py +58 -0
- claude_mpm/commander/frameworks/mpm.py +57 -0
- claude_mpm/commander/git/__init__.py +5 -0
- claude_mpm/commander/git/worktree_manager.py +212 -0
- claude_mpm/commander/inbox/__init__.py +16 -0
- claude_mpm/commander/inbox/dedup.py +128 -0
- claude_mpm/commander/inbox/inbox.py +224 -0
- claude_mpm/commander/inbox/models.py +70 -0
- claude_mpm/commander/instance_manager.py +865 -0
- claude_mpm/commander/llm/__init__.py +6 -0
- claude_mpm/commander/llm/openrouter_client.py +167 -0
- claude_mpm/commander/llm/summarizer.py +70 -0
- claude_mpm/commander/memory/__init__.py +45 -0
- claude_mpm/commander/memory/compression.py +347 -0
- claude_mpm/commander/memory/embeddings.py +230 -0
- claude_mpm/commander/memory/entities.py +310 -0
- claude_mpm/commander/memory/example_usage.py +290 -0
- claude_mpm/commander/memory/integration.py +325 -0
- claude_mpm/commander/memory/search.py +381 -0
- claude_mpm/commander/memory/store.py +657 -0
- claude_mpm/commander/models/__init__.py +18 -0
- claude_mpm/commander/models/events.py +127 -0
- claude_mpm/commander/models/project.py +162 -0
- claude_mpm/commander/models/work.py +214 -0
- claude_mpm/commander/parsing/__init__.py +20 -0
- claude_mpm/commander/parsing/extractor.py +132 -0
- claude_mpm/commander/parsing/output_parser.py +270 -0
- claude_mpm/commander/parsing/patterns.py +100 -0
- claude_mpm/commander/persistence/__init__.py +11 -0
- claude_mpm/commander/persistence/event_store.py +274 -0
- claude_mpm/commander/persistence/state_store.py +403 -0
- claude_mpm/commander/persistence/work_store.py +164 -0
- claude_mpm/commander/polling/__init__.py +13 -0
- claude_mpm/commander/polling/event_detector.py +104 -0
- claude_mpm/commander/polling/output_buffer.py +49 -0
- claude_mpm/commander/polling/output_poller.py +153 -0
- claude_mpm/commander/project_session.py +268 -0
- claude_mpm/commander/proxy/__init__.py +12 -0
- claude_mpm/commander/proxy/formatter.py +89 -0
- claude_mpm/commander/proxy/output_handler.py +191 -0
- claude_mpm/commander/proxy/relay.py +155 -0
- claude_mpm/commander/registry.py +410 -0
- claude_mpm/commander/runtime/__init__.py +10 -0
- claude_mpm/commander/runtime/executor.py +191 -0
- claude_mpm/commander/runtime/monitor.py +346 -0
- claude_mpm/commander/session/__init__.py +6 -0
- claude_mpm/commander/session/context.py +81 -0
- claude_mpm/commander/session/manager.py +59 -0
- claude_mpm/commander/tmux_orchestrator.py +362 -0
- claude_mpm/commander/web/__init__.py +1 -0
- claude_mpm/commander/work/__init__.py +30 -0
- claude_mpm/commander/work/executor.py +207 -0
- claude_mpm/commander/work/queue.py +405 -0
- claude_mpm/commander/workflow/__init__.py +27 -0
- claude_mpm/commander/workflow/event_handler.py +241 -0
- claude_mpm/commander/workflow/notifier.py +146 -0
- claude_mpm/commands/mpm-config.md +8 -0
- claude_mpm/commands/mpm-doctor.md +8 -0
- claude_mpm/commands/mpm-help.md +8 -0
- claude_mpm/commands/mpm-init.md +8 -0
- claude_mpm/commands/mpm-monitor.md +8 -0
- claude_mpm/commands/mpm-organize.md +8 -0
- claude_mpm/commands/mpm-postmortem.md +8 -0
- claude_mpm/commands/mpm-session-resume.md +9 -1
- claude_mpm/commands/mpm-status.md +8 -0
- claude_mpm/commands/mpm-ticket-view.md +8 -0
- claude_mpm/commands/mpm-version.md +8 -0
- claude_mpm/commands/mpm.md +8 -0
- claude_mpm/config/agent_presets.py +8 -7
- claude_mpm/config/skill_sources.py +16 -0
- claude_mpm/constants.py +6 -0
- claude_mpm/core/claude_runner.py +154 -2
- claude_mpm/core/config.py +35 -22
- claude_mpm/core/config_constants.py +74 -9
- claude_mpm/core/constants.py +56 -12
- claude_mpm/core/hook_manager.py +53 -4
- claude_mpm/core/interactive_session.py +12 -11
- claude_mpm/core/logger.py +26 -9
- claude_mpm/core/logging_utils.py +39 -13
- claude_mpm/core/network_config.py +148 -0
- claude_mpm/core/oneshot_session.py +7 -6
- claude_mpm/core/optimized_startup.py +3 -1
- claude_mpm/core/output_style_manager.py +66 -18
- claude_mpm/core/shared/config_loader.py +3 -1
- claude_mpm/core/socketio_pool.py +47 -15
- claude_mpm/core/unified_config.py +54 -8
- claude_mpm/core/unified_paths.py +95 -90
- claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.C33zOoyM.css +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.CW1J-YuA.css +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/1WZnGYqX.js +24 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/67pF3qNn.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/6RxdMKe4.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/8cZrfX0h.js +60 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/9a6T2nm-.js +7 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/B443AUzu.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/B8AwtY2H.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BF15LAsF.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BQaXIfA_.js +331 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BRcwIQNr.js +4 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{uj46x2Wr.js → BSNlmTZj.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BV6nKitt.js +43 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BViJ8lZt.js +128 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BcQ-Q0FE.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Bpyvgze_.js +30 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BzTRqg-z.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C0Fr8dve.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C3rbW_a-.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C8WYN38h.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C9I8FlXH.js +61 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CIQcWgO2.js +36 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CIctN7YN.js +7 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CKrS_JZW.js +145 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CR6P9C4A.js +89 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CRRR9MD_.js +2 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CRcR2DqT.js +334 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CSXtMOf0.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CT-sbxSk.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CWm6DJsp.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CmKTTxBW.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CpqQ1Kzn.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Cu_Erd72.js +261 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D2nGpDRe.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D9iCMida.js +267 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D9ykgMoY.js +10 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DL2Ldur1.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DPfltzjH.js +165 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{N4qtv3Hx.js → DR8nis88.js} +2 -2
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DUliQN2b.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DVp1hx9R.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DXlhR01x.js +122 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D_lyTybS.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DngoTTgh.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DqkmHtDC.js +220 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DsDh8EYs.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DypDmXgd.js +139 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Gi6I4Gst.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/IPYC-LnN.js +162 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/JTLiF7dt.js +24 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/JpevfAFt.js +68 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DjhvlsAc.js → NqQ1dWOy.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/R8CEIRAd.js +2 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Zxy7qc-l.js +64 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/q9Hm6zAU.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/qtd3IeO4.js +15 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/ulBFON_C.js +65 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/wQVh1CoA.js +10 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/app.Dr7t0z2J.js +2 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.BGhZHUS3.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/{0.CAGBuiOw.js → 0.RgBboRvH.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/1.DG-KkbDf.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.D_jnf-x6.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/version.json +1 -1
- claude_mpm/dashboard/static/svelte-build/index.html +11 -11
- claude_mpm/dashboard-svelte/node_modules/katex/src/fonts/generate_fonts.py +58 -0
- claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/extract_tfms.py +114 -0
- claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/extract_ttfs.py +122 -0
- claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/format_json.py +28 -0
- claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/parse_tfm.py +211 -0
- claude_mpm/experimental/cli_enhancements.py +2 -1
- claude_mpm/hooks/claude_hooks/INTEGRATION_EXAMPLE.md +243 -0
- claude_mpm/hooks/claude_hooks/README_AUTO_PAUSE.md +403 -0
- claude_mpm/hooks/claude_hooks/__pycache__/auto_pause_handler.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/auto_pause_handler.py +485 -0
- claude_mpm/hooks/claude_hooks/event_handlers.py +466 -136
- claude_mpm/hooks/claude_hooks/hook_handler.py +204 -104
- claude_mpm/hooks/claude_hooks/hook_wrapper.sh +6 -11
- claude_mpm/hooks/claude_hooks/installer.py +291 -59
- claude_mpm/hooks/claude_hooks/memory_integration.py +52 -32
- claude_mpm/hooks/claude_hooks/response_tracking.py +43 -60
- claude_mpm/hooks/claude_hooks/services/__init__.py +21 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/container.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/protocols.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/connection_manager.py +41 -26
- claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +38 -105
- claude_mpm/hooks/claude_hooks/services/container.py +326 -0
- claude_mpm/hooks/claude_hooks/services/protocols.py +328 -0
- claude_mpm/hooks/claude_hooks/services/state_manager.py +25 -38
- claude_mpm/hooks/claude_hooks/services/subagent_processor.py +75 -77
- claude_mpm/hooks/kuzu_memory_hook.py +5 -5
- claude_mpm/hooks/session_resume_hook.py +89 -1
- claude_mpm/hooks/templates/pre_tool_use_simple.py +6 -6
- claude_mpm/hooks/templates/pre_tool_use_template.py +16 -8
- claude_mpm/init.py +224 -4
- claude_mpm/mcp/__init__.py +9 -0
- claude_mpm/mcp/google_workspace_server.py +610 -0
- claude_mpm/scripts/claude-hook-handler.sh +46 -19
- claude_mpm/services/agents/agent_recommendation_service.py +8 -8
- claude_mpm/services/agents/agent_selection_service.py +2 -2
- claude_mpm/services/agents/cache_git_manager.py +1 -1
- claude_mpm/services/agents/deployment/agent_discovery_service.py +3 -1
- claude_mpm/services/agents/deployment/agent_format_converter.py +25 -13
- claude_mpm/services/agents/deployment/agent_template_builder.py +37 -17
- claude_mpm/services/agents/deployment/async_agent_deployment.py +31 -27
- claude_mpm/services/agents/deployment/deployment_reconciler.py +577 -0
- claude_mpm/services/agents/deployment/local_template_deployment.py +3 -1
- claude_mpm/services/agents/deployment/multi_source_deployment_service.py +36 -8
- claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +50 -26
- claude_mpm/services/agents/deployment/startup_reconciliation.py +138 -0
- claude_mpm/services/agents/git_source_manager.py +21 -2
- claude_mpm/services/agents/loading/framework_agent_loader.py +75 -2
- claude_mpm/services/agents/single_tier_deployment_service.py +4 -4
- claude_mpm/services/agents/sources/git_source_sync_service.py +116 -5
- claude_mpm/services/agents/startup_sync.py +5 -2
- claude_mpm/services/cli/__init__.py +3 -0
- claude_mpm/services/cli/incremental_pause_manager.py +561 -0
- claude_mpm/services/cli/session_resume_helper.py +10 -2
- claude_mpm/services/command_deployment_service.py +44 -26
- claude_mpm/services/delegation_detector.py +175 -0
- claude_mpm/services/diagnostics/checks/agent_sources_check.py +30 -0
- claude_mpm/services/diagnostics/checks/configuration_check.py +24 -0
- claude_mpm/services/diagnostics/checks/installation_check.py +22 -0
- claude_mpm/services/diagnostics/checks/mcp_services_check.py +23 -0
- claude_mpm/services/diagnostics/doctor_reporter.py +31 -1
- claude_mpm/services/diagnostics/models.py +14 -1
- claude_mpm/services/event_log.py +325 -0
- claude_mpm/services/hook_installer_service.py +77 -8
- claude_mpm/services/infrastructure/__init__.py +4 -0
- claude_mpm/services/infrastructure/context_usage_tracker.py +291 -0
- claude_mpm/services/infrastructure/resume_log_generator.py +24 -5
- claude_mpm/services/mcp_config_manager.py +99 -19
- claude_mpm/services/mcp_service_registry.py +294 -0
- claude_mpm/services/monitor/daemon_manager.py +15 -4
- claude_mpm/services/monitor/management/lifecycle.py +8 -3
- claude_mpm/services/monitor/server.py +111 -16
- claude_mpm/services/pm_skills_deployer.py +302 -94
- claude_mpm/services/profile_manager.py +10 -4
- claude_mpm/services/skills/git_skill_source_manager.py +192 -29
- claude_mpm/services/skills/selective_skill_deployer.py +211 -46
- claude_mpm/services/skills/skill_discovery_service.py +74 -4
- claude_mpm/services/skills_deployer.py +192 -70
- claude_mpm/services/socketio/handlers/hook.py +14 -7
- claude_mpm/services/socketio/server/main.py +12 -4
- claude_mpm/skills/__init__.py +2 -1
- claude_mpm/skills/bundled/collaboration/brainstorming/SKILL.md +79 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/SKILL.md +178 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/agent-prompts.md +577 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/coordination-patterns.md +467 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/examples.md +537 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/troubleshooting.md +730 -0
- claude_mpm/skills/bundled/collaboration/git-worktrees.md +317 -0
- claude_mpm/skills/bundled/collaboration/requesting-code-review/SKILL.md +112 -0
- claude_mpm/skills/bundled/collaboration/requesting-code-review/references/code-reviewer-template.md +146 -0
- claude_mpm/skills/bundled/collaboration/requesting-code-review/references/review-examples.md +412 -0
- claude_mpm/skills/bundled/collaboration/stacked-prs.md +251 -0
- claude_mpm/skills/bundled/collaboration/writing-plans/SKILL.md +81 -0
- claude_mpm/skills/bundled/collaboration/writing-plans/references/best-practices.md +362 -0
- claude_mpm/skills/bundled/collaboration/writing-plans/references/plan-structure-templates.md +312 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/SKILL.md +152 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/advanced-techniques.md +668 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/examples.md +587 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/integration.md +438 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/tracing-techniques.md +391 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/CREATION-LOG.md +119 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/SKILL.md +148 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/anti-patterns.md +483 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/examples.md +452 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/troubleshooting.md +449 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/workflow.md +411 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-academic.md +14 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-1.md +58 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-2.md +68 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-3.md +69 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/SKILL.md +131 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/gate-function.md +325 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/integration-and-workflows.md +490 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/red-flags-and-failures.md +425 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/verification-patterns.md +499 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/INTEGRATION.md +611 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/README.md +596 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/SKILL.md +260 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/examples/nextjs-env-structure.md +315 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/references/frameworks.md +436 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/references/security.md +433 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/references/synchronization.md +452 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/references/troubleshooting.md +404 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/references/validation.md +420 -0
- claude_mpm/skills/bundled/main/artifacts-builder/SKILL.md +86 -0
- claude_mpm/skills/bundled/main/internal-comms/SKILL.md +43 -0
- claude_mpm/skills/bundled/main/internal-comms/examples/3p-updates.md +47 -0
- claude_mpm/skills/bundled/main/internal-comms/examples/company-newsletter.md +65 -0
- claude_mpm/skills/bundled/main/internal-comms/examples/faq-answers.md +30 -0
- claude_mpm/skills/bundled/main/internal-comms/examples/general-comms.md +16 -0
- claude_mpm/skills/bundled/main/mcp-builder/SKILL.md +160 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/design_principles.md +412 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/evaluation.md +602 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/mcp_best_practices.md +915 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/node_mcp_server.md +916 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/python_mcp_server.md +752 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/workflow.md +1237 -0
- claude_mpm/skills/bundled/main/skill-creator/SKILL.md +189 -0
- claude_mpm/skills/bundled/main/skill-creator/references/best-practices.md +500 -0
- claude_mpm/skills/bundled/main/skill-creator/references/creation-workflow.md +464 -0
- claude_mpm/skills/bundled/main/skill-creator/references/examples.md +619 -0
- claude_mpm/skills/bundled/main/skill-creator/references/progressive-disclosure.md +437 -0
- claude_mpm/skills/bundled/main/skill-creator/references/skill-structure.md +231 -0
- claude_mpm/skills/bundled/php/espocrm-development/SKILL.md +170 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/architecture.md +602 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/common-tasks.md +821 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/development-workflow.md +742 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/frontend-customization.md +726 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/hooks-and-services.md +764 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/testing-debugging.md +831 -0
- claude_mpm/skills/bundled/pm/mpm/SKILL.md +38 -0
- claude_mpm/skills/bundled/pm/mpm-agent-update-workflow/SKILL.md +75 -0
- claude_mpm/skills/bundled/pm/mpm-bug-reporting/SKILL.md +248 -0
- claude_mpm/skills/bundled/pm/mpm-circuit-breaker-enforcement/SKILL.md +476 -0
- claude_mpm/skills/bundled/pm/mpm-config/SKILL.md +29 -0
- claude_mpm/skills/bundled/pm/mpm-delegation-patterns/SKILL.md +167 -0
- claude_mpm/skills/bundled/pm/mpm-doctor/SKILL.md +53 -0
- claude_mpm/skills/bundled/pm/mpm-git-file-tracking/SKILL.md +113 -0
- claude_mpm/skills/bundled/pm/mpm-help/SKILL.md +35 -0
- claude_mpm/skills/bundled/pm/mpm-init/SKILL.md +125 -0
- claude_mpm/skills/bundled/pm/mpm-monitor/SKILL.md +32 -0
- claude_mpm/skills/bundled/pm/mpm-organize/SKILL.md +121 -0
- claude_mpm/skills/bundled/pm/mpm-postmortem/SKILL.md +22 -0
- claude_mpm/skills/bundled/pm/mpm-pr-workflow/SKILL.md +124 -0
- claude_mpm/skills/bundled/pm/mpm-session-management/SKILL.md +312 -0
- claude_mpm/skills/bundled/pm/mpm-session-pause/SKILL.md +170 -0
- claude_mpm/skills/bundled/pm/mpm-session-resume/SKILL.md +31 -0
- claude_mpm/skills/bundled/pm/mpm-status/SKILL.md +37 -0
- claude_mpm/skills/bundled/pm/mpm-teaching-mode/SKILL.md +657 -0
- claude_mpm/skills/bundled/pm/mpm-ticket-view/SKILL.md +110 -0
- claude_mpm/skills/bundled/pm/mpm-ticketing-integration/SKILL.md +154 -0
- claude_mpm/skills/bundled/pm/mpm-tool-usage-guide/SKILL.md +386 -0
- claude_mpm/skills/bundled/pm/mpm-verification-protocols/SKILL.md +198 -0
- claude_mpm/skills/bundled/pm/mpm-version/SKILL.md +21 -0
- claude_mpm/skills/bundled/react/flexlayout-react.md +742 -0
- claude_mpm/skills/bundled/rust/desktop-applications/SKILL.md +226 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/architecture-patterns.md +901 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/native-gui-frameworks.md +901 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/platform-integration.md +775 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/state-management.md +937 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/tauri-framework.md +770 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/testing-deployment.md +961 -0
- claude_mpm/skills/bundled/security-scanning.md +112 -0
- claude_mpm/skills/bundled/tauri/tauri-async-patterns.md +495 -0
- claude_mpm/skills/bundled/tauri/tauri-build-deploy.md +599 -0
- claude_mpm/skills/bundled/tauri/tauri-command-patterns.md +535 -0
- claude_mpm/skills/bundled/tauri/tauri-error-handling.md +613 -0
- claude_mpm/skills/bundled/tauri/tauri-event-system.md +648 -0
- claude_mpm/skills/bundled/tauri/tauri-file-system.md +673 -0
- claude_mpm/skills/bundled/tauri/tauri-frontend-integration.md +767 -0
- claude_mpm/skills/bundled/tauri/tauri-performance.md +669 -0
- claude_mpm/skills/bundled/tauri/tauri-state-management.md +573 -0
- claude_mpm/skills/bundled/tauri/tauri-testing.md +384 -0
- claude_mpm/skills/bundled/tauri/tauri-window-management.md +628 -0
- claude_mpm/skills/bundled/testing/condition-based-waiting/SKILL.md +119 -0
- claude_mpm/skills/bundled/testing/condition-based-waiting/references/patterns-and-implementation.md +253 -0
- claude_mpm/skills/bundled/testing/test-driven-development/SKILL.md +145 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/anti-patterns.md +543 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/examples.md +741 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/integration.md +470 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/philosophy.md +458 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/workflow.md +639 -0
- claude_mpm/skills/bundled/testing/test-quality-inspector/SKILL.md +458 -0
- claude_mpm/skills/bundled/testing/test-quality-inspector/examples/example-inspection-report.md +411 -0
- claude_mpm/skills/bundled/testing/test-quality-inspector/references/assertion-quality.md +317 -0
- claude_mpm/skills/bundled/testing/test-quality-inspector/references/inspection-checklist.md +270 -0
- claude_mpm/skills/bundled/testing/test-quality-inspector/references/red-flags.md +436 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/SKILL.md +140 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/completeness-anti-patterns.md +572 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/core-anti-patterns.md +411 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/detection-guide.md +569 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/tdd-connection.md +695 -0
- claude_mpm/skills/bundled/testing/webapp-testing/SKILL.md +184 -0
- claude_mpm/skills/bundled/testing/webapp-testing/decision-tree.md +459 -0
- claude_mpm/skills/bundled/testing/webapp-testing/playwright-patterns.md +479 -0
- claude_mpm/skills/bundled/testing/webapp-testing/reconnaissance-pattern.md +687 -0
- claude_mpm/skills/bundled/testing/webapp-testing/server-management.md +758 -0
- claude_mpm/skills/bundled/testing/webapp-testing/troubleshooting.md +868 -0
- claude_mpm/skills/registry.py +295 -90
- claude_mpm/skills/skill_manager.py +29 -23
- claude_mpm/templates/.pre-commit-config.yaml +112 -0
- claude_mpm/utils/agent_dependency_loader.py +103 -4
- claude_mpm/utils/robust_installer.py +45 -24
- claude_mpm-5.6.72.dist-info/METADATA +416 -0
- {claude_mpm-5.4.41.dist-info → claude_mpm-5.6.72.dist-info}/RECORD +477 -159
- {claude_mpm-5.4.41.dist-info → claude_mpm-5.6.72.dist-info}/WHEEL +1 -1
- {claude_mpm-5.4.41.dist-info → claude_mpm-5.6.72.dist-info}/entry_points.txt +2 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.B_FtCwCQ.css +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.Cl_eSA4x.css +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BgChzWQ1.js +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CIXEwuWe.js +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CWc5urbQ.js +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DMkZpdF2.js +0 -2
- claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/app.DTL5mJO-.js +0 -2
- claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.DzuEhzqh.js +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/1.DFLC8jdE.js +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.DPvEihJJ.js +0 -10
- claude_mpm/hooks/claude_hooks/__pycache__/installer.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager.cpython-311.pyc +0 -0
- claude_mpm-5.4.41.dist-info/METADATA +0 -998
- {claude_mpm-5.4.41.dist-info → claude_mpm-5.6.72.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-5.4.41.dist-info → claude_mpm-5.6.72.dist-info}/licenses/LICENSE-FAQ.md +0 -0
- {claude_mpm-5.4.41.dist-info → claude_mpm-5.6.72.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,577 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Deployment Reconciliation Service - Simplified Deployment Model
|
|
3
|
+
|
|
4
|
+
This service implements the simplified deployment model where:
|
|
5
|
+
1. Configuration has explicit lists: agents.enabled and skills.enabled
|
|
6
|
+
2. On startup/sync, reconcile deployed state with configured state
|
|
7
|
+
3. Deploy agents from cache to project .claude/ directories
|
|
8
|
+
4. Remove agents/skills NOT in enabled lists
|
|
9
|
+
|
|
10
|
+
Key Principles:
|
|
11
|
+
- Explicit configuration over auto-discovery
|
|
12
|
+
- Clear reconciliation view (configured vs deployed)
|
|
13
|
+
- Simple cleanup of unneeded agents/skills
|
|
14
|
+
- Backward compatibility with empty enabled lists
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
import shutil
|
|
18
|
+
from dataclasses import dataclass
|
|
19
|
+
from pathlib import Path
|
|
20
|
+
from typing import Dict, List, Optional, Set
|
|
21
|
+
|
|
22
|
+
from claude_mpm.core.logging_utils import get_logger
|
|
23
|
+
from claude_mpm.core.unified_config import UnifiedConfig
|
|
24
|
+
from claude_mpm.core.unified_paths import get_path_manager
|
|
25
|
+
|
|
26
|
+
logger = get_logger(__name__)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@dataclass
|
|
30
|
+
class DeploymentResult:
|
|
31
|
+
"""Result of deployment reconciliation."""
|
|
32
|
+
|
|
33
|
+
deployed: List[str] # Newly deployed
|
|
34
|
+
removed: List[str] # Removed (not in config)
|
|
35
|
+
unchanged: List[str] # Already deployed and still needed
|
|
36
|
+
errors: List[str] # Errors during reconciliation
|
|
37
|
+
|
|
38
|
+
@property
|
|
39
|
+
def success(self) -> bool:
|
|
40
|
+
"""Whether reconciliation succeeded (no errors)."""
|
|
41
|
+
return len(self.errors) == 0
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@dataclass
|
|
45
|
+
class ReconciliationState:
|
|
46
|
+
"""Current state of agent/skill deployment."""
|
|
47
|
+
|
|
48
|
+
configured: Set[str] # IDs in config enabled list
|
|
49
|
+
deployed: Set[str] # IDs currently deployed
|
|
50
|
+
cached: Set[str] # IDs available in cache
|
|
51
|
+
|
|
52
|
+
@property
|
|
53
|
+
def to_deploy(self) -> Set[str]:
|
|
54
|
+
"""Agents/skills that need deployment (in config but not deployed)."""
|
|
55
|
+
return self.configured - self.deployed
|
|
56
|
+
|
|
57
|
+
@property
|
|
58
|
+
def to_remove(self) -> Set[str]:
|
|
59
|
+
"""Agents/skills that should be removed (deployed but not in config)."""
|
|
60
|
+
return self.deployed - self.configured
|
|
61
|
+
|
|
62
|
+
@property
|
|
63
|
+
def unchanged(self) -> Set[str]:
|
|
64
|
+
"""Agents/skills already deployed and still needed."""
|
|
65
|
+
return self.configured & self.deployed
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class DeploymentReconciler:
|
|
69
|
+
"""
|
|
70
|
+
Reconciles configured agents/skills with deployed state.
|
|
71
|
+
|
|
72
|
+
This service implements the simplified deployment model:
|
|
73
|
+
1. Read agents.enabled and skills.enabled from config
|
|
74
|
+
2. Discover what's currently deployed in .claude/agents and .claude/skills
|
|
75
|
+
3. Deploy missing agents/skills from cache
|
|
76
|
+
4. Remove agents/skills not in enabled lists
|
|
77
|
+
"""
|
|
78
|
+
|
|
79
|
+
def __init__(self, config: Optional[UnifiedConfig] = None):
|
|
80
|
+
"""
|
|
81
|
+
Initialize reconciler.
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
config: UnifiedConfig instance (auto-loads if None)
|
|
85
|
+
"""
|
|
86
|
+
self.config = config or self._load_config()
|
|
87
|
+
self.path_manager = get_path_manager()
|
|
88
|
+
|
|
89
|
+
def _load_config(self) -> UnifiedConfig:
|
|
90
|
+
"""Load configuration from standard location."""
|
|
91
|
+
# For now, return default config
|
|
92
|
+
# TODO: Load from .claude-mpm/configuration.yaml
|
|
93
|
+
return UnifiedConfig()
|
|
94
|
+
|
|
95
|
+
def reconcile_agents(self, project_path: Optional[Path] = None) -> DeploymentResult:
|
|
96
|
+
"""
|
|
97
|
+
Reconcile agent deployment with configuration.
|
|
98
|
+
|
|
99
|
+
Args:
|
|
100
|
+
project_path: Project directory (default: current directory)
|
|
101
|
+
|
|
102
|
+
Returns:
|
|
103
|
+
DeploymentResult with reconciliation summary
|
|
104
|
+
"""
|
|
105
|
+
project_path = project_path or Path.cwd()
|
|
106
|
+
cache_dir = self.path_manager.get_cache_dir() / "agents"
|
|
107
|
+
deploy_dir = project_path / ".claude" / "agents"
|
|
108
|
+
|
|
109
|
+
# Get current state
|
|
110
|
+
state = self._get_agent_state(cache_dir, deploy_dir)
|
|
111
|
+
|
|
112
|
+
# Check backward compatibility
|
|
113
|
+
if not self.config.agents.enabled and self.config.agents.auto_discover:
|
|
114
|
+
logger.warning(
|
|
115
|
+
"agents.enabled is empty and auto_discover is True. "
|
|
116
|
+
"Consider migrating to explicit agent list. "
|
|
117
|
+
"Falling back to auto-discovery mode."
|
|
118
|
+
)
|
|
119
|
+
# In auto-discovery mode, don't remove anything
|
|
120
|
+
return DeploymentResult(
|
|
121
|
+
deployed=[], removed=[], unchanged=list(state.deployed), errors=[]
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
result = DeploymentResult(deployed=[], removed=[], unchanged=[], errors=[])
|
|
125
|
+
|
|
126
|
+
# Deploy missing agents
|
|
127
|
+
for agent_id in state.to_deploy:
|
|
128
|
+
if agent_id not in state.cached:
|
|
129
|
+
error_msg = f"Agent '{agent_id}' not found in cache. Run 'claude-mpm agents sync' first."
|
|
130
|
+
logger.warning(error_msg)
|
|
131
|
+
result.errors.append(error_msg)
|
|
132
|
+
continue
|
|
133
|
+
|
|
134
|
+
try:
|
|
135
|
+
self._deploy_agent(agent_id, cache_dir, deploy_dir)
|
|
136
|
+
result.deployed.append(agent_id)
|
|
137
|
+
logger.info(f"Deployed agent: {agent_id}")
|
|
138
|
+
except Exception as e:
|
|
139
|
+
error_msg = f"Failed to deploy agent '{agent_id}': {e}"
|
|
140
|
+
logger.error(error_msg)
|
|
141
|
+
result.errors.append(error_msg)
|
|
142
|
+
|
|
143
|
+
# Remove unneeded agents (only MPM agents, not user-created)
|
|
144
|
+
for agent_id in state.to_remove:
|
|
145
|
+
try:
|
|
146
|
+
if self._is_mpm_agent(deploy_dir, agent_id):
|
|
147
|
+
self._remove_agent(agent_id, deploy_dir)
|
|
148
|
+
result.removed.append(agent_id)
|
|
149
|
+
logger.info(f"Removed agent: {agent_id}")
|
|
150
|
+
else:
|
|
151
|
+
logger.debug(f"Skipping removal of user agent: {agent_id}")
|
|
152
|
+
result.unchanged.append(agent_id)
|
|
153
|
+
except Exception as e:
|
|
154
|
+
error_msg = f"Failed to remove agent '{agent_id}': {e}"
|
|
155
|
+
logger.error(error_msg)
|
|
156
|
+
result.errors.append(error_msg)
|
|
157
|
+
|
|
158
|
+
# Track unchanged agents
|
|
159
|
+
result.unchanged.extend(list(state.unchanged))
|
|
160
|
+
|
|
161
|
+
return result
|
|
162
|
+
|
|
163
|
+
def reconcile_skills(self, project_path: Optional[Path] = None) -> DeploymentResult:
|
|
164
|
+
"""
|
|
165
|
+
Reconcile skill deployment with configuration.
|
|
166
|
+
|
|
167
|
+
This includes:
|
|
168
|
+
1. Skills in skills.enabled list
|
|
169
|
+
2. Skills required by enabled agents (if auto_detect_dependencies=True)
|
|
170
|
+
|
|
171
|
+
Args:
|
|
172
|
+
project_path: Project directory (default: current directory)
|
|
173
|
+
|
|
174
|
+
Returns:
|
|
175
|
+
DeploymentResult with reconciliation summary
|
|
176
|
+
"""
|
|
177
|
+
project_path = project_path or Path.cwd()
|
|
178
|
+
cache_dir = self.path_manager.get_cache_dir() / "skills"
|
|
179
|
+
deploy_dir = project_path / ".claude" / "skills"
|
|
180
|
+
|
|
181
|
+
# Get configured skills (explicit + agent dependencies)
|
|
182
|
+
configured_skills = set(self.config.skills.enabled)
|
|
183
|
+
|
|
184
|
+
if self.config.skills.auto_detect_dependencies:
|
|
185
|
+
# Add skills required by enabled agents
|
|
186
|
+
agent_skill_deps = self._get_agent_skill_dependencies(
|
|
187
|
+
self.config.agents.enabled
|
|
188
|
+
)
|
|
189
|
+
configured_skills.update(agent_skill_deps)
|
|
190
|
+
|
|
191
|
+
# Get current state
|
|
192
|
+
state = ReconciliationState(
|
|
193
|
+
configured=configured_skills,
|
|
194
|
+
deployed=self._list_deployed_skills(deploy_dir),
|
|
195
|
+
cached=self._list_cached_skills(cache_dir),
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
result = DeploymentResult(deployed=[], removed=[], unchanged=[], errors=[])
|
|
199
|
+
|
|
200
|
+
# Deploy missing skills
|
|
201
|
+
for skill_id in state.to_deploy:
|
|
202
|
+
if skill_id not in state.cached:
|
|
203
|
+
error_msg = (
|
|
204
|
+
f"Skill '{skill_id}' not found in cache. Check skill sources."
|
|
205
|
+
)
|
|
206
|
+
logger.warning(error_msg)
|
|
207
|
+
result.errors.append(error_msg)
|
|
208
|
+
continue
|
|
209
|
+
|
|
210
|
+
try:
|
|
211
|
+
self._deploy_skill(skill_id, cache_dir, deploy_dir)
|
|
212
|
+
result.deployed.append(skill_id)
|
|
213
|
+
logger.info(f"Deployed skill: {skill_id}")
|
|
214
|
+
except Exception as e:
|
|
215
|
+
error_msg = f"Failed to deploy skill '{skill_id}': {e}"
|
|
216
|
+
logger.error(error_msg)
|
|
217
|
+
result.errors.append(error_msg)
|
|
218
|
+
|
|
219
|
+
# Remove unneeded skills (only MPM skills)
|
|
220
|
+
for skill_id in state.to_remove:
|
|
221
|
+
try:
|
|
222
|
+
if self._is_mpm_skill(deploy_dir, skill_id):
|
|
223
|
+
self._remove_skill(skill_id, deploy_dir)
|
|
224
|
+
result.removed.append(skill_id)
|
|
225
|
+
logger.info(f"Removed skill: {skill_id}")
|
|
226
|
+
else:
|
|
227
|
+
logger.debug(f"Skipping removal of user skill: {skill_id}")
|
|
228
|
+
result.unchanged.append(skill_id)
|
|
229
|
+
except Exception as e:
|
|
230
|
+
error_msg = f"Failed to remove skill '{skill_id}': {e}"
|
|
231
|
+
logger.error(error_msg)
|
|
232
|
+
result.errors.append(error_msg)
|
|
233
|
+
|
|
234
|
+
# Track unchanged skills
|
|
235
|
+
result.unchanged.extend(list(state.unchanged))
|
|
236
|
+
|
|
237
|
+
return result
|
|
238
|
+
|
|
239
|
+
def _get_agent_state(
|
|
240
|
+
self, cache_dir: Path, deploy_dir: Path
|
|
241
|
+
) -> ReconciliationState:
|
|
242
|
+
"""Get current agent deployment state."""
|
|
243
|
+
# Start with enabled agents
|
|
244
|
+
configured_agents = set(self.config.agents.enabled)
|
|
245
|
+
|
|
246
|
+
# Add required agents (cannot be disabled)
|
|
247
|
+
configured_agents.update(self.config.agents.required)
|
|
248
|
+
|
|
249
|
+
# Add universal agents if enabled
|
|
250
|
+
if self.config.agents.include_universal:
|
|
251
|
+
universal_agents = self._get_universal_agents(cache_dir)
|
|
252
|
+
configured_agents.update(universal_agents)
|
|
253
|
+
|
|
254
|
+
return ReconciliationState(
|
|
255
|
+
configured=configured_agents,
|
|
256
|
+
deployed=self._list_deployed_agents(deploy_dir),
|
|
257
|
+
cached=self._list_cached_agents(cache_dir),
|
|
258
|
+
)
|
|
259
|
+
|
|
260
|
+
def _get_universal_agents(self, cache_dir: Path) -> Set[str]:
|
|
261
|
+
"""Get all agents with 'universal' toolchain/category."""
|
|
262
|
+
universal_agents = set()
|
|
263
|
+
if not cache_dir.exists():
|
|
264
|
+
return universal_agents
|
|
265
|
+
|
|
266
|
+
for agent_file in cache_dir.glob("**/*.md"):
|
|
267
|
+
try:
|
|
268
|
+
# Read frontmatter to check toolchain/category
|
|
269
|
+
content = agent_file.read_text(encoding="utf-8")
|
|
270
|
+
|
|
271
|
+
# Check for universal markers in frontmatter (within first 1000 chars)
|
|
272
|
+
frontmatter_section = content[:1000].lower()
|
|
273
|
+
if (
|
|
274
|
+
"toolchain: universal" in frontmatter_section
|
|
275
|
+
or "category: universal" in frontmatter_section
|
|
276
|
+
or "toolchain:\n - universal" in frontmatter_section
|
|
277
|
+
):
|
|
278
|
+
universal_agents.add(agent_file.stem)
|
|
279
|
+
except Exception as e:
|
|
280
|
+
logger.debug(
|
|
281
|
+
f"Failed to check universal marker for {agent_file.name}: {e}"
|
|
282
|
+
)
|
|
283
|
+
continue
|
|
284
|
+
|
|
285
|
+
return universal_agents
|
|
286
|
+
|
|
287
|
+
def _list_deployed_agents(self, deploy_dir: Path) -> Set[str]:
|
|
288
|
+
"""List agent IDs currently deployed."""
|
|
289
|
+
if not deploy_dir.exists():
|
|
290
|
+
return set()
|
|
291
|
+
|
|
292
|
+
agent_ids = set()
|
|
293
|
+
for agent_file in deploy_dir.glob("*.md"):
|
|
294
|
+
# Extract agent ID from filename (remove .md extension)
|
|
295
|
+
agent_id = agent_file.stem
|
|
296
|
+
agent_ids.add(agent_id)
|
|
297
|
+
|
|
298
|
+
return agent_ids
|
|
299
|
+
|
|
300
|
+
def _list_cached_agents(self, cache_dir: Path) -> Set[str]:
|
|
301
|
+
"""List agent IDs available in cache."""
|
|
302
|
+
if not cache_dir.exists():
|
|
303
|
+
return set()
|
|
304
|
+
|
|
305
|
+
agent_ids = set()
|
|
306
|
+
for agent_file in cache_dir.glob("**/*.md"):
|
|
307
|
+
# Extract agent ID from filename
|
|
308
|
+
agent_id = agent_file.stem
|
|
309
|
+
agent_ids.add(agent_id)
|
|
310
|
+
|
|
311
|
+
return agent_ids
|
|
312
|
+
|
|
313
|
+
def _list_deployed_skills(self, deploy_dir: Path) -> Set[str]:
|
|
314
|
+
"""List skill IDs currently deployed."""
|
|
315
|
+
if not deploy_dir.exists():
|
|
316
|
+
return set()
|
|
317
|
+
|
|
318
|
+
skill_ids = set()
|
|
319
|
+
for skill_file in deploy_dir.glob("*.md"):
|
|
320
|
+
skill_id = skill_file.stem
|
|
321
|
+
skill_ids.add(skill_id)
|
|
322
|
+
|
|
323
|
+
return skill_ids
|
|
324
|
+
|
|
325
|
+
def _list_cached_skills(self, cache_dir: Path) -> Set[str]:
|
|
326
|
+
"""List skill IDs available in cache."""
|
|
327
|
+
if not cache_dir.exists():
|
|
328
|
+
return set()
|
|
329
|
+
|
|
330
|
+
skill_ids = set()
|
|
331
|
+
for skill_file in cache_dir.glob("**/*.md"):
|
|
332
|
+
skill_id = skill_file.stem
|
|
333
|
+
skill_ids.add(skill_id)
|
|
334
|
+
|
|
335
|
+
return skill_ids
|
|
336
|
+
|
|
337
|
+
def _deploy_agent(self, agent_id: str, cache_dir: Path, deploy_dir: Path) -> None:
|
|
338
|
+
"""Deploy agent from cache to project directory."""
|
|
339
|
+
# Find agent file in cache
|
|
340
|
+
agent_file = self._find_file_in_cache(agent_id, cache_dir, "*.md")
|
|
341
|
+
if not agent_file:
|
|
342
|
+
raise FileNotFoundError(f"Agent file for '{agent_id}' not found in cache")
|
|
343
|
+
|
|
344
|
+
# Ensure deploy directory exists
|
|
345
|
+
deploy_dir.mkdir(parents=True, exist_ok=True)
|
|
346
|
+
|
|
347
|
+
# Copy agent file to deployment directory
|
|
348
|
+
dest_file = deploy_dir / agent_file.name
|
|
349
|
+
shutil.copy2(agent_file, dest_file)
|
|
350
|
+
|
|
351
|
+
def _deploy_skill(self, skill_id: str, cache_dir: Path, deploy_dir: Path) -> None:
|
|
352
|
+
"""Deploy skill from cache to project directory."""
|
|
353
|
+
# Find skill file in cache
|
|
354
|
+
skill_file = self._find_file_in_cache(skill_id, cache_dir, "*.md")
|
|
355
|
+
if not skill_file:
|
|
356
|
+
raise FileNotFoundError(f"Skill file for '{skill_id}' not found in cache")
|
|
357
|
+
|
|
358
|
+
# Ensure deploy directory exists
|
|
359
|
+
deploy_dir.mkdir(parents=True, exist_ok=True)
|
|
360
|
+
|
|
361
|
+
# Copy skill file to deployment directory
|
|
362
|
+
dest_file = deploy_dir / skill_file.name
|
|
363
|
+
shutil.copy2(skill_file, dest_file)
|
|
364
|
+
|
|
365
|
+
def _remove_agent(self, agent_id: str, deploy_dir: Path) -> None:
|
|
366
|
+
"""Remove deployed agent."""
|
|
367
|
+
agent_file = deploy_dir / f"{agent_id}.md"
|
|
368
|
+
if agent_file.exists():
|
|
369
|
+
agent_file.unlink()
|
|
370
|
+
|
|
371
|
+
def _remove_skill(self, skill_id: str, deploy_dir: Path) -> None:
|
|
372
|
+
"""Remove deployed skill."""
|
|
373
|
+
skill_file = deploy_dir / f"{skill_id}.md"
|
|
374
|
+
if skill_file.exists():
|
|
375
|
+
skill_file.unlink()
|
|
376
|
+
|
|
377
|
+
def _is_mpm_agent(self, deploy_dir: Path, agent_id: str) -> bool:
|
|
378
|
+
"""Check if agent is managed by MPM (not user-created)."""
|
|
379
|
+
agent_file = deploy_dir / f"{agent_id}.md"
|
|
380
|
+
if not agent_file.exists():
|
|
381
|
+
return False
|
|
382
|
+
|
|
383
|
+
try:
|
|
384
|
+
content = agent_file.read_text(encoding="utf-8")
|
|
385
|
+
# Check for MPM author markers
|
|
386
|
+
mpm_markers = [
|
|
387
|
+
"author: claude-mpm",
|
|
388
|
+
"author: 'claude-mpm'",
|
|
389
|
+
"author: anthropic",
|
|
390
|
+
]
|
|
391
|
+
return any(marker in content.lower() for marker in mpm_markers)
|
|
392
|
+
except Exception as e:
|
|
393
|
+
logger.warning(f"Failed to check MPM marker for {agent_id}: {e}")
|
|
394
|
+
return False
|
|
395
|
+
|
|
396
|
+
def _is_mpm_skill(self, deploy_dir: Path, skill_id: str) -> bool:
|
|
397
|
+
"""Check if skill is managed by MPM (not user-created)."""
|
|
398
|
+
skill_file = deploy_dir / f"{skill_id}.md"
|
|
399
|
+
if not skill_file.exists():
|
|
400
|
+
return False
|
|
401
|
+
|
|
402
|
+
try:
|
|
403
|
+
content = skill_file.read_text(encoding="utf-8")
|
|
404
|
+
# Check for MPM author markers
|
|
405
|
+
mpm_markers = [
|
|
406
|
+
"author: claude-mpm",
|
|
407
|
+
"author: 'claude-mpm'",
|
|
408
|
+
"author: anthropic",
|
|
409
|
+
]
|
|
410
|
+
return any(marker in content.lower() for marker in mpm_markers)
|
|
411
|
+
except Exception as e:
|
|
412
|
+
logger.warning(f"Failed to check MPM marker for {skill_id}: {e}")
|
|
413
|
+
return False
|
|
414
|
+
|
|
415
|
+
def _find_file_in_cache(
|
|
416
|
+
self, item_id: str, cache_dir: Path, pattern: str
|
|
417
|
+
) -> Optional[Path]:
|
|
418
|
+
"""Find file in cache directory by ID pattern."""
|
|
419
|
+
# Try exact match first
|
|
420
|
+
exact_match = cache_dir / f"{item_id}.md"
|
|
421
|
+
if exact_match.exists():
|
|
422
|
+
return exact_match
|
|
423
|
+
|
|
424
|
+
# Search recursively
|
|
425
|
+
for file_path in cache_dir.glob(f"**/{item_id}.md"):
|
|
426
|
+
return file_path
|
|
427
|
+
|
|
428
|
+
return None
|
|
429
|
+
|
|
430
|
+
def _get_agent_skill_dependencies(self, agent_ids: List[str]) -> Set[str]:
|
|
431
|
+
"""
|
|
432
|
+
Get skill dependencies for enabled agents.
|
|
433
|
+
|
|
434
|
+
This reads agent frontmatter to find required skills.
|
|
435
|
+
|
|
436
|
+
Args:
|
|
437
|
+
agent_ids: List of enabled agent IDs
|
|
438
|
+
|
|
439
|
+
Returns:
|
|
440
|
+
Set of skill IDs required by these agents
|
|
441
|
+
"""
|
|
442
|
+
skill_deps = set()
|
|
443
|
+
|
|
444
|
+
# Get deployed agents directory
|
|
445
|
+
project_path = Path.cwd()
|
|
446
|
+
agents_dir = project_path / ".claude" / "agents"
|
|
447
|
+
|
|
448
|
+
if not agents_dir.exists():
|
|
449
|
+
logger.debug("No agents directory found, cannot extract skill dependencies")
|
|
450
|
+
return skill_deps
|
|
451
|
+
|
|
452
|
+
for agent_id in agent_ids:
|
|
453
|
+
agent_file = agents_dir / f"{agent_id}.md"
|
|
454
|
+
if not agent_file.exists():
|
|
455
|
+
logger.debug(
|
|
456
|
+
f"Agent file not found for {agent_id}, skipping skill dependency extraction"
|
|
457
|
+
)
|
|
458
|
+
continue
|
|
459
|
+
|
|
460
|
+
try:
|
|
461
|
+
# Parse frontmatter to get skills list
|
|
462
|
+
skills = self._parse_agent_skills_from_frontmatter(agent_file)
|
|
463
|
+
if skills:
|
|
464
|
+
logger.debug(f"Agent {agent_id} requires skills: {skills}")
|
|
465
|
+
skill_deps.update(skills)
|
|
466
|
+
except Exception as e:
|
|
467
|
+
logger.warning(f"Failed to parse skills from {agent_id}: {e}")
|
|
468
|
+
|
|
469
|
+
return skill_deps
|
|
470
|
+
|
|
471
|
+
def _parse_agent_skills_from_frontmatter(self, agent_file: Path) -> List[str]:
|
|
472
|
+
"""
|
|
473
|
+
Parse skills list from agent frontmatter.
|
|
474
|
+
|
|
475
|
+
Expected frontmatter format:
|
|
476
|
+
---
|
|
477
|
+
name: Python Engineer
|
|
478
|
+
skills:
|
|
479
|
+
- pytest
|
|
480
|
+
- git-workflow
|
|
481
|
+
---
|
|
482
|
+
|
|
483
|
+
Args:
|
|
484
|
+
agent_file: Path to agent .md file
|
|
485
|
+
|
|
486
|
+
Returns:
|
|
487
|
+
List of skill IDs from frontmatter (empty if none found)
|
|
488
|
+
"""
|
|
489
|
+
try:
|
|
490
|
+
import yaml
|
|
491
|
+
except ImportError:
|
|
492
|
+
logger.warning("PyYAML not installed, cannot parse agent frontmatter")
|
|
493
|
+
return []
|
|
494
|
+
|
|
495
|
+
try:
|
|
496
|
+
content = agent_file.read_text(encoding="utf-8")
|
|
497
|
+
|
|
498
|
+
# Check for frontmatter delimiters
|
|
499
|
+
if not content.startswith("---"):
|
|
500
|
+
return []
|
|
501
|
+
|
|
502
|
+
# Find end of frontmatter
|
|
503
|
+
end_marker = content.find("\n---\n", 4)
|
|
504
|
+
if end_marker == -1:
|
|
505
|
+
end_marker = content.find("\n---\r\n", 4)
|
|
506
|
+
|
|
507
|
+
if end_marker == -1:
|
|
508
|
+
logger.debug(
|
|
509
|
+
f"No valid frontmatter end marker found in {agent_file.name}"
|
|
510
|
+
)
|
|
511
|
+
return []
|
|
512
|
+
|
|
513
|
+
# Extract frontmatter YAML
|
|
514
|
+
frontmatter_yaml = content[4:end_marker]
|
|
515
|
+
|
|
516
|
+
# Parse YAML
|
|
517
|
+
frontmatter = yaml.safe_load(frontmatter_yaml)
|
|
518
|
+
|
|
519
|
+
if not frontmatter or not isinstance(frontmatter, dict):
|
|
520
|
+
return []
|
|
521
|
+
|
|
522
|
+
# Get skills list
|
|
523
|
+
skills = frontmatter.get("skills", [])
|
|
524
|
+
if isinstance(skills, list):
|
|
525
|
+
return [str(skill) for skill in skills]
|
|
526
|
+
logger.debug(
|
|
527
|
+
f"Skills field in {agent_file.name} is not a list: {type(skills)}"
|
|
528
|
+
)
|
|
529
|
+
return []
|
|
530
|
+
|
|
531
|
+
except yaml.YAMLError as e:
|
|
532
|
+
logger.warning(
|
|
533
|
+
f"Failed to parse YAML frontmatter in {agent_file.name}: {e}"
|
|
534
|
+
)
|
|
535
|
+
return []
|
|
536
|
+
except Exception as e:
|
|
537
|
+
logger.warning(
|
|
538
|
+
f"Unexpected error parsing frontmatter in {agent_file.name}: {e}"
|
|
539
|
+
)
|
|
540
|
+
return []
|
|
541
|
+
|
|
542
|
+
def get_reconciliation_view(
|
|
543
|
+
self, project_path: Optional[Path] = None
|
|
544
|
+
) -> Dict[str, ReconciliationState]:
|
|
545
|
+
"""
|
|
546
|
+
Get reconciliation view for agents and skills.
|
|
547
|
+
|
|
548
|
+
Args:
|
|
549
|
+
project_path: Project directory
|
|
550
|
+
|
|
551
|
+
Returns:
|
|
552
|
+
Dictionary with 'agents' and 'skills' reconciliation states
|
|
553
|
+
"""
|
|
554
|
+
project_path = project_path or Path.cwd()
|
|
555
|
+
|
|
556
|
+
# Get agent state
|
|
557
|
+
agent_cache = self.path_manager.get_cache_dir() / "agents"
|
|
558
|
+
agent_deploy = project_path / ".claude" / "agents"
|
|
559
|
+
agent_state = self._get_agent_state(agent_cache, agent_deploy)
|
|
560
|
+
|
|
561
|
+
# Get skill state
|
|
562
|
+
skill_cache = self.path_manager.get_cache_dir() / "skills"
|
|
563
|
+
skill_deploy = project_path / ".claude" / "skills"
|
|
564
|
+
|
|
565
|
+
configured_skills = set(self.config.skills.enabled)
|
|
566
|
+
if self.config.skills.auto_detect_dependencies:
|
|
567
|
+
configured_skills.update(
|
|
568
|
+
self._get_agent_skill_dependencies(self.config.agents.enabled)
|
|
569
|
+
)
|
|
570
|
+
|
|
571
|
+
skill_state = ReconciliationState(
|
|
572
|
+
configured=configured_skills,
|
|
573
|
+
deployed=self._list_deployed_skills(skill_deploy),
|
|
574
|
+
cached=self._list_cached_skills(skill_cache),
|
|
575
|
+
)
|
|
576
|
+
|
|
577
|
+
return {"agents": agent_state, "skills": skill_state}
|
|
@@ -157,7 +157,9 @@ class LocalTemplateDeploymentService:
|
|
|
157
157
|
|
|
158
158
|
# Add capabilities
|
|
159
159
|
if template.capabilities:
|
|
160
|
-
|
|
160
|
+
# Only include model if explicitly set (no default)
|
|
161
|
+
if "model" in template.capabilities:
|
|
162
|
+
frontmatter["model"] = template.capabilities["model"]
|
|
161
163
|
tools = template.capabilities.get("tools", "*")
|
|
162
164
|
if tools == "*":
|
|
163
165
|
frontmatter["tools"] = "all"
|
|
@@ -26,6 +26,18 @@ from .agent_version_manager import AgentVersionManager
|
|
|
26
26
|
from .remote_agent_discovery_service import RemoteAgentDiscoveryService
|
|
27
27
|
|
|
28
28
|
|
|
29
|
+
def _normalize_agent_name(name: str) -> str:
|
|
30
|
+
"""Normalize agent name for consistent comparison.
|
|
31
|
+
|
|
32
|
+
Converts spaces, underscores to hyphens and lowercases.
|
|
33
|
+
Examples:
|
|
34
|
+
"Dart Engineer" -> "dart-engineer"
|
|
35
|
+
"dart_engineer" -> "dart-engineer"
|
|
36
|
+
"DART-ENGINEER" -> "dart-engineer"
|
|
37
|
+
"""
|
|
38
|
+
return name.lower().replace(" ", "-").replace("_", "-")
|
|
39
|
+
|
|
40
|
+
|
|
29
41
|
class MultiSourceAgentDeploymentService:
|
|
30
42
|
"""Service for deploying agents from multiple sources with version comparison.
|
|
31
43
|
|
|
@@ -531,22 +543,36 @@ class MultiSourceAgentDeploymentService:
|
|
|
531
543
|
|
|
532
544
|
# Apply exclusion filters
|
|
533
545
|
if excluded_agents:
|
|
534
|
-
# Find agents to remove by matching
|
|
546
|
+
# Find agents to remove by matching normalized names
|
|
547
|
+
# Normalization handles: "Dart Engineer", "dart_engineer", "dart-engineer"
|
|
535
548
|
agents_to_remove = []
|
|
536
|
-
excluded_set = {name
|
|
549
|
+
excluded_set = {_normalize_agent_name(name) for name in excluded_agents}
|
|
537
550
|
|
|
538
551
|
for canonical_id, agent_info in list(selected_agents.items()):
|
|
539
|
-
# Check agent name field
|
|
540
|
-
agent_name = agent_info.get("name", "")
|
|
552
|
+
# Check agent name field (normalized)
|
|
553
|
+
agent_name = _normalize_agent_name(agent_info.get("name", ""))
|
|
541
554
|
|
|
542
555
|
# Also check the agent_id portion of canonical_id (after the colon)
|
|
543
556
|
# Example: "bobmatnyc/claude-mpm-agents:pm" -> "pm"
|
|
544
|
-
|
|
557
|
+
raw_agent_id = (
|
|
558
|
+
canonical_id.split(":")[-1] if ":" in canonical_id else canonical_id
|
|
559
|
+
)
|
|
560
|
+
agent_id = _normalize_agent_name(raw_agent_id)
|
|
561
|
+
|
|
562
|
+
# Check file stem from path (most reliable match)
|
|
563
|
+
file_stem = ""
|
|
564
|
+
path_str = agent_info.get("path") or agent_info.get("file_path")
|
|
565
|
+
if path_str:
|
|
566
|
+
file_stem = _normalize_agent_name(Path(path_str).stem)
|
|
545
567
|
|
|
546
|
-
if
|
|
568
|
+
if (
|
|
569
|
+
agent_name in excluded_set
|
|
570
|
+
or agent_id in excluded_set
|
|
571
|
+
or file_stem in excluded_set
|
|
572
|
+
):
|
|
547
573
|
agents_to_remove.append(canonical_id)
|
|
548
574
|
self.logger.info(
|
|
549
|
-
f"Excluding agent '{agent_info.get('name',
|
|
575
|
+
f"Excluding agent '{agent_info.get('name', raw_agent_id)}' "
|
|
550
576
|
f"(canonical_id: {canonical_id}) from deployment"
|
|
551
577
|
)
|
|
552
578
|
|
|
@@ -625,7 +651,9 @@ class MultiSourceAgentDeploymentService:
|
|
|
625
651
|
|
|
626
652
|
# Safety check - only operate on deployed agents directory
|
|
627
653
|
if not deployed_agents_dir.exists():
|
|
628
|
-
self.logger.debug(
|
|
654
|
+
self.logger.debug(
|
|
655
|
+
"Deployed agents directory does not exist, no cleanup needed"
|
|
656
|
+
)
|
|
629
657
|
return cleanup_results
|
|
630
658
|
|
|
631
659
|
# Build set of agent names that should exist (file stems without .md extension)
|