claude-mpm 4.0.22__py3-none-any.whl → 4.0.25__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 (70) hide show
  1. claude_mpm/BUILD_NUMBER +1 -1
  2. claude_mpm/VERSION +1 -1
  3. claude_mpm/agents/BASE_AGENT_TEMPLATE.md +4 -1
  4. claude_mpm/agents/BASE_PM.md +3 -0
  5. claude_mpm/agents/templates/code_analyzer.json +3 -3
  6. claude_mpm/agents/templates/data_engineer.json +2 -2
  7. claude_mpm/agents/templates/documentation.json +36 -9
  8. claude_mpm/agents/templates/engineer.json +2 -2
  9. claude_mpm/agents/templates/ops.json +2 -2
  10. claude_mpm/agents/templates/qa.json +2 -2
  11. claude_mpm/agents/templates/refactoring_engineer.json +65 -43
  12. claude_mpm/agents/templates/security.json +2 -2
  13. claude_mpm/agents/templates/version_control.json +2 -2
  14. claude_mpm/agents/templates/web_ui.json +2 -2
  15. claude_mpm/cli/commands/agents.py +453 -113
  16. claude_mpm/cli/commands/aggregate.py +107 -15
  17. claude_mpm/cli/commands/cleanup.py +142 -10
  18. claude_mpm/cli/commands/config.py +358 -224
  19. claude_mpm/cli/commands/info.py +184 -75
  20. claude_mpm/cli/commands/mcp_command_router.py +5 -76
  21. claude_mpm/cli/commands/mcp_install_commands.py +68 -36
  22. claude_mpm/cli/commands/mcp_server_commands.py +30 -37
  23. claude_mpm/cli/commands/memory.py +331 -61
  24. claude_mpm/cli/commands/monitor.py +101 -7
  25. claude_mpm/cli/commands/run.py +368 -8
  26. claude_mpm/cli/commands/tickets.py +206 -24
  27. claude_mpm/cli/parsers/mcp_parser.py +3 -0
  28. claude_mpm/cli/shared/__init__.py +40 -0
  29. claude_mpm/cli/shared/argument_patterns.py +212 -0
  30. claude_mpm/cli/shared/command_base.py +234 -0
  31. claude_mpm/cli/shared/error_handling.py +238 -0
  32. claude_mpm/cli/shared/output_formatters.py +231 -0
  33. claude_mpm/config/agent_config.py +29 -8
  34. claude_mpm/core/container.py +6 -4
  35. claude_mpm/core/framework_loader.py +32 -9
  36. claude_mpm/core/service_registry.py +4 -2
  37. claude_mpm/core/shared/__init__.py +17 -0
  38. claude_mpm/core/shared/config_loader.py +320 -0
  39. claude_mpm/core/shared/path_resolver.py +277 -0
  40. claude_mpm/core/shared/singleton_manager.py +208 -0
  41. claude_mpm/hooks/claude_hooks/memory_integration.py +4 -2
  42. claude_mpm/hooks/claude_hooks/response_tracking.py +14 -3
  43. claude_mpm/hooks/memory_integration_hook.py +11 -2
  44. claude_mpm/services/agents/deployment/agent_deployment.py +43 -23
  45. claude_mpm/services/agents/deployment/deployment_wrapper.py +71 -0
  46. claude_mpm/services/agents/deployment/pipeline/pipeline_context.py +1 -0
  47. claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +43 -0
  48. claude_mpm/services/agents/deployment/processors/agent_deployment_context.py +4 -0
  49. claude_mpm/services/agents/deployment/processors/agent_processor.py +1 -1
  50. claude_mpm/services/agents/loading/base_agent_manager.py +11 -3
  51. claude_mpm/services/agents/registry/deployed_agent_discovery.py +14 -5
  52. claude_mpm/services/event_aggregator.py +4 -2
  53. claude_mpm/services/mcp_gateway/config/config_loader.py +89 -28
  54. claude_mpm/services/mcp_gateway/config/configuration.py +29 -0
  55. claude_mpm/services/mcp_gateway/registry/service_registry.py +22 -5
  56. claude_mpm/services/memory/builder.py +6 -1
  57. claude_mpm/services/response_tracker.py +3 -1
  58. claude_mpm/services/runner_configuration_service.py +15 -6
  59. claude_mpm/services/shared/__init__.py +20 -0
  60. claude_mpm/services/shared/async_service_base.py +219 -0
  61. claude_mpm/services/shared/config_service_base.py +292 -0
  62. claude_mpm/services/shared/lifecycle_service_base.py +317 -0
  63. claude_mpm/services/shared/manager_base.py +303 -0
  64. claude_mpm/services/shared/service_factory.py +308 -0
  65. {claude_mpm-4.0.22.dist-info → claude_mpm-4.0.25.dist-info}/METADATA +19 -13
  66. {claude_mpm-4.0.22.dist-info → claude_mpm-4.0.25.dist-info}/RECORD +70 -54
  67. {claude_mpm-4.0.22.dist-info → claude_mpm-4.0.25.dist-info}/WHEEL +0 -0
  68. {claude_mpm-4.0.22.dist-info → claude_mpm-4.0.25.dist-info}/entry_points.txt +0 -0
  69. {claude_mpm-4.0.22.dist-info → claude_mpm-4.0.25.dist-info}/licenses/LICENSE +0 -0
  70. {claude_mpm-4.0.22.dist-info → claude_mpm-4.0.25.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.22
4
- Summary: Claude Multi-agent Project Manager - Clean orchestration with ticket management
5
- Home-page: https://github.com/bobmatnyc/claude-mpm
6
- Author: Claude MPM Team
7
- Author-email: bob@matsuoka.com
3
+ Version: 4.0.25
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: aiofiles>=23.0.0
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