claude-mpm 5.4.22__py3-none-any.whl → 5.6.34__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of claude-mpm might be problematic. Click here for more details.
- claude_mpm/VERSION +1 -1
- claude_mpm/agents/BASE_AGENT.md +164 -0
- claude_mpm/agents/BASE_ENGINEER.md +658 -0
- claude_mpm/agents/CLAUDE_MPM_OUTPUT_STYLE.md +66 -241
- claude_mpm/agents/CLAUDE_MPM_RESEARCH_OUTPUT_STYLE.md +413 -0
- claude_mpm/agents/CLAUDE_MPM_TEACHER_OUTPUT_STYLE.md +109 -1925
- claude_mpm/agents/MEMORY.md +1 -1
- claude_mpm/agents/PM_INSTRUCTIONS.md +374 -1257
- claude_mpm/agents/WORKFLOW.md +6 -253
- claude_mpm/agents/agent_loader.py +1 -1
- claude_mpm/agents/base_agent.json +31 -0
- claude_mpm/agents/frontmatter_validator.py +2 -2
- claude_mpm/agents/templates/circuit-breakers.md +26 -17
- claude_mpm/cli/__init__.py +5 -1
- claude_mpm/cli/commands/agent_state_manager.py +10 -10
- claude_mpm/cli/commands/agents.py +11 -13
- claude_mpm/cli/commands/agents_reconcile.py +197 -0
- claude_mpm/cli/commands/auto_configure.py +4 -4
- claude_mpm/cli/commands/autotodos.py +566 -0
- claude_mpm/cli/commands/commander.py +216 -0
- claude_mpm/cli/commands/configure.py +621 -22
- claude_mpm/cli/commands/configure_agent_display.py +12 -0
- 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 +72 -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 +182 -32
- claude_mpm/cli/executor.py +130 -16
- claude_mpm/cli/interactive/__init__.py +10 -0
- claude_mpm/cli/interactive/agent_wizard.py +32 -52
- claude_mpm/cli/interactive/questionary_styles.py +65 -0
- claude_mpm/cli/interactive/skill_selector.py +481 -0
- claude_mpm/cli/parsers/base_parser.py +83 -1
- claude_mpm/cli/parsers/commander_parser.py +116 -0
- 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 +2 -3
- claude_mpm/cli/startup.py +690 -386
- 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 +20 -249
- claude_mpm/commands/mpm-doctor.md +16 -21
- claude_mpm/commands/mpm-help.md +12 -205
- claude_mpm/commands/mpm-init.md +88 -506
- claude_mpm/commands/mpm-monitor.md +22 -401
- claude_mpm/commands/mpm-organize.md +70 -442
- 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/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/loaders/agent_loader.py +1 -1
- claude_mpm/core/framework/loaders/instruction_loader.py +52 -11
- claude_mpm/core/hook_manager.py +51 -3
- claude_mpm/core/interactive_session.py +12 -11
- claude_mpm/core/logger.py +26 -9
- claude_mpm/core/logging_utils.py +39 -13
- 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 +66 -18
- claude_mpm/core/shared/config_loader.py +3 -1
- claude_mpm/core/socketio_pool.py +47 -15
- claude_mpm/core/unified_agent_registry.py +1 -1
- claude_mpm/core/unified_config.py +54 -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/event_handlers.py +527 -136
- claude_mpm/hooks/claude_hooks/hook_handler.py +313 -99
- claude_mpm/hooks/claude_hooks/hook_wrapper.sh +6 -11
- claude_mpm/hooks/claude_hooks/installer.py +206 -36
- claude_mpm/hooks/claude_hooks/memory_integration.py +52 -32
- claude_mpm/hooks/claude_hooks/response_tracking.py +43 -60
- claude_mpm/hooks/claude_hooks/services/__init__.py +21 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/container.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/protocols.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/connection_manager.py +67 -32
- claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +38 -105
- claude_mpm/hooks/claude_hooks/services/container.py +310 -0
- claude_mpm/hooks/claude_hooks/services/protocols.py +328 -0
- claude_mpm/hooks/claude_hooks/services/state_manager.py +25 -38
- claude_mpm/hooks/claude_hooks/services/subagent_processor.py +75 -77
- claude_mpm/hooks/kuzu_memory_hook.py +5 -5
- claude_mpm/hooks/session_resume_hook.py +89 -1
- claude_mpm/hooks/templates/pre_tool_use_simple.py +6 -6
- claude_mpm/hooks/templates/pre_tool_use_template.py +16 -8
- claude_mpm/init.py +276 -0
- claude_mpm/models/git_repository.py +3 -3
- claude_mpm/scripts/claude-hook-handler.sh +46 -19
- claude_mpm/services/agents/agent_builder.py +3 -3
- claude_mpm/services/agents/agent_recommendation_service.py +8 -8
- claude_mpm/services/agents/agent_selection_service.py +2 -2
- claude_mpm/services/agents/cache_git_manager.py +7 -7
- claude_mpm/services/agents/deployment/agent_deployment.py +29 -7
- claude_mpm/services/agents/deployment/agent_discovery_service.py +4 -2
- claude_mpm/services/agents/deployment/agent_format_converter.py +25 -13
- claude_mpm/services/agents/deployment/agent_template_builder.py +39 -19
- 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 +169 -26
- claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +101 -75
- claude_mpm/services/agents/deployment/startup_reconciliation.py +138 -0
- claude_mpm/services/agents/git_source_manager.py +23 -4
- 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 +121 -10
- claude_mpm/services/agents/startup_sync.py +27 -4
- claude_mpm/services/cli/__init__.py +3 -0
- claude_mpm/services/cli/incremental_pause_manager.py +561 -0
- claude_mpm/services/cli/session_resume_helper.py +10 -2
- claude_mpm/services/command_deployment_service.py +44 -26
- claude_mpm/services/delegation_detector.py +175 -0
- claude_mpm/services/diagnostics/checks/agent_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_log.py +325 -0
- claude_mpm/services/git/git_operations_service.py +8 -8
- claude_mpm/services/hook_installer_service.py +77 -8
- claude_mpm/services/infrastructure/__init__.py +4 -0
- claude_mpm/services/infrastructure/context_usage_tracker.py +291 -0
- claude_mpm/services/infrastructure/resume_log_generator.py +24 -5
- claude_mpm/services/monitor/daemon_manager.py +15 -4
- claude_mpm/services/monitor/management/lifecycle.py +15 -3
- claude_mpm/services/monitor/server.py +571 -11
- claude_mpm/services/pm_skills_deployer.py +884 -0
- claude_mpm/services/profile_manager.py +337 -0
- claude_mpm/services/skills/git_skill_source_manager.py +281 -20
- claude_mpm/services/skills/selective_skill_deployer.py +211 -46
- claude_mpm/services/skills/skill_discovery_service.py +74 -4
- claude_mpm/services/skills_deployer.py +192 -70
- claude_mpm/services/socketio/dashboard_server.py +1 -0
- claude_mpm/services/socketio/event_normalizer.py +37 -6
- claude_mpm/services/socketio/handlers/hook.py +14 -7
- claude_mpm/services/socketio/server/core.py +262 -123
- claude_mpm/services/socketio/server/main.py +12 -4
- claude_mpm/skills/__init__.py +2 -1
- claude_mpm/skills/bundled/collaboration/brainstorming/SKILL.md +79 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/SKILL.md +178 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/agent-prompts.md +577 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/coordination-patterns.md +467 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/examples.md +537 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/troubleshooting.md +730 -0
- claude_mpm/skills/bundled/collaboration/git-worktrees.md +317 -0
- claude_mpm/skills/bundled/collaboration/requesting-code-review/SKILL.md +112 -0
- claude_mpm/skills/bundled/collaboration/requesting-code-review/references/code-reviewer-template.md +146 -0
- claude_mpm/skills/bundled/collaboration/requesting-code-review/references/review-examples.md +412 -0
- claude_mpm/skills/bundled/collaboration/stacked-prs.md +251 -0
- claude_mpm/skills/bundled/collaboration/writing-plans/SKILL.md +81 -0
- claude_mpm/skills/bundled/collaboration/writing-plans/references/best-practices.md +362 -0
- claude_mpm/skills/bundled/collaboration/writing-plans/references/plan-structure-templates.md +312 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/SKILL.md +152 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/advanced-techniques.md +668 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/examples.md +587 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/integration.md +438 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/tracing-techniques.md +391 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/CREATION-LOG.md +119 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/SKILL.md +148 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/anti-patterns.md +483 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/examples.md +452 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/troubleshooting.md +449 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/workflow.md +411 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-academic.md +14 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-1.md +58 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-2.md +68 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-3.md +69 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/SKILL.md +131 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/gate-function.md +325 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/integration-and-workflows.md +490 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/red-flags-and-failures.md +425 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/verification-patterns.md +499 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/INTEGRATION.md +611 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/README.md +596 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/SKILL.md +260 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/examples/nextjs-env-structure.md +315 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/references/frameworks.md +436 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/references/security.md +433 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/references/synchronization.md +452 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/references/troubleshooting.md +404 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/references/validation.md +420 -0
- claude_mpm/skills/bundled/main/artifacts-builder/SKILL.md +86 -0
- claude_mpm/skills/bundled/main/internal-comms/SKILL.md +43 -0
- claude_mpm/skills/bundled/main/internal-comms/examples/3p-updates.md +47 -0
- claude_mpm/skills/bundled/main/internal-comms/examples/company-newsletter.md +65 -0
- claude_mpm/skills/bundled/main/internal-comms/examples/faq-answers.md +30 -0
- claude_mpm/skills/bundled/main/internal-comms/examples/general-comms.md +16 -0
- claude_mpm/skills/bundled/main/mcp-builder/SKILL.md +160 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/design_principles.md +412 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/evaluation.md +602 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/mcp_best_practices.md +915 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/node_mcp_server.md +916 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/python_mcp_server.md +752 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/workflow.md +1237 -0
- claude_mpm/skills/bundled/main/skill-creator/SKILL.md +189 -0
- claude_mpm/skills/bundled/main/skill-creator/references/best-practices.md +500 -0
- claude_mpm/skills/bundled/main/skill-creator/references/creation-workflow.md +464 -0
- claude_mpm/skills/bundled/main/skill-creator/references/examples.md +619 -0
- claude_mpm/skills/bundled/main/skill-creator/references/progressive-disclosure.md +437 -0
- claude_mpm/skills/bundled/main/skill-creator/references/skill-structure.md +231 -0
- claude_mpm/skills/bundled/php/espocrm-development/SKILL.md +170 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/architecture.md +602 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/common-tasks.md +821 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/development-workflow.md +742 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/frontend-customization.md +726 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/hooks-and-services.md +764 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/testing-debugging.md +831 -0
- claude_mpm/skills/bundled/pm/mpm/SKILL.md +38 -0
- claude_mpm/skills/bundled/pm/mpm-agent-update-workflow/SKILL.md +75 -0
- claude_mpm/skills/bundled/pm/mpm-bug-reporting/SKILL.md +248 -0
- claude_mpm/skills/bundled/pm/mpm-circuit-breaker-enforcement/SKILL.md +476 -0
- claude_mpm/skills/bundled/pm/mpm-config/SKILL.md +29 -0
- claude_mpm/skills/bundled/pm/mpm-delegation-patterns/SKILL.md +167 -0
- claude_mpm/skills/bundled/pm/mpm-doctor/SKILL.md +53 -0
- claude_mpm/skills/bundled/pm/mpm-git-file-tracking/SKILL.md +113 -0
- claude_mpm/skills/bundled/pm/mpm-help/SKILL.md +35 -0
- claude_mpm/skills/bundled/pm/mpm-init/SKILL.md +125 -0
- claude_mpm/skills/bundled/pm/mpm-monitor/SKILL.md +32 -0
- claude_mpm/skills/bundled/pm/mpm-organize/SKILL.md +121 -0
- claude_mpm/skills/bundled/pm/mpm-postmortem/SKILL.md +22 -0
- claude_mpm/skills/bundled/pm/mpm-pr-workflow/SKILL.md +124 -0
- claude_mpm/skills/bundled/pm/mpm-session-management/SKILL.md +312 -0
- claude_mpm/skills/bundled/pm/mpm-session-pause/SKILL.md +170 -0
- claude_mpm/skills/bundled/pm/mpm-session-resume/SKILL.md +31 -0
- claude_mpm/skills/bundled/pm/mpm-status/SKILL.md +37 -0
- claude_mpm/skills/bundled/pm/mpm-teaching-mode/SKILL.md +657 -0
- claude_mpm/skills/bundled/pm/mpm-ticket-view/SKILL.md +110 -0
- claude_mpm/skills/bundled/pm/mpm-ticketing-integration/SKILL.md +154 -0
- claude_mpm/skills/bundled/pm/mpm-tool-usage-guide/SKILL.md +386 -0
- claude_mpm/skills/bundled/pm/mpm-verification-protocols/SKILL.md +198 -0
- claude_mpm/skills/bundled/pm/mpm-version/SKILL.md +21 -0
- claude_mpm/skills/bundled/react/flexlayout-react.md +742 -0
- claude_mpm/skills/bundled/rust/desktop-applications/SKILL.md +226 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/architecture-patterns.md +901 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/native-gui-frameworks.md +901 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/platform-integration.md +775 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/state-management.md +937 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/tauri-framework.md +770 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/testing-deployment.md +961 -0
- claude_mpm/skills/bundled/security-scanning.md +112 -0
- claude_mpm/skills/bundled/tauri/tauri-async-patterns.md +495 -0
- claude_mpm/skills/bundled/tauri/tauri-build-deploy.md +599 -0
- claude_mpm/skills/bundled/tauri/tauri-command-patterns.md +535 -0
- claude_mpm/skills/bundled/tauri/tauri-error-handling.md +613 -0
- claude_mpm/skills/bundled/tauri/tauri-event-system.md +648 -0
- claude_mpm/skills/bundled/tauri/tauri-file-system.md +673 -0
- claude_mpm/skills/bundled/tauri/tauri-frontend-integration.md +767 -0
- claude_mpm/skills/bundled/tauri/tauri-performance.md +669 -0
- claude_mpm/skills/bundled/tauri/tauri-state-management.md +573 -0
- claude_mpm/skills/bundled/tauri/tauri-testing.md +384 -0
- claude_mpm/skills/bundled/tauri/tauri-window-management.md +628 -0
- claude_mpm/skills/bundled/testing/condition-based-waiting/SKILL.md +119 -0
- claude_mpm/skills/bundled/testing/condition-based-waiting/references/patterns-and-implementation.md +253 -0
- claude_mpm/skills/bundled/testing/test-driven-development/SKILL.md +145 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/anti-patterns.md +543 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/examples.md +741 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/integration.md +470 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/philosophy.md +458 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/workflow.md +639 -0
- claude_mpm/skills/bundled/testing/test-quality-inspector/SKILL.md +458 -0
- claude_mpm/skills/bundled/testing/test-quality-inspector/examples/example-inspection-report.md +411 -0
- claude_mpm/skills/bundled/testing/test-quality-inspector/references/assertion-quality.md +317 -0
- claude_mpm/skills/bundled/testing/test-quality-inspector/references/inspection-checklist.md +270 -0
- claude_mpm/skills/bundled/testing/test-quality-inspector/references/red-flags.md +436 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/SKILL.md +140 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/completeness-anti-patterns.md +572 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/core-anti-patterns.md +411 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/detection-guide.md +569 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/tdd-connection.md +695 -0
- claude_mpm/skills/bundled/testing/webapp-testing/SKILL.md +184 -0
- claude_mpm/skills/bundled/testing/webapp-testing/decision-tree.md +459 -0
- claude_mpm/skills/bundled/testing/webapp-testing/playwright-patterns.md +479 -0
- claude_mpm/skills/bundled/testing/webapp-testing/reconnaissance-pattern.md +687 -0
- claude_mpm/skills/bundled/testing/webapp-testing/server-management.md +758 -0
- claude_mpm/skills/bundled/testing/webapp-testing/troubleshooting.md +868 -0
- claude_mpm/skills/registry.py +295 -90
- claude_mpm/skills/skill_manager.py +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 +1 -1
- claude_mpm/utils/migration.py +4 -4
- claude_mpm/utils/robust_installer.py +86 -21
- claude_mpm-5.6.34.dist-info/METADATA +393 -0
- {claude_mpm-5.4.22.dist-info → claude_mpm-5.6.34.dist-info}/RECORD +486 -145
- claude_mpm-5.4.22.dist-info/METADATA +0 -996
- {claude_mpm-5.4.22.dist-info → claude_mpm-5.6.34.dist-info}/WHEEL +0 -0
- {claude_mpm-5.4.22.dist-info → claude_mpm-5.6.34.dist-info}/entry_points.txt +0 -0
- {claude_mpm-5.4.22.dist-info → claude_mpm-5.6.34.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-5.4.22.dist-info → claude_mpm-5.6.34.dist-info}/licenses/LICENSE-FAQ.md +0 -0
- {claude_mpm-5.4.22.dist-info → claude_mpm-5.6.34.dist-info}/top_level.txt +0 -0
|
@@ -28,7 +28,7 @@ References:
|
|
|
28
28
|
import json
|
|
29
29
|
import platform
|
|
30
30
|
import shutil
|
|
31
|
-
import subprocess
|
|
31
|
+
import subprocess # nosec B404 - subprocess needed for safe git operations
|
|
32
32
|
from pathlib import Path
|
|
33
33
|
from typing import Any, Dict, List, Optional
|
|
34
34
|
|
|
@@ -174,44 +174,93 @@ class SkillsDeployerService(LoggerMixin):
|
|
|
174
174
|
if selective:
|
|
175
175
|
# Auto-detect project root if not provided
|
|
176
176
|
if project_root is None:
|
|
177
|
-
# Try to find project root by looking for .claude directory
|
|
177
|
+
# Try to find project root by looking for .claude-mpm directory
|
|
178
178
|
# Start from current directory and walk up
|
|
179
179
|
current = Path.cwd()
|
|
180
180
|
while current != current.parent:
|
|
181
|
-
if (current / ".claude").exists():
|
|
181
|
+
if (current / ".claude-mpm").exists():
|
|
182
182
|
project_root = current
|
|
183
183
|
break
|
|
184
184
|
current = current.parent
|
|
185
185
|
|
|
186
|
+
# Read skills from configuration.yaml instead of agent frontmatter
|
|
186
187
|
if project_root:
|
|
187
|
-
|
|
188
|
+
config_path = Path(project_root) / ".claude-mpm" / "configuration.yaml"
|
|
188
189
|
else:
|
|
189
|
-
# Fallback to current directory's
|
|
190
|
-
|
|
190
|
+
# Fallback to current directory's configuration
|
|
191
|
+
config_path = Path.cwd() / ".claude-mpm" / "configuration.yaml"
|
|
191
192
|
|
|
192
193
|
from claude_mpm.services.skills.selective_skill_deployer import (
|
|
193
194
|
get_required_skills_from_agents,
|
|
195
|
+
get_skills_to_deploy,
|
|
196
|
+
save_agent_skills_to_config,
|
|
194
197
|
)
|
|
195
198
|
|
|
196
|
-
|
|
199
|
+
# Check if agent_referenced is empty and needs to be populated
|
|
200
|
+
required_skill_names, source = get_skills_to_deploy(config_path)
|
|
201
|
+
|
|
202
|
+
if not required_skill_names and project_root:
|
|
203
|
+
# agent_referenced is empty, scan deployed agents to populate it
|
|
204
|
+
agents_dir = Path(project_root) / ".claude" / "agents"
|
|
205
|
+
if agents_dir.exists():
|
|
206
|
+
self.logger.info(
|
|
207
|
+
"agent_referenced is empty in configuration.yaml, scanning deployed agents..."
|
|
208
|
+
)
|
|
209
|
+
agent_skills = get_required_skills_from_agents(agents_dir)
|
|
210
|
+
if agent_skills:
|
|
211
|
+
save_agent_skills_to_config(list(agent_skills), config_path)
|
|
212
|
+
self.logger.info(
|
|
213
|
+
f"Populated agent_referenced with {len(agent_skills)} skills from deployed agents"
|
|
214
|
+
)
|
|
215
|
+
# Re-read configuration after update
|
|
216
|
+
required_skill_names, source = get_skills_to_deploy(config_path)
|
|
217
|
+
else:
|
|
218
|
+
self.logger.warning(
|
|
219
|
+
"No skills found in deployed agents - configuration.yaml remains empty"
|
|
220
|
+
)
|
|
221
|
+
else:
|
|
222
|
+
self.logger.warning(
|
|
223
|
+
f"Agents directory not found at {agents_dir} - cannot scan for skills"
|
|
224
|
+
)
|
|
197
225
|
|
|
198
226
|
if required_skill_names:
|
|
227
|
+
# Convert required_skill_names to a set for O(1) lookup
|
|
228
|
+
required_set = set(required_skill_names)
|
|
229
|
+
|
|
199
230
|
# Filter to only required skills
|
|
200
|
-
# Match on
|
|
231
|
+
# Match on: 'name', 'skill_id', or normalized 'source_path'
|
|
232
|
+
# source_path example: "universal/web/api-design-patterns/SKILL.md"
|
|
233
|
+
# normalized: "universal-web-api-design-patterns"
|
|
234
|
+
def skill_matches_requirement(skill):
|
|
235
|
+
# Check basic name and skill_id
|
|
236
|
+
if skill.get("name") in required_set:
|
|
237
|
+
return True
|
|
238
|
+
if skill.get("skill_id") in required_set:
|
|
239
|
+
return True
|
|
240
|
+
|
|
241
|
+
# Check normalized source_path
|
|
242
|
+
source_path = skill.get("source_path", "")
|
|
243
|
+
if source_path:
|
|
244
|
+
# Remove /SKILL.md suffix and replace / with -
|
|
245
|
+
normalized = source_path.replace("/SKILL.md", "").replace(
|
|
246
|
+
"/", "-"
|
|
247
|
+
)
|
|
248
|
+
if normalized in required_set:
|
|
249
|
+
return True
|
|
250
|
+
|
|
251
|
+
return False
|
|
252
|
+
|
|
201
253
|
filtered_skills = [
|
|
202
|
-
s
|
|
203
|
-
for s in filtered_skills
|
|
204
|
-
if s.get("name") in required_skill_names
|
|
205
|
-
or s.get("skill_id") in required_skill_names
|
|
254
|
+
s for s in filtered_skills if skill_matches_requirement(s)
|
|
206
255
|
]
|
|
207
256
|
|
|
208
257
|
self.logger.info(
|
|
209
258
|
f"Selective deployment: {len(filtered_skills)}/{total_available} skills "
|
|
210
|
-
f"(
|
|
259
|
+
f"(source: {source})"
|
|
211
260
|
)
|
|
212
261
|
else:
|
|
213
262
|
self.logger.warning(
|
|
214
|
-
f"No skills found in
|
|
263
|
+
f"No skills found in configuration at {config_path}. "
|
|
215
264
|
f"Deploying all {total_available} skills."
|
|
216
265
|
)
|
|
217
266
|
else:
|
|
@@ -224,12 +273,19 @@ class SkillsDeployerService(LoggerMixin):
|
|
|
224
273
|
skipped = []
|
|
225
274
|
errors = []
|
|
226
275
|
|
|
227
|
-
# Extract skill names for cleanup (needed regardless of deployment outcome)
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
if isinstance(skill, dict) and "name" in skill
|
|
232
|
-
|
|
276
|
+
# Extract normalized skill names for cleanup (needed regardless of deployment outcome)
|
|
277
|
+
# Must match the names used during deployment (normalized from source_path)
|
|
278
|
+
filtered_skills_names = []
|
|
279
|
+
for skill in filtered_skills:
|
|
280
|
+
if isinstance(skill, dict) and "name" in skill:
|
|
281
|
+
source_path = skill.get("source_path", "")
|
|
282
|
+
if source_path:
|
|
283
|
+
# Normalize: "universal/web/api-design-patterns/SKILL.md" -> "universal-web-api-design-patterns"
|
|
284
|
+
normalized = source_path.replace("/SKILL.md", "").replace("/", "-")
|
|
285
|
+
filtered_skills_names.append(normalized)
|
|
286
|
+
else:
|
|
287
|
+
# Fallback to skill name
|
|
288
|
+
filtered_skills_names.append(skill["name"])
|
|
233
289
|
|
|
234
290
|
for skill in filtered_skills:
|
|
235
291
|
try:
|
|
@@ -243,9 +299,25 @@ class SkillsDeployerService(LoggerMixin):
|
|
|
243
299
|
skill, skills_data["temp_dir"], collection_name, force=force
|
|
244
300
|
)
|
|
245
301
|
if result["deployed"]:
|
|
246
|
-
|
|
302
|
+
# Use normalized name for reporting
|
|
303
|
+
source_path = skill.get("source_path", "")
|
|
304
|
+
if source_path:
|
|
305
|
+
normalized = source_path.replace("/SKILL.md", "").replace(
|
|
306
|
+
"/", "-"
|
|
307
|
+
)
|
|
308
|
+
deployed.append(normalized)
|
|
309
|
+
else:
|
|
310
|
+
deployed.append(skill["name"])
|
|
247
311
|
elif result["skipped"]:
|
|
248
|
-
|
|
312
|
+
# Use normalized name for reporting
|
|
313
|
+
source_path = skill.get("source_path", "")
|
|
314
|
+
if source_path:
|
|
315
|
+
normalized = source_path.replace("/SKILL.md", "").replace(
|
|
316
|
+
"/", "-"
|
|
317
|
+
)
|
|
318
|
+
skipped.append(normalized)
|
|
319
|
+
else:
|
|
320
|
+
skipped.append(skill["name"])
|
|
249
321
|
if result["error"]:
|
|
250
322
|
errors.append(result["error"])
|
|
251
323
|
except Exception as e:
|
|
@@ -257,9 +329,9 @@ class SkillsDeployerService(LoggerMixin):
|
|
|
257
329
|
self.logger.error(f"Failed to deploy {skill_name}: {e}")
|
|
258
330
|
errors.append(f"{skill_name}: {e}")
|
|
259
331
|
|
|
260
|
-
# Step 5: Cleanup orphaned skills (
|
|
332
|
+
# Step 5: Cleanup orphaned skills (always run in selective mode)
|
|
261
333
|
cleanup_result = {"removed_count": 0, "removed_skills": []}
|
|
262
|
-
if selective
|
|
334
|
+
if selective:
|
|
263
335
|
# Get the set of skills that should remain deployed
|
|
264
336
|
# This is the union of what we just deployed and what was already there
|
|
265
337
|
try:
|
|
@@ -267,7 +339,8 @@ class SkillsDeployerService(LoggerMixin):
|
|
|
267
339
|
cleanup_orphan_skills,
|
|
268
340
|
)
|
|
269
341
|
|
|
270
|
-
#
|
|
342
|
+
# Cleanup orphaned skills not referenced by agents
|
|
343
|
+
# This runs even if nothing new was deployed to remove stale skills
|
|
271
344
|
cleanup_result = cleanup_orphan_skills(
|
|
272
345
|
self.CLAUDE_SKILLS_DIR, set(filtered_skills_names)
|
|
273
346
|
)
|
|
@@ -580,7 +653,7 @@ class SkillsDeployerService(LoggerMixin):
|
|
|
580
653
|
f"Updating existing collection '{collection_name}' at {target_dir}"
|
|
581
654
|
)
|
|
582
655
|
try:
|
|
583
|
-
result = subprocess.run(
|
|
656
|
+
result = subprocess.run( # nosec B603 B607 - Safe: hardcoded git command
|
|
584
657
|
["git", "pull"],
|
|
585
658
|
cwd=target_dir,
|
|
586
659
|
capture_output=True,
|
|
@@ -611,7 +684,7 @@ class SkillsDeployerService(LoggerMixin):
|
|
|
611
684
|
f"Installing new collection '{collection_name}' to {target_dir}"
|
|
612
685
|
)
|
|
613
686
|
try:
|
|
614
|
-
result = subprocess.run(
|
|
687
|
+
result = subprocess.run( # nosec B603 B607 - Safe: hardcoded git command
|
|
615
688
|
["git", "clone", repo_url, str(target_dir)],
|
|
616
689
|
capture_output=True,
|
|
617
690
|
text=True,
|
|
@@ -700,6 +773,32 @@ class SkillsDeployerService(LoggerMixin):
|
|
|
700
773
|
if isinstance(skills_data, dict):
|
|
701
774
|
flat_skills = []
|
|
702
775
|
|
|
776
|
+
# Define valid top-level categories
|
|
777
|
+
VALID_CATEGORIES = {"universal", "toolchains"}
|
|
778
|
+
|
|
779
|
+
# Check for unknown categories and warn user
|
|
780
|
+
unknown_categories = set(skills_data.keys()) - VALID_CATEGORIES
|
|
781
|
+
if unknown_categories:
|
|
782
|
+
# Count skills in unknown categories
|
|
783
|
+
skipped_count = 0
|
|
784
|
+
for cat in unknown_categories:
|
|
785
|
+
cat_data = skills_data.get(cat, [])
|
|
786
|
+
if isinstance(cat_data, list):
|
|
787
|
+
skipped_count += len(cat_data)
|
|
788
|
+
elif isinstance(cat_data, dict):
|
|
789
|
+
# If it's a dict like toolchains, count nested skills
|
|
790
|
+
for skills_list in cat_data.values():
|
|
791
|
+
if isinstance(skills_list, list):
|
|
792
|
+
skipped_count += len(skills_list)
|
|
793
|
+
|
|
794
|
+
self.logger.warning(
|
|
795
|
+
f"Unknown categories in manifest will be skipped: "
|
|
796
|
+
f"{', '.join(sorted(unknown_categories))} ({skipped_count} skills)"
|
|
797
|
+
)
|
|
798
|
+
self.logger.info(
|
|
799
|
+
f"Valid top-level categories: {', '.join(sorted(VALID_CATEGORIES))}"
|
|
800
|
+
)
|
|
801
|
+
|
|
703
802
|
# Add universal skills
|
|
704
803
|
universal_skills = skills_data.get("universal", [])
|
|
705
804
|
if isinstance(universal_skills, list):
|
|
@@ -804,55 +903,76 @@ class SkillsDeployerService(LoggerMixin):
|
|
|
804
903
|
Dict with deployed, skipped, error flags
|
|
805
904
|
"""
|
|
806
905
|
skill_name = skill["name"]
|
|
807
|
-
|
|
906
|
+
|
|
907
|
+
# Use normalized source_path for both target directory and deployment tracking
|
|
908
|
+
# This ensures consistency with configuration.yaml skill names
|
|
909
|
+
source_path = skill.get("source_path", "")
|
|
910
|
+
if source_path:
|
|
911
|
+
# Normalize: "universal/web/api-design-patterns/SKILL.md" -> "universal-web-api-design-patterns"
|
|
912
|
+
normalized_name = source_path.replace("/SKILL.md", "").replace("/", "-")
|
|
913
|
+
target_dir = self.CLAUDE_SKILLS_DIR / normalized_name
|
|
914
|
+
else:
|
|
915
|
+
# Fallback to skill name if no source_path
|
|
916
|
+
target_dir = self.CLAUDE_SKILLS_DIR / skill_name
|
|
808
917
|
|
|
809
918
|
# Check if already deployed
|
|
810
919
|
if target_dir.exists() and not force:
|
|
811
920
|
self.logger.debug(f"Skipped {skill_name} (already deployed)")
|
|
812
921
|
return {"deployed": False, "skipped": True, "error": None}
|
|
813
922
|
|
|
814
|
-
# Find skill source
|
|
815
|
-
|
|
816
|
-
# OR: collection_dir / universal / skill-name
|
|
817
|
-
# OR: collection_dir / toolchains / toolchain-name / skill-name
|
|
923
|
+
# Find skill source using source_path from manifest
|
|
924
|
+
source_dir = None
|
|
818
925
|
|
|
819
|
-
|
|
820
|
-
|
|
926
|
+
if source_path:
|
|
927
|
+
# Direct lookup using source_path (most reliable)
|
|
928
|
+
# Example: "universal/web/api-design-patterns/SKILL.md" -> "universal/web/api-design-patterns"
|
|
929
|
+
skill_dir_path = source_path.replace("/SKILL.md", "")
|
|
930
|
+
potential_source = collection_dir / skill_dir_path
|
|
931
|
+
if potential_source.exists():
|
|
932
|
+
source_dir = potential_source
|
|
933
|
+
else:
|
|
934
|
+
self.logger.debug(
|
|
935
|
+
f"Source path {skill_dir_path} not found, trying fallback search"
|
|
936
|
+
)
|
|
821
937
|
|
|
822
|
-
#
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
search_paths
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
for cat_dir in skills_base.iterdir():
|
|
849
|
-
if not cat_dir.is_dir():
|
|
850
|
-
continue
|
|
851
|
-
potential = cat_dir / skill_name
|
|
852
|
-
if potential.exists():
|
|
853
|
-
source_dir = potential
|
|
938
|
+
# Fallback: search using old logic (for backward compatibility)
|
|
939
|
+
if not source_dir:
|
|
940
|
+
skills_base = collection_dir / "skills"
|
|
941
|
+
category = skill.get("category", "")
|
|
942
|
+
|
|
943
|
+
# Try multiple possible locations
|
|
944
|
+
search_paths = []
|
|
945
|
+
|
|
946
|
+
# Try category-based path
|
|
947
|
+
if category and skills_base.exists():
|
|
948
|
+
search_paths.append(skills_base / category / skill_name)
|
|
949
|
+
|
|
950
|
+
# Try universal/toolchains structure
|
|
951
|
+
if (collection_dir / "universal").exists():
|
|
952
|
+
search_paths.append(collection_dir / "universal" / skill_name)
|
|
953
|
+
|
|
954
|
+
if (collection_dir / "toolchains").exists():
|
|
955
|
+
toolchain_dir = collection_dir / "toolchains"
|
|
956
|
+
for tc in toolchain_dir.iterdir():
|
|
957
|
+
if tc.is_dir():
|
|
958
|
+
search_paths.append(tc / skill_name)
|
|
959
|
+
|
|
960
|
+
# Search in all possible locations
|
|
961
|
+
for path in search_paths:
|
|
962
|
+
if path.exists():
|
|
963
|
+
source_dir = path
|
|
854
964
|
break
|
|
855
965
|
|
|
966
|
+
# Final fallback: search recursively for skill in skills directory
|
|
967
|
+
if not source_dir and skills_base.exists():
|
|
968
|
+
for cat_dir in skills_base.iterdir():
|
|
969
|
+
if not cat_dir.is_dir():
|
|
970
|
+
continue
|
|
971
|
+
potential = cat_dir / skill_name
|
|
972
|
+
if potential.exists():
|
|
973
|
+
source_dir = potential
|
|
974
|
+
break
|
|
975
|
+
|
|
856
976
|
if not source_dir or not source_dir.exists():
|
|
857
977
|
return {
|
|
858
978
|
"deployed": False,
|
|
@@ -887,12 +1007,14 @@ class SkillsDeployerService(LoggerMixin):
|
|
|
887
1007
|
# NOTE: We use copy instead of symlink to maintain Claude Code compatibility
|
|
888
1008
|
shutil.copytree(source_dir, target_dir)
|
|
889
1009
|
|
|
890
|
-
# Track deployment in index
|
|
1010
|
+
# Track deployment in index using normalized name
|
|
891
1011
|
from claude_mpm.services.skills.selective_skill_deployer import (
|
|
892
1012
|
track_deployed_skill,
|
|
893
1013
|
)
|
|
894
1014
|
|
|
895
|
-
|
|
1015
|
+
# Use normalized name for tracking (matches configuration.yaml format)
|
|
1016
|
+
track_name = normalized_name if source_path else skill_name
|
|
1017
|
+
track_deployed_skill(self.CLAUDE_SKILLS_DIR, track_name, collection_name)
|
|
896
1018
|
|
|
897
1019
|
self.logger.debug(
|
|
898
1020
|
f"Deployed {skill_name} from {source_dir} to {target_dir}"
|
|
@@ -926,12 +1048,12 @@ class SkillsDeployerService(LoggerMixin):
|
|
|
926
1048
|
"""
|
|
927
1049
|
try:
|
|
928
1050
|
if platform.system() == "Windows":
|
|
929
|
-
result = subprocess.run(
|
|
1051
|
+
result = subprocess.run( # nosec B603 B607 - Safe: hardcoded tasklist command
|
|
930
1052
|
["tasklist"], check=False, capture_output=True, text=True, timeout=5
|
|
931
1053
|
)
|
|
932
1054
|
return "claude" in result.stdout.lower()
|
|
933
1055
|
# macOS and Linux
|
|
934
|
-
result = subprocess.run(
|
|
1056
|
+
result = subprocess.run( # nosec B603 B607 - Safe: hardcoded ps command
|
|
935
1057
|
["ps", "aux"], check=False, capture_output=True, text=True, timeout=5
|
|
936
1058
|
)
|
|
937
1059
|
# Look for "Claude Code" or "claude-code" process
|
|
@@ -152,6 +152,7 @@ class DashboardServer(SocketIOServiceInterface):
|
|
|
152
152
|
|
|
153
153
|
# Register handlers for all events we want to relay from monitor to dashboard
|
|
154
154
|
relay_events = [
|
|
155
|
+
"claude_event", # Tool events from Claude Code hooks
|
|
155
156
|
"session_started",
|
|
156
157
|
"session_ended",
|
|
157
158
|
"claude_status",
|
|
@@ -6,7 +6,7 @@ This normalizer ensures all events follow a consistent schema before broadcastin
|
|
|
6
6
|
providing backward compatibility while establishing a standard format.
|
|
7
7
|
|
|
8
8
|
DESIGN DECISION: Transform all events to a consistent schema:
|
|
9
|
-
- event: Socket.IO event name (always "
|
|
9
|
+
- event: Socket.IO event name (always "mpm_event")
|
|
10
10
|
- type: Main category (hook, system, session, file, connection)
|
|
11
11
|
- subtype: Specific event type (pre_tool, heartbeat, started, etc.)
|
|
12
12
|
- timestamp: ISO format timestamp
|
|
@@ -72,7 +72,7 @@ class NormalizedEvent:
|
|
|
72
72
|
structure explicit and self-documenting.
|
|
73
73
|
"""
|
|
74
74
|
|
|
75
|
-
event: str = "
|
|
75
|
+
event: str = "mpm_event" # Socket.IO event name
|
|
76
76
|
source: str = "" # WHERE the event comes from
|
|
77
77
|
type: str = "" # WHAT category of event
|
|
78
78
|
subtype: str = "" # Specific event type
|
|
@@ -81,6 +81,8 @@ class NormalizedEvent:
|
|
|
81
81
|
correlation_id: Optional[str] = (
|
|
82
82
|
None # For correlating related events (e.g., pre_tool/post_tool)
|
|
83
83
|
)
|
|
84
|
+
session_id: Optional[str] = None # Session identifier for stream grouping
|
|
85
|
+
cwd: Optional[str] = None # Working directory for project identification
|
|
84
86
|
|
|
85
87
|
def to_dict(self) -> Dict[str, Any]:
|
|
86
88
|
"""Convert to dictionary for emission."""
|
|
@@ -95,6 +97,12 @@ class NormalizedEvent:
|
|
|
95
97
|
# Include correlation_id if present
|
|
96
98
|
if self.correlation_id:
|
|
97
99
|
result["correlation_id"] = self.correlation_id
|
|
100
|
+
# Include session_id if present
|
|
101
|
+
if self.session_id:
|
|
102
|
+
result["session_id"] = self.session_id
|
|
103
|
+
# Include cwd if present
|
|
104
|
+
if self.cwd:
|
|
105
|
+
result["cwd"] = self.cwd
|
|
98
106
|
return result
|
|
99
107
|
|
|
100
108
|
|
|
@@ -113,6 +121,7 @@ class EventNormalizer:
|
|
|
113
121
|
"pre_response": (EventType.HOOK, "pre_response"),
|
|
114
122
|
"post_response": (EventType.HOOK, "post_response"),
|
|
115
123
|
"hook_event": (EventType.HOOK, "generic"),
|
|
124
|
+
"hook_execution": (EventType.HOOK, "execution"), # Hook execution metadata
|
|
116
125
|
"UserPrompt": (EventType.HOOK, "user_prompt"), # Legacy format
|
|
117
126
|
# Test events (legacy format)
|
|
118
127
|
"TestStart": (EventType.TEST, "start"),
|
|
@@ -225,20 +234,32 @@ class EventNormalizer:
|
|
|
225
234
|
# Get or generate timestamp
|
|
226
235
|
timestamp = self._extract_timestamp(event_data)
|
|
227
236
|
|
|
228
|
-
# Extract correlation_id if present
|
|
237
|
+
# Extract correlation_id, session_id, and cwd if present
|
|
229
238
|
correlation_id = None
|
|
239
|
+
session_id = None
|
|
240
|
+
cwd = None
|
|
230
241
|
if isinstance(event_data, dict):
|
|
231
242
|
correlation_id = event_data.get("correlation_id")
|
|
243
|
+
# Try both naming conventions for session_id
|
|
244
|
+
session_id = event_data.get("session_id") or event_data.get("sessionId")
|
|
245
|
+
# Try multiple field names for working directory
|
|
246
|
+
cwd = (
|
|
247
|
+
event_data.get("cwd")
|
|
248
|
+
or event_data.get("working_directory")
|
|
249
|
+
or event_data.get("workingDirectory")
|
|
250
|
+
)
|
|
232
251
|
|
|
233
252
|
# Create normalized event
|
|
234
253
|
normalized = NormalizedEvent(
|
|
235
|
-
event="
|
|
254
|
+
event="mpm_event",
|
|
236
255
|
source=event_source,
|
|
237
256
|
type=event_type,
|
|
238
257
|
subtype=subtype,
|
|
239
258
|
timestamp=timestamp,
|
|
240
259
|
data=data,
|
|
241
260
|
correlation_id=correlation_id,
|
|
261
|
+
session_id=session_id,
|
|
262
|
+
cwd=cwd,
|
|
242
263
|
)
|
|
243
264
|
|
|
244
265
|
self.stats["normalized"] += 1
|
|
@@ -252,7 +273,7 @@ class EventNormalizer:
|
|
|
252
273
|
|
|
253
274
|
# Return a generic event on error
|
|
254
275
|
return NormalizedEvent(
|
|
255
|
-
event="
|
|
276
|
+
event="mpm_event",
|
|
256
277
|
source="system",
|
|
257
278
|
type="unknown",
|
|
258
279
|
subtype="error",
|
|
@@ -285,8 +306,16 @@ class EventNormalizer:
|
|
|
285
306
|
# If source is not a valid EventSource value, keep it as-is
|
|
286
307
|
pass
|
|
287
308
|
|
|
309
|
+
# Extract session_id and cwd, trying multiple naming conventions
|
|
310
|
+
session_id = event_data.get("session_id") or event_data.get("sessionId")
|
|
311
|
+
cwd = (
|
|
312
|
+
event_data.get("cwd")
|
|
313
|
+
or event_data.get("working_directory")
|
|
314
|
+
or event_data.get("workingDirectory")
|
|
315
|
+
)
|
|
316
|
+
|
|
288
317
|
return NormalizedEvent(
|
|
289
|
-
event="
|
|
318
|
+
event="mpm_event", # Always use standard event name
|
|
290
319
|
source=source,
|
|
291
320
|
type=event_data.get("type", "unknown"),
|
|
292
321
|
subtype=event_data.get("subtype", "generic"),
|
|
@@ -295,6 +324,8 @@ class EventNormalizer:
|
|
|
295
324
|
),
|
|
296
325
|
data=event_data.get("data", {}),
|
|
297
326
|
correlation_id=event_data.get("correlation_id"),
|
|
327
|
+
session_id=session_id,
|
|
328
|
+
cwd=cwd,
|
|
298
329
|
)
|
|
299
330
|
|
|
300
331
|
def _extract_event_info(self, event_data: Any) -> Tuple[str, str, Dict[str, Any]]:
|
|
@@ -118,7 +118,8 @@ class HookEventHandler(BaseEventHandler):
|
|
|
118
118
|
self.server.active_sessions[session_id] = {
|
|
119
119
|
"session_id": session_id,
|
|
120
120
|
"start_time": datetime.now(timezone.utc).isoformat(),
|
|
121
|
-
"
|
|
121
|
+
"current_agent": agent_type, # Current active agent
|
|
122
|
+
"agents": [agent_type], # All agents used in this session
|
|
122
123
|
"status": ServiceState.RUNNING,
|
|
123
124
|
"prompt": data.get("prompt", "")[:100], # First 100 chars
|
|
124
125
|
"last_activity": datetime.now(timezone.utc).isoformat(),
|
|
@@ -169,7 +170,8 @@ class HookEventHandler(BaseEventHandler):
|
|
|
169
170
|
self.server.active_sessions[session_id] = {
|
|
170
171
|
"session_id": session_id,
|
|
171
172
|
"start_time": datetime.now(timezone.utc).isoformat(),
|
|
172
|
-
"
|
|
173
|
+
"current_agent": "pm", # Current active agent
|
|
174
|
+
"agents": ["pm"], # All agents used in this session
|
|
173
175
|
"status": ServiceState.RUNNING,
|
|
174
176
|
"prompt": data.get("prompt_text", "")[:100],
|
|
175
177
|
"working_directory": data.get("working_directory", ""),
|
|
@@ -200,11 +202,16 @@ class HookEventHandler(BaseEventHandler):
|
|
|
200
202
|
# Update session with new agent
|
|
201
203
|
if hasattr(self.server, "active_sessions"):
|
|
202
204
|
if session_id in self.server.active_sessions:
|
|
203
|
-
self.server.active_sessions[session_id]
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
205
|
+
session = self.server.active_sessions[session_id]
|
|
206
|
+
session["current_agent"] = agent_type
|
|
207
|
+
session["status"] = "delegated"
|
|
208
|
+
session["last_activity"] = datetime.now(timezone.utc).isoformat()
|
|
209
|
+
|
|
210
|
+
# Add to agents list if not already present
|
|
211
|
+
if "agents" not in session:
|
|
212
|
+
session["agents"] = []
|
|
213
|
+
if agent_type not in session["agents"]:
|
|
214
|
+
session["agents"].append(agent_type)
|
|
208
215
|
|
|
209
216
|
self.logger.debug(
|
|
210
217
|
f"Updated session delegation: session={session_id[:8]}..., agent={agent_type}"
|