claude-mpm 4.4.3__py3-none-any.whl → 4.4.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 (118) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/agent_loader.py +3 -2
  3. claude_mpm/agents/agent_loader_integration.py +2 -1
  4. claude_mpm/agents/async_agent_loader.py +2 -2
  5. claude_mpm/agents/base_agent_loader.py +2 -2
  6. claude_mpm/agents/frontmatter_validator.py +1 -0
  7. claude_mpm/agents/system_agent_config.py +2 -1
  8. claude_mpm/cli/commands/doctor.py +44 -5
  9. claude_mpm/cli/commands/mpm_init.py +116 -62
  10. claude_mpm/cli/parsers/configure_parser.py +3 -1
  11. claude_mpm/cli/startup_logging.py +1 -3
  12. claude_mpm/config/agent_config.py +1 -1
  13. claude_mpm/config/paths.py +2 -1
  14. claude_mpm/core/agent_name_normalizer.py +1 -0
  15. claude_mpm/core/config.py +2 -1
  16. claude_mpm/core/config_aliases.py +2 -1
  17. claude_mpm/core/file_utils.py +0 -1
  18. claude_mpm/core/framework/__init__.py +6 -6
  19. claude_mpm/core/framework/formatters/__init__.py +2 -2
  20. claude_mpm/core/framework/formatters/capability_generator.py +19 -8
  21. claude_mpm/core/framework/formatters/content_formatter.py +8 -3
  22. claude_mpm/core/framework/formatters/context_generator.py +7 -3
  23. claude_mpm/core/framework/loaders/__init__.py +3 -3
  24. claude_mpm/core/framework/loaders/agent_loader.py +7 -3
  25. claude_mpm/core/framework/loaders/file_loader.py +16 -6
  26. claude_mpm/core/framework/loaders/instruction_loader.py +16 -6
  27. claude_mpm/core/framework/loaders/packaged_loader.py +36 -12
  28. claude_mpm/core/framework/processors/__init__.py +2 -2
  29. claude_mpm/core/framework/processors/memory_processor.py +14 -6
  30. claude_mpm/core/framework/processors/metadata_processor.py +5 -5
  31. claude_mpm/core/framework/processors/template_processor.py +12 -6
  32. claude_mpm/core/framework_loader.py +44 -20
  33. claude_mpm/core/log_manager.py +2 -1
  34. claude_mpm/core/tool_access_control.py +1 -0
  35. claude_mpm/core/unified_agent_registry.py +2 -1
  36. claude_mpm/core/unified_paths.py +1 -0
  37. claude_mpm/experimental/cli_enhancements.py +1 -0
  38. claude_mpm/hooks/base_hook.py +1 -0
  39. claude_mpm/hooks/instruction_reinforcement.py +1 -0
  40. claude_mpm/hooks/kuzu_memory_hook.py +20 -13
  41. claude_mpm/hooks/validation_hooks.py +1 -1
  42. claude_mpm/scripts/mpm_doctor.py +1 -0
  43. claude_mpm/services/agents/loading/agent_profile_loader.py +1 -1
  44. claude_mpm/services/agents/loading/base_agent_manager.py +1 -1
  45. claude_mpm/services/agents/loading/framework_agent_loader.py +1 -1
  46. claude_mpm/services/agents/management/agent_capabilities_generator.py +1 -0
  47. claude_mpm/services/agents/management/agent_management_service.py +1 -1
  48. claude_mpm/services/agents/memory/memory_categorization_service.py +0 -1
  49. claude_mpm/services/agents/memory/memory_file_service.py +6 -2
  50. claude_mpm/services/agents/memory/memory_format_service.py +0 -1
  51. claude_mpm/services/agents/registry/deployed_agent_discovery.py +1 -1
  52. claude_mpm/services/async_session_logger.py +1 -1
  53. claude_mpm/services/claude_session_logger.py +1 -0
  54. claude_mpm/services/core/path_resolver.py +1 -0
  55. claude_mpm/services/diagnostics/checks/__init__.py +2 -0
  56. claude_mpm/services/diagnostics/checks/installation_check.py +126 -25
  57. claude_mpm/services/diagnostics/checks/mcp_services_check.py +399 -0
  58. claude_mpm/services/diagnostics/diagnostic_runner.py +3 -0
  59. claude_mpm/services/diagnostics/doctor_reporter.py +259 -32
  60. claude_mpm/services/event_bus/direct_relay.py +2 -1
  61. claude_mpm/services/event_bus/event_bus.py +1 -0
  62. claude_mpm/services/event_bus/relay.py +3 -2
  63. claude_mpm/services/framework_claude_md_generator/content_assembler.py +1 -1
  64. claude_mpm/services/infrastructure/daemon_manager.py +1 -1
  65. claude_mpm/services/mcp_config_manager.py +10 -10
  66. claude_mpm/services/mcp_gateway/core/process_pool.py +62 -23
  67. claude_mpm/services/mcp_gateway/tools/__init__.py +6 -5
  68. claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +3 -1
  69. claude_mpm/services/mcp_gateway/tools/kuzu_memory_service.py +16 -31
  70. claude_mpm/services/memory/cache/simple_cache.py +1 -1
  71. claude_mpm/services/project/archive_manager.py +159 -96
  72. claude_mpm/services/project/documentation_manager.py +64 -45
  73. claude_mpm/services/project/enhanced_analyzer.py +132 -89
  74. claude_mpm/services/project/project_organizer.py +225 -131
  75. claude_mpm/services/response_tracker.py +1 -1
  76. claude_mpm/services/socketio/server/eventbus_integration.py +1 -1
  77. claude_mpm/services/unified/__init__.py +1 -1
  78. claude_mpm/services/unified/analyzer_strategies/__init__.py +3 -3
  79. claude_mpm/services/unified/analyzer_strategies/code_analyzer.py +97 -53
  80. claude_mpm/services/unified/analyzer_strategies/dependency_analyzer.py +81 -40
  81. claude_mpm/services/unified/analyzer_strategies/performance_analyzer.py +277 -178
  82. claude_mpm/services/unified/analyzer_strategies/security_analyzer.py +196 -112
  83. claude_mpm/services/unified/analyzer_strategies/structure_analyzer.py +83 -49
  84. claude_mpm/services/unified/config_strategies/__init__.py +111 -126
  85. claude_mpm/services/unified/config_strategies/config_schema.py +157 -111
  86. claude_mpm/services/unified/config_strategies/context_strategy.py +91 -89
  87. claude_mpm/services/unified/config_strategies/error_handling_strategy.py +183 -173
  88. claude_mpm/services/unified/config_strategies/file_loader_strategy.py +160 -152
  89. claude_mpm/services/unified/config_strategies/unified_config_service.py +124 -112
  90. claude_mpm/services/unified/config_strategies/validation_strategy.py +298 -259
  91. claude_mpm/services/unified/deployment_strategies/__init__.py +7 -7
  92. claude_mpm/services/unified/deployment_strategies/base.py +24 -28
  93. claude_mpm/services/unified/deployment_strategies/cloud_strategies.py +168 -88
  94. claude_mpm/services/unified/deployment_strategies/local.py +49 -34
  95. claude_mpm/services/unified/deployment_strategies/utils.py +39 -43
  96. claude_mpm/services/unified/deployment_strategies/vercel.py +30 -24
  97. claude_mpm/services/unified/interfaces.py +0 -26
  98. claude_mpm/services/unified/migration.py +17 -40
  99. claude_mpm/services/unified/strategies.py +9 -26
  100. claude_mpm/services/unified/unified_analyzer.py +48 -44
  101. claude_mpm/services/unified/unified_config.py +21 -19
  102. claude_mpm/services/unified/unified_deployment.py +21 -26
  103. claude_mpm/storage/state_storage.py +1 -0
  104. claude_mpm/utils/agent_dependency_loader.py +18 -6
  105. claude_mpm/utils/common.py +14 -12
  106. claude_mpm/utils/database_connector.py +15 -12
  107. claude_mpm/utils/error_handler.py +1 -0
  108. claude_mpm/utils/log_cleanup.py +1 -0
  109. claude_mpm/utils/path_operations.py +1 -0
  110. claude_mpm/utils/session_logging.py +1 -1
  111. claude_mpm/utils/subprocess_utils.py +1 -0
  112. claude_mpm/validation/agent_validator.py +1 -1
  113. {claude_mpm-4.4.3.dist-info → claude_mpm-4.4.4.dist-info}/METADATA +9 -3
  114. {claude_mpm-4.4.3.dist-info → claude_mpm-4.4.4.dist-info}/RECORD +118 -117
  115. {claude_mpm-4.4.3.dist-info → claude_mpm-4.4.4.dist-info}/WHEEL +0 -0
  116. {claude_mpm-4.4.3.dist-info → claude_mpm-4.4.4.dist-info}/entry_points.txt +0 -0
  117. {claude_mpm-4.4.3.dist-info → claude_mpm-4.4.4.dist-info}/licenses/LICENSE +0 -0
  118. {claude_mpm-4.4.3.dist-info → claude_mpm-4.4.4.dist-info}/top_level.txt +0 -0
