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
package/.mcp.json ADDED
@@ -0,0 +1,11 @@
1
+ {
2
+ "mcpServers": {
3
+ "claude-mem": {
4
+ "command": "npx",
5
+ "args": [
6
+ "-y",
7
+ "@modelcontextprotocol/server-memory"
8
+ ]
9
+ }
10
+ }
11
+ }
package/claude-mem CHANGED
Binary file
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/cli.js ADDED
@@ -0,0 +1,64 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from 'commander';
3
+ import { PACKAGE_NAME, PACKAGE_VERSION, PACKAGE_DESCRIPTION } from './config.js';
4
+ // Import command handlers
5
+ import { compress } from './commands/compress.js';
6
+ import { install } from './commands/install.js';
7
+ import { uninstall } from './commands/uninstall.js';
8
+ import { status } from './commands/status.js';
9
+ import { logs } from './commands/logs.js';
10
+ import { loadContext } from './commands/load-context.js';
11
+ const program = new Command();
12
+ program
13
+ .name(PACKAGE_NAME)
14
+ .description(PACKAGE_DESCRIPTION)
15
+ .version(PACKAGE_VERSION);
16
+ // Compress command
17
+ program
18
+ .command('compress [transcript]')
19
+ .description('Compress a Claude Code transcript into memory')
20
+ .option('--output <path>', 'Output directory for compressed files')
21
+ .option('--dry-run', 'Show what would be compressed without doing it')
22
+ .option('-v, --verbose', 'Show detailed output')
23
+ .action(compress);
24
+ // Install command
25
+ program
26
+ .command('install')
27
+ .description('Install Claude Code hooks for automatic compression')
28
+ .option('--global', 'Install globally (default)')
29
+ .option('--project', 'Install for current project only')
30
+ .option('--force', 'Force installation even if already installed')
31
+ .action(install);
32
+ // Uninstall command
33
+ program
34
+ .command('uninstall')
35
+ .description('Remove Claude Code hooks')
36
+ .option('--global', 'Remove from global settings')
37
+ .option('--project', 'Remove from project settings')
38
+ .option('--all', 'Remove from both global and project settings')
39
+ .action(uninstall);
40
+ // Status command
41
+ program
42
+ .command('status')
43
+ .description('Check installation status of Claude Memory System')
44
+ .action(status);
45
+ // Logs command
46
+ program
47
+ .command('logs')
48
+ .description('View claude-mem operation logs')
49
+ .option('--debug', 'Show debug logs only')
50
+ .option('--error', 'Show error logs only')
51
+ .option('--tail [n]', 'Show last n lines', '50')
52
+ .option('--follow', 'Follow log output')
53
+ .action(logs);
54
+ // Load-context command
55
+ program
56
+ .command('load-context')
57
+ .description('Load compressed memories for current session')
58
+ .option('--project <name>', 'Filter by project name')
59
+ .option('--count <n>', 'Number of memories to load', '10')
60
+ .option('--raw', 'Output raw JSON instead of formatted text')
61
+ .option('--format <type>', 'Output format: json, session-start, or default')
62
+ .action(loadContext);
63
+ // Parse arguments and execute
64
+ program.parse();
@@ -0,0 +1,2 @@
1
+ import { OptionValues } from 'commander';
2
+ export declare function compress(transcript?: string, options?: OptionValues): Promise<void>;
@@ -0,0 +1,59 @@
1
+ import { existsSync } from 'fs';
2
+ import { dirname, basename } from 'path';
3
+ import { fileURLToPath } from 'url';
4
+ const __filename = fileURLToPath(import.meta.url);
5
+ const __dirname = dirname(__filename);
6
+ export async function compress(transcript, options = {}) {
7
+ if (!transcript) {
8
+ console.error('❌ Transcript file path is required');
9
+ process.exit(1);
10
+ }
11
+ if (!existsSync(transcript)) {
12
+ console.error(`❌ Transcript file not found: ${transcript}`);
13
+ process.exit(1);
14
+ }
15
+ console.log(`🗜️ Compressing transcript: ${transcript}`);
16
+ if (options.dryRun) {
17
+ console.log('📋 Dry run mode - no files will be written');
18
+ return;
19
+ }
20
+ try {
21
+ // Import TranscriptCompressor dynamically to ensure it's available
22
+ const { TranscriptCompressor } = await import('../utils/TranscriptCompressor.js');
23
+ // Create compressor instance with debug mode based on verbose option
24
+ const compressor = new TranscriptCompressor({
25
+ debug: options.verbose || false
26
+ });
27
+ // Extract session ID from transcript filename if not provided
28
+ const sessionId = options.sessionId || basename(transcript, '.jsonl');
29
+ if (options.verbose) {
30
+ console.log(`📊 Starting compression with session ID: ${sessionId}`);
31
+ }
32
+ // Perform compression
33
+ const archivePath = await compressor.compress(transcript, sessionId);
34
+ console.log('✅ Compression completed successfully');
35
+ console.log(`📦 Archive created: ${archivePath}`);
36
+ if (options.output && options.output !== dirname(archivePath)) {
37
+ console.log(`📂 Output directory: ${options.output} (archive location may differ)`);
38
+ }
39
+ }
40
+ catch (error) {
41
+ const err = error;
42
+ console.error('❌ Compression failed:', err.message);
43
+ if (options.verbose) {
44
+ console.error('Stack trace:', err.stack);
45
+ }
46
+ // Provide helpful error messages for common issues
47
+ if (err.message.includes('Claude Code executable not found')) {
48
+ console.error('💡 Hint: Make sure Claude Code is installed and accessible in your PATH');
49
+ console.error(' Or set CLAUDE_CODE_PATH environment variable');
50
+ }
51
+ else if (err.message.includes('JWT_SECRET')) {
52
+ console.error('💡 Hint: Make sure JWT_SECRET is set in your MCP configuration');
53
+ }
54
+ else if (err.message.includes('No summaries extracted')) {
55
+ console.error('💡 Hint: The transcript may be too short or not contain analyzable content');
56
+ }
57
+ process.exit(1);
58
+ }
59
+ }
@@ -0,0 +1,2 @@
1
+ import { OptionValues } from 'commander';
2
+ export declare function install(options?: OptionValues): Promise<void>;
@@ -0,0 +1,372 @@
1
+ import { readFileSync, writeFileSync, existsSync, chmodSync, mkdirSync, copyFileSync, statSync } from 'fs';
2
+ import { join, resolve, dirname } from 'path';
3
+ import { homedir } from 'os';
4
+ import { fileURLToPath } from 'url';
5
+ import { PACKAGE_NAME, MCP_SERVER_SCRIPT } from '../config.js';
6
+ import { CLI_MESSAGES } from '../constants.js';
7
+ const __dirname = dirname(fileURLToPath(import.meta.url));
8
+ function ensureDirectoryStructure() {
9
+ const claudeMemDir = join(homedir(), '.claude-mem');
10
+ const hooksDir = join(claudeMemDir, 'hooks');
11
+ const indexDir = join(claudeMemDir, 'index');
12
+ const archivesDir = join(claudeMemDir, 'archives');
13
+ const logsDir = join(claudeMemDir, 'logs');
14
+ [claudeMemDir, hooksDir, indexDir, archivesDir, logsDir].forEach(dir => {
15
+ if (!existsSync(dir)) {
16
+ mkdirSync(dir, { recursive: true });
17
+ }
18
+ });
19
+ }
20
+ function writeHookFiles() {
21
+ const hooksDir = join(homedir(), '.claude-mem', 'hooks');
22
+ const preCompactDest = join(hooksDir, 'pre-compact.js');
23
+ const sessionStartDest = join(hooksDir, 'session-start.js');
24
+ const sessionEndDest = join(hooksDir, 'session-end.js');
25
+ const mcpServerDest = join(homedir(), '.claude-mem', MCP_SERVER_SCRIPT);
26
+ // Find hooks directory relative to the package location
27
+ const possibleHooksPaths = [
28
+ resolve(join(__dirname, '..', '..', 'hooks')), // Development mode
29
+ resolve(join(dirname(process.execPath), 'hooks')), // Standalone executable with hooks alongside
30
+ resolve(join(dirname(process.execPath), '..', 'lib', 'node_modules', 'claude-mem', 'hooks')), // npm global install
31
+ resolve(join(dirname(process.execPath), '..', '..', 'lib', 'node_modules', 'claude-mem', 'hooks')), // npm global install (alternative path)
32
+ ];
33
+ // Find MCP server script in dist directory
34
+ const possibleMcpServerPaths = [
35
+ resolve(join(__dirname, '..', '..', 'dist', MCP_SERVER_SCRIPT)), // Development mode - look in project dist/
36
+ resolve(join(__dirname, '..', MCP_SERVER_SCRIPT)), // Development mode - compiled to same dist/
37
+ resolve(join(dirname(process.execPath), '..', 'lib', 'node_modules', 'claude-mem', 'dist', MCP_SERVER_SCRIPT)), // npm global install
38
+ resolve(join(dirname(process.execPath), '..', '..', 'lib', 'node_modules', 'claude-mem', 'dist', MCP_SERVER_SCRIPT)), // npm global install (alternative path)
39
+ resolve(join(dirname(process.execPath), MCP_SERVER_SCRIPT)), // Standalone executable with script alongside
40
+ ];
41
+ let preCompactSource = null;
42
+ let sessionStartSource = null;
43
+ let sessionEndSource = null;
44
+ let mcpServerSource = null;
45
+ for (const hooksPath of possibleHooksPaths) {
46
+ const preCompactCandidate = join(hooksPath, 'pre-compact.js');
47
+ const sessionStartCandidate = join(hooksPath, 'session-start.js');
48
+ const sessionEndCandidate = join(hooksPath, 'session-end.js');
49
+ if (existsSync(preCompactCandidate) && existsSync(sessionStartCandidate)) {
50
+ preCompactSource = preCompactCandidate;
51
+ sessionStartSource = sessionStartCandidate;
52
+ // Check for session-end.js, but don't require it for backward compatibility
53
+ if (existsSync(sessionEndCandidate)) {
54
+ sessionEndSource = sessionEndCandidate;
55
+ }
56
+ break;
57
+ }
58
+ }
59
+ // Find MCP server script
60
+ for (const mcpServerPath of possibleMcpServerPaths) {
61
+ if (existsSync(mcpServerPath)) {
62
+ mcpServerSource = mcpServerPath;
63
+ break;
64
+ }
65
+ }
66
+ if (preCompactSource && sessionStartSource) {
67
+ copyFileSync(preCompactSource, preCompactDest);
68
+ copyFileSync(sessionStartSource, sessionStartDest);
69
+ // Copy session-end.js if it exists
70
+ if (sessionEndSource) {
71
+ copyFileSync(sessionEndSource, sessionEndDest);
72
+ chmodSync(sessionEndDest, 0o755);
73
+ }
74
+ chmodSync(preCompactDest, 0o755);
75
+ chmodSync(sessionStartDest, 0o755);
76
+ // Copy MCP server script
77
+ if (mcpServerSource) {
78
+ copyFileSync(mcpServerSource, mcpServerDest);
79
+ chmodSync(mcpServerDest, 0o755);
80
+ console.log('✅ MCP server script installed');
81
+ }
82
+ else {
83
+ console.error('❌ MCP server script not found');
84
+ console.error('Searched in:');
85
+ possibleMcpServerPaths.forEach(path => console.error(` - ${path}`));
86
+ process.exit(1);
87
+ }
88
+ // Write a configuration file for hooks to know the package name
89
+ const hookConfigPath = join(hooksDir, 'config.json');
90
+ const hookConfig = {
91
+ packageName: PACKAGE_NAME,
92
+ cliCommand: PACKAGE_NAME, // The command to call (claude-mem)
93
+ backend: 'weaviate' // Always use embedded Weaviate
94
+ };
95
+ writeFileSync(hookConfigPath, JSON.stringify(hookConfig, null, 2));
96
+ console.log(CLI_MESSAGES.INSTALLATION.HOOKS_INSTALLED);
97
+ // Validate MCP server script installation
98
+ if (existsSync(mcpServerDest)) {
99
+ try {
100
+ // Test script has execute permissions by checking file stats
101
+ const stats = statSync(mcpServerDest);
102
+ if (stats.mode & parseInt('100', 8)) {
103
+ console.log('✅ MCP server script validated');
104
+ }
105
+ else {
106
+ console.warn('⚠️ MCP server script may not be executable');
107
+ }
108
+ }
109
+ catch (error) {
110
+ console.warn(`⚠️ MCP server script validation failed: ${error.message}`);
111
+ }
112
+ }
113
+ else {
114
+ console.error('❌ MCP server script validation failed - file not found');
115
+ process.exit(1);
116
+ }
117
+ }
118
+ else {
119
+ console.error(CLI_MESSAGES.ERRORS.HOOKS_NOT_FOUND);
120
+ console.error('Searched in:');
121
+ possibleHooksPaths.forEach(path => console.error(` - ${path}`));
122
+ process.exit(1);
123
+ }
124
+ }
125
+ /**
126
+ * 🔒 LOCKED by @docs-agent | Change to 🔑 to allow @docs-agent edits
127
+ *
128
+ * OFFICIAL DOCS: Claude Code MCP Configuration v2025
129
+ * Last Verified: 2025-08-31
130
+ * @see https://docs.anthropic.com/en/docs/claude-code/mcp
131
+ *
132
+ * MCP Config File Locations (per official docs):
133
+ * - User scope: ~/.claude.json
134
+ * - Project scope: ./.mcp.json (checked into version control)
135
+ * - Local scope: Not officially documented (implementation decision)
136
+ *
137
+ * @see docs/claude-code/mcp-configuration.md
138
+ */
139
+ function configureMcpServer(settingsDir, scope) {
140
+ // Determine the correct MCP config file based on scope
141
+ let mcpConfigPath;
142
+ if (scope === 'user') {
143
+ // User scope: ~/.claude.json
144
+ mcpConfigPath = join(homedir(), '.claude.json');
145
+ }
146
+ else if (scope === 'project') {
147
+ // Project scope: .mcp.json in current directory
148
+ mcpConfigPath = join(process.cwd(), '.mcp.json');
149
+ }
150
+ else {
151
+ // Local scope: use .claude.json with project-specific section
152
+ mcpConfigPath = join(homedir(), '.claude.json');
153
+ }
154
+ let config = {};
155
+ if (existsSync(mcpConfigPath)) {
156
+ try {
157
+ config = JSON.parse(readFileSync(mcpConfigPath, 'utf8'));
158
+ }
159
+ catch (error) {
160
+ console.log(CLI_MESSAGES.ERRORS.MCP_CONFIG_PARSE_FAILED(error.message));
161
+ return; // Don't overwrite a file we can't parse
162
+ }
163
+ }
164
+ if (!config.mcpServers) {
165
+ config.mcpServers = {};
166
+ }
167
+ // Only add/update the server for this package, preserve everything else
168
+ // Use local MCP server script with embedded Weaviate instead of npx
169
+ config.mcpServers[PACKAGE_NAME] = {
170
+ command: "node",
171
+ args: [join(homedir(), '.claude-mem', MCP_SERVER_SCRIPT)]
172
+ };
173
+ try {
174
+ writeFileSync(mcpConfigPath, JSON.stringify(config, null, 2));
175
+ console.log(CLI_MESSAGES.INSTALLATION.MCP_CONFIGURED(mcpConfigPath));
176
+ console.log('✅ Configured embedded Weaviate MCP server');
177
+ }
178
+ catch (error) {
179
+ console.log(CLI_MESSAGES.ERRORS.MCP_CONFIG_WRITE_FAILED(error.message));
180
+ }
181
+ }
182
+ export async function install(options = {}) {
183
+ console.log(CLI_MESSAGES.INSTALLATION.STARTING);
184
+ console.log('🧠 Installing embedded Weaviate MCP server for persistent semantic memory');
185
+ // Ensure claude-mem directory structure exists
186
+ ensureDirectoryStructure();
187
+ // Determine which settings file to use
188
+ let settingsDir;
189
+ let settingsFile;
190
+ let settingsType;
191
+ if (options.local) {
192
+ settingsDir = join(process.cwd(), '.claude');
193
+ settingsFile = 'settings.local.json';
194
+ settingsType = 'Local';
195
+ }
196
+ else if (options.project) {
197
+ settingsDir = join(process.cwd(), '.claude');
198
+ settingsFile = 'settings.json';
199
+ settingsType = 'Project';
200
+ }
201
+ else {
202
+ // Default to user settings (--user or --global or no flag)
203
+ settingsDir = join(homedir(), '.claude');
204
+ settingsFile = 'settings.json';
205
+ settingsType = 'User';
206
+ }
207
+ const settingsPath = join(settingsDir, settingsFile);
208
+ // Determine scope for MCP configuration
209
+ const scope = options.local ? 'local' :
210
+ options.project ? 'project' :
211
+ 'user';
212
+ // Configure MCP server with the appropriate scope
213
+ configureMcpServer(settingsDir, scope);
214
+ // Write hook files to ~/.claude-mem/hooks/
215
+ writeHookFiles();
216
+ // Point settings to the installed hooks
217
+ const claudeMemHooksDir = join(homedir(), '.claude-mem', 'hooks');
218
+ const preCompactScript = join(claudeMemHooksDir, 'pre-compact.js');
219
+ const sessionStartScript = join(claudeMemHooksDir, 'session-start.js');
220
+ const sessionEndScript = join(claudeMemHooksDir, 'session-end.js');
221
+ let settings = {};
222
+ if (existsSync(settingsPath)) {
223
+ try {
224
+ const content = readFileSync(settingsPath, 'utf8');
225
+ settings = JSON.parse(content);
226
+ }
227
+ catch (error) {
228
+ console.log(`⚠️ Creating new settings file (could not parse existing): ${error.message}`);
229
+ }
230
+ }
231
+ // Ensure settings directory exists
232
+ if (!existsSync(settingsDir)) {
233
+ mkdirSync(settingsDir, { recursive: true });
234
+ }
235
+ // Initialize hooks structure if it doesn't exist
236
+ if (!settings.hooks) {
237
+ settings.hooks = {};
238
+ }
239
+ // Check for existing hooks from this package
240
+ // Non-tool hooks structure: array of { hooks: [...] } (no matcher field)
241
+ const hasExistingPreCompact = settings.hooks.PreCompact?.some((config) => config.hooks?.some((hook) => hook.command?.includes(PACKAGE_NAME) || hook.command?.includes('pre-compact.js')));
242
+ const hasExistingSessionStart = settings.hooks.SessionStart?.some((config) => config.hooks?.some((hook) => hook.command?.includes(PACKAGE_NAME) || hook.command?.includes('session-start.js')));
243
+ const hasExistingSessionEnd = settings.hooks.SessionEnd?.some((config) => config.hooks?.some((hook) => hook.command?.includes(PACKAGE_NAME) || hook.command?.includes('session-end.js')));
244
+ if ((hasExistingPreCompact || hasExistingSessionStart || hasExistingSessionEnd) && !options.force) {
245
+ console.log(CLI_MESSAGES.INSTALLATION.ALREADY_INSTALLED);
246
+ console.log(CLI_MESSAGES.INSTALLATION.USE_FORCE);
247
+ return;
248
+ }
249
+ // Remove existing claude-mem hooks if forcing
250
+ if (options.force) {
251
+ // Non-tool hooks: filter out configs where hooks contain our commands
252
+ if (settings.hooks.PreCompact) {
253
+ settings.hooks.PreCompact = settings.hooks.PreCompact.filter((config) => !config.hooks?.some((hook) => hook.command?.includes(PACKAGE_NAME) || hook.command?.includes('pre-compact.js')));
254
+ if (settings.hooks.PreCompact.length === 0) {
255
+ delete settings.hooks.PreCompact;
256
+ }
257
+ }
258
+ if (settings.hooks.SessionStart) {
259
+ settings.hooks.SessionStart = settings.hooks.SessionStart.filter((config) => !config.hooks?.some((hook) => hook.command?.includes(PACKAGE_NAME) || hook.command?.includes('session-start.js')));
260
+ if (settings.hooks.SessionStart.length === 0) {
261
+ delete settings.hooks.SessionStart;
262
+ }
263
+ }
264
+ if (settings.hooks.SessionEnd) {
265
+ settings.hooks.SessionEnd = settings.hooks.SessionEnd.filter((config) => !config.hooks?.some((hook) => hook.command?.includes(PACKAGE_NAME) || hook.command?.includes('session-end.js')));
266
+ if (settings.hooks.SessionEnd.length === 0) {
267
+ delete settings.hooks.SessionEnd;
268
+ }
269
+ }
270
+ }
271
+ /**
272
+ * 🔒 LOCKED by @docs-agent | Change to 🔑 to allow @docs-agent edits
273
+ *
274
+ * OFFICIAL DOCS: Claude Code Hooks Configuration v2025
275
+ * Last Verified: 2025-08-31
276
+ *
277
+ * Hook Configuration Structure Requirements:
278
+ * - Tool-related hooks (PreToolUse, PostToolUse): Use 'matcher' field for tool patterns
279
+ * - Non-tool hooks (PreCompact, SessionStart, SessionEnd, etc.): NO matcher/pattern field
280
+ *
281
+ * Correct Non-Tool Hook Structure:
282
+ * {
283
+ * hooks: [{
284
+ * type: "command",
285
+ * command: "/path/to/script.js"
286
+ * }]
287
+ * }
288
+ *
289
+ * @see https://docs.anthropic.com/en/docs/claude-code/hooks
290
+ * @see docs/claude-code/hook-configuration.md for full documentation
291
+ */
292
+ // Add PreCompact hook - Non-tool hook (no matcher field)
293
+ if (!settings.hooks.PreCompact) {
294
+ settings.hooks.PreCompact = [];
295
+ }
296
+ // ✅ CORRECT: Non-tool hooks have no 'pattern' or 'matcher' field
297
+ settings.hooks.PreCompact.push({
298
+ hooks: [
299
+ {
300
+ type: "command",
301
+ command: preCompactScript,
302
+ timeout: 180000
303
+ }
304
+ ]
305
+ });
306
+ // Add SessionStart hook - Non-tool hook (no matcher field)
307
+ if (!settings.hooks.SessionStart) {
308
+ settings.hooks.SessionStart = [];
309
+ }
310
+ // ✅ CORRECT: Non-tool hooks have no 'pattern' or 'matcher' field
311
+ settings.hooks.SessionStart.push({
312
+ hooks: [
313
+ {
314
+ type: "command",
315
+ command: sessionStartScript
316
+ }
317
+ ]
318
+ });
319
+ // Add SessionEnd hook (only if the file exists)
320
+ if (existsSync(sessionEndScript)) {
321
+ if (!settings.hooks.SessionEnd) {
322
+ settings.hooks.SessionEnd = [];
323
+ }
324
+ // ✅ CORRECT: Non-tool hooks have no 'pattern' or 'matcher' field
325
+ settings.hooks.SessionEnd.push({
326
+ hooks: [{
327
+ type: "command",
328
+ command: sessionEndScript,
329
+ timeout: 180000
330
+ }]
331
+ });
332
+ }
333
+ // Write updated settings
334
+ try {
335
+ writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
336
+ console.log(CLI_MESSAGES.INSTALLATION.SETTINGS_WRITTEN(settingsType, settingsPath));
337
+ console.log('');
338
+ console.log(CLI_MESSAGES.INSTALLATION.SUCCESS);
339
+ // Store backend setting in user settings
340
+ const userSettingsDir = join(homedir(), '.claude-mem');
341
+ const userSettingsPath = join(userSettingsDir, 'settings.json');
342
+ let userSettings = {};
343
+ if (existsSync(userSettingsPath)) {
344
+ try {
345
+ userSettings = JSON.parse(readFileSync(userSettingsPath, 'utf8'));
346
+ }
347
+ catch (error) {
348
+ console.log(`⚠️ Creating new user settings file (could not parse existing): ${error.message}`);
349
+ }
350
+ }
351
+ userSettings.backend = 'weaviate';
352
+ userSettings.installed = true;
353
+ // Always use embedded Weaviate - no external config needed
354
+ userSettings.embedded = true;
355
+ try {
356
+ writeFileSync(userSettingsPath, JSON.stringify(userSettings, null, 2));
357
+ console.log(`✅ Backend configuration saved: embedded Weaviate`);
358
+ }
359
+ catch (error) {
360
+ console.log(`⚠️ Could not save backend settings: ${error.message}`);
361
+ }
362
+ console.log('');
363
+ console.log('Next steps:');
364
+ CLI_MESSAGES.NEXT_STEPS.forEach((step) => {
365
+ console.log(step);
366
+ });
367
+ }
368
+ catch (error) {
369
+ console.error(CLI_MESSAGES.ERRORS.SETTINGS_WRITE_FAILED(settingsPath, error.message));
370
+ process.exit(1);
371
+ }
372
+ }
@@ -0,0 +1,2 @@
1
+ import { OptionValues } from 'commander';
2
+ export declare function loadContext(options?: OptionValues): Promise<void>;