claude-mpm 4.5.11__py3-none-any.whl → 4.5.13__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 (190) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/BASE_ENGINEER.md +47 -0
  3. claude_mpm/agents/BASE_QA.md +60 -0
  4. claude_mpm/agents/frontmatter_validator.py +4 -4
  5. claude_mpm/agents/templates/nextjs_engineer.json +2 -2
  6. claude_mpm/agents/templates/qa.json +13 -3
  7. claude_mpm/agents/templates/react_engineer.json +2 -2
  8. claude_mpm/agents/templates/typescript_engineer.json +2 -2
  9. claude_mpm/agents/templates/web_qa.json +14 -3
  10. claude_mpm/cli/commands/agent_manager.py +3 -3
  11. claude_mpm/cli/commands/agents.py +6 -6
  12. claude_mpm/cli/commands/aggregate.py +4 -4
  13. claude_mpm/cli/commands/analyze.py +2 -2
  14. claude_mpm/cli/commands/analyze_code.py +1 -1
  15. claude_mpm/cli/commands/cleanup.py +3 -3
  16. claude_mpm/cli/commands/config.py +2 -2
  17. claude_mpm/cli/commands/configure.py +14 -14
  18. claude_mpm/cli/commands/dashboard.py +1 -1
  19. claude_mpm/cli/commands/debug.py +3 -3
  20. claude_mpm/cli/commands/doctor.py +1 -1
  21. claude_mpm/cli/commands/mcp.py +7 -7
  22. claude_mpm/cli/commands/mcp_command_router.py +1 -1
  23. claude_mpm/cli/commands/mcp_config.py +2 -2
  24. claude_mpm/cli/commands/mcp_external_commands.py +2 -2
  25. claude_mpm/cli/commands/mcp_install_commands.py +3 -3
  26. claude_mpm/cli/commands/mcp_pipx_config.py +2 -2
  27. claude_mpm/cli/commands/mcp_setup_external.py +3 -3
  28. claude_mpm/cli/commands/monitor.py +1 -1
  29. claude_mpm/cli/commands/mpm_init_handler.py +1 -1
  30. claude_mpm/cli/interactive/agent_wizard.py +1 -1
  31. claude_mpm/cli/parsers/search_parser.py +1 -1
  32. claude_mpm/cli/shared/argument_patterns.py +2 -2
  33. claude_mpm/cli/shared/base_command.py +1 -1
  34. claude_mpm/cli/startup_logging.py +6 -4
  35. claude_mpm/config/experimental_features.py +4 -4
  36. claude_mpm/config/socketio_config.py +2 -2
  37. claude_mpm/core/agent_session_manager.py +2 -2
  38. claude_mpm/core/api_validator.py +3 -3
  39. claude_mpm/core/base_service.py +10 -1
  40. claude_mpm/core/cache.py +2 -2
  41. claude_mpm/core/config.py +4 -4
  42. claude_mpm/core/config_aliases.py +4 -4
  43. claude_mpm/core/config_constants.py +1 -1
  44. claude_mpm/core/error_handler.py +1 -1
  45. claude_mpm/core/file_utils.py +5 -5
  46. claude_mpm/core/framework/formatters/capability_generator.py +5 -5
  47. claude_mpm/core/framework/loaders/agent_loader.py +1 -1
  48. claude_mpm/core/framework/processors/metadata_processor.py +1 -1
  49. claude_mpm/core/framework/processors/template_processor.py +3 -3
  50. claude_mpm/core/framework_loader.py +2 -2
  51. claude_mpm/core/log_manager.py +4 -4
  52. claude_mpm/core/logger.py +2 -2
  53. claude_mpm/core/optimized_startup.py +1 -1
  54. claude_mpm/core/output_style_manager.py +1 -1
  55. claude_mpm/core/service_registry.py +2 -2
  56. claude_mpm/core/session_manager.py +3 -3
  57. claude_mpm/core/shared/config_loader.py +1 -1
  58. claude_mpm/core/socketio_pool.py +2 -2
  59. claude_mpm/core/unified_agent_registry.py +2 -2
  60. claude_mpm/core/unified_config.py +6 -6
  61. claude_mpm/core/unified_paths.py +2 -2
  62. claude_mpm/dashboard/api/simple_directory.py +1 -1
  63. claude_mpm/generators/agent_profile_generator.py +1 -1
  64. claude_mpm/hooks/claude_hooks/event_handlers.py +2 -2
  65. claude_mpm/hooks/claude_hooks/installer.py +9 -9
  66. claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +7 -2
  67. claude_mpm/hooks/claude_hooks/tool_analysis.py +2 -2
  68. claude_mpm/hooks/memory_integration_hook.py +1 -1
  69. claude_mpm/hooks/validation_hooks.py +1 -1
  70. claude_mpm/init.py +4 -4
  71. claude_mpm/models/agent_session.py +1 -1
  72. claude_mpm/scripts/socketio_daemon.py +5 -5
  73. claude_mpm/services/__init__.py +2 -2
  74. claude_mpm/services/agent_capabilities_service.py +1 -1
  75. claude_mpm/services/agents/agent_builder.py +6 -4
  76. claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +1 -1
  77. claude_mpm/services/agents/deployment/agent_metrics_collector.py +1 -1
  78. claude_mpm/services/agents/deployment/agent_record_service.py +3 -3
  79. claude_mpm/services/agents/deployment/deployment_wrapper.py +1 -1
  80. claude_mpm/services/agents/deployment/pipeline/steps/target_directory_step.py +2 -2
  81. claude_mpm/services/agents/loading/agent_profile_loader.py +2 -2
  82. claude_mpm/services/agents/local_template_manager.py +5 -5
  83. claude_mpm/services/agents/registry/deployed_agent_discovery.py +1 -1
  84. claude_mpm/services/agents/registry/modification_tracker.py +19 -11
  85. claude_mpm/services/async_session_logger.py +1 -1
  86. claude_mpm/services/claude_session_logger.py +1 -1
  87. claude_mpm/services/cli/agent_listing_service.py +3 -3
  88. claude_mpm/services/cli/agent_validation_service.py +1 -1
  89. claude_mpm/services/cli/session_manager.py +2 -2
  90. claude_mpm/services/core/path_resolver.py +1 -1
  91. claude_mpm/services/diagnostics/checks/agent_check.py +1 -1
  92. claude_mpm/services/diagnostics/checks/claude_code_check.py +2 -2
  93. claude_mpm/services/diagnostics/checks/common_issues_check.py +3 -3
  94. claude_mpm/services/diagnostics/checks/configuration_check.py +2 -2
  95. claude_mpm/services/diagnostics/checks/installation_check.py +1 -1
  96. claude_mpm/services/diagnostics/checks/mcp_check.py +1 -1
  97. claude_mpm/services/diagnostics/checks/mcp_services_check.py +9 -9
  98. claude_mpm/services/diagnostics/checks/monitor_check.py +1 -1
  99. claude_mpm/services/diagnostics/doctor_reporter.py +1 -1
  100. claude_mpm/services/event_aggregator.py +1 -1
  101. claude_mpm/services/event_bus/event_bus.py +9 -2
  102. claude_mpm/services/events/consumers/dead_letter.py +2 -2
  103. claude_mpm/services/framework_claude_md_generator/__init__.py +1 -1
  104. claude_mpm/services/framework_claude_md_generator/deployment_manager.py +3 -3
  105. claude_mpm/services/framework_claude_md_generator/version_manager.py +1 -1
  106. claude_mpm/services/hook_installer_service.py +7 -7
  107. claude_mpm/services/infrastructure/context_preservation.py +7 -7
  108. claude_mpm/services/infrastructure/daemon_manager.py +5 -5
  109. claude_mpm/services/mcp_config_manager.py +10 -10
  110. claude_mpm/services/mcp_gateway/auto_configure.py +5 -5
  111. claude_mpm/services/mcp_gateway/config/config_loader.py +2 -2
  112. claude_mpm/services/mcp_gateway/config/configuration.py +5 -3
  113. claude_mpm/services/mcp_gateway/core/process_pool.py +3 -3
  114. claude_mpm/services/mcp_gateway/core/singleton_manager.py +2 -2
  115. claude_mpm/services/mcp_gateway/core/startup_verification.py +1 -1
  116. claude_mpm/services/mcp_gateway/main.py +1 -1
  117. claude_mpm/services/mcp_gateway/registry/service_registry.py +4 -2
  118. claude_mpm/services/mcp_gateway/registry/tool_registry.py +2 -1
  119. claude_mpm/services/mcp_gateway/server/stdio_handler.py +1 -1
  120. claude_mpm/services/mcp_gateway/tools/document_summarizer.py +1 -1
  121. claude_mpm/services/mcp_gateway/tools/health_check_tool.py +1 -1
  122. claude_mpm/services/mcp_gateway/tools/hello_world.py +1 -1
  123. claude_mpm/services/mcp_gateway/utils/package_version_checker.py +5 -5
  124. claude_mpm/services/mcp_gateway/utils/update_preferences.py +2 -2
  125. claude_mpm/services/mcp_service_verifier.py +1 -1
  126. claude_mpm/services/memory/builder.py +1 -1
  127. claude_mpm/services/memory/cache/shared_prompt_cache.py +2 -1
  128. claude_mpm/services/memory/indexed_memory.py +3 -3
  129. claude_mpm/services/monitor/daemon.py +1 -1
  130. claude_mpm/services/monitor/daemon_manager.py +9 -9
  131. claude_mpm/services/monitor/handlers/file.py +1 -1
  132. claude_mpm/services/monitor/handlers/hooks.py +3 -3
  133. claude_mpm/services/monitor/management/lifecycle.py +7 -7
  134. claude_mpm/services/monitor/server.py +2 -2
  135. claude_mpm/services/orphan_detection.py +11 -16
  136. claude_mpm/services/port_manager.py +2 -2
  137. claude_mpm/services/project/analyzer.py +3 -3
  138. claude_mpm/services/project/archive_manager.py +17 -13
  139. claude_mpm/services/project/dependency_analyzer.py +4 -4
  140. claude_mpm/services/project/documentation_manager.py +4 -4
  141. claude_mpm/services/project/enhanced_analyzer.py +19 -8
  142. claude_mpm/services/project/registry.py +4 -4
  143. claude_mpm/services/project_port_allocator.py +7 -12
  144. claude_mpm/services/session_management_service.py +1 -1
  145. claude_mpm/services/socketio/event_normalizer.py +1 -1
  146. claude_mpm/services/socketio/handlers/code_analysis.py +14 -12
  147. claude_mpm/services/socketio/handlers/file.py +1 -1
  148. claude_mpm/services/socketio/migration_utils.py +1 -1
  149. claude_mpm/services/socketio/server/core.py +1 -1
  150. claude_mpm/services/unified/analyzer_strategies/code_analyzer.py +1 -1
  151. claude_mpm/services/unified/analyzer_strategies/dependency_analyzer.py +4 -4
  152. claude_mpm/services/unified/analyzer_strategies/structure_analyzer.py +1 -1
  153. claude_mpm/services/unified/config_strategies/config_schema.py +4 -4
  154. claude_mpm/services/unified/config_strategies/context_strategy.py +8 -6
  155. claude_mpm/services/unified/config_strategies/error_handling_strategy.py +10 -10
  156. claude_mpm/services/unified/config_strategies/file_loader_strategy.py +5 -5
  157. claude_mpm/services/unified/config_strategies/unified_config_service.py +8 -8
  158. claude_mpm/services/unified/config_strategies/validation_strategy.py +15 -15
  159. claude_mpm/services/unified/deployment_strategies/base.py +4 -4
  160. claude_mpm/services/unified/deployment_strategies/cloud_strategies.py +15 -15
  161. claude_mpm/services/unified/deployment_strategies/local.py +11 -11
  162. claude_mpm/services/unified/deployment_strategies/utils.py +11 -9
  163. claude_mpm/services/unified/deployment_strategies/vercel.py +7 -9
  164. claude_mpm/services/unified/unified_config.py +5 -5
  165. claude_mpm/services/unified/unified_deployment.py +2 -2
  166. claude_mpm/services/utility_service.py +1 -1
  167. claude_mpm/services/version_control/conflict_resolution.py +2 -2
  168. claude_mpm/services/version_control/git_operations.py +3 -3
  169. claude_mpm/services/version_control/semantic_versioning.py +13 -13
  170. claude_mpm/services/version_control/version_parser.py +1 -1
  171. claude_mpm/storage/state_storage.py +12 -13
  172. claude_mpm/tools/code_tree_analyzer.py +5 -5
  173. claude_mpm/tools/code_tree_builder.py +4 -4
  174. claude_mpm/tools/socketio_debug.py +1 -1
  175. claude_mpm/utils/agent_dependency_loader.py +4 -4
  176. claude_mpm/utils/common.py +2 -2
  177. claude_mpm/utils/config_manager.py +3 -3
  178. claude_mpm/utils/dependency_cache.py +2 -2
  179. claude_mpm/utils/dependency_strategies.py +6 -6
  180. claude_mpm/utils/file_utils.py +11 -11
  181. claude_mpm/utils/log_cleanup.py +1 -1
  182. claude_mpm/utils/path_operations.py +1 -1
  183. claude_mpm/validation/agent_validator.py +2 -2
  184. claude_mpm/validation/frontmatter_validator.py +1 -1
  185. {claude_mpm-4.5.11.dist-info → claude_mpm-4.5.13.dist-info}/METADATA +1 -1
  186. {claude_mpm-4.5.11.dist-info → claude_mpm-4.5.13.dist-info}/RECORD +190 -190
  187. {claude_mpm-4.5.11.dist-info → claude_mpm-4.5.13.dist-info}/WHEEL +0 -0
  188. {claude_mpm-4.5.11.dist-info → claude_mpm-4.5.13.dist-info}/entry_points.txt +0 -0
  189. {claude_mpm-4.5.11.dist-info → claude_mpm-4.5.13.dist-info}/licenses/LICENSE +0 -0
  190. {claude_mpm-4.5.11.dist-info → claude_mpm-4.5.13.dist-info}/top_level.txt +0 -0