@@ -14,11 +14,12 @@ from .base_adapter import (
14
14
  from .document_summarizer import DocumentSummarizerTool
15
15
  from .kuzu_memory_service import (
16
16
  KuzuMemoryService,
17
- store_memory,
17
+ get_context,
18
18
  recall_memories,
19
19
  search_memories,
20
- get_context,
20
+ store_memory,
21
21
  )
22
+
22
23
  # Ticket tools removed - using mcp-ticketer instead
23
24
 
24
25
  __all__ = [
@@ -26,10 +27,10 @@ __all__ = [
26
27
  "CalculatorToolAdapter",
27
28
  "DocumentSummarizerTool",
28
29
  "EchoToolAdapter",
29
- "SystemInfoToolAdapter",
30
30
  "KuzuMemoryService",
31
- "store_memory",
31
+ "SystemInfoToolAdapter",
32
+ "get_context",
32
33
  "recall_memories",
33
34
  "search_memories",
34
- "get_context",
35
+ "store_memory",
35
36
  ]
@@ -432,7 +432,9 @@ class ExternalMCPServiceManager:
432
432
  f"Initialized external service: {service.service_name}"
433
433
  )
434
434
  elif self.logger:
435
- self.logger.debug(f"Service not available (optional): {service.service_name}")
435
+ self.logger.debug(
436
+ f"Service not available (optional): {service.service_name}"
437
+ )
436
438
  except Exception as e:
437
439
  if self.logger:
438
440
  self.logger.error(f"Error initializing {service.service_name}: {e}")
@@ -17,17 +17,15 @@ DESIGN DECISIONS:
17
17
 
18
18
  import json
19
19
  import subprocess
20
- import sys
21
- from datetime import datetime
22
20
  from pathlib import Path
23
21
  from typing import Any, Dict, List, Optional
24
22
 
25
- from claude_mpm.services.mcp_gateway.tools.base_adapter import BaseToolAdapter
26
23
  from claude_mpm.services.mcp_gateway.core.interfaces import (
27
24
  MCPToolDefinition,
28
25
  MCPToolInvocation,
29
26
  MCPToolResult,
30
27
  )
28
+ from claude_mpm.services.mcp_gateway.tools.base_adapter import BaseToolAdapter
31
29
 
32
30
 
33
31
  class KuzuMemoryService(BaseToolAdapter):
@@ -181,45 +179,33 @@ class KuzuMemoryService(BaseToolAdapter):
181
179
  try:
182
180
  if action == "store":
183
181
  result = await self.store_memory(
184
- params.get("content"),
185
- params.get("tags"),
186
- {} # metadata
182
+ params.get("content"), params.get("tags"), {} # metadata
187
183
  )
188
184
  elif action == "recall":
189
185
  result = await self.recall_memories(
190
- params.get("query"),
191
- params.get("limit", 5),
192
- params.get("tags")
186
+ params.get("query"), params.get("limit", 5), params.get("tags")
193
187
  )
194
188
  elif action == "search":
195
189
  result = await self.search_memories(
196
190
  params.get("query", ""),
197
191
  "both", # search_type
198
- params.get("limit", 10)
192
+ params.get("limit", 10),
199
193
  )
200
194
  elif action == "context":
201
195
  result = await self.get_context(
202
- params.get("query", ""),
203
- 2, # depth
204
- True # include_related
196
+ params.get("query", ""), 2, True # depth # include_related
205
197
  )
206
198
  else:
207
- return MCPToolResult(
208
- success=False,
209
- error=f"Unknown action: {action}"
210
- )
199
+ return MCPToolResult(success=False, error=f"Unknown action: {action}")
211
200
 
212
201
  return MCPToolResult(
213
202
  success=result.get("success", False),
214
203
  data=result,
215
- error=result.get("error")
204
+ error=result.get("error"),
216
205
  )
217
206
 
218
207
  except Exception as e:
219
- return MCPToolResult(
220
- success=False,
221
- error=str(e)
222
- )
208
+ return MCPToolResult(success=False, error=str(e))
223
209
 
224
210
  def validate_parameters(self, parameters: Dict[str, Any]) -> bool:
225
211
  """Validate tool parameters - basic implementation."""
@@ -227,8 +213,7 @@ class KuzuMemoryService(BaseToolAdapter):
227
213
 
228
214
  async def shutdown(self) -> None:
229
215
  """Shutdown the service."""
230
- pass # No resources to clean up
231
-
216
+ # No resources to clean up
232
217
 
233
218
  async def store_memory(
234
219
  self,
@@ -264,13 +249,13 @@ class KuzuMemoryService(BaseToolAdapter):
264
249
  capture_output=True,
265
250
  text=True,
266
251
  timeout=10,
267
- cwd=str(self.project_path),
252
+ cwd=str(self.project_path), check=False,
268
253
  )
269
254
 
270
255
  if result.returncode == 0:
271
256
  return {
272
257
  "success": True,
273
- "message": f"Memory stored successfully",
258
+ "message": "Memory stored successfully",
274
259
  "content": content[:100],
275
260
  "tags": tags or [],
276
261
  }
@@ -330,7 +315,7 @@ class KuzuMemoryService(BaseToolAdapter):
330
315
  capture_output=True,
331
316
  text=True,
332
317
  timeout=10,
333
- cwd=str(self.project_path),
318
+ cwd=str(self.project_path), check=False,
334
319
  )
