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,111 @@
1
+ /**
2
+ * Interface for message objects in transcript
3
+ */
4
+ interface TranscriptMessage {
5
+ type: string;
6
+ message?: {
7
+ content?: string | Array<{
8
+ text?: string;
9
+ content?: string;
10
+ }>;
11
+ role?: string;
12
+ timestamp?: string;
13
+ created_at?: string;
14
+ };
15
+ content?: string | Array<{
16
+ text?: string;
17
+ content?: string;
18
+ }>;
19
+ role?: string;
20
+ uuid?: string;
21
+ session_id?: string;
22
+ parent_tool_use_id?: string;
23
+ timestamp?: string;
24
+ created_at?: string;
25
+ subtype?: string;
26
+ result?: string;
27
+ model?: string;
28
+ tools?: unknown[];
29
+ mcp_servers?: unknown[];
30
+ toolUseResult?: {
31
+ stdout?: string;
32
+ stderr?: string;
33
+ interrupted?: boolean;
34
+ isImage?: boolean;
35
+ };
36
+ }
37
+ /**
38
+ * Interface for tool use chains extracted from messages
39
+ */
40
+ interface ToolUseChain {
41
+ id: string;
42
+ tools: string[];
43
+ messages: TranscriptMessage[];
44
+ }
45
+ /**
46
+ * Compression options for the TranscriptCompressor
47
+ */
48
+ export interface CompressionOptions {
49
+ output?: string;
50
+ dryRun?: boolean;
51
+ verbose?: boolean;
52
+ debug?: boolean;
53
+ }
54
+ /**
55
+ * TranscriptCompressor handles the analysis and compression of Claude Code conversation transcripts
56
+ * into a searchable knowledge graph format using the Model Context Protocol.
57
+ */
58
+ export declare class TranscriptCompressor {
59
+ private paths;
60
+ private debugMode;
61
+ constructor(options?: CompressionOptions);
62
+ /**
63
+ * Ensures that the required directory structure exists
64
+ */
65
+ private ensureClaudeMemStructure;
66
+ /**
67
+ * Extracts tool use chains from conversation messages
68
+ */
69
+ extractToolUseChains(messages: TranscriptMessage[]): ToolUseChain[];
70
+ /**
71
+ * Main compression method that processes a transcript and creates compressed memories
72
+ */
73
+ compress(transcriptPath: string, sessionId?: string): Promise<string>;
74
+ /**
75
+ * Finds Claude Code executable in common locations
76
+ */
77
+ private findClaudeExecutable;
78
+ /**
79
+ * Finds MCP configuration file
80
+ */
81
+ private findMCPConfig;
82
+ /**
83
+ * Processes Claude response to extract summaries
84
+ */
85
+ private processClaudeResponse;
86
+ /**
87
+ * Formats conversation messages for analysis prompt
88
+ */
89
+ private formatConversationForPrompt;
90
+ /**
91
+ * Extracts content from message object
92
+ */
93
+ private extractContent;
94
+ /**
95
+ * Summarizes tool use results
96
+ */
97
+ private summarizeToolResult;
98
+ /**
99
+ * Normalizes timestamp formats
100
+ */
101
+ private normalizeTimestamp;
102
+ /**
103
+ * Creates an archive file of the original transcript
104
+ */
105
+ private createArchive;
106
+ /**
107
+ * Appends compression summaries to the index file
108
+ */
109
+ private appendToIndex;
110
+ }
111
+ export {};
@@ -0,0 +1,486 @@
1
+ import { query } from '@anthropic-ai/claude-code';
2
+ import fs from 'fs';
3
+ import path, { join } from 'path';
4
+ import os from 'os';
5
+ import { PathResolver } from './PathResolver.js';
6
+ import { createAnalysisPrompt, DEBUG_MESSAGES } from '../constants.js';
7
+ import { log } from './logger.js';
8
+ import { CompressionError } from '../types.js';
9
+ /**
10
+ * TranscriptCompressor handles the analysis and compression of Claude Code conversation transcripts
11
+ * into a searchable knowledge graph format using the Model Context Protocol.
12
+ */
13
+ export class TranscriptCompressor {
14
+ paths;
15
+ debugMode;
16
+ constructor(options = {}) {
17
+ this.paths = new PathResolver();
18
+ this.debugMode = options.debug || false;
19
+ this.ensureClaudeMemStructure();
20
+ if (this.debugMode) {
21
+ log.debug('🤖 TranscriptCompressor initialized');
22
+ }
23
+ }
24
+ /**
25
+ * Ensures that the required directory structure exists
26
+ */
27
+ ensureClaudeMemStructure() {
28
+ const configDir = this.paths.getConfigDir();
29
+ const indexDir = this.paths.getIndexDir();
30
+ const archiveDir = this.paths.getArchiveDir();
31
+ const logsDir = this.paths.getLogsDir();
32
+ PathResolver.ensureDirectories([configDir, indexDir, archiveDir, logsDir]);
33
+ }
34
+ /**
35
+ * Extracts tool use chains from conversation messages
36
+ */
37
+ extractToolUseChains(messages) {
38
+ const chains = [];
39
+ const toolUseMap = new Map();
40
+ messages.forEach((msg) => {
41
+ if (msg.parent_tool_use_id) {
42
+ const parentId = msg.parent_tool_use_id;
43
+ if (!toolUseMap.has(parentId)) {
44
+ toolUseMap.set(parentId, {
45
+ id: parentId,
46
+ tools: [],
47
+ messages: [],
48
+ });
49
+ }
50
+ toolUseMap.get(parentId).messages.push(msg);
51
+ if (msg.type === 'assistant' && msg.message?.content) {
52
+ const content = Array.isArray(msg.message.content)
53
+ ? msg.message.content[0]?.text || ''
54
+ : msg.message.content;
55
+ const toolMatch = content.match(/Using (\w+) tool/i);
56
+ if (toolMatch) {
57
+ toolUseMap.get(parentId).tools.push(toolMatch[1]);
58
+ }
59
+ }
60
+ }
61
+ });
62
+ toolUseMap.forEach((chain) => {
63
+ if (chain.tools.length > 0) {
64
+ chains.push(chain);
65
+ }
66
+ });
67
+ return chains;
68
+ }
69
+ /**
70
+ * Main compression method that processes a transcript and creates compressed memories
71
+ */
72
+ async compress(transcriptPath, sessionId) {
73
+ if (this.debugMode) {
74
+ log.debug(DEBUG_MESSAGES.COMPRESSION_STARTED);
75
+ log.debug(DEBUG_MESSAGES.TRANSCRIPT_PATH(transcriptPath));
76
+ log.debug(DEBUG_MESSAGES.SESSION_ID(sessionId || 'auto-detected'));
77
+ }
78
+ try {
79
+ const projectName = PathResolver.extractProjectName(transcriptPath);
80
+ if (this.debugMode) {
81
+ log.debug(DEBUG_MESSAGES.PROJECT_NAME(projectName));
82
+ }
83
+ // Read and parse transcript
84
+ const content = fs.readFileSync(transcriptPath, 'utf-8');
85
+ const lines = content.trim().split('\n').filter(line => line.trim());
86
+ const messages = [];
87
+ let parseErrors = 0;
88
+ for (let i = 0; i < lines.length; i++) {
89
+ try {
90
+ const parsed = JSON.parse(lines[i]);
91
+ messages.push(parsed);
92
+ }
93
+ catch (e) {
94
+ parseErrors++;
95
+ if (this.debugMode) {
96
+ log.debug(`Parse error on line ${i + 1}: ${e.message}`);
97
+ }
98
+ }
99
+ }
100
+ if (this.debugMode) {
101
+ log.debug(DEBUG_MESSAGES.TRANSCRIPT_STATS(content.length, messages.length));
102
+ if (parseErrors > 0) {
103
+ log.debug(`Parse errors: ${parseErrors}`);
104
+ }
105
+ }
106
+ // Generate final session ID
107
+ const finalSessionId = sessionId || path.basename(transcriptPath, '.jsonl');
108
+ // Format conversation for analysis
109
+ const conversationText = this.formatConversationForPrompt(messages);
110
+ const toolUseChains = this.extractToolUseChains(messages);
111
+ // Create analysis prompt using the utility from constants.ts
112
+ const prompt = createAnalysisPrompt(projectName, finalSessionId, false, // hasCompressedContent
113
+ '', // existingMemoriesText
114
+ toolUseChains);
115
+ if (this.debugMode) {
116
+ log.debug('📤 Analysis prompt created');
117
+ log.debug(`📊 Prompt length: ${prompt.length} characters`);
118
+ }
119
+ // Find Claude Code executable and MCP config
120
+ const claudePath = this.findClaudeExecutable();
121
+ const mcpConfigPath = this.findMCPConfig();
122
+ if (this.debugMode) {
123
+ if (claudePath) {
124
+ log.debug(DEBUG_MESSAGES.CLAUDE_PATH_FOUND(claudePath));
125
+ }
126
+ if (mcpConfigPath) {
127
+ log.debug(DEBUG_MESSAGES.MCP_CONFIG_USED(mcpConfigPath));
128
+ }
129
+ }
130
+ // Call Claude SDK for analysis
131
+ const fullPrompt = `${prompt}\n\nConversation to compress:\n${conversationText}`;
132
+ const response = await query({
133
+ prompt: fullPrompt,
134
+ options: {
135
+ maxTurns: 1,
136
+ allowedTools: [
137
+ 'mcp__claude-mem__create_entities',
138
+ 'mcp__claude-mem__create_relations',
139
+ ],
140
+ },
141
+ });
142
+ // Process response and extract summaries
143
+ const summaries = await this.processClaudeResponse(response);
144
+ if (this.debugMode) {
145
+ log.debug(DEBUG_MESSAGES.COMPRESSION_COMPLETE(summaries.length));
146
+ }
147
+ if (summaries.length === 0) {
148
+ if (this.debugMode) {
149
+ log.debug('⚠️ WARNING: No summaries were extracted!');
150
+ }
151
+ throw new CompressionError('No summaries extracted from Claude response', transcriptPath, 'analyzing');
152
+ }
153
+ // Create archive and update index
154
+ const archivePath = this.createArchive(transcriptPath, projectName, finalSessionId, content);
155
+ this.appendToIndex(summaries, projectName, finalSessionId, messages, archivePath);
156
+ if (this.debugMode) {
157
+ log.debug(`✅ SUCCESS`);
158
+ log.debug(`Archive created: ${archivePath}`);
159
+ log.debug(`Summaries created: ${summaries.length}`);
160
+ }
161
+ return archivePath;
162
+ }
163
+ catch (error) {
164
+ log.error('COMPRESSION FAILED', error, {
165
+ transcriptPath,
166
+ sessionId
167
+ });
168
+ throw error;
169
+ }
170
+ }
171
+ /**
172
+ * Finds Claude Code executable in common locations
173
+ */
174
+ findClaudeExecutable() {
175
+ const possiblePaths = [
176
+ '/opt/homebrew/bin/claude',
177
+ '/usr/local/bin/claude',
178
+ process.env.CLAUDE_CODE_PATH,
179
+ ].filter(Boolean);
180
+ for (const path of possiblePaths) {
181
+ if (path && fs.existsSync(path)) {
182
+ return path;
183
+ }
184
+ }
185
+ return undefined;
186
+ }
187
+ /**
188
+ * Finds MCP configuration file
189
+ */
190
+ findMCPConfig() {
191
+ const possibleConfigs = [
192
+ join(process.cwd(), '.mcp.json'),
193
+ join(os.homedir(), '.claude.json'),
194
+ join(os.homedir(), '.claude', '.mcp.json'),
195
+ ];
196
+ const mcpConfigPath = possibleConfigs.find(fs.existsSync);
197
+ return mcpConfigPath || join(os.homedir(), '.claude.json');
198
+ }
199
+ /**
200
+ * Processes Claude response to extract summaries
201
+ */
202
+ async processClaudeResponse(response) {
203
+ const summaries = [];
204
+ let fullContent = '';
205
+ if (response && typeof response === 'object' && Symbol.asyncIterator in response) {
206
+ // Handle streaming response
207
+ for await (const message of response) {
208
+ if (message?.content)
209
+ fullContent += message.content;
210
+ if (message?.text)
211
+ fullContent += message.text;
212
+ if (message?.data)
213
+ fullContent += message.data;
214
+ if (message?.message?.content) {
215
+ if (Array.isArray(message.message.content)) {
216
+ message.message.content.forEach((item) => {
217
+ if (item.type === 'text' && item.text) {
218
+ fullContent += item.text;
219
+ }
220
+ });
221
+ }
222
+ }
223
+ if (message?.type === 'result' && message?.result) {
224
+ fullContent = message.result;
225
+ }
226
+ }
227
+ }
228
+ else if (typeof response === 'string') {
229
+ fullContent = response;
230
+ }
231
+ else if (Array.isArray(response)) {
232
+ response.forEach((item) => {
233
+ if (item?.session_id && item?.summary && item?.nodes && item?.keywords) {
234
+ summaries.push(item);
235
+ }
236
+ });
237
+ }
238
+ else if (typeof response === 'object' && response !== null) {
239
+ const obj = response;
240
+ if (obj.session_id && obj.summary && obj.nodes && obj.keywords) {
241
+ summaries.push(obj);
242
+ }
243
+ }
244
+ // Parse JSONL content if we have it
245
+ if (fullContent && summaries.length === 0) {
246
+ const lines = fullContent.split('\n');
247
+ lines.forEach((line) => {
248
+ const trimmed = line.trim();
249
+ if (!trimmed)
250
+ return;
251
+ try {
252
+ const parsed = JSON.parse(trimmed);
253
+ if (parsed.session_id && parsed.summary && parsed.nodes && parsed.keywords) {
254
+ summaries.push(parsed);
255
+ }
256
+ }
257
+ catch (e) {
258
+ if (this.debugMode) {
259
+ log.debug(`Failed to parse JSONL line: ${e.message}`);
260
+ }
261
+ }
262
+ });
263
+ }
264
+ return summaries;
265
+ }
266
+ /**
267
+ * Formats conversation messages for analysis prompt
268
+ */
269
+ formatConversationForPrompt(messages) {
270
+ const jsonlLines = [];
271
+ messages.forEach((m, index) => {
272
+ let role = 'unknown';
273
+ const messageType = m.type;
274
+ if (m.type === 'assistant') {
275
+ role = 'assistant';
276
+ }
277
+ else if (m.type === 'user') {
278
+ role = 'user';
279
+ }
280
+ else if (m.type === 'result') {
281
+ role = 'system';
282
+ }
283
+ else if (m.type === 'system') {
284
+ role = 'system';
285
+ }
286
+ else {
287
+ role = m.message?.role || m.role || 'unknown';
288
+ }
289
+ const content = this.extractContent(m);
290
+ if (!content || content.trim() === '') {
291
+ if (this.debugMode) {
292
+ log.debug(`Skipping message ${index + 1}: empty content`);
293
+ }
294
+ return;
295
+ }
296
+ const timestamp = this.normalizeTimestamp(m);
297
+ const messageObj = {
298
+ type: messageType,
299
+ role: role,
300
+ content: content,
301
+ };
302
+ if (m.uuid)
303
+ messageObj.uuid = m.uuid;
304
+ if (m.session_id)
305
+ messageObj.session_id = m.session_id;
306
+ if (m.parent_tool_use_id)
307
+ messageObj.parent_tool_use_id = m.parent_tool_use_id;
308
+ if (timestamp)
309
+ messageObj.ts = timestamp;
310
+ try {
311
+ jsonlLines.push(JSON.stringify(messageObj));
312
+ }
313
+ catch (e) {
314
+ const safeObj = {
315
+ type: messageType,
316
+ role: role,
317
+ content: String(content).replace(/[\u0000-\u001F\u007F-\u009F]/g, ''),
318
+ error: 'content_sanitized',
319
+ };
320
+ if (m.uuid)
321
+ safeObj.uuid = m.uuid;
322
+ if (m.session_id)
323
+ safeObj.session_id = m.session_id;
324
+ if (timestamp)
325
+ safeObj.ts = timestamp;
326
+ jsonlLines.push(JSON.stringify(safeObj));
327
+ if (this.debugMode) {
328
+ log.debug(`Message ${index + 1} sanitized due to JSON error: ${e.message}`);
329
+ }
330
+ }
331
+ });
332
+ if (this.debugMode) {
333
+ log.debug(`Field filtering complete: ${jsonlLines.length} messages processed`);
334
+ }
335
+ return `\`\`\`\n${jsonlLines.join('\n')}\n\`\`\`\n\n* All dates/times are in UTC`;
336
+ }
337
+ /**
338
+ * Extracts content from message object
339
+ */
340
+ extractContent(m) {
341
+ if (m.type === 'assistant' || m.type === 'user') {
342
+ const messageContent = m.message?.content;
343
+ if (messageContent) {
344
+ if (Array.isArray(messageContent)) {
345
+ return messageContent
346
+ .map((item) => {
347
+ if (typeof item === 'string')
348
+ return item;
349
+ if (item.text)
350
+ return item.text;
351
+ if (item.content)
352
+ return item.content;
353
+ return '';
354
+ })
355
+ .filter(Boolean)
356
+ .join(' ');
357
+ }
358
+ return String(messageContent).trim();
359
+ }
360
+ }
361
+ else if (m.type === 'result') {
362
+ if (m.subtype === 'success' && m.result) {
363
+ return `[Result: ${m.result}]`;
364
+ }
365
+ else if (m.subtype === 'error_max_turns') {
366
+ return '[Error: Maximum turns reached]';
367
+ }
368
+ else if (m.subtype === 'error_during_execution') {
369
+ return '[Error during execution]';
370
+ }
371
+ }
372
+ else if (m.type === 'system' && m.subtype === 'init') {
373
+ return `[System initialized: ${m.model}, tools: ${m.tools?.length || 0}, MCP servers: ${m.mcp_servers?.length || 0}]`;
374
+ }
375
+ let content = m.message?.content || m.content || '';
376
+ if (Array.isArray(content)) {
377
+ content = content
378
+ .map((item) => {
379
+ if (typeof item === 'string')
380
+ return item;
381
+ if (typeof item === 'object' && item !== null) {
382
+ const obj = item;
383
+ if (obj.text)
384
+ return obj.text;
385
+ if (obj.content)
386
+ return obj.content;
387
+ }
388
+ return '';
389
+ })
390
+ .filter(Boolean)
391
+ .join(' ');
392
+ }
393
+ if (m.toolUseResult) {
394
+ const toolSummary = this.summarizeToolResult(m.toolUseResult, String(content));
395
+ if (toolSummary) {
396
+ content = content ? `${content}\n\n${toolSummary}` : toolSummary;
397
+ }
398
+ }
399
+ return String(content).trim();
400
+ }
401
+ /**
402
+ * Summarizes tool use results
403
+ */
404
+ summarizeToolResult(toolResult, existingContent) {
405
+ const summaryParts = [];
406
+ if (toolResult.stdout) {
407
+ const stdout = String(toolResult.stdout);
408
+ if (stdout.length > 200) {
409
+ const lineCount = stdout.split('\n').length;
410
+ const charCount = stdout.length;
411
+ const lines = stdout.split('\n');
412
+ const preview = lines.slice(0, 3).join('\n');
413
+ const suffix = lines.length > 6 ? `\n...\n${lines.slice(-2).join('\n')}` : '';
414
+ summaryParts.push(`Result: ${preview}${suffix} (${lineCount} lines, ${charCount} chars)`);
415
+ }
416
+ else {
417
+ summaryParts.push(`Result: ${stdout}`);
418
+ }
419
+ }
420
+ if (toolResult.stderr && toolResult.stderr.trim()) {
421
+ summaryParts.push(`Error: ${toolResult.stderr.substring(0, 150)}${toolResult.stderr.length > 150 ? '...' : ''}`);
422
+ }
423
+ if (toolResult.interrupted) {
424
+ summaryParts.push('(interrupted)');
425
+ }
426
+ if (toolResult.isImage) {
427
+ summaryParts.push('(image output)');
428
+ }
429
+ return summaryParts.join('\n');
430
+ }
431
+ /**
432
+ * Normalizes timestamp formats
433
+ */
434
+ normalizeTimestamp(m) {
435
+ const ts = m.timestamp || m.message?.timestamp || m.created_at || m.message?.created_at;
436
+ if (!ts)
437
+ return '';
438
+ try {
439
+ const date = new Date(ts);
440
+ if (isNaN(date.getTime()))
441
+ return '';
442
+ return date.toISOString().slice(0, 19).replace('T', ' ');
443
+ }
444
+ catch (e) {
445
+ if (this.debugMode) {
446
+ log.debug(`Invalid timestamp format: ${ts}`);
447
+ }
448
+ return '';
449
+ }
450
+ }
451
+ /**
452
+ * Creates an archive file of the original transcript
453
+ */
454
+ createArchive(transcriptPath, projectName, sessionId, content) {
455
+ const projectArchiveDir = this.paths.getProjectArchiveDir(projectName);
456
+ PathResolver.ensureDirectory(projectArchiveDir);
457
+ const archivePath = join(projectArchiveDir, `${sessionId}.jsonl.archive`);
458
+ fs.writeFileSync(archivePath, content);
459
+ if (this.debugMode) {
460
+ log.debug(`📦 Created archive: ${archivePath}`);
461
+ }
462
+ return archivePath;
463
+ }
464
+ /**
465
+ * Appends compression summaries to the index file
466
+ */
467
+ appendToIndex(summaries, projectName, sessionId, messages, archivePath) {
468
+ const indexPath = this.paths.getIndexPath();
469
+ const indexDir = path.dirname(indexPath);
470
+ PathResolver.ensureDirectory(indexDir);
471
+ const messageCount = messages.length;
472
+ const indexEntries = summaries.map((entry) => ({
473
+ ...entry,
474
+ session_id: sessionId,
475
+ project: projectName,
476
+ message_count: entry.message_count || messageCount,
477
+ archive_path: archivePath,
478
+ }));
479
+ const indexContent = indexEntries.map((entry) => JSON.stringify(entry)).join('\n') + '\n';
480
+ fs.appendFileSync(indexPath, indexContent);
481
+ if (this.debugMode) {
482
+ log.debug(`📝 Appended ${indexEntries.length} entries to index`);
483
+ log.debug(`Index path: ${indexPath}`);
484
+ }
485
+ }
486
+ }
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Common utilities for the memory compression system - CONSOLIDATED
3
+ *
4
+ * This module now re-exports the main utility classes to maintain backward compatibility.
5
+ * The duplicate implementations have been consolidated into the main utility files:
6
+ *
7
+ * - PathResolver -> src/utils/PathResolver.ts
8
+ * - SettingsManager -> src/utils/SettingsManager.ts
9
+ * - HookDetector -> src/utils/HookDetector.ts
10
+ */
11
+ export { PathResolver } from './PathResolver.js';
12
+ export { SettingsManager } from './SettingsManager.js';
13
+ export { HookDetector } from './HookDetector.js';
14
+ export type { SettingsLocation } from './PathResolver.js';
15
+ export type { ClaudeSettings, SettingsResult } from './SettingsManager.js';
16
+ export type { HookDetectionResult, HookInfo } from './HookDetector.js';
17
+ export interface InstallOptions {
18
+ local?: boolean;
19
+ project?: boolean;
20
+ force?: boolean;
21
+ }
22
+ export interface ClaudeMemPaths {
23
+ baseDir: string;
24
+ hooksDir: string;
25
+ indexDir: string;
26
+ archivesDir: string;
27
+ logsDir: string;
28
+ settingsFile: string;
29
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Common utilities for the memory compression system - CONSOLIDATED
3
+ *
4
+ * This module now re-exports the main utility classes to maintain backward compatibility.
5
+ * The duplicate implementations have been consolidated into the main utility files:
6
+ *
7
+ * - PathResolver -> src/utils/PathResolver.ts
8
+ * - SettingsManager -> src/utils/SettingsManager.ts
9
+ * - HookDetector -> src/utils/HookDetector.ts
10
+ */
11
+ // Re-export main utility classes for backward compatibility
12
+ export { PathResolver } from './PathResolver.js';
13
+ export { SettingsManager } from './SettingsManager.js';
14
+ export { HookDetector } from './HookDetector.js';