claude-self-reflect 2.2.1 → 2.3.2

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.
@@ -11,19 +11,96 @@ const __filename = fileURLToPath(import.meta.url);
11
11
  const __dirname = dirname(__filename);
12
12
  const projectRoot = join(__dirname, '..');
13
13
 
14
- const rl = readline.createInterface({
14
+ // Parse command line arguments
15
+ const args = process.argv.slice(2);
16
+ let voyageKey = null;
17
+ let localMode = false;
18
+ let mcpConfigured = false;
19
+
20
+ for (const arg of args) {
21
+ if (arg.startsWith('--voyage-key=')) {
22
+ voyageKey = arg.split('=')[1];
23
+ } else if (arg === '--local') {
24
+ localMode = true;
25
+ }
26
+ }
27
+
28
+ const isInteractive = process.stdin.isTTY && process.stdout.isTTY;
29
+
30
+ const rl = isInteractive ? readline.createInterface({
15
31
  input: process.stdin,
16
32
  output: process.stdout
17
- });
33
+ }) : null;
18
34
 
19
- const question = (query) => new Promise((resolve) => rl.question(query, resolve));
35
+ const question = (query) => {
36
+ if (!isInteractive) {
37
+ console.log(`Non-interactive mode detected. ${query} [Defaulting to 'n']`);
38
+ return Promise.resolve('n');
39
+ }
40
+ return new Promise((resolve) => rl.question(query, resolve));
41
+ };
20
42
 