335
320
 
336
321
  if result.returncode == 0 and result.stdout:
@@ -399,7 +384,7 @@ class KuzuMemoryService(BaseToolAdapter):
399
384
  capture_output=True,
400
385
  text=True,
401
386
  timeout=10,
402
- cwd=str(self.project_path),
387
+ cwd=str(self.project_path), check=False,
403
388
  )
404
389
 
405
390
  if result.returncode == 0 and result.stdout:
@@ -476,7 +461,7 @@ class KuzuMemoryService(BaseToolAdapter):
476
461
  capture_output=True,
477
462
  text=True,
478
463
  timeout=15,
479
- cwd=str(self.project_path),
464
+ cwd=str(self.project_path), check=False,
480
465
  )
481
466
 
482
467
  if result.returncode == 0 and result.stdout:
@@ -484,7 +469,7 @@ class KuzuMemoryService(BaseToolAdapter):
484
469
  "success": True,
485
470
  "topic": topic,
486
471
  "context": result.stdout.strip(),
487
- "memories": [] # Enhanced context is already processed
472
+ "memories": [], # Enhanced context is already processed
488
473
  }
489
474
 
490
475
  # Fallback to recall if enhance fails
@@ -539,4 +524,4 @@ async def get_context(
539
524
  """Get enriched context for a topic."""
540
525
  service = KuzuMemoryService()
541
526
  await service.initialize()
542
- return await service.get_context(topic, depth, include_related)
527
+ return await service.get_context(topic, depth, include_related)
@@ -22,8 +22,8 @@ from pathlib import Path
22
22
  from typing import Any, Dict, List, Optional, Set
23
23
 
24
24
  from claude_mpm.core.interfaces import ICacheService
25
-
26
25
  from claude_mpm.core.logging_utils import get_logger
26
+
27
27
  logger = get_logger(__name__)
28
28
 
29
29
 
@@ -25,12 +25,13 @@ import shutil
25
25
  import subprocess
26
26
  from datetime import datetime, timedelta
27
27
  from pathlib import Path
28
- from typing import Any, Dict, List, Optional, Set, Tuple
28
+ from typing import Dict, List, Optional, Tuple
29
29
 
30
30
  from rich.console import Console
31
31
  from rich.table import Table
32
32
 
33
33
  from claude_mpm.core.logging_utils import get_logger
34
+
34
35
  logger = get_logger(__name__)
35
36
  console = Console()
36
37
 
@@ -125,13 +126,15 @@ Generated by Claude MPM Archive Manager
125
126
  # Create metadata file if provided
126
127
  if metadata or reason:
127
128
  meta_data = metadata or {}
128
- meta_data.update({
129
- "original_path": str(file_path),
130
- "archived_at": datetime.now().isoformat(),
131
- "reason": reason or "Manual archive",
132
- "file_size": file_path.stat().st_size,
133
- "file_hash": self._calculate_file_hash(file_path),
134
- })
129
+ meta_data.update(
130
+ {
131
+ "original_path": str(file_path),
132
+ "archived_at": datetime.now().isoformat(),
133
+ "reason": reason or "Manual archive",
134
+ "file_size": file_path.stat().st_size,
135
+ "file_hash": self._calculate_file_hash(file_path),
136
+ }
137
+ )
135
138
 
136
139
  meta_path = self.archive_path / f"{archive_name}.meta.json"
137
140
  meta_path.write_text(json.dumps(meta_data, indent=2))
@@ -252,7 +255,9 @@ Generated by Claude MPM Archive Manager
252
255
  "name": archive_file.name,
253
256
  "path": str(archive_file),
254
257
  "size": archive_file.stat().st_size,
255
- "modified": datetime.fromtimestamp(archive_file.stat().st_mtime).isoformat(),
258
+ "modified": datetime.fromtimestamp(
259
+ archive_file.stat().st_mtime
260
+ ).isoformat(),
256
261
  "compressed": archive_file.suffix == ".gz",
257
262
  }