@@ -24,6 +24,10 @@ import time
24
24
  from contextlib import contextmanager, suppress
25
25
  from typing import Any, Dict, Optional, Tuple, Union
26
26
 
27
+ from claude_mpm.core.logging_utils import get_logger
28
+
29
+ logger = get_logger(__name__)
30
+
27
31
 
28
32
  class StateStorage:
29
33
  """Reliable state storage with atomic operations."""
@@ -37,11 +41,6 @@ class StateStorage:
37
41
  self.storage_dir = storage_dir or Path.home() / ".claude-mpm" / "storage"
38
42
  self.storage_dir.mkdir(parents=True, exist_ok=True)
39
43
 
40
- # Logging
41
- from claude_mpm.core.logging_utils import get_logger
42
-
43
- logger = get_logger(__name__)
44
-
45
44
  # File locking support (Unix-like systems)
46
45
  self.supports_locking = platform.system() != "Windows"
47
46
 
@@ -80,7 +79,7 @@ logger = get_logger(__name__)
80
79
  with gzip.open(file_path, "wt", encoding="utf-8") as f:
81
80
  json.dump(data, f, indent=2, default=str)
82
81
  else:
83
- with open(file_path, "w") as f:
82
+ with file_path.open("w") as f:
84
83
  json.dump(data, f, indent=2, default=str)
