claude-mpm 3.4.27__py3-none-any.whl → 3.5.1__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 (123) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/INSTRUCTIONS.md +182 -299
  3. claude_mpm/agents/agent_loader.py +283 -57
  4. claude_mpm/agents/agent_loader_integration.py +6 -9
  5. claude_mpm/agents/base_agent.json +2 -1
  6. claude_mpm/agents/base_agent_loader.py +1 -1
  7. claude_mpm/cli/__init__.py +5 -7
  8. claude_mpm/cli/commands/__init__.py +0 -2
  9. claude_mpm/cli/commands/agents.py +1 -1
  10. claude_mpm/cli/commands/memory.py +1 -1
  11. claude_mpm/cli/commands/run.py +12 -0
  12. claude_mpm/cli/parser.py +0 -13
  13. claude_mpm/cli/utils.py +1 -1
  14. claude_mpm/config/__init__.py +44 -2
  15. claude_mpm/config/agent_config.py +348 -0
  16. claude_mpm/config/paths.py +322 -0
  17. claude_mpm/constants.py +0 -1
  18. claude_mpm/core/__init__.py +2 -5
  19. claude_mpm/core/agent_registry.py +63 -17
  20. claude_mpm/core/claude_runner.py +354 -43
  21. claude_mpm/core/config.py +7 -1
  22. claude_mpm/core/config_aliases.py +4 -3
  23. claude_mpm/core/config_paths.py +151 -0
  24. claude_mpm/core/factories.py +4 -50
  25. claude_mpm/core/logger.py +11 -13
  26. claude_mpm/core/service_registry.py +2 -2
  27. claude_mpm/dashboard/static/js/components/agent-inference.js +101 -25
  28. claude_mpm/dashboard/static/js/components/event-processor.js +3 -2
  29. claude_mpm/hooks/claude_hooks/hook_handler.py +343 -83
  30. claude_mpm/hooks/memory_integration_hook.py +1 -1
  31. claude_mpm/init.py +37 -6
  32. claude_mpm/scripts/socketio_daemon.py +6 -2
  33. claude_mpm/services/__init__.py +71 -3
  34. claude_mpm/services/agents/__init__.py +85 -0
  35. claude_mpm/services/agents/deployment/__init__.py +21 -0
  36. claude_mpm/services/{agent_deployment.py → agents/deployment/agent_deployment.py} +192 -41
  37. claude_mpm/services/{agent_lifecycle_manager.py → agents/deployment/agent_lifecycle_manager.py} +11 -10
  38. claude_mpm/services/agents/loading/__init__.py +11 -0
  39. claude_mpm/services/{agent_profile_loader.py → agents/loading/agent_profile_loader.py} +9 -8
  40. claude_mpm/services/{base_agent_manager.py → agents/loading/base_agent_manager.py} +2 -2
  41. claude_mpm/services/{framework_agent_loader.py → agents/loading/framework_agent_loader.py} +116 -40
  42. claude_mpm/services/agents/management/__init__.py +9 -0
  43. claude_mpm/services/{agent_management_service.py → agents/management/agent_management_service.py} +6 -5
  44. claude_mpm/services/agents/memory/__init__.py +21 -0
  45. claude_mpm/services/{agent_memory_manager.py → agents/memory/agent_memory_manager.py} +3 -3
  46. claude_mpm/services/agents/registry/__init__.py +29 -0
  47. claude_mpm/services/{agent_registry.py → agents/registry/agent_registry.py} +101 -16
  48. claude_mpm/services/{deployed_agent_discovery.py → agents/registry/deployed_agent_discovery.py} +12 -2
  49. claude_mpm/services/{agent_modification_tracker.py → agents/registry/modification_tracker.py} +6 -5
  50. claude_mpm/services/async_session_logger.py +584 -0
  51. claude_mpm/services/claude_session_logger.py +299 -0
  52. claude_mpm/services/framework_claude_md_generator/content_assembler.py +2 -2
  53. claude_mpm/services/framework_claude_md_generator/section_generators/agents.py +17 -17
  54. claude_mpm/services/framework_claude_md_generator/section_generators/claude_pm_init.py +3 -3
  55. claude_mpm/services/framework_claude_md_generator/section_generators/core_responsibilities.py +1 -1
  56. claude_mpm/services/framework_claude_md_generator/section_generators/orchestration_principles.py +1 -1
  57. claude_mpm/services/framework_claude_md_generator/section_generators/todo_task_tools.py +19 -24
  58. claude_mpm/services/framework_claude_md_generator/section_generators/troubleshooting.py +1 -1
  59. claude_mpm/services/framework_claude_md_generator.py +4 -2
  60. claude_mpm/services/memory/__init__.py +17 -0
  61. claude_mpm/services/{memory_builder.py → memory/builder.py} +3 -3
  62. claude_mpm/services/memory/cache/__init__.py +14 -0
  63. claude_mpm/services/{shared_prompt_cache.py → memory/cache/shared_prompt_cache.py} +1 -1
  64. claude_mpm/services/memory/cache/simple_cache.py +317 -0
  65. claude_mpm/services/{memory_optimizer.py → memory/optimizer.py} +1 -1
  66. claude_mpm/services/{memory_router.py → memory/router.py} +1 -1
  67. claude_mpm/services/optimized_hook_service.py +542 -0
  68. claude_mpm/services/project_registry.py +14 -8
  69. claude_mpm/services/response_tracker.py +237 -0
  70. claude_mpm/services/ticketing_service_original.py +4 -2
  71. claude_mpm/services/version_control/branch_strategy.py +3 -1
  72. claude_mpm/utils/paths.py +12 -10
  73. claude_mpm/utils/session_logging.py +114 -0
  74. claude_mpm/validation/agent_validator.py +2 -1
  75. {claude_mpm-3.4.27.dist-info → claude_mpm-3.5.1.dist-info}/METADATA +28 -20
  76. {claude_mpm-3.4.27.dist-info → claude_mpm-3.5.1.dist-info}/RECORD +83 -106
  77. claude_mpm/cli/commands/ui.py +0 -57
  78. claude_mpm/core/simple_runner.py +0 -1046
  79. claude_mpm/hooks/builtin/__init__.py +0 -1
  80. claude_mpm/hooks/builtin/logging_hook_example.py +0 -165
  81. claude_mpm/hooks/builtin/memory_hooks_example.py +0 -67
  82. claude_mpm/hooks/builtin/mpm_command_hook.py +0 -125
  83. claude_mpm/hooks/builtin/post_delegation_hook_example.py +0 -124
  84. claude_mpm/hooks/builtin/pre_delegation_hook_example.py +0 -125
  85. claude_mpm/hooks/builtin/submit_hook_example.py +0 -100
  86. claude_mpm/hooks/builtin/ticket_extraction_hook_example.py +0 -237
  87. claude_mpm/hooks/builtin/todo_agent_prefix_hook.py +0 -240
  88. claude_mpm/hooks/builtin/workflow_start_hook.py +0 -181
  89. claude_mpm/orchestration/__init__.py +0 -6
  90. claude_mpm/orchestration/archive/direct_orchestrator.py +0 -195
  91. claude_mpm/orchestration/archive/factory.py +0 -215
  92. claude_mpm/orchestration/archive/hook_enabled_orchestrator.py +0 -188
  93. claude_mpm/orchestration/archive/hook_integration_example.py +0 -178
  94. claude_mpm/orchestration/archive/interactive_subprocess_orchestrator.py +0 -826
  95. claude_mpm/orchestration/archive/orchestrator.py +0 -501
  96. claude_mpm/orchestration/archive/pexpect_orchestrator.py +0 -252
  97. claude_mpm/orchestration/archive/pty_orchestrator.py +0 -270
  98. claude_mpm/orchestration/archive/simple_orchestrator.py +0 -82
  99. claude_mpm/orchestration/archive/subprocess_orchestrator.py +0 -801
  100. claude_mpm/orchestration/archive/system_prompt_orchestrator.py +0 -278
  101. claude_mpm/orchestration/archive/wrapper_orchestrator.py +0 -187
  102. claude_mpm/schemas/workflow_validator.py +0 -411
  103. claude_mpm/services/parent_directory_manager/__init__.py +0 -577
  104. claude_mpm/services/parent_directory_manager/backup_manager.py +0 -258
  105. claude_mpm/services/parent_directory_manager/config_manager.py +0 -210
  106. claude_mpm/services/parent_directory_manager/deduplication_manager.py +0 -279
  107. claude_mpm/services/parent_directory_manager/framework_protector.py +0 -143
  108. claude_mpm/services/parent_directory_manager/operations.py +0 -186
  109. claude_mpm/services/parent_directory_manager/state_manager.py +0 -624
  110. claude_mpm/services/parent_directory_manager/template_deployer.py +0 -579
  111. claude_mpm/services/parent_directory_manager/validation_manager.py +0 -378
  112. claude_mpm/services/parent_directory_manager/version_control_helper.py +0 -339
  113. claude_mpm/services/parent_directory_manager/version_manager.py +0 -222
  114. claude_mpm/ui/__init__.py +0 -1
  115. claude_mpm/ui/rich_terminal_ui.py +0 -295
  116. claude_mpm/ui/terminal_ui.py +0 -328
  117. /claude_mpm/services/{agent_versioning.py → agents/deployment/agent_versioning.py} +0 -0
  118. /claude_mpm/services/{agent_capabilities_generator.py → agents/management/agent_capabilities_generator.py} +0 -0
  119. /claude_mpm/services/{agent_persistence_service.py → agents/memory/agent_persistence_service.py} +0 -0
  120. {claude_mpm-3.4.27.dist-info → claude_mpm-3.5.1.dist-info}/WHEEL +0 -0
  121. {claude_mpm-3.4.27.dist-info → claude_mpm-3.5.1.dist-info}/entry_points.txt +0 -0
  122. {claude_mpm-3.4.27.dist-info → claude_mpm-3.5.1.dist-info}/licenses/LICENSE +0 -0
  123. {claude_mpm-3.4.27.dist-info → claude_mpm-3.5.1.dist-info}/top_level.txt +0 -0