258
263
 
@@ -308,7 +313,9 @@ Generated by Claude MPM Archive Manager
308
313
  # Backup current file if it exists
309
314
  if target_path.exists():
310
315
  self.archive_file(
311
- target_path, reason="Backup before restoration", metadata={"restoration_from": archive_name}
316
+ target_path,
317
+ reason="Backup before restoration",
318
+ metadata={"restoration_from": archive_name},
312
319
  )
313
320
 
314
321
  # Restore file
@@ -325,7 +332,7 @@ Generated by Claude MPM Archive Manager
325
332
 
326
333
  except Exception as e:
327
334
  logger.error(f"Failed to restore {archive_name}: {e}")
328
- return False, f"Restoration failed: {str(e)}"
335
+ return False, f"Restoration failed: {e!s}"
329
336
 
330
337
  def compare_with_archive(self, current_file: Path, archive_name: str) -> Dict:
331
338
  """Compare current file with an archived version."""
@@ -366,7 +373,7 @@ Generated by Claude MPM Archive Manager
366
373
  }
367
374
 
368
375
  except Exception as e:
369
- return {"error": f"Comparison failed: {str(e)}"}
376
+ return {"error": f"Comparison failed: {e!s}"}
370
377
 
371
378
  def create_archive_report(self) -> Dict:
372
379
  """Generate a report of all archives."""
@@ -462,13 +469,15 @@ Generated by Claude MPM Archive Manager
462
469
  return []
463
470
 
464
471
  relative_path = file_path.relative_to(self.project_path)
465
- output = self._run_git_command([
466
- "log",
467
- f"-{limit}",
468
- "--pretty=format:%H|%an|%at|%s",
469
- "--follow",
470
- str(relative_path),
471
- ])
472
+ output = self._run_git_command(
473
+ [
474
+ "log",
475
+ f"-{limit}",
476
+ "--pretty=format:%H|%an|%at|%s",
477
+ "--follow",
478
+ str(relative_path),
479
+ ]
480
+ )
472
481
 
473
482
  if not output:
474
483
  return []
@@ -477,12 +486,14 @@ Generated by Claude MPM Archive Manager
477
486
  for line in output.splitlines():
478
487
  parts = line.split("|", 3)
479
488
  if len(parts) == 4:
480
- commits.append({
481
- "hash": parts[0][:8],
482
- "author": parts[1],
483
- "date": datetime.fromtimestamp(int(parts[2])).isoformat(),
484
- "message": parts[3],
485
- })
489
+ commits.append(
490
+ {
491
+ "hash": parts[0][:8],
492
+ "author": parts[1],
493
+ "date": datetime.fromtimestamp(int(parts[2])).isoformat(),
494
+ "message": parts[3],
495
+ }
496
+ )
486
497
  return commits