85
84
 
86
85
  self.write_count += 1
@@ -119,7 +118,7 @@ logger = get_logger(__name__)
119
118
  with gzip.open(file_path, "rt", encoding="utf-8") as f:
120
119
  data = json.load(f)
121
120
  else:
122
- with open(file_path) as f:
121
+ with file_path.open() as f:
123
122
  data = json.load(f)
124
123
 
125
124
  self.read_count += 1
@@ -160,7 +159,7 @@ logger = get_logger(__name__)
160
159
  with gzip.open(file_path, "wb") as f:
161
160
  pickle.dump(data, f, protocol=pickle.HIGHEST_PROTOCOL)
162
161
  else:
163
- with open(file_path, "wb") as f:
162
+ with file_path.open("wb") as f:
164
163
  pickle.dump(data, f, protocol=pickle.HIGHEST_PROTOCOL)
165
164
 
166
165
  self.write_count += 1
@@ -199,7 +198,7 @@ logger = get_logger(__name__)
199
198
  with gzip.open(file_path, "rb") as f:
200
199
  data = pickle.load(f)
201
200
  else:
202
- with open(file_path, "rb") as f:
201
+ with file_path.open("rb") as f:
203
202
  data = pickle.load(f)
204
203
 
205
204
  self.read_count += 1
