claude-self-reflect 1.1.3 → 1.2.0

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.
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
package/dist/cli.js ADDED
@@ -0,0 +1,55 @@
1
+ #!/usr/bin/env node
2
+ import { spawn } from 'child_process';
3
+ import { fileURLToPath } from 'url';
4
+ import { dirname, join } from 'path';
5
+ import { readFileSync } from 'fs';
6
+ const __filename = fileURLToPath(import.meta.url);
7
+ const __dirname = dirname(__filename);
8
+ // Handle command line arguments
9
+ const args = process.argv.slice(2);
10
+ const command = args[0];
11
+ if (command === 'setup') {
12
+ // Run the setup wizard
13
+ const setupPath = join(__dirname, '..', 'scripts', 'setup-wizard.js');
14
+ const child = spawn('node', [setupPath], {
15
+ stdio: 'inherit'
16
+ });
17
+ child.on('error', (error) => {
18
+ console.error('Failed to start setup wizard:', error);
19
+ process.exit(1);
20
+ });
21
+ child.on('exit', (code) => {
22
+ process.exit(code || 0);
23
+ });
24
+ }
25
+ else if (command === '--version' || command === '-v') {
26
+ // Read package.json to get version
27
+ const packagePath = join(__dirname, '..', 'package.json');
28
+ const pkg = JSON.parse(readFileSync(packagePath, 'utf8'));
29
+ console.log(pkg.version);
30
+ }
31
+ else if (command === '--help' || command === '-h' || !command) {
32
+ console.log(`
33
+ Claude Self-Reflect - Give Claude perfect memory of all your conversations
34
+
35
+ Usage:
36
+ claude-self-reflect <command>
37
+
38
+ Commands:
39
+ setup Run the interactive setup wizard
40
+
41
+ Options:
42
+ --version Show version number
43
+ --help Show this help message
44
+
45
+ Examples:
46
+ claude-self-reflect setup # Run interactive setup
47
+ npx claude-self-reflect setup # Run without installing globally
48
+ `);
49
+ }
50
+ else {
51
+ console.error(`Unknown command: ${command}`);
52
+ console.error('Run "claude-self-reflect --help" for usage information');
53
+ process.exit(1);
54
+ }
55
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AACtC,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AACrC,OAAO,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAElC,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AAEtC,gCAAgC;AAChC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACnC,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;AAExB,IAAI,OAAO,KAAK,OAAO,EAAE,CAAC;IACxB,uBAAuB;IACvB,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,iBAAiB,CAAC,CAAC;IACtE,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,SAAS,CAAC,EAAE;QACvC,KAAK,EAAE,SAAS;KACjB,CAAC,CAAC;IAEH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;QAC1B,OAAO,CAAC,KAAK,CAAC,+BAA+B,EAAE,KAAK,CAAC,CAAC;QACtD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;IAEH,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;QACxB,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC;IAC1B,CAAC,CAAC,CAAC;AACL,CAAC;KAAM,IAAI,OAAO,KAAK,WAAW,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;IACvD,mCAAmC;IACnC,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,cAAc,CAAC,CAAC;IAC1D,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,CAAC;IAC1D,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;AAC3B,CAAC;KAAM,IAAI,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;IAChE,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;;;;;;CAgBb,CAAC,CAAC;AACH,CAAC;KAAM,CAAC;IACN,OAAO,CAAC,KAAK,CAAC,oBAAoB,OAAO,EAAE,CAAC,CAAC;IAC7C,OAAO,CAAC,KAAK,CAAC,wDAAwD,CAAC,CAAC;IACxE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-self-reflect",
3
- "version": "1.1.3",
3
+ "version": "1.2.0",
4
4
  "description": "Give Claude perfect memory of all your conversations - Semantic search across your entire Claude Desktop history",
