claude-mem 3.0.2 → 3.0.4

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 (56) hide show
  1. package/.mcp.json +11 -0
  2. package/claude-mem +0 -0
  3. package/dist/cli.d.ts +2 -0
  4. package/dist/cli.js +64 -0
  5. package/dist/commands/compress.d.ts +2 -0
  6. package/dist/commands/compress.js +59 -0
  7. package/dist/commands/install.d.ts +2 -0
  8. package/dist/commands/install.js +372 -0
  9. package/dist/commands/load-context.d.ts +2 -0
  10. package/dist/commands/load-context.js +330 -0
  11. package/dist/commands/logs.d.ts +2 -0
  12. package/dist/commands/logs.js +41 -0
  13. package/dist/commands/migrate.d.ts +9 -0
  14. package/dist/commands/migrate.js +174 -0
  15. package/dist/commands/status.d.ts +1 -0
  16. package/dist/commands/status.js +159 -0
  17. package/dist/commands/uninstall.d.ts +2 -0
  18. package/dist/commands/uninstall.js +105 -0
  19. package/dist/config.d.ts +6 -0
  20. package/dist/config.js +33 -0
  21. package/dist/constants.d.ts +516 -0
  22. package/dist/constants.js +522 -0
  23. package/dist/error-handler.d.ts +17 -0
  24. package/dist/error-handler.js +103 -0
  25. package/dist/mcp-server-cli.d.ts +34 -0
  26. package/dist/mcp-server-cli.js +158 -0
  27. package/dist/mcp-server.d.ts +103 -0
  28. package/dist/mcp-server.js +269 -0
  29. package/dist/types.d.ts +148 -0
  30. package/dist/types.js +78 -0
  31. package/dist/utils/HookDetector.d.ts +64 -0
  32. package/dist/utils/HookDetector.js +213 -0
  33. package/dist/utils/PathResolver.d.ts +16 -0
  34. package/dist/utils/PathResolver.js +55 -0
  35. package/dist/utils/SettingsManager.d.ts +63 -0
  36. package/dist/utils/SettingsManager.js +133 -0
  37. package/dist/utils/TranscriptCompressor.d.ts +111 -0
  38. package/dist/utils/TranscriptCompressor.js +486 -0
  39. package/dist/utils/common.d.ts +29 -0
  40. package/dist/utils/common.js +14 -0
  41. package/dist/utils/error-utils.d.ts +93 -0
  42. package/dist/utils/error-utils.js +238 -0
  43. package/dist/utils/index.d.ts +19 -0
  44. package/dist/utils/index.js +26 -0
  45. package/dist/utils/logger.d.ts +19 -0
  46. package/dist/utils/logger.js +42 -0
  47. package/dist/utils/mcp-client-factory.d.ts +51 -0
  48. package/dist/utils/mcp-client-factory.js +115 -0
  49. package/dist/utils/mcp-client.d.ts +75 -0
  50. package/dist/utils/mcp-client.js +120 -0
  51. package/dist/utils/memory-mcp-client.d.ts +135 -0
  52. package/dist/utils/memory-mcp-client.js +490 -0
  53. package/dist/utils/weaviate-mcp-adapter.d.ts +102 -0
  54. package/dist/utils/weaviate-mcp-adapter.js +587 -0
  55. package/package.json +3 -2
  56. package/src/claude-mem.js +0 -859