21
43
  async function checkPython() {
22
44
  console.log('\nšŸ“¦ Checking Python installation...');
23
45
  try {
24
46
  const version = execSync('python3 --version').toString().trim();
25
47
  console.log(`āœ… Found ${version}`);
26
- return true;
48
+
49
+ // Check if SSL module works
50
+ try {
51
+ execSync('python3 -c "import ssl"', { stdio: 'pipe' });
52
+ return true;
53
+ } catch (sslError) {
54
+ console.log('āš ļø Python SSL module not working');
55
+
56
+ // Check if we're using pyenv
57
+ const whichPython = execSync('which python3').toString().trim();
58
+ if (whichPython.includes('pyenv')) {
59
+ console.log('šŸ” Detected pyenv Python with broken SSL');
60
+
61
+ // Check if brew Python is available
62
+ try {
63
+ const brewPrefix = execSync('brew --prefix python@3.11 2>/dev/null || brew --prefix python@3.10 2>/dev/null || brew --prefix python@3.12 2>/dev/null', { shell: true }).toString().trim();
64
+ if (brewPrefix) {
65
+ // Find the actual python executable
66
+ let pythonPath = null;
67
+ for (const exe of ['python3.11', 'python3.10', 'python3.12', 'python3']) {
68
+ try {
69
+ const fullPath = `${brewPrefix}/bin/${exe}`;
70
+ execSync(`test -f ${fullPath}`);
71
+ pythonPath = fullPath;
72
+ break;
73
+ } catch {}
74
+ }
75
+
76
+ if (pythonPath) {
77
+ console.log(`āœ… Found brew Python at ${pythonPath}`);
78
+ // Test if SSL works with brew Python
79
+ try {
80
+ execSync(`${pythonPath} -c "import ssl"`, { stdio: 'pipe' });
81
+ process.env.PYTHON_PATH = pythonPath;
82
+ return true;
83
+ } catch {
84
+ console.log('āš ļø Brew Python also has SSL issues');
85
+ }
86
+ }
87
+ }
88
+ } catch {}
89
+
90
+ console.log('\nšŸ”§ Attempting to install Python with brew...');
91
+ try {
92
+ execSync('brew install python@3.11', { stdio: 'inherit' });
93
+ const brewPython = execSync('brew --prefix python@3.11').toString().trim();
94
+ process.env.PYTHON_PATH = `${brewPython}/bin/python3`;
95
+ console.log('āœ… Installed Python 3.11 with brew');
96
+ return true;
97
+ } catch {
98
+ console.log('āŒ Failed to install Python with brew');
99
+ }
100
+ }
101
+
102
+ return false;
103
+ }
27
104
  } catch {
28
105
  console.log('āŒ Python 3.10+ not found');
29
106
  console.log(' Please install Python from https://python.org');
@@ -31,27 +108,94 @@ async function checkPython() {
31
108
  }
32
109
  }
33
110
 
111
+ async function checkDocker() {
112
+ try {
113
+ execSync('docker info', { stdio: 'ignore' });
114
+ return true;
115
+ } catch {
116
+ return false;
117
+ }
118
+ }
119
+
34
120
  async function checkQdrant() {
35
121
  console.log('\n🐳 Checking Qdrant...');
36
122
  try {
37
- const response = await fetch('http://localhost:6333/health');
38
- if (response.ok) {
123
+ const response = await fetch('http://localhost:6333');
124
+ const data = await response.json();
125
+ if (data.title && data.title.includes('qdrant')) {
39
126
  console.log('āœ… Qdrant is already running');
40
127
  return true;
41
128
  }
42
129
  } catch {}
43
130
 
44
131
  console.log('āŒ Qdrant not found');
45
- const start = await question('Would you like to start Qdrant with Docker? (y/n): ');
132
+
133
+ // Check if Docker is available and running
134
+ const dockerAvailable = await checkDocker();
135
+ if (!dockerAvailable) {
136
+ console.log('āŒ Docker is not running or not installed');
137
+ console.log(' Please install Docker from https://docker.com and ensure the Docker daemon is running');
138
+ console.log(' Then run this setup again');
139
+ return false;
140
+ }
141
+
142
+ // In non-interactive mode, skip standalone Qdrant - docker-compose will handle it
143
+ let start = 'n';
144
+ if (isInteractive) {
145
+ start = await question('Would you like to start Qdrant with Docker? (y/n): ');
146
+ } else {
147
+ console.log('šŸ¤– Non-interactive mode detected. Qdrant will be started with Docker Compose later...');
148
+ return 'pending'; // Special value to indicate we'll handle it later
149
+ }
46
150
 
47
151
  if (start.toLowerCase() === 'y') {
48
152
  try {
153
+ // Check if a container named 'qdrant' already exists
154
+ try {
155
+ execSync('docker container inspect qdrant', { stdio: 'ignore' });
156
+ console.log('Removing existing Qdrant container...');
157
+ execSync('docker rm -f qdrant', { stdio: 'ignore' });
158
+ } catch {
159
+ // Container doesn't exist, which is fine
160
+ }
161
+
49
162
  console.log('Starting Qdrant...');
50
- execSync('docker run -d --name qdrant -p 6333:6333 qdrant/qdrant:latest', { stdio: 'inherit' });
51
- console.log('āœ… Qdrant started successfully');
52
- return true;
163
+ execSync('docker run -d --name qdrant -p 6333:6333 -v qdrant_storage:/qdrant/storage qdrant/qdrant:latest', { stdio: 'inherit' });
164
+
165
+ // Wait for Qdrant to be ready
166
+ console.log('Waiting for Qdrant to start...');
167
+ await new Promise(resolve => setTimeout(resolve, 3000)); // Initial wait for container to start
168
+
169
+ let retries = 60; // Increase to 60 seconds
170
+ while (retries > 0) {
171
+ try {
172
+ const response = await fetch('http://localhost:6333');
173
+ const data = await response.json();
174
+ if (data.title && data.title.includes('qdrant')) {
175
+ console.log('āœ… Qdrant started successfully');
176
+ return true;
177
+ }
178
+ } catch (e) {
179
+ // Show progress every 10 attempts
180
+ if (retries % 10 === 0) {
181
+ console.log(` Still waiting... (${retries} seconds left)`);
182
+ // Check if container is still running
183
+ try {
184
+ execSync('docker ps | grep qdrant', { stdio: 'pipe' });
185
+ } catch {
186
+ console.log('āŒ Qdrant container stopped unexpectedly');
187
+ return false;
188
+ }
189
+ }
190
+ }
191
+ await new Promise(resolve => setTimeout(resolve, 1000));
192
+ retries--;
193
+ }
194
+
195
+ console.log('āŒ Qdrant failed to start properly');
196
+ return false;
53
197
  } catch (error) {
54
- console.log('āŒ Failed to start Qdrant. Please install Docker first.');
198
+ console.log('āŒ Failed to start Qdrant:', error.message);
55
199
  return false;
56
200
  }
57
201
  }
@@ -63,22 +207,142 @@ async function setupPythonEnvironment() {
63
207
  console.log('\nšŸ Setting up Python MCP server...');
64
208
 
65
209
  const mcpPath = join(projectRoot, 'mcp-server');
210
+ const scriptsPath = join(projectRoot, 'scripts');
66
211
 
67
212
  try {
68
- // Create virtual environment
69
- console.log('Creating virtual environment...');
70
- execSync(`cd "${mcpPath}" && python3 -m venv venv`, { stdio: 'inherit' });
213
+ // Check if venv already exists
214
+ const venvPath = join(mcpPath, 'venv');
215
+ let venvExists = false;
216
+ try {
217
+ await fs.access(venvPath);
218
+ venvExists = true;
219
+ console.log('āœ… Virtual environment already exists');
220
+ } catch {
221
+ // venv doesn't exist, create it
222
+ }
71
223
 
72
- // Install dependencies
73
- console.log('Installing dependencies...');
224
+ if (!venvExists) {
225
+ // Create virtual environment
226
+ console.log('Creating virtual environment...');
227
+ const pythonCmd = process.env.PYTHON_PATH || 'python3';
228
+ try {
229
+ execSync(`cd "${mcpPath}" && ${pythonCmd} -m venv venv`, { stdio: 'inherit' });
230
+ } catch (venvError) {
231
+ console.log('āš ļø Failed to create venv with python3, trying python...');
232
+ try {
233
+ execSync(`cd "${mcpPath}" && python -m venv venv`, { stdio: 'inherit' });
234
+ } catch {
235
+ console.log('āŒ Failed to create virtual environment');
236
+ console.log('šŸ“š Fix: Install python3-venv package');
237
+ console.log(' Ubuntu/Debian: sudo apt install python3-venv');
238
+ console.log(' macOS: Should be included with Python');
239
+ return false;
240
+ }
241
+ }
242
+ }
243
+
244
+ // Activate and upgrade pip first to avoid SSL issues
245
+ console.log('Setting up pip in virtual environment...');
74
246
  const activateCmd = process.platform === 'win32'
75
247
  ? 'venv\\Scripts\\activate'
76
248
  : 'source venv/bin/activate';
77
249
 
78
- execSync(`cd "${mcpPath}" && ${activateCmd} && pip install -e .`, {
79
- stdio: 'inherit',
80
- shell: true
81
- });
250
+ // First, try to install certifi to help with SSL issues
251
+ console.log('Installing certificate handler...');
252
+ try {
253
+ execSync(`cd "${mcpPath}" && ${activateCmd} && pip install --trusted-host pypi.org --trusted-host files.pythonhosted.org certifi`, {
254
+ stdio: 'pipe',
255
+ shell: true
256
+ });
257
+ } catch {
258
+ // Continue even if certifi fails
259
+ }
260
+
261
+ // Upgrade pip and install wheel first
262
+ try {
263
+ // Use --no-cache-dir and --timeout to fail faster
264
+ execSync(`cd "${mcpPath}" && ${activateCmd} && python -m pip install --no-cache-dir --timeout 5 --retries 1 --upgrade pip wheel setuptools`, {
265
+ stdio: 'pipe',
266
+ shell: true
267
+ });
268
+ console.log('āœ… Pip upgraded successfully');
269
+ } catch {
270
+ // If upgrade fails due to SSL, skip it and continue
271
+ console.log('āš ļø Pip upgrade failed (likely SSL issue), continuing with existing pip...');
272
+ }
273
+
274
+ // Now install dependencies
275
+ console.log('Installing MCP server dependencies...');
276
+ try {
277
+ execSync(`cd "${mcpPath}" && ${activateCmd} && pip install --no-cache-dir --timeout 10 --retries 1 -e .`, {
278
+ stdio: 'pipe',
279
+ shell: true
280
+ });
281
+ console.log('āœ… MCP server dependencies installed');
282
+ } catch (error) {
283
+ // Check for SSL errors
284
+ const errorStr = error.toString();
285
+ if (errorStr.includes('SSL') || errorStr.includes('HTTPS') || errorStr.includes('ssl')) {
286
+ console.log('āš ļø SSL error detected. Attempting automatic fix...');
287
+
288
+ // Try different approaches to fix SSL
289
+ const fixes = [
290
+ {
291
+ name: 'Using trusted host flags',
292
+ cmd: `${activateCmd} && pip install --trusted-host pypi.org --trusted-host files.pythonhosted.org --no-cache-dir -e .`
293
+ },
294
+ {
295
+ name: 'Using index-url without SSL',
296
+ cmd: `${activateCmd} && pip config set global.index-url https://pypi.org/simple/ && pip config set global.trusted-host "pypi.org files.pythonhosted.org" && pip install --no-cache-dir -e .`
297
+ },
298
+ {
299
+ name: 'Using system certificates',
300
+ cmd: `${activateCmd} && export SSL_CERT_FILE=$(python -m certifi) && pip install --no-cache-dir -e .`
301
+ }
302
+ ];
303
+
304
+ for (const fix of fixes) {
305
+ console.log(`\n Trying: ${fix.name}...`);
306
+ try {
307
+ execSync(`cd "${mcpPath}" && ${fix.cmd}`, {
308
+ stdio: 'pipe',
309
+ shell: true,
310
+ env: { ...process.env, PYTHONWARNINGS: 'ignore:Unverified HTTPS request' }
311
+ });
312
+ console.log(' āœ… Success! Dependencies installed using workaround');
313
+ return true;
314
+ } catch (e) {
315
+ console.log(' āŒ Failed');
316
+ }
317
+ }
318
+
319
+ console.log('\nāŒ All automatic fixes failed');
320
+ return false;
321
+ } else {
322
+ console.log('āŒ Failed to install dependencies');
323
+ return false;
324
+ }
325
+ }
326
+
327
+ // Install script dependencies
328
+ console.log('Installing import script dependencies...');
329
+ try {
330
+ execSync(`cd "${mcpPath}" && ${activateCmd} && pip install -r "${scriptsPath}/requirements.txt"`, {
331
+ stdio: 'inherit',
332
+ shell: true
333
+ });
334
+ } catch (error) {
335
+ // Try with trusted host if SSL error
336
+ try {
337
+ execSync(`cd "${mcpPath}" && ${activateCmd} && pip install --trusted-host pypi.org --trusted-host files.pythonhosted.org -r "${scriptsPath}/requirements.txt"`, {
338
+ stdio: 'inherit',
339
+ shell: true
340
+ });
341
+ } catch {
342
+ console.log('āš ļø Could not install script dependencies automatically');
343
+ console.log(' You may need to install them manually later');
344
+ }
345
+ }
82
346
 
83
347
  console.log('āœ… Python environment setup complete');
84
348
  return true;
@@ -93,6 +357,7 @@ async function configureEnvironment() {
93
357
 
94
358
  const envPath = join(projectRoot, '.env');
95
359
  let envContent = '';
360
+ let hasValidApiKey = false;
96
361
 
97
362
  try {
98
363
  envContent = await fs.readFile(envPath, 'utf-8');
@@ -100,16 +365,69 @@ async function configureEnvironment() {
100
365
  // .env doesn't exist, create it
101
366
  }
102
367
 
103
- // Check for VOYAGE_KEY
104
- if (!envContent.includes('VOYAGE_KEY=') || envContent.includes('VOYAGE_KEY=your-')) {
105
- console.log('\nVoyage AI provides embeddings for semantic search.');
106
- console.log('Get your free API key at: https://www.voyageai.com/');
107
-
108
- const voyageKey = await question('Enter your Voyage AI API key (or press Enter to skip): ');
109
-
110
- if (voyageKey) {
368
+ // Check if we have a command line API key
369
+ if (voyageKey) {
370
+ if (voyageKey.startsWith('pa-')) {
371
+ console.log('āœ… Using API key from command line');
111
372
  envContent = envContent.replace(/VOYAGE_KEY=.*/g, '');
112
373
  envContent += `\nVOYAGE_KEY=${voyageKey}\n`;
374
+ hasValidApiKey = true;
375
+ } else {
376
+ console.log('āŒ Invalid API key format. Voyage keys start with "pa-"');
377
+ process.exit(1);
378
+ }
379
+ } else if (localMode) {
380
+ console.log('šŸ  Running in local mode - API key not required');
381
+ console.log(' Note: Semantic search will be disabled');
382
+ hasValidApiKey = false; // Mark as false but don't fail
383
+ } else {
384
+ // Check if we already have a valid API key
385
+ const existingKeyMatch = envContent.match(/VOYAGE_KEY=([^\s]+)/);
386
+ if (existingKeyMatch && existingKeyMatch[1] && !existingKeyMatch[1].includes('your-')) {
387
+ console.log('āœ… Found existing Voyage API key in .env file');
388
+ hasValidApiKey = true;
389
+ } else {
390
+ // Need to get API key
391
+ console.log('\nšŸ”‘ Voyage AI API Key Setup');
392
+ console.log('━━━━━━━━━━━━━━━━━━━━━━━━━');
393
+ console.log('Claude Self-Reflect uses Voyage AI for semantic search.');
394
+ console.log('You\'ll need a free API key to continue.\n');
395
+ console.log('šŸ“ Steps to get your API key:');
396
+ console.log(' 1. Visit https://www.voyageai.com/');
397
+ console.log(' 2. Click "Sign Up" (free account)');
398
+ console.log(' 3. Go to API Keys section');
399
+ console.log(' 4. Create a new API key');
400
+ console.log(' 5. Copy the key (starts with "pa-")\n');
401
+
402
+ if (isInteractive) {
403
+ const inputKey = await question('Paste your Voyage AI key here (or press Enter to skip): ');
404
+
405
+ if (inputKey && inputKey.trim() && inputKey !== 'n') {
406
+ // Validate key format
407
+ if (inputKey.trim().startsWith('pa-')) {
408
+ envContent = envContent.replace(/VOYAGE_KEY=.*/g, '');
409
+ envContent += `\nVOYAGE_KEY=${inputKey.trim()}\n`;
410
+ hasValidApiKey = true;
411
+ console.log('āœ… API key saved to .env file');
412
+ } else {
413
+ console.log('āš ļø Invalid key format. Voyage keys start with "pa-"');
414
+ console.log(' You can add it manually to .env file later');
415
+ }
416
+ } else {
417
+ console.log('\nāš ļø No API key provided');
418
+ console.log(' Setup will continue, but you\'ll need to add it to .env file:');
419
+ console.log(' VOYAGE_KEY=your-api-key-here');
420
+ }
421
+ } else {
422
+ console.log('\nāš ļø Non-interactive mode: Cannot prompt for API key');
423
+ console.log(' Please add your Voyage API key to the .env file:');
424
+ console.log(' VOYAGE_KEY=your-api-key-here');
425
+
426
+ // Create placeholder
427
+ if (!envContent.includes('VOYAGE_KEY=')) {
428
+ envContent += '\n# Get your free API key at https://www.voyageai.com/\nVOYAGE_KEY=your-voyage-api-key-here\n';
429
+ }
430
+ }
113
431
  }
114
432
  }
115
433
 
@@ -118,8 +436,21 @@ async function configureEnvironment() {
118
436
  envContent += 'QDRANT_URL=http://localhost:6333\n';
119
437
  }
120
438
 
439
+ // Add other default settings if not present
440
+ if (!envContent.includes('ENABLE_MEMORY_DECAY=')) {
441
+ envContent += 'ENABLE_MEMORY_DECAY=false\n';
442
+ }
443
+ if (!envContent.includes('DECAY_WEIGHT=')) {
444
+ envContent += 'DECAY_WEIGHT=0.3\n';
445
+ }
446
+ if (!envContent.includes('DECAY_SCALE_DAYS=')) {
447
+ envContent += 'DECAY_SCALE_DAYS=90\n';
448
+ }
449
+
121
450
  await fs.writeFile(envPath, envContent.trim() + '\n');
122
- console.log('āœ… Environment configured');
451
+ console.log('āœ… Environment file created/updated');
452
+
453
+ return { apiKey: hasValidApiKey };
123
454
  }
124
455
 
125
456
  async function setupClaude() {
@@ -127,10 +458,48 @@ async function setupClaude() {
127
458
 
128
459
  const runScript = join(projectRoot, 'mcp-server', 'run-mcp.sh');
129
460
 
130
- console.log('\nAdd this to your Claude Code settings:');
131
- console.log('```bash');
132
- console.log(`claude mcp add claude-self-reflect "${runScript}" -e VOYAGE_KEY="<your-key>" -e QDRANT_URL="http://localhost:6333"`);
133
- console.log('```');
461
+ // Check if Claude CLI is available
462
+ try {
463
+ execSync('which claude', { stdio: 'ignore' });
464
+
465
+ // Try to add the MCP automatically
466
+ try {
467
+ const voyageKeyValue = voyageKey || process.env.VOYAGE_KEY || '';
468
+ if (!voyageKeyValue && !localMode) {
469
+ console.log('āš ļø No Voyage API key available for MCP configuration');
470
+ console.log('\nAdd this to your Claude Code settings manually:');
471
+ console.log('```bash');
472
+ console.log(`claude mcp add claude-self-reflect "${runScript}" -e VOYAGE_KEY="<your-key>" -e QDRANT_URL="http://localhost:6333"`);
473
+ console.log('```');
474
+ return;
475
+ }
476
+
477
+ console.log('šŸ”§ Adding MCP to Claude Code...');
478
+ const mcpCommand = localMode
479
+ ? `claude mcp add claude-self-reflect "${runScript}" -e QDRANT_URL="http://localhost:6333"`
480
+ : `claude mcp add claude-self-reflect "${runScript}" -e VOYAGE_KEY="${voyageKeyValue}" -e QDRANT_URL="http://localhost:6333"`;
481
+
482
+ execSync(mcpCommand, { stdio: 'inherit' });
483
+ console.log('āœ… MCP added successfully!');
484
+ console.log('\nāš ļø You may need to restart Claude Code for the changes to take effect.');
485
+
486
+ // Store that we've configured MCP
487
+ mcpConfigured = true;
488
+ } catch (error) {
489
+ console.log('āš ļø Could not add MCP automatically');
490
+ console.log('\nAdd this to your Claude Code settings manually:');
491
+ console.log('```bash');
492
+ console.log(`claude mcp add claude-self-reflect "${runScript}" -e VOYAGE_KEY="${voyageKey || '<your-key>'}" -e QDRANT_URL="http://localhost:6333"`);
493
+ console.log('```');
494
+ }
495
+ } catch {
496
+ // Claude CLI not installed
497
+ console.log('āš ļø Claude CLI not found. Please install Claude Code first.');
498
+ console.log('\nOnce installed, add this MCP:');
499
+ console.log('```bash');
500
+ console.log(`claude mcp add claude-self-reflect "${runScript}" -e VOYAGE_KEY="${voyageKey || '<your-key>'}" -e QDRANT_URL="http://localhost:6333"`);
501
+ console.log('```');
502
+ }
134
503
 
135
504
  console.log('\nThen restart Claude Code for the changes to take effect.');
136
505
  }
@@ -164,27 +533,701 @@ async function installAgents() {
164
533
  }
165
534
  }
166
535
 
167
- async function main() {
536
+ async function showPreSetupInstructions() {
168
537
  console.log('šŸš€ Welcome to Claude Self-Reflect Setup!\n');
169
538
  console.log('This wizard will help you set up conversation memory for Claude.\n');
170
539
 
540
+ console.log('šŸ“‹ Before we begin, you\'ll need:');
541
+ console.log(' 1. Docker Desktop installed and running');
542
+ console.log(' 2. Python 3.10 or higher');
543
+ console.log(' 3. A Voyage AI API key (we\'ll help you get one)\n');
544
+
545
+ if (isInteractive) {
546
+ await question('Press Enter to continue...');
547
+ }
548
+ }
549
+
550
+ async function importConversations() {
551
+ console.log('\nšŸ“š Import Claude Conversations...');
552
+
553
+ // Skip import in local mode
554
+ if (localMode) {
555
+ console.log('šŸ  Skipping import in local mode (no API key for embeddings)');
556
+ return;
557
+ }
558
+
559
+ // Check if Claude logs directory exists
560
+ const logsDir = join(process.env.HOME || process.env.USERPROFILE, '.claude', 'projects');
561
+ let hasConversations = false;
562
+ let totalProjects = 0;
563
+
564
+ try {
565
+ await fs.access(logsDir);
566
+ const projects = await fs.readdir(logsDir);
567
+ const validProjects = projects.filter(p => !p.startsWith('.'));
568
+ totalProjects = validProjects.length;
569
+ if (totalProjects > 0) {
570
+ hasConversations = true;
571
+ console.log(`āœ… Found ${totalProjects} Claude projects`);
572
+ }
573
+ } catch {
574
+ console.log('šŸ“­ No Claude conversations found yet');
575
+ console.log(' Conversations will be imported automatically once you start using Claude Code');
576
+ return;
577
+ }
578
+
579
+ if (!hasConversations) {
580
+ console.log('šŸ“­ No Claude conversations found yet');
581
+ console.log(' Conversations will be imported automatically once you start using Claude Code');
582
+ return;
583
+ }
584
+
585
+ // Check if already imported or partially imported
586
+ const stateFile = join(process.env.HOME || process.env.USERPROFILE, '.claude-self-reflect', 'imported-files.json');
587
+ let importedProjects = 0;
588
+ try {
589
+ const stateData = await fs.readFile(stateFile, 'utf-8');
590
+ const state = JSON.parse(stateData);
591
+ if (state.projects && Object.keys(state.projects).length > 0) {
592
+ importedProjects = Object.keys(state.projects).length;
593
+
594
+ // Check if all projects are imported
595
+ if (importedProjects >= totalProjects) {
596
+ console.log('āœ… All conversations already imported');
597
+ console.log(` ${importedProjects} projects in database`);
598
+ return;
599
+ } else {
600
+ console.log(`šŸ“Š Partially imported: ${importedProjects}/${totalProjects} projects`);
601
+ console.log(' Continuing import for remaining projects...');
602
+ }
603
+ }
604
+ } catch {
605
+ // State file doesn't exist, proceed with import
606
+ }
607
+
608
+ // Run import
609
+ console.log('\nšŸ”„ Importing conversations...');
610
+ console.log(' This may take a few minutes depending on your conversation history');
611
+
612
+ try {
613
+ const pythonCmd = process.env.PYTHON_PATH || 'python3';
614
+ const importScript = join(projectRoot, 'scripts', 'import-conversations-voyage.py');
615
+
616
+ // Use the venv Python directly - platform specific
617
+ let venvPython;
618
+ if (process.platform === 'win32') {
619
+ venvPython = join(projectRoot, 'mcp-server', 'venv', 'Scripts', 'python.exe');
620
+ } else if (process.platform === 'darwin') {
621
+ // macOS
622
+ venvPython = join(projectRoot, 'mcp-server', 'venv', 'bin', 'python');
623
+ } else {
624
+ // Linux
625
+ venvPython = join(projectRoot, 'mcp-server', 'venv', 'bin', 'python');
626
+ }
627
+
628
+ // Verify venv Python exists
629
+ try {
630
+ await fs.access(venvPython);
631
+ } catch {
632
+ console.log('āš ļø Virtual environment Python not found');
633
+ console.log(' Please run the import manually:');
634
+ console.log(' cd claude-self-reflect');
635
+ console.log(' source mcp-server/venv/bin/activate');
636
+ console.log(' python scripts/import-conversations-voyage.py');
637
+ return;
638
+ }
639
+
640
+ const importProcess = spawn(venvPython, [importScript], {
641
+ cwd: projectRoot,
642
+ env: {
643
+ ...process.env,
644
+ VOYAGE_KEY: voyageKey || process.env.VOYAGE_KEY,
645
+ QDRANT_URL: 'http://localhost:6333',
646
+ LOGS_DIR: logsDir,
647
+ STATE_FILE: stateFile
648
+ },
649
+ stdio: 'inherit'
650
+ });
651
+
652
+ await new Promise((resolve, reject) => {
653
+ importProcess.on('exit', (code) => {
654
+ if (code === 0) {
655
+ console.log('\nāœ… Conversations imported successfully!');
656
+ resolve();
657
+ } else {
658
+ console.log('\nāš ļø Import completed with warnings');
659
+ console.log(' Some conversations may not have been imported');
660
+ console.log(' You can run the import again later if needed');
661
+ resolve(); // Don't fail setup if import has issues
662
+ }
663
+ });
664
+
665
+ importProcess.on('error', (err) => {
666
+ console.log('\nāš ļø Could not run import automatically');
667
+ console.log(' You can import manually later');
668
+ resolve(); // Don't fail setup
669
+ });
670
+ });
671
+
672
+ } catch (error) {
673
+ console.log('\nāš ļø Could not run import automatically:', error.message);
674
+ console.log(' You can import conversations manually later');
675
+ }
676
+ }
677
+
678
+ async function showSystemDashboard() {
679
+ console.log('\nšŸ“Š System Health Dashboard');
680
+ console.log('═══════════════════════════════════════════════════════════════\n');
681
+
682
+ // Check system components
683
+ const status = {
684
+ docker: false,
685
+ qdrant: false,
686
+ python: false,
687
+ venv: false,
688
+ apiKey: false,
689
+ imported: 0,
690
+ total: 0,
691
+ watcherInstalled: false,
692
+ watcherRunning: false
693
+ };
694
+
695
+ // Docker status
696
+ try {
697
+ execSync('docker info', { stdio: 'ignore' });
698
+ status.docker = true;
699
+ } catch {}
700
+
701
+ // Qdrant status
702
+ try {
703
+ const response = await fetch('http://localhost:6333');
704
+ const data = await response.json();
705
+ if (data.title && data.title.includes('qdrant')) {
706
+ status.qdrant = true;
707
+ }
708
+ } catch {}
709
+
710
+ // Python status
711
+ try {
712
+ const pythonCmd = process.env.PYTHON_PATH || 'python3';
713
+ execSync(`${pythonCmd} --version`, { stdio: 'ignore' });
714
+ status.python = true;
715
+ } catch {}
716
+
717
+ // Virtual environment status
718
+ const venvPath = join(projectRoot, 'mcp-server', 'venv');
719
+ try {
720
+ await fs.access(venvPath);
721
+ status.venv = true;
722
+ } catch {}
723
+
724
+ // API key status
725
+ const envPath = join(projectRoot, '.env');
726
+ try {
727
+ const envContent = await fs.readFile(envPath, 'utf-8');
728
+ const keyMatch = envContent.match(/VOYAGE_KEY=([^\s]+)/);
729
+ if (keyMatch && keyMatch[1] && !keyMatch[1].includes('your-')) {
730
+ status.apiKey = true;
731
+ }
732
+ } catch {}
733
+
734
+ // Import status
735
+ const logsDir = join(process.env.HOME || process.env.USERPROFILE, '.claude', 'projects');
736
+ try {
737
+ const projects = await fs.readdir(logsDir);
738
+ status.total = projects.filter(p => !p.startsWith('.')).length;
739
+ } catch {}
740
+
741
+ const stateFile = join(projectRoot, 'config', 'imported-files.json');
742
+ try {
743
+ const stateData = await fs.readFile(stateFile, 'utf-8');
744
+ const state = JSON.parse(stateData);
745
+ if (state.projects) {
746
+ status.imported = Object.keys(state.projects).length;
747
+ }
748
+ } catch {}
749
+
750
+ // Get Qdrant collection statistics
751
+ status.collections = 0;
752
+ status.totalDocuments = 0;
753
+ try {
754
+ const collectionsResponse = await fetch('http://localhost:6333/collections');
755
+ const collectionsData = await collectionsResponse.json();
756
+ if (collectionsData.result && collectionsData.result.collections) {
757
+ status.collections = collectionsData.result.collections.length;
758
+
759
+ // Get document count from each collection
760
+ for (const collection of collectionsData.result.collections) {
761
+ try {
762
+ const countResponse = await fetch(`http://localhost:6333/collections/${collection.name}`);
763
+ const countData = await countResponse.json();
764
+ if (countData.result && countData.result.points_count) {
765
+ status.totalDocuments += countData.result.points_count;
766
+ }
767
+ } catch {}
768
+ }
769
+ }
770
+ } catch {}
771
+
772
+ // Check watcher logs for recent activity
773
+ status.watcherErrors = [];
774
+ status.lastImportTime = null;
775
+ try {
776
+ const watcherLogs = execSync('docker logs claude-reflection-watcher --tail 50 2>&1', {
777
+ encoding: 'utf-8'
778
+ }).toString();
779
+
780
+ // Check for recent errors
781
+ const errorMatches = watcherLogs.match(/ERROR.*Import failed.*/g);
782
+ if (errorMatches) {
783
+ status.watcherErrors = errorMatches.slice(-3); // Last 3 errors
784
+ }
785
+
786
+ // Check for successful imports
787
+ const successMatch = watcherLogs.match(/Successfully imported project: ([^\s]+)/g);
788
+ if (successMatch && successMatch.length > 0) {
789
+ const lastSuccess = successMatch[successMatch.length - 1];
790
+ status.lastImportTime = 'Recently';
791
+ }
792
+ } catch {}
793
+
794
+ // Watcher status
795
+ try {
796
+ // Check if watcher script exists
797
+ const watcherScript = join(projectRoot, 'scripts', 'import-watcher.py');
798
+ await fs.access(watcherScript);
799
+ status.watcherInstalled = true;
800
+
801
+ // Check if watcher is running via Docker
802
+ try {
803
+ const dockerStatus = execSync('docker ps --filter "name=claude-reflection-watcher" --format "{{.Names}}" 2>/dev/null', {
804
+ cwd: projectRoot,
805
+ encoding: 'utf-8'
806
+ }).toString().trim();
807
+
808
+ if (dockerStatus.includes('watcher')) {
809
+ status.watcherRunning = true;
810
+ }
811
+ } catch {
812
+ // Docker compose not available or watcher not running
813
+ }
814
+ } catch {
815
+ status.watcherInstalled = false;
816
+ }
817
+
818
+ // Display dashboard
819
+ console.log('šŸ”§ System Components:');
820
+ console.log(` Docker: ${status.docker ? 'āœ… Running' : 'āŒ Not running'}`);
821
+ console.log(` Qdrant: ${status.qdrant ? 'āœ… Running on port 6333' : 'āŒ Not accessible'}`);
822
+ console.log(` Python: ${status.python ? 'āœ… Installed' : 'āŒ Not found'}`);
823
+ console.log(` Virtual Env: ${status.venv ? 'āœ… Created' : 'āŒ Not created'}`);
824
+ console.log(` API Key: ${status.apiKey ? 'āœ… Configured' : localMode ? 'šŸ  Local mode' : 'āŒ Not configured'}`);
825
+
826
+ console.log('\nšŸ“š Import Status:');
827
+ if (status.total === 0) {
828
+ console.log(' No Claude conversations found yet');
829
+ } else if (status.imported === 0 && status.collections === 0) {
830
+ console.log(` šŸ“­ Not started (${status.total} projects available)`);
831
+ } else if (status.imported < status.total || status.collections > 0) {
832
+ const percent = status.total > 0 ? Math.round((status.imported / status.total) * 100) : 0;
833
+ if (status.collections > 0) {
834
+ console.log(` šŸ”„ Active: ${status.collections} collections, ${status.totalDocuments} conversation chunks`);
835
+ }
836
+ if (status.total > 0) {
837
+ console.log(` šŸ“Š Projects: ${status.imported}/${status.total} (${percent}%)`);
838
+ console.log(` ā–“${'ā–“'.repeat(Math.floor(percent/5))}${'ā–‘'.repeat(20-Math.floor(percent/5))} ${percent}%`);
839
+ }
840
+ if (status.lastImportTime) {
841
+ console.log(` ā° Last import: ${status.lastImportTime}`);
842
+ }
843
+ } else {
844
+ console.log(` āœ… Complete: ${status.imported} projects, ${status.totalDocuments} chunks indexed`);
845
+ }
846
+
847
+ console.log('\nšŸ”„ Continuous Import (Watcher):');
848
+ if (status.watcherInstalled) {
849
+ if (status.watcherRunning) {
850
+ console.log(' Status: āœ… Running in Docker');
851
+ } else {
852
+ console.log(' Status: ⚪ Available but not running');
853
+ console.log(' • Manual: python scripts/import-watcher.py');
854
+ console.log(' • Docker: docker compose --profile watch up -d');
855
+ }
856
+
857
+ if (status.watcherErrors.length > 0) {
858
+ console.log(' āš ļø Recent errors:');
859
+ status.watcherErrors.forEach(err => {
860
+ const shortErr = err.replace(/.*ERROR.*?: /, '').substring(0, 60) + '...';
861
+ console.log(` • ${shortErr}`);
862
+ });
863
+ }
864
+ } else {
865
+ console.log(' Status: āŒ Not available');
866
+ }
867
+
868
+ // Check for issues
869
+ const issues = [];
870
+ if (!status.docker) issues.push('Docker is not running');
871
+ if (!status.qdrant && status.docker) issues.push('Qdrant is not running');
872
+ if (!status.python) issues.push('Python is not installed');
873
+ if (!status.apiKey && !localMode) issues.push('Voyage API key not configured');
874
+
875
+ if (issues.length > 0) {
876
+ console.log('\nāš ļø Issues Found:');
877
+ issues.forEach(issue => console.log(` • ${issue}`));
878
+ console.log('\nšŸ’” Run setup again to fix these issues');
879
+ } else if (status.imported < status.total) {
880
+ console.log('\nšŸ’” Setup will continue with import process...');
881
+ } else {
882
+ console.log('\nāœ… System is fully configured and healthy!');
883
+ }
884
+
885
+ console.log('\n═══════════════════════════════════════════════════════════════\n');
886
+
887
+ return {
888
+ healthy: issues.length === 0,
889
+ needsImport: status.imported < status.total,
890
+ issues
891
+ };
892
+ }
893
+
894
+ async function setupWatcher() {
895
+ console.log('\nāš™ļø Setting up Continuous Import (Watcher)...');
896
+
897
+ const watcherScript = join(projectRoot, 'scripts', 'import-watcher.py');
898
+
899
+ // Check if watcher exists
900
+ try {
901
+ await fs.access(watcherScript);
902
+ console.log('āœ… Watcher script found');
903
+
904
+ // Skip in local mode
905
+ if (localMode) {
906
+ console.log('šŸ  Skipping watcher in local mode');
907
+ return;
908
+ }
909
+
910
+ // Ask if user wants to enable watcher
911
+ let enableWatcher = 'y';
912
+ if (isInteractive) {
913
+ console.log('\nšŸ’” The watcher monitors for new conversations and imports them automatically.');
914
+ enableWatcher = await question('Enable continuous import watcher? (y/n): ');
915
+ }
916
+
917
+ if (enableWatcher.toLowerCase() === 'y') {
918
+ // Check if docker-compose.yaml exists
919
+ const dockerComposeFile = join(projectRoot, 'docker-compose.yaml');
920
+ try {
921
+ await fs.access(dockerComposeFile);
922
+
923
+ console.log('\n🐳 Starting watcher with Docker Compose...');
924
+ try {
925
+ // First ensure .env has VOYAGE_KEY to avoid warnings
926
+ const envPath = join(projectRoot, '.env');
927
+ const envContent = await fs.readFile(envPath, 'utf-8');
928
+ if (!envContent.includes('VOYAGE_KEY=') && voyageKey) {
929
+ await fs.appendFile(envPath, `\nVOYAGE_KEY=${voyageKey}\n`);
930
+ }
931
+
932
+ // Clean up all existing containers first
933
+ console.log('🧹 Cleaning up existing containers...');
934
+ try {
935
+ // Stop all claude-reflection containers
936
+ execSync('docker compose down 2>/dev/null || true', {
937
+ cwd: projectRoot,
938
+ stdio: 'pipe'
939
+ });
940
+
941
+ // Also stop any standalone containers
942
+ execSync('docker stop claude-reflection-watcher claude-reflection-qdrant qdrant 2>/dev/null || true', {
943
+ stdio: 'pipe'
944
+ });
945
+
946
+ // Remove them
947
+ execSync('docker rm claude-reflection-watcher claude-reflection-qdrant qdrant 2>/dev/null || true', {
948
+ stdio: 'pipe'
949
+ });
950
+
951
+ // Wait a moment for cleanup
952
+ await new Promise(resolve => setTimeout(resolve, 2000));
953
+ } catch {}
954
+
955
+ // Start both services with compose
956
+ console.log('šŸš€ Starting Qdrant and Watcher services...');
957
+ execSync('docker compose --profile watch up -d', {
958
+ cwd: projectRoot,
959
+ stdio: 'pipe' // Use pipe to capture output
960
+ });
961
+
962
+ console.log('ā³ Waiting for containers to start...');
963
+ await new Promise(resolve => setTimeout(resolve, 8000)); // Give more time
964
+
965
+ // Check container status
966
+ try {
967
+ const psOutput = execSync('docker ps --filter "name=claude-reflection" --format "table {{.Names}}\t{{.Status}}"', {
968
+ cwd: projectRoot,
969
+ encoding: 'utf8'
970
+ });
971
+
972
+ const qdrantReady = psOutput.includes('claude-reflection-qdrant') && psOutput.includes('Up');
973
+ const watcherReady = psOutput.includes('claude-reflection-watcher') && psOutput.includes('Up');
974
+
975
+ if (qdrantReady && watcherReady) {
976
+ console.log('āœ… All services started successfully!');
977
+ console.log(' • Qdrant is ready for storing conversations');
978
+ console.log(' • Watcher will check for new conversations every 60 seconds');
979
+ console.log('\nšŸ“Š Container Status:');
980
+ console.log(psOutput);
981
+ console.log('\nšŸ“ Useful commands:');
982
+ console.log(' Check status: docker compose ps');
983
+ console.log(' View logs: docker compose logs -f watcher');
984
+ console.log(' Stop services: docker compose --profile watch down');
985
+ } else if (qdrantReady) {
986
+ console.log('āœ… Qdrant started successfully');
987
+ console.log('ā³ Watcher is still starting...');
988
+ console.log('\nšŸ“ Check full status with:');
989
+ console.log(' docker compose ps');
990
+ console.log(' docker compose logs watcher');
991
+ } else {
992
+ console.log('ā³ Services are still starting...');
993
+ console.log('\nšŸ“ Check status with:');
994
+ console.log(' docker compose ps');
995
+ console.log(' docker compose logs');
996
+ }
997
+ } catch (statusError) {
998
+ console.log('āœ… Services deployment initiated');
999
+ console.log('\nšŸ“ Check status with:');
1000
+ console.log(' docker compose ps');
1001
+ }
1002
+ } catch (error) {
1003
+ console.log('āš ļø Could not start watcher automatically');
1004
+ console.log('Error:', error.message);
1005
+ console.log('\nšŸ“ To start manually, run:');
1006
+ console.log(' cd claude-self-reflect');
1007
+ console.log(' docker compose --profile watch up -d');
1008
+ }
1009
+ } catch {
1010
+ // Fallback to manual Python execution
1011
+ console.log('\nšŸ“ To enable the watcher, run:');
1012
+ console.log(' cd claude-self-reflect');
1013
+ console.log(' source mcp-server/venv/bin/activate');
1014
+ console.log(' python scripts/import-watcher.py &');
1015
+ }
1016
+ } else {
1017
+ console.log('\nšŸ“ You can enable the watcher later by running:');
1018
+ console.log(' docker compose --profile watch up -d');
1019
+ }
1020
+ } catch {
1021
+ console.log('āš ļø Watcher script not found');
1022
+ }
1023
+ }
1024
+
1025
+ async function verifyMCP() {
1026
+ console.log('\nšŸ” Verifying MCP Installation...');
1027
+
1028
+ // Skip verification if MCP wasn't configured
1029
+ if (!mcpConfigured) {
1030
+ console.log('āš ļø MCP was not automatically configured. Please add it manually and verify.');
1031
+ return;
1032
+ }
1033
+
1034
+ try {
1035
+ // Check if MCP is listed
1036
+ const mcpList = execSync('claude mcp list', { encoding: 'utf8' });
1037
+ if (!mcpList.includes('claude-self-reflect')) {
1038
+ console.log('āŒ MCP not found in Claude Code');
1039
+ return;
1040
+ }
1041
+
1042
+ console.log('āœ… MCP is installed in Claude Code');
1043
+
1044
+ // Create a test verification script
1045
+ const testScript = `#!/usr/bin/env python3
1046
+ import asyncio
1047
+ import sys
1048
+ import os
1049
+
1050
+ # Add the mcp-server src to the path
1051
+ sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'mcp-server', 'src'))
1052
+
1053
+ async def test_mcp():
1054
+ try:
1055
+ # Import the server module
1056
+ from server_v2 import mcp, get_voyage_collections
1057
+
1058
+ # Check that MCP is loaded
1059
+ print(f"āœ… MCP server loaded successfully!")
1060
+ print(f" - Server name: {mcp.name}")
1061
+
1062
+ # Check for our specific tools by trying to access them
1063
+ tool_names = ['reflect_on_past', 'store_reflection']
1064
+ found_tools = []
1065
+
1066
+ # FastMCP doesn't expose tools list directly, so we'll check if imports worked
1067
+ try:
1068
+ from server_v2 import reflect_on_past, store_reflection
1069
+ found_tools = tool_names
1070
+ except ImportError:
1071
+ pass
1072
+ if 'reflect_on_past' in found_tools:
1073
+ print("āœ… Tool 'reflect_on_past' is available")
1074
+ else:
1075
+ print("āŒ Tool 'reflect_on_past' not found")
1076
+
1077
+ if 'store_reflection' in found_tools:
1078
+ print("āœ… Tool 'store_reflection' is available")
1079
+ else:
1080
+ print("āŒ Tool 'store_reflection' not found")
1081
+
1082
+ # Test that we can connect to Qdrant
1083
+ try:
1084
+ collections = await get_voyage_collections()
1085
+ print(f"āœ… Connected to Qdrant: {len(collections)} collections found")
1086
+ if len(collections) == 0:
1087
+ print(" (This is normal if no conversations have been imported yet)")
1088
+ except Exception as e:
1089
+ print(f"āš ļø Qdrant connection: {e}")
1090
+
1091
+ except Exception as e:
1092
+ print(f"āŒ Failed to load MCP server: {e}")
1093
+ sys.exit(1)
1094
+
1095
+ # Run the async test
1096
+ asyncio.run(test_mcp())
1097
+ `;
1098
+
1099
+ // Write test script
1100
+ const testPath = join(projectRoot, 'test-mcp.py');
1101
+ await fs.writeFile(testPath, testScript, { mode: 0o755 });
1102
+
1103
+ // Run the test
1104
+ console.log('\n🧪 Testing MCP functionality...');
1105
+ try {
1106
+ const testResult = execSync(`cd "${projectRoot}" && source mcp-server/venv/bin/activate && python test-mcp.py`, {
1107
+ encoding: 'utf8',
1108
+ shell: '/bin/bash'
1109
+ });
1110
+ console.log(testResult);
1111
+
1112
+ // Clean up test script
1113
+ await fs.unlink(testPath);
1114
+
1115
+ console.log('\nāœ… MCP verification complete! The reflection tools are working.');
1116
+ } catch (error) {
1117
+ console.log('āŒ MCP test failed:', error.message);
1118
+ console.log('\nāš ļø The MCP may need to be restarted in Claude Code.');
1119
+
1120
+ // Clean up test script
1121
+ try { await fs.unlink(testPath); } catch {}
1122
+ }
1123
+
1124
+ } catch (error) {
1125
+ console.log('āš ļø Could not verify MCP:', error.message);
1126
+ console.log('\nPlease verify manually by:');
1127
+ console.log('1. Restarting Claude Code');
1128
+ console.log('2. Checking that the reflection tools appear in Claude');
1129
+ }
1130
+ }
1131
+
1132
+ async function main() {
1133
+ // Show dashboard first if system is partially configured
1134
+ const venvExists = await fs.access(join(projectRoot, 'mcp-server', 'venv')).then(() => true).catch(() => false);
1135
+ const envExists = await fs.access(join(projectRoot, '.env')).then(() => true).catch(() => false);
1136
+
1137
+ if (venvExists || envExists) {
1138
+ // System has been partially configured, show dashboard
1139
+ const dashboardStatus = await showSystemDashboard();
1140
+
1141
+ if (dashboardStatus.healthy && !dashboardStatus.needsImport) {
1142
+ // Everything is already set up
1143
+ if (isInteractive) {
1144
+ const proceed = await question('System is already configured. Continue with setup anyway? (y/n): ');
1145
+ if (proceed.toLowerCase() !== 'y') {
1146
+ console.log('\nšŸ‘‹ Setup cancelled. Your system is already configured!');
1147
+ if (rl) rl.close();
1148
+ process.exit(0);
1149
+ }
1150
+ }
1151
+ }
1152
+ }
1153
+
1154
+ // Check for non-interactive mode without required flags
1155
+ if (!isInteractive && !voyageKey && !localMode) {
1156
+ console.log('āŒ Non-interactive mode requires either --voyage-key or --local flag\n');
1157
+ console.log('Usage:');
1158
+ console.log(' claude-self-reflect setup --voyage-key=<your-key>');
1159
+ console.log(' claude-self-reflect setup --local\n');
1160
+ console.log('Get your free API key at: https://www.voyageai.com/');
1161
+ process.exit(1);
1162
+ }
1163
+
1164
+ await showPreSetupInstructions();
1165
+
171
1166
  // Check prerequisites
172
1167
  const pythonOk = await checkPython();
173
1168
  if (!pythonOk) {
174
1169
  console.log('\nāŒ Setup cannot continue without Python');
1170
+ console.log('\nšŸ“‹ Fix Required:');
1171
+ console.log(' 1. Install Python 3.10+ from https://python.org');
1172
+ console.log(' 2. Ensure python3 is in your PATH');
1173
+ console.log('\nšŸ”„ After fixing, run again:');
1174
+ console.log(' claude-self-reflect setup');
175
1175
  process.exit(1);
176
1176
  }
177
1177
 
1178
+ // Check Docker and Qdrant
178
1179
  const qdrantOk = await checkQdrant();
179
- if (!qdrantOk) {
180
- console.log('\nāš ļø Qdrant is required for the vector database');
1180
+ if (qdrantOk === false) {
1181
+ console.log('\nāŒ Setup cannot continue without Qdrant');
1182
+ console.log('\nšŸ“‹ Fix Required - Choose one:');
1183
+ console.log('\n Option 1: Start Docker Desktop');
1184
+ console.log(' - Open Docker Desktop application');
1185
+ console.log(' - Wait for it to fully start (green icon)');
1186
+ console.log('\n Option 2: Manually start Qdrant');
1187
+ console.log(' - docker run -d --name qdrant -p 6333:6333 qdrant/qdrant:latest');
1188
+ console.log('\nšŸ”„ After fixing, run again:');
1189
+ console.log(' claude-self-reflect setup');
1190
+
1191
+ if (rl) rl.close();
1192
+ process.exit(1);
181
1193
  }
1194
+ // If qdrantOk is 'pending', we'll start it with docker-compose later
182
1195
 
183
1196
  // Setup Python environment
184
- await setupPythonEnvironment();
1197
+ const pythonEnvOk = await setupPythonEnvironment();
1198
+ if (!pythonEnvOk) {
1199
+ console.log('\nāŒ Python environment setup failed');
1200
+ console.log('\nšŸ“‹ Fix Required:');
1201
+ console.log('\n For SSL/HTTPS errors:');
1202
+ console.log(' - macOS: brew reinstall python@3.10');
1203
+ console.log(' - Ubuntu: sudo apt-get install python3-dev libssl-dev');
1204
+ console.log(' - Or use a different Python installation');
1205
+ console.log('\n For venv errors:');
1206
+ console.log(' - Ubuntu: sudo apt install python3-venv');
1207
+ console.log(' - macOS: Should be included with Python');
1208
+ console.log('\nšŸ”„ After fixing, run again:');
1209
+ console.log(' claude-self-reflect setup');
1210
+
1211
+ if (rl) rl.close();
1212
+ process.exit(1);
1213
+ }
185
1214
 
186
1215
  // Configure environment
187
- await configureEnvironment();
1216
+ const envOk = await configureEnvironment();
1217
+ if (!localMode && (!envOk || !envOk.apiKey)) {
1218
+ console.log('\nāš ļø No Voyage API key configured');
1219
+ console.log('\nšŸ“‹ Next Steps:');
1220
+ console.log(' 1. Get your free API key from https://www.voyageai.com/');
1221
+ console.log(' 2. Add it to the .env file:');
1222
+ console.log(' VOYAGE_KEY=your-api-key-here');
1223
+ console.log('\nšŸ”„ After adding the key, run again:');
1224
+ console.log(' claude-self-reflect setup');
1225
+ console.log('\nšŸ’” Or run in local mode:');
1226
+ console.log(' claude-self-reflect setup --local');
1227
+
1228
+ if (rl) rl.close();
1229
+ process.exit(1);
1230
+ }
188
1231
 
189
1232
  // Install agents
190
1233
  await installAgents();
@@ -192,13 +1235,31 @@ async function main() {
192
1235
  // Show Claude configuration
193
1236
  await setupClaude();
194
1237
 
1238
+ // Import conversations
1239
+ await importConversations();
1240
+
1241
+ // Setup watcher for continuous import
1242
+ await setupWatcher();
1243
+
1244
+ // Verify MCP installation
1245
+ await verifyMCP();
1246
+
195
1247
  console.log('\nāœ… Setup complete!');
196
1248
  console.log('\nNext steps:');
197
- console.log('1. Import your conversations: cd scripts && python import-conversations-voyage.py');
198
- console.log('2. Use the reflection tools in Claude Code');
1249
+ if (!mcpConfigured) {
1250
+ console.log('1. Add the MCP to Claude Code manually (see instructions above)');
1251
+ console.log('2. Restart Claude Code');
1252
+ console.log('3. Start using the reflection tools!');
1253
+ } else {
1254
+ console.log('1. Restart Claude Code if needed');
1255
+ console.log('2. Start using the reflection tools!');
1256
+ console.log(' - Ask about past conversations');
1257
+ console.log(' - Store important insights');
1258
+ }
199
1259
  console.log('\nFor more info: https://github.com/ramakay/claude-self-reflect');
200
1260
 
201
- rl.close();
1261
+ if (rl) rl.close();
1262
+ process.exit(0);
202
1263
  }
203
1264
 
204
1265
  main().catch(console.error);