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.
- claude_mpm/VERSION +1 -1
- claude_mpm/agents/agent_loader.py +3 -2
- claude_mpm/agents/agent_loader_integration.py +2 -1
- claude_mpm/agents/async_agent_loader.py +2 -2
- claude_mpm/agents/base_agent_loader.py +2 -2
- claude_mpm/agents/frontmatter_validator.py +1 -0
- claude_mpm/agents/system_agent_config.py +2 -1
- claude_mpm/cli/commands/doctor.py +44 -5
- claude_mpm/cli/commands/mpm_init.py +116 -62
- claude_mpm/cli/parsers/configure_parser.py +3 -1
- claude_mpm/cli/startup_logging.py +1 -3
- claude_mpm/config/agent_config.py +1 -1
- claude_mpm/config/paths.py +2 -1
- claude_mpm/core/agent_name_normalizer.py +1 -0
- claude_mpm/core/config.py +2 -1
- claude_mpm/core/config_aliases.py +2 -1
- claude_mpm/core/file_utils.py +0 -1
- claude_mpm/core/framework/__init__.py +6 -6
- claude_mpm/core/framework/formatters/__init__.py +2 -2
- claude_mpm/core/framework/formatters/capability_generator.py +19 -8
- claude_mpm/core/framework/formatters/content_formatter.py +8 -3
- claude_mpm/core/framework/formatters/context_generator.py +7 -3
- claude_mpm/core/framework/loaders/__init__.py +3 -3
- claude_mpm/core/framework/loaders/agent_loader.py +7 -3
- claude_mpm/core/framework/loaders/file_loader.py +16 -6
- claude_mpm/core/framework/loaders/instruction_loader.py +16 -6
- claude_mpm/core/framework/loaders/packaged_loader.py +36 -12
- claude_mpm/core/framework/processors/__init__.py +2 -2
- claude_mpm/core/framework/processors/memory_processor.py +14 -6
- claude_mpm/core/framework/processors/metadata_processor.py +5 -5
- claude_mpm/core/framework/processors/template_processor.py +12 -6
- claude_mpm/core/framework_loader.py +44 -20
- claude_mpm/core/log_manager.py +2 -1
- claude_mpm/core/tool_access_control.py +1 -0
- claude_mpm/core/unified_agent_registry.py +2 -1
- claude_mpm/core/unified_paths.py +1 -0
- claude_mpm/experimental/cli_enhancements.py +1 -0
- claude_mpm/hooks/base_hook.py +1 -0
- claude_mpm/hooks/instruction_reinforcement.py +1 -0
- claude_mpm/hooks/kuzu_memory_hook.py +20 -13
- claude_mpm/hooks/validation_hooks.py +1 -1
- claude_mpm/scripts/mpm_doctor.py +1 -0
- claude_mpm/services/agents/loading/agent_profile_loader.py +1 -1
- claude_mpm/services/agents/loading/base_agent_manager.py +1 -1
- claude_mpm/services/agents/loading/framework_agent_loader.py +1 -1
- claude_mpm/services/agents/management/agent_capabilities_generator.py +1 -0
- claude_mpm/services/agents/management/agent_management_service.py +1 -1
- claude_mpm/services/agents/memory/memory_categorization_service.py +0 -1
- claude_mpm/services/agents/memory/memory_file_service.py +6 -2
- claude_mpm/services/agents/memory/memory_format_service.py +0 -1
- claude_mpm/services/agents/registry/deployed_agent_discovery.py +1 -1
- claude_mpm/services/async_session_logger.py +1 -1
- claude_mpm/services/claude_session_logger.py +1 -0
- claude_mpm/services/core/path_resolver.py +1 -0
- claude_mpm/services/diagnostics/checks/__init__.py +2 -0
- claude_mpm/services/diagnostics/checks/installation_check.py +126 -25
- claude_mpm/services/diagnostics/checks/mcp_services_check.py +399 -0
- claude_mpm/services/diagnostics/diagnostic_runner.py +3 -0
- claude_mpm/services/diagnostics/doctor_reporter.py +259 -32
- claude_mpm/services/event_bus/direct_relay.py +2 -1
- claude_mpm/services/event_bus/event_bus.py +1 -0
- claude_mpm/services/event_bus/relay.py +3 -2
- claude_mpm/services/framework_claude_md_generator/content_assembler.py +1 -1
- claude_mpm/services/infrastructure/daemon_manager.py +1 -1
- claude_mpm/services/mcp_config_manager.py +10 -10
- claude_mpm/services/mcp_gateway/core/process_pool.py +62 -23
- claude_mpm/services/mcp_gateway/tools/__init__.py +6 -5
- claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +3 -1
- claude_mpm/services/mcp_gateway/tools/kuzu_memory_service.py +16 -31
- claude_mpm/services/memory/cache/simple_cache.py +1 -1
- claude_mpm/services/project/archive_manager.py +159 -96
- claude_mpm/services/project/documentation_manager.py +64 -45
- claude_mpm/services/project/enhanced_analyzer.py +132 -89
- claude_mpm/services/project/project_organizer.py +225 -131
- claude_mpm/services/response_tracker.py +1 -1
- claude_mpm/services/socketio/server/eventbus_integration.py +1 -1
- claude_mpm/services/unified/__init__.py +1 -1
- claude_mpm/services/unified/analyzer_strategies/__init__.py +3 -3
- claude_mpm/services/unified/analyzer_strategies/code_analyzer.py +97 -53
- claude_mpm/services/unified/analyzer_strategies/dependency_analyzer.py +81 -40
- claude_mpm/services/unified/analyzer_strategies/performance_analyzer.py +277 -178
- claude_mpm/services/unified/analyzer_strategies/security_analyzer.py +196 -112
- claude_mpm/services/unified/analyzer_strategies/structure_analyzer.py +83 -49
- claude_mpm/services/unified/config_strategies/__init__.py +111 -126
- claude_mpm/services/unified/config_strategies/config_schema.py +157 -111
- claude_mpm/services/unified/config_strategies/context_strategy.py +91 -89
- claude_mpm/services/unified/config_strategies/error_handling_strategy.py +183 -173
- claude_mpm/services/unified/config_strategies/file_loader_strategy.py +160 -152
- claude_mpm/services/unified/config_strategies/unified_config_service.py +124 -112
- claude_mpm/services/unified/config_strategies/validation_strategy.py +298 -259
- claude_mpm/services/unified/deployment_strategies/__init__.py +7 -7
- claude_mpm/services/unified/deployment_strategies/base.py +24 -28
- claude_mpm/services/unified/deployment_strategies/cloud_strategies.py +168 -88
- claude_mpm/services/unified/deployment_strategies/local.py +49 -34
- claude_mpm/services/unified/deployment_strategies/utils.py +39 -43
- claude_mpm/services/unified/deployment_strategies/vercel.py +30 -24
- claude_mpm/services/unified/interfaces.py +0 -26
- claude_mpm/services/unified/migration.py +17 -40
- claude_mpm/services/unified/strategies.py +9 -26
- claude_mpm/services/unified/unified_analyzer.py +48 -44
- claude_mpm/services/unified/unified_config.py +21 -19
- claude_mpm/services/unified/unified_deployment.py +21 -26
- claude_mpm/storage/state_storage.py +1 -0
- claude_mpm/utils/agent_dependency_loader.py +18 -6
- claude_mpm/utils/common.py +14 -12
- claude_mpm/utils/database_connector.py +15 -12
- claude_mpm/utils/error_handler.py +1 -0
- claude_mpm/utils/log_cleanup.py +1 -0
- claude_mpm/utils/path_operations.py +1 -0
- claude_mpm/utils/session_logging.py +1 -1
- claude_mpm/utils/subprocess_utils.py +1 -0
- claude_mpm/validation/agent_validator.py +1 -1
- {claude_mpm-4.4.3.dist-info → claude_mpm-4.4.4.dist-info}/METADATA +9 -3
- {claude_mpm-4.4.3.dist-info → claude_mpm-4.4.4.dist-info}/RECORD +118 -117
- {claude_mpm-4.4.3.dist-info → claude_mpm-4.4.4.dist-info}/WHEEL +0 -0
- {claude_mpm-4.4.3.dist-info → claude_mpm-4.4.4.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.4.3.dist-info → claude_mpm-4.4.4.dist-info}/licenses/LICENSE +0 -0
- {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
|
-
|
17
|
+
get_context,
|
18
18
|
recall_memories,
|
19
19
|
search_memories,
|
20
|
-
|
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
|
-
"
|
31
|
+
"SystemInfoToolAdapter",
|
32
|
+
"get_context",
|
32
33
|
"recall_memories",
|
33
34
|
"search_memories",
|
34
|
-
"
|
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(
|
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
|
-
|
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":
|
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)
|
@@ -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
|
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
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
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(
|
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,
|
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: {
|
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: {
|
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
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
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
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
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
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
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
|
-
|
528
|
-
|
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
|
-
|
566
|
-
|
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
|
-
|
596
|
-
|
597
|
-
|
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(
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
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
|
-
|
653
|
-
|
654
|
-
|
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(
|
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
|
-
|
664
|
-
|
665
|
-
|
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
|
-
|
677
|
-
|
678
|
-
|
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
|
-
|
683
|
-
|
684
|
-
|
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(
|
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(
|
712
|
-
|
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(
|
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(
|
721
|
-
|
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
|
-
"
|
778
|
-
}
|
779
|
-
|
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(
|
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(
|
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(
|
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: {
|
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 =
|
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(
|
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(
|
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)
|