claude-mpm 4.4.0__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/WORKFLOW.md +2 -14
- 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/configure.py +2 -29
- claude_mpm/cli/commands/doctor.py +44 -5
- claude_mpm/cli/commands/mpm_init.py +117 -63
- claude_mpm/cli/parsers/configure_parser.py +6 -15
- 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 +38 -0
- claude_mpm/core/framework/formatters/__init__.py +11 -0
- claude_mpm/core/framework/formatters/capability_generator.py +367 -0
- claude_mpm/core/framework/formatters/content_formatter.py +288 -0
- claude_mpm/core/framework/formatters/context_generator.py +184 -0
- claude_mpm/core/framework/loaders/__init__.py +13 -0
- claude_mpm/core/framework/loaders/agent_loader.py +206 -0
- claude_mpm/core/framework/loaders/file_loader.py +223 -0
- claude_mpm/core/framework/loaders/instruction_loader.py +161 -0
- claude_mpm/core/framework/loaders/packaged_loader.py +232 -0
- claude_mpm/core/framework/processors/__init__.py +11 -0
- claude_mpm/core/framework/processors/memory_processor.py +230 -0
- claude_mpm/core/framework/processors/metadata_processor.py +146 -0
- claude_mpm/core/framework/processors/template_processor.py +244 -0
- claude_mpm/core/framework_loader.py +298 -1795
- 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/__init__.py +9 -1
- claude_mpm/hooks/base_hook.py +1 -0
- claude_mpm/hooks/instruction_reinforcement.py +1 -0
- claude_mpm/hooks/kuzu_memory_hook.py +359 -0
- 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 +2 -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 +4 -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 +67 -4
- claude_mpm/services/mcp_gateway/core/process_pool.py +320 -0
- claude_mpm/services/mcp_gateway/core/startup_verification.py +2 -2
- claude_mpm/services/mcp_gateway/main.py +3 -13
- claude_mpm/services/mcp_gateway/server/stdio_server.py +4 -10
- claude_mpm/services/mcp_gateway/tools/__init__.py +14 -2
- claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +38 -6
- claude_mpm/services/mcp_gateway/tools/kuzu_memory_service.py +527 -0
- 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/shared/__init__.py +2 -1
- claude_mpm/services/shared/service_factory.py +8 -5
- 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 +175 -0
- claude_mpm/services/unified/config_strategies/config_schema.py +735 -0
- claude_mpm/services/unified/config_strategies/context_strategy.py +750 -0
- claude_mpm/services/unified/config_strategies/error_handling_strategy.py +1009 -0
- claude_mpm/services/unified/config_strategies/file_loader_strategy.py +879 -0
- claude_mpm/services/unified/config_strategies/unified_config_service.py +814 -0
- claude_mpm/services/unified/config_strategies/validation_strategy.py +1144 -0
- 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.0.dist-info → claude_mpm-4.4.4.dist-info}/METADATA +23 -17
- {claude_mpm-4.4.0.dist-info → claude_mpm-4.4.4.dist-info}/RECORD +126 -105
- claude_mpm/cli/commands/configure_tui.py +0 -1927
- claude_mpm/services/mcp_gateway/tools/ticket_tools.py +0 -645
- claude_mpm/services/mcp_gateway/tools/unified_ticket_tool.py +0 -602
- {claude_mpm-4.4.0.dist-info → claude_mpm-4.4.4.dist-info}/WHEEL +0 -0
- {claude_mpm-4.4.0.dist-info → claude_mpm-4.4.4.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.4.0.dist-info → claude_mpm-4.4.4.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.4.0.dist-info → claude_mpm-4.4.4.dist-info}/top_level.txt +0 -0
claude_mpm/core/log_manager.py
CHANGED
@@ -23,10 +23,11 @@ from queue import Full, Queue
|
|
23
23
|
from threading import Lock, Thread
|
24
24
|
from typing import Any, Dict, Optional
|
25
25
|
|
26
|
+
from claude_mpm.core.logging_utils import get_logger
|
27
|
+
|
26
28
|
from ..core.config import Config
|
27
29
|
from ..core.constants import SystemLimits
|
28
30
|
|
29
|
-
from claude_mpm.core.logging_utils import get_logger
|
30
31
|
logger = get_logger(__name__)
|
31
32
|
|
32
33
|
# Import cleanup utility for automatic cleanup
|
@@ -34,9 +34,10 @@ from enum import Enum
|
|
34
34
|
from pathlib import Path
|
35
35
|
from typing import Any, Dict, List, Optional, Set, Union
|
36
36
|
|
37
|
+
from claude_mpm.core.logging_utils import get_logger
|
38
|
+
|
37
39
|
from .unified_paths import get_path_manager
|
38
40
|
|
39
|
-
from claude_mpm.core.logging_utils import get_logger
|
40
41
|
logger = get_logger(__name__)
|
41
42
|
|
42
43
|
|
claude_mpm/core/unified_paths.py
CHANGED
@@ -54,6 +54,7 @@ class CLIContext:
|
|
54
54
|
def setup_logging(self, debug: bool = False) -> None:
|
55
55
|
"""Setup logging based on debug flag."""
|
56
56
|
import logging
|
57
|
+
|
57
58
|
level = logging.DEBUG if debug else logging.INFO
|
58
59
|
format_str = (
|
59
60
|
"%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
claude_mpm/hooks/__init__.py
CHANGED
@@ -1,5 +1,13 @@
|
|
1
1
|
"""Hook system for claude-mpm."""
|
2
2
|
|
3
3
|
from .base_hook import BaseHook, HookContext, HookResult, HookType
|
4
|
+
from .kuzu_memory_hook import KuzuMemoryHook, get_kuzu_memory_hook
|
4
5
|
|
5
|
-
__all__ = [
|
6
|
+
__all__ = [
|
7
|
+
"BaseHook",
|
8
|
+
"HookContext",
|
9
|
+
"HookResult",
|
10
|
+
"HookType",
|
11
|
+
"KuzuMemoryHook",
|
12
|
+
"get_kuzu_memory_hook",
|
13
|
+
]
|
claude_mpm/hooks/base_hook.py
CHANGED
@@ -0,0 +1,359 @@
|
|
1
|
+
"""
|
2
|
+
Kuzu-Memory Integration Hook
|
3
|
+
============================
|
4
|
+
|
5
|
+
Integrates kuzu-memory knowledge graph with Claude MPM for persistent memory
|
6
|
+
across conversations. This hook intercepts user prompts to enrich them with
|
7
|
+
relevant memories and stores new learnings after responses.
|
8
|
+
|
9
|
+
WHY: Claude MPM needs a way to persistently remember information across
|
10
|
+
different conversations and sessions. Kuzu-memory provides a graph database
|
11
|
+
for structured memory storage with semantic search capabilities.
|
12
|
+
|
13
|
+
DESIGN DECISIONS:
|
14
|
+
- Priority 10 for early execution to enrich prompts before other hooks
|
15
|
+
- Uses subprocess to call kuzu-memory directly for maximum compatibility
|
16
|
+
- Graceful degradation if kuzu-memory is not installed
|
17
|
+
- Automatic extraction and storage of important information
|
18
|
+
"""
|
19
|
+
|
20
|
+
import json
|
21
|
+
import re
|
22
|
+
import shutil
|
23
|
+
import subprocess
|
24
|
+
from pathlib import Path
|
25
|
+
from typing import Any, Dict, List, Optional
|
26
|
+
|
27
|
+
from claude_mpm.core.logging_utils import get_logger
|
28
|
+
from claude_mpm.hooks.base_hook import HookContext, HookResult, SubmitHook
|
29
|
+
|
30
|
+
logger = get_logger(__name__)
|
31
|
+
|
32
|
+
|
33
|
+
class KuzuMemoryHook(SubmitHook):
|
34
|
+
"""
|
35
|
+
Hook that integrates kuzu-memory for persistent knowledge management.
|
36
|
+
|
37
|
+
This hook:
|
38
|
+
1. Checks if kuzu-memory is installed via pipx
|
39
|
+
2. Enriches user prompts with relevant memories
|
40
|
+
3. Stores important information from conversations
|
41
|
+
4. Provides context-aware memory retrieval
|
42
|
+
"""
|
43
|
+
|
44
|
+
def __init__(self):
|
45
|
+
"""Initialize the kuzu-memory integration hook."""
|
46
|
+
super().__init__(name="kuzu_memory_integration", priority=10)
|
47
|
+
|
48
|
+
# Check if kuzu-memory is available
|
49
|
+
self.kuzu_memory_cmd = self._detect_kuzu_memory()
|
50
|
+
self.enabled = self.kuzu_memory_cmd is not None
|
51
|
+
|
52
|
+
if not self.enabled:
|
53
|
+
logger.info("Kuzu-memory not found. Install with: pipx install kuzu-memory")
|
54
|
+
else:
|
55
|
+
logger.info(f"Kuzu-memory integration enabled: {self.kuzu_memory_cmd}")
|
56
|
+
|
57
|
+
# Use current project directory (kuzu-memory works with project-specific databases)
|
58
|
+
self.project_path = Path.cwd()
|
59
|
+
|
60
|
+
# Memory extraction patterns
|
61
|
+
self.memory_patterns = [
|
62
|
+
r"#\s*(?:Remember|Memorize|Store):\s*(.+?)(?:#|$)",
|
63
|
+
r"(?:Important|Note|Key point):\s*(.+?)(?:\n|$)",
|
64
|
+
r"(?:Learned|Discovered|Found that):\s*(.+?)(?:\n|$)",
|
65
|
+
]
|
66
|
+
|
67
|
+
def _detect_kuzu_memory(self) -> Optional[str]:
|
68
|
+
"""
|
69
|
+
Detect if kuzu-memory is installed and return its command path.
|
70
|
+
|
71
|
+
Priority:
|
72
|
+
1. Check pipx installation
|
73
|
+
2. Check system PATH
|
74
|
+
3. Return None if not found
|
75
|
+
"""
|
76
|
+
# Check pipx installation
|
77
|
+
pipx_path = (
|
78
|
+
Path.home()
|
79
|
+
/ ".local"
|
80
|
+
/ "pipx"
|
81
|
+
/ "venvs"
|
82
|
+
/ "kuzu-memory"
|
83
|
+
/ "bin"
|
84
|
+
/ "kuzu-memory"
|
85
|
+
)
|
86
|
+
if pipx_path.exists():
|
87
|
+
return str(pipx_path)
|
88
|
+
|
89
|
+
# Check system PATH
|
90
|
+
kuzu_cmd = shutil.which("kuzu-memory")
|
91
|
+
if kuzu_cmd:
|
92
|
+
return kuzu_cmd
|
93
|
+
|
94
|
+
return None
|
95
|
+
|
96
|
+
def execute(self, context: HookContext) -> HookResult:
|
97
|
+
"""
|
98
|
+
Process user prompts with kuzu-memory integration.
|
99
|
+
|
100
|
+
This method:
|
101
|
+
1. Retrieves relevant memories for the prompt
|
102
|
+
2. Enriches the prompt with memory context
|
103
|
+
3. Stores new memories after processing
|
104
|
+
"""
|
105
|
+
if not self.enabled:
|
106
|
+
return HookResult(success=True, data=context.data, modified=False)
|
107
|
+
|
108
|
+
try:
|
109
|
+
# Extract user prompt
|
110
|
+
prompt = context.data.get("prompt", "")
|
111
|
+
if not prompt:
|
112
|
+
return HookResult(success=True, data=context.data, modified=False)
|
113
|
+
|
114
|
+
# Retrieve relevant memories
|
115
|
+
memories = self._retrieve_memories(prompt)
|
116
|
+
|
117
|
+
if memories:
|
118
|
+
# Enrich prompt with memories
|
119
|
+
enriched_data = self._enrich_prompt(context.data, prompt, memories)
|
120
|
+
|
121
|
+
logger.info(f"Enriched prompt with {len(memories)} memories")
|
122
|
+
|
123
|
+
# Store the original prompt for later processing
|
124
|
+
enriched_data["_original_prompt"] = prompt
|
125
|
+
enriched_data["_memory_enriched"] = True
|
126
|
+
|
127
|
+
return HookResult(
|
128
|
+
success=True,
|
129
|
+
data=enriched_data,
|
130
|
+
modified=True,
|
131
|
+
metadata={
|
132
|
+
"memories_added": len(memories),
|
133
|
+
"memory_source": "kuzu",
|
134
|
+
},
|
135
|
+
)
|
136
|
+
|
137
|
+
return HookResult(success=True, data=context.data, modified=False)
|
138
|
+
|
139
|
+
except Exception as e:
|
140
|
+
logger.error(f"Kuzu-memory hook failed: {e}")
|
141
|
+
# Don't fail the request if memory integration fails
|
142
|
+
return HookResult(
|
143
|
+
success=True,
|
144
|
+
data=context.data,
|
145
|
+
modified=False,
|
146
|
+
error=f"Memory integration failed: {e}",
|
147
|
+
)
|
148
|
+
|
149
|
+
def _retrieve_memories(self, query: str) -> List[Dict[str, Any]]:
|
150
|
+
"""
|
151
|
+
Retrieve relevant memories for the given query.
|
152
|
+
|
153
|
+
Args:
|
154
|
+
query: The user prompt to find memories for
|
155
|
+
|
156
|
+
Returns:
|
157
|
+
List of relevant memory dictionaries
|
158
|
+
"""
|
159
|
+
try:
|
160
|
+
# Use kuzu-memory recall command
|
161
|
+
result = subprocess.run(
|
162
|
+
[self.kuzu_memory_cmd, "recall", query, "--format", "json"],
|
163
|
+
capture_output=True,
|
164
|
+
text=True,
|
165
|
+
timeout=5,
|
166
|
+
cwd=str(self.project_path), check=False,
|
167
|
+
)
|
168
|
+
|
169
|
+
if result.returncode == 0 and result.stdout:
|
170
|
+
memories = json.loads(result.stdout)
|
171
|
+
return memories if isinstance(memories, list) else []
|
172
|
+
|
173
|
+
except (subprocess.TimeoutExpired, json.JSONDecodeError, Exception) as e:
|
174
|
+
logger.debug(f"Memory retrieval failed: {e}")
|
175
|
+
|
176
|
+
return []
|
177
|
+
|
178
|
+
def _enrich_prompt(
|
179
|
+
self, original_data: Dict[str, Any], prompt: str, memories: List[Dict[str, Any]]
|
180
|
+
) -> Dict[str, Any]:
|
181
|
+
"""
|
182
|
+
Enrich the user prompt with relevant memories.
|
183
|
+
|
184
|
+
Args:
|
185
|
+
original_data: Original hook context data
|
186
|
+
prompt: User prompt
|
187
|
+
memories: Retrieved memories
|
188
|
+
|
189
|
+
Returns:
|
190
|
+
Enriched context data
|
191
|
+
"""
|
192
|
+
# Format memories for context
|
193
|
+
memory_context = self._format_memories(memories)
|
194
|
+
|
195
|
+
# Create enriched prompt
|
196
|
+
enriched_prompt = f"""
|
197
|
+
## RELEVANT MEMORIES FROM KUZU KNOWLEDGE GRAPH
|
198
|
+
|
199
|
+
{memory_context}
|
200
|
+
|
201
|
+
## USER REQUEST
|
202
|
+
|
203
|
+
{prompt}
|
204
|
+
|
205
|
+
Note: Use the memories above to provide more informed and contextual responses.
|
206
|
+
"""
|
207
|
+
|
208
|
+
# Create new data with enriched prompt
|
209
|
+
enriched_data = original_data.copy()
|
210
|
+
enriched_data["prompt"] = enriched_prompt
|
211
|
+
|
212
|
+
return enriched_data
|
213
|
+
|
214
|
+
def _format_memories(self, memories: List[Dict[str, Any]]) -> str:
|
215
|
+
"""
|
216
|
+
Format memories into a readable context string.
|
217
|
+
|
218
|
+
Args:
|
219
|
+
memories: List of memory dictionaries
|
220
|
+
|
221
|
+
Returns:
|
222
|
+
Formatted memory context
|
223
|
+
"""
|
224
|
+
if not memories:
|
225
|
+
return "No relevant memories found."
|
226
|
+
|
227
|
+
formatted = []
|
228
|
+
for i, memory in enumerate(memories, 1):
|
229
|
+
# Extract memory content and metadata
|
230
|
+
content = memory.get("content", "")
|
231
|
+
tags = memory.get("tags", [])
|
232
|
+
timestamp = memory.get("timestamp", "")
|
233
|
+
relevance = memory.get("relevance", 0.0)
|
234
|
+
|
235
|
+
# Format memory entry
|
236
|
+
entry = f"{i}. {content}"
|
237
|
+
if tags:
|
238
|
+
entry += f" [Tags: {', '.join(tags)}]"
|
239
|
+
if relevance > 0:
|
240
|
+
entry += f" (Relevance: {relevance:.2f})"
|
241
|
+
|
242
|
+
formatted.append(entry)
|
243
|
+
|
244
|
+
return "\n".join(formatted)
|
245
|
+
|
246
|
+
def store_memory(self, content: str, tags: Optional[List[str]] = None) -> bool:
|
247
|
+
"""
|
248
|
+
Store a memory using kuzu-memory.
|
249
|
+
|
250
|
+
Args:
|
251
|
+
content: The memory content to store
|
252
|
+
tags: Optional tags for categorization
|
253
|
+
|
254
|
+
Returns:
|
255
|
+
True if storage was successful
|
256
|
+
"""
|
257
|
+
if not self.enabled:
|
258
|
+
return False
|
259
|
+
|
260
|
+
try:
|
261
|
+
# Use kuzu-memory remember command (synchronous)
|
262
|
+
cmd = [self.kuzu_memory_cmd, "remember", content]
|
263
|
+
|
264
|
+
# Execute store command in project directory
|
265
|
+
result = subprocess.run(
|
266
|
+
cmd,
|
267
|
+
capture_output=True,
|
268
|
+
text=True,
|
269
|
+
timeout=5,
|
270
|
+
cwd=str(self.project_path), check=False,
|
271
|
+
)
|
272
|
+
|
273
|
+
if result.returncode == 0:
|
274
|
+
logger.debug(f"Stored memory: {content[:50]}...")
|
275
|
+
return True
|
276
|
+
|
277
|
+
except Exception as e:
|
278
|
+
logger.error(f"Failed to store memory: {e}")
|
279
|
+
|
280
|
+
return False
|
281
|
+
|
282
|
+
def extract_and_store_learnings(self, text: str) -> int:
|
283
|
+
"""
|
284
|
+
Extract learnings from text and store them as memories.
|
285
|
+
|
286
|
+
Args:
|
287
|
+
text: Text to extract learnings from
|
288
|
+
|
289
|
+
Returns:
|
290
|
+
Number of learnings stored
|
291
|
+
"""
|
292
|
+
if not self.enabled:
|
293
|
+
return 0
|
294
|
+
|
295
|
+
stored_count = 0
|
296
|
+
|
297
|
+
# Extract learnings using patterns
|
298
|
+
for pattern in self.memory_patterns:
|
299
|
+
matches = re.finditer(pattern, text, re.IGNORECASE | re.MULTILINE)
|
300
|
+
for match in matches:
|
301
|
+
learning = match.group(1).strip()
|
302
|
+
if learning and len(learning) > 10: # Minimum length check
|
303
|
+
# Determine tags based on content
|
304
|
+
tags = self._infer_tags(learning)
|
305
|
+
|
306
|
+
# Store the learning
|
307
|
+
if self.store_memory(learning, tags):
|
308
|
+
stored_count += 1
|
309
|
+
|
310
|
+
return stored_count
|
311
|
+
|
312
|
+
def _infer_tags(self, content: str) -> List[str]:
|
313
|
+
"""
|
314
|
+
Infer tags based on memory content.
|
315
|
+
|
316
|
+
Args:
|
317
|
+
content: Memory content
|
318
|
+
|
319
|
+
Returns:
|
320
|
+
List of inferred tags
|
321
|
+
"""
|
322
|
+
tags = []
|
323
|
+
content_lower = content.lower()
|
324
|
+
|
325
|
+
# Technical tags
|
326
|
+
if any(
|
327
|
+
word in content_lower for word in ["code", "function", "class", "module"]
|
328
|
+
):
|
329
|
+
tags.append("technical")
|
330
|
+
if any(word in content_lower for word in ["bug", "error", "fix", "issue"]):
|
331
|
+
tags.append("debugging")
|
332
|
+
if any(word in content_lower for word in ["pattern", "architecture", "design"]):
|
333
|
+
tags.append("architecture")
|
334
|
+
if any(word in content_lower for word in ["performance", "optimize", "speed"]):
|
335
|
+
tags.append("performance")
|
336
|
+
|
337
|
+
# Project context tags
|
338
|
+
if "claude-mpm" in content_lower or "mpm" in content_lower:
|
339
|
+
tags.append("claude-mpm")
|
340
|
+
if any(word in content_lower for word in ["hook", "agent", "service"]):
|
341
|
+
tags.append("framework")
|
342
|
+
|
343
|
+
# Default tag if no others found
|
344
|
+
if not tags:
|
345
|
+
tags.append("general")
|
346
|
+
|
347
|
+
return tags
|
348
|
+
|
349
|
+
|
350
|
+
# Create a singleton instance
|
351
|
+
_kuzu_memory_hook = None
|
352
|
+
|
353
|
+
|
354
|
+
def get_kuzu_memory_hook() -> KuzuMemoryHook:
|
355
|
+
"""Get the singleton kuzu-memory hook instance."""
|
356
|
+
global _kuzu_memory_hook
|
357
|
+
if _kuzu_memory_hook is None:
|
358
|
+
_kuzu_memory_hook = KuzuMemoryHook()
|
359
|
+
return _kuzu_memory_hook
|
@@ -10,9 +10,9 @@ from typing import Any, Callable, Dict, List, Optional
|
|
10
10
|
|
11
11
|
import yaml
|
12
12
|
|
13
|
+
from claude_mpm.core.logging_utils import get_logger
|
13
14
|
from claude_mpm.validation import AgentValidator, ValidationResult
|
14
15
|
|
15
|
-
from claude_mpm.core.logging_utils import get_logger
|
16
16
|
logger = get_logger(__name__)
|
17
17
|
|
18
18
|
|
claude_mpm/scripts/mpm_doctor.py
CHANGED
@@ -32,11 +32,11 @@ import yaml
|
|
32
32
|
|
33
33
|
from claude_mpm.core.base_service import BaseService
|
34
34
|
from claude_mpm.core.config import Config
|
35
|
+
from claude_mpm.core.logging_utils import get_logger
|
35
36
|
from claude_mpm.core.unified_paths import get_path_manager
|
36
37
|
from claude_mpm.services.agents.registry import AgentRegistry
|
37
38
|
from claude_mpm.services.memory.cache.shared_prompt_cache import SharedPromptCache
|
38
39
|
|
39
|
-
from claude_mpm.core.logging_utils import get_logger
|
40
40
|
logger = get_logger(__name__)
|
41
41
|
|
42
42
|
# ============================================================================
|
@@ -14,10 +14,10 @@ from pathlib import Path
|
|
14
14
|
from typing import Any, Dict, List, Optional
|
15
15
|
|
16
16
|
from claude_mpm.agents.base_agent_loader import clear_base_agent_cache
|
17
|
+
from claude_mpm.core.logging_utils import get_logger
|
17
18
|
from claude_mpm.services.memory.cache.shared_prompt_cache import SharedPromptCache
|
18
19
|
from claude_mpm.services.shared import ConfigServiceBase
|
19
20
|
|
20
|
-
from claude_mpm.core.logging_utils import get_logger
|
21
21
|
logger = get_logger(__name__)
|
22
22
|
|
23
23
|
|
@@ -19,9 +19,9 @@ from claude_mpm.agents.agent_loader import (
|
|
19
19
|
AgentTier,
|
20
20
|
list_agents_by_tier,
|
21
21
|
)
|
22
|
+
from claude_mpm.core.logging_utils import get_logger
|
22
23
|
from claude_mpm.core.unified_paths import get_path_manager
|
23
24
|
|
24
|
-
from claude_mpm.core.logging_utils import get_logger
|
25
25
|
logger = get_logger(__name__)
|
26
26
|
|
27
27
|
|
@@ -19,6 +19,7 @@ import frontmatter
|
|
19
19
|
import mistune
|
20
20
|
import yaml
|
21
21
|
|
22
|
+
from claude_mpm.core.logging_utils import get_logger
|
22
23
|
from claude_mpm.core.unified_paths import get_path_manager
|
23
24
|
from claude_mpm.models.agent_definition import (
|
24
25
|
AgentDefinition,
|
@@ -32,7 +33,6 @@ from claude_mpm.services.memory.cache.shared_prompt_cache import SharedPromptCac
|
|
32
33
|
|
33
34
|
from ..deployment.agent_versioning import AgentVersionManager
|
34
35
|
|
35
|
-
from claude_mpm.core.logging_utils import get_logger
|
36
36
|
logger = get_logger(__name__)
|
37
37
|
|
38
38
|
|
@@ -41,14 +41,18 @@ class MemoryFileService:
|
|
41
41
|
old_file = directory / f"{normalized_id}_memory.md"
|
42
42
|
|
43
43
|
# Also check for legacy hyphenated versions
|
44
|
-
hyphenated_file =
|
44
|
+
hyphenated_file = (
|
45
|
+
directory / f"{agent_id}_memories.md" if "-" in agent_id else None
|
46
|
+
)
|
45
47
|
|
46
48
|
# Migration priority:
|
47
49
|
# 1. If hyphenated version exists and normalized doesn't, migrate it
|
48
50
|
if hyphenated_file and hyphenated_file.exists() and not new_file.exists():
|
49
51
|
try:
|
50
52
|
hyphenated_file.rename(new_file)
|
51
|
-
self.logger.info(
|
53
|
+
self.logger.info(
|
54
|
+
f"Migrated hyphenated memory file: {hyphenated_file} -> {new_file}"
|
55
|
+
)
|
52
56
|
except Exception as e:
|
53
57
|
self.logger.warning(f"Could not migrate hyphenated memory file: {e}")
|
54
58
|
# Fall back to using the hyphenated version
|
@@ -15,7 +15,6 @@ class MemoryFormatService:
|
|
15
15
|
|
16
16
|
def __init__(self):
|
17
17
|
"""Initialize the memory format service."""
|
18
|
-
pass
|
19
18
|
|
20
19
|
def build_simple_memory_content(self, agent_id: str, items: List[str]) -> str:
|
21
20
|
"""Build memory content as a simple list with header and timestamp.
|
@@ -9,10 +9,10 @@ from pathlib import Path
|
|
9
9
|
from typing import Any, Dict, List, Optional
|
10
10
|
|
11
11
|
from claude_mpm.core.agent_registry import AgentRegistryAdapter
|
12
|
+
from claude_mpm.core.logging_utils import get_logger
|
12
13
|
from claude_mpm.core.unified_paths import get_path_manager
|
13
14
|
from claude_mpm.services.shared import ConfigServiceBase
|
14
15
|
|
15
|
-
from claude_mpm.core.logging_utils import get_logger
|
16
16
|
logger = get_logger(__name__)
|
17
17
|
|
18
18
|
|
@@ -29,11 +29,11 @@ from threading import Lock, Thread
|
|
29
29
|
from typing import Any, Dict, Optional
|
30
30
|
|
31
31
|
from claude_mpm.core.constants import PerformanceConfig, SystemLimits, TimeoutConfig
|
32
|
+
from claude_mpm.core.logging_utils import get_logger
|
32
33
|
|
33
34
|
# Import configuration manager
|
34
35
|
from ..core.config import Config
|
35
36
|
|
36
|
-
from claude_mpm.core.logging_utils import get_logger
|
37
37
|
logger = get_logger(__name__)
|
38
38
|
|
39
39
|
|
@@ -19,6 +19,7 @@ from pathlib import Path
|
|
19
19
|
from typing import Dict, Optional, Tuple
|
20
20
|
|
21
21
|
from claude_mpm.core.logging_utils import get_logger
|
22
|
+
|
22
23
|
from .service_interfaces import ICacheManager, IPathResolver
|
23
24
|
|
24
25
|
logger = get_logger(__name__)
|
@@ -50,6 +51,7 @@ class PathResolver(IPathResolver):
|
|
50
51
|
Args:
|
51
52
|
cache_manager: Optional cache manager for caching resolved paths
|
52
53
|
"""
|
54
|
+
self.logger = get_logger("path_resolver")
|
53
55
|
self.cache_manager = cache_manager
|
54
56
|
self._framework_path: Optional[Path] = None
|
55
57
|
self._deployment_context: Optional[DeploymentContext] = None
|
@@ -14,6 +14,7 @@ from .filesystem_check import FilesystemCheck
|
|
14
14
|
from .installation_check import InstallationCheck
|
15
15
|
from .instructions_check import InstructionsCheck
|
16
16
|
from .mcp_check import MCPCheck
|
17
|
+
from .mcp_services_check import MCPServicesCheck
|
17
18
|
from .monitor_check import MonitorCheck
|
18
19
|
from .startup_log_check import StartupLogCheck
|
19
20
|
|
@@ -27,6 +28,7 @@ __all__ = [
|
|
27
28
|
"InstallationCheck",
|
28
29
|
"InstructionsCheck",
|
29
30
|
"MCPCheck",
|
31
|
+
"MCPServicesCheck",
|
30
32
|
"MonitorCheck",
|
31
33
|
"StartupLogCheck",
|
32
34
|
]
|