claude-mpm 4.1.2__py3-none-any.whl → 4.1.4__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.
Files changed (87) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/BASE_AGENT_TEMPLATE.md +16 -19
  3. claude_mpm/agents/MEMORY.md +21 -49
  4. claude_mpm/agents/templates/OPTIMIZATION_REPORT.md +156 -0
  5. claude_mpm/agents/templates/api_qa.json +36 -116
  6. claude_mpm/agents/templates/backup/data_engineer_agent_20250726_234551.json +42 -9
  7. claude_mpm/agents/templates/backup/documentation_agent_20250726_234551.json +29 -6
  8. claude_mpm/agents/templates/backup/engineer_agent_20250726_234551.json +34 -6
  9. claude_mpm/agents/templates/backup/ops_agent_20250726_234551.json +41 -9
  10. claude_mpm/agents/templates/backup/qa_agent_20250726_234551.json +30 -8
  11. claude_mpm/agents/templates/backup/research_agent_2025011_234551.json +2 -2
  12. claude_mpm/agents/templates/backup/research_agent_20250726_234551.json +29 -6
  13. claude_mpm/agents/templates/backup/research_memory_efficient.json +2 -2
  14. claude_mpm/agents/templates/backup/security_agent_20250726_234551.json +41 -9
  15. claude_mpm/agents/templates/backup/version_control_agent_20250726_234551.json +23 -7
  16. claude_mpm/agents/templates/code_analyzer.json +18 -36
  17. claude_mpm/agents/templates/data_engineer.json +43 -14
  18. claude_mpm/agents/templates/documentation.json +55 -74
  19. claude_mpm/agents/templates/engineer.json +57 -40
  20. claude_mpm/agents/templates/imagemagick.json +7 -2
  21. claude_mpm/agents/templates/memory_manager.json +1 -1
  22. claude_mpm/agents/templates/ops.json +36 -4
  23. claude_mpm/agents/templates/project_organizer.json +23 -71
  24. claude_mpm/agents/templates/qa.json +34 -2
  25. claude_mpm/agents/templates/refactoring_engineer.json +9 -5
  26. claude_mpm/agents/templates/research.json +36 -4
  27. claude_mpm/agents/templates/security.json +29 -2
  28. claude_mpm/agents/templates/ticketing.json +3 -3
  29. claude_mpm/agents/templates/vercel_ops_agent.json +2 -2
  30. claude_mpm/agents/templates/version_control.json +28 -2
  31. claude_mpm/agents/templates/web_qa.json +38 -151
  32. claude_mpm/agents/templates/web_ui.json +2 -2
  33. claude_mpm/cli/commands/agent_manager.py +221 -1
  34. claude_mpm/cli/commands/agents.py +556 -1009
  35. claude_mpm/cli/commands/memory.py +248 -927
  36. claude_mpm/cli/commands/run.py +139 -484
  37. claude_mpm/cli/parsers/agent_manager_parser.py +34 -0
  38. claude_mpm/cli/startup_logging.py +76 -0
  39. claude_mpm/core/agent_registry.py +6 -10
  40. claude_mpm/core/framework_loader.py +205 -595
  41. claude_mpm/core/log_manager.py +49 -1
  42. claude_mpm/core/logging_config.py +2 -4
  43. claude_mpm/hooks/claude_hooks/event_handlers.py +7 -117
  44. claude_mpm/hooks/claude_hooks/hook_handler.py +91 -755
  45. claude_mpm/hooks/claude_hooks/hook_handler_original.py +1040 -0
  46. claude_mpm/hooks/claude_hooks/hook_handler_refactored.py +347 -0
  47. claude_mpm/hooks/claude_hooks/services/__init__.py +13 -0
  48. claude_mpm/hooks/claude_hooks/services/connection_manager.py +190 -0
  49. claude_mpm/hooks/claude_hooks/services/duplicate_detector.py +106 -0
  50. claude_mpm/hooks/claude_hooks/services/state_manager.py +282 -0
  51. claude_mpm/hooks/claude_hooks/services/subagent_processor.py +374 -0
  52. claude_mpm/services/agents/deployment/agent_deployment.py +42 -454
  53. claude_mpm/services/agents/deployment/base_agent_locator.py +132 -0
  54. claude_mpm/services/agents/deployment/deployment_results_manager.py +185 -0
  55. claude_mpm/services/agents/deployment/single_agent_deployer.py +315 -0
  56. claude_mpm/services/agents/memory/agent_memory_manager.py +42 -508
  57. claude_mpm/services/agents/memory/memory_categorization_service.py +165 -0
  58. claude_mpm/services/agents/memory/memory_file_service.py +103 -0
  59. claude_mpm/services/agents/memory/memory_format_service.py +201 -0
  60. claude_mpm/services/agents/memory/memory_limits_service.py +99 -0
  61. claude_mpm/services/agents/registry/__init__.py +1 -1
  62. claude_mpm/services/cli/__init__.py +18 -0
  63. claude_mpm/services/cli/agent_cleanup_service.py +407 -0
  64. claude_mpm/services/cli/agent_dependency_service.py +395 -0
  65. claude_mpm/services/cli/agent_listing_service.py +463 -0
  66. claude_mpm/services/cli/agent_output_formatter.py +605 -0
  67. claude_mpm/services/cli/agent_validation_service.py +589 -0
  68. claude_mpm/services/cli/dashboard_launcher.py +424 -0
  69. claude_mpm/services/cli/memory_crud_service.py +617 -0
  70. claude_mpm/services/cli/memory_output_formatter.py +604 -0
  71. claude_mpm/services/cli/session_manager.py +513 -0
  72. claude_mpm/services/cli/socketio_manager.py +498 -0
  73. claude_mpm/services/cli/startup_checker.py +370 -0
  74. claude_mpm/services/core/cache_manager.py +311 -0
  75. claude_mpm/services/core/memory_manager.py +637 -0
  76. claude_mpm/services/core/path_resolver.py +498 -0
  77. claude_mpm/services/core/service_container.py +520 -0
  78. claude_mpm/services/core/service_interfaces.py +436 -0
  79. claude_mpm/services/diagnostics/checks/agent_check.py +65 -19
  80. claude_mpm/services/memory/router.py +116 -10
  81. {claude_mpm-4.1.2.dist-info → claude_mpm-4.1.4.dist-info}/METADATA +1 -1
  82. {claude_mpm-4.1.2.dist-info → claude_mpm-4.1.4.dist-info}/RECORD +86 -55
  83. claude_mpm/cli/commands/run_config_checker.py +0 -159
  84. {claude_mpm-4.1.2.dist-info → claude_mpm-4.1.4.dist-info}/WHEEL +0 -0
  85. {claude_mpm-4.1.2.dist-info → claude_mpm-4.1.4.dist-info}/entry_points.txt +0 -0
  86. {claude_mpm-4.1.2.dist-info → claude_mpm-4.1.4.dist-info}/licenses/LICENSE +0 -0
  87. {claude_mpm-4.1.2.dist-info → claude_mpm-4.1.4.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,165 @@
1
+ #!/usr/bin/env python3
2
+ """Memory Categorization Service - Categorizes learnings into appropriate sections."""
3
+
4
+ import logging
5
+ from typing import List
6
+
7
+
8
+ class MemoryCategorizationService:
9
+ """Service for categorizing memory learnings."""
10
+
11
+ # Category keywords for automatic categorization
12
+ CATEGORY_KEYWORDS = {
13
+ "Project Architecture": [
14
+ "architecture",
15
+ "structure",
16
+ "design",
17
+ "pattern",
18
+ "framework",
19
+ "component",
20
+ "module",
21
+ "service",
22
+ "interface",
23
+ "api",
24
+ "endpoint",
25
+ "schema",
26
+ "model",
27
+ "database",
28
+ "microservice",
29
+ ],
30
+ "Implementation Guidelines": [
31
+ "implement",
32
+ "code",
33
+ "function",
34
+ "method",
35
+ "class",
36
+ "algorithm",
37
+ "logic",
38
+ "process",
39
+ "workflow",
40
+ "feature",
41
+ "requirement",
42
+ "specification",
43
+ "standard",
44
+ "convention",
45
+ "practice",
46
+ ],
47
+ "Common Mistakes to Avoid": [
48
+ "mistake",
49
+ "error",
50
+ "bug",
51
+ "issue",
52
+ "problem",
53
+ "avoid",
54
+ "don't",
55
+ "never",
56
+ "warning",
57
+ "caution",
58
+ "gotcha",
59
+ "pitfall",
60
+ "trap",
61
+ "wrong",
62
+ "incorrect",
63
+ ],
64
+ "Current Technical Context": [
65
+ "current",
66
+ "status",
67
+ "context",
68
+ "environment",
69
+ "configuration",
70
+ "setup",
71
+ "version",
72
+ "dependency",
73
+ "tool",
74
+ "library",
75
+ "package",
76
+ "integration",
77
+ "deployment",
78
+ "infrastructure",
79
+ "state",
80
+ ],
81
+ }
82
+
83
+ def __init__(self):
84
+ """Initialize the categorization service."""
85
+ self.logger = logging.getLogger(__name__)
86
+
87
+ def categorize_learning(self, learning: str) -> str:
88
+ """Categorize a learning item based on its content.
89
+
90
+ WHY: Learnings are automatically organized into categories to make them
91
+ easier to find and review. This uses keyword matching to determine the
92
+ most appropriate category.
93
+
94
+ Args:
95
+ learning: The learning content to categorize
96
+
97
+ Returns:
98
+ Category name (defaults to "Current Technical Context")
99
+ """
100
+ if not learning:
101
+ return "Current Technical Context"
102
+
103
+ learning_lower = learning.lower()
104
+ category_scores = {}
105
+
106
+ # Score each category based on keyword matches
107
+ for category, keywords in self.CATEGORY_KEYWORDS.items():
108
+ score = sum(1 for keyword in keywords if keyword in learning_lower)
109
+ if score > 0:
110
+ category_scores[category] = score
111
+
112
+ # Return category with highest score, or default
113
+ if category_scores:
114
+ return max(category_scores, key=category_scores.get)
115
+
116
+ return "Current Technical Context"
117
+
118
+ def categorize_learnings_batch(self, learnings: List[str]) -> dict:
119
+ """Categorize multiple learnings at once.
120
+
121
+ Args:
122
+ learnings: List of learning items to categorize
123
+
124
+ Returns:
125
+ Dictionary mapping categories to lists of learnings
126
+ """
127
+ categorized = {}
128
+
129
+ for learning in learnings:
130
+ category = self.categorize_learning(learning)
131
+ if category not in categorized:
132
+ categorized[category] = []
133
+ categorized[category].append(learning)
134
+
135
+ return categorized
136
+
137
+ def merge_categorized_learnings(
138
+ self, existing: dict, new: dict, max_per_category: int = 15
139
+ ) -> dict:
140
+ """Merge new categorized learnings with existing ones.
141
+
142
+ Args:
143
+ existing: Existing categorized learnings
144
+ new: New categorized learnings to add
145
+ max_per_category: Maximum items per category
146
+
147
+ Returns:
148
+ Merged categorized learnings with limits applied
149
+ """
150
+ merged = existing.copy()
151
+
152
+ for category, items in new.items():
153
+ if category not in merged:
154
+ merged[category] = []
155
+
156
+ # Add new items, avoiding duplicates
157
+ for item in items:
158
+ if item not in merged[category]:
159
+ merged[category].append(item)
160
+
161
+ # Apply limit (keep most recent)
162
+ if len(merged[category]) > max_per_category:
163
+ merged[category] = merged[category][-max_per_category:]
164
+
165
+ return merged
@@ -0,0 +1,103 @@
1
+ #!/usr/bin/env python3
2
+ """Memory File Service - Handles file operations for agent memories."""
3
+
4
+ import logging
5
+ from pathlib import Path
6
+
7
+
8
+ class MemoryFileService:
9
+ """Service for handling memory file operations."""
10
+
11
+ def __init__(self, memories_dir: Path):
12
+ """Initialize the memory file service.
13
+
14
+ Args:
15
+ memories_dir: Directory where memory files are stored
16
+ """
17
+ self.memories_dir = memories_dir
18
+ self.logger = logging.getLogger(__name__)
19
+
20
+ def get_memory_file_with_migration(self, directory: Path, agent_id: str) -> Path:
21
+ """Get memory file path with migration support.
22
+
23
+ Migrates from old naming convention if needed.
24
+
25
+ Args:
26
+ directory: Directory to check for memory file
27
+ agent_id: Agent identifier
28
+
29
+ Returns:
30
+ Path to the memory file
31
+ """
32
+ new_file = directory / f"{agent_id}_memories.md"
33
+ old_file = directory / f"{agent_id}_memory.md"
34
+
35
+ # Migrate from old naming convention if needed
36
+ if old_file.exists() and not new_file.exists():
37
+ try:
38
+ old_file.rename(new_file)
39
+ self.logger.info(f"Migrated memory file: {old_file} -> {new_file}")
40
+ except Exception as e:
41
+ self.logger.warning(f"Could not migrate memory file: {e}")
42
+ return old_file
43
+
44
+ return new_file
45
+
46
+ def save_memory_file(self, file_path: Path, content: str) -> bool:
47
+ """Save content to a memory file.
48
+
49
+ Args:
50
+ file_path: Path to the memory file
51
+ content: Content to save
52
+
53
+ Returns:
54
+ True if saved successfully, False otherwise
55
+ """
56
+ try:
57
+ # Ensure directory exists
58
+ file_path.parent.mkdir(parents=True, exist_ok=True)
59
+
60
+ # Write content
61
+ file_path.write_text(content)
62
+
63
+ self.logger.debug(f"Saved memory file: {file_path}")
64
+ return True
65
+
66
+ except Exception as e:
67
+ self.logger.error(f"Failed to save memory file {file_path}: {e}")
68
+ return False
69
+
70
+ def ensure_memories_directory(self) -> None:
71
+ """Ensure the memories directory exists with README."""
72
+ try:
73
+ # Create directory if it doesn't exist
74
+ self.memories_dir.mkdir(parents=True, exist_ok=True)
75
+
76
+ # Create README if it doesn't exist
77
+ readme_path = self.memories_dir / "README.md"
78
+ if not readme_path.exists():
79
+ readme_content = """# Agent Memories Directory
80
+
81
+ This directory contains memory files for various agents used in the project.
82
+
83
+ ## File Format
84
+
85
+ Memory files follow the naming convention: `{agent_id}_memories.md`
86
+
87
+ Each file contains:
88
+ - Agent metadata (name, type, version)
89
+ - Project-specific learnings organized by category
90
+ - Timestamps for tracking updates
91
+
92
+ ## Auto-generated
93
+
94
+ These files are managed automatically by the agent memory system.
95
+ Manual edits should be done carefully to preserve the format.
96
+ """
97
+ readme_path.write_text(readme_content)
98
+ self.logger.debug(
99
+ f"Created README in memories directory: {readme_path}"
100
+ )
101
+
102
+ except Exception as e:
103
+ self.logger.error(f"Failed to ensure memories directory: {e}")
@@ -0,0 +1,201 @@
1
+ #!/usr/bin/env python3
2
+ """Memory Format Service - Handles memory content formatting and parsing."""
3
+
4
+ import logging
5
+ import re
6
+ from datetime import datetime
7
+ from typing import Dict, List
8
+
9
+
10
+ class MemoryFormatService:
11
+ """Service for memory content formatting and parsing."""
12
+
13
+ def __init__(self):
14
+ """Initialize the memory format service."""
15
+ self.logger = logging.getLogger(__name__)
16
+
17
+ def build_simple_memory_content(self, agent_id: str, items: List[str]) -> str:
18
+ """Build memory content as a simple list with header and timestamp.
19
+
20
+ Args:
21
+ agent_id: Agent identifier for the header
22
+ items: List of memory items
23
+
24
+ Returns:
25
+ Formatted memory content string
26
+ """
27
+ # Build header
28
+ header = f"# {agent_id.title()} Agent Memory\n\n"
29
+ header += f"Last Updated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n\n"
30
+ header += "## Learnings\n\n"
31
+
32
+ # Build item list
33
+ item_lines = []
34
+ for item in items:
35
+ # Clean and format each item
36
+ item = item.strip()
37
+ if item and not item.startswith("- "):
38
+ item = f"- {item}"
39
+ if item:
40
+ item_lines.append(item)
41
+
42
+ # Combine
43
+ content = header + "\n".join(item_lines)
44
+ if item_lines:
45
+ content += "\n"
46
+
47
+ return content
48
+
49
+ def parse_memory_list(self, memory_content: str) -> List[str]:
50
+ """Parse memory content into a simple list.
51
+
52
+ Args:
53
+ memory_content: Raw memory content
54
+
55
+ Returns:
56
+ List of memory items (without "- " prefix)
57
+ """
58
+ items = []
59
+ lines = memory_content.split("\n")
60
+
61
+ for line in lines:
62
+ line = line.strip()
63
+ # Skip headers, empty lines, and metadata
64
+ if (
65
+ not line
66
+ or line.startswith("#")
67
+ or line.startswith("Last Updated:")
68
+ or line.startswith("**")
69
+ or line == "---"
70
+ ):
71
+ continue
72
+
73
+ # Extract list items
74
+ if line.startswith("- "):
75
+ item = line[2:].strip()
76
+ if item:
77
+ items.append(item)
78
+ elif line and not any(
79
+ line.startswith(p) for p in ["#", "**", "Last Updated:", "---"]
80
+ ):
81
+ # Include non-list items that aren't headers
82
+ items.append(line)
83
+
84
+ return items
85
+
86
+ def parse_memory_sections(self, memory_content: str) -> Dict[str, List[str]]:
87
+ """Parse memory content into sections and items.
88
+
89
+ Args:
90
+ memory_content: Raw memory file content
91
+
92
+ Returns:
93
+ Dict mapping section names to lists of items
94
+ """
95
+ sections = {}
96
+ current_section = None
97
+ current_items = []
98
+
99
+ for line in memory_content.split("\n"):
100
+ # Check for section header (## Section Name)
101
+ if line.startswith("## "):
102
+ # Save previous section if exists
103
+ if current_section and current_items:
104
+ sections[current_section] = current_items
105
+ # Start new section
106
+ current_section = line[3:].strip()
107
+ current_items = []
108
+ # Check for list item
109
+ elif line.startswith("- ") and current_section:
110
+ item = line[2:].strip()
111
+ if item:
112
+ current_items.append(item)
113
+
114
+ # Save last section
115
+ if current_section and current_items:
116
+ sections[current_section] = current_items
117
+
118
+ return sections
119
+
120
+ def clean_template_placeholders(
121
+ self,
122
+ content: str,
123
+ preserve_structure: bool = False,
124
+ agent_id: str = "agent",
125
+ ) -> str:
126
+ """Clean template placeholders from memory content.
127
+
128
+ WHY: Default templates contain placeholder text that should be removed
129
+ when adding real memories. This method cleans those placeholders while
130
+ preserving any actual content.
131
+
132
+ Args:
133
+ content: Memory content to clean
134
+ preserve_structure: If True, preserve empty sections
135
+ agent_id: Agent ID for context
136
+
137
+ Returns:
138
+ Cleaned content string
139
+ """
140
+ if not content:
141
+ return content
142
+
143
+ # Patterns to remove
144
+ placeholder_patterns = [
145
+ r"\[Agent will add.*?\]",
146
+ r"\[No .* yet\]",
147
+ r"<!-- .* -->",
148
+ r"No items yet.*",
149
+ r"Memory items will be added.*",
150
+ r"\*\*Note:.*?\*\*",
151
+ ]
152
+
153
+ cleaned = content
154
+ for pattern in placeholder_patterns:
155
+ cleaned = re.sub(pattern, "", cleaned, flags=re.IGNORECASE | re.MULTILINE)
156
+
157
+ if not preserve_structure:
158
+ # Remove empty sections
159
+ lines = []
160
+ skip_empty = False
161
+ for line in cleaned.split("\n"):
162
+ if line.startswith("## "):
163
+ skip_empty = True
164
+ lines.append(line)
165
+ elif line.strip() and skip_empty:
166
+ skip_empty = False
167
+ lines.append(line)
168
+ elif not skip_empty:
169
+ lines.append(line)
170
+
171
+ cleaned = "\n".join(lines)
172
+
173
+ # Clean up multiple blank lines
174
+ cleaned = re.sub(r"\n{3,}", "\n\n", cleaned)
175
+
176
+ return cleaned.strip()
177
+
178
+ def clean_template_placeholders_list(self, items: List[str]) -> List[str]:
179
+ """Clean template placeholders from a list of items.
180
+
181
+ Args:
182
+ items: List of items to clean
183
+
184
+ Returns:
185
+ Cleaned list of items
186
+ """
187
+ cleaned = []
188
+ for item in items:
189
+ # Skip placeholder items
190
+ if any(
191
+ pattern in item.lower()
192
+ for pattern in [
193
+ "[agent will add",
194
+ "[no ",
195
+ "no items yet",
196
+ "memory items will be added",
197
+ ]
198
+ ):
199
+ continue
200
+ cleaned.append(item)
201
+ return cleaned
@@ -0,0 +1,99 @@
1
+ #!/usr/bin/env python3
2
+ """Memory Limits Service - Manages memory size limits and configuration."""
3
+
4
+ import logging
5
+ from typing import Any, Dict, Optional
6
+
7
+ from claude_mpm.core.config import Config
8
+
9
+
10
+ class MemoryLimitsService:
11
+ """Service for managing memory limits and configuration."""
12
+
13
+ # Default limits
14
+ DEFAULT_MEMORY_LIMITS = {
15
+ "max_file_size_kb": 80, # 80KB (20k tokens)
16
+ "max_items": 100, # Maximum total memory items
17
+ "max_line_length": 120,
18
+ }
19
+
20
+ def __init__(self, config: Optional[Config] = None):
21
+ """Initialize the memory limits service.
22
+
23
+ Args:
24
+ config: Optional Config object for reading configuration
25
+ """
26
+ self.config = config or Config()
27
+ self.logger = logging.getLogger(__name__)
28
+ self.memory_limits = self._init_memory_limits()
29
+
30
+ def _init_memory_limits(self) -> Dict[str, Any]:
31
+ """Initialize memory limits from configuration.
32
+
33
+ Returns:
34
+ Dictionary of memory limits
35
+ """
36
+ try:
37
+ limits = self.DEFAULT_MEMORY_LIMITS.copy()
38
+
39
+ # Try to load from config
40
+ if hasattr(self.config, "agent_memory_limits"):
41
+ config_limits = self.config.agent_memory_limits
42
+ if isinstance(config_limits, dict):
43
+ limits.update(config_limits)
44
+
45
+ self.logger.debug(f"Initialized memory limits: {limits}")
46
+ return limits
47
+
48
+ except Exception as e:
49
+ self.logger.warning(f"Failed to load memory limits from config: {e}")
50
+ return self.DEFAULT_MEMORY_LIMITS.copy()
51
+
52
+ def get_agent_limits(self, agent_id: str) -> Dict[str, Any]:
53
+ """Get memory limits for a specific agent.
54
+
55
+ Args:
56
+ agent_id: Agent identifier
57
+
58
+ Returns:
59
+ Dictionary of memory limits for the agent
60
+ """
61
+ # Start with default limits
62
+ limits = self.memory_limits.copy()
63
+
64
+ # Check for agent-specific overrides
65
+ try:
66
+ if hasattr(self.config, "agents") and agent_id in self.config.agents:
67
+ agent_config = self.config.agents[agent_id]
68
+ if "memory_limits" in agent_config:
69
+ limits.update(agent_config["memory_limits"])
70
+ except Exception as e:
71
+ self.logger.debug(f"No agent-specific limits for {agent_id}: {e}")
72
+
73
+ return limits
74
+
75
+ def get_agent_auto_learning(self, agent_id: str) -> bool:
76
+ """Get auto-learning setting for a specific agent.
77
+
78
+ Args:
79
+ agent_id: Agent identifier
80
+
81
+ Returns:
82
+ True if auto-learning is enabled, False otherwise
83
+ """
84
+ try:
85
+ # Check agent-specific config
86
+ if hasattr(self.config, "agents") and agent_id in self.config.agents:
87
+ agent_config = self.config.agents[agent_id]
88
+ if "auto_learning" in agent_config:
89
+ return agent_config["auto_learning"]
90
+
91
+ # Check global config
92
+ if hasattr(self.config, "agent_auto_learning"):
93
+ return self.config.agent_auto_learning
94
+
95
+ except Exception as e:
96
+ self.logger.debug(f"Error checking auto-learning for {agent_id}: {e}")
97
+
98
+ # Default to True (auto-learning enabled)
99
+ return True
@@ -4,8 +4,8 @@ from claude_mpm.core.unified_agent_registry import (
4
4
  AgentMetadata,
5
5
  AgentTier,
6
6
  AgentType,
7
+ UnifiedAgentRegistry as AgentRegistry,
7
8
  )
8
- from claude_mpm.core.unified_agent_registry import UnifiedAgentRegistry as AgentRegistry
9
9
 
10
10
  from .deployed_agent_discovery import DeployedAgentDiscovery
11
11
  from .modification_tracker import (
@@ -0,0 +1,18 @@
1
+ """CLI services package.
2
+
3
+ Services specifically for CLI command support and utilities.
4
+ """
5
+
6
+ from .agent_dependency_service import AgentDependencyService, IAgentDependencyService
7
+ from .agent_validation_service import AgentValidationService, IAgentValidationService
8
+ from .startup_checker import IStartupChecker, StartupCheckerService, StartupWarning
9
+
10
+ __all__ = [
11
+ "AgentDependencyService",
12
+ "AgentValidationService",
13
+ "IAgentDependencyService",
14
+ "IAgentValidationService",
15
+ "IStartupChecker",
16
+ "StartupCheckerService",
17
+ "StartupWarning",
18
+ ]