claude-mpm 5.0.9__py3-none-any.whl → 5.6.23__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of claude-mpm might be problematic. Click here for more details.
- claude_mpm/VERSION +1 -1
- claude_mpm/__init__.py +4 -0
- claude_mpm/agents/BASE_AGENT.md +164 -0
- claude_mpm/agents/CLAUDE_MPM_OUTPUT_STYLE.md +115 -0
- claude_mpm/agents/CLAUDE_MPM_RESEARCH_OUTPUT_STYLE.md +413 -0
- claude_mpm/agents/CLAUDE_MPM_TEACHER_OUTPUT_STYLE.md +186 -0
- claude_mpm/agents/MEMORY.md +1 -1
- claude_mpm/agents/PM_INSTRUCTIONS.md +479 -616
- claude_mpm/agents/WORKFLOW.md +6 -253
- claude_mpm/agents/agent_loader.py +13 -44
- claude_mpm/agents/base_agent.json +1 -1
- claude_mpm/agents/frontmatter_validator.py +70 -2
- claude_mpm/agents/templates/circuit-breakers.md +457 -62
- claude_mpm/cli/__init__.py +5 -2
- claude_mpm/cli/__main__.py +4 -0
- claude_mpm/cli/chrome_devtools_installer.py +175 -0
- claude_mpm/cli/commands/agent_state_manager.py +18 -27
- claude_mpm/cli/commands/agents.py +177 -41
- claude_mpm/cli/commands/agents_reconcile.py +197 -0
- claude_mpm/cli/commands/auto_configure.py +723 -236
- claude_mpm/cli/commands/autotodos.py +566 -0
- claude_mpm/cli/commands/commander.py +216 -0
- claude_mpm/cli/commands/config.py +88 -2
- claude_mpm/cli/commands/configure.py +1874 -170
- claude_mpm/cli/commands/configure_agent_display.py +27 -6
- 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 +232 -46
- claude_mpm/cli/commands/mpm_init/knowledge_extractor.py +481 -0
- claude_mpm/cli/commands/mpm_init/prompts.py +280 -0
- claude_mpm/cli/commands/postmortem.py +1 -1
- claude_mpm/cli/commands/profile.py +276 -0
- claude_mpm/cli/commands/run.py +35 -3
- claude_mpm/cli/commands/skill_source.py +51 -2
- claude_mpm/cli/commands/skills.py +379 -204
- claude_mpm/cli/commands/summarize.py +413 -0
- claude_mpm/cli/executor.py +141 -19
- claude_mpm/cli/interactive/__init__.py +10 -0
- claude_mpm/cli/interactive/agent_wizard.py +115 -60
- claude_mpm/cli/interactive/questionary_styles.py +65 -0
- claude_mpm/cli/interactive/skill_selector.py +481 -0
- claude_mpm/cli/parsers/agents_parser.py +54 -9
- claude_mpm/cli/parsers/auto_configure_parser.py +13 -138
- claude_mpm/cli/parsers/base_parser.py +88 -1
- claude_mpm/cli/parsers/commander_parser.py +116 -0
- claude_mpm/cli/parsers/config_parser.py +153 -83
- claude_mpm/cli/parsers/profile_parser.py +147 -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 +1 -1
- claude_mpm/cli/startup.py +1017 -266
- claude_mpm/cli/startup_display.py +74 -6
- claude_mpm/cli/startup_logging.py +2 -2
- claude_mpm/cli/utils.py +7 -3
- claude_mpm/commander/__init__.py +78 -0
- claude_mpm/commander/adapters/__init__.py +60 -0
- claude_mpm/commander/adapters/auggie.py +260 -0
- claude_mpm/commander/adapters/base.py +288 -0
- claude_mpm/commander/adapters/claude_code.py +392 -0
- claude_mpm/commander/adapters/codex.py +237 -0
- claude_mpm/commander/adapters/communication.py +366 -0
- claude_mpm/commander/adapters/example_usage.py +310 -0
- claude_mpm/commander/adapters/mpm.py +389 -0
- claude_mpm/commander/adapters/registry.py +204 -0
- claude_mpm/commander/api/__init__.py +16 -0
- claude_mpm/commander/api/app.py +121 -0
- claude_mpm/commander/api/errors.py +133 -0
- claude_mpm/commander/api/routes/__init__.py +8 -0
- claude_mpm/commander/api/routes/events.py +184 -0
- claude_mpm/commander/api/routes/inbox.py +171 -0
- claude_mpm/commander/api/routes/messages.py +148 -0
- claude_mpm/commander/api/routes/projects.py +271 -0
- claude_mpm/commander/api/routes/sessions.py +226 -0
- claude_mpm/commander/api/routes/work.py +296 -0
- claude_mpm/commander/api/schemas.py +186 -0
- claude_mpm/commander/chat/__init__.py +7 -0
- claude_mpm/commander/chat/cli.py +146 -0
- claude_mpm/commander/chat/commands.py +96 -0
- claude_mpm/commander/chat/repl.py +310 -0
- claude_mpm/commander/config.py +51 -0
- claude_mpm/commander/config_loader.py +115 -0
- claude_mpm/commander/core/__init__.py +10 -0
- claude_mpm/commander/core/block_manager.py +325 -0
- claude_mpm/commander/core/response_manager.py +323 -0
- claude_mpm/commander/daemon.py +603 -0
- claude_mpm/commander/env_loader.py +59 -0
- claude_mpm/commander/events/__init__.py +26 -0
- claude_mpm/commander/events/manager.py +332 -0
- claude_mpm/commander/frameworks/__init__.py +12 -0
- claude_mpm/commander/frameworks/base.py +146 -0
- claude_mpm/commander/frameworks/claude_code.py +58 -0
- claude_mpm/commander/frameworks/mpm.py +62 -0
- claude_mpm/commander/inbox/__init__.py +16 -0
- claude_mpm/commander/inbox/dedup.py +128 -0
- claude_mpm/commander/inbox/inbox.py +224 -0
- claude_mpm/commander/inbox/models.py +70 -0
- claude_mpm/commander/instance_manager.py +450 -0
- claude_mpm/commander/llm/__init__.py +6 -0
- claude_mpm/commander/llm/openrouter_client.py +167 -0
- claude_mpm/commander/llm/summarizer.py +70 -0
- claude_mpm/commander/memory/__init__.py +45 -0
- claude_mpm/commander/memory/compression.py +347 -0
- claude_mpm/commander/memory/embeddings.py +230 -0
- claude_mpm/commander/memory/entities.py +310 -0
- claude_mpm/commander/memory/example_usage.py +290 -0
- claude_mpm/commander/memory/integration.py +325 -0
- claude_mpm/commander/memory/search.py +381 -0
- claude_mpm/commander/memory/store.py +657 -0
- claude_mpm/commander/models/__init__.py +18 -0
- claude_mpm/commander/models/events.py +121 -0
- claude_mpm/commander/models/project.py +162 -0
- claude_mpm/commander/models/work.py +214 -0
- claude_mpm/commander/parsing/__init__.py +20 -0
- claude_mpm/commander/parsing/extractor.py +132 -0
- claude_mpm/commander/parsing/output_parser.py +270 -0
- claude_mpm/commander/parsing/patterns.py +100 -0
- claude_mpm/commander/persistence/__init__.py +11 -0
- claude_mpm/commander/persistence/event_store.py +274 -0
- claude_mpm/commander/persistence/state_store.py +309 -0
- claude_mpm/commander/persistence/work_store.py +164 -0
- claude_mpm/commander/polling/__init__.py +13 -0
- claude_mpm/commander/polling/event_detector.py +104 -0
- claude_mpm/commander/polling/output_buffer.py +49 -0
- claude_mpm/commander/polling/output_poller.py +153 -0
- claude_mpm/commander/project_session.py +268 -0
- claude_mpm/commander/proxy/__init__.py +12 -0
- claude_mpm/commander/proxy/formatter.py +89 -0
- claude_mpm/commander/proxy/output_handler.py +191 -0
- claude_mpm/commander/proxy/relay.py +155 -0
- claude_mpm/commander/registry.py +410 -0
- claude_mpm/commander/runtime/__init__.py +10 -0
- claude_mpm/commander/runtime/executor.py +191 -0
- claude_mpm/commander/runtime/monitor.py +346 -0
- claude_mpm/commander/session/__init__.py +6 -0
- claude_mpm/commander/session/context.py +81 -0
- claude_mpm/commander/session/manager.py +59 -0
- claude_mpm/commander/tmux_orchestrator.py +361 -0
- claude_mpm/commander/web/__init__.py +1 -0
- claude_mpm/commander/work/__init__.py +30 -0
- claude_mpm/commander/work/executor.py +207 -0
- claude_mpm/commander/work/queue.py +405 -0
- claude_mpm/commander/workflow/__init__.py +27 -0
- claude_mpm/commander/workflow/event_handler.py +241 -0
- claude_mpm/commander/workflow/notifier.py +146 -0
- claude_mpm/commands/mpm-config.md +36 -0
- claude_mpm/commands/mpm-doctor.md +16 -21
- claude_mpm/commands/mpm-help.md +12 -286
- claude_mpm/commands/mpm-init.md +88 -506
- claude_mpm/commands/mpm-monitor.md +22 -401
- claude_mpm/commands/mpm-organize.md +128 -0
- claude_mpm/commands/mpm-postmortem.md +13 -107
- claude_mpm/commands/mpm-session-resume.md +20 -363
- claude_mpm/commands/mpm-status.md +13 -69
- claude_mpm/commands/mpm-ticket-view.md +60 -495
- claude_mpm/commands/mpm-version.md +13 -107
- claude_mpm/commands/mpm.md +8 -0
- claude_mpm/config/agent_presets.py +8 -7
- claude_mpm/config/agent_sources.py +27 -0
- claude_mpm/config/skill_sources.py +16 -0
- claude_mpm/constants.py +1 -0
- claude_mpm/core/claude_runner.py +154 -2
- claude_mpm/core/config.py +37 -26
- claude_mpm/core/config_constants.py +74 -9
- claude_mpm/core/constants.py +56 -12
- claude_mpm/core/framework/formatters/content_formatter.py +3 -13
- claude_mpm/core/framework/loaders/agent_loader.py +8 -5
- claude_mpm/core/framework/loaders/instruction_loader.py +52 -11
- claude_mpm/core/framework_loader.py +4 -2
- claude_mpm/core/hook_manager.py +51 -3
- claude_mpm/core/interactive_session.py +12 -11
- claude_mpm/core/logger.py +39 -9
- claude_mpm/core/logging_utils.py +35 -11
- claude_mpm/core/network_config.py +148 -0
- claude_mpm/core/oneshot_session.py +7 -6
- claude_mpm/core/optimized_startup.py +61 -0
- claude_mpm/core/output_style_manager.py +219 -44
- claude_mpm/core/shared/config_loader.py +3 -1
- claude_mpm/core/socketio_pool.py +16 -8
- claude_mpm/core/unified_agent_registry.py +134 -16
- claude_mpm/core/unified_config.py +76 -8
- claude_mpm/core/unified_paths.py +95 -90
- claude_mpm/dashboard/static/svelte-build/_app/env.js +1 -0
- 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/BSNlmTZj.js +1 -0
- 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/DR8nis88.js +2 -0
- 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/NqQ1dWOy.js +1 -0
- 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.RgBboRvH.js +1 -0
- 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 -0
- claude_mpm/dashboard/static/svelte-build/favicon.svg +7 -0
- claude_mpm/dashboard/static/svelte-build/index.html +36 -0
- 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__/__init__.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/auto_pause_handler.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/correlation_manager.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/__pycache__/tool_analysis.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/auto_pause_handler.py +485 -0
- claude_mpm/hooks/claude_hooks/correlation_manager.py +60 -0
- claude_mpm/hooks/claude_hooks/event_handlers.py +479 -128
- claude_mpm/hooks/claude_hooks/hook_handler.py +254 -83
- claude_mpm/hooks/claude_hooks/hook_wrapper.sh +6 -11
- claude_mpm/hooks/claude_hooks/installer.py +149 -18
- claude_mpm/hooks/claude_hooks/memory_integration.py +67 -19
- claude_mpm/hooks/claude_hooks/response_tracking.py +44 -62
- 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__/duplicate_detector.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 +69 -30
- claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +36 -103
- claude_mpm/hooks/claude_hooks/services/state_manager.py +23 -36
- claude_mpm/hooks/claude_hooks/services/subagent_processor.py +73 -75
- claude_mpm/hooks/kuzu_memory_hook.py +5 -5
- claude_mpm/hooks/memory_integration_hook.py +46 -1
- claude_mpm/hooks/session_resume_hook.py +89 -1
- claude_mpm/hooks/templates/pre_tool_use_template.py +10 -2
- claude_mpm/init.py +276 -19
- claude_mpm/models/agent_definition.py +7 -0
- claude_mpm/models/git_repository.py +3 -3
- claude_mpm/scripts/claude-hook-handler.sh +87 -20
- claude_mpm/scripts/launch_monitor.py +93 -13
- claude_mpm/scripts/start_activity_logging.py +0 -0
- claude_mpm/services/agents/agent_builder.py +3 -3
- claude_mpm/services/agents/agent_recommendation_service.py +278 -0
- claude_mpm/services/agents/agent_review_service.py +280 -0
- claude_mpm/services/agents/agent_selection_service.py +2 -2
- claude_mpm/services/agents/cache_git_manager.py +7 -7
- claude_mpm/services/agents/deployment/agent_deployment.py +29 -7
- claude_mpm/services/agents/deployment/agent_discovery_service.py +6 -5
- claude_mpm/services/agents/deployment/agent_format_converter.py +25 -13
- claude_mpm/services/agents/deployment/agent_template_builder.py +42 -20
- claude_mpm/services/agents/deployment/agents_directory_resolver.py +2 -2
- 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 +348 -29
- claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +570 -68
- claude_mpm/services/agents/deployment/startup_reconciliation.py +138 -0
- claude_mpm/services/agents/git_source_manager.py +57 -4
- claude_mpm/services/agents/loading/base_agent_manager.py +1 -13
- claude_mpm/services/agents/loading/framework_agent_loader.py +75 -2
- claude_mpm/services/agents/recommender.py +5 -3
- claude_mpm/services/agents/single_tier_deployment_service.py +6 -6
- claude_mpm/services/agents/sources/git_source_sync_service.py +129 -11
- claude_mpm/services/agents/startup_sync.py +27 -4
- claude_mpm/services/agents/toolchain_detector.py +10 -6
- claude_mpm/services/analysis/__init__.py +11 -1
- claude_mpm/services/analysis/clone_detector.py +1030 -0
- 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 +81 -10
- claude_mpm/services/delegation_detector.py +175 -0
- claude_mpm/services/diagnostics/checks/agent_check.py +2 -2
- claude_mpm/services/diagnostics/checks/agent_sources_check.py +31 -1
- 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_bus/config.py +3 -1
- claude_mpm/services/event_log.py +325 -0
- claude_mpm/services/git/git_operations_service.py +101 -16
- 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.py +9 -2
- claude_mpm/services/monitor/daemon_manager.py +54 -7
- claude_mpm/services/monitor/management/lifecycle.py +15 -3
- claude_mpm/services/monitor/server.py +796 -30
- claude_mpm/services/pm_skills_deployer.py +884 -0
- claude_mpm/services/profile_manager.py +337 -0
- claude_mpm/services/project/project_organizer.py +4 -0
- claude_mpm/services/self_upgrade_service.py +120 -12
- claude_mpm/services/skills/__init__.py +3 -0
- claude_mpm/services/skills/git_skill_source_manager.py +303 -12
- claude_mpm/services/skills/selective_skill_deployer.py +869 -0
- claude_mpm/services/skills/skill_discovery_service.py +74 -4
- claude_mpm/services/skills/skill_to_agent_mapper.py +406 -0
- claude_mpm/services/skills_deployer.py +294 -55
- claude_mpm/services/socketio/dashboard_server.py +1 -0
- claude_mpm/services/socketio/event_normalizer.py +51 -6
- claude_mpm/services/socketio/handlers/hook.py +14 -7
- claude_mpm/services/socketio/server/core.py +386 -108
- claude_mpm/services/socketio/server/main.py +12 -4
- claude_mpm/services/version_control/git_operations.py +103 -0
- 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 +98 -3
- claude_mpm/templates/.pre-commit-config.yaml +112 -0
- claude_mpm/utils/agent_dependency_loader.py +115 -4
- claude_mpm/utils/agent_filters.py +17 -44
- claude_mpm/utils/gitignore.py +3 -0
- claude_mpm/utils/migration.py +4 -4
- claude_mpm/utils/robust_installer.py +86 -21
- claude_mpm-5.6.23.dist-info/METADATA +393 -0
- {claude_mpm-5.0.9.dist-info → claude_mpm-5.6.23.dist-info}/RECORD +508 -261
- claude_mpm-5.6.23.dist-info/entry_points.txt +5 -0
- claude_mpm-5.6.23.dist-info/licenses/LICENSE +94 -0
- claude_mpm-5.6.23.dist-info/licenses/LICENSE-FAQ.md +153 -0
- claude_mpm/agents/BASE_AGENT_TEMPLATE.md +0 -292
- claude_mpm/agents/BASE_DOCUMENTATION.md +0 -53
- claude_mpm/agents/BASE_OPS.md +0 -219
- claude_mpm/agents/BASE_PM.md +0 -480
- claude_mpm/agents/BASE_PROMPT_ENGINEER.md +0 -787
- claude_mpm/agents/BASE_QA.md +0 -167
- claude_mpm/agents/BASE_RESEARCH.md +0 -53
- claude_mpm/agents/OUTPUT_STYLE.md +0 -290
- claude_mpm/agents/PM_INSTRUCTIONS_TEACH.md +0 -1322
- claude_mpm/agents/base_agent_loader.py +0 -601
- claude_mpm/cli/commands/agents_detect.py +0 -380
- claude_mpm/cli/commands/agents_recommend.py +0 -309
- claude_mpm/cli/ticket_cli.py +0 -35
- claude_mpm/commands/mpm-agents-auto-configure.md +0 -278
- claude_mpm/commands/mpm-agents-detect.md +0 -177
- claude_mpm/commands/mpm-agents-list.md +0 -131
- claude_mpm/commands/mpm-agents-recommend.md +0 -223
- claude_mpm/commands/mpm-config-view.md +0 -150
- claude_mpm/commands/mpm-ticket-organize.md +0 -304
- claude_mpm/dashboard/analysis_runner.py +0 -455
- claude_mpm/dashboard/index.html +0 -13
- claude_mpm/dashboard/open_dashboard.py +0 -66
- claude_mpm/dashboard/static/css/activity.css +0 -1958
- claude_mpm/dashboard/static/css/connection-status.css +0 -370
- claude_mpm/dashboard/static/css/dashboard.css +0 -4701
- claude_mpm/dashboard/static/js/components/activity-tree.js +0 -1871
- claude_mpm/dashboard/static/js/components/agent-hierarchy.js +0 -777
- claude_mpm/dashboard/static/js/components/agent-inference.js +0 -956
- claude_mpm/dashboard/static/js/components/build-tracker.js +0 -333
- claude_mpm/dashboard/static/js/components/code-simple.js +0 -857
- claude_mpm/dashboard/static/js/components/connection-debug.js +0 -654
- claude_mpm/dashboard/static/js/components/diff-viewer.js +0 -891
- claude_mpm/dashboard/static/js/components/event-processor.js +0 -542
- claude_mpm/dashboard/static/js/components/event-viewer.js +0 -1155
- claude_mpm/dashboard/static/js/components/export-manager.js +0 -368
- claude_mpm/dashboard/static/js/components/file-change-tracker.js +0 -443
- claude_mpm/dashboard/static/js/components/file-change-viewer.js +0 -690
- claude_mpm/dashboard/static/js/components/file-tool-tracker.js +0 -724
- claude_mpm/dashboard/static/js/components/file-viewer.js +0 -580
- claude_mpm/dashboard/static/js/components/hud-library-loader.js +0 -211
- claude_mpm/dashboard/static/js/components/hud-manager.js +0 -671
- claude_mpm/dashboard/static/js/components/hud-visualizer.js +0 -1718
- claude_mpm/dashboard/static/js/components/module-viewer.js +0 -2764
- claude_mpm/dashboard/static/js/components/session-manager.js +0 -579
- claude_mpm/dashboard/static/js/components/socket-manager.js +0 -368
- claude_mpm/dashboard/static/js/components/ui-state-manager.js +0 -749
- claude_mpm/dashboard/static/js/components/unified-data-viewer.js +0 -1824
- claude_mpm/dashboard/static/js/components/working-directory.js +0 -920
- claude_mpm/dashboard/static/js/connection-manager.js +0 -536
- claude_mpm/dashboard/static/js/dashboard.js +0 -1914
- claude_mpm/dashboard/static/js/extension-error-handler.js +0 -164
- claude_mpm/dashboard/static/js/socket-client.js +0 -1474
- claude_mpm/dashboard/static/js/tab-isolation-fix.js +0 -185
- claude_mpm/dashboard/static/socket.io.min.js +0 -7
- claude_mpm/dashboard/static/socket.io.v4.8.1.backup.js +0 -7
- claude_mpm/dashboard/templates/code_simple.html +0 -153
- claude_mpm/dashboard/templates/index.html +0 -606
- claude_mpm/dashboard/test_dashboard.html +0 -372
- claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-313.pyc +0 -0
- claude_mpm/scripts/mcp_server.py +0 -75
- claude_mpm/scripts/mcp_wrapper.py +0 -39
- claude_mpm/services/mcp_gateway/__init__.py +0 -159
- claude_mpm/services/mcp_gateway/auto_configure.py +0 -369
- claude_mpm/services/mcp_gateway/config/__init__.py +0 -17
- claude_mpm/services/mcp_gateway/config/config_loader.py +0 -296
- claude_mpm/services/mcp_gateway/config/config_schema.py +0 -243
- claude_mpm/services/mcp_gateway/config/configuration.py +0 -429
- claude_mpm/services/mcp_gateway/core/__init__.py +0 -43
- claude_mpm/services/mcp_gateway/core/base.py +0 -312
- claude_mpm/services/mcp_gateway/core/exceptions.py +0 -253
- claude_mpm/services/mcp_gateway/core/interfaces.py +0 -443
- claude_mpm/services/mcp_gateway/core/process_pool.py +0 -977
- claude_mpm/services/mcp_gateway/core/singleton_manager.py +0 -315
- claude_mpm/services/mcp_gateway/core/startup_verification.py +0 -316
- claude_mpm/services/mcp_gateway/main.py +0 -589
- claude_mpm/services/mcp_gateway/registry/__init__.py +0 -12
- claude_mpm/services/mcp_gateway/registry/service_registry.py +0 -412
- claude_mpm/services/mcp_gateway/registry/tool_registry.py +0 -489
- claude_mpm/services/mcp_gateway/server/__init__.py +0 -15
- claude_mpm/services/mcp_gateway/server/mcp_gateway.py +0 -414
- claude_mpm/services/mcp_gateway/server/stdio_handler.py +0 -372
- claude_mpm/services/mcp_gateway/server/stdio_server.py +0 -712
- claude_mpm/services/mcp_gateway/tools/__init__.py +0 -36
- claude_mpm/services/mcp_gateway/tools/base_adapter.py +0 -485
- claude_mpm/services/mcp_gateway/tools/document_summarizer.py +0 -789
- claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +0 -654
- claude_mpm/services/mcp_gateway/tools/health_check_tool.py +0 -456
- claude_mpm/services/mcp_gateway/tools/hello_world.py +0 -551
- claude_mpm/services/mcp_gateway/tools/kuzu_memory_service.py +0 -555
- claude_mpm/services/mcp_gateway/utils/__init__.py +0 -14
- claude_mpm/services/mcp_gateway/utils/package_version_checker.py +0 -160
- claude_mpm/services/mcp_gateway/utils/update_preferences.py +0 -170
- claude_mpm-5.0.9.dist-info/METADATA +0 -1028
- claude_mpm-5.0.9.dist-info/entry_points.txt +0 -10
- claude_mpm-5.0.9.dist-info/licenses/LICENSE +0 -21
- {claude_mpm-5.0.9.dist-info → claude_mpm-5.6.23.dist-info}/WHEEL +0 -0
- {claude_mpm-5.0.9.dist-info → claude_mpm-5.6.23.dist-info}/top_level.txt +0 -0
claude_mpm/cli/startup.py
CHANGED
|
@@ -10,47 +10,128 @@ Part of cli/__init__.py refactoring to reduce file size and improve modularity.
|
|
|
10
10
|
|
|
11
11
|
import os
|
|
12
12
|
import sys
|
|
13
|
-
import warnings
|
|
14
13
|
from pathlib import Path
|
|
15
14
|
|
|
16
15
|
|
|
17
|
-
def
|
|
18
|
-
"""
|
|
16
|
+
def sync_hooks_on_startup(quiet: bool = False) -> bool:
|
|
17
|
+
"""Ensure hooks are up-to-date on startup.
|
|
18
|
+
|
|
19
|
+
WHY: Users can have stale hook configurations in settings.json that cause errors.
|
|
20
|
+
Reinstalling hooks ensures the hook format matches the current code.
|
|
19
21
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
with 26 active code references, while cache/agents/ has only 7 legacy references.
|
|
22
|
+
DESIGN DECISION: Shows brief status message on success for user awareness.
|
|
23
|
+
Failures are logged but don't prevent startup to ensure claude-mpm remains functional.
|
|
23
24
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
Args:
|
|
26
|
+
quiet: If True, suppress all output (used internally)
|
|
27
|
+
|
|
28
|
+
Returns:
|
|
29
|
+
bool: True if hooks were synced successfully, False otherwise
|
|
28
30
|
"""
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
canonical_cache = home / ".claude-mpm" / "cache" / "remote-agents"
|
|
32
|
-
migration_marker = home / ".claude-mpm" / "cache" / ".migrated_to_remote_agents"
|
|
31
|
+
try:
|
|
32
|
+
from ..hooks.claude_hooks.installer import HookInstaller
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
installer = HookInstaller()
|
|
35
|
+
|
|
36
|
+
# Show brief status (hooks sync is fast)
|
|
37
|
+
if not quiet:
|
|
38
|
+
print("Syncing Claude Code hooks...", end=" ", flush=True)
|
|
39
|
+
|
|
40
|
+
# Reinstall hooks (force=True ensures update)
|
|
41
|
+
success = installer.install_hooks(force=True)
|
|
42
|
+
|
|
43
|
+
if not quiet:
|
|
44
|
+
if success:
|
|
45
|
+
print("✓")
|
|
46
|
+
else:
|
|
47
|
+
print("(skipped)")
|
|
48
|
+
|
|
49
|
+
return success
|
|
50
|
+
|
|
51
|
+
except Exception as e:
|
|
52
|
+
if not quiet:
|
|
53
|
+
print("(error)")
|
|
54
|
+
# Log but don't fail startup
|
|
55
|
+
from ..core.logger import get_logger
|
|
56
|
+
|
|
57
|
+
logger = get_logger("startup")
|
|
58
|
+
logger.warning(f"Hook sync failed (non-fatal): {e}")
|
|
59
|
+
return False
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def cleanup_legacy_agent_cache() -> None:
|
|
63
|
+
"""Remove legacy hierarchical agent cache directories.
|
|
64
|
+
|
|
65
|
+
WHY: Old agent cache used category-based directory structure directly in cache.
|
|
66
|
+
New structure uses remote source paths. This cleanup prevents confusion from
|
|
67
|
+
stale cache directories.
|
|
37
68
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
69
|
+
Old structure (removed):
|
|
70
|
+
~/.claude-mpm/cache/agents/engineer/
|
|
71
|
+
~/.claude-mpm/cache/agents/ops/
|
|
72
|
+
~/.claude-mpm/cache/agents/qa/
|
|
73
|
+
...
|
|
74
|
+
|
|
75
|
+
New structure (kept):
|
|
76
|
+
~/.claude-mpm/cache/agents/bobmatnyc/claude-mpm-agents/agents/...
|
|
77
|
+
|
|
78
|
+
DESIGN DECISION: Runs early in startup before agent deployment to ensure
|
|
79
|
+
clean cache state. Removes only known legacy directories to avoid deleting
|
|
80
|
+
user data.
|
|
81
|
+
"""
|
|
82
|
+
import shutil
|
|
83
|
+
from pathlib import Path
|
|
84
|
+
|
|
85
|
+
from ..core.logger import get_logger
|
|
86
|
+
|
|
87
|
+
logger = get_logger("startup")
|
|
88
|
+
|
|
89
|
+
cache_dir = Path.home() / ".claude-mpm" / "cache" / "agents"
|
|
90
|
+
if not cache_dir.exists():
|
|
41
91
|
return
|
|
42
92
|
|
|
43
|
-
#
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
93
|
+
# Known legacy category directories (from old hierarchical structure)
|
|
94
|
+
legacy_dirs = [
|
|
95
|
+
"claude-mpm",
|
|
96
|
+
"documentation",
|
|
97
|
+
"engineer",
|
|
98
|
+
"ops",
|
|
99
|
+
"qa",
|
|
100
|
+
"security",
|
|
101
|
+
"universal",
|
|
102
|
+
]
|
|
103
|
+
|
|
104
|
+
removed = []
|
|
105
|
+
|
|
106
|
+
# Remove legacy category directories
|
|
107
|
+
for dir_name in legacy_dirs:
|
|
108
|
+
legacy_path = cache_dir / dir_name
|
|
109
|
+
if legacy_path.exists() and legacy_path.is_dir():
|
|
110
|
+
try:
|
|
111
|
+
shutil.rmtree(legacy_path)
|
|
112
|
+
removed.append(dir_name)
|
|
113
|
+
except Exception as e:
|
|
114
|
+
logger.debug(f"Failed to remove legacy directory {dir_name}: {e}")
|
|
115
|
+
|
|
116
|
+
# Also remove stray BASE-AGENT.md in cache root
|
|
117
|
+
base_agent = cache_dir / "BASE-AGENT.md"
|
|
118
|
+
if base_agent.exists():
|
|
119
|
+
try:
|
|
120
|
+
base_agent.unlink()
|
|
121
|
+
removed.append("BASE-AGENT.md")
|
|
122
|
+
except Exception as e:
|
|
123
|
+
logger.debug(f"Failed to remove BASE-AGENT.md: {e}")
|
|
124
|
+
|
|
125
|
+
if removed:
|
|
126
|
+
logger.info(f"Cleaned up legacy agent cache: {', '.join(removed)}")
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def check_legacy_cache() -> None:
|
|
130
|
+
"""Deprecated: Legacy cache checking is no longer needed.
|
|
131
|
+
|
|
132
|
+
This function is kept for backward compatibility but does nothing.
|
|
133
|
+
All agent cache operations now use the standardized cache/agents/ directory.
|
|
134
|
+
"""
|
|
54
135
|
|
|
55
136
|
|
|
56
137
|
def setup_early_environment(argv):
|
|
@@ -80,7 +161,25 @@ def setup_early_environment(argv):
|
|
|
80
161
|
# CRITICAL: Suppress ALL logging by default
|
|
81
162
|
# This catches all loggers (claude_mpm.*, service.*, framework_loader, etc.)
|
|
82
163
|
# This will be overridden by setup_mcp_server_logging() based on user preference
|
|
83
|
-
logging.getLogger()
|
|
164
|
+
root_logger = logging.getLogger()
|
|
165
|
+
root_logger.setLevel(logging.CRITICAL + 1) # Root logger catches everything
|
|
166
|
+
root_logger.handlers = [] # Remove any handlers
|
|
167
|
+
|
|
168
|
+
# Also suppress common module loggers explicitly to prevent handler leakage
|
|
169
|
+
for logger_name in [
|
|
170
|
+
"claude_mpm",
|
|
171
|
+
"path_resolver",
|
|
172
|
+
"file_loader",
|
|
173
|
+
"framework_loader",
|
|
174
|
+
"service",
|
|
175
|
+
"instruction_loader",
|
|
176
|
+
"agent_loader",
|
|
177
|
+
"startup",
|
|
178
|
+
]:
|
|
179
|
+
module_logger = logging.getLogger(logger_name)
|
|
180
|
+
module_logger.setLevel(logging.CRITICAL + 1)
|
|
181
|
+
module_logger.handlers = []
|
|
182
|
+
module_logger.propagate = False
|
|
84
183
|
|
|
85
184
|
# Process argv
|
|
86
185
|
if argv is None:
|
|
@@ -110,7 +209,17 @@ def should_skip_background_services(args, processed_argv):
|
|
|
110
209
|
skip_commands = ["--version", "-v", "--help", "-h"]
|
|
111
210
|
return any(cmd in (processed_argv or sys.argv[1:]) for cmd in skip_commands) or (
|
|
112
211
|
hasattr(args, "command")
|
|
113
|
-
and args.command
|
|
212
|
+
and args.command
|
|
213
|
+
in [
|
|
214
|
+
"info",
|
|
215
|
+
"doctor",
|
|
216
|
+
"config",
|
|
217
|
+
"mcp",
|
|
218
|
+
"configure",
|
|
219
|
+
"hook-errors",
|
|
220
|
+
"autotodos",
|
|
221
|
+
"commander",
|
|
222
|
+
]
|
|
114
223
|
)
|
|
115
224
|
|
|
116
225
|
|
|
@@ -153,7 +262,7 @@ def deploy_bundled_skills():
|
|
|
153
262
|
if not skills_config.get("auto_deploy", True):
|
|
154
263
|
# Auto-deploy disabled, skip silently
|
|
155
264
|
return
|
|
156
|
-
except Exception:
|
|
265
|
+
except Exception: # nosec B110
|
|
157
266
|
# If config loading fails, assume auto-deploy is enabled (default)
|
|
158
267
|
pass
|
|
159
268
|
|
|
@@ -221,79 +330,243 @@ def discover_and_link_runtime_skills():
|
|
|
221
330
|
|
|
222
331
|
def deploy_output_style_on_startup():
|
|
223
332
|
"""
|
|
224
|
-
Deploy claude-mpm output
|
|
333
|
+
Deploy claude-mpm output styles to PROJECT-LEVEL directory on CLI startup.
|
|
334
|
+
|
|
335
|
+
WHY: Automatically deploy output styles to ensure consistent, professional
|
|
336
|
+
communication without emojis and exclamation points. Styles are project-specific
|
|
337
|
+
to allow different projects to have different communication styles.
|
|
225
338
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
339
|
+
DESIGN DECISION: This is non-blocking and idempotent. Deploys to user-level
|
|
340
|
+
directory (~/.claude/output-styles/) which is the official Claude Code location
|
|
341
|
+
for custom output styles.
|
|
229
342
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
343
|
+
Deploys all styles:
|
|
344
|
+
- claude-mpm.md (professional mode)
|
|
345
|
+
- claude-mpm-teacher.md (teaching mode)
|
|
346
|
+
- claude-mpm-research.md (research mode - for codebase analysis)
|
|
233
347
|
"""
|
|
234
348
|
try:
|
|
235
|
-
from pathlib import Path
|
|
236
|
-
|
|
237
349
|
from ..core.output_style_manager import OutputStyleManager
|
|
238
350
|
|
|
239
|
-
#
|
|
240
|
-
|
|
351
|
+
# Initialize the output style manager
|
|
352
|
+
manager = OutputStyleManager()
|
|
241
353
|
|
|
242
|
-
# Check if Claude Code supports output styles
|
|
243
|
-
if not
|
|
244
|
-
#
|
|
354
|
+
# Check if Claude Code version supports output styles (>= 1.0.83)
|
|
355
|
+
if not manager.supports_output_styles():
|
|
356
|
+
# Skip deployment for older versions
|
|
357
|
+
# The manager will fall back to injecting content directly
|
|
245
358
|
return
|
|
246
359
|
|
|
247
|
-
# Check if already deployed and
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
# Already deployed and active with content
|
|
265
|
-
already_configured = True
|
|
266
|
-
except Exception:
|
|
267
|
-
pass # Continue with deployment if we can't read settings
|
|
268
|
-
|
|
269
|
-
if already_configured:
|
|
270
|
-
# Show feedback that output style is ready
|
|
271
|
-
print("✓ Output style configured", flush=True)
|
|
360
|
+
# Check if all styles are already deployed and up-to-date
|
|
361
|
+
all_up_to_date = True
|
|
362
|
+
for style_config in manager.styles.values():
|
|
363
|
+
source_path = style_config["source"]
|
|
364
|
+
target_path = style_config["target"]
|
|
365
|
+
|
|
366
|
+
if not (
|
|
367
|
+
target_path.exists()
|
|
368
|
+
and source_path.exists()
|
|
369
|
+
and target_path.stat().st_size == source_path.stat().st_size
|
|
370
|
+
):
|
|
371
|
+
all_up_to_date = False
|
|
372
|
+
break
|
|
373
|
+
|
|
374
|
+
if all_up_to_date:
|
|
375
|
+
# Show feedback that output styles are ready
|
|
376
|
+
print("✓ Output styles ready", flush=True)
|
|
272
377
|
return
|
|
273
378
|
|
|
274
|
-
#
|
|
275
|
-
|
|
379
|
+
# Deploy all styles using the manager
|
|
380
|
+
results = manager.deploy_all_styles(activate_default=True)
|
|
276
381
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
return
|
|
382
|
+
# Count successful deployments
|
|
383
|
+
deployed_count = sum(1 for success in results.values() if success)
|
|
280
384
|
|
|
281
|
-
|
|
385
|
+
if deployed_count > 0:
|
|
386
|
+
print(f"✓ Output styles deployed ({deployed_count} styles)", flush=True)
|
|
387
|
+
else:
|
|
388
|
+
# Deployment failed - log but don't fail startup
|
|
389
|
+
from ..core.logger import get_logger
|
|
282
390
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
print("✓ Output style configured", flush=True)
|
|
391
|
+
logger = get_logger("cli")
|
|
392
|
+
logger.debug("Failed to deploy any output styles")
|
|
286
393
|
|
|
287
394
|
except Exception as e:
|
|
288
395
|
# Non-critical - log but don't fail startup
|
|
289
396
|
from ..core.logger import get_logger
|
|
290
397
|
|
|
291
398
|
logger = get_logger("cli")
|
|
292
|
-
logger.debug(f"Failed to deploy output
|
|
399
|
+
logger.debug(f"Failed to deploy output styles: {e}")
|
|
293
400
|
# Continue execution - output style deployment shouldn't block startup
|
|
294
401
|
|
|
295
402
|
|
|
296
|
-
def
|
|
403
|
+
def _cleanup_orphaned_agents(deploy_target: Path, deployed_agents: list[str]) -> int:
|
|
404
|
+
"""Remove agents that are managed by claude-mpm but no longer deployed.
|
|
405
|
+
|
|
406
|
+
WHY: When agent configurations change, old agents should be removed to avoid
|
|
407
|
+
confusion and stale agent references. Only removes claude-mpm managed agents,
|
|
408
|
+
leaving user-created agents untouched.
|
|
409
|
+
|
|
410
|
+
SAFETY: Only removes files with claude-mpm ownership markers in frontmatter.
|
|
411
|
+
Files without frontmatter or without ownership indicators are preserved.
|
|
412
|
+
|
|
413
|
+
Args:
|
|
414
|
+
deploy_target: Path to .claude/agents/ directory
|
|
415
|
+
deployed_agents: List of agent filenames that should remain
|
|
416
|
+
|
|
417
|
+
Returns:
|
|
418
|
+
Number of agents removed
|
|
419
|
+
"""
|
|
420
|
+
import re
|
|
421
|
+
|
|
422
|
+
import yaml
|
|
423
|
+
|
|
424
|
+
from ..core.logger import get_logger
|
|
425
|
+
|
|
426
|
+
logger = get_logger("cli")
|
|
427
|
+
removed_count = 0
|
|
428
|
+
deployed_set = set(deployed_agents)
|
|
429
|
+
|
|
430
|
+
if not deploy_target.exists():
|
|
431
|
+
return 0
|
|
432
|
+
|
|
433
|
+
# Scan all .md files in agents directory
|
|
434
|
+
for agent_file in deploy_target.glob("*.md"):
|
|
435
|
+
# Skip hidden files
|
|
436
|
+
if agent_file.name.startswith("."):
|
|
437
|
+
continue
|
|
438
|
+
|
|
439
|
+
# Skip if this agent should remain deployed
|
|
440
|
+
if agent_file.name in deployed_set:
|
|
441
|
+
continue
|
|
442
|
+
|
|
443
|
+
# Check if this is a claude-mpm managed agent
|
|
444
|
+
try:
|
|
445
|
+
content = agent_file.read_text(encoding="utf-8")
|
|
446
|
+
|
|
447
|
+
# Parse YAML frontmatter
|
|
448
|
+
if content.startswith("---"):
|
|
449
|
+
match = re.match(r"^---\n(.*?)\n---", content, re.DOTALL)
|
|
450
|
+
if match:
|
|
451
|
+
frontmatter = yaml.safe_load(match.group(1))
|
|
452
|
+
|
|
453
|
+
# Check ownership indicators
|
|
454
|
+
is_ours = False
|
|
455
|
+
if frontmatter:
|
|
456
|
+
author = frontmatter.get("author", "")
|
|
457
|
+
source = frontmatter.get("source", "")
|
|
458
|
+
agent_id = frontmatter.get("agent_id", "")
|
|
459
|
+
|
|
460
|
+
# It's ours if it has any of these markers
|
|
461
|
+
if (
|
|
462
|
+
"Claude MPM" in str(author)
|
|
463
|
+
or source == "remote"
|
|
464
|
+
or agent_id
|
|
465
|
+
):
|
|
466
|
+
is_ours = True
|
|
467
|
+
|
|
468
|
+
if is_ours:
|
|
469
|
+
# Safe to remove - it's our agent but not deployed
|
|
470
|
+
agent_file.unlink()
|
|
471
|
+
removed_count += 1
|
|
472
|
+
logger.info(f"Removed orphaned agent: {agent_file.name}")
|
|
473
|
+
|
|
474
|
+
except Exception as e:
|
|
475
|
+
logger.debug(f"Could not check agent {agent_file.name}: {e}")
|
|
476
|
+
# Don't remove if we can't verify ownership
|
|
477
|
+
|
|
478
|
+
return removed_count
|
|
479
|
+
|
|
480
|
+
|
|
481
|
+
def _save_deployment_state_after_reconciliation(
|
|
482
|
+
agent_result, project_path: Path
|
|
483
|
+
) -> None:
|
|
484
|
+
"""Save deployment state after reconciliation to prevent duplicate deployment.
|
|
485
|
+
|
|
486
|
+
WHY: After perform_startup_reconciliation() deploys agents to .claude/agents/,
|
|
487
|
+
we need to save a deployment state file so that ClaudeRunner.setup_agents()
|
|
488
|
+
can detect agents are already deployed and skip redundant deployment.
|
|
489
|
+
|
|
490
|
+
This prevents the "✓ Deployed 31 native agents" duplicate deployment that
|
|
491
|
+
occurs when setup_agents() doesn't know reconciliation already ran.
|
|
492
|
+
|
|
493
|
+
Args:
|
|
494
|
+
agent_result: DeploymentResult from perform_startup_reconciliation()
|
|
495
|
+
project_path: Project root directory
|
|
496
|
+
|
|
497
|
+
DESIGN DECISION: Use same state file format as ClaudeRunner._save_deployment_state()
|
|
498
|
+
Located at: .claude-mpm/cache/deployment_state.json
|
|
499
|
+
|
|
500
|
+
State file format:
|
|
501
|
+
{
|
|
502
|
+
"version": "5.6.13",
|
|
503
|
+
"agent_count": 15,
|
|
504
|
+
"deployment_hash": "sha256:...",
|
|
505
|
+
"deployed_at": 1234567890.123
|
|
506
|
+
}
|
|
507
|
+
"""
|
|
508
|
+
import hashlib
|
|
509
|
+
import json
|
|
510
|
+
import time
|
|
511
|
+
|
|
512
|
+
from ..core.logger import get_logger
|
|
513
|
+
|
|
514
|
+
logger = get_logger("cli")
|
|
515
|
+
|
|
516
|
+
try:
|
|
517
|
+
# Get version from package
|
|
518
|
+
from claude_mpm import __version__
|
|
519
|
+
|
|
520
|
+
# Path to state file (matches ClaudeRunner._get_deployment_state_path())
|
|
521
|
+
state_file = project_path / ".claude-mpm" / "cache" / "deployment_state.json"
|
|
522
|
+
agents_dir = project_path / ".claude" / "agents"
|
|
523
|
+
|
|
524
|
+
# Count deployed agents
|
|
525
|
+
if agents_dir.exists():
|
|
526
|
+
agent_count = len(list(agents_dir.glob("*.md")))
|
|
527
|
+
else:
|
|
528
|
+
agent_count = 0
|
|
529
|
+
|
|
530
|
+
# Calculate deployment hash (matches ClaudeRunner._calculate_deployment_hash())
|
|
531
|
+
# CRITICAL: Must match exact hash algorithm used in ClaudeRunner
|
|
532
|
+
# Hashes filename + file content (not mtime) for consistency
|
|
533
|
+
deployment_hash = ""
|
|
534
|
+
if agents_dir.exists():
|
|
535
|
+
agent_files = sorted(agents_dir.glob("*.md"))
|
|
536
|
+
hash_obj = hashlib.sha256()
|
|
537
|
+
for agent_file in agent_files:
|
|
538
|
+
# Include filename and content in hash (matches ClaudeRunner)
|
|
539
|
+
hash_obj.update(agent_file.name.encode())
|
|
540
|
+
try:
|
|
541
|
+
hash_obj.update(agent_file.read_bytes())
|
|
542
|
+
except Exception as e:
|
|
543
|
+
logger.debug(f"Error reading {agent_file} for hash: {e}")
|
|
544
|
+
|
|
545
|
+
deployment_hash = hash_obj.hexdigest()
|
|
546
|
+
|
|
547
|
+
# Create state data
|
|
548
|
+
state_data = {
|
|
549
|
+
"version": __version__,
|
|
550
|
+
"agent_count": agent_count,
|
|
551
|
+
"deployment_hash": deployment_hash,
|
|
552
|
+
"deployed_at": time.time(),
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
# Ensure directory exists
|
|
556
|
+
state_file.parent.mkdir(parents=True, exist_ok=True)
|
|
557
|
+
|
|
558
|
+
# Write state file
|
|
559
|
+
state_file.write_text(json.dumps(state_data, indent=2))
|
|
560
|
+
logger.debug(
|
|
561
|
+
f"Saved deployment state after reconciliation: {agent_count} agents"
|
|
562
|
+
)
|
|
563
|
+
|
|
564
|
+
except Exception as e:
|
|
565
|
+
# Non-critical error - log but don't fail startup
|
|
566
|
+
logger.debug(f"Failed to save deployment state: {e}")
|
|
567
|
+
|
|
568
|
+
|
|
569
|
+
def sync_remote_agents_on_startup(force_sync: bool = False):
|
|
297
570
|
"""
|
|
298
571
|
Synchronize agent templates from remote sources on startup.
|
|
299
572
|
|
|
@@ -308,18 +581,47 @@ def sync_remote_agents_on_startup():
|
|
|
308
581
|
Workflow:
|
|
309
582
|
1. Sync all enabled Git sources (download/cache files) - Phase 1 progress bar
|
|
310
583
|
2. Deploy agents to ~/.claude/agents/ - Phase 2 progress bar
|
|
311
|
-
3.
|
|
584
|
+
3. Cleanup orphaned agents (ours but no longer deployed) - Phase 3
|
|
585
|
+
4. Cleanup legacy agent cache directories (after sync/deployment) - Phase 4
|
|
586
|
+
5. Log deployment results
|
|
587
|
+
|
|
588
|
+
Args:
|
|
589
|
+
force_sync: Force download even if cache is fresh (bypasses ETag).
|
|
312
590
|
"""
|
|
313
|
-
#
|
|
591
|
+
# DEPRECATED: Legacy warning - no-op function, kept for compatibility
|
|
314
592
|
check_legacy_cache()
|
|
315
593
|
|
|
316
594
|
try:
|
|
317
|
-
|
|
595
|
+
# Load active profile if configured
|
|
596
|
+
# Get project root (where .claude-mpm exists)
|
|
597
|
+
from pathlib import Path
|
|
598
|
+
|
|
599
|
+
from ..core.shared.config_loader import ConfigLoader
|
|
318
600
|
from ..services.agents.startup_sync import sync_agents_on_startup
|
|
601
|
+
from ..services.profile_manager import ProfileManager
|
|
319
602
|
from ..utils.progress import ProgressBar
|
|
320
603
|
|
|
604
|
+
project_root = Path.cwd()
|
|
605
|
+
|
|
606
|
+
profile_manager = ProfileManager(project_dir=project_root)
|
|
607
|
+
config_loader = ConfigLoader()
|
|
608
|
+
main_config = config_loader.load_main_config()
|
|
609
|
+
active_profile = main_config.get("active_profile")
|
|
610
|
+
|
|
611
|
+
if active_profile:
|
|
612
|
+
success = profile_manager.load_profile(active_profile)
|
|
613
|
+
if success:
|
|
614
|
+
summary = profile_manager.get_filtering_summary()
|
|
615
|
+
from ..core.logger import get_logger
|
|
616
|
+
|
|
617
|
+
logger = get_logger("cli")
|
|
618
|
+
logger.info(
|
|
619
|
+
f"Profile '{active_profile}' active: "
|
|
620
|
+
f"{summary['enabled_agents_count']} agents enabled"
|
|
621
|
+
)
|
|
622
|
+
|
|
321
623
|
# Phase 1: Sync files from Git sources
|
|
322
|
-
result = sync_agents_on_startup()
|
|
624
|
+
result = sync_agents_on_startup(force_refresh=force_sync)
|
|
323
625
|
|
|
324
626
|
# Only proceed with deployment if sync was enabled and ran
|
|
325
627
|
if result.get("enabled") and result.get("sources_synced", 0) > 0:
|
|
@@ -342,130 +644,95 @@ def sync_remote_agents_on_startup():
|
|
|
342
644
|
logger.warning(f"Agent sync completed with {len(errors)} errors")
|
|
343
645
|
|
|
344
646
|
# Phase 2: Deploy agents from cache to ~/.claude/agents/
|
|
345
|
-
#
|
|
647
|
+
# Use reconciliation service to respect configuration.yaml settings
|
|
346
648
|
try:
|
|
347
|
-
# Initialize deployment service
|
|
348
|
-
deployment_service = AgentDeploymentService()
|
|
349
|
-
|
|
350
|
-
# Count agents in cache to show accurate progress
|
|
351
649
|
from pathlib import Path
|
|
352
650
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
# Exclude PM templates, BASE-AGENT, and documentation files
|
|
361
|
-
pm_templates = {
|
|
362
|
-
"base-agent.md",
|
|
363
|
-
"circuit_breakers.md",
|
|
364
|
-
"pm_examples.md",
|
|
365
|
-
"pm_red_flags.md",
|
|
366
|
-
"research_gate_examples.md",
|
|
367
|
-
"response_format.md",
|
|
368
|
-
"ticket_completeness_examples.md",
|
|
369
|
-
"validation_templates.md",
|
|
370
|
-
"git_file_tracking.md",
|
|
371
|
-
}
|
|
372
|
-
# Documentation files to exclude (by filename)
|
|
373
|
-
doc_files = {
|
|
374
|
-
"readme.md",
|
|
375
|
-
"changelog.md",
|
|
376
|
-
"contributing.md",
|
|
377
|
-
"implementation-summary.md",
|
|
378
|
-
"reorganization-plan.md",
|
|
379
|
-
"auto-deploy-index.md",
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
# Find all markdown files
|
|
383
|
-
all_md_files = list(cache_dir.rglob("*.md"))
|
|
384
|
-
|
|
385
|
-
# Filter to only agent files:
|
|
386
|
-
# 1. Must have "/agents/" in path (from git repos)
|
|
387
|
-
# 2. Must not be in PM templates or doc files
|
|
388
|
-
# 3. Exclude BASE-AGENT.md which is not a deployable agent
|
|
389
|
-
agent_files = [
|
|
390
|
-
f
|
|
391
|
-
for f in all_md_files
|
|
392
|
-
if (
|
|
393
|
-
# Must be in an agent directory (from git repos like bobmatnyc/claude-mpm-agents/agents/)
|
|
394
|
-
"/agents/" in str(f)
|
|
395
|
-
# Exclude PM templates, doc files, and BASE-AGENT
|
|
396
|
-
and f.name.lower() not in pm_templates
|
|
397
|
-
and f.name.lower() not in doc_files
|
|
398
|
-
and f.name.lower() != "base-agent.md"
|
|
399
|
-
)
|
|
400
|
-
]
|
|
401
|
-
agent_count = len(agent_files)
|
|
651
|
+
from ..core.unified_config import UnifiedConfig
|
|
652
|
+
from ..services.agents.deployment.startup_reconciliation import (
|
|
653
|
+
perform_startup_reconciliation,
|
|
654
|
+
)
|
|
655
|
+
|
|
656
|
+
# Load configuration
|
|
657
|
+
unified_config = UnifiedConfig()
|
|
402
658
|
|
|
403
|
-
|
|
404
|
-
|
|
659
|
+
# Override with profile settings if active
|
|
660
|
+
if active_profile and profile_manager.active_profile:
|
|
661
|
+
# Get enabled agents from profile (returns Set[str])
|
|
662
|
+
profile_enabled_agents = (
|
|
663
|
+
profile_manager.active_profile.get_enabled_agents()
|
|
664
|
+
)
|
|
665
|
+
# Update config with profile's enabled list (convert Set to List)
|
|
666
|
+
unified_config.agents.enabled = list(profile_enabled_agents)
|
|
667
|
+
logger.info(
|
|
668
|
+
f"Profile '{active_profile}': Using {len(profile_enabled_agents)} enabled agents"
|
|
669
|
+
)
|
|
670
|
+
|
|
671
|
+
# Perform reconciliation to deploy configured agents
|
|
672
|
+
project_path = Path.cwd()
|
|
673
|
+
agent_result, _skill_result = perform_startup_reconciliation(
|
|
674
|
+
project_path=project_path, config=unified_config, silent=False
|
|
675
|
+
)
|
|
676
|
+
|
|
677
|
+
# Display results with progress bar
|
|
678
|
+
total_operations = (
|
|
679
|
+
len(agent_result.deployed)
|
|
680
|
+
+ len(agent_result.removed)
|
|
681
|
+
+ len(agent_result.unchanged)
|
|
682
|
+
)
|
|
683
|
+
|
|
684
|
+
if total_operations > 0:
|
|
405
685
|
deploy_progress = ProgressBar(
|
|
406
|
-
total=
|
|
686
|
+
total=total_operations,
|
|
407
687
|
prefix="Deploying agents",
|
|
408
688
|
show_percentage=True,
|
|
409
689
|
show_counter=True,
|
|
410
690
|
)
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
691
|
+
deploy_progress.update(total_operations)
|
|
692
|
+
|
|
693
|
+
# Build summary message
|
|
694
|
+
deployed = len(agent_result.deployed)
|
|
695
|
+
removed = len(agent_result.removed)
|
|
696
|
+
unchanged = len(agent_result.unchanged)
|
|
697
|
+
|
|
698
|
+
summary_parts = []
|
|
699
|
+
if deployed > 0:
|
|
700
|
+
summary_parts.append(f"{deployed} new")
|
|
701
|
+
if removed > 0:
|
|
702
|
+
summary_parts.append(f"{removed} removed")
|
|
703
|
+
if unchanged > 0:
|
|
704
|
+
summary_parts.append(f"{unchanged} unchanged")
|
|
705
|
+
|
|
706
|
+
summary = f"Complete: {', '.join(summary_parts)}"
|
|
707
|
+
deploy_progress.finish(summary)
|
|
708
|
+
|
|
709
|
+
# Display errors if any
|
|
710
|
+
if agent_result.errors:
|
|
711
|
+
logger.warning(
|
|
712
|
+
f"Agent deployment completed with {len(agent_result.errors)} errors"
|
|
418
713
|
)
|
|
714
|
+
print("\n⚠️ Agent Deployment Errors:")
|
|
715
|
+
max_errors_to_show = 10
|
|
716
|
+
errors_to_display = agent_result.errors[:max_errors_to_show]
|
|
419
717
|
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
# Finish deployment progress bar
|
|
424
|
-
deployed = len(deployment_result.get("deployed", []))
|
|
425
|
-
updated = len(deployment_result.get("updated", []))
|
|
426
|
-
skipped = len(deployment_result.get("skipped", []))
|
|
427
|
-
total_available = deployed + updated + skipped
|
|
428
|
-
|
|
429
|
-
# Show total available agents (deployed + updated + already existing)
|
|
430
|
-
if deployed > 0 or updated > 0:
|
|
431
|
-
deploy_progress.finish(
|
|
432
|
-
f"Complete: {deployed} deployed, {updated} updated, {skipped} already present ({total_available} total)"
|
|
433
|
-
)
|
|
434
|
-
else:
|
|
435
|
-
deploy_progress.finish(
|
|
436
|
-
f"Complete: {total_available} agents ready (all up-to-date)"
|
|
437
|
-
)
|
|
438
|
-
|
|
439
|
-
# Display deployment errors to user (not just logs)
|
|
440
|
-
deploy_errors = deployment_result.get("errors", [])
|
|
441
|
-
if deploy_errors:
|
|
442
|
-
# Log for debugging
|
|
443
|
-
logger.warning(
|
|
444
|
-
f"Agent deployment completed with {len(deploy_errors)} errors: {deploy_errors}"
|
|
445
|
-
)
|
|
446
|
-
|
|
447
|
-
# Display errors to user with clear formatting
|
|
448
|
-
print("\n⚠️ Agent Deployment Errors:")
|
|
718
|
+
for error in errors_to_display:
|
|
719
|
+
print(f" - {error}")
|
|
449
720
|
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
721
|
+
if len(agent_result.errors) > max_errors_to_show:
|
|
722
|
+
remaining = len(agent_result.errors) - max_errors_to_show
|
|
723
|
+
print(f" ... and {remaining} more error(s)")
|
|
453
724
|
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
# If more errors exist, show count
|
|
460
|
-
if len(deploy_errors) > max_errors_to_show:
|
|
461
|
-
remaining = len(deploy_errors) - max_errors_to_show
|
|
462
|
-
print(f" ... and {remaining} more error(s)")
|
|
725
|
+
print(
|
|
726
|
+
f"\n❌ Failed to deploy {len(agent_result.errors)} agent(s). "
|
|
727
|
+
"Please check the error messages above."
|
|
728
|
+
)
|
|
729
|
+
print(" Run with --verbose for detailed error information.\n")
|
|
463
730
|
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
731
|
+
# Save deployment state to prevent duplicate deployment in ClaudeRunner
|
|
732
|
+
# This ensures setup_agents() skips deployment since we already reconciled
|
|
733
|
+
_save_deployment_state_after_reconciliation(
|
|
734
|
+
agent_result=agent_result, project_path=project_path
|
|
735
|
+
)
|
|
469
736
|
|
|
470
737
|
except Exception as e:
|
|
471
738
|
# Deployment failure shouldn't block startup
|
|
@@ -474,6 +741,11 @@ def sync_remote_agents_on_startup():
|
|
|
474
741
|
logger = get_logger("cli")
|
|
475
742
|
logger.warning(f"Failed to deploy agents from cache: {e}")
|
|
476
743
|
|
|
744
|
+
# Phase 4: Cleanup legacy agent cache directories (after sync/deployment)
|
|
745
|
+
# CRITICAL: This must run AFTER sync completes because sync may recreate
|
|
746
|
+
# legacy directories. Running cleanup here ensures they're removed.
|
|
747
|
+
cleanup_legacy_agent_cache()
|
|
748
|
+
|
|
477
749
|
except Exception as e:
|
|
478
750
|
# Non-critical - log but don't fail startup
|
|
479
751
|
from ..core.logger import get_logger
|
|
@@ -482,8 +754,14 @@ def sync_remote_agents_on_startup():
|
|
|
482
754
|
logger.debug(f"Failed to sync remote agents: {e}")
|
|
483
755
|
# Continue execution - agent sync failure shouldn't block startup
|
|
484
756
|
|
|
757
|
+
# Cleanup legacy cache even if sync failed
|
|
758
|
+
try:
|
|
759
|
+
cleanup_legacy_agent_cache()
|
|
760
|
+
except Exception: # nosec B110
|
|
761
|
+
pass # Ignore cleanup errors
|
|
762
|
+
|
|
485
763
|
|
|
486
|
-
def sync_remote_skills_on_startup():
|
|
764
|
+
def sync_remote_skills_on_startup(force_sync: bool = False):
|
|
487
765
|
"""
|
|
488
766
|
Synchronize skill templates from remote sources on startup.
|
|
489
767
|
|
|
@@ -496,16 +774,51 @@ def sync_remote_skills_on_startup():
|
|
|
496
774
|
|
|
497
775
|
Workflow:
|
|
498
776
|
1. Sync all enabled Git sources (download/cache files) - Phase 1 progress bar
|
|
499
|
-
2.
|
|
500
|
-
3.
|
|
777
|
+
2. Scan deployed agents for skill requirements → save to configuration.yaml
|
|
778
|
+
3. Resolve which skills to deploy (user_defined vs agent_referenced)
|
|
779
|
+
4. Apply profile filtering if active
|
|
780
|
+
5. Deploy resolved skills to ~/.claude/skills/ - Phase 2 progress bar
|
|
781
|
+
6. Log deployment results with source indication
|
|
782
|
+
|
|
783
|
+
Args:
|
|
784
|
+
force_sync: Force download even if cache is fresh (bypasses ETag).
|
|
501
785
|
"""
|
|
502
786
|
try:
|
|
503
787
|
from pathlib import Path
|
|
504
788
|
|
|
505
789
|
from ..config.skill_sources import SkillSourceConfiguration
|
|
790
|
+
from ..core.shared.config_loader import ConfigLoader
|
|
791
|
+
from ..services.profile_manager import ProfileManager
|
|
506
792
|
from ..services.skills.git_skill_source_manager import GitSkillSourceManager
|
|
793
|
+
from ..services.skills.selective_skill_deployer import (
|
|
794
|
+
get_required_skills_from_agents,
|
|
795
|
+
get_skills_to_deploy,
|
|
796
|
+
save_agent_skills_to_config,
|
|
797
|
+
)
|
|
507
798
|
from ..utils.progress import ProgressBar
|
|
508
799
|
|
|
800
|
+
# Load active profile if configured
|
|
801
|
+
# Get project root (where .claude-mpm exists)
|
|
802
|
+
project_root = Path.cwd()
|
|
803
|
+
|
|
804
|
+
profile_manager = ProfileManager(project_dir=project_root)
|
|
805
|
+
config_loader = ConfigLoader()
|
|
806
|
+
main_config = config_loader.load_main_config()
|
|
807
|
+
active_profile = main_config.get("active_profile")
|
|
808
|
+
|
|
809
|
+
if active_profile:
|
|
810
|
+
success = profile_manager.load_profile(active_profile)
|
|
811
|
+
if success:
|
|
812
|
+
from ..core.logger import get_logger
|
|
813
|
+
|
|
814
|
+
logger = get_logger("cli")
|
|
815
|
+
summary = profile_manager.get_filtering_summary()
|
|
816
|
+
logger.info(
|
|
817
|
+
f"Profile '{active_profile}' active: "
|
|
818
|
+
f"{summary['enabled_skills_count']} skills enabled, "
|
|
819
|
+
f"{summary['disabled_patterns_count']} patterns disabled"
|
|
820
|
+
)
|
|
821
|
+
|
|
509
822
|
config = SkillSourceConfiguration()
|
|
510
823
|
manager = GitSkillSourceManager(config)
|
|
511
824
|
|
|
@@ -523,6 +836,8 @@ def sync_remote_skills_on_startup():
|
|
|
523
836
|
|
|
524
837
|
# Discover total file count across all sources
|
|
525
838
|
total_file_count = 0
|
|
839
|
+
total_skill_dirs = 0 # Count actual skill directories (folders with SKILL.md)
|
|
840
|
+
|
|
526
841
|
for source in enabled_sources:
|
|
527
842
|
try:
|
|
528
843
|
# Parse GitHub URL
|
|
@@ -546,22 +861,33 @@ def sync_remote_skills_on_startup():
|
|
|
546
861
|
]
|
|
547
862
|
total_file_count += len(relevant_files)
|
|
548
863
|
|
|
864
|
+
# Count skill directories (unique directories containing SKILL.md)
|
|
865
|
+
skill_dirs = set()
|
|
866
|
+
for f in all_files:
|
|
867
|
+
if f.endswith("/SKILL.md"):
|
|
868
|
+
# Extract directory path
|
|
869
|
+
skill_dir = "/".join(f.split("/")[:-1])
|
|
870
|
+
skill_dirs.add(skill_dir)
|
|
871
|
+
total_skill_dirs += len(skill_dirs)
|
|
872
|
+
|
|
549
873
|
except Exception as e:
|
|
550
874
|
logger.debug(f"Failed to discover files for {source.id}: {e}")
|
|
551
875
|
# Use estimate if discovery fails
|
|
552
876
|
total_file_count += 150
|
|
877
|
+
total_skill_dirs += 50 # Estimate ~50 skills
|
|
553
878
|
|
|
554
879
|
# Create progress bar for sync phase with actual file count
|
|
880
|
+
# Note: We sync files (md, json, etc.), but will deploy skill directories
|
|
555
881
|
sync_progress = ProgressBar(
|
|
556
882
|
total=total_file_count if total_file_count > 0 else 1,
|
|
557
|
-
prefix="Syncing
|
|
883
|
+
prefix="Syncing skill files",
|
|
558
884
|
show_percentage=True,
|
|
559
885
|
show_counter=True,
|
|
560
886
|
)
|
|
561
887
|
|
|
562
888
|
# Sync all sources with progress callback
|
|
563
889
|
results = manager.sync_all_sources(
|
|
564
|
-
force=
|
|
890
|
+
force=force_sync, progress_callback=sync_progress.update
|
|
565
891
|
)
|
|
566
892
|
|
|
567
893
|
# Finish sync progress bar with clear breakdown
|
|
@@ -571,69 +897,201 @@ def sync_remote_skills_on_startup():
|
|
|
571
897
|
|
|
572
898
|
if cached > 0:
|
|
573
899
|
sync_progress.finish(
|
|
574
|
-
f"Complete: {downloaded} downloaded, {cached} cached ({total_files}
|
|
900
|
+
f"Complete: {downloaded} downloaded, {cached} cached ({total_files} files, {total_skill_dirs} skills)"
|
|
575
901
|
)
|
|
576
902
|
else:
|
|
577
903
|
# All new downloads (first sync)
|
|
578
|
-
sync_progress.finish(
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
#
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
904
|
+
sync_progress.finish(
|
|
905
|
+
f"Complete: {downloaded} files downloaded ({total_skill_dirs} skills)"
|
|
906
|
+
)
|
|
907
|
+
|
|
908
|
+
# Phase 2: Scan agents and save to configuration.yaml
|
|
909
|
+
# This step populates configuration.yaml with agent-referenced skills
|
|
910
|
+
# CRITICAL: Always scan agents to populate agent_referenced, even when using cached skills.
|
|
911
|
+
# Without this, skill_filter=None causes ALL skills to deploy and NO cleanup to run.
|
|
912
|
+
agents_dir = Path.cwd() / ".claude" / "agents"
|
|
913
|
+
|
|
914
|
+
# Scan agents for skill requirements (ALWAYS run to ensure cleanup works)
|
|
915
|
+
agent_skills = get_required_skills_from_agents(agents_dir)
|
|
916
|
+
logger.info(
|
|
917
|
+
f"Agent scan found {len(agent_skills)} unique skills across deployed agents"
|
|
918
|
+
)
|
|
919
|
+
|
|
920
|
+
# Save to project-level configuration.yaml
|
|
921
|
+
project_config_path = Path.cwd() / ".claude-mpm" / "configuration.yaml"
|
|
922
|
+
save_agent_skills_to_config(list(agent_skills), project_config_path)
|
|
923
|
+
logger.debug(
|
|
924
|
+
f"Saved {len(agent_skills)} agent-referenced skills to {project_config_path}"
|
|
925
|
+
)
|
|
926
|
+
|
|
927
|
+
# Phase 3: Resolve which skills to deploy (user_defined or agent_referenced)
|
|
928
|
+
skills_to_deploy, skill_source = get_skills_to_deploy(project_config_path)
|
|
929
|
+
|
|
930
|
+
# CRITICAL DEBUG: Log deployment resolution to diagnose cleanup issues
|
|
931
|
+
if skills_to_deploy:
|
|
932
|
+
logger.info(
|
|
933
|
+
f"Resolved {len(skills_to_deploy)} skills from {skill_source} (cleanup will run)"
|
|
934
|
+
)
|
|
935
|
+
else:
|
|
936
|
+
logger.warning(
|
|
937
|
+
f"No skills resolved from {skill_source} - will deploy ALL skills WITHOUT cleanup! "
|
|
938
|
+
f"This may indicate agent_referenced is empty in configuration.yaml."
|
|
939
|
+
)
|
|
940
|
+
|
|
941
|
+
# Phase 4: Apply profile filtering if active
|
|
942
|
+
if active_profile and profile_manager.active_profile:
|
|
943
|
+
# Filter skills based on profile
|
|
944
|
+
if skills_to_deploy:
|
|
945
|
+
# Filter the resolved skill list
|
|
946
|
+
original_count = len(skills_to_deploy)
|
|
947
|
+
filtered_skills = [
|
|
948
|
+
skill
|
|
949
|
+
for skill in skills_to_deploy
|
|
950
|
+
if profile_manager.is_skill_enabled(skill)
|
|
951
|
+
]
|
|
952
|
+
filtered_count = original_count - len(filtered_skills)
|
|
953
|
+
|
|
954
|
+
# SAFEGUARD: Warn if all skills were filtered out (misconfiguration)
|
|
955
|
+
if not filtered_skills and original_count > 0:
|
|
956
|
+
logger.warning(
|
|
957
|
+
f"Profile '{active_profile}' filtered ALL {original_count} skills. "
|
|
958
|
+
f"This may indicate a naming mismatch in the profile."
|
|
959
|
+
)
|
|
960
|
+
elif filtered_count > 0:
|
|
961
|
+
logger.info(
|
|
962
|
+
f"Profile '{active_profile}' filtered {filtered_count} skills "
|
|
963
|
+
f"({len(filtered_skills)} remaining)"
|
|
964
|
+
)
|
|
965
|
+
|
|
966
|
+
skills_to_deploy = filtered_skills
|
|
967
|
+
skill_source = f"{skill_source} + profile filtered"
|
|
968
|
+
else:
|
|
969
|
+
# No explicit skill list - filter from all available
|
|
970
|
+
all_skills = manager.get_all_skills()
|
|
971
|
+
filtered_skills = [
|
|
972
|
+
skill["name"]
|
|
973
|
+
for skill in all_skills
|
|
974
|
+
if profile_manager.is_skill_enabled(skill["name"])
|
|
975
|
+
]
|
|
976
|
+
skills_to_deploy = filtered_skills
|
|
977
|
+
skill_source = "profile filtered"
|
|
978
|
+
logger.info(
|
|
979
|
+
f"Profile '{active_profile}': "
|
|
980
|
+
f"{len(filtered_skills)} skills enabled from {len(all_skills)} available"
|
|
981
|
+
)
|
|
982
|
+
|
|
983
|
+
# Get all skills to determine counts
|
|
984
|
+
all_skills = manager.get_all_skills()
|
|
985
|
+
total_skill_count = len(all_skills)
|
|
986
|
+
|
|
987
|
+
# Determine skill count based on resolution
|
|
988
|
+
skill_count = len(skills_to_deploy) if skills_to_deploy else total_skill_count
|
|
989
|
+
|
|
990
|
+
if skill_count > 0:
|
|
991
|
+
# Deploy skills with resolved filter
|
|
992
|
+
# Deploy ONLY to project directory (not user-level)
|
|
993
|
+
# DESIGN DECISION: Project-level deployment keeps skills isolated per project,
|
|
994
|
+
# avoiding pollution of user's global ~/.claude/skills/ directory.
|
|
995
|
+
|
|
996
|
+
# Deploy to project-local directory with cleanup
|
|
997
|
+
deployment_result = manager.deploy_skills(
|
|
998
|
+
target_dir=Path.cwd() / ".claude" / "skills",
|
|
999
|
+
force=force_sync,
|
|
1000
|
+
# CRITICAL FIX: Empty list should mean "deploy no skills", not "deploy all"
|
|
1001
|
+
# When skills_to_deploy is [], we want skill_filter=set() NOT skill_filter=None
|
|
1002
|
+
# None means "no filtering" (deploy all), empty set means "filter to nothing"
|
|
1003
|
+
skill_filter=set(skills_to_deploy)
|
|
1004
|
+
if skills_to_deploy is not None
|
|
1005
|
+
else None,
|
|
1006
|
+
)
|
|
1007
|
+
|
|
1008
|
+
# REMOVED: User-level deployment (lines 1068-1074)
|
|
1009
|
+
# Reason: Skills should be project-specific, not user-global.
|
|
1010
|
+
# Claude Code can read from project-level .claude/skills/ directory.
|
|
1011
|
+
|
|
1012
|
+
# Get actual counts from deployment result (use project-local for display)
|
|
1013
|
+
deployed = deployment_result.get("deployed_count", 0)
|
|
1014
|
+
skipped = deployment_result.get("skipped_count", 0)
|
|
1015
|
+
filtered = deployment_result.get("filtered_count", 0)
|
|
1016
|
+
removed = deployment_result.get("removed_count", 0)
|
|
1017
|
+
total_available = deployed + skipped
|
|
1018
|
+
|
|
1019
|
+
# Only show progress bar if there are skills to deploy
|
|
1020
|
+
if total_available > 0:
|
|
590
1021
|
deploy_progress = ProgressBar(
|
|
591
|
-
total=
|
|
1022
|
+
total=total_available,
|
|
592
1023
|
prefix="Deploying skill directories",
|
|
593
1024
|
show_percentage=True,
|
|
594
1025
|
show_counter=True,
|
|
595
1026
|
)
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
1027
|
+
# Update progress bar to completion
|
|
1028
|
+
deploy_progress.update(total_available)
|
|
1029
|
+
else:
|
|
1030
|
+
# No skills to deploy - create dummy progress for message only
|
|
1031
|
+
deploy_progress = ProgressBar(
|
|
1032
|
+
total=1,
|
|
1033
|
+
prefix="Deploying skill directories",
|
|
1034
|
+
show_percentage=False,
|
|
1035
|
+
show_counter=False,
|
|
603
1036
|
)
|
|
1037
|
+
deploy_progress.update(1)
|
|
604
1038
|
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
1039
|
+
# Show total available skills (deployed + already existing)
|
|
1040
|
+
# Include source indication (user_defined vs agent_referenced)
|
|
1041
|
+
# Note: total_skill_count is from cache, total_available is what's deployed/needed
|
|
1042
|
+
source_label = (
|
|
1043
|
+
"user override" if skill_source == "user_defined" else "from agents"
|
|
1044
|
+
)
|
|
609
1045
|
|
|
610
|
-
|
|
611
|
-
|
|
1046
|
+
# Build finish message with cleanup info
|
|
1047
|
+
if deployed > 0 or removed > 0:
|
|
1048
|
+
parts = []
|
|
612
1049
|
if deployed > 0:
|
|
1050
|
+
parts.append(f"{deployed} new")
|
|
1051
|
+
if skipped > 0:
|
|
1052
|
+
parts.append(f"{skipped} unchanged")
|
|
1053
|
+
if removed > 0:
|
|
1054
|
+
parts.append(f"{removed} removed")
|
|
1055
|
+
|
|
1056
|
+
status = ", ".join(parts)
|
|
1057
|
+
|
|
1058
|
+
if filtered > 0:
|
|
613
1059
|
deploy_progress.finish(
|
|
614
|
-
f"Complete: {
|
|
1060
|
+
f"Complete: {status} ({total_available} {source_label}, {filtered} files in cache)"
|
|
615
1061
|
)
|
|
616
1062
|
else:
|
|
617
1063
|
deploy_progress.finish(
|
|
618
|
-
f"Complete: {total_available} skills
|
|
1064
|
+
f"Complete: {status} ({total_available} skills {source_label} from {total_skill_count} files in cache)"
|
|
619
1065
|
)
|
|
1066
|
+
elif filtered > 0:
|
|
1067
|
+
# Skills filtered means agents require fewer skills than available
|
|
1068
|
+
deploy_progress.finish(
|
|
1069
|
+
f"No skills needed ({source_label}, {total_skill_count} files in cache)"
|
|
1070
|
+
)
|
|
1071
|
+
else:
|
|
1072
|
+
# No changes - all skills already deployed
|
|
1073
|
+
msg = f"Complete: {total_available} skills {source_label}"
|
|
1074
|
+
if removed > 0:
|
|
1075
|
+
msg += f", {removed} removed"
|
|
1076
|
+
msg += f" ({total_skill_count} files in cache)"
|
|
1077
|
+
deploy_progress.finish(msg)
|
|
1078
|
+
|
|
1079
|
+
# Log deployment errors if any
|
|
1080
|
+
from ..core.logger import get_logger
|
|
620
1081
|
|
|
621
|
-
|
|
622
|
-
from ..core.logger import get_logger
|
|
623
|
-
|
|
624
|
-
logger = get_logger("cli")
|
|
1082
|
+
logger = get_logger("cli")
|
|
625
1083
|
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
1084
|
+
errors = deployment_result.get("errors", [])
|
|
1085
|
+
if errors:
|
|
1086
|
+
logger.warning(
|
|
1087
|
+
f"Skill deployment completed with {len(errors)} errors: {errors}"
|
|
1088
|
+
)
|
|
631
1089
|
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
1090
|
+
# Log sync errors if any
|
|
1091
|
+
if results["failed_count"] > 0:
|
|
1092
|
+
logger.warning(
|
|
1093
|
+
f"Skill sync completed with {results['failed_count']} failures"
|
|
1094
|
+
)
|
|
637
1095
|
|
|
638
1096
|
except Exception as e:
|
|
639
1097
|
# Non-critical - log but don't fail startup
|
|
@@ -644,7 +1102,282 @@ def sync_remote_skills_on_startup():
|
|
|
644
1102
|
# Continue execution - skill sync failure shouldn't block startup
|
|
645
1103
|
|
|
646
1104
|
|
|
647
|
-
def
|
|
1105
|
+
def show_agent_summary():
|
|
1106
|
+
"""
|
|
1107
|
+
Display agent availability summary on startup.
|
|
1108
|
+
|
|
1109
|
+
WHY: Users should see at a glance how many agents are available and installed
|
|
1110
|
+
without having to run /mpm-agents list.
|
|
1111
|
+
|
|
1112
|
+
DESIGN DECISION: Fast, non-blocking check that counts agents from the deployment
|
|
1113
|
+
directory. Shows simple "X installed / Y available" format. Failures are silent
|
|
1114
|
+
to avoid blocking startup.
|
|
1115
|
+
"""
|
|
1116
|
+
try:
|
|
1117
|
+
from pathlib import Path
|
|
1118
|
+
|
|
1119
|
+
# Count deployed agents (installed)
|
|
1120
|
+
deploy_target = Path.cwd() / ".claude" / "agents"
|
|
1121
|
+
installed_count = 0
|
|
1122
|
+
if deploy_target.exists():
|
|
1123
|
+
# Count .md files, excluding README and other docs
|
|
1124
|
+
agent_files = [
|
|
1125
|
+
f
|
|
1126
|
+
for f in deploy_target.glob("*.md")
|
|
1127
|
+
if not f.name.startswith(("README", "INSTRUCTIONS", "."))
|
|
1128
|
+
]
|
|
1129
|
+
installed_count = len(agent_files)
|
|
1130
|
+
|
|
1131
|
+
# Count available agents in cache (from remote sources)
|
|
1132
|
+
cache_dir = Path.home() / ".claude-mpm" / "cache" / "agents"
|
|
1133
|
+
available_count = 0
|
|
1134
|
+
if cache_dir.exists():
|
|
1135
|
+
# Use same filtering logic as agent deployment (lines 486-533 in startup.py)
|
|
1136
|
+
pm_templates = {
|
|
1137
|
+
"base-agent.md",
|
|
1138
|
+
"circuit_breakers.md",
|
|
1139
|
+
"pm_examples.md",
|
|
1140
|
+
"pm_red_flags.md",
|
|
1141
|
+
"research_gate_examples.md",
|
|
1142
|
+
"response_format.md",
|
|
1143
|
+
"ticket_completeness_examples.md",
|
|
1144
|
+
"validation_templates.md",
|
|
1145
|
+
"git_file_tracking.md",
|
|
1146
|
+
}
|
|
1147
|
+
doc_files = {
|
|
1148
|
+
"readme.md",
|
|
1149
|
+
"changelog.md",
|
|
1150
|
+
"contributing.md",
|
|
1151
|
+
"implementation-summary.md",
|
|
1152
|
+
"reorganization-plan.md",
|
|
1153
|
+
"auto-deploy-index.md",
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1156
|
+
# Find all markdown files in agents/ directories
|
|
1157
|
+
all_md_files = list(cache_dir.rglob("*.md"))
|
|
1158
|
+
agent_files = [
|
|
1159
|
+
f
|
|
1160
|
+
for f in all_md_files
|
|
1161
|
+
if (
|
|
1162
|
+
"/agents/" in str(f)
|
|
1163
|
+
and f.name.lower() not in pm_templates
|
|
1164
|
+
and f.name.lower() not in doc_files
|
|
1165
|
+
and f.name.lower() != "base-agent.md"
|
|
1166
|
+
and not any(
|
|
1167
|
+
part in str(f).split("/")
|
|
1168
|
+
for part in ["dist", "build", ".cache"]
|
|
1169
|
+
)
|
|
1170
|
+
)
|
|
1171
|
+
]
|
|
1172
|
+
available_count = len(agent_files)
|
|
1173
|
+
|
|
1174
|
+
# Display summary if we have agents
|
|
1175
|
+
if installed_count > 0 or available_count > 0:
|
|
1176
|
+
print(
|
|
1177
|
+
f"✓ Agents: {installed_count} deployed / {max(0, available_count - installed_count)} cached",
|
|
1178
|
+
flush=True,
|
|
1179
|
+
)
|
|
1180
|
+
|
|
1181
|
+
except Exception as e:
|
|
1182
|
+
# Silent failure - agent summary is informational only
|
|
1183
|
+
from ..core.logger import get_logger
|
|
1184
|
+
|
|
1185
|
+
logger = get_logger("cli")
|
|
1186
|
+
logger.debug(f"Failed to generate agent summary: {e}")
|
|
1187
|
+
|
|
1188
|
+
|
|
1189
|
+
def show_skill_summary():
|
|
1190
|
+
"""
|
|
1191
|
+
Display skill availability summary on startup.
|
|
1192
|
+
|
|
1193
|
+
WHY: Users should see at a glance how many skills are deployed and available
|
|
1194
|
+
from cache, similar to the agent summary showing "X deployed / Y cached".
|
|
1195
|
+
|
|
1196
|
+
DESIGN DECISION: Fast, non-blocking check that counts skills from:
|
|
1197
|
+
- Deployed skills: PROJECT-level .claude/skills/ directory
|
|
1198
|
+
- Cached skills: ~/.claude-mpm/cache/skills/ directory (from remote sources)
|
|
1199
|
+
|
|
1200
|
+
Shows format: "✓ Skills: X deployed / Y cached"
|
|
1201
|
+
Failures are silent to avoid blocking startup.
|
|
1202
|
+
"""
|
|
1203
|
+
try:
|
|
1204
|
+
from pathlib import Path
|
|
1205
|
+
|
|
1206
|
+
# Count deployed skills (PROJECT-level, not user-level)
|
|
1207
|
+
project_skills_dir = Path.cwd() / ".claude" / "skills"
|
|
1208
|
+
deployed_count = 0
|
|
1209
|
+
if project_skills_dir.exists():
|
|
1210
|
+
# Count directories with SKILL.md (excludes collection repos)
|
|
1211
|
+
# Exclude collection directories (obra-superpowers, etc.)
|
|
1212
|
+
skill_dirs = [
|
|
1213
|
+
d
|
|
1214
|
+
for d in project_skills_dir.iterdir()
|
|
1215
|
+
if d.is_dir()
|
|
1216
|
+
and (d / "SKILL.md").exists()
|
|
1217
|
+
and not (d / ".git").exists() # Exclude collection repos
|
|
1218
|
+
]
|
|
1219
|
+
deployed_count = len(skill_dirs)
|
|
1220
|
+
|
|
1221
|
+
# Count cached skills (from remote sources, not deployed yet)
|
|
1222
|
+
# This matches the agent summary pattern: deployed vs cached
|
|
1223
|
+
cache_dir = Path.home() / ".claude-mpm" / "cache" / "skills"
|
|
1224
|
+
cached_count = 0
|
|
1225
|
+
if cache_dir.exists():
|
|
1226
|
+
# Scan all repository directories in cache
|
|
1227
|
+
# Cache structure: ~/.claude-mpm/cache/skills/{owner}/{repo}/...
|
|
1228
|
+
for repo_dir in cache_dir.rglob("*"):
|
|
1229
|
+
if not repo_dir.is_dir():
|
|
1230
|
+
continue
|
|
1231
|
+
|
|
1232
|
+
# Count skill directories (those with SKILL.md)
|
|
1233
|
+
# Skills can be nested in: skills/category/skill-name/SKILL.md
|
|
1234
|
+
# or in flat structure: skill-name/SKILL.md
|
|
1235
|
+
for root, dirs, files in os.walk(repo_dir):
|
|
1236
|
+
if "SKILL.md" in files:
|
|
1237
|
+
# Exclude build artifacts and hidden directories
|
|
1238
|
+
root_path = Path(root)
|
|
1239
|
+
if not any(
|
|
1240
|
+
part.startswith(".")
|
|
1241
|
+
or part in ["dist", "build", "__pycache__"]
|
|
1242
|
+
for part in root_path.parts
|
|
1243
|
+
):
|
|
1244
|
+
cached_count += 1
|
|
1245
|
+
|
|
1246
|
+
# Display summary using agent summary format: "X deployed / Y cached"
|
|
1247
|
+
# Only show non-deployed cached skills (subtract deployed from cached)
|
|
1248
|
+
non_deployed_cached = max(0, cached_count - deployed_count)
|
|
1249
|
+
if deployed_count > 0 or non_deployed_cached > 0:
|
|
1250
|
+
print(
|
|
1251
|
+
f"✓ Skills: {deployed_count} deployed / {non_deployed_cached} cached",
|
|
1252
|
+
flush=True,
|
|
1253
|
+
)
|
|
1254
|
+
|
|
1255
|
+
except Exception as e:
|
|
1256
|
+
# Silent failure - skill summary is informational only
|
|
1257
|
+
from ..core.logger import get_logger
|
|
1258
|
+
|
|
1259
|
+
logger = get_logger("cli")
|
|
1260
|
+
logger.debug(f"Failed to generate skill summary: {e}")
|
|
1261
|
+
|
|
1262
|
+
|
|
1263
|
+
def verify_and_show_pm_skills():
|
|
1264
|
+
"""Verify PM skills and display status with enhanced validation.
|
|
1265
|
+
|
|
1266
|
+
WHY: PM skills are CRITICAL for PM agent operation. PM must KNOW if
|
|
1267
|
+
framework knowledge is unavailable at startup. Enhanced validation
|
|
1268
|
+
checks all required skills exist, are not corrupted, and auto-repairs
|
|
1269
|
+
if needed.
|
|
1270
|
+
|
|
1271
|
+
Shows deployment status:
|
|
1272
|
+
- "✓ PM skills: 8/8 verified" if all required skills are valid
|
|
1273
|
+
- "⚠ PM skills: 2 missing, auto-repairing..." if issues detected
|
|
1274
|
+
- Non-blocking but visible warning if auto-repair fails
|
|
1275
|
+
"""
|
|
1276
|
+
try:
|
|
1277
|
+
from pathlib import Path
|
|
1278
|
+
|
|
1279
|
+
from ..services.pm_skills_deployer import (
|
|
1280
|
+
REQUIRED_PM_SKILLS,
|
|
1281
|
+
PMSkillsDeployerService,
|
|
1282
|
+
)
|
|
1283
|
+
|
|
1284
|
+
deployer = PMSkillsDeployerService()
|
|
1285
|
+
project_dir = Path.cwd()
|
|
1286
|
+
|
|
1287
|
+
# Verify with auto-repair enabled
|
|
1288
|
+
result = deployer.verify_pm_skills(project_dir, auto_repair=True)
|
|
1289
|
+
|
|
1290
|
+
if result.verified:
|
|
1291
|
+
# Show verified status with count
|
|
1292
|
+
total_required = len(REQUIRED_PM_SKILLS)
|
|
1293
|
+
print(
|
|
1294
|
+
f"✓ PM skills: {total_required}/{total_required} verified", flush=True
|
|
1295
|
+
)
|
|
1296
|
+
else:
|
|
1297
|
+
# Show warning with details
|
|
1298
|
+
missing_count = len(result.missing_skills)
|
|
1299
|
+
corrupted_count = len(result.corrupted_skills)
|
|
1300
|
+
|
|
1301
|
+
# Build status message
|
|
1302
|
+
issues = []
|
|
1303
|
+
if missing_count > 0:
|
|
1304
|
+
issues.append(f"{missing_count} missing")
|
|
1305
|
+
if corrupted_count > 0:
|
|
1306
|
+
issues.append(f"{corrupted_count} corrupted")
|
|
1307
|
+
|
|
1308
|
+
status = ", ".join(issues)
|
|
1309
|
+
|
|
1310
|
+
# Check if auto-repair was attempted
|
|
1311
|
+
if "Auto-repaired" in result.message:
|
|
1312
|
+
# Auto-repair succeeded
|
|
1313
|
+
total_required = len(REQUIRED_PM_SKILLS)
|
|
1314
|
+
print(
|
|
1315
|
+
f"✓ PM skills: {total_required}/{total_required} verified (auto-repaired)",
|
|
1316
|
+
flush=True,
|
|
1317
|
+
)
|
|
1318
|
+
else:
|
|
1319
|
+
# Auto-repair failed or not attempted
|
|
1320
|
+
print(f"⚠ PM skills: {status}", flush=True)
|
|
1321
|
+
|
|
1322
|
+
# Log warnings for debugging
|
|
1323
|
+
from ..core.logger import get_logger
|
|
1324
|
+
|
|
1325
|
+
logger = get_logger("cli")
|
|
1326
|
+
for warning in result.warnings:
|
|
1327
|
+
logger.warning(f"PM skills: {warning}")
|
|
1328
|
+
|
|
1329
|
+
except ImportError:
|
|
1330
|
+
# PM skills deployer not available - skip silently
|
|
1331
|
+
pass
|
|
1332
|
+
except Exception as e:
|
|
1333
|
+
from ..core.logger import get_logger
|
|
1334
|
+
|
|
1335
|
+
logger = get_logger("cli")
|
|
1336
|
+
logger.debug(f"PM skills verification failed: {e}")
|
|
1337
|
+
|
|
1338
|
+
|
|
1339
|
+
def auto_install_chrome_devtools_on_startup():
|
|
1340
|
+
"""
|
|
1341
|
+
Automatically install chrome-devtools-mcp on startup if enabled.
|
|
1342
|
+
|
|
1343
|
+
WHY: Browser automation capabilities should be available out-of-the-box without
|
|
1344
|
+
manual MCP server configuration. chrome-devtools-mcp provides powerful browser
|
|
1345
|
+
interaction tools for Claude Code.
|
|
1346
|
+
|
|
1347
|
+
DESIGN DECISION: Non-blocking installation that doesn't prevent startup if it fails.
|
|
1348
|
+
Respects user configuration setting (enabled by default). Only installs if not
|
|
1349
|
+
already configured in Claude.
|
|
1350
|
+
"""
|
|
1351
|
+
try:
|
|
1352
|
+
# Check if auto-install is disabled in config
|
|
1353
|
+
from ..config.config_loader import ConfigLoader
|
|
1354
|
+
|
|
1355
|
+
config_loader = ConfigLoader()
|
|
1356
|
+
try:
|
|
1357
|
+
config = config_loader.load_main_config()
|
|
1358
|
+
chrome_devtools_config = config.get("chrome_devtools", {})
|
|
1359
|
+
if not chrome_devtools_config.get("auto_install", True):
|
|
1360
|
+
# Auto-install disabled, skip silently
|
|
1361
|
+
return
|
|
1362
|
+
except Exception: # nosec B110
|
|
1363
|
+
# If config loading fails, assume auto-install is enabled (default)
|
|
1364
|
+
pass
|
|
1365
|
+
|
|
1366
|
+
# Import and run chrome-devtools installation
|
|
1367
|
+
from ..cli.chrome_devtools_installer import auto_install_chrome_devtools
|
|
1368
|
+
|
|
1369
|
+
auto_install_chrome_devtools(quiet=False)
|
|
1370
|
+
|
|
1371
|
+
except Exception as e:
|
|
1372
|
+
# Import logger here to avoid circular imports
|
|
1373
|
+
from ..core.logger import get_logger
|
|
1374
|
+
|
|
1375
|
+
logger = get_logger("cli")
|
|
1376
|
+
logger.debug(f"Failed to auto-install chrome-devtools-mcp: {e}")
|
|
1377
|
+
# Continue execution - chrome-devtools installation failure shouldn't block startup
|
|
1378
|
+
|
|
1379
|
+
|
|
1380
|
+
def run_background_services(force_sync: bool = False):
|
|
648
1381
|
"""
|
|
649
1382
|
Initialize all background services on startup.
|
|
650
1383
|
|
|
@@ -655,12 +1388,23 @@ def run_background_services():
|
|
|
655
1388
|
explicitly requests them via agent-manager commands. This prevents unwanted
|
|
656
1389
|
file creation in project .claude/ directories.
|
|
657
1390
|
See: SystemInstructionsDeployer and agent_deployment.py line 504-509
|
|
1391
|
+
|
|
1392
|
+
Args:
|
|
1393
|
+
force_sync: Force download even if cache is fresh (bypasses ETag).
|
|
658
1394
|
"""
|
|
1395
|
+
# Sync hooks early to ensure up-to-date configuration
|
|
1396
|
+
# RATIONALE: Hooks should be synced before other services to fix stale configs
|
|
1397
|
+
# This is fast (<100ms) and non-blocking, so it doesn't delay startup
|
|
1398
|
+
sync_hooks_on_startup() # Shows "Syncing Claude Code hooks... ✓"
|
|
1399
|
+
|
|
659
1400
|
initialize_project_registry()
|
|
660
1401
|
check_mcp_auto_configuration()
|
|
661
1402
|
verify_mcp_gateway_startup()
|
|
662
1403
|
check_for_updates_async()
|
|
663
|
-
sync_remote_agents_on_startup(
|
|
1404
|
+
sync_remote_agents_on_startup(
|
|
1405
|
+
force_sync=force_sync
|
|
1406
|
+
) # Sync agents from remote sources
|
|
1407
|
+
show_agent_summary() # Display agent counts after deployment
|
|
664
1408
|
|
|
665
1409
|
# Skills deployment order (precedence: remote > bundled)
|
|
666
1410
|
# 1. Deploy bundled skills first (base layer from package)
|
|
@@ -668,11 +1412,18 @@ def run_background_services():
|
|
|
668
1412
|
# 3. Discover and link runtime skills (user-added skills)
|
|
669
1413
|
# This ensures remote skills take precedence over bundled skills when names conflict
|
|
670
1414
|
deploy_bundled_skills() # Base layer: package-bundled skills
|
|
671
|
-
sync_remote_skills_on_startup(
|
|
1415
|
+
sync_remote_skills_on_startup(
|
|
1416
|
+
force_sync=force_sync
|
|
1417
|
+
) # Override layer: Git-based skills (takes precedence)
|
|
672
1418
|
discover_and_link_runtime_skills() # Discovery: user-added skills
|
|
1419
|
+
show_skill_summary() # Display skill counts after deployment
|
|
1420
|
+
verify_and_show_pm_skills() # PM skills verification and status
|
|
673
1421
|
|
|
674
1422
|
deploy_output_style_on_startup()
|
|
675
1423
|
|
|
1424
|
+
# Auto-install chrome-devtools-mcp for browser automation
|
|
1425
|
+
auto_install_chrome_devtools_on_startup()
|
|
1426
|
+
|
|
676
1427
|
|
|
677
1428
|
def setup_mcp_server_logging(args):
|
|
678
1429
|
"""
|
|
@@ -776,11 +1527,19 @@ def check_mcp_auto_configuration():
|
|
|
776
1527
|
check_and_configure_mcp()
|
|
777
1528
|
|
|
778
1529
|
# Clear the "Checking..." message by overwriting with spaces
|
|
779
|
-
|
|
1530
|
+
# Only use carriage return clearing if stdout is a real TTY
|
|
1531
|
+
if sys.stdout.isatty():
|
|
1532
|
+
print("\r" + " " * 30 + "\r", end="", flush=True)
|
|
1533
|
+
else:
|
|
1534
|
+
print() # Simple newline for non-TTY (like Claude Code REPL)
|
|
780
1535
|
|
|
781
1536
|
except Exception as e:
|
|
782
1537
|
# Clear progress message on error
|
|
783
|
-
|
|
1538
|
+
# Only use carriage return clearing if stdout is a real TTY
|
|
1539
|
+
if sys.stdout.isatty():
|
|
1540
|
+
print("\r" + " " * 30 + "\r", end="", flush=True)
|
|
1541
|
+
else:
|
|
1542
|
+
print() # Simple newline for non-TTY (like Claude Code REPL)
|
|
784
1543
|
|
|
785
1544
|
# Non-critical - log but don't fail
|
|
786
1545
|
from ..core.logger import get_logger
|
|
@@ -800,18 +1559,10 @@ def verify_mcp_gateway_startup():
|
|
|
800
1559
|
DESIGN DECISION: This is non-blocking - failures are logged but don't prevent
|
|
801
1560
|
startup to ensure claude-mpm remains functional even if MCP gateway has issues.
|
|
802
1561
|
"""
|
|
803
|
-
#
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
logger = get_logger("mcp_verify")
|
|
809
|
-
all_ok, message = verify_mcp_services_on_startup()
|
|
810
|
-
if not all_ok:
|
|
811
|
-
logger.warning(message)
|
|
812
|
-
except Exception:
|
|
813
|
-
# Non-critical - continue with startup
|
|
814
|
-
pass
|
|
1562
|
+
# DISABLED: MCP service verification removed - Claude Code handles MCP natively
|
|
1563
|
+
# The previous check warned about missing MCP services, but users should configure
|
|
1564
|
+
# MCP servers through Claude Code's native MCP management, not through claude-mpm.
|
|
1565
|
+
# See: https://docs.anthropic.com/en/docs/claude-code/mcp
|
|
815
1566
|
|
|
816
1567
|
try:
|
|
817
1568
|
import asyncio
|
|
@@ -871,7 +1622,7 @@ def verify_mcp_gateway_startup():
|
|
|
871
1622
|
loop.run_until_complete(
|
|
872
1623
|
asyncio.gather(*pending, return_exceptions=True)
|
|
873
1624
|
)
|
|
874
|
-
except Exception:
|
|
1625
|
+
except Exception: # nosec B110
|
|
875
1626
|
pass # Ignore cleanup errors
|
|
876
1627
|
finally:
|
|
877
1628
|
loop.close()
|
|
@@ -965,7 +1716,7 @@ def check_for_updates_async():
|
|
|
965
1716
|
|
|
966
1717
|
logger = get_logger("upgrade_check")
|
|
967
1718
|
logger.debug(f"Update check failed (non-critical): {e}")
|
|
968
|
-
except Exception:
|
|
1719
|
+
except Exception: # nosec B110
|
|
969
1720
|
pass # Avoid any errors in error handling
|
|
970
1721
|
finally:
|
|
971
1722
|
# Properly clean up event loop
|
|
@@ -980,7 +1731,7 @@ def check_for_updates_async():
|
|
|
980
1731
|
loop.run_until_complete(
|
|
981
1732
|
asyncio.gather(*pending, return_exceptions=True)
|
|
982
1733
|
)
|
|
983
|
-
except Exception:
|
|
1734
|
+
except Exception: # nosec B110
|
|
984
1735
|
pass # Ignore cleanup errors
|
|
985
1736
|
finally:
|
|
986
1737
|
loop.close()
|