claude-mem 3.2.0 → 3.2.1

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 (50) hide show
  1. package/claude-mem +0 -0
  2. package/package.json +1 -2
  3. package/dist/bin/cli.d.ts +0 -2
  4. package/dist/bin/cli.js +0 -129
  5. package/dist/commands/compress.d.ts +0 -2
  6. package/dist/commands/compress.js +0 -27
  7. package/dist/commands/hooks.d.ts +0 -19
  8. package/dist/commands/hooks.js +0 -131
  9. package/dist/commands/install.d.ts +0 -2
  10. package/dist/commands/install.js +0 -649
  11. package/dist/commands/load-context.d.ts +0 -2
  12. package/dist/commands/load-context.js +0 -108
  13. package/dist/commands/logs.d.ts +0 -2
  14. package/dist/commands/logs.js +0 -76
  15. package/dist/commands/migrate-to-jsonl.d.ts +0 -5
  16. package/dist/commands/migrate-to-jsonl.js +0 -99
  17. package/dist/commands/status.d.ts +0 -1
  18. package/dist/commands/status.js +0 -136
  19. package/dist/commands/uninstall.d.ts +0 -2
  20. package/dist/commands/uninstall.js +0 -107
  21. package/dist/constants.d.ts +0 -271
  22. package/dist/constants.js +0 -199
  23. package/dist/core/compression/TranscriptCompressor.d.ts +0 -83
  24. package/dist/core/compression/TranscriptCompressor.js +0 -602
  25. package/dist/core/orchestration/PromptOrchestrator.d.ts +0 -165
  26. package/dist/core/orchestration/PromptOrchestrator.js +0 -182
  27. package/dist/lib/time-utils.d.ts +0 -5
  28. package/dist/lib/time-utils.js +0 -70
  29. package/dist/prompts/constants.d.ts +0 -126
  30. package/dist/prompts/constants.js +0 -161
  31. package/dist/prompts/index.d.ts +0 -10
  32. package/dist/prompts/index.js +0 -11
  33. package/dist/prompts/templates/analysis/AnalysisTemplates.d.ts +0 -13
  34. package/dist/prompts/templates/analysis/AnalysisTemplates.js +0 -94
  35. package/dist/prompts/templates/context/ContextTemplates.d.ts +0 -119
  36. package/dist/prompts/templates/context/ContextTemplates.js +0 -399
  37. package/dist/prompts/templates/hooks/HookTemplates.d.ts +0 -175
  38. package/dist/prompts/templates/hooks/HookTemplates.js +0 -394
  39. package/dist/prompts/templates/hooks/HookTemplates.test.d.ts +0 -7
  40. package/dist/prompts/templates/hooks/HookTemplates.test.js +0 -127
  41. package/dist/shared/config.d.ts +0 -4
  42. package/dist/shared/config.js +0 -41
  43. package/dist/shared/error-handler.d.ts +0 -22
  44. package/dist/shared/error-handler.js +0 -142
  45. package/dist/shared/logger.d.ts +0 -19
  46. package/dist/shared/logger.js +0 -51
  47. package/dist/shared/paths.d.ts +0 -28
  48. package/dist/shared/paths.js +0 -100
  49. package/dist/shared/types.d.ts +0 -141
  50. package/dist/shared/types.js +0 -78