@@ -328,7 +327,7 @@ logger = get_logger(__name__)
328
327
 
329
328
  # Calculate checksum
330
329
  hasher = hashlib.sha256()
331
- with open(file_path, "rb") as f:
330
+ with file_path.open("rb") as f:
332
331
  for chunk in iter(lambda: f.read(4096), b""):
333
332
  hasher.update(chunk)
334
333
 
@@ -336,7 +335,7 @@ logger = get_logger(__name__)
336
335
 
337
336
  # Write checksum file
338
337
  checksum_path = file_path.with_suffix(file_path.suffix + ".sha256")
339
- with open(checksum_path, "w") as f:
338
+ with checksum_path.open("w") as f:
340
339
  f.write(checksum)
341
340
 
342
341
  except Exception as e:
@@ -359,12 +358,12 @@ logger = get_logger(__name__)
359
358
  return True # No checksum to verify
360
359
 
361
360
  # Read expected checksum
362
- with open(checksum_path) as f:
361
+ with checksum_path.open() as f:
363
362
  expected = f.read().strip()
364
363
 
365
364
  # Calculate actual checksum
366
365
  hasher = hashlib.sha256()
367
- with open(file_path, "rb") as f:
366
+ with file_path.open("rb") as f:
368
367
  for chunk in iter(lambda: f.read(4096), b""):
