claude-memory-agent 2.0.0 → 2.1.0

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 (34) hide show
  1. package/README.md +206 -200
  2. package/agent_card.py +186 -0
  3. package/bin/cli.js +317 -181
  4. package/bin/postinstall.js +270 -216
  5. package/dashboard.html +4232 -2689
  6. package/hooks/__pycache__/grounding-hook.cpython-312.pyc +0 -0
  7. package/hooks/__pycache__/session_end.cpython-312.pyc +0 -0
  8. package/hooks/grounding-hook.py +422 -348
  9. package/hooks/session_end.py +293 -192
  10. package/hooks/session_start.py +227 -227
  11. package/install.py +919 -887
  12. package/main.py +4496 -2859
  13. package/package.json +47 -55
  14. package/services/__init__.py +50 -50
  15. package/services/__pycache__/__init__.cpython-312.pyc +0 -0
  16. package/services/__pycache__/curator.cpython-312.pyc +0 -0
  17. package/services/__pycache__/database.cpython-312.pyc +0 -0
  18. package/services/curator.py +1606 -0
  19. package/services/database.py +3637 -2485
  20. package/skills/__init__.py +21 -1
  21. package/skills/__pycache__/__init__.cpython-312.pyc +0 -0
  22. package/skills/__pycache__/confidence_tracker.cpython-312.pyc +0 -0
  23. package/skills/__pycache__/context.cpython-312.pyc +0 -0
  24. package/skills/__pycache__/curator.cpython-312.pyc +0 -0
  25. package/skills/__pycache__/search.cpython-312.pyc +0 -0
  26. package/skills/__pycache__/session_review.cpython-312.pyc +0 -0
  27. package/skills/__pycache__/store.cpython-312.pyc +0 -0
  28. package/skills/confidence_tracker.py +441 -0
  29. package/skills/context.py +675 -0
  30. package/skills/curator.py +348 -0
  31. package/skills/search.py +369 -213
  32. package/skills/session_review.py +418 -0
  33. package/skills/store.py +377 -179
  34. package/update_system.py +829 -817