487
498
 
488
499
  def get_file_last_modified(self, file_path: Path) -> Optional[datetime]:
@@ -491,12 +502,14 @@ Generated by Claude MPM Archive Manager
491
502
  return None
492
503
 
493
504
  relative_path = file_path.relative_to(self.project_path)
494
- output = self._run_git_command([
495
- "log",
496
- "-1",
497
- "--format=%at",
498
- str(relative_path),
499
- ])
505
+ output = self._run_git_command(
506
+ [
507
+ "log",
508
+ "-1",
509
+ "--format=%at",
510
+ str(relative_path),
511
+ ]
512
+ )
500
513
 
501
514
  if output:
502
515
  return datetime.fromtimestamp(int(output))
@@ -523,10 +536,12 @@ Generated by Claude MPM Archive Manager
523
536
 
524
537
  # Check for outdated content
525
538
  if file_report.get("outdated_indicators"):
526
- report["outdated_sections"].append({
527
- "file": doc_file,
528
- "indicators": file_report["outdated_indicators"],
529
- })
539
+ report["outdated_sections"].append(
540
+ {
541
+ "file": doc_file,
542
+ "indicators": file_report["outdated_indicators"],
543
+ }
544
+ )
530
545
 
531
546
  # Check synchronization between docs
532
547
  sync_issues = self._check_documentation_sync()
@@ -561,10 +576,12 @@ Generated by Claude MPM Archive Manager
561
576
  for pattern_name, pattern in self.version_patterns.items():
562
577
  matches = pattern.findall(content)
563
578
  if matches:
564
- report["version_references"].append({
565
- "type": pattern_name,
566
- "versions": matches[:5], # First 5 matches
567
- })
579
+ report["version_references"].append(
580
+ {
581
+ "type": pattern_name,
582
+ "versions": matches[:5], # First 5 matches
583
+ }
584
+ )
568
585
 
569
586
  # Detect outdated indicators
570
587
  outdated_indicators = self._detect_outdated_content(content, file_path.name)
@@ -591,11 +608,13 @@ Generated by Claude MPM Archive Manager
591
608
  regex = re.compile(pattern, re.IGNORECASE)
592
609
  for i, line in enumerate(lines, 1):
593
610
  if regex.search(line):
594
- indicators.append({
595
- "line": i,
596
- "type": description,
597
- "content": line.strip()[:100], # First 100 chars
598
- })
611
+ indicators.append(
612
+ {
613
+ "line": i,
614
+ "type": description,
615
+ "content": line.strip()[:100], # First 100 chars
616
+ }
617
+ )
599
618
 
600
619
  # Check for old version numbers if VERSION file exists
601
620
  version_file = self.project_path / "VERSION"
@@ -605,13 +624,17 @@ Generated by Claude MPM Archive Manager
605
624
 
606
625
  for match in old_version_pattern.finditer(content):
607
626
  found_version = match.group(0)
608
- if found_version != current_version and self._is_older_version(found_version, current_version):
609
- pos = content[:match.start()].count('\n') + 1
610
- indicators.append({
611
- "line": pos,
612
- "type": "Old version reference",
613
- "content": f"Found {found_version} (current: {current_version})",
614
- })
627
+ if found_version != current_version and self._is_older_version(
628
+ found_version, current_version
629
+ ):
630
+ pos = content[: match.start()].count("\n") + 1
631
+ indicators.append(
632
+ {
633
+ "line": pos,
634
+ "type": "Old version reference",
635
+ "content": f"Found {found_version} (current: {current_version})",
636
+ }
637
+ )
615
638
 
616
639
  return indicators[:20] # Limit to 20 most relevant
617
640
 
@@ -648,22 +671,28 @@ Generated by Claude MPM Archive Manager
648
671
 
649
672
  if claude_versions and readme_versions:
650
673
  if claude_versions[0] != readme_versions[0]:
651
- issues.append({
652
- "type": "Version mismatch",
653
- "files": ["CLAUDE.md", "README.md"],
654
- "details": f"CLAUDE.md: {claude_versions[0]}, README.md: {readme_versions[0]}",
655
- })
674
+ issues.append(
675
+ {
676
+ "type": "Version mismatch",
677
+ "files": ["CLAUDE.md", "README.md"],
678
+ "details": f"CLAUDE.md: {claude_versions[0]}, README.md: {readme_versions[0]}",
679
+ }
680
+ )
656
681
 