@@ -1,649 +0,0 @@
1
- import { readFileSync, writeFileSync, existsSync, chmodSync, mkdirSync, copyFileSync, statSync, readdirSync } from 'fs';
2
- import { join, dirname } from 'path';
3
- import { homedir } from 'os';
4
- import { execSync } from 'child_process';
5
- import * as p from '@clack/prompts';
6
- import { PACKAGE_NAME } from '../shared/config.js';
7
- // <Block> Prerequisites validation
8
- async function validatePrerequisites() {
9
- const s = p.spinner();
10
- s.start('Checking prerequisites');
11
- const issues = [];
12
- // Check Node.js version
13
- const nodeVersion = process.versions.node;
14
- const [major] = nodeVersion.split('.').map(Number);
15
- if (major < 18) {
16
- issues.push(`Node.js version ${nodeVersion} is below minimum required (18.0.0)`);
17
- }
18
- // Check if Claude Code is installed
19
- try {
20
- execSync('which claude', { stdio: 'ignore' });
21
- }
22
- catch {
23
- issues.push('Claude Code CLI is not installed or not in PATH');
24
- }
25
- // Check write permissions to home directory
26
- const testDir = join(homedir(), '.claude-mem-test');
27
- try {
28
- mkdirSync(testDir, { recursive: true });
29
- writeFileSync(join(testDir, 'test'), 'test');
30
- execSync(`rm -rf ${testDir}`, { stdio: 'ignore' });
31
- }
32
- catch {
33
- issues.push('No write permissions to home directory');
34
- }
35
- if (issues.length > 0) {
36
- s.stop('Prerequisites check failed');
37
- return false;
38
- }
39
- s.stop('Prerequisites check passed');
40
- return true;
41
- }
42
- // </Block>
43
- // <Block> Installation status detection
44
- function detectExistingInstallation() {
45
- const result = {
46
- hasHooks: false,
47
- hasChromaMcp: false,
48
- hasSettings: false,
49
- scope: undefined
50
- };
51
- // Check for hooks
52
- const hooksDir = join(homedir(), '.claude-mem', 'hooks');
53
- result.hasHooks = existsSync(hooksDir) &&
54
- existsSync(join(hooksDir, 'pre-compact.js')) &&
55
- existsSync(join(hooksDir, 'session-start.js'));
56
- // Check for Chroma MCP server configuration
57
- const userMcpPath = join(homedir(), '.claude.json');
58
- const projectMcpPath = join(process.cwd(), '.mcp.json');
59
- if (existsSync(userMcpPath)) {
60
- try {
61
- const config = JSON.parse(readFileSync(userMcpPath, 'utf8'));
62
- if (config.mcpServers?.['claude-mem']) {
63
- result.hasChromaMcp = true;
64
- result.scope = 'user';
65
- }
66
- }
67
- catch { }
68
- }
69
- if (existsSync(projectMcpPath)) {
70
- try {
71
- const config = JSON.parse(readFileSync(projectMcpPath, 'utf8'));
72
- if (config.mcpServers?.['claude-mem']) {
73
- result.hasChromaMcp = true;
74
- result.scope = 'project';
75
- }
76
- }
77
- catch { }
78
- }
79
- // Check for settings
80
- const userSettingsPath = join(homedir(), '.claude-mem', 'settings.json');
81
- result.hasSettings = existsSync(userSettingsPath);
82
- return result;
83
- }
84
- // </Block>
85
- // <Block> Interactive installation wizard
86
- async function runInstallationWizard(existingInstall) {
87
- const config = {};
88
- // If existing installation found, ask about reinstallation
89
- if (existingInstall.hasHooks || existingInstall.hasChromaMcp) {
90
- const action = await p.select({
91
- message: 'Existing installation detected. What would you like to do?',
92
- options: [
93
- { value: 'update', label: 'Update existing installation' },
94
- { value: 'reinstall', label: 'Clean reinstall (removes existing configuration)' },
95
- { value: 'cancel', label: 'Cancel installation' }
96
- ]
97
- });
98
- if (p.isCancel(action) || action === 'cancel') {
99
- p.cancel('Installation cancelled');
100
- return null;
101
- }
102
- config.forceReinstall = action === 'reinstall';
103
- }
104
- else {
105
- config.forceReinstall = false;
106
- }
107
- // Select installation scope
108
- const scope = await p.select({
109
- message: 'Select installation scope',
110
- options: [
111
- {
112
- value: 'user',
113
- label: 'User (Recommended)',
114
- hint: 'Install for current user (~/.claude)'
115
- },
116
- {
117
- value: 'project',
118
- label: 'Project',
119
- hint: 'Install for current project only (./.mcp.json)'
120
- },
121
- {
122
- value: 'local',
123
- label: 'Local',
124
- hint: 'Custom local installation'
125
- }
126
- ],
127
- initialValue: existingInstall.scope || 'user'
128
- });
129
- if (p.isCancel(scope)) {
130
- p.cancel('Installation cancelled');
131
- return null;
132
- }
133
- config.scope = scope;
134
- // If local scope, ask for custom path
135
- if (scope === 'local') {
136
- const customPath = await p.text({
137
- message: 'Enter custom installation directory',
138
- placeholder: join(process.cwd(), '.claude-mem'),
139
- validate: (value) => {
140
- if (!value)
141
- return 'Path is required';
142
- if (!value.startsWith('/') && !value.startsWith('~')) {
143
- return 'Please provide an absolute path';
144
- }
145
- }
146
- });
147
- if (p.isCancel(customPath)) {
148
- p.cancel('Installation cancelled');
149
- return null;
150
- }
151
- config.customPath = customPath;
152
- }
153
- // Use default hook timeout (3 minutes)
154
- config.hookTimeout = 180000;
155
- // Ask about Chroma MCP installation
156
- if (!existingInstall.hasChromaMcp) {
157
- const installChroma = await p.confirm({
158
- message: 'Install Chroma MCP server for vector storage?',
159
- initialValue: true
160
- });
161
- if (p.isCancel(installChroma)) {
162
- p.cancel('Installation cancelled');
163
- return null;
164
- }
165
- config.skipMcpInstall = !installChroma;
166
- }
167
- else {
168
- config.skipMcpInstall = true; // Already installed
169
- }
170
- return config;
171
- }
172
- // </Block>
173
- // <Block> Backup existing configuration
174
- async function backupExistingConfig() {
175
- const backupDir = join(homedir(), '.claude-mem', 'backups', new Date().toISOString().replace(/[:.]/g, '-'));
176
- try {
177
- mkdirSync(backupDir, { recursive: true });
178
- // Backup hooks if they exist
179
- const hooksDir = join(homedir(), '.claude-mem', 'hooks');
180
- if (existsSync(hooksDir)) {
181
- copyFileRecursively(hooksDir, join(backupDir, 'hooks'));
182
- }
183
- // Backup settings
184
- const settingsPath = join(homedir(), '.claude-mem', 'settings.json');
185
- if (existsSync(settingsPath)) {
186
- copyFileSync(settingsPath, join(backupDir, 'settings.json'));
187
- }
188
- // Backup Claude settings
189
- const claudeSettingsPath = join(homedir(), '.claude', 'settings.json');
190
- if (existsSync(claudeSettingsPath)) {
191
- copyFileSync(claudeSettingsPath, join(backupDir, 'claude-settings.json'));
192
- }
193
- return backupDir;
194
- }
195
- catch (error) {
196
- return null;
197
- }
198
- }
199
- // </Block>
200
- // <Block> Directory structure creation - natural setup flow
201
- function ensureDirectoryStructure() {
202
- const claudeMemDir = join(homedir(), '.claude-mem');
203
- const hooksDir = join(claudeMemDir, 'hooks');
204
- const indexDir = join(claudeMemDir, 'index');
205
- const archivesDir = join(claudeMemDir, 'archives');
206
- const logsDir = join(claudeMemDir, 'logs');
207
- const backupsDir = join(claudeMemDir, 'backups');
208
- [claudeMemDir, hooksDir, indexDir, archivesDir, logsDir, backupsDir].forEach(dir => {
209
- if (!existsSync(dir)) {
210
- mkdirSync(dir, { recursive: true });
211
- }
212
- });
213
- }
214
- // </Block>
215
- function copyFileRecursively(src, dest) {
216
- const stat = statSync(src);
217
- if (stat.isDirectory()) {
218
- if (!existsSync(dest)) {
219
- mkdirSync(dest, { recursive: true });
220
- }
221
- const files = readdirSync(src);
222
- files.forEach((file) => {
223
- copyFileRecursively(join(src, file), join(dest, file));
224
- });
225
- }
226
- else {
227
- copyFileSync(src, dest);
228
- }
229
- }
230
- function writeHookFiles(timeout = 180000) {
231
- const hooksDir = join(homedir(), '.claude-mem', 'hooks');
232
- // For binary distribution, write minimal wrapper hooks that call the binary
233
- const hookWrapper = (command) => `#!/usr/bin/env node
234
- // Hook wrapper for claude-mem binary distribution
235
- const { execSync } = require('child_process');
236
- const path = require('path');
237
-
238
- // Try to find the claude-mem binary
239
- const possiblePaths = [
240
- 'claude-mem', // In PATH
241
- path.join(__dirname, '..', '..', 'claude-mem'), // Relative to hooks dir
242
- process.env.CLAUDE_MEM_BINARY // Environment variable override
243
- ].filter(Boolean);
244
-
245
- let binaryPath;
246
- for (const testPath of possiblePaths) {
247
- try {
248
- execSync(\`which \${testPath}\`, { stdio: 'ignore' });
249
- binaryPath = testPath;
250
- break;
251
- } catch {
252
- // Try next path
253
- }
254
- }
255
-
256
- if (!binaryPath) {
257
- console.error('Could not find claude-mem binary');
258
- process.exit(1);
259
- }
260
-
261
- try {
262
- execSync(\`\${binaryPath} ${command}\`, { stdio: 'inherit' });
263
- process.exit(0);
264
- } catch (error) {
265
- process.exit(error.status || 1);
266
- }
267
- `;
268
- // Write hook wrappers
269
- const hooks = [
270
- { name: 'pre-compact.js', command: 'hook:pre-compact' },
271
- { name: 'session-start.js', command: 'hook:session-start' },
272
- { name: 'session-end.js', command: 'hook:session-end' }
273
- ];
274
- for (const hook of hooks) {
275
- const hookPath = join(hooksDir, hook.name);
276
- writeFileSync(hookPath, hookWrapper(hook.command));
277
- chmodSync(hookPath, 0o755);
278
- }
279
- // Write configuration with custom timeout
280
- const hookConfigPath = join(hooksDir, 'config.json');
281
- const hookConfig = {
282
- packageName: PACKAGE_NAME,
283
- cliCommand: PACKAGE_NAME,
284
- backend: 'chroma',
285
- timeout
286
- };
287
- writeFileSync(hookConfigPath, JSON.stringify(hookConfig, null, 2));
288
- }
289
- function ensureClaudeMdInstructions() {
290
- const claudeMdPath = join(homedir(), '.claude', 'CLAUDE.md');
291
- const claudeMdDir = dirname(claudeMdPath);
292
- // Ensure .claude directory exists
293
- if (!existsSync(claudeMdDir)) {
294
- mkdirSync(claudeMdDir, { recursive: true });
295
- }
296
- const instructions = `
297
- <!-- CLAUDE-MEM INSTRUCTIONS -->
298
- - You have access to a persistent memory system via the Chroma MCP server (installed as "claude-mem")
299
- - The memory system automatically compresses and stores context from your sessions
300
- - Available MCP tools:
301
- - \`mcp__claude-mem__chroma_add_documents\`: Store new knowledge as documents in the "claude_memories" collection
302
- - \`mcp__claude-mem__chroma_query_documents\`: Search for relevant memories using semantic search in the "claude_memories" collection
303
- - \`mcp__claude-mem__chroma_get_documents\`: Retrieve specific documents by IDs from the "claude_memories" collection
304
- - **Document Structure:**
305
- - Documents are stored as natural language descriptions of knowledge
306
- - Each document has metadata including: timestamp, session_id, keywords, entity_type
307
- - Use descriptive content that captures the essence of what was learned or accomplished
308
- - **Search Tips:**
309
- - Use semantic queries: \`chroma_query_documents\` with natural language queries
310
- - Search by metadata: Use \`where\` parameter to filter by entity_type, timestamp, etc.
311
- - Use keywords in metadata for precise filtering
312
- - **Storage Format:**
313
- - Store knowledge as readable documents rather than structured entities
314
- - Include context, rationale, and outcomes in document content
315
- - Use metadata to categorize and filter memories
316
- - **Smart Retrieval Commands:**
317
- - **Find similar concepts**: \`chroma_query_documents(["your search terms"])\`
318
- - Example: \`chroma_query_documents(["websocket", "connection"])\` - finds all websocket-related memories
319
- - **Load specific memory**: \`chroma_get_documents(["document_id"])\`
320
- - Example: \`chroma_get_documents(["project_session_1"])\` - loads exact memory by ID
321
- - **Search by metadata**: Use keywords from memories to find related items
322
- - The system uses semantic search, so "auth" will find "authentication", "login", etc.
323
- - **Find connected memories**: Look for memories with related_to fields linking them together
324
- - Collection name: "claude_memories"
325
- - Compressed session archives are stored in ~/.claude-mem/archives/
326
- - **Optimal Search Strategies:**
327
- - **Most Effective Patterns:**
328
- - Session continuity: \`where: {session_id: "xxx"}\` - precise retrieval of all session work
329
- - Find specific fixes: \`where: {type: "fix"}\` - filters to only bug fixes
330
- - Natural language queries: "fixing overview display in templates" beats "fix AND overview AND template"
331
- - Include file/function names: "extractOverview ContextTemplates" for precise code location
332
- - **Search by Intent:**
333
- - Debug: Use exact error messages or symptom descriptions
334
- - Find code: Include function names + file names when known
335
- - Architecture: Search "migration from X to Y" or "refactored X"
336
- - Agent work: Search agent names directly (e.g., "steve-krug-ux")
337
- - **What Doesn't Work:**
338
- - Boolean operators (AND/OR) - treated as literal text
339
- - Timestamp filtering with strings - needs numeric values
340
- - Generic tech terms alone - too broad, add context
341
- - Complex where clauses - only basic operators supported ($eq, $ne, $in)
342
- - **Best Practice:** Semantic search for discovery, metadata filtering for precision. Combine both when possible.
343
- <!-- /CLAUDE-MEM INSTRUCTIONS -->`;
344
- // Check if file exists and read content
345
- let content = '';
346
- if (existsSync(claudeMdPath)) {
347
- content = readFileSync(claudeMdPath, 'utf8');
348
- // Check if instructions already exist
349
- if (content.includes('<!-- CLAUDE-MEM INSTRUCTIONS -->')) {
350
- // Replace existing instructions
351
- const startMarker = '<!-- CLAUDE-MEM INSTRUCTIONS -->';
352
- const endMarker = '<!-- /CLAUDE-MEM INSTRUCTIONS -->';
353
- const startIndex = content.indexOf(startMarker);
354
- const endIndex = content.indexOf(endMarker) + endMarker.length;
355
- if (startIndex !== -1 && endIndex !== -1) {
356
- content = content.substring(0, startIndex) + instructions.trim() + content.substring(endIndex);
357
- }
358
- }
359
- else {
360
- // Append instructions to the end
361
- content = content.trim() + '\n' + instructions;
362
- }
363
- }
364
- else {
365
- // Create new file with instructions
366
- content = instructions.trim();
367
- }
368
- // Write the updated content
369
- writeFileSync(claudeMdPath, content);
370
- }
371
- async function installChromaMcp() {
372
- const chromaMcpCommand = `claude mcp add claude-mem -- uvx chroma-mcp --client-type persistent --data-dir ${homedir()}/.claude-mem/chroma`;
373
- const s = p.spinner();
374
- s.start('Installing Chroma MCP server');
375
- try {
376
- execSync(chromaMcpCommand, { stdio: 'pipe' });
377
- s.stop('Chroma MCP server installed successfully');
378
- return true;
379
- }
380
- catch (error) {
381
- s.stop('Chroma MCP server installation failed');
382
- p.log.warn('You may need to install it manually:');
383
- p.log.info(chromaMcpCommand);
384
- return false;
385
- }
386
- }
387
- async function configureHooks(settingsPath, config) {
388
- const claudeMemHooksDir = join(homedir(), '.claude-mem', 'hooks');
389
- const preCompactScript = join(claudeMemHooksDir, 'pre-compact.js');
390
- const sessionStartScript = join(claudeMemHooksDir, 'session-start.js');
391
- const sessionEndScript = join(claudeMemHooksDir, 'session-end.js');
392
- let settings = {};
393
- if (existsSync(settingsPath)) {
394
- const content = readFileSync(settingsPath, 'utf8');
395
- settings = JSON.parse(content);
396
- }
397
- // Ensure settings directory exists
398
- const settingsDir = dirname(settingsPath);
399
- if (!existsSync(settingsDir)) {
400
- mkdirSync(settingsDir, { recursive: true });
401
- }
402
- // Initialize hooks structure if it doesn't exist
403
- if (!settings.hooks) {
404
- settings.hooks = {};
405
- }
406
- // Remove existing claude-mem hooks to ensure clean installation/update
407
- // Non-tool hooks: filter out configs where hooks contain our commands
408
- if (settings.hooks.PreCompact) {
409
- settings.hooks.PreCompact = settings.hooks.PreCompact.filter((cfg) => !cfg.hooks?.some((hook) => hook.command?.includes(PACKAGE_NAME) || hook.command?.includes('pre-compact.js')));
410
- if (!settings.hooks.PreCompact.length)
411
- delete settings.hooks.PreCompact;
412
- }
413
- if (settings.hooks.SessionStart) {
414
- settings.hooks.SessionStart = settings.hooks.SessionStart.filter((cfg) => !cfg.hooks?.some((hook) => hook.command?.includes(PACKAGE_NAME) || hook.command?.includes('session-start.js')));
415
- if (!settings.hooks.SessionStart.length)
416
- delete settings.hooks.SessionStart;
417
- }
418
- if (settings.hooks.SessionEnd) {
419
- settings.hooks.SessionEnd = settings.hooks.SessionEnd.filter((cfg) => !cfg.hooks?.some((hook) => hook.command?.includes(PACKAGE_NAME) || hook.command?.includes('session-end.js')));
420
- if (!settings.hooks.SessionEnd.length)
421
- delete settings.hooks.SessionEnd;
422
- }
423
- /**
424
- * 🔒 LOCKED by @docs-agent | Change to 🔑 to allow @docs-agent edits
425
- *
426
- * OFFICIAL DOCS: Claude Code Hooks Configuration v2025
427
- * Last Verified: 2025-08-31
428
- *
429
- * Hook Configuration Structure Requirements:
430
- * - Tool-related hooks (PreToolUse, PostToolUse): Use 'matcher' field for tool patterns
431
- * - Non-tool hooks (PreCompact, SessionStart, SessionEnd, etc.): NO matcher/pattern field
432
- *
433
- * Correct Non-Tool Hook Structure:
434
- * {
435
- * hooks: [{
436
- * type: "command",
437
- * command: "/path/to/script.js"
438
- * }]
439
- * }
440
- *
441
- * @see https://docs.anthropic.com/en/docs/claude-code/hooks
442
- * @see docs/claude-code/hook-configuration.md for full documentation
443
- */
444
- // Add PreCompact hook - Non-tool hook (no matcher field)
445
- if (!settings.hooks.PreCompact) {
446
- settings.hooks.PreCompact = [];
447
- }
448
- // ✅ CORRECT: Non-tool hooks have no 'pattern' or 'matcher' field
449
- settings.hooks.PreCompact.push({
450
- hooks: [
451
- {
452
- type: "command",
453
- command: preCompactScript,
454
- timeout: config.hookTimeout
455
- }
456
- ]
457
- });
458
- // Add SessionStart hook - Non-tool hook (no matcher field)
459
- if (!settings.hooks.SessionStart) {
460
- settings.hooks.SessionStart = [];
461
- }
462
- // ✅ CORRECT: Non-tool hooks have no 'pattern' or 'matcher' field
463
- settings.hooks.SessionStart.push({
464
- hooks: [
465
- {
466
- type: "command",
467
- command: sessionStartScript
468
- }
469
- ]
470
- });
471
- // Add SessionEnd hook (only if the file exists)
472
- if (existsSync(sessionEndScript)) {
473
- if (!settings.hooks.SessionEnd) {
474
- settings.hooks.SessionEnd = [];
475
- }
476
- // ✅ CORRECT: Non-tool hooks have no 'pattern' or 'matcher' field
477
- settings.hooks.SessionEnd.push({
478
- hooks: [{
479
- type: "command",
480
- command: sessionEndScript,
481
- timeout: config.hookTimeout
482
- }]
483
- });
484
- }
485
- // Write updated settings
486
- writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
487
- }
488
- async function verifyInstallation() {
489
- const s = p.spinner();
490
- s.start('Verifying installation');
491
- const issues = [];
492
- // Check hooks
493
- const hooksDir = join(homedir(), '.claude-mem', 'hooks');
494
- if (!existsSync(join(hooksDir, 'pre-compact.js'))) {
495
- issues.push('Pre-compact hook not found');
496
- }
497
- if (!existsSync(join(hooksDir, 'session-start.js'))) {
498
- issues.push('Session-start hook not found');
499
- }
500
- // Check Chroma MCP configuration
501
- const userMcpPath = join(homedir(), '.claude.json');
502
- const projectMcpPath = join(process.cwd(), '.mcp.json');
503
- let chromaMcpConfigured = false;
504
- if (existsSync(userMcpPath)) {
505
- try {
506
- const config = JSON.parse(readFileSync(userMcpPath, 'utf8'));
507
- if (config.mcpServers?.['claude-mem']) {
508
- chromaMcpConfigured = true;
509
- }
510
- }
511
- catch { }
512
- }
513
- if (!chromaMcpConfigured && existsSync(projectMcpPath)) {
514
- try {
515
- const config = JSON.parse(readFileSync(projectMcpPath, 'utf8'));
516
- if (config.mcpServers?.['claude-mem']) {
517
- chromaMcpConfigured = true;
518
- }
519
- }
520
- catch { }
521
- }
522
- if (!chromaMcpConfigured) {
523
- issues.push('Chroma MCP server not configured');
524
- }
525
- if (issues.length > 0) {
526
- s.stop('Installation verification completed with issues');
527
- p.log.warn('The following issues were detected:');
528
- issues.forEach(issue => p.log.error(` - ${issue}`));
529
- p.log.info('The installation may not work correctly. Consider reinstalling with --force flag.');
530
- }
531
- else {
532
- s.stop('Installation verified successfully');
533
- }
534
- }
535
- export async function install(options = {}) {
536
- p.intro(`🧠 Claude Memory Installation`);
537
- // Check if running with flags (non-interactive mode)
538
- const isNonInteractive = options.user || options.project || options.local || options.force;
539
- let config;
540
- if (isNonInteractive) {
541
- // Non-interactive mode - use flags
542
- config = {
543
- scope: options.local ? 'local' : options.project ? 'project' : 'user',
544
- customPath: options.path,
545
- hookTimeout: options.timeout || 180000,
546
- forceReinstall: !!options.force,
547
- skipMcpInstall: !!options.skipMcp
548
- };
549
- }
550
- else {
551
- // Interactive mode
552
- // Validate prerequisites
553
- const prereqValid = await validatePrerequisites();
554
- if (!prereqValid) {
555
- p.outro('Please fix the prerequisites issues and try again');
556
- process.exit(1);
557
- }
558
- // Detect existing installation
559
- const existingInstall = detectExistingInstallation();
560
- // Run installation wizard
561
- const wizardConfig = await runInstallationWizard(existingInstall);
562
- if (!wizardConfig) {
563
- process.exit(0);
564
- }
565
- config = wizardConfig;
566
- }
567
- // Backup existing configuration if force reinstall
568
- if (config.forceReinstall) {
569
- const backupPath = await backupExistingConfig();
570
- if (backupPath) {
571
- p.log.info(`Backup created at: ${backupPath}`);
572
- }
573
- }
574
- // Installation steps
575
- await p.group({
576
- directories: async () => {
577
- const s = p.spinner();
578
- s.start('Creating directory structure');
579
- ensureDirectoryStructure();
580
- s.stop('Directory structure created');
581
- },
582
- chromaMcp: async () => {
583
- if (!config.skipMcpInstall) {
584
- await installChromaMcp();
585
- }
586
- },
587
- instructions: async () => {
588
- const s = p.spinner();
589
- s.start('Adding CLAUDE.md instructions');
590
- ensureClaudeMdInstructions();
591
- s.stop('CLAUDE.md instructions added');
592
- },
593
- hooks: async () => {
594
- const s = p.spinner();
595
- s.start('Installing hooks');
596
- writeHookFiles(config.hookTimeout);
597
- s.stop('Hooks installed');
598
- },
599
- settings: async () => {
600
- const s = p.spinner();
601
- s.start('Configuring Claude settings');
602
- // Determine settings path
603
- let settingsPath;
604
- if (config.scope === 'local' && config.customPath) {
605
- settingsPath = join(config.customPath, 'settings.local.json');
606
- }
607
- else if (config.scope === 'project') {
608
- settingsPath = join(process.cwd(), '.claude', 'settings.json');
609
- }
610
- else {
611
- settingsPath = join(homedir(), '.claude', 'settings.json');
612
- }
613
- await configureHooks(settingsPath, config);
614
- // Store backend setting in user settings
615
- const userSettingsDir = join(homedir(), '.claude-mem');
616
- const userSettingsPath = join(userSettingsDir, 'settings.json');
617
- let userSettings = {};
618
- if (existsSync(userSettingsPath)) {
619
- try {
620
- userSettings = JSON.parse(readFileSync(userSettingsPath, 'utf8'));
621
- }
622
- catch { }
623
- }
624
- userSettings.backend = 'chroma';
625
- userSettings.installed = true;
626
- userSettings.embedded = true;
627
- writeFileSync(userSettingsPath, JSON.stringify(userSettings, null, 2));
628
- s.stop('Settings configured');
629
- }
630
- }, {
631
- onCancel: () => {
632
- p.cancel('Installation cancelled');
633
- process.exit(0);
634
- }
635
- });
636
- // Verify installation
637
- await verifyInstallation();
638
- p.outro(`✅ Claude Memory installed successfully!
639
-
640
- How it works:
641
- • When you start Claude Code, claude-mem will load the latest memories as a startup message
642
- • To save your work, do /compact or /clear, wait for it to process (takes about 30s)
643
- • You'll see an updated context message with your latest memories
644
- • We added instructions to your ~/.claude/CLAUDE.md that teaches Claude Code how to use its new memory system
645
-
646
- To search memories, just ask Claude to search claude-mem. That's it.
647
-
648
- Restart Claude Code to begin using your new memory system.`);
649
- }
@@ -1,2 +0,0 @@
1
- import { OptionValues } from 'commander';
2
- export declare function loadContext(options?: OptionValues): Promise<void>;