claude-mpm 3.3.2__py3-none-any.whl → 3.4.2__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/cli/commands/memory.py +192 -14
- claude_mpm/cli/parser.py +13 -1
- claude_mpm/constants.py +1 -0
- claude_mpm/core/claude_runner.py +61 -0
- claude_mpm/core/config.py +161 -1
- claude_mpm/core/simple_runner.py +61 -0
- claude_mpm/hooks/builtin/mpm_command_hook.py +5 -5
- claude_mpm/hooks/claude_hooks/hook_handler.py +211 -4
- claude_mpm/hooks/claude_hooks/hook_wrapper.sh +10 -3
- claude_mpm/hooks/memory_integration_hook.py +51 -5
- claude_mpm/scripts/socketio_daemon.py +49 -9
- claude_mpm/scripts/socketio_server_manager.py +370 -45
- claude_mpm/services/__init__.py +41 -5
- claude_mpm/services/agent_memory_manager.py +541 -51
- claude_mpm/services/exceptions.py +677 -0
- claude_mpm/services/health_monitor.py +892 -0
- claude_mpm/services/memory_builder.py +341 -7
- claude_mpm/services/memory_optimizer.py +6 -2
- claude_mpm/services/project_analyzer.py +771 -0
- claude_mpm/services/recovery_manager.py +670 -0
- claude_mpm/services/socketio_server.py +653 -36
- claude_mpm/services/standalone_socketio_server.py +703 -34
- claude_mpm/services/version_control/git_operations.py +26 -0
- {claude_mpm-3.3.2.dist-info → claude_mpm-3.4.2.dist-info}/METADATA +34 -10
- {claude_mpm-3.3.2.dist-info → claude_mpm-3.4.2.dist-info}/RECORD +30 -44
- claude_mpm/agents/agent-template.yaml +0 -83
- claude_mpm/agents/test_fix_deployment/.claude-pm/config/project.json +0 -6
- claude_mpm/cli/README.md +0 -109
- claude_mpm/cli_module/refactoring_guide.md +0 -253
- claude_mpm/core/agent_registry.py.bak +0 -312
- claude_mpm/core/base_service.py.bak +0 -406
- claude_mpm/hooks/README.md +0 -97
- claude_mpm/orchestration/SUBPROCESS_DESIGN.md +0 -66
- claude_mpm/schemas/README_SECURITY.md +0 -92
- claude_mpm/schemas/agent_schema.json +0 -395
- claude_mpm/schemas/agent_schema_documentation.md +0 -181
- claude_mpm/schemas/agent_schema_security_notes.md +0 -165
- claude_mpm/schemas/examples/standard_workflow.json +0 -505
- claude_mpm/schemas/ticket_workflow_documentation.md +0 -482
- claude_mpm/schemas/ticket_workflow_schema.json +0 -590
- claude_mpm/services/framework_claude_md_generator/README.md +0 -92
- claude_mpm/services/parent_directory_manager/README.md +0 -83
- claude_mpm/services/version_control/VERSION +0 -1
- /claude_mpm/{web → dashboard}/open_dashboard.py +0 -0
- {claude_mpm-3.3.2.dist-info → claude_mpm-3.4.2.dist-info}/WHEEL +0 -0
- {claude_mpm-3.3.2.dist-info → claude_mpm-3.4.2.dist-info}/entry_points.txt +0 -0
- {claude_mpm-3.3.2.dist-info → claude_mpm-3.4.2.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-3.3.2.dist-info → claude_mpm-3.4.2.dist-info}/top_level.txt +0 -0
|
@@ -23,6 +23,7 @@ while preserving essential information.
|
|
|
23
23
|
"""
|
|
24
24
|
|
|
25
25
|
import re
|
|
26
|
+
import os
|
|
26
27
|
from pathlib import Path
|
|
27
28
|
from typing import Dict, List, Optional, Any, Tuple
|
|
28
29
|
from datetime import datetime
|
|
@@ -31,6 +32,7 @@ from claude_mpm.core import LoggerMixin
|
|
|
31
32
|
from claude_mpm.core.config import Config
|
|
32
33
|
from claude_mpm.utils.paths import PathResolver
|
|
33
34
|
from claude_mpm.services.memory_router import MemoryRouter
|
|
35
|
+
from claude_mpm.services.project_analyzer import ProjectAnalyzer
|
|
34
36
|
|
|
35
37
|
|
|
36
38
|
class MemoryBuilder(LoggerMixin):
|
|
@@ -98,17 +100,110 @@ class MemoryBuilder(LoggerMixin):
|
|
|
98
100
|
]
|
|
99
101
|
}
|
|
100
102
|
|
|
101
|
-
def __init__(self, config: Optional[Config] = None):
|
|
103
|
+
def __init__(self, config: Optional[Config] = None, working_directory: Optional[Path] = None):
|
|
102
104
|
"""Initialize the memory builder.
|
|
103
105
|
|
|
104
106
|
Args:
|
|
105
107
|
config: Optional Config object
|
|
108
|
+
working_directory: Optional working directory for project-specific analysis
|
|
106
109
|
"""
|
|
107
110
|
super().__init__()
|
|
108
111
|
self.config = config or Config()
|
|
109
112
|
self.project_root = PathResolver.get_project_root()
|
|
110
|
-
|
|
113
|
+
# Use current working directory by default, not project root
|
|
114
|
+
self.working_directory = working_directory or Path(os.getcwd())
|
|
115
|
+
self.memories_dir = self.working_directory / ".claude-mpm" / "memories"
|
|
111
116
|
self.router = MemoryRouter(config)
|
|
117
|
+
self.project_analyzer = ProjectAnalyzer(config, self.working_directory)
|
|
118
|
+
|
|
119
|
+
def _get_dynamic_doc_files(self) -> Dict[str, Dict[str, Any]]:
|
|
120
|
+
"""Get documentation files to process based on project analysis.
|
|
121
|
+
|
|
122
|
+
WHY: Instead of hardcoded file list, dynamically discover important files
|
|
123
|
+
based on actual project structure and characteristics.
|
|
124
|
+
|
|
125
|
+
Returns:
|
|
126
|
+
Dict mapping file paths to processing configuration
|
|
127
|
+
"""
|
|
128
|
+
dynamic_files = {}
|
|
129
|
+
|
|
130
|
+
# Start with static important files
|
|
131
|
+
static_files = self.DOC_FILES.copy()
|
|
132
|
+
|
|
133
|
+
# Get project-specific important files
|
|
134
|
+
try:
|
|
135
|
+
important_files = self.project_analyzer.get_important_files_for_context()
|
|
136
|
+
project_characteristics = self.project_analyzer.analyze_project()
|
|
137
|
+
|
|
138
|
+
# Add configuration files
|
|
139
|
+
for config_file in project_characteristics.important_configs:
|
|
140
|
+
if config_file not in static_files:
|
|
141
|
+
file_ext = Path(config_file).suffix.lower()
|
|
142
|
+
|
|
143
|
+
if file_ext in ['.json', '.toml', '.yaml', '.yml']:
|
|
144
|
+
dynamic_files[config_file] = {
|
|
145
|
+
'priority': 'medium',
|
|
146
|
+
'sections': ['configuration', 'setup', 'dependencies'],
|
|
147
|
+
'agents': ['engineer', 'pm'],
|
|
148
|
+
'file_type': 'config'
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
# Add project-specific documentation
|
|
152
|
+
for doc_file in important_files:
|
|
153
|
+
if doc_file not in static_files and doc_file not in dynamic_files:
|
|
154
|
+
file_path = Path(doc_file)
|
|
155
|
+
|
|
156
|
+
# Determine processing config based on file name/path
|
|
157
|
+
if 'api' in doc_file.lower() or 'endpoint' in doc_file.lower():
|
|
158
|
+
dynamic_files[doc_file] = {
|
|
159
|
+
'priority': 'high',
|
|
160
|
+
'sections': ['api', 'endpoints', 'integration'],
|
|
161
|
+
'agents': ['engineer', 'integration'],
|
|
162
|
+
'file_type': 'api_doc'
|
|
163
|
+
}
|
|
164
|
+
elif 'architecture' in doc_file.lower() or 'design' in doc_file.lower():
|
|
165
|
+
dynamic_files[doc_file] = {
|
|
166
|
+
'priority': 'high',
|
|
167
|
+
'sections': ['architecture', 'design', 'patterns'],
|
|
168
|
+
'agents': ['engineer', 'architect'],
|
|
169
|
+
'file_type': 'architecture'
|
|
170
|
+
}
|
|
171
|
+
elif 'test' in doc_file.lower():
|
|
172
|
+
dynamic_files[doc_file] = {
|
|
173
|
+
'priority': 'medium',
|
|
174
|
+
'sections': ['testing', 'quality'],
|
|
175
|
+
'agents': ['qa', 'engineer'],
|
|
176
|
+
'file_type': 'test_doc'
|
|
177
|
+
}
|
|
178
|
+
elif file_path.suffix.lower() == '.md':
|
|
179
|
+
# Generic markdown file
|
|
180
|
+
dynamic_files[doc_file] = {
|
|
181
|
+
'priority': 'low',
|
|
182
|
+
'sections': ['documentation', 'guidelines'],
|
|
183
|
+
'agents': ['pm', 'engineer'],
|
|
184
|
+
'file_type': 'markdown'
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
# Add key source files for pattern analysis (limited selection)
|
|
188
|
+
if project_characteristics.entry_points:
|
|
189
|
+
for entry_point in project_characteristics.entry_points[:2]: # Only first 2
|
|
190
|
+
if entry_point not in dynamic_files:
|
|
191
|
+
dynamic_files[entry_point] = {
|
|
192
|
+
'priority': 'low',
|
|
193
|
+
'sections': ['patterns', 'implementation'],
|
|
194
|
+
'agents': ['engineer'],
|
|
195
|
+
'file_type': 'source',
|
|
196
|
+
'extract_patterns_only': True # Only extract patterns, not full content
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
except Exception as e:
|
|
200
|
+
self.logger.warning(f"Error getting dynamic doc files: {e}")
|
|
201
|
+
|
|
202
|
+
# Merge static and dynamic files
|
|
203
|
+
all_files = {**static_files, **dynamic_files}
|
|
204
|
+
|
|
205
|
+
self.logger.debug(f"Processing {len(all_files)} documentation files ({len(static_files)} static, {len(dynamic_files)} dynamic)")
|
|
206
|
+
return all_files
|
|
112
207
|
|
|
113
208
|
def build_from_documentation(self, force_rebuild: bool = False) -> Dict[str, Any]:
|
|
114
209
|
"""Build agent memories from project documentation.
|
|
@@ -134,8 +229,11 @@ class MemoryBuilder(LoggerMixin):
|
|
|
134
229
|
"errors": []
|
|
135
230
|
}
|
|
136
231
|
|
|
232
|
+
# Get dynamic list of files to process
|
|
233
|
+
doc_files = self._get_dynamic_doc_files()
|
|
234
|
+
|
|
137
235
|
# Process each documentation file
|
|
138
|
-
for doc_path, doc_config in
|
|
236
|
+
for doc_path, doc_config in doc_files.items():
|
|
139
237
|
file_path = self.project_root / doc_path
|
|
140
238
|
|
|
141
239
|
if not file_path.exists():
|
|
@@ -292,8 +390,236 @@ class MemoryBuilder(LoggerMixin):
|
|
|
292
390
|
"error": str(e)
|
|
293
391
|
}
|
|
294
392
|
|
|
393
|
+
def _extract_from_config_file(self, content: str, file_path: Path, doc_config: Dict[str, Any]) -> List[Dict[str, Any]]:
|
|
394
|
+
"""Extract memory-worthy information from configuration files.
|
|
395
|
+
|
|
396
|
+
WHY: Configuration files contain important setup patterns, dependencies,
|
|
397
|
+
and architectural decisions that agents should understand.
|
|
398
|
+
|
|
399
|
+
Args:
|
|
400
|
+
content: File content
|
|
401
|
+
file_path: Path to the file
|
|
402
|
+
doc_config: Processing configuration
|
|
403
|
+
|
|
404
|
+
Returns:
|
|
405
|
+
List of extracted memory items
|
|
406
|
+
"""
|
|
407
|
+
extracted_items = []
|
|
408
|
+
source = str(file_path.relative_to(self.project_root))
|
|
409
|
+
|
|
410
|
+
try:
|
|
411
|
+
file_ext = file_path.suffix.lower()
|
|
412
|
+
|
|
413
|
+
if file_ext == '.json':
|
|
414
|
+
# Parse JSON configuration
|
|
415
|
+
import json
|
|
416
|
+
config_data = json.loads(content)
|
|
417
|
+
items = self._extract_from_json_config(config_data, source)
|
|
418
|
+
extracted_items.extend(items)
|
|
419
|
+
|
|
420
|
+
elif file_ext in ['.toml']:
|
|
421
|
+
# Parse TOML configuration
|
|
422
|
+
try:
|
|
423
|
+
try:
|
|
424
|
+
import tomllib
|
|
425
|
+
except ImportError:
|
|
426
|
+
import tomli as tomllib
|
|
427
|
+
with open(file_path, 'rb') as f:
|
|
428
|
+
config_data = tomllib.load(f)
|
|
429
|
+
items = self._extract_from_toml_config(config_data, source)
|
|
430
|
+
extracted_items.extend(items)
|
|
431
|
+
except ImportError:
|
|
432
|
+
self.logger.warning(f"TOML parsing not available for {source}")
|
|
433
|
+
|
|
434
|
+
elif file_ext in ['.yaml', '.yml']:
|
|
435
|
+
# For YAML, fall back to text-based extraction for now
|
|
436
|
+
items = self.extract_from_text(content, source)
|
|
437
|
+
extracted_items.extend(items)
|
|
438
|
+
|
|
439
|
+
# Also extract text patterns for comments and documentation
|
|
440
|
+
text_items = self.extract_from_text(content, source)
|
|
441
|
+
extracted_items.extend(text_items)
|
|
442
|
+
|
|
443
|
+
except Exception as e:
|
|
444
|
+
self.logger.warning(f"Error parsing config file {source}: {e}")
|
|
445
|
+
# Fall back to text extraction
|
|
446
|
+
extracted_items = self.extract_from_text(content, source)
|
|
447
|
+
|
|
448
|
+
return extracted_items
|
|
449
|
+
|
|
450
|
+
def _extract_from_json_config(self, config_data: dict, source: str) -> List[Dict[str, Any]]:
|
|
451
|
+
"""Extract patterns from JSON configuration."""
|
|
452
|
+
items = []
|
|
453
|
+
|
|
454
|
+
# Extract dependencies information
|
|
455
|
+
if 'dependencies' in config_data:
|
|
456
|
+
deps = config_data['dependencies']
|
|
457
|
+
if isinstance(deps, dict) and deps:
|
|
458
|
+
dep_names = list(deps.keys())[:5] # Limit to prevent overwhelming
|
|
459
|
+
deps_str = ", ".join(dep_names)
|
|
460
|
+
items.append({
|
|
461
|
+
"content": f"Key dependencies: {deps_str}",
|
|
462
|
+
"type": "dependency_info",
|
|
463
|
+
"source": source,
|
|
464
|
+
"target_agent": "engineer",
|
|
465
|
+
"section": "Current Technical Context",
|
|
466
|
+
"confidence": 0.8
|
|
467
|
+
})
|
|
468
|
+
|
|
469
|
+
# Extract scripts (for package.json)
|
|
470
|
+
if 'scripts' in config_data:
|
|
471
|
+
scripts = config_data['scripts']
|
|
472
|
+
if isinstance(scripts, dict):
|
|
473
|
+
for script_name, script_cmd in list(scripts.items())[:3]: # Limit to first 3
|
|
474
|
+
items.append({
|
|
475
|
+
"content": f"Build script '{script_name}': {script_cmd[:50]}{'...' if len(script_cmd) > 50 else ''}",
|
|
476
|
+
"type": "build_pattern",
|
|
477
|
+
"source": source,
|
|
478
|
+
"target_agent": "engineer",
|
|
479
|
+
"section": "Implementation Guidelines",
|
|
480
|
+
"confidence": 0.7
|
|
481
|
+
})
|
|
482
|
+
|
|
483
|
+
return items
|
|
484
|
+
|
|
485
|
+
def _extract_from_toml_config(self, config_data: dict, source: str) -> List[Dict[str, Any]]:
|
|
486
|
+
"""Extract patterns from TOML configuration."""
|
|
487
|
+
items = []
|
|
488
|
+
|
|
489
|
+
# Extract project metadata (for pyproject.toml)
|
|
490
|
+
if 'project' in config_data:
|
|
491
|
+
project_info = config_data['project']
|
|
492
|
+
if 'dependencies' in project_info:
|
|
493
|
+
deps = project_info['dependencies']
|
|
494
|
+
if deps:
|
|
495
|
+
items.append({
|
|
496
|
+
"content": f"Python dependencies: {', '.join(deps[:5])}",
|
|
497
|
+
"type": "dependency_info",
|
|
498
|
+
"source": source,
|
|
499
|
+
"target_agent": "engineer",
|
|
500
|
+
"section": "Current Technical Context",
|
|
501
|
+
"confidence": 0.8
|
|
502
|
+
})
|
|
503
|
+
|
|
504
|
+
# Extract Rust dependencies (for Cargo.toml)
|
|
505
|
+
if 'dependencies' in config_data:
|
|
506
|
+
deps = config_data['dependencies']
|
|
507
|
+
if isinstance(deps, dict) and deps:
|
|
508
|
+
dep_names = list(deps.keys())[:5]
|
|
509
|
+
items.append({
|
|
510
|
+
"content": f"Rust dependencies: {', '.join(dep_names)}",
|
|
511
|
+
"type": "dependency_info",
|
|
512
|
+
"source": source,
|
|
513
|
+
"target_agent": "engineer",
|
|
514
|
+
"section": "Current Technical Context",
|
|
515
|
+
"confidence": 0.8
|
|
516
|
+
})
|
|
517
|
+
|
|
518
|
+
return items
|
|
519
|
+
|
|
520
|
+
def _extract_from_source_file(self, content: str, file_path: Path, doc_config: Dict[str, Any]) -> List[Dict[str, Any]]:
|
|
521
|
+
"""Extract patterns from source code files.
|
|
522
|
+
|
|
523
|
+
WHY: Source files contain implementation patterns and architectural
|
|
524
|
+
decisions that agents should be aware of, but we only extract high-level
|
|
525
|
+
patterns rather than detailed code analysis.
|
|
526
|
+
|
|
527
|
+
Args:
|
|
528
|
+
content: File content
|
|
529
|
+
file_path: Path to the file
|
|
530
|
+
doc_config: Processing configuration
|
|
531
|
+
|
|
532
|
+
Returns:
|
|
533
|
+
List of extracted memory items
|
|
534
|
+
"""
|
|
535
|
+
extracted_items = []
|
|
536
|
+
source = str(file_path.relative_to(self.project_root))
|
|
537
|
+
|
|
538
|
+
# Only extract patterns if specified
|
|
539
|
+
if not doc_config.get('extract_patterns_only', False):
|
|
540
|
+
return []
|
|
541
|
+
|
|
542
|
+
file_ext = file_path.suffix.lower()
|
|
543
|
+
|
|
544
|
+
# Language-specific pattern extraction
|
|
545
|
+
if file_ext == '.py':
|
|
546
|
+
items = self._extract_python_patterns(content, source)
|
|
547
|
+
extracted_items.extend(items)
|
|
548
|
+
elif file_ext in ['.js', '.ts']:
|
|
549
|
+
items = self._extract_javascript_patterns(content, source)
|
|
550
|
+
extracted_items.extend(items)
|
|
551
|
+
|
|
552
|
+
return extracted_items[:3] # Limit to prevent overwhelming
|
|
553
|
+
|
|
554
|
+
def _extract_python_patterns(self, content: str, source: str) -> List[Dict[str, Any]]:
|
|
555
|
+
"""Extract high-level patterns from Python source."""
|
|
556
|
+
items = []
|
|
557
|
+
|
|
558
|
+
# Check for common patterns
|
|
559
|
+
if 'if __name__ == "__main__"' in content:
|
|
560
|
+
items.append({
|
|
561
|
+
"content": "Uses if __name__ == '__main__' pattern for script execution",
|
|
562
|
+
"type": "pattern",
|
|
563
|
+
"source": source,
|
|
564
|
+
"target_agent": "engineer",
|
|
565
|
+
"section": "Coding Patterns Learned",
|
|
566
|
+
"confidence": 0.8
|
|
567
|
+
})
|
|
568
|
+
|
|
569
|
+
if 'from pathlib import Path' in content:
|
|
570
|
+
items.append({
|
|
571
|
+
"content": "Uses pathlib.Path for file operations (recommended pattern)",
|
|
572
|
+
"type": "pattern",
|
|
573
|
+
"source": source,
|
|
574
|
+
"target_agent": "engineer",
|
|
575
|
+
"section": "Coding Patterns Learned",
|
|
576
|
+
"confidence": 0.7
|
|
577
|
+
})
|
|
578
|
+
|
|
579
|
+
# Check for class definitions
|
|
580
|
+
class_matches = re.findall(r'class\s+(\w+)', content)
|
|
581
|
+
if class_matches:
|
|
582
|
+
items.append({
|
|
583
|
+
"content": f"Defines classes: {', '.join(class_matches[:3])}",
|
|
584
|
+
"type": "architecture",
|
|
585
|
+
"source": source,
|
|
586
|
+
"target_agent": "engineer",
|
|
587
|
+
"section": "Project Architecture",
|
|
588
|
+
"confidence": 0.6
|
|
589
|
+
})
|
|
590
|
+
|
|
591
|
+
return items
|
|
592
|
+
|
|
593
|
+
def _extract_javascript_patterns(self, content: str, source: str) -> List[Dict[str, Any]]:
|
|
594
|
+
"""Extract high-level patterns from JavaScript/TypeScript source."""
|
|
595
|
+
items = []
|
|
596
|
+
|
|
597
|
+
# Check for async patterns
|
|
598
|
+
if 'async function' in content or 'async ' in content:
|
|
599
|
+
items.append({
|
|
600
|
+
"content": "Uses async/await patterns for asynchronous operations",
|
|
601
|
+
"type": "pattern",
|
|
602
|
+
"source": source,
|
|
603
|
+
"target_agent": "engineer",
|
|
604
|
+
"section": "Coding Patterns Learned",
|
|
605
|
+
"confidence": 0.8
|
|
606
|
+
})
|
|
607
|
+
|
|
608
|
+
# Check for module patterns
|
|
609
|
+
if 'export ' in content:
|
|
610
|
+
items.append({
|
|
611
|
+
"content": "Uses ES6 module export patterns",
|
|
612
|
+
"type": "pattern",
|
|
613
|
+
"source": source,
|
|
614
|
+
"target_agent": "engineer",
|
|
615
|
+
"section": "Coding Patterns Learned",
|
|
616
|
+
"confidence": 0.7
|
|
617
|
+
})
|
|
618
|
+
|
|
619
|
+
return items
|
|
620
|
+
|
|
295
621
|
def _process_documentation_file(self, file_path: Path, doc_config: Dict[str, Any]) -> Dict[str, Any]:
|
|
296
|
-
"""Process a single documentation file.
|
|
622
|
+
"""Process a single documentation file with enhanced file type support.
|
|
297
623
|
|
|
298
624
|
Args:
|
|
299
625
|
file_path: Path to documentation file
|
|
@@ -304,10 +630,18 @@ class MemoryBuilder(LoggerMixin):
|
|
|
304
630
|
"""
|
|
305
631
|
try:
|
|
306
632
|
# Read file content
|
|
307
|
-
content = file_path.read_text(encoding='utf-8')
|
|
633
|
+
content = file_path.read_text(encoding='utf-8', errors='ignore')
|
|
308
634
|
|
|
309
|
-
#
|
|
310
|
-
|
|
635
|
+
# Handle different file types
|
|
636
|
+
file_type = doc_config.get('file_type', 'markdown')
|
|
637
|
+
|
|
638
|
+
if file_type == 'config':
|
|
639
|
+
extracted_items = self._extract_from_config_file(content, file_path, doc_config)
|
|
640
|
+
elif file_type == 'source':
|
|
641
|
+
extracted_items = self._extract_from_source_file(content, file_path, doc_config)
|
|
642
|
+
else:
|
|
643
|
+
# Default markdown/text processing
|
|
644
|
+
extracted_items = self.extract_from_text(content, str(file_path.relative_to(self.project_root)))
|
|
311
645
|
|
|
312
646
|
result = {
|
|
313
647
|
"success": True,
|
|
@@ -23,6 +23,7 @@ information than lose important insights.
|
|
|
23
23
|
"""
|
|
24
24
|
|
|
25
25
|
import re
|
|
26
|
+
import os
|
|
26
27
|
from pathlib import Path
|
|
27
28
|
from typing import Dict, List, Optional, Any, Set, Tuple
|
|
28
29
|
from datetime import datetime
|
|
@@ -57,16 +58,19 @@ class MemoryOptimizer(LoggerMixin):
|
|
|
57
58
|
'low': ['note', 'tip', 'hint', 'example', 'reference']
|
|
58
59
|
}
|
|
59
60
|
|
|
60
|
-
def __init__(self, config: Optional[Config] = None):
|
|
61
|
+
def __init__(self, config: Optional[Config] = None, working_directory: Optional[Path] = None):
|
|
61
62
|
"""Initialize the memory optimizer.
|
|
62
63
|
|
|
63
64
|
Args:
|
|
64
65
|
config: Optional Config object
|
|
66
|
+
working_directory: Optional working directory. If not provided, uses current working directory.
|
|
65
67
|
"""
|
|
66
68
|
super().__init__()
|
|
67
69
|
self.config = config or Config()
|
|
68
70
|
self.project_root = PathResolver.get_project_root()
|
|
69
|
-
|
|
71
|
+
# Use current working directory by default, not project root
|
|
72
|
+
self.working_directory = working_directory or Path(os.getcwd())
|
|
73
|
+
self.memories_dir = self.working_directory / ".claude-mpm" / "memories"
|
|
70
74
|
|
|
71
75
|
def optimize_agent_memory(self, agent_id: str) -> Dict[str, Any]:
|
|
72
76
|
"""Optimize memory for a specific agent.
|