369
368
  hasher.update(chunk)
370
369
 
@@ -692,7 +692,7 @@ class MultiLanguageAnalyzer:
692
692
  nodes = []
693
693
 
694
694
  try:
695
- with open(file_path, "rb") as f:
695
+ with file_path.open("rb") as f:
696
696
  source = f.read()
697
697
 
698
698
  parser = self.parsers[language]
@@ -1099,7 +1099,7 @@ class CodeTreeAnalyzer:
1099
1099
  def _get_file_hash(self, file_path: Path) -> str:
1100
1100
  """Get hash of file contents for caching."""
1101
1101
  hasher = hashlib.md5()
1102
- with open(file_path, "rb") as f:
1102
+ with file_path.open("rb") as f:
1103
1103
  hasher.update(f.read())
1104
1104
  return hasher.hexdigest()
1105
1105
 
@@ -1166,7 +1166,7 @@ class CodeTreeAnalyzer:
1166
1166
  cache_file = self.cache_dir / "code_tree_cache.json"
1167
1167
  if cache_file.exists():
1168
1168
  try:
1169
- with open(cache_file) as f:
1169
+ with cache_file.open() as f:
1170
1170
  cache_data = json.load(f)
1171
1171
  # Reconstruct CodeNode objects
1172
1172
  for key, nodes_data in cache_data.items():
@@ -1203,7 +1203,7 @@ class CodeTreeAnalyzer:
1203
1203
  for n in nodes
1204
1204
  ]
1205
1205
 
1206
- with open(cache_file, "w") as f:
1206
+ with cache_file.open("w") as f:
1207
1207
  json.dump(cache_data, f, indent=2)
1208
1208
 
1209
1209
  self.logger.info(f"Saved cache with {len(self.cache)} entries")
@@ -1726,7 +1726,7 @@ class CodeTreeAnalyzer:
1726
1726
  },
1727
1727
  }
1728
1728
 
1729
- def _is_internal_node(self, node: CodeNode) -> bool: # noqa: PLR0911
1729
+ def _is_internal_node(self, node: CodeNode) -> bool:
1730
1730
  """Check if node is an internal function that should be filtered."""
1731
1731
  # Don't filter classes - always show them
1732
1732
  if node.node_type == "class":
@@ -81,7 +81,7 @@ class GitignoreParser:
81
81
 
82
82
  if gitignore_path.exists():
83
83
  try:
84
- with open(gitignore_path) as f:
84
+ with gitignore_path.open() as f:
85
85
  for line in f:
86
86
  line = line.strip()
87
87
  # Skip comments and empty lines
@@ -481,7 +481,7 @@ class CodeTreeBuilder:
481
481
  hasher = hashlib.md5()
482
482
 
483
483
  try:
484
- with open(path, "rb") as f:
484
+ with path.open("rb") as f:
485
485
  # Read in chunks for large files
486
486
  while chunk := f.read(8192):
487
487
  hasher.update(chunk)
@@ -508,7 +508,7 @@ class CodeTreeBuilder:
508
508
  "generated_at": datetime.now(timezone.utc).isoformat(),
509
509
  }
510
510
 
511
- with open(output_path, "w") as f:
511
+ with output_path.open("w") as f:
512
512
  json.dump(tree_dict, f, indent=2)
513
513
 
514
514
  self.logger.info(f"Saved tree to {output_path}")
@@ -522,7 +522,7 @@ class CodeTreeBuilder:
522
522
  Returns:
523
523
  Root tree node
