claude-mpm 5.4.14__py3-none-any.whl → 5.4.36__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_TEACHER_OUTPUT_STYLE.md +1 -1
- claude_mpm/agents/MEMORY.md +1 -1
- claude_mpm/agents/PM_INSTRUCTIONS.md +363 -817
- claude_mpm/agents/WORKFLOW.md +5 -254
- claude_mpm/agents/agent_loader.py +1 -1
- claude_mpm/agents/base_agent.json +31 -0
- claude_mpm/cli/chrome_devtools_installer.py +175 -0
- claude_mpm/cli/commands/agent_state_manager.py +10 -10
- claude_mpm/cli/commands/agents.py +9 -40
- claude_mpm/cli/commands/auto_configure.py +4 -4
- claude_mpm/cli/commands/configure.py +1 -1
- claude_mpm/cli/commands/postmortem.py +1 -1
- claude_mpm/cli/commands/skills.py +193 -187
- claude_mpm/cli/interactive/agent_wizard.py +2 -2
- claude_mpm/cli/parsers/agents_parser.py +0 -9
- claude_mpm/cli/parsers/auto_configure_parser.py +0 -138
- claude_mpm/cli/startup.py +330 -78
- claude_mpm/commands/mpm-config.md +1 -2
- claude_mpm/commands/mpm-help.md +14 -95
- claude_mpm/commands/mpm-organize.md +350 -153
- claude_mpm/core/config.py +2 -4
- claude_mpm/core/framework/loaders/agent_loader.py +1 -1
- claude_mpm/core/framework/loaders/instruction_loader.py +52 -11
- claude_mpm/core/unified_agent_registry.py +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/env.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.B_FtCwCQ.css +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.Cl_eSA4x.css +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BgChzWQ1.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CIXEwuWe.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CWc5urbQ.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DMkZpdF2.js +2 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DjhvlsAc.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/N4qtv3Hx.js +2 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/uj46x2Wr.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/app.DTL5mJO-.js +2 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.DzuEhzqh.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/0.CAGBuiOw.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/1.DFLC8jdE.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.DPvEihJJ.js +10 -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/hooks/claude_hooks/__pycache__/__init__.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__/installer.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/event_handlers.py +5 -0
- claude_mpm/hooks/claude_hooks/hook_handler.py +149 -1
- claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager.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 +26 -6
- claude_mpm/models/git_repository.py +3 -3
- claude_mpm/scripts/start_activity_logging.py +0 -0
- claude_mpm/services/agents/cache_git_manager.py +6 -6
- claude_mpm/services/agents/deployment/agent_deployment.py +7 -7
- claude_mpm/services/agents/deployment/agent_discovery_service.py +2 -2
- claude_mpm/services/agents/deployment/agent_template_builder.py +2 -2
- claude_mpm/services/agents/deployment/agents_directory_resolver.py +2 -2
- claude_mpm/services/agents/deployment/multi_source_deployment_service.py +20 -22
- claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +55 -53
- claude_mpm/services/agents/git_source_manager.py +2 -2
- claude_mpm/services/agents/recommender.py +5 -3
- claude_mpm/services/agents/single_tier_deployment_service.py +2 -2
- claude_mpm/services/agents/sources/git_source_sync_service.py +5 -5
- claude_mpm/services/agents/startup_sync.py +22 -2
- claude_mpm/services/command_deployment_service.py +10 -0
- claude_mpm/services/diagnostics/checks/agent_check.py +2 -2
- claude_mpm/services/diagnostics/checks/agent_sources_check.py +1 -1
- claude_mpm/services/git/git_operations_service.py +8 -8
- claude_mpm/services/monitor/server.py +473 -3
- claude_mpm/services/skills/selective_skill_deployer.py +475 -1
- claude_mpm/services/skills_deployer.py +62 -6
- claude_mpm/services/socketio/dashboard_server.py +1 -0
- claude_mpm/services/socketio/event_normalizer.py +37 -6
- claude_mpm/services/socketio/server/core.py +262 -123
- claude_mpm/utils/agent_dependency_loader.py +14 -2
- claude_mpm/utils/agent_filters.py +1 -1
- claude_mpm/utils/migration.py +4 -4
- claude_mpm/utils/robust_installer.py +47 -3
- {claude_mpm-5.4.14.dist-info → claude_mpm-5.4.36.dist-info}/METADATA +5 -3
- {claude_mpm-5.4.14.dist-info → claude_mpm-5.4.36.dist-info}/RECORD +96 -66
- claude_mpm/cli/commands/agents_detect.py +0 -380
- claude_mpm/cli/commands/agents_recommend.py +0 -309
- 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-5.4.14.dist-info → claude_mpm-5.4.36.dist-info}/WHEEL +0 -0
- {claude_mpm-5.4.14.dist-info → claude_mpm-5.4.36.dist-info}/entry_points.txt +0 -0
- {claude_mpm-5.4.14.dist-info → claude_mpm-5.4.36.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-5.4.14.dist-info → claude_mpm-5.4.36.dist-info}/licenses/LICENSE-FAQ.md +0 -0
- {claude_mpm-5.4.14.dist-info → claude_mpm-5.4.36.dist-info}/top_level.txt +0 -0
claude_mpm/cli/startup.py
CHANGED
|
@@ -10,7 +10,6 @@ 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
|
|
|
@@ -61,42 +60,11 @@ def sync_hooks_on_startup(quiet: bool = False) -> bool:
|
|
|
61
60
|
|
|
62
61
|
|
|
63
62
|
def check_legacy_cache() -> None:
|
|
64
|
-
"""
|
|
63
|
+
"""Deprecated: Legacy cache checking is no longer needed.
|
|
65
64
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
with 26 active code references, while cache/agents/ has only 7 legacy references.
|
|
69
|
-
|
|
70
|
-
DESIGN DECISIONS:
|
|
71
|
-
- Non-blocking warning: Doesn't stop execution, just informs user
|
|
72
|
-
- Migration guidance: Provides clear path to migrate
|
|
73
|
-
- One-time check: Only warns if legacy cache contains files
|
|
65
|
+
This function is kept for backward compatibility but does nothing.
|
|
66
|
+
All agent cache operations now use the standardized cache/agents/ directory.
|
|
74
67
|
"""
|
|
75
|
-
home = Path.home()
|
|
76
|
-
legacy_cache = home / ".claude-mpm" / "cache" / "agents"
|
|
77
|
-
canonical_cache = home / ".claude-mpm" / "cache" / "remote-agents"
|
|
78
|
-
migration_marker = home / ".claude-mpm" / "cache" / ".migrated_to_remote_agents"
|
|
79
|
-
|
|
80
|
-
# Skip if already migrated or no legacy cache
|
|
81
|
-
if migration_marker.exists() or not legacy_cache.exists():
|
|
82
|
-
return
|
|
83
|
-
|
|
84
|
-
# Check if legacy cache has actual agent files
|
|
85
|
-
legacy_files = list(legacy_cache.glob("*.md")) + list(legacy_cache.glob("*.json"))
|
|
86
|
-
if not legacy_files:
|
|
87
|
-
return
|
|
88
|
-
|
|
89
|
-
# Only warn if canonical cache doesn't exist (indicating unmigrated system)
|
|
90
|
-
if not canonical_cache.exists():
|
|
91
|
-
warnings.warn(
|
|
92
|
-
f"\n⚠️ DEPRECATION: Legacy cache directory detected\n"
|
|
93
|
-
f" Location: {legacy_cache}\n"
|
|
94
|
-
f" Files found: {len(legacy_files)}\n\n"
|
|
95
|
-
f"The 'cache/agents/' directory is deprecated. Please migrate to 'cache/remote-agents/'.\n"
|
|
96
|
-
f"Run: python scripts/migrate_cache_to_remote_agents.py\n",
|
|
97
|
-
DeprecationWarning,
|
|
98
|
-
stacklevel=2,
|
|
99
|
-
)
|
|
100
68
|
|
|
101
69
|
|
|
102
70
|
def setup_early_environment(argv):
|
|
@@ -476,13 +444,76 @@ def sync_remote_agents_on_startup():
|
|
|
476
444
|
# Count agents in cache to show accurate progress
|
|
477
445
|
from pathlib import Path
|
|
478
446
|
|
|
479
|
-
cache_dir = Path.home() / ".claude-mpm" / "cache" / "
|
|
447
|
+
cache_dir = Path.home() / ".claude-mpm" / "cache" / "agents"
|
|
480
448
|
agent_count = 0
|
|
481
449
|
|
|
482
450
|
if cache_dir.exists():
|
|
483
|
-
#
|
|
484
|
-
#
|
|
485
|
-
#
|
|
451
|
+
# BUGFIX (cache-count-inflation): Clean up stale cache files
|
|
452
|
+
# from old repositories before counting to prevent inflated counts.
|
|
453
|
+
# Issue: Old caches like bobmatnyc/claude-mpm-agents/agents/
|
|
454
|
+
# were counted alongside current agents, inflating count
|
|
455
|
+
# from 44 to 85.
|
|
456
|
+
#
|
|
457
|
+
# Solution: Remove files with nested /agents/ paths
|
|
458
|
+
# (e.g., cache/agents/user/repo/agents/...)
|
|
459
|
+
# Keep only current agents (e.g., cache/agents/engineer/...)
|
|
460
|
+
removed_count = 0
|
|
461
|
+
stale_dirs = set()
|
|
462
|
+
|
|
463
|
+
for md_file in cache_dir.rglob("*.md"):
|
|
464
|
+
# Stale cache files have multiple /agents/ in their path
|
|
465
|
+
# Current: ~/.claude-mpm/cache/agents/engineer/...
|
|
466
|
+
# (1 occurrence)
|
|
467
|
+
# Old: ~/.claude-mpm/cache/agents/bobmatnyc/.../agents/...
|
|
468
|
+
# (2+ occurrences)
|
|
469
|
+
if str(md_file).count("/agents/") > 1:
|
|
470
|
+
# Track parent directory for cleanup
|
|
471
|
+
# Extract subdirectory under cache/agents/
|
|
472
|
+
# (e.g., "bobmatnyc")
|
|
473
|
+
parts = md_file.parts
|
|
474
|
+
cache_agents_idx = parts.index("agents")
|
|
475
|
+
if cache_agents_idx + 1 < len(parts):
|
|
476
|
+
stale_subdir = parts[cache_agents_idx + 1]
|
|
477
|
+
# Only remove if it's not a known category directory
|
|
478
|
+
if stale_subdir not in [
|
|
479
|
+
"engineer",
|
|
480
|
+
"ops",
|
|
481
|
+
"qa",
|
|
482
|
+
"universal",
|
|
483
|
+
"documentation",
|
|
484
|
+
"claude-mpm",
|
|
485
|
+
"security",
|
|
486
|
+
]:
|
|
487
|
+
stale_dirs.add(cache_dir / stale_subdir)
|
|
488
|
+
|
|
489
|
+
md_file.unlink()
|
|
490
|
+
removed_count += 1
|
|
491
|
+
|
|
492
|
+
# Remove empty stale directories
|
|
493
|
+
for stale_dir in stale_dirs:
|
|
494
|
+
if stale_dir.exists() and stale_dir.is_dir():
|
|
495
|
+
try:
|
|
496
|
+
# Remove directory and all contents
|
|
497
|
+
import shutil
|
|
498
|
+
|
|
499
|
+
shutil.rmtree(stale_dir)
|
|
500
|
+
except Exception:
|
|
501
|
+
pass # Ignore cleanup errors
|
|
502
|
+
|
|
503
|
+
if removed_count > 0:
|
|
504
|
+
from loguru import logger
|
|
505
|
+
|
|
506
|
+
logger.info(
|
|
507
|
+
f"Cleaned up {removed_count} stale cache files "
|
|
508
|
+
f"from old repositories"
|
|
509
|
+
)
|
|
510
|
+
|
|
511
|
+
# Count MD files in cache (agent markdown files from
|
|
512
|
+
# current repos)
|
|
513
|
+
# BUGFIX: Only count files in agent directories,
|
|
514
|
+
# not docs/templates/READMEs
|
|
515
|
+
# Valid agent paths must contain "/agents/" exactly ONCE
|
|
516
|
+
# (current structure)
|
|
486
517
|
# Exclude PM templates, BASE-AGENT, and documentation files
|
|
487
518
|
pm_templates = {
|
|
488
519
|
"base-agent.md",
|
|
@@ -505,25 +536,34 @@ def sync_remote_agents_on_startup():
|
|
|
505
536
|
"auto-deploy-index.md",
|
|
506
537
|
}
|
|
507
538
|
|
|
508
|
-
# Find all markdown files
|
|
539
|
+
# Find all markdown files (after cleanup)
|
|
509
540
|
all_md_files = list(cache_dir.rglob("*.md"))
|
|
510
541
|
|
|
511
542
|
# Filter to only agent files:
|
|
512
|
-
# 1. Must have "/agents/" in path
|
|
543
|
+
# 1. Must have "/agents/" in path exactly ONCE
|
|
544
|
+
# (current structure)
|
|
513
545
|
# 2. Must not be in PM templates or doc files
|
|
514
546
|
# 3. Exclude BASE-AGENT.md which is not a deployable agent
|
|
515
|
-
# 4. Exclude build artifacts (dist/, build/, .cache/)
|
|
547
|
+
# 4. Exclude build artifacts (dist/, build/, .cache/)
|
|
548
|
+
# to prevent double-counting
|
|
516
549
|
agent_files = [
|
|
517
550
|
f
|
|
518
551
|
for f in all_md_files
|
|
519
552
|
if (
|
|
520
|
-
# Must be in an agent directory (from
|
|
553
|
+
# Must be in an agent directory (from current
|
|
554
|
+
# cache structure)
|
|
521
555
|
"/agents/" in str(f)
|
|
556
|
+
# NEW: Only ONE /agents/ in path (excludes old
|
|
557
|
+
# nested repos)
|
|
558
|
+
# This prevents counting old caches like
|
|
559
|
+
# bobmatnyc/claude-mpm-agents/agents/...
|
|
560
|
+
and str(f).count("/agents/") == 1
|
|
522
561
|
# Exclude PM templates, doc files, and BASE-AGENT
|
|
523
562
|
and f.name.lower() not in pm_templates
|
|
524
563
|
and f.name.lower() not in doc_files
|
|
525
564
|
and f.name.lower() != "base-agent.md"
|
|
526
|
-
# Exclude build artifacts (prevents double-counting
|
|
565
|
+
# Exclude build artifacts (prevents double-counting
|
|
566
|
+
# source + built files)
|
|
527
567
|
and not any(
|
|
528
568
|
part in str(f).split("/")
|
|
529
569
|
for part in ["dist", "build", ".cache"]
|
|
@@ -594,27 +634,27 @@ def sync_remote_agents_on_startup():
|
|
|
594
634
|
)
|
|
595
635
|
|
|
596
636
|
# Show total configured agents (deployed + updated + already existing)
|
|
597
|
-
# Include
|
|
637
|
+
# Include cache count for context and removed count if any
|
|
598
638
|
if deployed > 0 or updated > 0:
|
|
599
639
|
if removed > 0:
|
|
600
640
|
deploy_progress.finish(
|
|
601
641
|
f"Complete: {deployed} new, {updated} updated, {skipped} unchanged, "
|
|
602
|
-
f"{removed} removed ({total_configured} configured from {agent_count} in
|
|
642
|
+
f"{removed} removed ({total_configured} configured from {agent_count} files in cache)"
|
|
603
643
|
)
|
|
604
644
|
else:
|
|
605
645
|
deploy_progress.finish(
|
|
606
646
|
f"Complete: {deployed} new, {updated} updated, {skipped} unchanged "
|
|
607
|
-
f"({total_configured} configured from {agent_count} in
|
|
647
|
+
f"({total_configured} configured from {agent_count} files in cache)"
|
|
608
648
|
)
|
|
609
649
|
elif removed > 0:
|
|
610
650
|
deploy_progress.finish(
|
|
611
|
-
f"Complete: {total_configured} agents
|
|
612
|
-
f"{removed} removed ({agent_count}
|
|
651
|
+
f"Complete: {total_configured} agents deployed, "
|
|
652
|
+
f"{removed} removed ({agent_count} files in cache)"
|
|
613
653
|
)
|
|
614
654
|
else:
|
|
615
655
|
deploy_progress.finish(
|
|
616
|
-
f"Complete: {total_configured} agents
|
|
617
|
-
f"({agent_count}
|
|
656
|
+
f"Complete: {total_configured} agents deployed "
|
|
657
|
+
f"({agent_count} files in cache)"
|
|
618
658
|
)
|
|
619
659
|
|
|
620
660
|
# Display deployment errors to user (not just logs)
|
|
@@ -677,14 +717,21 @@ def sync_remote_skills_on_startup():
|
|
|
677
717
|
|
|
678
718
|
Workflow:
|
|
679
719
|
1. Sync all enabled Git sources (download/cache files) - Phase 1 progress bar
|
|
680
|
-
2.
|
|
681
|
-
3.
|
|
720
|
+
2. Scan deployed agents for skill requirements → save to configuration.yaml
|
|
721
|
+
3. Resolve which skills to deploy (user_defined vs agent_referenced)
|
|
722
|
+
4. Deploy resolved skills to ~/.claude/skills/ - Phase 2 progress bar
|
|
723
|
+
5. Log deployment results with source indication
|
|
682
724
|
"""
|
|
683
725
|
try:
|
|
684
726
|
from pathlib import Path
|
|
685
727
|
|
|
686
728
|
from ..config.skill_sources import SkillSourceConfiguration
|
|
687
729
|
from ..services.skills.git_skill_source_manager import GitSkillSourceManager
|
|
730
|
+
from ..services.skills.selective_skill_deployer import (
|
|
731
|
+
get_required_skills_from_agents,
|
|
732
|
+
get_skills_to_deploy,
|
|
733
|
+
save_agent_skills_to_config,
|
|
734
|
+
)
|
|
688
735
|
from ..utils.progress import ProgressBar
|
|
689
736
|
|
|
690
737
|
config = SkillSourceConfiguration()
|
|
@@ -773,37 +820,37 @@ def sync_remote_skills_on_startup():
|
|
|
773
820
|
f"Complete: {downloaded} files downloaded ({total_skill_dirs} skills)"
|
|
774
821
|
)
|
|
775
822
|
|
|
776
|
-
# Phase 2:
|
|
777
|
-
# This
|
|
778
|
-
# into flat deployment (e.g., collaboration-dispatching-parallel-agents/SKILL.md)
|
|
823
|
+
# Phase 2: Scan agents and save to configuration.yaml
|
|
824
|
+
# This step populates configuration.yaml with agent-referenced skills
|
|
779
825
|
if results["synced_count"] > 0:
|
|
780
|
-
# Get required skills from deployed agents (selective deployment)
|
|
781
|
-
from ..services.skills.selective_skill_deployer import (
|
|
782
|
-
get_required_skills_from_agents,
|
|
783
|
-
)
|
|
784
|
-
|
|
785
826
|
agents_dir = Path.cwd() / ".claude" / "agents"
|
|
786
|
-
|
|
827
|
+
|
|
828
|
+
# Scan agents for skill requirements
|
|
829
|
+
agent_skills = get_required_skills_from_agents(agents_dir)
|
|
830
|
+
|
|
831
|
+
# Save to project-level configuration.yaml
|
|
832
|
+
project_config_path = Path.cwd() / ".claude-mpm" / "configuration.yaml"
|
|
833
|
+
save_agent_skills_to_config(list(agent_skills), project_config_path)
|
|
834
|
+
|
|
835
|
+
# Phase 3: Resolve which skills to deploy (user_defined or agent_referenced)
|
|
836
|
+
skills_to_deploy, skill_source = get_skills_to_deploy(project_config_path)
|
|
787
837
|
|
|
788
838
|
# Get all skills to determine counts
|
|
789
839
|
all_skills = manager.get_all_skills()
|
|
790
840
|
total_skill_count = len(all_skills)
|
|
791
841
|
|
|
792
|
-
# Determine skill count based on
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
else:
|
|
797
|
-
# No agent requirements found - deploy all skills
|
|
798
|
-
skill_count = total_skill_count
|
|
842
|
+
# Determine skill count based on resolution
|
|
843
|
+
skill_count = (
|
|
844
|
+
len(skills_to_deploy) if skills_to_deploy else total_skill_count
|
|
845
|
+
)
|
|
799
846
|
|
|
800
847
|
if skill_count > 0:
|
|
801
|
-
# Deploy skills with
|
|
848
|
+
# Deploy skills with resolved filter
|
|
802
849
|
# Deploy to project directory (like agents), not user directory
|
|
803
850
|
deployment_result = manager.deploy_skills(
|
|
804
851
|
target_dir=Path.cwd() / ".claude" / "skills",
|
|
805
852
|
force=False,
|
|
806
|
-
skill_filter=
|
|
853
|
+
skill_filter=set(skills_to_deploy) if skills_to_deploy else None,
|
|
807
854
|
)
|
|
808
855
|
|
|
809
856
|
# Get actual counts from deployment result
|
|
@@ -833,28 +880,32 @@ def sync_remote_skills_on_startup():
|
|
|
833
880
|
deploy_progress.update(1)
|
|
834
881
|
|
|
835
882
|
# Show total available skills (deployed + already existing)
|
|
836
|
-
# Include
|
|
837
|
-
# Note: total_skill_count is from
|
|
883
|
+
# Include source indication (user_defined vs agent_referenced)
|
|
884
|
+
# Note: total_skill_count is from cache, total_available is what's deployed/needed
|
|
885
|
+
source_label = (
|
|
886
|
+
"user override" if skill_source == "user_defined" else "from agents"
|
|
887
|
+
)
|
|
888
|
+
|
|
838
889
|
if deployed > 0:
|
|
839
890
|
if filtered > 0:
|
|
840
891
|
deploy_progress.finish(
|
|
841
892
|
f"Complete: {deployed} new, {skipped} unchanged "
|
|
842
|
-
f"({total_available}
|
|
893
|
+
f"({total_available} {source_label}, {filtered} files in cache)"
|
|
843
894
|
)
|
|
844
895
|
else:
|
|
845
896
|
deploy_progress.finish(
|
|
846
897
|
f"Complete: {deployed} new, {skipped} unchanged "
|
|
847
|
-
f"({total_available} skills
|
|
898
|
+
f"({total_available} skills {source_label} from {total_skill_count} files in cache)"
|
|
848
899
|
)
|
|
849
900
|
elif filtered > 0:
|
|
850
901
|
# Skills filtered means agents require fewer skills than available
|
|
851
902
|
deploy_progress.finish(
|
|
852
|
-
f"
|
|
903
|
+
f"No skills needed ({source_label}, {total_skill_count} files in cache)"
|
|
853
904
|
)
|
|
854
905
|
else:
|
|
855
906
|
deploy_progress.finish(
|
|
856
|
-
f"Complete: {total_available} skills
|
|
857
|
-
f"({total_skill_count}
|
|
907
|
+
f"Complete: {total_available} skills {source_label} "
|
|
908
|
+
f"({total_skill_count} files in cache)"
|
|
858
909
|
)
|
|
859
910
|
|
|
860
911
|
# Log deployment errors if any
|
|
@@ -883,6 +934,202 @@ def sync_remote_skills_on_startup():
|
|
|
883
934
|
# Continue execution - skill sync failure shouldn't block startup
|
|
884
935
|
|
|
885
936
|
|
|
937
|
+
def show_agent_summary():
|
|
938
|
+
"""
|
|
939
|
+
Display agent availability summary on startup.
|
|
940
|
+
|
|
941
|
+
WHY: Users should see at a glance how many agents are available and installed
|
|
942
|
+
without having to run /mpm-agents list.
|
|
943
|
+
|
|
944
|
+
DESIGN DECISION: Fast, non-blocking check that counts agents from the deployment
|
|
945
|
+
directory. Shows simple "X installed / Y available" format. Failures are silent
|
|
946
|
+
to avoid blocking startup.
|
|
947
|
+
"""
|
|
948
|
+
try:
|
|
949
|
+
from pathlib import Path
|
|
950
|
+
|
|
951
|
+
# Count deployed agents (installed)
|
|
952
|
+
deploy_target = Path.cwd() / ".claude" / "agents"
|
|
953
|
+
installed_count = 0
|
|
954
|
+
if deploy_target.exists():
|
|
955
|
+
# Count .md files, excluding README and other docs
|
|
956
|
+
agent_files = [
|
|
957
|
+
f
|
|
958
|
+
for f in deploy_target.glob("*.md")
|
|
959
|
+
if not f.name.startswith(("README", "INSTRUCTIONS", "."))
|
|
960
|
+
]
|
|
961
|
+
installed_count = len(agent_files)
|
|
962
|
+
|
|
963
|
+
# Count available agents in cache (from remote sources)
|
|
964
|
+
cache_dir = Path.home() / ".claude-mpm" / "cache" / "agents"
|
|
965
|
+
available_count = 0
|
|
966
|
+
if cache_dir.exists():
|
|
967
|
+
# Use same filtering logic as agent deployment (lines 486-533 in startup.py)
|
|
968
|
+
pm_templates = {
|
|
969
|
+
"base-agent.md",
|
|
970
|
+
"circuit_breakers.md",
|
|
971
|
+
"pm_examples.md",
|
|
972
|
+
"pm_red_flags.md",
|
|
973
|
+
"research_gate_examples.md",
|
|
974
|
+
"response_format.md",
|
|
975
|
+
"ticket_completeness_examples.md",
|
|
976
|
+
"validation_templates.md",
|
|
977
|
+
"git_file_tracking.md",
|
|
978
|
+
}
|
|
979
|
+
doc_files = {
|
|
980
|
+
"readme.md",
|
|
981
|
+
"changelog.md",
|
|
982
|
+
"contributing.md",
|
|
983
|
+
"implementation-summary.md",
|
|
984
|
+
"reorganization-plan.md",
|
|
985
|
+
"auto-deploy-index.md",
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
# Find all markdown files in agents/ directories
|
|
989
|
+
all_md_files = list(cache_dir.rglob("*.md"))
|
|
990
|
+
agent_files = [
|
|
991
|
+
f
|
|
992
|
+
for f in all_md_files
|
|
993
|
+
if (
|
|
994
|
+
"/agents/" in str(f)
|
|
995
|
+
and f.name.lower() not in pm_templates
|
|
996
|
+
and f.name.lower() not in doc_files
|
|
997
|
+
and f.name.lower() != "base-agent.md"
|
|
998
|
+
and not any(
|
|
999
|
+
part in str(f).split("/")
|
|
1000
|
+
for part in ["dist", "build", ".cache"]
|
|
1001
|
+
)
|
|
1002
|
+
)
|
|
1003
|
+
]
|
|
1004
|
+
available_count = len(agent_files)
|
|
1005
|
+
|
|
1006
|
+
# Display summary if we have agents
|
|
1007
|
+
if installed_count > 0 or available_count > 0:
|
|
1008
|
+
print(
|
|
1009
|
+
f"✓ Agents: {installed_count} deployed / {available_count} cached",
|
|
1010
|
+
flush=True,
|
|
1011
|
+
)
|
|
1012
|
+
|
|
1013
|
+
except Exception as e:
|
|
1014
|
+
# Silent failure - agent summary is informational only
|
|
1015
|
+
from ..core.logger import get_logger
|
|
1016
|
+
|
|
1017
|
+
logger = get_logger("cli")
|
|
1018
|
+
logger.debug(f"Failed to generate agent summary: {e}")
|
|
1019
|
+
|
|
1020
|
+
|
|
1021
|
+
def show_skill_summary():
|
|
1022
|
+
"""
|
|
1023
|
+
Display skill availability summary on startup.
|
|
1024
|
+
|
|
1025
|
+
WHY: Users should see at a glance how many skills are deployed and available
|
|
1026
|
+
from collections, similar to the agent summary.
|
|
1027
|
+
|
|
1028
|
+
DESIGN DECISION: Fast, non-blocking check that counts skills from deployment
|
|
1029
|
+
directory and collection repos. Shows "X installed (Y available)" format.
|
|
1030
|
+
Failures are silent to avoid blocking startup.
|
|
1031
|
+
"""
|
|
1032
|
+
try:
|
|
1033
|
+
from pathlib import Path
|
|
1034
|
+
|
|
1035
|
+
# Count deployed skills (installed)
|
|
1036
|
+
skills_dir = Path.home() / ".claude" / "skills"
|
|
1037
|
+
installed_count = 0
|
|
1038
|
+
if skills_dir.exists():
|
|
1039
|
+
# Count directories with SKILL.md (excludes collection repos)
|
|
1040
|
+
# Exclude collection directories (obra-superpowers, etc.)
|
|
1041
|
+
skill_dirs = [
|
|
1042
|
+
d
|
|
1043
|
+
for d in skills_dir.iterdir()
|
|
1044
|
+
if d.is_dir()
|
|
1045
|
+
and (d / "SKILL.md").exists()
|
|
1046
|
+
and not (d / ".git").exists() # Exclude collection repos
|
|
1047
|
+
]
|
|
1048
|
+
installed_count = len(skill_dirs)
|
|
1049
|
+
|
|
1050
|
+
# Count available skills in collections
|
|
1051
|
+
available_count = 0
|
|
1052
|
+
if skills_dir.exists():
|
|
1053
|
+
# Scan all collection directories (those with .git)
|
|
1054
|
+
for collection_dir in skills_dir.iterdir():
|
|
1055
|
+
if (
|
|
1056
|
+
not collection_dir.is_dir()
|
|
1057
|
+
or not (collection_dir / ".git").exists()
|
|
1058
|
+
):
|
|
1059
|
+
continue
|
|
1060
|
+
|
|
1061
|
+
# Count skill directories in this collection
|
|
1062
|
+
# Skills can be nested in: skills/category/skill-name/SKILL.md
|
|
1063
|
+
# or in flat structure: skill-name/SKILL.md
|
|
1064
|
+
for root, dirs, files in os.walk(collection_dir):
|
|
1065
|
+
if "SKILL.md" in files:
|
|
1066
|
+
# Exclude build artifacts and hidden directories (within the collection)
|
|
1067
|
+
# Get relative path from collection_dir to avoid excluding based on .claude parent
|
|
1068
|
+
root_path = Path(root)
|
|
1069
|
+
relative_parts = root_path.relative_to(collection_dir).parts
|
|
1070
|
+
if not any(
|
|
1071
|
+
part.startswith(".")
|
|
1072
|
+
or part in ["dist", "build", "__pycache__"]
|
|
1073
|
+
for part in relative_parts
|
|
1074
|
+
):
|
|
1075
|
+
available_count += 1
|
|
1076
|
+
|
|
1077
|
+
# Display summary if we have skills
|
|
1078
|
+
if installed_count > 0 or available_count > 0:
|
|
1079
|
+
print(
|
|
1080
|
+
f"✓ Skills: {installed_count} installed ({available_count} available)",
|
|
1081
|
+
flush=True,
|
|
1082
|
+
)
|
|
1083
|
+
|
|
1084
|
+
except Exception as e:
|
|
1085
|
+
# Silent failure - skill summary is informational only
|
|
1086
|
+
from ..core.logger import get_logger
|
|
1087
|
+
|
|
1088
|
+
logger = get_logger("cli")
|
|
1089
|
+
logger.debug(f"Failed to generate skill summary: {e}")
|
|
1090
|
+
|
|
1091
|
+
|
|
1092
|
+
def auto_install_chrome_devtools_on_startup():
|
|
1093
|
+
"""
|
|
1094
|
+
Automatically install chrome-devtools-mcp on startup if enabled.
|
|
1095
|
+
|
|
1096
|
+
WHY: Browser automation capabilities should be available out-of-the-box without
|
|
1097
|
+
manual MCP server configuration. chrome-devtools-mcp provides powerful browser
|
|
1098
|
+
interaction tools for Claude Code.
|
|
1099
|
+
|
|
1100
|
+
DESIGN DECISION: Non-blocking installation that doesn't prevent startup if it fails.
|
|
1101
|
+
Respects user configuration setting (enabled by default). Only installs if not
|
|
1102
|
+
already configured in Claude.
|
|
1103
|
+
"""
|
|
1104
|
+
try:
|
|
1105
|
+
# Check if auto-install is disabled in config
|
|
1106
|
+
from ..config.config_loader import ConfigLoader
|
|
1107
|
+
|
|
1108
|
+
config_loader = ConfigLoader()
|
|
1109
|
+
try:
|
|
1110
|
+
config = config_loader.load_main_config()
|
|
1111
|
+
chrome_devtools_config = config.get("chrome_devtools", {})
|
|
1112
|
+
if not chrome_devtools_config.get("auto_install", True):
|
|
1113
|
+
# Auto-install disabled, skip silently
|
|
1114
|
+
return
|
|
1115
|
+
except Exception:
|
|
1116
|
+
# If config loading fails, assume auto-install is enabled (default)
|
|
1117
|
+
pass
|
|
1118
|
+
|
|
1119
|
+
# Import and run chrome-devtools installation
|
|
1120
|
+
from ..cli.chrome_devtools_installer import auto_install_chrome_devtools
|
|
1121
|
+
|
|
1122
|
+
auto_install_chrome_devtools(quiet=False)
|
|
1123
|
+
|
|
1124
|
+
except Exception as e:
|
|
1125
|
+
# Import logger here to avoid circular imports
|
|
1126
|
+
from ..core.logger import get_logger
|
|
1127
|
+
|
|
1128
|
+
logger = get_logger("cli")
|
|
1129
|
+
logger.debug(f"Failed to auto-install chrome-devtools-mcp: {e}")
|
|
1130
|
+
# Continue execution - chrome-devtools installation failure shouldn't block startup
|
|
1131
|
+
|
|
1132
|
+
|
|
886
1133
|
def run_background_services():
|
|
887
1134
|
"""
|
|
888
1135
|
Initialize all background services on startup.
|
|
@@ -905,6 +1152,7 @@ def run_background_services():
|
|
|
905
1152
|
verify_mcp_gateway_startup()
|
|
906
1153
|
check_for_updates_async()
|
|
907
1154
|
sync_remote_agents_on_startup() # Sync agents from remote sources
|
|
1155
|
+
show_agent_summary() # Display agent counts after deployment
|
|
908
1156
|
|
|
909
1157
|
# Skills deployment order (precedence: remote > bundled)
|
|
910
1158
|
# 1. Deploy bundled skills first (base layer from package)
|
|
@@ -914,9 +1162,13 @@ def run_background_services():
|
|
|
914
1162
|
deploy_bundled_skills() # Base layer: package-bundled skills
|
|
915
1163
|
sync_remote_skills_on_startup() # Override layer: Git-based skills (takes precedence)
|
|
916
1164
|
discover_and_link_runtime_skills() # Discovery: user-added skills
|
|
1165
|
+
show_skill_summary() # Display skill counts after deployment
|
|
917
1166
|
|
|
918
1167
|
deploy_output_style_on_startup()
|
|
919
1168
|
|
|
1169
|
+
# Auto-install chrome-devtools-mcp for browser automation
|
|
1170
|
+
auto_install_chrome_devtools_on_startup()
|
|
1171
|
+
|
|
920
1172
|
|
|
921
1173
|
def setup_mcp_server_logging(args):
|
|
922
1174
|
"""
|
|
@@ -262,5 +262,4 @@ default_configuration:
|
|
|
262
262
|
- `/mpm-doctor`: Diagnose configuration issues
|
|
263
263
|
- `/mpm-init`: Initialize project configuration
|
|
264
264
|
- `/mpm-agents`: Manually manage agents
|
|
265
|
-
- `/mpm-
|
|
266
|
-
- `/mpm-agents-recommend`: Show recommendations only
|
|
265
|
+
- `/mpm-configure`: Unified configuration interface (includes toolchain detection and recommendations)
|