claude-mpm 4.0.23__py3-none-any.whl → 4.0.28__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.
- claude_mpm/BUILD_NUMBER +1 -1
- claude_mpm/VERSION +1 -1
- claude_mpm/agents/BASE_AGENT_TEMPLATE.md +4 -1
- claude_mpm/agents/BASE_PM.md +3 -0
- claude_mpm/agents/templates/code_analyzer.json +2 -2
- claude_mpm/cli/commands/agents.py +453 -113
- claude_mpm/cli/commands/aggregate.py +107 -15
- claude_mpm/cli/commands/cleanup.py +142 -10
- claude_mpm/cli/commands/config.py +358 -224
- claude_mpm/cli/commands/info.py +184 -75
- claude_mpm/cli/commands/mcp_command_router.py +5 -76
- claude_mpm/cli/commands/mcp_install_commands.py +68 -36
- claude_mpm/cli/commands/mcp_server_commands.py +30 -37
- claude_mpm/cli/commands/memory.py +331 -61
- claude_mpm/cli/commands/monitor.py +101 -7
- claude_mpm/cli/commands/run.py +368 -8
- claude_mpm/cli/commands/tickets.py +206 -24
- claude_mpm/cli/parsers/mcp_parser.py +3 -0
- claude_mpm/cli/shared/__init__.py +40 -0
- claude_mpm/cli/shared/argument_patterns.py +212 -0
- claude_mpm/cli/shared/command_base.py +234 -0
- claude_mpm/cli/shared/error_handling.py +238 -0
- claude_mpm/cli/shared/output_formatters.py +231 -0
- claude_mpm/config/agent_config.py +29 -8
- claude_mpm/core/container.py +6 -4
- claude_mpm/core/service_registry.py +4 -2
- claude_mpm/core/shared/__init__.py +17 -0
- claude_mpm/core/shared/config_loader.py +320 -0
- claude_mpm/core/shared/path_resolver.py +277 -0
- claude_mpm/core/shared/singleton_manager.py +208 -0
- claude_mpm/hooks/claude_hooks/memory_integration.py +4 -2
- claude_mpm/hooks/claude_hooks/response_tracking.py +14 -3
- claude_mpm/hooks/memory_integration_hook.py +11 -2
- claude_mpm/services/agents/deployment/agent_deployment.py +49 -23
- claude_mpm/services/agents/deployment/deployment_wrapper.py +71 -0
- claude_mpm/services/agents/deployment/pipeline/pipeline_context.py +1 -0
- claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +43 -0
- claude_mpm/services/agents/deployment/processors/agent_deployment_context.py +4 -0
- claude_mpm/services/agents/deployment/processors/agent_processor.py +1 -1
- claude_mpm/services/agents/loading/base_agent_manager.py +11 -3
- claude_mpm/services/agents/registry/deployed_agent_discovery.py +14 -5
- claude_mpm/services/event_aggregator.py +4 -2
- claude_mpm/services/mcp_gateway/config/config_loader.py +89 -28
- claude_mpm/services/mcp_gateway/config/configuration.py +29 -0
- claude_mpm/services/mcp_gateway/registry/service_registry.py +22 -5
- claude_mpm/services/memory/builder.py +6 -1
- claude_mpm/services/response_tracker.py +3 -1
- claude_mpm/services/runner_configuration_service.py +15 -6
- claude_mpm/services/shared/__init__.py +20 -0
- claude_mpm/services/shared/async_service_base.py +219 -0
- claude_mpm/services/shared/config_service_base.py +292 -0
- claude_mpm/services/shared/lifecycle_service_base.py +317 -0
- claude_mpm/services/shared/manager_base.py +303 -0
- claude_mpm/services/shared/service_factory.py +308 -0
- {claude_mpm-4.0.23.dist-info → claude_mpm-4.0.28.dist-info}/METADATA +19 -13
- {claude_mpm-4.0.23.dist-info → claude_mpm-4.0.28.dist-info}/RECORD +60 -44
- {claude_mpm-4.0.23.dist-info → claude_mpm-4.0.28.dist-info}/WHEEL +0 -0
- {claude_mpm-4.0.23.dist-info → claude_mpm-4.0.28.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.0.23.dist-info → claude_mpm-4.0.28.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.0.23.dist-info → claude_mpm-4.0.28.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Service factory utilities to reduce service creation duplication.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from typing import Any, Dict, Optional, Type, TypeVar
|
|
6
|
+
|
|
7
|
+
from ...core.config import Config
|
|
8
|
+
from ...core.logger import get_logger
|
|
9
|
+
from ...core.shared import ConfigLoader, PathResolver, SingletonManager
|
|
10
|
+
|
|
11
|
+
T = TypeVar('T')
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class ServiceFactory:
|
|
15
|
+
"""
|
|
16
|
+
Factory for creating services with common patterns.
|
|
17
|
+
|
|
18
|
+
Reduces duplication by providing standard service creation patterns:
|
|
19
|
+
- Configuration injection
|
|
20
|
+
- Dependency resolution
|
|
21
|
+
- Singleton management
|
|
22
|
+
- Standard initialization
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
def __init__(self):
|
|
26
|
+
"""Initialize service factory."""
|
|
27
|
+
self.logger = get_logger("service_factory")
|
|
28
|
+
self._config_loader = ConfigLoader()
|
|
29
|
+
self._path_resolver = PathResolver()
|
|
30
|
+
self._registered_services: Dict[str, Type] = {}
|
|
31
|
+
|
|
32
|
+
def register_service(self, service_name: str, service_class: Type[T]) -> None:
|
|
33
|
+
"""
|
|
34
|
+
Register a service class.
|
|
35
|
+
|
|
36
|
+
Args:
|
|
37
|
+
service_name: Name to register service under
|
|
38
|
+
service_class: Service class to register
|
|
39
|
+
"""
|
|
40
|
+
self._registered_services[service_name] = service_class
|
|
41
|
+
self.logger.debug(f"Registered service: {service_name} -> {service_class.__name__}")
|
|
42
|
+
|
|
43
|
+
def create_service(self,
|
|
44
|
+
service_class: Type[T],
|
|
45
|
+
service_name: str = None,
|
|
46
|
+
config: Optional[Dict[str, Any]] = None,
|
|
47
|
+
singleton: bool = False,
|
|
48
|
+
**kwargs) -> T:
|
|
49
|
+
"""
|
|
50
|
+
Create a service instance with standard patterns.
|
|
51
|
+
|
|
52
|
+
Args:
|
|
53
|
+
service_class: Service class to instantiate
|
|
54
|
+
service_name: Optional service name (defaults to class name)
|
|
55
|
+
config: Optional configuration override
|
|
56
|
+
singleton: Whether to use singleton pattern
|
|
57
|
+
**kwargs: Additional constructor arguments
|
|
58
|
+
|
|
59
|
+
Returns:
|
|
60
|
+
Service instance
|
|
61
|
+
"""
|
|
62
|
+
if service_name is None:
|
|
63
|
+
service_name = service_class.__name__
|
|
64
|
+
|
|
65
|
+
self.logger.debug(f"Creating service: {service_name}")
|
|
66
|
+
|
|
67
|
+
# Load configuration if not provided
|
|
68
|
+
if config is None:
|
|
69
|
+
config = self._load_service_config(service_name)
|
|
70
|
+
|
|
71
|
+
# Prepare constructor arguments
|
|
72
|
+
constructor_args = {
|
|
73
|
+
"service_name": service_name,
|
|
74
|
+
"config": config,
|
|
75
|
+
**kwargs
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
# Filter arguments based on constructor signature
|
|
79
|
+
filtered_args = self._filter_constructor_args(service_class, constructor_args)
|
|
80
|
+
|
|
81
|
+
# Create instance
|
|
82
|
+
if singleton:
|
|
83
|
+
instance = SingletonManager.get_instance(service_class, **filtered_args)
|
|
84
|
+
else:
|
|
85
|
+
instance = service_class(**filtered_args)
|
|
86
|
+
|
|
87
|
+
self.logger.info(f"Created service: {service_name} ({service_class.__name__})")
|
|
88
|
+
return instance
|
|
89
|
+
|
|
90
|
+
def create_registered_service(self,
|
|
91
|
+
service_name: str,
|
|
92
|
+
config: Optional[Dict[str, Any]] = None,
|
|
93
|
+
singleton: bool = False,
|
|
94
|
+
**kwargs) -> Any:
|
|
95
|
+
"""
|
|
96
|
+
Create a service by registered name.
|
|
97
|
+
|
|
98
|
+
Args:
|
|
99
|
+
service_name: Name of registered service
|
|
100
|
+
config: Optional configuration override
|
|
101
|
+
singleton: Whether to use singleton pattern
|
|
102
|
+
**kwargs: Additional constructor arguments
|
|
103
|
+
|
|
104
|
+
Returns:
|
|
105
|
+
Service instance
|
|
106
|
+
|
|
107
|
+
Raises:
|
|
108
|
+
ValueError: If service not registered
|
|
109
|
+
"""
|
|
110
|
+
if service_name not in self._registered_services:
|
|
111
|
+
raise ValueError(f"Service not registered: {service_name}")
|
|
112
|
+
|
|
113
|
+
service_class = self._registered_services[service_name]
|
|
114
|
+
return self.create_service(
|
|
115
|
+
service_class=service_class,
|
|
116
|
+
service_name=service_name,
|
|
117
|
+
config=config,
|
|
118
|
+
singleton=singleton,
|
|
119
|
+
**kwargs
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
def create_agent_service(self,
|
|
123
|
+
service_class: Type[T],
|
|
124
|
+
agent_name: str,
|
|
125
|
+
agent_dir: str = None,
|
|
126
|
+
**kwargs) -> T:
|
|
127
|
+
"""
|
|
128
|
+
Create an agent-related service.
|
|
129
|
+
|
|
130
|
+
Args:
|
|
131
|
+
service_class: Service class to instantiate
|
|
132
|
+
agent_name: Name of the agent
|
|
133
|
+
agent_dir: Optional agent directory
|
|
134
|
+
**kwargs: Additional constructor arguments
|
|
135
|
+
|
|
136
|
+
Returns:
|
|
137
|
+
Service instance
|
|
138
|
+
"""
|
|
139
|
+
# Load agent-specific configuration
|
|
140
|
+
config = self._config_loader.load_agent_config(agent_dir)
|
|
141
|
+
|
|
142
|
+
# Add agent-specific paths
|
|
143
|
+
if agent_dir:
|
|
144
|
+
agent_path = self._path_resolver.resolve_relative_path(agent_dir)
|
|
145
|
+
else:
|
|
146
|
+
agent_path = self._path_resolver.find_agent_file(agent_name)
|
|
147
|
+
if agent_path:
|
|
148
|
+
agent_path = agent_path.parent
|
|
149
|
+
|
|
150
|
+
constructor_args = {
|
|
151
|
+
"agent_name": agent_name,
|
|
152
|
+
"agent_dir": agent_path,
|
|
153
|
+
"config": config,
|
|
154
|
+
**kwargs
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return self.create_service(
|
|
158
|
+
service_class=service_class,
|
|
159
|
+
service_name=f"agent_{agent_name}",
|
|
160
|
+
config=config,
|
|
161
|
+
**constructor_args
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
def create_memory_service(self,
|
|
165
|
+
service_class: Type[T],
|
|
166
|
+
agent_name: str = None,
|
|
167
|
+
memory_dir: str = None,
|
|
168
|
+
**kwargs) -> T:
|
|
169
|
+
"""
|
|
170
|
+
Create a memory-related service.
|
|
171
|
+
|
|
172
|
+
Args:
|
|
173
|
+
service_class: Service class to instantiate
|
|
174
|
+
agent_name: Optional agent name
|
|
175
|
+
memory_dir: Optional memory directory
|
|
176
|
+
**kwargs: Additional constructor arguments
|
|
177
|
+
|
|
178
|
+
Returns:
|
|
179
|
+
Service instance
|
|
180
|
+
"""
|
|
181
|
+
# Load memory-specific configuration
|
|
182
|
+
config = self._config_loader.load_memory_config(memory_dir)
|
|
183
|
+
|
|
184
|
+
# Resolve memory directory
|
|
185
|
+
if memory_dir:
|
|
186
|
+
memory_path = self._path_resolver.resolve_relative_path(memory_dir)
|
|
187
|
+
else:
|
|
188
|
+
memory_path = self._path_resolver.resolve_memories_dir(create=True)
|
|
189
|
+
|
|
190
|
+
constructor_args = {
|
|
191
|
+
"memory_dir": memory_path,
|
|
192
|
+
"config": config,
|
|
193
|
+
**kwargs
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
if agent_name:
|
|
197
|
+
constructor_args["agent_name"] = agent_name
|
|
198
|
+
|
|
199
|
+
service_name = f"memory_{agent_name}" if agent_name else "memory"
|
|
200
|
+
|
|
201
|
+
return self.create_service(
|
|
202
|
+
service_class=service_class,
|
|
203
|
+
service_name=service_name,
|
|
204
|
+
config=config,
|
|
205
|
+
**constructor_args
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
def create_config_service(self,
|
|
209
|
+
service_class: Type[T],
|
|
210
|
+
config_section: str = None,
|
|
211
|
+
**kwargs) -> T:
|
|
212
|
+
"""
|
|
213
|
+
Create a configuration-heavy service.
|
|
214
|
+
|
|
215
|
+
Args:
|
|
216
|
+
service_class: Service class to instantiate
|
|
217
|
+
config_section: Configuration section name
|
|
218
|
+
**kwargs: Additional constructor arguments
|
|
219
|
+
|
|
220
|
+
Returns:
|
|
221
|
+
Service instance
|
|
222
|
+
"""
|
|
223
|
+
# Load service-specific configuration
|
|
224
|
+
service_name = config_section or service_class.__name__.lower()
|
|
225
|
+
config = self._config_loader.load_service_config(service_name)
|
|
226
|
+
|
|
227
|
+
constructor_args = {
|
|
228
|
+
"config": config,
|
|
229
|
+
"config_section": config_section,
|
|
230
|
+
**kwargs
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
return self.create_service(
|
|
234
|
+
service_class=service_class,
|
|
235
|
+
service_name=service_name,
|
|
236
|
+
config=config,
|
|
237
|
+
**constructor_args
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
def _load_service_config(self, service_name: str) -> Config:
|
|
241
|
+
"""Load configuration for a service."""
|
|
242
|
+
try:
|
|
243
|
+
return self._config_loader.load_service_config(service_name)
|
|
244
|
+
except Exception as e:
|
|
245
|
+
self.logger.warning(f"Failed to load config for {service_name}: {e}")
|
|
246
|
+
# Return default config using ConfigLoader
|
|
247
|
+
return self._config_loader.load_main_config()
|
|
248
|
+
|
|
249
|
+
def _filter_constructor_args(self,
|
|
250
|
+
service_class: Type,
|
|
251
|
+
args: Dict[str, Any]) -> Dict[str, Any]:
|
|
252
|
+
"""Filter constructor arguments based on class signature."""
|
|
253
|
+
import inspect
|
|
254
|
+
|
|
255
|
+
try:
|
|
256
|
+
# Get constructor signature
|
|
257
|
+
sig = inspect.signature(service_class.__init__)
|
|
258
|
+
param_names = set(sig.parameters.keys()) - {'self'}
|
|
259
|
+
|
|
260
|
+
# Filter arguments
|
|
261
|
+
filtered = {k: v for k, v in args.items() if k in param_names}
|
|
262
|
+
|
|
263
|
+
# Log filtered arguments
|
|
264
|
+
if len(filtered) != len(args):
|
|
265
|
+
filtered_out = set(args.keys()) - set(filtered.keys())
|
|
266
|
+
self.logger.debug(f"Filtered out arguments: {filtered_out}")
|
|
267
|
+
|
|
268
|
+
return filtered
|
|
269
|
+
|
|
270
|
+
except Exception as e:
|
|
271
|
+
self.logger.warning(f"Failed to filter constructor args: {e}")
|
|
272
|
+
return args
|
|
273
|
+
|
|
274
|
+
def get_registered_services(self) -> Dict[str, str]:
|
|
275
|
+
"""
|
|
276
|
+
Get list of registered services.
|
|
277
|
+
|
|
278
|
+
Returns:
|
|
279
|
+
Dictionary mapping service names to class names
|
|
280
|
+
"""
|
|
281
|
+
return {
|
|
282
|
+
name: cls.__name__
|
|
283
|
+
for name, cls in self._registered_services.items()
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
def clear_registrations(self) -> None:
|
|
287
|
+
"""Clear all service registrations."""
|
|
288
|
+
self._registered_services.clear()
|
|
289
|
+
self.logger.debug("Cleared all service registrations")
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
# Global factory instance
|
|
293
|
+
_global_factory = ServiceFactory()
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
def get_service_factory() -> ServiceFactory:
|
|
297
|
+
"""Get global service factory instance."""
|
|
298
|
+
return _global_factory
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
def create_service(service_class: Type[T], **kwargs) -> T:
|
|
302
|
+
"""Convenience function to create service using global factory."""
|
|
303
|
+
return _global_factory.create_service(service_class, **kwargs)
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
def register_service(service_name: str, service_class: Type) -> None:
|
|
307
|
+
"""Convenience function to register service with global factory."""
|
|
308
|
+
_global_factory.register_service(service_name, service_class)
|
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: claude-mpm
|
|
3
|
-
Version: 4.0.
|
|
4
|
-
Summary: Claude Multi-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
Author-email: bob@matsuoka.com
|
|
3
|
+
Version: 4.0.28
|
|
4
|
+
Summary: Claude Multi-Agent Project Manager - Orchestrate Claude with agent delegation and ticket tracking
|
|
5
|
+
Author-email: Bob Matsuoka <bob@matsuoka.com>
|
|
6
|
+
Maintainer: Claude MPM Team
|
|
8
7
|
License: MIT
|
|
8
|
+
Project-URL: Homepage, https://github.com/bobmatnyc/claude-mpm
|
|
9
|
+
Project-URL: Repository, https://github.com/bobmatnyc/claude-mpm.git
|
|
10
|
+
Project-URL: Issues, https://github.com/bobmatnyc/claude-mpm/issues
|
|
11
|
+
Project-URL: Documentation, https://github.com/bobmatnyc/claude-mpm/blob/main/README.md
|
|
9
12
|
Keywords: claude,orchestration,multi-agent,ticket-management
|
|
10
13
|
Classifier: Development Status :: 3 - Alpha
|
|
11
14
|
Classifier: Intended Audience :: Developers
|
|
12
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
13
15
|
Classifier: Programming Language :: Python :: 3
|
|
14
16
|
Classifier: Programming Language :: Python :: 3.8
|
|
15
17
|
Classifier: Programming Language :: Python :: 3.9
|
|
@@ -29,16 +31,21 @@ Requires-Dist: requests>=2.25.0
|
|
|
29
31
|
Requires-Dist: flask>=3.0.0
|
|
30
32
|
Requires-Dist: flask-cors>=4.0.0
|
|
31
33
|
Requires-Dist: watchdog>=3.0.0
|
|
32
|
-
Requires-Dist: tree-sitter>=0.21.0
|
|
33
34
|
Requires-Dist: python-socketio>=5.11.0
|
|
34
35
|
Requires-Dist: aiohttp>=3.9.0
|
|
35
36
|
Requires-Dist: aiohttp-cors<0.8.0,>=0.7.0
|
|
36
37
|
Requires-Dist: python-engineio>=4.8.0
|
|
38
|
+
Requires-Dist: aiofiles>=23.0.0
|
|
39
|
+
Requires-Dist: websockets>=12.0
|
|
37
40
|
Requires-Dist: python-frontmatter>=1.0.0
|
|
38
41
|
Requires-Dist: mistune>=3.0.0
|
|
39
|
-
Requires-Dist:
|
|
40
|
-
Requires-Dist: mcp>=0.1.0
|
|
42
|
+
Requires-Dist: tree-sitter>=0.21.0
|
|
41
43
|
Requires-Dist: ijson>=3.2.0
|
|
44
|
+
Requires-Dist: mcp>=0.1.0
|
|
45
|
+
Requires-Dist: toml>=0.10.2
|
|
46
|
+
Requires-Dist: packaging>=21.0
|
|
47
|
+
Requires-Dist: pydantic>=2.0.0
|
|
48
|
+
Requires-Dist: pydantic-settings>=2.0.0
|
|
42
49
|
Requires-Dist: importlib-resources>=5.0; python_version < "3.9"
|
|
43
50
|
Provides-Extra: dev
|
|
44
51
|
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
@@ -46,8 +53,10 @@ Requires-Dist: pytest-asyncio; extra == "dev"
|
|
|
46
53
|
Requires-Dist: pytest-cov; extra == "dev"
|
|
47
54
|
Requires-Dist: black; extra == "dev"
|
|
48
55
|
Requires-Dist: flake8; extra == "dev"
|
|
49
|
-
Requires-Dist: mypy; extra == "dev"
|
|
50
56
|
Requires-Dist: pre-commit; extra == "dev"
|
|
57
|
+
Requires-Dist: mypy>=1.0.0; extra == "dev"
|
|
58
|
+
Requires-Dist: types-PyYAML>=6.0.0; extra == "dev"
|
|
59
|
+
Requires-Dist: types-requests>=2.25.0; extra == "dev"
|
|
51
60
|
Provides-Extra: docs
|
|
52
61
|
Requires-Dist: sphinx>=7.2.0; extra == "docs"
|
|
53
62
|
Requires-Dist: sphinx-rtd-theme>=1.3.0; extra == "docs"
|
|
@@ -96,10 +105,7 @@ Requires-Dist: tree-sitter-cpp>=0.21.0; extra == "agents"
|
|
|
96
105
|
Requires-Dist: tree-sitter-c>=0.21.0; extra == "agents"
|
|
97
106
|
Requires-Dist: tree-sitter-ruby>=0.21.0; extra == "agents"
|
|
98
107
|
Requires-Dist: tree-sitter-php>=0.21.0; extra == "agents"
|
|
99
|
-
Dynamic: author-email
|
|
100
|
-
Dynamic: home-page
|
|
101
108
|
Dynamic: license-file
|
|
102
|
-
Dynamic: requires-python
|
|
103
109
|
|
|
104
110
|
# Claude MPM - Multi-Agent Project Manager
|
|
105
111
|
|