5
5
  "keywords": [
6
6
  "claude",
@@ -26,11 +26,15 @@
26
26
  "main": "dist/index.js",
27
27
  "types": "dist/index.d.ts",
28
28
  "type": "module",
29
+ "bin": {
30
+ "claude-self-reflect": "./dist/cli.js"
31
+ },
29
32
  "files": [
30
33
  "dist",
31
34
  "src",
32
35
  "agents",
33
36
  "scripts/install-agent.js",
37
+ "scripts/setup-wizard.js",
34
38
  "README.md",
35
39
  "LICENSE",
36
40
  "config/claude-desktop-config.json"
@@ -0,0 +1,527 @@
1
+ #!/usr/bin/env node
2
+ import readline from 'readline';
3
+ import { execSync, spawn } from 'child_process';
4
+ import { existsSync, mkdirSync, writeFileSync, readFileSync } from 'fs';
5
+ import { join, dirname } from 'path';
6
+ import { fileURLToPath } from 'url';
7
+ import { homedir } from 'os';
8
+ import https from 'https';
9
+
10
+ const __filename = fileURLToPath(import.meta.url);
11
+ const __dirname = dirname(__filename);
12
+
13
+ const rl = readline.createInterface({
14
+ input: process.stdin,
15
+ output: process.stdout
16
+ });
17
+
18
+ // ANSI color codes
19
+ const colors = {
20
+ reset: '\x1b[0m',
21
+ green: '\x1b[32m',
22
+ yellow: '\x1b[33m',
23
+ blue: '\x1b[34m',
24
+ red: '\x1b[31m',
25
+ cyan: '\x1b[36m'
26
+ };
27
+
28
+ function question(prompt) {
29
+ return new Promise((resolve) => {
30
+ rl.question(prompt, resolve);
31
+ });
32
+ }
33
+
34
+ function success(message) {
35
+ console.log(`${colors.green}✅ ${message}${colors.reset}`);
36
+ }
37
+
38
+ function info(message) {
39
+ console.log(`${colors.blue}ℹ️ ${message}${colors.reset}`);
40
+ }
41
+
42
+ function warning(message) {
43
+ console.log(`${colors.yellow}⚠️ ${message}${colors.reset}`);
44
+ }
45
+
46
+ function error(message) {
47
+ console.log(`${colors.red}❌ ${message}${colors.reset}`);
48
+ }
49
+
50
+ function header(message) {
51
+ console.log(`\n${colors.cyan}${'='.repeat(60)}${colors.reset}`);
52
+ console.log(`${colors.cyan}${message}${colors.reset}`);
53
+ console.log(`${colors.cyan}${'='.repeat(60)}${colors.reset}\n`);
54
+ }
55
+
56
+ async function checkCommand(command) {
57
+ try {
58
+ execSync(`which ${command}`, { stdio: 'ignore' });
59
+ return true;
60
+ } catch {
61
+ return false;
62
+ }
63
+ }
64
+
65
+ async function checkDocker() {
66
+ if (!await checkCommand('docker')) {
67
+ return { installed: false };
68
+ }
69
+
70
+ try {
71
+ execSync('docker info', { stdio: 'ignore' });
72
+ return { installed: true, running: true };
73
+ } catch {
74
+ return { installed: true, running: false };
75
+ }
76
+ }
77
+
78
+ async function checkPython() {
79
+ const commands = ['python3', 'python'];
80
+ for (const cmd of commands) {
81
+ if (await checkCommand(cmd)) {
82
+ try {
83
+ const version = execSync(`${cmd} --version`, { encoding: 'utf8' }).trim();
84
+ return { installed: true, command: cmd, version };
85
+ } catch {}
86
+ }
87
+ }
88
+ return { installed: false };
89
+ }
90
+
91
+ async function validateApiKey(provider, apiKey) {
92
+ return new Promise((resolve) => {
93
+ if (!apiKey || apiKey.length < 10) {
94
+ resolve(false);
95
+ return;
96
+ }
97
+
98
+ let options;
99
+ switch (provider) {
100
+ case 'voyage':
101
+ options = {
102
+ hostname: 'api.voyageai.com',
103
+ path: '/v1/models',
104
+ method: 'GET',
105
+ headers: {
106
+ 'Authorization': `Bearer ${apiKey}`
107
+ }
108
+ };
109
+ break;
110
+ case 'openai':
111
+ options = {
112
+ hostname: 'api.openai.com',
113
+ path: '/v1/models',
114
+ method: 'GET',
115
+ headers: {
116
+ 'Authorization': `Bearer ${apiKey}`
117
+ }
118
+ };
119
+ break;
120
+ case 'gemini':
121
+ // Gemini uses a different validation approach
122
+ resolve(apiKey.startsWith('AI') && apiKey.length > 20);
123
+ return;
124
+ default:
125
+ resolve(true);
126
+ return;
127
+ }
128
+
129
+ const req = https.request(options, (res) => {
130
+ resolve(res.statusCode === 200);
131
+ });
132
+
133
+ req.on('error', () => resolve(false));
134
+ req.setTimeout(5000, () => {
135
+ req.destroy();
136
+ resolve(false);
137
+ });
138
+ req.end();
139
+ });
140
+ }
141
+
142
+ async function setupQdrant() {
143
+ header('Setting up Qdrant Vector Database');
144
+
145
+ const docker = await checkDocker();
146
+
147
+ if (!docker.installed) {
148
+ error('Docker is not installed');
149
+ console.log('\nTo install Docker:');
150
+ console.log('1. Visit https://docs.docker.com/get-docker/');
151
+ console.log('2. Download Docker Desktop for your platform');
152
+ console.log('3. Run the installer and start Docker');
153
+ console.log('4. Run this setup again\n');
154
+
155
+ const proceed = await question('Would you like to continue without Docker? (y/n): ');
156
+ if (proceed.toLowerCase() !== 'y') {
157
+ return false;
158
+ }
159
+
160
+ warning('Continuing without vector database - search functionality will be limited');
161
+ return true;
162
+ }
163
+
164
+ if (!docker.running) {
165
+ error('Docker is installed but not running');
166
+ console.log('Please start Docker Desktop and run this setup again\n');
167
+ return false;
168
+ }
169
+
170
+ // Check if Qdrant is already running
171
+ try {
172
+ execSync('docker ps | grep qdrant', { stdio: 'ignore' });
173
+ success('Qdrant is already running');
174
+ return true;
175
+ } catch {
176
+ // Not running, let's start it
177
+ }
178
+
179
+ info('Starting Qdrant container...');
180
+ try {
181
+ execSync('docker run -d --name qdrant -p 6333:6333 --restart always qdrant/qdrant:latest', {
182
+ stdio: 'inherit'
183
+ });
184
+ success('Qdrant started successfully');
185
+ return true;
186
+ } catch (err) {
187
+ // Container might already exist but be stopped
188
+ try {
189
+ execSync('docker start qdrant', { stdio: 'inherit' });
190
+ success('Qdrant restarted successfully');
191
+ return true;
192
+ } catch {
193
+ error('Failed to start Qdrant');
194
+ return false;
195
+ }
196
+ }
197
+ }
198
+
199
+ async function selectEmbeddingProvider() {
200
+ header('Choose Your Embedding Provider');
201
+
202
+ console.log('Embedding models convert your conversations into searchable vectors.\n');
203
+
204
+ console.log(`${colors.green}1. Voyage AI (Recommended)${colors.reset}`);
205
+ console.log(' ✅ 200M tokens FREE - covers most users completely');
206
+ console.log(' ✅ Best quality for conversation search');
207
+ console.log(' ✅ Only $0.02/1M tokens after free tier\n');
208
+
209
+ console.log(`${colors.blue}2. Google Gemini${colors.reset}`);
210
+ console.log(' ✅ Completely FREE (unlimited usage)');
211
+ console.log(' ⚠️ Your data used to improve Google products');
212
+ console.log(' ✅ Good multilingual support\n');
213
+
214
+ console.log(`${colors.yellow}3. Local Processing${colors.reset}`);
215
+ console.log(' ✅ Completely FREE, works offline');
216
+ console.log(' ✅ No API keys, no data sharing');
217
+ console.log(' ⚠️ Lower quality results, slower processing\n');
218
+
219
+ console.log(`${colors.cyan}4. OpenAI${colors.reset}`);
220
+ console.log(' ❌ No free tier');
221
+ console.log(' ✅ $0.02/1M tokens (same as Voyage paid)');
222
+ console.log(' ✅ Good quality, established ecosystem\n');
223
+
224
+ const choice = await question('Enter your choice (1-4): ');
225
+
226
+ switch (choice) {
227
+ case '1': return 'voyage';
228
+ case '2': return 'gemini';
229
+ case '3': return 'local';
230
+ case '4': return 'openai';
231
+ default:
232
+ warning('Invalid choice, defaulting to Voyage AI');
233
+ return 'voyage';
234
+ }
235
+ }
236
+
237
+ async function getApiKey(provider) {
238
+ if (provider === 'local') return null;
239
+
240
+ const urls = {
241
+ voyage: 'https://dash.voyageai.com/',
242
+ gemini: 'https://ai.google.dev/gemini-api/docs',
243
+ openai: 'https://platform.openai.com/api-keys'
244
+ };
245
+
246
+ console.log(`\nTo get your API key, visit: ${colors.blue}${urls[provider]}${colors.reset}`);
247
+
248
+ let apiKey;
249
+ let valid = false;
250
+
251
+ while (!valid) {
252
+ apiKey = await question(`Enter your ${provider.toUpperCase()} API key: `);
253
+
254
+ if (!apiKey) {
255
+ const skip = await question('Skip API key for now? (y/n): ');
256
+ if (skip.toLowerCase() === 'y') {
257
+ return null;
258
+ }
259
+ continue;
260
+ }
261
+
262
+ info('Validating API key...');
263
+ valid = await validateApiKey(provider, apiKey);
264
+
265
+ if (valid) {
266
+ success('API key validated successfully');
267
+ } else {
268
+ error('Invalid API key. Please check and try again.');
269
+ }
270
+ }
271
+
272
+ return apiKey;
273
+ }
274
+
275
+ async function setupPython() {
276
+ header('Setting up Python Dependencies');
277
+
278
+ const python = await checkPython();
279
+
280
+ if (!python.installed) {
281
+ error('Python is not installed');
282
+ console.log('\nTo install Python:');
283
+ console.log('1. Visit https://www.python.org/downloads/');
284
+ console.log('2. Download Python 3.8 or later');
285
+ console.log('3. Run the installer\n');
286
+ return false;
287
+ }
288
+
289
+ success(`Found ${python.version}`);
290
+
291
+ // Clone the repository if needed
292
+ const repoPath = join(homedir(), '.claude-self-reflect');
293
+
294
+ if (!existsSync(repoPath)) {
295
+ info('Downloading import scripts...');
296
+ try {
297
+ execSync(`git clone https://github.com/ramakay/claude-self-reflect.git "${repoPath}"`, {
298
+ stdio: 'inherit'
299
+ });
300
+ success('Downloaded import scripts');
301
+ } catch {
302
+ error('Failed to download import scripts');
303
+ return false;
304
+ }
305
+ }
306
+
307
+ // Install Python dependencies
308
+ info('Installing Python dependencies...');
309
+ const requirementsPath = join(repoPath, 'scripts', 'requirements.txt');
310
+
311
+ try {
312
+ execSync(`${python.command} -m pip install -r "${requirementsPath}"`, {
313
+ stdio: 'inherit',
314
+ cwd: repoPath
315
+ });
316
+ success('Python dependencies installed');
317
+ return { command: python.command, repoPath };
318
+ } catch {
319
+ error('Failed to install Python dependencies');
320
+ warning('You may need to install pip or run with administrator privileges');
321
+ return false;
322
+ }
323
+ }
324
+
325
+ async function saveConfiguration(config) {
326
+ const envPath = join(homedir(), '.claude-self-reflect', '.env');
327
+ const envDir = dirname(envPath);
328
+
329
+ if (!existsSync(envDir)) {
330
+ mkdirSync(envDir, { recursive: true });
331
+ }
332
+
333
+ let envContent = '# Claude Self-Reflect Configuration\n';
334
+ envContent += '# Generated by setup wizard\n\n';
335
+
336
+ if (config.provider === 'voyage' && config.apiKey) {
337
+ envContent += `VOYAGE_API_KEY="${config.apiKey}"\n`;
338
+ } else if (config.provider === 'gemini' && config.apiKey) {
339
+ envContent += `GEMINI_API_KEY="${config.apiKey}"\n`;
340
+ } else if (config.provider === 'openai' && config.apiKey) {
341
+ envContent += `OPENAI_API_KEY="${config.apiKey}"\n`;
342
+ } else if (config.provider === 'local') {
343
+ envContent += 'USE_LOCAL_EMBEDDINGS=true\n';
344
+ }
345
+
346
+ envContent += 'QDRANT_URL=http://localhost:6333\n';
347
+
348
+ writeFileSync(envPath, envContent);
349
+ success(`Configuration saved to ${envPath}`);
350
+ }
351
+
352
+ async function runImport(pythonConfig, provider, apiKey) {
353
+ header('Importing Conversation History');
354
+
355
+ const claudeLogsPath = join(homedir(), '.claude', 'projects');
356
+
357
+ if (!existsSync(claudeLogsPath)) {
358
+ warning('No Claude conversation logs found at ~/.claude/projects');
359
+ console.log('Make sure you have used Claude Desktop and have some conversations');
360
+ return;
361
+ }
362
+
363
+ info('Scanning for conversation files...');
364
+ const scriptPath = join(pythonConfig.repoPath, 'scripts', 'import-openai-enhanced.py');
365
+
366
+ // Set environment variables for the import
367
+ const env = { ...process.env };
368
+ if (provider === 'voyage' && apiKey) {
369
+ env.VOYAGE_API_KEY = apiKey;
370
+ } else if (provider === 'gemini' && apiKey) {
371
+ env.GEMINI_API_KEY = apiKey;
372
+ } else if (provider === 'openai' && apiKey) {
373
+ env.OPENAI_API_KEY = apiKey;
374
+ } else if (provider === 'local') {
375
+ env.USE_LOCAL_EMBEDDINGS = 'true';
376
+ }
377
+
378
+ const importProcess = spawn(pythonConfig.command, [scriptPath], {
379
+ cwd: pythonConfig.repoPath,
380
+ env,
381
+ stdio: 'inherit'
382
+ });
383
+
384
+ return new Promise((resolve) => {
385
+ importProcess.on('close', (code) => {
386
+ if (code === 0) {
387
+ success('Import completed successfully');
388
+ resolve(true);
389
+ } else {
390
+ error('Import failed');
391
+ resolve(false);
392
+ }
393
+ });
394
+ });
395
+ }
396
+
397
+ async function setupClaudeDesktop() {
398
+ header('Configure Claude Desktop (Optional)');
399
+
400
+ console.log('To use this with Claude Desktop, add the following to your config:\n');
401
+
402
+ const config = {
403
+ mcpServers: {
404
+ 'claude-self-reflect': {
405
+ command: 'npx',
406
+ args: ['claude-self-reflect'],
407
+ env: {
408
+ QDRANT_URL: 'http://localhost:6333'
409
+ }
410
+ }
411
+ }
412
+ };
413
+
414
+ console.log(JSON.stringify(config, null, 2));
415
+
416
+ console.log('\nConfig file location:');
417
+ console.log('- macOS: ~/Library/Application Support/Claude/claude_desktop_config.json');
418
+ console.log('- Windows: %APPDATA%\\Claude\\claude_desktop_config.json');
419
+ console.log('- Linux: ~/.config/Claude/claude_desktop_config.json\n');
420
+
421
+ const configure = await question('Would you like to automatically configure Claude Desktop? (y/n): ');
422
+
423
+ if (configure.toLowerCase() === 'y') {
424
+ // Detect platform and find config file
425
+ const platform = process.platform;
426
+ let configPath;
427
+
428
+ if (platform === 'darwin') {
429
+ configPath = join(homedir(), 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json');
430
+ } else if (platform === 'win32') {
431
+ configPath = join(process.env.APPDATA, 'Claude', 'claude_desktop_config.json');
432
+ } else {
433
+ configPath = join(homedir(), '.config', 'Claude', 'claude_desktop_config.json');
434
+ }
435
+
436
+ try {
437
+ let existingConfig = {};
438
+ if (existsSync(configPath)) {
439
+ existingConfig = JSON.parse(readFileSync(configPath, 'utf8'));
440
+ }
441
+
442
+ // Merge configurations
443
+ existingConfig.mcpServers = existingConfig.mcpServers || {};
444
+ existingConfig.mcpServers['claude-self-reflect'] = config.mcpServers['claude-self-reflect'];
445
+
446
+ // Ensure directory exists
447
+ mkdirSync(dirname(configPath), { recursive: true });
448
+
449
+ // Write config
450
+ writeFileSync(configPath, JSON.stringify(existingConfig, null, 2));
451
+ success('Claude Desktop configured successfully');
452
+ info('Restart Claude Desktop to use the new configuration');
453
+ } catch (err) {
454
+ error('Failed to configure Claude Desktop automatically');
455
+ console.log('Please add the configuration manually');
456
+ }
457
+ }
458
+ }
459
+
460
+ async function main() {
461
+ console.clear();
462
+ header('🚀 Claude Self-Reflect Setup Wizard');
463
+
464
+ console.log('This wizard will help you set up Claude Self-Reflect in just a few minutes.\n');
465
+
466
+ // Step 1: Check and setup Qdrant
467
+ const qdrantOk = await setupQdrant();
468
+ if (!qdrantOk) {
469
+ error('Setup incomplete. Please fix the issues and try again.');
470
+ rl.close();
471
+ process.exit(1);
472
+ }
473
+
474
+ // Step 2: Select embedding provider
475
+ const provider = await selectEmbeddingProvider();
476
+
477
+ // Step 3: Get API key
478
+ const apiKey = await getApiKey(provider);
479
+
480
+ // Step 4: Setup Python
481
+ const pythonConfig = await setupPython();
482
+ if (!pythonConfig) {
483
+ error('Setup incomplete. Please fix the issues and try again.');
484
+ rl.close();
485
+ process.exit(1);
486
+ }
487
+
488
+ // Step 5: Save configuration
489
+ await saveConfiguration({ provider, apiKey });
490
+
491
+ // Step 6: Run import
492
+ if (apiKey || provider === 'local') {
493
+ const runImportNow = await question('\nWould you like to import your conversation history now? (y/n): ');
494
+ if (runImportNow.toLowerCase() === 'y') {
495
+ await runImport(pythonConfig, provider, apiKey);
496
+ }
497
+ }
498
+
499
+ // Step 7: Configure Claude Desktop
500
+ await setupClaudeDesktop();
501
+
502
+ // Done!
503
+ header('✨ Setup Complete!');
504
+
505
+ console.log('Next steps:');
506
+ console.log('1. If using Claude Code, the reflection agent is already available');
507
+ console.log('2. Try asking: "Find our previous discussions about [topic]"');
508
+ console.log('3. To re-run import later: python scripts/import-openai-enhanced.py\n');
509
+
510
+ success('Happy reflecting! 🎉');
511
+
512
+ rl.close();
513
+ }
514
+
515
+ // Handle errors gracefully
516
+ process.on('unhandledRejection', (error) => {
517
+ console.error('\nSetup failed with error:', error);
518
+ rl.close();
519
+ process.exit(1);
520
+ });
521
+
522
+ // Run the wizard
523
+ main().catch((error) => {
524
+ console.error('\nSetup failed:', error);
525
+ rl.close();
526
+ process.exit(1);
527
+ });
package/src/cli.ts ADDED
@@ -0,0 +1,56 @@
1
+ #!/usr/bin/env node
2
+ import { spawn } from 'child_process';
3
+ import { fileURLToPath } from 'url';
4
+ import { dirname, join } from 'path';
5
+ import { readFileSync } from 'fs';
6
+
7
+ const __filename = fileURLToPath(import.meta.url);
8
+ const __dirname = dirname(__filename);
9
+
10
+ // Handle command line arguments
11
+ const args = process.argv.slice(2);
12
+ const command = args[0];
13
+
14
+ if (command === 'setup') {
15
+ // Run the setup wizard
16
+ const setupPath = join(__dirname, '..', 'scripts', 'setup-wizard.js');
17
+ const child = spawn('node', [setupPath], {
18
+ stdio: 'inherit'
19
+ });
20
+
21
+ child.on('error', (error) => {
22
+ console.error('Failed to start setup wizard:', error);
23
+ process.exit(1);
24
+ });
25
+
26
+ child.on('exit', (code) => {
27
+ process.exit(code || 0);
28
+ });
29
+ } else if (command === '--version' || command === '-v') {
30
+ // Read package.json to get version
31
+ const packagePath = join(__dirname, '..', 'package.json');
32
+ const pkg = JSON.parse(readFileSync(packagePath, 'utf8'));
33
+ console.log(pkg.version);
34
+ } else if (command === '--help' || command === '-h' || !command) {
35
+ console.log(`
36
+ Claude Self-Reflect - Give Claude perfect memory of all your conversations
37
+
38
+ Usage:
39
+ claude-self-reflect <command>
40
+
41
+ Commands:
42
+ setup Run the interactive setup wizard
43
+
44
+ Options:
45
+ --version Show version number
46
+ --help Show this help message
47
+
48
+ Examples:
49
+ claude-self-reflect setup # Run interactive setup
50
+ npx claude-self-reflect setup # Run without installing globally
51
+ `);
52
+ } else {
53
+ console.error(`Unknown command: ${command}`);
54
+ console.error('Run "claude-self-reflect --help" for usage information');
55
+ process.exit(1);
56
+ }