657
682
  # Check for project name consistency
658
- project_names = re.findall(r"Claude MPM|claude-mpm", readme_content, re.IGNORECASE)
683
+ project_names = re.findall(
684
+ r"Claude MPM|claude-mpm", readme_content, re.IGNORECASE
685
+ )
659
686
  if project_names:
660
687
  unique_names = set(project_names)
661
688
  if len(unique_names) > 1:
662
- issues.append({
663
- "type": "Inconsistent project naming",
664
- "files": ["README.md"],
665
- "details": f"Found variations: {', '.join(unique_names)}",
666
- })
689
+ issues.append(
690
+ {
691
+ "type": "Inconsistent project naming",
692
+ "files": ["README.md"],
693
+ "details": f"Found variations: {', '.join(unique_names)}",
694
+ }
695
+ )
667
696
 
668
697
  # Check CHANGELOG.md exists and is recent
669
698
  changelog_path = self.project_path / "CHANGELOG.md"
@@ -672,17 +701,21 @@ Generated by Claude MPM Archive Manager
672
701
  if last_modified:
673
702
  days_old = (datetime.now() - last_modified).days
674
703
  if days_old > 30:
675
- issues.append({
676
- "type": "Stale changelog",
677
- "files": ["CHANGELOG.md"],
678
- "details": f"Last updated {days_old} days ago",
679
- })
704
+ issues.append(
705
+ {
706
+ "type": "Stale changelog",
707
+ "files": ["CHANGELOG.md"],
708
+ "details": f"Last updated {days_old} days ago",
709
+ }
710
+ )
680
711
  else:
681
- issues.append({
682
- "type": "Missing file",
683
- "files": ["CHANGELOG.md"],
684
- "details": "CHANGELOG.md does not exist",
685
- })
712
+ issues.append(
713
+ {
714
+ "type": "Missing file",
715
+ "files": ["CHANGELOG.md"],
716
+ "details": "CHANGELOG.md does not exist",
717
+ }
718
+ )
686
719
 
687
720
  return issues
688
721
 
@@ -700,7 +733,9 @@ Generated by Claude MPM Archive Manager
700
733
  if report["synchronization_issues"]:
701
734
  for issue in report["synchronization_issues"]:
702
735
  if issue["type"] == "Version mismatch":
703
- recommendations.append("🔄 Synchronize version numbers across documentation files")
736
+ recommendations.append(
737
+ "🔄 Synchronize version numbers across documentation files"
738
+ )
704
739
  elif issue["type"] == "Stale changelog":
705
740
  recommendations.append("📅 Update CHANGELOG.md with recent changes")
706
741
  elif issue["type"] == "Missing file":
@@ -708,17 +743,29 @@ Generated by Claude MPM Archive Manager
708
743
 
709
744
  # Check for TODO items
710
745
  total_todos = sum(
711
- len([i for i in file_report.get("outdated_indicators", [])
712
- if i["type"] == "Unresolved TODOs"])
746
+ len(
747
+ [
748
+ i
749
+ for i in file_report.get("outdated_indicators", [])
750
+ if i["type"] == "Unresolved TODOs"
751
+ ]
752
+ )
713
753
  for file_report in report["files_reviewed"].values()
714
754
  )
715
755
  if total_todos > 0:
716
- recommendations.append(f"✅ Resolve {total_todos} TODO items in documentation")
756
+ recommendations.append(
757
+ f"✅ Resolve {total_todos} TODO items in documentation"
758
+ )
717
759
 
718
760
  # Check for deprecated references
719
761
  deprecated_count = sum(
720
- len([i for i in file_report.get("outdated_indicators", [])
721
- if "deprecated" in i["type"].lower()])
762
+ len(
763
+ [
764
+ i
765
+ for i in file_report.get("outdated_indicators", [])
766
+ if "deprecated" in i["type"].lower()
767
+ ]
768
+ )
722
769
  for file_report in report["files_reviewed"].values()
723
770
  )
724
771
  if deprecated_count > 0:
@@ -768,20 +815,24 @@ Generated by Claude MPM Archive Manager
768
815
  "auto_detection": True,