@@ -1,378 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- Validation Manager - Handles validation and compatibility checks
4
- ================================================================================
5
-
6
- This module manages validation of parent directories, subsystem compatibility,
7
- and version comparisons.
8
- """
9
-
10
- import os
11
- from pathlib import Path
12
- from typing import Dict, Any, Optional, List, Tuple
13
- from datetime import datetime
14
- import logging
15
-
16
- from .state_manager import ParentDirectoryOperation, ParentDirectoryAction
17
- from ...utils.path_operations import path_ops
18
-
19
-
20
- class ValidationManager:
21
- """Manages validation and compatibility checks."""
22
-
23
- def __init__(self, logger: Optional[logging.Logger] = None):
24
- """
25
- Initialize the Validation Manager.
26
-
27
- Args:
28
- logger: Logger instance to use
29
- """
30
- self.logger = logger or logging.getLogger(__name__)
31
-
32
- async def validate_parent_directory(
33
- self,
34
- target_directory: Path,
35
- managed_directories: Dict[str, Any],
36
- template_manager: Optional[Any] = None
37
- ) -> ParentDirectoryOperation:
38
- """
39
- Validate a parent directory's template.
40
-
41
- Args:
42
- target_directory: Directory to validate
43
- managed_directories: Dictionary of managed directories
44
- template_manager: Template manager instance (optional)
45
-
46
- Returns:
47
- ParentDirectoryOperation result
48
- """
49
- try:
50
- # Check for INSTRUCTIONS.md first, then CLAUDE.md
51
- target_file = target_directory / "INSTRUCTIONS.md"
52
- if not path_ops.validate_exists(target_file):
53
- target_file = target_directory / "CLAUDE.md"
54
-
55
- if not path_ops.validate_exists(target_file):
56
- return ParentDirectoryOperation(
57
- action=ParentDirectoryAction.VALIDATE,
58
- target_path=target_file,
59
- success=False,
60
- error_message="INSTRUCTIONS.md/CLAUDE.md file not found",
61
- )
62
-
63
- # Check if managed
64
- directory_key = str(target_directory)
65
- if directory_key not in managed_directories:
66
- return ParentDirectoryOperation(
67
- action=ParentDirectoryAction.VALIDATE,
68
- target_path=target_file,
69
- success=True,
70
- warnings=["Directory not managed by Parent Directory Manager"],
71
- )
72
-
73
- config = managed_directories[directory_key]
74
-
75
- # Validate template if template manager available
76
- validation_errors = []
77
- validation_warnings = []
78
-
79
- # template_manager removed - use Claude Code Task Tool instead
80
- rendered_content = None
81
-
82
- if rendered_content:
83
- # Compare with actual content
84
- actual_content = path_ops.safe_read(target_file)
85
- if not actual_content:
86
- return ParentDirectoryOperation(
87
- action=ParentDirectoryAction.VALIDATE,
88
- target_path=target_file,
89
- success=False,
90
- error_message="Failed to read file content",
91
- )
92
-
93
- if actual_content != rendered_content:
94
- validation_warnings.append("Content differs from expected template output")
95
- else:
96
- validation_errors.append("Failed to render template for validation")
97
-
98
- # Check file permissions
99
- if not os.access(target_file, os.R_OK):
100
- validation_errors.append("File is not readable")
101
-
102
- if not os.access(target_file, os.W_OK):
103
- validation_warnings.append("File is not writable")
104
-
105
- # Create operation result
106
- operation = ParentDirectoryOperation(
107
- action=ParentDirectoryAction.VALIDATE,
108
- target_path=target_file,
109
- success=len(validation_errors) == 0,
110
- template_id=config.template_id,
111
- error_message="; ".join(validation_errors) if validation_errors else None,
112
- warnings=validation_warnings,
113
- )
114
-
115
- return operation
116
-
117
- except Exception as e:
118
- self.logger.error(f"Failed to validate parent directory {target_directory}: {e}")
119
- return ParentDirectoryOperation(
120
- action=ParentDirectoryAction.VALIDATE,
121
- # Try to determine which file would be used
122
- target_file = target_directory / "INSTRUCTIONS.md"
123
- if not path_ops.validate_exists(target_file):
124
- target_file = target_directory / "CLAUDE.md"
125
- return ParentDirectoryOperation(
126
- action=ParentDirectoryAction.VALIDATE,
127
- target_path=target_file,
128
- success=False,
129
- success=False,
130
- error_message=str(e),
131
- )
132
-
133
- async def validate_subsystem_compatibility(
134
- self,
135
- required_versions: Dict[str, str],
136
- get_subsystem_version_func
137
- ) -> Dict[str, Any]:
138
- """
139
- Validate subsystem version compatibility against requirements.
140
-
141
- Args:
142
- required_versions: Dictionary of subsystem -> required version
143
- get_subsystem_version_func: Function to get current subsystem version
144
-
145
- Returns:
146
- Validation results with compatibility status
147
- """
148
- try:
149
- results = {
150
- "compatible": True,
151
- "validation_timestamp": datetime.now().isoformat(),
152
- "subsystem_checks": {}
153
- }
154
-
155
- for subsystem, required_version in required_versions.items():
156
- current_version = get_subsystem_version_func(subsystem)
157
-
158
- check_result = {
159
- "subsystem": subsystem,
160
- "required_version": required_version,
161
- "current_version": current_version,
162
- "compatible": False,
163
- "status": "unknown"
164
- }
165
-
166
- if current_version is None or current_version in ["unknown", "not_found"]:
167
- check_result["status"] = "missing"
168
- results["compatible"] = False
169
- elif current_version == required_version:
170
- check_result["compatible"] = True
171
- check_result["status"] = "exact_match"
172
- else:
173
- # Try version comparison for compatibility
174
- try:
175
- comparison = self.compare_subsystem_versions(current_version, required_version)
176
- if comparison >= 0:
177
- check_result["compatible"] = True
178
- check_result["status"] = "compatible" if comparison > 0 else "exact_match"
179
- else:
180
- check_result["status"] = "outdated"
181
- results["compatible"] = False
182
- except Exception as comp_error:
183
- check_result["status"] = "comparison_failed"
184
- check_result["error"] = str(comp_error)
185
- results["compatible"] = False
186
-
187
- results["subsystem_checks"][subsystem] = check_result
188
-
189
- return results
190
-
191
- except Exception as e:
192
- self.logger.error(f"Failed to validate subsystem compatibility: {e}")
193
- return {
194
- "compatible": False,
195
- "error": str(e),
196
- "validation_timestamp": datetime.now().isoformat()
197
- }
198
-
199
- def compare_subsystem_versions(self, version1: str, version2: str) -> int:
200
- """
201
- Compare two subsystem version strings.
202
- Supports serial number format (001, 002, etc.).
203
-
204
- Args:
205
- version1: First version string
206
- version2: Second version string
207
-
208
- Returns:
209
- -1 if version1 < version2
210
- 0 if version1 == version2
211
- 1 if version1 > version2
212
- """
213
- try:
214
- # Handle serial number format (001, 002, etc.)
215
- if version1.isdigit() and version2.isdigit():
216
- v1_num = int(version1)
217
- v2_num = int(version2)
218
- if v1_num < v2_num:
219
- return -1
220
- elif v1_num > v2_num:
221
- return 1
222
- else:
223
- return 0
224
-
225
- # Handle semantic versioning (x.y.z)
226
- if "." in version1 and "." in version2:
227
- v1_parts = [int(x) for x in version1.split(".")]
228
- v2_parts = [int(x) for x in version2.split(".")]
229
-
230
- # Pad shorter version with zeros
231
- max_len = max(len(v1_parts), len(v2_parts))
232
- v1_parts.extend([0] * (max_len - len(v1_parts)))
233
- v2_parts.extend([0] * (max_len - len(v2_parts)))
234
-
235
- for i in range(max_len):
236
- if v1_parts[i] < v2_parts[i]:
237
- return -1
238
- elif v1_parts[i] > v2_parts[i]:
239
- return 1
240
-
241
- return 0
242
-
243
- # String comparison fallback
244
- if version1 < version2:
245
- return -1
246
- elif version1 > version2:
247
- return 1
248
- else:
249
- return 0
250
-
251
- except Exception as e:
252
- self.logger.error(f"Failed to compare subsystem versions {version1} vs {version2}: {e}")
253
- # If comparison fails, assume versions are different
254
- return -1 if version1 != version2 else 0
255
-
256
- def validate_framework_template_integrity(self, framework_path: Path) -> bool:
257
- """
258
- Validate that the framework template exists and has expected content.
259
-
260
- Args:
261
- framework_path: Path to framework
262
-
263
- Returns:
264
- True if framework template is valid, False otherwise
265
- """
266
- try:
267
- # Try INSTRUCTIONS.md first, then fall back to CLAUDE.md
268
- framework_template_path = framework_path / "agents" / "INSTRUCTIONS.md"
269
- if not path_ops.validate_exists(framework_template_path):
270
- framework_template_path = framework_path / "agents" / "CLAUDE.md"
271
-
272
- if not path_ops.validate_exists(framework_template_path):
273
- self.logger.error(f"Framework template does not exist: {framework_template_path}")
274
- return False
275
-
276
- if not path_ops.validate_is_file(framework_template_path):
277
- self.logger.error(f"Framework template path is not a file: {framework_template_path}")
278
- return False
279
-
280
- # Read and validate content
281
- content = path_ops.safe_read(framework_template_path)
282
- if not content:
283
- self.logger.error(f"Failed to read framework template at {framework_template_path}")
284
- return False
285
-
286
- if len(content.strip()) == 0:
287
- self.logger.error(f"Framework template is empty: {framework_template_path}")
288
- return False
289
-
290
- # Check for critical content markers
291
- critical_markers = [
292
- "AI ASSISTANT ROLE DESIGNATION",
293
- "CLAUDE_MD_VERSION:",
294
- "Framework Context"
295
- ]
296
-
297
- missing_critical = [marker for marker in critical_markers if marker not in content]
298
-
299
- if missing_critical:
300
- self.logger.error(f"Framework template missing critical content: {missing_critical}")
301
- return False
302
-
303
- self.logger.debug(f"Framework template integrity verified: {framework_template_path}")
304
- return True
305
-
306
- except Exception as e:
307
- self.logger.error(f"Failed to validate framework template integrity: {e}")
308
- return False
309
-
310
- async def validate_deployment_context(
311
- self,
312
- deployment_aware: bool,
313
- dependency_manager: Optional[Any] = None
314
- ) -> Optional[Dict[str, Any]]:
315
- """
316
- Validate deployment context using CMPM-101.
317
-
318
- Args:
319
- deployment_aware: Whether to check deployment context
320
- dependency_manager: Dependency manager instance
321
-
322
- Returns:
323
- Deployment context or None
324
- """
325
- try:
326
- if not deployment_aware:
327
- return None
328
-
329
- # Use dependency manager to get deployment context
330
- # dependency_manager removed - use Claude Code Task Tool instead
331
- deployment_config = None
332
- if deployment_config:
333
- self.logger.info(
334
- f"Deployment context validated: {deployment_config.get('strategy', 'unknown')}"
335
- )
336
- return deployment_config
337
- else:
338
- self.logger.warning("No deployment context available - dependency manager removed")
339
- return None
340
-
341
- except Exception as e:
342
- self.logger.error(f"Failed to validate deployment context: {e}")
343
- return None
344
-
345
- def should_skip_deployment(
346
- self,
347
- target_file: Path,
348
- template_content: str,
349
- force: bool,
350
- template_deployer
351
- ) -> Tuple[bool, Optional[str], bool]:
352
- """
353
- Check if deployment should be skipped based on file type and version comparison.
354
-
355
- Args:
356
- target_file: Target file path
357
- template_content: Template content to deploy
358
- force: Force deployment flag
359
- template_deployer: Template deployer instance
360
-
361
- Returns:
362
- Tuple of (should_skip, reason, is_permanent_protection)
363
- """
364
- should_skip, reason = template_deployer.should_skip_deployment(
365
- target_file, template_content, force
366
- )
367
-
368
- # Check for permanent protection
369
- is_permanent_protection = False
370
- if path_ops.validate_exists(target_file) and should_skip:
371
- existing_content = path_ops.safe_read(target_file)
372
- if not existing_content:
373
- return False, "Failed to read existing file content"
374
- if not template_deployer.is_framework_deployment_template(existing_content):
375
- is_permanent_protection = True
376
- reason = "Existing file is not a framework deployment template"
377
-
378
- return should_skip, reason, is_permanent_protection