@@ -0,0 +1,348 @@
1
+ """Curator MCP Skills - Graph exploration and maintenance capabilities."""
2
+ import logging
3
+ from typing import Dict, Any, Optional, List
4
+
5
+ from services.database import DatabaseService
6
+ from services.embeddings import EmbeddingService
7
+ from services.curator import get_curator
8
+
9
+ logger = logging.getLogger(__name__)
10
+
11
+
12
+ async def curator_explore(
13
+ db: DatabaseService,
14
+ embeddings: EmbeddingService,
15
+ start_node_id: int,
16
+ max_depth: int = 3,
17
+ mode: str = "bfs",
18
+ relationship_filter: Optional[List[str]] = None
19
+ ) -> Dict[str, Any]:
20
+ """
21
+ Explore the memory graph from a starting node.
22
+
23
+ Args:
24
+ db: Database service instance
25
+ embeddings: Embedding service instance
26
+ start_node_id: ID of the memory to start from
27
+ max_depth: Maximum traversal depth (default 3)
28
+ mode: 'bfs' (breadth-first) or 'dfs' (depth-first)
29
+ relationship_filter: Only follow these relationship types
30
+
31
+ Returns:
32
+ Dict with explored nodes, edges, clusters, and insights
33
+ """
34
+ curator = get_curator(db, embeddings)
35
+ return await curator.explore_graph(
36
+ start_node_id=start_node_id,
37
+ max_depth=max_depth,
38
+ mode=mode,
39
+ relationship_filter=relationship_filter
40
+ )
41
+
42
+
43
+ async def curator_find_duplicates(
44
+ db: DatabaseService,
45
+ embeddings: EmbeddingService,
46
+ project_path: Optional[str] = None,
47
+ similarity_threshold: float = 0.92,
48
+ limit: int = 50
49
+ ) -> Dict[str, Any]:
50
+ """
51
+ Find semantically similar (duplicate) memories.
52
+
53
+ Args:
54
+ db: Database service instance
55
+ embeddings: Embedding service instance
56
+ project_path: Optional project filter
57
+ similarity_threshold: Minimum similarity to consider duplicates
58
+ limit: Maximum number of duplicate pairs to return
59
+
60
+ Returns:
61
+ Dict with duplicate clusters and merge suggestions
62
+ """
63
+ curator = get_curator(db, embeddings)
64
+ return await curator.find_duplicates(
65
+ project_path=project_path,
66
+ similarity_threshold=similarity_threshold,
67
+ limit=limit
68
+ )
69
+
70
+
71
+ async def curator_suggest_links(
72
+ db: DatabaseService,
73
+ embeddings: EmbeddingService,
74
+ memory_id: Optional[int] = None,
75
+ project_path: Optional[str] = None,
76
+ similarity_threshold: float = 0.7,
77
+ limit: int = 20
78
+ ) -> Dict[str, Any]:
79
+ """
80
+ Suggest missing relationships between memories.
81
+
82
+ Args:
83
+ db: Database service instance
84
+ embeddings: Embedding service instance
85
+ memory_id: Optional specific memory to find links for
86
+ project_path: Optional project filter
87
+ similarity_threshold: Minimum similarity for suggestions
88
+ limit: Maximum suggestions to return
89
+
90
+ Returns:
91
+ Dict with suggested relationships
92
+ """
93
+ curator = get_curator(db, embeddings)
94
+ return await curator.suggest_relationships(
95
+ memory_id=memory_id,
96
+ project_path=project_path,
97
+ similarity_threshold=similarity_threshold,
98
+ limit=limit
99
+ )
100
+
101
+
102
+ async def curator_merge(
103
+ db: DatabaseService,
104
+ embeddings: EmbeddingService,
105
+ keep_id: int,
106
+ remove_ids: List[int],
107
+ merge_content: bool = False
108
+ ) -> Dict[str, Any]:
109
+ """
110
+ Merge duplicate memories into one.
111
+
112
+ Args:
113
+ db: Database service instance
114
+ embeddings: Embedding service instance
115
+ keep_id: Memory ID to keep
116
+ remove_ids: Memory IDs to merge into keep_id
117
+ merge_content: If True, append removed content to kept memory
118
+
119
+ Returns:
120
+ Dict with merge result
121
+ """
122
+ curator = get_curator(db, embeddings)
123
+ return await curator.merge_memories(
124
+ keep_id=keep_id,
125
+ remove_ids=remove_ids,
126
+ merge_content=merge_content
127
+ )
128
+
129
+
130
+ async def curator_get_summary(
131
+ db: DatabaseService,
132
+ embeddings: EmbeddingService,
133
+ query: str,
134
+ project_path: Optional[str] = None,
135
+ max_memories: int = 10,
136
+ include_graph: bool = True
137
+ ) -> Dict[str, Any]:
138
+ """
139
+ Generate curated context summary for a query.
140
+
141
+ This is what gets injected into the main Claude's context.
142
+
143
+ Args:
144
+ db: Database service instance
145
+ embeddings: Embedding service instance
146
+ query: The topic/query to generate context for
147
+ project_path: Optional project filter
148
+ max_memories: Maximum memories to include
149
+ include_graph: Include relationship graph context
150
+
151
+ Returns:
152
+ Dict with curated context summary
153
+ """
154
+ curator = get_curator(db, embeddings)
155
+ return await curator.generate_summary(
156
+ query=query,
157
+ project_path=project_path,
158
+ max_memories=max_memories,
159
+ include_graph=include_graph
160
+ )
161
+
162
+
163
+ async def curator_run_maintenance(
164
+ db: DatabaseService,
165
+ embeddings: EmbeddingService,
166
+ project_path: Optional[str] = None,
167
+ tasks: Optional[List[str]] = None
168
+ ) -> Dict[str, Any]:
169
+ """
170
+ Run curator maintenance tasks.
171
+
172
+ Args:
173
+ db: Database service instance
174
+ embeddings: Embedding service instance
175
+ project_path: Optional project filter
176
+ tasks: Specific tasks to run, or None for all
177
+ Options: dedup, orphans, links, decay, quality
178
+
179
+ Returns:
180
+ Dict with maintenance report
181
+ """
182
+ curator = get_curator(db, embeddings)
183
+ return await curator.run_maintenance(
184
+ project_path=project_path,
185
+ tasks=tasks
186
+ )
187
+
188
+
189
+ async def curator_get_report(
190
+ db: DatabaseService,
191
+ embeddings: EmbeddingService,
192
+ project_path: Optional[str] = None
193
+ ) -> Dict[str, Any]:
194
+ """
195
+ Get the latest curator report.
196
+
197
+ Args:
198
+ db: Database service instance
199
+ embeddings: Embedding service instance
200
+ project_path: Optional project filter
201
+
202
+ Returns:
203
+ Dict with latest report or None
204
+ """
205
+ curator = get_curator(db, embeddings)
206
+ report = await curator.get_latest_report(project_path=project_path)
207
+ if report:
208
+ return report
209
+ return {"message": "No curator reports found"}
210
+
211
+
212
+ async def curator_get_status(
213
+ db: DatabaseService,
214
+ embeddings: EmbeddingService
215
+ ) -> Dict[str, Any]:
216
+ """
217
+ Get current curator agent status.
218
+
219
+ Args:
220
+ db: Database service instance
221
+ embeddings: Embedding service instance
222
+
223
+ Returns:
224
+ Dict with curator status
225
+ """
226
+ curator = get_curator(db, embeddings)
227
+ return await curator.get_status()
228
+
229
+
230
+ async def curator_score_quality(
231
+ db: DatabaseService,
232
+ embeddings: EmbeddingService,
233
+ memory_id: Optional[int] = None,
234
+ project_path: Optional[str] = None,
235
+ limit: int = 100
236
+ ) -> Dict[str, Any]:
237
+ """
238
+ Calculate quality scores for memories.
239
+
240
+ Args:
241
+ db: Database service instance
242
+ embeddings: Embedding service instance
243
+ memory_id: Optional specific memory to score
244
+ project_path: Optional project filter
245
+ limit: Maximum memories to score
246
+
247
+ Returns:
248
+ Dict with quality scores and insights
249
+ """
250
+ curator = get_curator(db, embeddings)
251
+ return await curator.score_quality(
252
+ memory_id=memory_id,
253
+ project_path=project_path,
254
+ limit=limit
255
+ )
256
+
257
+
258
+ async def curator_find_orphans(
259
+ db: DatabaseService,
260
+ embeddings: EmbeddingService,
261
+ project_path: Optional[str] = None,
262
+ limit: int = 50
263
+ ) -> Dict[str, Any]:
264
+ """
265
+ Find memories with no relationships (orphans).
266
+
267
+ Args:
268
+ db: Database service instance
269
+ embeddings: Embedding service instance
270
+ project_path: Optional project filter
271
+ limit: Maximum orphans to return
272
+
273
+ Returns:
274
+ Dict with orphan memories
275
+ """
276
+ curator = get_curator(db, embeddings)
277
+ orphans = await curator.find_orphan_memories(
278
+ project_path=project_path,
279
+ limit=limit
280
+ )
281
+ return {
282
+ "orphans": orphans,
283
+ "total_found": len(orphans),
284
+ "recommendation": "Consider linking these memories or archiving if no longer relevant"
285
+ }
286
+
287
+
288
+ async def curator_get_config(
289
+ db: DatabaseService,
290
+ embeddings: EmbeddingService,
291
+ project_path: Optional[str] = None
292
+ ) -> Dict[str, Any]:
293
+ """
294
+ Get curator configuration.
295
+
296
+ Args:
297
+ db: Database service instance
298
+ embeddings: Embedding service instance
299
+ project_path: Optional project path
300
+
301
+ Returns:
302
+ Dict with curator configuration
303
+ """
304
+ curator = get_curator(db, embeddings)
305
+ return await curator.get_config(project_path=project_path)
306
+
307
+
308
+ async def curator_update_config(
309
+ db: DatabaseService,
310
+ embeddings: EmbeddingService,
311
+ project_path: str,
312
+ auto_dedup_enabled: Optional[bool] = None,
313
+ auto_link_enabled: Optional[bool] = None,
314
+ dedup_threshold: Optional[float] = None,
315
+ maintenance_interval_hours: Optional[int] = None,
316
+ curator_active: Optional[bool] = None
317
+ ) -> Dict[str, Any]:
318
+ """
319
+ Update curator configuration for a project.
320
+
321
+ Args:
322
+ db: Database service instance
323
+ embeddings: Embedding service instance
324
+ project_path: Project path to update config for
325
+ auto_dedup_enabled: Enable auto-deduplication
326
+ auto_link_enabled: Enable auto-linking
327
+ dedup_threshold: Similarity threshold for duplicates
328
+ maintenance_interval_hours: Hours between maintenance runs
329
+ curator_active: Enable/disable curator
330
+
331
+ Returns:
332
+ Dict with updated configuration
333
+ """
334
+ curator = get_curator(db, embeddings)
335
+
336
+ config_updates = {}
337
+ if auto_dedup_enabled is not None:
338
+ config_updates["auto_dedup_enabled"] = auto_dedup_enabled
339
+ if auto_link_enabled is not None:
340
+ config_updates["auto_link_enabled"] = auto_link_enabled
341
+ if dedup_threshold is not None:
342
+ config_updates["dedup_threshold"] = dedup_threshold
343
+ if maintenance_interval_hours is not None:
344
+ config_updates["maintenance_interval_hours"] = maintenance_interval_hours
345
+ if curator_active is not None:
346
+ config_updates["curator_active"] = curator_active
347
+
348
+ return await curator.update_config(project_path=project_path, **config_updates)