769
816
  "indicators": file_report.get("outdated_indicators", [])[:5],
770
817
  "review_timestamp": review["timestamp"],
771
- }
818
+ },
772
819
  )
773
820
  if archive_result:
774
- result["archived_files"].append({
821
+ result["archived_files"].append(
822
+ {
823
+ "file": filename,
824
+ "reason": archive_reason,
825
+ "archive_path": str(archive_result),
826
+ }
827
+ )
828
+ elif should_archive:
829
+ result["skipped_files"].append(
830
+ {
775
831
  "file": filename,
776
832
  "reason": archive_reason,
777
- "archive_path": str(archive_result),
778
- })
779
- elif should_archive:
780
- result["skipped_files"].append({
781
- "file": filename,
782
- "reason": archive_reason,
783
- "action": "Would archive (dry run)",
784
- })
833
+ "action": "Would archive (dry run)",
834
+ }
835
+ )
785
836
 
786
837
  return result
787
838
 
@@ -854,7 +905,9 @@ Generated by Claude MPM Archive Manager
854
905
  # Archive before update
855
906
  self.archive_file(readme_path, reason="Before version sync")
856
907
  readme_path.write_text(updated_readme)
857
- result["changes"].append(f"Updated README.md to version {current_version}")
908
+ result["changes"].append(
909
+ f"Updated README.md to version {current_version}"
910
+ )
858
911
 
859
912
  # Update CHANGELOG.md header if exists
860
913
  if changelog_path.exists() and current_version:
@@ -877,14 +930,18 @@ Generated by Claude MPM Archive Manager
877
930
  updated_changelog = "\n".join(lines)
878
931
 
879
932
  # Archive before update
880
- self.archive_file(changelog_path, reason="Before adding new version")
933
+ self.archive_file(
934
+ changelog_path, reason="Before adding new version"
935
+ )
881
936
  changelog_path.write_text(updated_changelog)
882
- result["changes"].append(f"Added {current_version} section to CHANGELOG.md")
937
+ result["changes"].append(
938
+ f"Added {current_version} section to CHANGELOG.md"
939
+ )
883
940
 
884
941
  result["synced"] = len(result["changes"]) > 0
885
942
 
886
943
  except Exception as e:
887
- result["errors"].append(f"Sync failed: {str(e)}")
944
+ result["errors"].append(f"Sync failed: {e!s}")
888
945
  logger.error(f"Documentation sync failed: {e}")
889
946
 
890
947
  return result
@@ -919,7 +976,9 @@ Generated by Claude MPM Archive Manager
919
976
  table.add_column("Last Updated", style="magenta")
920
977
 
921
978
  for filename, report in review["files_reviewed"].items():
922
- status = "✅ OK" if not report.get("outdated_indicators") else "⚠️ Needs Review"
979
+ status = (
980
+ "✅ OK" if not report.get("outdated_indicators") else "⚠️ Needs Review"
981
+ )
923
982
  issues = len(report.get("outdated_indicators", []))
924
983
 
925
984
  last_updated = "Unknown"
@@ -964,13 +1023,17 @@ Generated by Claude MPM Archive Manager
964
1023
 
965
1024
  # Generate diff if current file exists and review requested
966
1025
  if target_path.exists() and review_changes:
967
- diff_report = self.generate_documentation_diff_report(target_path, archive_file)
1026
+ diff_report = self.generate_documentation_diff_report(
1027
+ target_path, archive_file
1028
+ )
968
1029
 
969
1030
  console.print("\n[bold cyan]📝 Changes to be applied:[/bold cyan]")
970
1031
  console.print(diff_report)
971
1032
 
972
1033
  # Ask for confirmation
973
- console.print("\n[bold yellow]Proceed with restoration? (y/n): [/bold yellow]", end="")
1034
+ console.print(
1035
+ "\n[bold yellow]Proceed with restoration? (y/n): [/bold yellow]", end=""
1036
+ )
974
1037
  # In automated context, assume yes
975
1038
  confirm = True
976
1039
 
@@ -978,4 +1041,4 @@ Generated by Claude MPM Archive Manager
978
1041
  return False, "Restoration cancelled by user"
979
1042
 
980
1043
  # Proceed with restoration
981
- return self.restore_archive(archive_name, target_path)
1044
+ return self.restore_archive(archive_name, target_path)