@@ -0,0 +1,330 @@
1
+ import { getMCPClient } from '../utils/mcp-client.js';
2
+ import { SESSION_START_TEMPLATES, TIME_FORMATS, CLI_MESSAGES, CONTEXT_TEMPLATES } from '../constants.js';
3
+ // =============================================================================
4
+ // HELPER FUNCTIONS FOR WEAVIATE INTEGRATION
5
+ // =============================================================================
6
+ /**
7
+ * Build search query based on CLI options
8
+ * @param options CLI options from commander
9
+ * @returns Search query string for Weaviate
10
+ */
11
+ function buildSearchQuery(options) {
12
+ // If project is specified, search for entities with that project prefix
13
+ if (options.project) {
14
+ return `${options.project}_`;
15
+ }
16
+ // Default to searching for all entities (return empty string for broad search)
17
+ return '';
18
+ }
19
+ /**
20
+ * Format Weaviate search results for display
21
+ * @param result MCPSearchResult from Weaviate
22
+ * @param options CLI options for formatting
23
+ * @returns Formatted display data
24
+ */
25
+ function formatWeaviateResults(result, options) {
26
+ const entities = result.entities || [];
27
+ if (entities.length === 0) {
28
+ return {
29
+ entries: [],
30
+ isEmpty: true
31
+ };
32
+ }
33
+ // Convert entities to the format expected by existing formatting functions
34
+ const entries = entities.map(entity => ({
35
+ summary: entity.observations?.[0] || entity.name.replace(/^[^_]+_/, ''),
36
+ nodes: [entity.name],
37
+ keywords: extractKeywordsFromEntity(entity),
38
+ timestamp: new Date().toISOString(), // Use current time as fallback
39
+ project: extractProjectFromEntityName(entity.name)
40
+ }));
41
+ // Apply count limit
42
+ const count = parseInt(options.count) || 10;
43
+ const limitedEntries = entries.slice(-count);
44
+ return {
45
+ entries: limitedEntries,
46
+ isEmpty: false
47
+ };
48
+ }
49
+ /**
50
+ * Extract keywords from entity observations
51
+ * @param entity MCPEntity
52
+ * @returns Array of keywords
53
+ */
54
+ function extractKeywordsFromEntity(entity) {
55
+ const keywords = [];
56
+ // Add entity type as keyword
57
+ if (entity.entityType) {
58
+ keywords.push(entity.entityType);
59
+ }
60
+ // Extract keywords from observations (simple word extraction)
61
+ if (entity.observations) {
62
+ entity.observations.forEach(obs => {
63
+ const words = obs.split(/\s+/).filter(word => word.length > 3);
64
+ keywords.push(...words.slice(0, 3)); // Take first 3 meaningful words
65
+ });
66
+ }
67
+ return [...new Set(keywords)]; // Remove duplicates
68
+ }
69
+ /**
70
+ * Extract project name from entity name
71
+ * @param entityName Full entity name
72
+ * @returns Project name
73
+ */
74
+ function extractProjectFromEntityName(entityName) {
75
+ const parts = entityName.split('_');
76
+ return parts[0] || 'unknown';
77
+ }
78
+ function extractEntityType(nodes, types) {
79
+ const results = [];
80
+ for (const node of nodes) {
81
+ for (const type of types) {
82
+ if (node.toLowerCase().includes(type.toLowerCase())) {
83
+ results.push(node);
84
+ break;
85
+ }
86
+ }
87
+ }
88
+ return [...new Set(results)];
89
+ }
90
+ function formatEntityList(entities, entries) {
91
+ let output = '';
92
+ const seen = new Set();
93
+ entities.forEach(entity => {
94
+ if (!seen.has(entity)) {
95
+ seen.add(entity);
96
+ const cleanName = entity.replace(/^[^_]+_/, '');
97
+ const summary = findEntitySummary(entity, entries);
98
+ output += `${SESSION_START_TEMPLATES.ENTITY_BULLET}${cleanName}`;
99
+ if (summary) {
100
+ output += ` - ${summary}`;
101
+ }
102
+ output += '\n';
103
+ }
104
+ });
105
+ return output;
106
+ }
107
+ function findEntitySummary(entity, entries) {
108
+ for (const entry of entries) {
109
+ if (entry.nodes && entry.nodes.includes(entity)) {
110
+ return entry.summary || '';
111
+ }
112
+ }
113
+ return '';
114
+ }
115
+ function extractFocus(entries) {
116
+ const recent = entries[entries.length - 1];
117
+ if (recent.summary) {
118
+ return recent.summary;
119
+ }
120
+ const keywords = entries.flatMap(e => e.keywords || []);
121
+ const allKeywords = getMostFrequent(keywords);
122
+ return allKeywords.join(', ') || 'General development';
123
+ }
124
+ function extractNextActions(entries) {
125
+ const actions = [];
126
+ for (const entry of entries) {
127
+ if (entry.summary) {
128
+ if (entry.summary.toLowerCase().includes('todo') ||
129
+ entry.summary.toLowerCase().includes('next')) {
130
+ actions.push(entry.summary);
131
+ }
132
+ else if (entry.summary.toLowerCase().includes('implement')) {
133
+ actions.push(`Continue: ${entry.summary}`);
134
+ }
135
+ }
136
+ }
137
+ if (actions.length === 0 && entries.length > 0) {
138
+ const recent = entries[entries.length - 1];
139
+ if (recent.keywords && recent.keywords.length > 0) {
140
+ actions.push(`Review and continue work on: ${recent.keywords.join(', ')}`);
141
+ }
142
+ }
143
+ return actions;
144
+ }
145
+ function getMostFrequent(items, count) {
146
+ const frequency = new Map();
147
+ items.forEach(item => {
148
+ frequency.set(item, (frequency.get(item) || 0) + 1);
149
+ });
150
+ const sorted = Array.from(frequency.entries())
151
+ .sort((a, b) => b[1] - a[1])
152
+ .map(([item]) => item);
153
+ return count ? sorted.slice(0, count) : sorted;
154
+ }
155
+ function timeAgo(timestamp) {
156
+ if (!timestamp)
157
+ return TIME_FORMATS.RECENTLY;
158
+ const date = new Date(timestamp);
159
+ const now = new Date();
160
+ const diffMs = now.getTime() - date.getTime();
161
+ const diffHours = Math.floor(diffMs / (1000 * 60 * 60));
162
+ const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));
163
+ if (diffHours < 1) {
164
+ return TIME_FORMATS.JUST_NOW;
165
+ }
166
+ else if (diffHours < 24) {
167
+ return TIME_FORMATS.HOURS_AGO(diffHours);
168
+ }
169
+ else if (diffDays < 7) {
170
+ return TIME_FORMATS.DAYS_AGO(diffDays);
171
+ }
172
+ else {
173
+ return date.toLocaleDateString();
174
+ }
175
+ }
176
+ function formatSessionStart(entries) {
177
+ if (entries.length === 0) {
178
+ return ''; // Return empty string for session-start format
179
+ }
180
+ const recent = entries[entries.length - 1];
181
+ const allNodes = entries.flatMap(e => e.nodes || []);
182
+ const projectName = recent.project || 'Unknown Project';
183
+ const components = extractEntityType(allNodes, ['Component', 'Service', 'Module', 'Class']);
184
+ const decisions = extractEntityType(allNodes, ['Decision', 'Choice', 'Strategy']);
185
+ const patterns = extractEntityType(allNodes, ['Pattern', 'Architecture', 'Workflow']);
186
+ const tools = extractEntityType(allNodes, ['Tool', 'Library', 'Integration']);
187
+ const fixes = extractEntityType(allNodes, ['Fix', 'Bug', 'Issue']);
188
+ let output = CONTEXT_TEMPLATES.SESSION_START_HEADER + '\n';
189
+ output += CONTEXT_TEMPLATES.SESSION_START_SEPARATOR + '\n\n';
190
+ output += SESSION_START_TEMPLATES.FOCUS_LINE(extractFocus(entries)) + '\n';
191
+ output += SESSION_START_TEMPLATES.LAST_WORKED(timeAgo(recent.timestamp), projectName) + '\n\n';
192
+ if (components.length > 0) {
193
+ output += SESSION_START_TEMPLATES.SECTIONS.COMPONENTS + '\n';
194
+ output += formatEntityList(components, entries);
195
+ output += '\n';
196
+ }
197
+ if (decisions.length > 0 || patterns.length > 0) {
198
+ output += SESSION_START_TEMPLATES.SECTIONS.DECISIONS + '\n';
199
+ output += formatEntityList([...decisions, ...patterns], entries);
200
+ output += '\n';
201
+ }
202
+ if (tools.length > 0) {
203
+ output += SESSION_START_TEMPLATES.SECTIONS.TOOLS + '\n';
204
+ output += formatEntityList(tools, entries);
205
+ output += '\n';
206
+ }
207
+ if (fixes.length > 0) {
208
+ output += SESSION_START_TEMPLATES.SECTIONS.FIXES + '\n';
209
+ output += formatEntityList(fixes, entries);
210
+ output += '\n';
211
+ }
212
+ const nextActions = extractNextActions(entries);
213
+ if (nextActions.length > 0) {
214
+ output += SESSION_START_TEMPLATES.SECTIONS.ACTIONS + '\n';
215
+ nextActions.forEach(action => {
216
+ output += `${SESSION_START_TEMPLATES.ACTION_PREFIX}${action}\n`;
217
+ });
218
+ output += '\n';
219
+ }
220
+ output += CONTEXT_TEMPLATES.RESUME_INSTRUCTIONS + '\n\n';
221
+ output += CONTEXT_TEMPLATES.SESSION_START_SEPARATOR;
222
+ return output;
223
+ }
224
+ export async function loadContext(options = {}) {
225
+ try {
226
+ // Get MCP client connected to embedded Weaviate
227
+ const client = await getMCPClient();
228
+ await client.connect();
229
+ // Build search query based on options
230
+ const searchQuery = buildSearchQuery(options);
231
+ // Execute search in embedded Weaviate
232
+ let searchResult;
233
+ if (searchQuery) {
234
+ searchResult = await client.searchNodes(searchQuery);
235
+ }
236
+ else {
237
+ // For broad search, search for common entity patterns
238
+ searchResult = await client.searchNodes('Component_ Decision_ Pattern_ Tool_ Fix_');
239
+ }
240
+ // Format results for display
241
+ const { entries, isEmpty } = formatWeaviateResults(searchResult, options);
242
+ if (isEmpty) {
243
+ if (options.format === 'session-start') {
244
+ // For session-start format, output nothing when no memories exist
245
+ return;
246
+ }
247
+ console.log(CLI_MESSAGES.STATUS.NO_MATCHES);
248
+ return;
249
+ }
250
+ // Sort entries by timestamp from oldest to newest
251
+ entries.sort((a, b) => {
252
+ const timeA = a.timestamp ? new Date(a.timestamp).getTime() : 0;
253
+ const timeB = b.timestamp ? new Date(b.timestamp).getTime() : 0;
254
+ return timeA - timeB;
255
+ });
256
+ const count = parseInt(options.count) || 10;
257
+ const recentEntries = entries.slice(-count);
258
+ // Output in requested format
259
+ if (options.raw || options.format === 'json') {
260
+ recentEntries.forEach(entry => {
261
+ console.log(JSON.stringify(entry));
262
+ });
263
+ }
264
+ else if (options.format === 'session-start') {
265
+ console.log(formatSessionStart(recentEntries));
266
+ }
267
+ else {
268
+ // Default interactive format
269
+ console.log(CLI_MESSAGES.STATUS.RECENT_MEMORIES);
270
+ console.log('═'.repeat(70));
271
+ recentEntries.forEach((entry, index) => {
272
+ console.log(`\n${index + 1}. ${entry.summary}`);
273
+ if (entry.nodes && entry.nodes.length > 0) {
274
+ const nodeNames = entry.nodes
275
+ .map((n) => n.replace(/^[^_]+_/, ''))
276
+ .join(' â€ĸ ');
277
+ console.log(` 📍 ${nodeNames}`);
278
+ }
279
+ if (entry.keywords && entry.keywords.length > 0) {
280
+ console.log(` 🔖 ${entry.keywords.join(', ')}`);
281
+ }
282
+ if (entry.timestamp) {
283
+ const date = new Date(entry.timestamp);
284
+ const now = new Date();
285
+ const diffMs = now.getTime() - date.getTime();
286
+ const diffHours = Math.floor(diffMs / (1000 * 60 * 60));
287
+ const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));
288
+ let timeStr;
289
+ if (diffHours < 1) {
290
+ timeStr = 'just now';
291
+ }
292
+ else if (diffHours < 24) {
293
+ timeStr = `${diffHours} hour${diffHours > 1 ? 's' : ''} ago`;
294
+ }
295
+ else if (diffDays < 7) {
296
+ timeStr = `${diffDays} day${diffDays > 1 ? 's' : ''} ago`;
297
+ }
298
+ else {
299
+ timeStr = date.toLocaleDateString();
300
+ }
301
+ console.log(` ⏰ ${timeStr}`);
302
+ }
303
+ });
304
+ console.log('\n' + '═'.repeat(70));
305
+ console.log(CLI_MESSAGES.STATUS.MEMORY_COUNT(recentEntries.length));
306
+ console.log(CLI_MESSAGES.STATUS.FULL_CONTEXT_AVAILABLE);
307
+ }
308
+ }
309
+ catch (error) {
310
+ // Enhanced error handling for Weaviate connection failures
311
+ if (error instanceof Error) {
312
+ if (error.message.includes('connection') || error.message.includes('ECONNREFUSED')) {
313
+ console.error('❌ Failed to connect to embedded Weaviate instance.');
314
+ console.error(' Try running: claude-mem install --force');
315
+ console.error(' Or check: claude-mem status');
316
+ }
317
+ else if (error.message.includes('schema') || error.message.includes('collection')) {
318
+ console.error('❌ Weaviate schema not initialized.');
319
+ console.error(' Try running: claude-mem install --force');
320
+ }
321
+ else {
322
+ console.error(CLI_MESSAGES.ERRORS.CONTEXT_LOAD_FAILED(error.message));
323
+ }
324
+ }
325
+ else {
326
+ console.error(CLI_MESSAGES.ERRORS.CONTEXT_LOAD_FAILED(String(error)));
327
+ }
328
+ process.exit(1);
329
+ }
330
+ }
@@ -0,0 +1,2 @@
1
+ import { OptionValues } from 'commander';
2
+ export declare function logs(options?: OptionValues): Promise<void>;
@@ -0,0 +1,41 @@
1
+ import { readFileSync } from 'fs';
2
+ import { join } from 'path';
3
+ async function showLog(logPath, logType, tail) {
4
+ try {
5
+ const content = readFileSync(logPath, 'utf8');
6
+ const lines = content.split('\n').filter(line => line.trim());
7
+ const displayLines = lines.slice(-tail);
8
+ console.log(`📋 ${logType} Logs (last ${tail} lines):`);
9
+ console.log(` File: ${logPath}`);
10
+ console.log('');
11
+ if (displayLines.length === 0) {
12
+ console.log(' No log entries found');
13
+ }
14
+ else {
15
+ displayLines.forEach(line => {
16
+ console.log(` ${line}`);
17
+ });
18
+ }
19
+ console.log('');
20
+ }
21
+ catch (error) {
22
+ console.log(`❌ Could not read ${logType.toLowerCase()} log: ${logPath}`);
23
+ }
24
+ }
25
+ export async function logs(options = {}) {
26
+ const logsDir = join(process.cwd(), 'logs');
27
+ const tail = parseInt(options.tail) || 20;
28
+ if (options.error || (!options.debug && !options.error)) {
29
+ await showLog(join(logsDir, 'claude-mem-error.log'), 'Error', tail);
30
+ }
31
+ if (options.debug) {
32
+ await showLog(join(logsDir, 'claude-mem-debug.log'), 'Debug', tail);
33
+ }
34
+ if (options.follow) {
35
+ console.log('Following logs... (Press Ctrl+C to stop)');
36
+ // Basic follow implementation - would need more sophisticated watching in real usage
37
+ setInterval(() => {
38
+ // This would need proper file watching implementation
39
+ }, 1000);
40
+ }
41
+ }
@@ -0,0 +1,9 @@
1
+ import { OptionValues } from 'commander';
2
+ interface MigrationOptions extends OptionValues {
3
+ from?: 'memory' | 'weaviate';
4
+ to?: 'memory' | 'weaviate';
5
+ dryRun?: boolean;
6
+ force?: boolean;
7
+ }
8
+ export declare function migrate(options?: MigrationOptions): Promise<void>;
9
+ export {};
@@ -0,0 +1,174 @@
1
+ import { readFileSync, writeFileSync, existsSync, readdirSync } from 'fs';
2
+ import { join } from 'path';
3
+ import { homedir } from 'os';
4
+ /**
5
+ * Simple MCP client interface for migration purposes
6
+ * This is a minimal implementation to avoid complex dependencies
7
+ */
8
+ class MigrationMCPClient {
9
+ backend;
10
+ constructor(backend) {
11
+ this.backend = backend;
12
+ }
13
+ async connect() {
14
+ console.log(`🔗 Connecting to ${this.backend} backend...`);
15
+ // In a real implementation, this would establish the connection
16
+ // For now, we'll simulate the connection
17
+ }
18
+ async disconnect() {
19
+ console.log(`👋 Disconnected from ${this.backend} backend`);
20
+ }
21
+ async createEntities(entities) {
22
+ console.log(`📝 Creating ${entities.length} entities in ${this.backend} backend...`);
23
+ // In a real implementation, this would call the appropriate MCP server
24
+ // For migration purposes, we simulate the creation
25
+ entities.forEach(entity => {
26
+ console.log(` â€ĸ Created entity: ${entity.name}`);
27
+ });
28
+ }
29
+ async createRelations(relations) {
30
+ console.log(`🔗 Creating ${relations.length} relations in ${this.backend} backend...`);
31
+ // In a real implementation, this would call the appropriate MCP server
32
+ relations.forEach(relation => {
33
+ console.log(` â€ĸ Created relation: ${relation.from} -> ${relation.to}`);
34
+ });
35
+ }
36
+ async getAllEntities() {
37
+ console.log(`📖 Reading all entities from ${this.backend} backend...`);
38
+ // In a real implementation, this would query the MCP server for all entities
39
+ // For migration, we'll need to implement this based on the source backend
40
+ return [];
41
+ }
42
+ async getAllRelations() {
43
+ console.log(`🔗 Reading all relations from ${this.backend} backend...`);
44
+ // In a real implementation, this would query the MCP server for all relations
45
+ return [];
46
+ }
47
+ }
48
+ function loadUserSettings() {
49
+ const settingsPath = join(homedir(), '.claude-mem', 'settings.json');
50
+ if (!existsSync(settingsPath)) {
51
+ return { backend: 'memory' };
52
+ }
53
+ try {
54
+ const content = readFileSync(settingsPath, 'utf8');
55
+ return JSON.parse(content);
56
+ }
57
+ catch (error) {
58
+ console.log(`âš ī¸ Could not parse settings file: ${error.message}`);
59
+ return { backend: 'memory' };
60
+ }
61
+ }
62
+ function saveUserSettings(settings) {
63
+ const settingsPath = join(homedir(), '.claude-mem', 'settings.json');
64
+ try {
65
+ writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
66
+ console.log(`✅ Updated settings with new backend: ${settings.backend}`);
67
+ }
68
+ catch (error) {
69
+ console.error(`❌ Failed to save settings: ${error.message}`);
70
+ }
71
+ }
72
+ function readIndexFiles() {
73
+ const indexDir = join(homedir(), '.claude-mem', 'index');
74
+ const archivesDir = join(homedir(), '.claude-mem', 'archives');
75
+ const entities = [];
76
+ const relations = [];
77
+ const entries = [];
78
+ if (!existsSync(indexDir)) {
79
+ console.log('📂 No index directory found');
80
+ return { entities, relations, entries };
81
+ }
82
+ try {
83
+ const indexFiles = readdirSync(indexDir).filter(file => file.endsWith('.jsonl'));
84
+ for (const file of indexFiles) {
85
+ const filePath = join(indexDir, file);
86
+ const content = readFileSync(filePath, 'utf8');
87
+ const lines = content.trim().split('\n').filter(line => line.trim());
88
+ for (const line of lines) {
89
+ try {
90
+ const entry = JSON.parse(line);
91
+ entries.push(entry);
92
+ // Extract entities and relations from the index entry's nodes
93
+ // In a real migration, we'd need to query the source MCP server
94
+ // For now, we'll create basic entities from the node names
95
+ if (entry.nodes && Array.isArray(entry.nodes)) {
96
+ entry.nodes.forEach(nodeName => {
97
+ // Extract entity type from node name (e.g., "project_Component_Name")
98
+ const parts = nodeName.split('_');
99
+ if (parts.length >= 3) {
100
+ const entityType = parts[1].toLowerCase();
101
+ const entity = {
102
+ name: nodeName,
103
+ entityType: entityType,
104
+ observations: [
105
+ `Core purpose: ${entry.summary}`,
106
+ `Brief description: ${entry.summary}`,
107
+ `Session: ${entry.session_id}`,
108
+ `Project: ${entry.project}`,
109
+ `Keywords: ${entry.keywords?.join(', ') || ''}`,
110
+ `UUID: ${entry.uuid}`
111
+ ]
112
+ };
113
+ entities.push(entity);
114
+ // Create a relation to the session entity
115
+ const sessionEntityName = `${entry.project}_Session_${entry.session_id}`;
116
+ const relation = {
117
+ from: sessionEntityName,
118
+ to: nodeName,
119
+ relationType: 'contains'
120
+ };
121
+ relations.push(relation);
122
+ }
123
+ });
124
+ }
125
+ }
126
+ catch (error) {
127
+ console.log(`âš ī¸ Skipping malformed index entry: ${error.message}`);
128
+ }
129
+ }
130
+ }
131
+ console.log(`📊 Found ${entries.length} index entries, extracted ${entities.length} entities and ${relations.length} relations`);
132
+ }
133
+ catch (error) {
134
+ console.error(`❌ Error reading index files: ${error.message}`);
135
+ }
136
+ return { entities, relations, entries };
137
+ }
138
+ function createBackupFile(settings) {
139
+ const backupDir = join(homedir(), '.claude-mem', 'backups');
140
+ const backupFile = join(backupDir, `settings-backup-${Date.now()}.json`);
141
+ try {
142
+ // Ensure backup directory exists
143
+ if (!existsSync(backupDir)) {
144
+ require('fs').mkdirSync(backupDir, { recursive: true });
145
+ }
146
+ writeFileSync(backupFile, JSON.stringify(settings, null, 2));
147
+ console.log(`💾 Created settings backup: ${backupFile}`);
148
+ }
149
+ catch (error) {
150
+ console.log(`âš ī¸ Could not create backup: ${error.message}`);
151
+ }
152
+ }
153
+ async function performMigration(fromBackend, toBackend, options) {
154
+ // This function is no longer used with embedded Weaviate
155
+ // Migration is handled by the main migrate() function
156
+ console.log('Migration logic moved to main migrate() function');
157
+ }
158
+ export async function migrate(options = {}) {
159
+ console.log('🔄 Claude Memory Backend Migration');
160
+ console.log('==================================\n');
161
+ console.log('â„šī¸ claude-mem now uses embedded Weaviate as the only backend.');
162
+ console.log(' Migration between backends is no longer needed.');
163
+ console.log('');
164
+ console.log('📊 Current Configuration:');
165
+ console.log(' Backend: Embedded Weaviate');
166
+ console.log(' Storage: Persistent across sessions');
167
+ console.log(' Features: Vector search, semantic similarity');
168
+ console.log('');
169
+ console.log('✅ All memory data is automatically stored in the embedded instance.');
170
+ console.log('');
171
+ console.log('💡 If you need to reset your memory data, use:');
172
+ console.log(' rm -rf ~/.claude-mem/weaviate-data/');
173
+ console.log('');
174
+ }
@@ -0,0 +1 @@
1
+ export declare function status(): Promise<void>;