524
524
  """
525
- with open(input_path) as f:
525
+ with input_path.open() as f:
526
526
  tree_dict = json.load(f)
527
527
 
528
528
  # Remove stats if present
@@ -430,7 +430,7 @@ class SocketIODebugger:
430
430
  return
431
431
 
432
432
  try:
433
- with open(self.output_file, "a") as f:
433
+ with self.output_file.open("a") as f:
434
434
  f.write(json.dumps(data) + "\n")
435
435
  except Exception as e:
436
436
  self._log("error", f"Failed to write to file: {e}")
@@ -111,7 +111,7 @@ class AgentDependencyLoader:
111
111
  config_file = config_dir / f"{agent_id}.json"
112
112
  if config_file.exists():
113
113
  try:
114
- with open(config_file) as f:
114
+ with config_file.open() as f:
115
115
  config = json.load(f)
116
116
  if "dependencies" in config:
117
117
  agent_dependencies[agent_id] = config["dependencies"]
@@ -835,7 +835,7 @@ class AgentDependencyLoader:
835
835
  hash_obj.update(str(stat.st_size).encode("utf-8"))
836
836
 
837
837
  # Include file content for comprehensive change detection
838
- with open(agent_path, "rb") as f:
838
+ with agent_path.open("rb") as f:
839
839
  hash_obj.update(f.read())
840
840
  except Exception as e:
841
841
  logger.debug(f"Could not hash agent file {agent_path}: {e}")
@@ -855,7 +855,7 @@ class AgentDependencyLoader:
855
855
  return {}
856
856
 
857
857
  try:
858
- with open(self.deployment_state_file) as f:
858
+ with self.deployment_state_file.open() as f:
859
859
  return json.load(f)
860
860
  except Exception as e:
861
861
  logger.debug(f"Could not load deployment state: {e}")
@@ -872,7 +872,7 @@ class AgentDependencyLoader:
872
872
  # Ensure directory exists
873
873
  self.deployment_state_file.parent.mkdir(parents=True, exist_ok=True)
874
874
 
875
- with open(self.deployment_state_file, "w") as f:
875
+ with self.deployment_state_file.open("w") as f:
876
876
  json.dump(state, f, indent=2)
877
877
  except Exception as e:
878
878
  logger.debug(f"Could not save deployment state: {e}")
@@ -85,7 +85,7 @@ def save_json_safe(
85
85
  if create_parents:
86
86
  file_path.parent.mkdir(parents=True, exist_ok=True)
87
87
 
88
- with open(file_path, "w", encoding=encoding) as f:
88
+ with file_path.open("w", encoding=encoding) as f:
89
89
  json.dump(data, f, indent=indent, ensure_ascii=False)
90
90
  return True
91
91
  except Exception as e:
@@ -149,7 +149,7 @@ def save_yaml_safe(
149
149
  if create_parents:
150
150
  file_path.parent.mkdir(parents=True, exist_ok=True)
151
151
 
152
- with open(file_path, "w", encoding=encoding) as f:
152
+ with file_path.open("w", encoding=encoding) as f:
153
153
  yaml.safe_dump(data, f, default_flow_style=False, allow_unicode=True)
154
154
  return True
155
155
  except Exception as e:
@@ -242,7 +242,7 @@ class ConfigurationManager:
242
242
  # Create parent directories if needed
243
243
  file_path.parent.mkdir(parents=True, exist_ok=True)
244
244
 
245
- with open(file_path, "w", encoding="utf-8") as f:
245
+ with file_path.open("w", encoding="utf-8") as f:
246
246
  json.dump(config, f, indent=indent, sort_keys=sort_keys)
247
247
  logger.info(f"Configuration saved to {file_path}")
248
248
  except Exception as e:
@@ -279,7 +279,7 @@ class ConfigurationManager:
279
279
  # Create parent directories if needed
280
280
  file_path.parent.mkdir(parents=True, exist_ok=True)
281
281
 
282
- with open(file_path, "w", encoding="utf-8") as f:
282
+ with file_path.open("w", encoding="utf-8") as f:
283
283
  yaml.dump(
284
284
  config,
285
285
  f,
@@ -313,7 +313,7 @@ class ConfigurationManager:
313
313
  # Create parent directories if needed
314
314
  file_path.parent.mkdir(parents=True, exist_ok=True)
315
315
 
316
- with open(file_path, "w", encoding="utf-8") as f:
316
+ with file_path.open("w", encoding="utf-8") as f:
317
317
  toml.dump(config, f)
318
318
  logger.info(f"Configuration saved to {file_path}")
319
319
  except Exception as e:
@@ -66,7 +66,7 @@ class DependencyCache:
66
66
  return self._cache_data
67
67
 
68
68
  try:
69
- with open(self.cache_file) as f:
69
+ with self.cache_file.open() as f:
70
70
  self._cache_data = json.load(f)
71
71
  return self._cache_data
72
72
  except Exception as e:
@@ -85,7 +85,7 @@ class DependencyCache:
85
85
  # Ensure directory exists
86
86
  self.cache_dir.mkdir(parents=True, exist_ok=True)
87
87
 
88
- with open(self.cache_file, "w") as f:
88
+ with self.cache_file.open("w") as f:
89
89
  json.dump(cache_data, f, indent=2)
90
90
 
91
91
  self._cache_data = cache_data
@@ -128,7 +128,7 @@ class DependencyStrategy:
128
128
  # Try to load YAML config
129
129
  import yaml
130
130
 
131
- with open(self.config_path) as f:
131
+ with self.config_path.open() as f:
132
132
  config = yaml.safe_load(f)
133
133
  mode_str = config.get("dependency_mode")
134
134
  if mode_str:
@@ -155,7 +155,7 @@ class DependencyStrategy:
155
155
  return True
156
156
 
157
157
  try:
158
- with open(self.cache_path) as f:
158
+ with self.cache_path.open() as f:
159
159
  cache = json.load(f)
160
160
  last_check = datetime.fromisoformat(cache.get("timestamp", ""))
161
161
 
@@ -186,7 +186,7 @@ class DependencyStrategy:
186
186
  "results": results,
187
187
  }
188
188
 
189
- with open(self.cache_path, "w") as f:
189
+ with self.cache_path.open("w") as f:
190
190
  json.dump(cache_data, f, indent=2)
191
191
 
192
192
  logger.debug(f"Cached dependency results to {self.cache_path}")
@@ -205,7 +205,7 @@ class DependencyStrategy:
205
205
  return None
206
206
 
207
207
  try:
208
- with open(self.cache_path) as f:
208
+ with self.cache_path.open() as f:
209
209
  cache = json.load(f)
210
210
  return cache.get("results")
211
211
  except Exception:
@@ -285,7 +285,7 @@ class DependencyStrategy:
285
285
  if self.config_path.exists():
286
286
  import yaml
287
287
 
288
- with open(self.config_path) as f:
288
+ with self.config_path.open() as f:
289
289
  config = yaml.safe_load(f) or {}
290
290
 
291
291
  # Update dependency mode
@@ -294,7 +294,7 @@ class DependencyStrategy:
294
294
  # Save config
295
295
  import yaml
296
296
 
297
- with open(self.config_path, "w") as f:
297
+ with self.config_path.open("w") as f:
298
298
  yaml.dump(config, f, default_flow_style=False)
299
299
 
300
300
  print(f"✓ Saved preference: {mode.value}")
@@ -41,7 +41,7 @@ def ensure_directory(path: Union[str, Path]) -> Path:
41
41
  "operation": "mkdir",
42
42
  "error_type": type(e).__name__,
43
43
  },
44
- )
44
+ ) from e
45
45
 
46
46
 
47
47
  def safe_read_file(path: Union[str, Path], encoding: str = "utf-8") -> str:
@@ -61,7 +61,7 @@ def safe_read_file(path: Union[str, Path], encoding: str = "utf-8") -> str:
61
61
  path = Path(path)
62
62
  try:
63
63
  return path.read_text(encoding=encoding)
64
- except FileNotFoundError:
64
+ except FileNotFoundError as e:
65
65
  raise FileOperationError(
66
66
  f"File not found: {path}",
67
67
  context={
@@ -70,7 +70,7 @@ def safe_read_file(path: Union[str, Path], encoding: str = "utf-8") -> str:
70
70
  "encoding": encoding,
71
71
  "error_type": "FileNotFoundError",
72
72
  },
73
- )
73
+ ) from e
74
74
  except (OSError, PermissionError, UnicodeDecodeError) as e:
75
75
  raise FileOperationError(
76
76
  f"Failed to read file: {e}",
@@ -80,7 +80,7 @@ def safe_read_file(path: Union[str, Path], encoding: str = "utf-8") -> str:
80
80
  "encoding": encoding,
81
81
  "error_type": type(e).__name__,
82
82
  },
83
- )
83
+ ) from e
84
84
 
85
85
 
86
86
  def safe_write_file(
@@ -107,7 +107,7 @@ def safe_write_file(
107
107
  ensure_directory(path.parent)
108
108
  path.write_text(content, encoding=encoding)
109
109
  except Exception as e:
110
- raise FileOperationError(f"Failed to write file {path}: {e}")
110
+ raise FileOperationError(f"Failed to write file {path}: {e}") from e
111
111
 
112
112
 
113
113
  def atomic_write(
@@ -152,7 +152,7 @@ def atomic_write(
152
152
  os.unlink(temp_path)
153
153
  except Exception:
154
154
  pass
155
- raise FileOperationError(f"Failed to atomically write file {path}: {e}")
155
+ raise FileOperationError(f"Failed to atomically write file {path}: {e}") from e
156
156
 
157
157
 
158
158
  def get_file_info(path: Union[str, Path]) -> Optional[Dict[str, Any]]:
@@ -211,7 +211,7 @@ def safe_copy_file(
211
211
  shutil.copy2(src, dst)
212
212
 
213
213
  except Exception as e:
214
- raise FileOperationError(f"Failed to copy {src} to {dst}: {e}")
214
+ raise FileOperationError(f"Failed to copy {src} to {dst}: {e}") from e
215
215
 
216
216
 
217
217
  def safe_remove_file(path: Union[str, Path]) -> bool:
@@ -234,7 +234,7 @@ def safe_remove_file(path: Union[str, Path]) -> bool:
234
234
  path.unlink()
235
235
  return True
236
236
  except Exception as e:
237
- raise FileOperationError(f"Failed to remove file {path}: {e}")
237
+ raise FileOperationError(f"Failed to remove file {path}: {e}") from e
238
238
 
239
239
 
240
240
  def read_json_file(path: Union[str, Path]) -> Any:
@@ -254,7 +254,7 @@ def read_json_file(path: Union[str, Path]) -> Any:
254
254
  content = safe_read_file(path)
255
255
  return json.loads(content)
256
256
  except json.JSONDecodeError as e:
257
- raise FileOperationError(f"Invalid JSON in file {path}: {e}")
257
+ raise FileOperationError(f"Invalid JSON in file {path}: {e}") from e
258
258
 
259
259
 
260
260
  def write_json_file(
@@ -279,7 +279,7 @@ def write_json_file(
279
279
  else:
280
280
  safe_write_file(path, content)
281
281
  except Exception as e:
282
- raise FileOperationError(f"Failed to write JSON file {path}: {e}")
282
+ raise FileOperationError(f"Failed to write JSON file {path}: {e}") from e
283
283
 
284
284
 
285
285
  def backup_file(path: Union[str, Path], backup_suffix: str = ".backup") -> Path:
@@ -303,4 +303,4 @@ def backup_file(path: Union[str, Path], backup_suffix: str = ".backup") -> Path:
303
303
  safe_copy_file(path, backup_path)
304
304
  return backup_path
305
305
  except Exception as e:
306
- raise FileOperationError(f"Failed to create backup of {path}: {e}")
306
+ raise FileOperationError(f"Failed to create backup of {path}: {e}") from e
@@ -357,7 +357,7 @@ class LogCleanupUtility:
357
357
  space_saved += estimated_saved
358
358
  else:
359
359
  # Actually compress the file
360
- with open(log_file, "rb") as f_in:
360
+ with log_file.open("rb") as f_in:
361
361
  with gzip.open(
362
362
  compressed_path, "wb", compresslevel=9
363
363
  ) as f_out:
@@ -187,7 +187,7 @@ class PathOperations:
187
187
  shutil.move(tmp_path, str(path_obj))
188
188
  else:
189
189
  # Direct write
190
- with open(path_obj, "w", encoding=encoding) as f:
190
+ with path_obj.open("w", encoding=encoding) as f:
191
191
  f.write(content)
192
192
 
193
193
  logger.info(f"Successfully wrote to {path}")
@@ -102,7 +102,7 @@ class AgentValidator:
102
102
  if not self.schema_path.is_file():
103
103
  raise ValueError(f"Schema path is not a file: {self.schema_path}")
104
104
 
105
- with open(self.schema_path) as f:
105
+ with self.schema_path.open() as f:
106
106
  return json.load(f)
107
107
  except Exception as e:
108
108
  logger.error(f"Failed to load schema from {self.schema_path}: {e}")
@@ -392,7 +392,7 @@ class AgentValidator:
392
392
  max_size = SystemLimits.MAX_AGENT_CONFIG_SIZE
393
393
  if file_size > max_size:
394
394
  raise ValueError(ErrorMessages.FILE_TOO_LARGE.format(limit=max_size))
395
- with open(file_path) as f:
395
+ with file_path.open() as f:
396
396
  agent_data = json.load(f)
397
397
 
398
398
  result = self.validate_agent(agent_data)
@@ -185,7 +185,7 @@ class FrontmatterValidator:
185
185
  errors = []
186
186
 
187
187
  try:
188
- with open(file_path) as f:
188
+ with file_path.open() as f:
189
189
  content = f.read()
190
190
 
191
191
  # Check for frontmatter markers
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: claude-mpm
3
- Version: 4.5.11
3
+ Version: 4.5.13
4
4
  Summary: Claude Multi-Agent Project Manager - Orchestrate Claude with agent delegation and ticket tracking
5
5
  Author-email: Bob Matsuoka <bob@matsuoka.com>
6
6
  Maintainer: Claude MPM Team