claude-conversation-memory-mcp 0.1.0 โ†’ 0.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/README.md CHANGED
@@ -93,6 +93,94 @@ Start Claude Code CLI and ask:
93
93
 
94
94
  If you see a response like "Indexed 3 conversations with 1247 messages", it's working!
95
95
 
96
+ ## ๐Ÿ–ฅ๏ธ Standalone CLI / REPL Mode
97
+
98
+ Beyond the MCP server, this package includes a powerful **standalone CLI** for managing your conversation memory directly from the terminal.
99
+
100
+ ### Three Modes of Operation
101
+
102
+ **1. Interactive REPL Mode** (Default)
103
+ ```bash
104
+ claude-conversation-memory-mcp
105
+ # Starts interactive shell with 40+ commands
106
+ ```
107
+
108
+ **2. Single Command Mode**
109
+ ```bash
110
+ claude-conversation-memory-mcp status
111
+ claude-conversation-memory-mcp "search authentication"
112
+ claude-conversation-memory-mcp mistakes --limit 5
113
+ ```
114
+
115
+ **3. MCP Server Mode** (Used by Claude Code CLI)
116
+ ```bash
117
+ claude-conversation-memory-mcp --server
118
+ # Or automatically via stdio from Claude Code CLI
119
+ ```
120
+
121
+ ### Quick CLI Examples
122
+
123
+ ```bash
124
+ # View database status
125
+ claude-conversation-memory-mcp status
126
+
127
+ # Index conversations
128
+ claude-conversation-memory-mcp index --include-mcp
129
+
130
+ # Search for topics
131
+ claude-conversation-memory-mcp "search database migration" --limit 3
132
+
133
+ # Find past mistakes
134
+ claude-conversation-memory-mcp mistakes "async" --type logic_error
135
+
136
+ # Check file context before editing
137
+ claude-conversation-memory-mcp check src/auth.ts
138
+
139
+ # Configure embedding model
140
+ claude-conversation-memory-mcp config
141
+ claude-conversation-memory-mcp set model mxbai-embed-large
142
+ claude-conversation-memory-mcp set dimensions 1024
143
+
144
+ # View help
145
+ claude-conversation-memory-mcp help
146
+ claude-conversation-memory-mcp "help search"
147
+ ```
148
+
149
+ ### Configuration Management
150
+
151
+ The CLI includes built-in commands for managing embedding models and dimensions:
152
+
153
+ ```bash
154
+ # View current configuration
155
+ claude-conversation-memory-mcp config
156
+
157
+ # Switch to Ollama with mxbai-embed-large (1024 dimensions)
158
+ claude-conversation-memory-mcp set provider ollama
159
+ claude-conversation-memory-mcp set model mxbai-embed-large
160
+ claude-conversation-memory-mcp set dimensions 1024
161
+
162
+ # Switch to Transformers.js (offline, no setup)
163
+ claude-conversation-memory-mcp set provider transformers
164
+ claude-conversation-memory-mcp set model Xenova/all-MiniLM-L6-v2
165
+ claude-conversation-memory-mcp set dimensions 384
166
+
167
+ # Get specific config value
168
+ claude-conversation-memory-mcp get provider
169
+ ```
170
+
171
+ ### Available Commands
172
+
173
+ - **๐Ÿ“ฅ Indexing**: `index`, `reindex`
174
+ - **๐Ÿ” Search**: `search`, `decisions`, `mistakes`, `similar`
175
+ - **๐Ÿ“‹ Files**: `check`, `history`
176
+ - **๐Ÿ”— Git**: `commits`
177
+ - **๐Ÿ“ Other**: `requirements`, `tools`, `docs`
178
+ - **โ„น๏ธ Info**: `status`, `version`, `help`
179
+ - **โš™๏ธ Config**: `config`, `get`, `set`
180
+ - **๐Ÿงน Maintenance**: `vacuum`, `reset`
181
+
182
+ **๐Ÿ‘‰ See [Complete CLI Guide](docs/CLI-USAGE.md) for all commands, examples, and workflows**
183
+
96
184
  ## ๐ŸŽฏ Usage Examples
97
185
 
98
186
  ### First Time Setup
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Command execution and parsing for CLI
3
+ */
4
+ import { ToolHandlers } from "../tools/ToolHandlers.js";
5
+ /**
6
+ * Execute a command
7
+ */
8
+ export declare function executeCommand(input: string, handlers: ToolHandlers): Promise<string | null>;
9
+ //# sourceMappingURL=commands.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../src/cli/commands.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAqCxD;;GAEG;AACH,wBAAsB,cAAc,CAClC,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,YAAY,GACrB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA4JxB"}
@@ -0,0 +1,572 @@
1
+ /**
2
+ * Command execution and parsing for CLI
3
+ */
4
+ import chalk from "chalk";
5
+ import Table from "cli-table3";
6
+ import { getSQLiteManager } from "../storage/SQLiteManager.js";
7
+ import { showHelp, showCommandHelp } from "./help.js";
8
+ import { ConfigManager } from "../embeddings/ConfigManager.js";
9
+ /**
10
+ * Parse command line arguments
11
+ */
12
+ function parseArgs(input) {
13
+ const parts = input.match(/(?:[^\s"]+|"[^"]*")+/g) || [];
14
+ const command = parts[0] || "";
15
+ const rest = parts.slice(1);
16
+ const args = [];
17
+ const options = {};
18
+ for (let i = 0; i < rest.length; i++) {
19
+ const part = rest[i];
20
+ if (part.startsWith("--")) {
21
+ const key = part.slice(2);
22
+ const nextPart = rest[i + 1];
23
+ if (nextPart && !nextPart.startsWith("--")) {
24
+ options[key] = nextPart.replace(/^"(.*)"$/, "$1");
25
+ i++;
26
+ }
27
+ else {
28
+ options[key] = true;
29
+ }
30
+ }
31
+ else {
32
+ args.push(part.replace(/^"(.*)"$/, "$1"));
33
+ }
34
+ }
35
+ return { command, args, options };
36
+ }
37
+ /**
38
+ * Execute a command
39
+ */
40
+ export async function executeCommand(input, handlers) {
41
+ const { command, args, options } = parseArgs(input);
42
+ // Handle exit commands
43
+ if (command === "exit" || command === "quit" || command === "q") {
44
+ return "exit";
45
+ }
46
+ // Handle clear
47
+ if (command === "clear") {
48
+ return "clear";
49
+ }
50
+ // Handle help
51
+ if (command === "help" || command === "?") {
52
+ if (args.length > 0) {
53
+ return showCommandHelp(args[0]);
54
+ }
55
+ return showHelp();
56
+ }
57
+ // Handle version
58
+ if (command === "version") {
59
+ return chalk.cyan("Claude Conversation Memory v0.2.0");
60
+ }
61
+ // Handle status/stats
62
+ if (command === "status" || command === "stats") {
63
+ return await handleStatus();
64
+ }
65
+ // Handle index
66
+ if (command === "index") {
67
+ return await handleIndex(handlers, options);
68
+ }
69
+ // Handle reindex
70
+ if (command === "reindex") {
71
+ return await handleReindex(handlers, options);
72
+ }
73
+ // Handle search
74
+ if (command === "search" || command === "find") {
75
+ if (args.length === 0) {
76
+ return chalk.yellow("Usage: search <query> [options]");
77
+ }
78
+ return await handleSearch(handlers, args.join(" "), options);
79
+ }
80
+ // Handle decisions
81
+ if (command === "decisions" || command === "why") {
82
+ if (args.length === 0) {
83
+ return chalk.yellow("Usage: decisions <topic> [options]");
84
+ }
85
+ return await handleDecisions(handlers, args.join(" "), options);
86
+ }
87
+ // Handle mistakes
88
+ if (command === "mistakes" || command === "errors") {
89
+ if (args.length === 0) {
90
+ return chalk.yellow("Usage: mistakes <query> [options]");
91
+ }
92
+ return await handleMistakes(handlers, args.join(" "), options);
93
+ }
94
+ // Handle check
95
+ if (command === "check") {
96
+ if (args.length === 0) {
97
+ return chalk.yellow("Usage: check <file>");
98
+ }
99
+ return await handleCheck(handlers, args[0]);
100
+ }
101
+ // Handle history/evolution
102
+ if (command === "history" || command === "evolution") {
103
+ if (args.length === 0) {
104
+ return chalk.yellow("Usage: history <file> [options]");
105
+ }
106
+ return await handleHistory(handlers, args[0], options);
107
+ }
108
+ // Handle commits/git
109
+ if (command === "commits" || command === "git") {
110
+ return await handleCommits(handlers, args.join(" "), options);
111
+ }
112
+ // Handle similar/related
113
+ if (command === "similar" || command === "related") {
114
+ if (args.length === 0) {
115
+ return chalk.yellow("Usage: similar <query> [options]");
116
+ }
117
+ return await handleSimilar(handlers, args.join(" "), options);
118
+ }
119
+ // Handle requirements/deps
120
+ if (command === "requirements" || command === "deps") {
121
+ if (args.length === 0) {
122
+ return chalk.yellow("Usage: requirements <component> [options]");
123
+ }
124
+ return await handleRequirements(handlers, args.join(" "), options);
125
+ }
126
+ // Handle tools
127
+ if (command === "tools" || command === "history-tools") {
128
+ return await handleTools(handlers, options);
129
+ }
130
+ // Handle docs/generate
131
+ if (command === "docs" || command === "generate") {
132
+ return await handleDocs(handlers, options);
133
+ }
134
+ // Handle reset
135
+ if (command === "reset") {
136
+ return await handleReset();
137
+ }
138
+ // Handle vacuum
139
+ if (command === "vacuum") {
140
+ return await handleVacuum();
141
+ }
142
+ // Handle config
143
+ if (command === "config") {
144
+ if (args.length === 0) {
145
+ return handleConfigShow();
146
+ }
147
+ else if (args.length === 2) {
148
+ return handleConfigSet(args[0], args[1]);
149
+ }
150
+ else {
151
+ return chalk.yellow("Usage: config (show current config)\n config <key> <value> (set config value)");
152
+ }
153
+ }
154
+ // Handle get
155
+ if (command === "get") {
156
+ if (args.length === 0) {
157
+ return chalk.yellow("Usage: get <key>");
158
+ }
159
+ return handleConfigGet(args[0]);
160
+ }
161
+ // Handle set
162
+ if (command === "set") {
163
+ if (args.length < 2) {
164
+ return chalk.yellow("Usage: set <key> <value>");
165
+ }
166
+ return handleConfigSet(args[0], args[1]);
167
+ }
168
+ // Handle commands
169
+ if (command === "commands") {
170
+ return showHelp();
171
+ }
172
+ // Unknown command
173
+ return chalk.yellow(`Unknown command: ${command}\nType 'help' for available commands.`);
174
+ }
175
+ /**
176
+ * Handle status command
177
+ */
178
+ async function handleStatus() {
179
+ const dbManager = getSQLiteManager();
180
+ const db = dbManager.getDatabase();
181
+ const stats = dbManager.getStats();
182
+ const dbPath = stats.dbPath.replace(process.env.HOME || "", "~");
183
+ // Query counts from database
184
+ const conversations = db.prepare("SELECT COUNT(*) as count FROM conversations").get().count;
185
+ const messages = db.prepare("SELECT COUNT(*) as count FROM messages").get().count;
186
+ const decisions = db.prepare("SELECT COUNT(*) as count FROM decisions").get().count;
187
+ const mistakes = db.prepare("SELECT COUNT(*) as count FROM mistakes").get().count;
188
+ const commits = db.prepare("SELECT COUNT(*) as count FROM git_commits").get().count;
189
+ const embeddings = db.prepare("SELECT COUNT(*) as count FROM message_embeddings").get().count;
190
+ const table = new Table({
191
+ head: [chalk.cyan("Metric"), chalk.cyan("Value")],
192
+ colWidths: [30, 30],
193
+ });
194
+ table.push(["Database", dbPath], ["Conversations", String(conversations)], ["Messages", String(messages)], ["Decisions", String(decisions)], ["Mistakes", String(mistakes)], ["Git Commits", String(commits)], ["Embeddings", String(embeddings)], ["Semantic Search", embeddings > 0 ? chalk.green("enabled") : chalk.yellow("disabled")]);
195
+ let output = "\n" + table.toString() + "\n";
196
+ if (conversations === 0) {
197
+ output += "\n" + chalk.yellow("โš ๏ธ No conversations indexed yet. Run 'index' to get started.\n");
198
+ }
199
+ return output;
200
+ }
201
+ /**
202
+ * Handle index command
203
+ */
204
+ async function handleIndex(handlers, options) {
205
+ const args = {
206
+ project_path: typeof options.project === "string" ? options.project : process.cwd(),
207
+ };
208
+ if (typeof options.session === "string") {
209
+ args.session_id = options.session;
210
+ }
211
+ if (options["exclude-mcp"]) {
212
+ args.exclude_mcp_conversations = "all-mcp";
213
+ }
214
+ if (options["include-mcp"]) {
215
+ args.exclude_mcp_conversations = false;
216
+ }
217
+ if (options["no-git"]) {
218
+ args.enable_git = false;
219
+ }
220
+ if (options.thinking) {
221
+ args.include_thinking = true;
222
+ }
223
+ console.log(chalk.blue("Indexing conversations..."));
224
+ const result = await handlers.indexConversations(args);
225
+ return chalk.green(`\nโœ“ Indexing complete!\n\n${JSON.stringify(result, null, 2)}`);
226
+ }
227
+ /**
228
+ * Handle reindex command
229
+ */
230
+ async function handleReindex(handlers, options) {
231
+ console.log(chalk.yellow("โš ๏ธ This will clear all indexed data and re-index."));
232
+ console.log(chalk.yellow("Press Ctrl+C to cancel, or wait 3 seconds to continue..."));
233
+ await new Promise((resolve) => setTimeout(resolve, 3000));
234
+ // Clear database
235
+ const db = getSQLiteManager().getDatabase();
236
+ db.exec("DELETE FROM conversations");
237
+ db.exec("DELETE FROM messages");
238
+ db.exec("DELETE FROM decisions");
239
+ db.exec("DELETE FROM mistakes");
240
+ db.exec("DELETE FROM git_commits");
241
+ console.log(chalk.blue("Database cleared. Indexing conversations..."));
242
+ return await handleIndex(handlers, options);
243
+ }
244
+ /**
245
+ * Handle search command
246
+ */
247
+ async function handleSearch(handlers, query, options) {
248
+ const args = { query };
249
+ if (typeof options.limit === "string") {
250
+ args.limit = parseInt(options.limit, 10);
251
+ }
252
+ const result = await handlers.searchConversations(args);
253
+ if (!result.results || result.results.length === 0) {
254
+ return chalk.yellow(`No results found for: ${query}`);
255
+ }
256
+ let output = chalk.green(`\nFound ${result.results.length} results:\n\n`);
257
+ result.results.forEach((r, i) => {
258
+ output += chalk.cyan(`${i + 1}. `) + `[${r.timestamp}] Session ${r.conversation_id.slice(0, 8)}\n`;
259
+ output += ` ${r.snippet.slice(0, 200)}${r.snippet.length > 200 ? "..." : ""}\n`;
260
+ output += chalk.gray(` Similarity: ${(r.similarity * 100).toFixed(1)}%\n\n`);
261
+ });
262
+ return output;
263
+ }
264
+ /**
265
+ * Handle decisions command
266
+ */
267
+ async function handleDecisions(handlers, query, options) {
268
+ const args = { query };
269
+ if (typeof options.file === "string") {
270
+ args.file_path = options.file;
271
+ }
272
+ if (typeof options.limit === "string") {
273
+ args.limit = parseInt(options.limit, 10);
274
+ }
275
+ const result = await handlers.getDecisions(args);
276
+ if (!result.decisions || result.decisions.length === 0) {
277
+ return chalk.yellow(`No decisions found for: ${query}`);
278
+ }
279
+ let output = chalk.green(`\nFound ${result.decisions.length} decisions:\n\n`);
280
+ result.decisions.forEach((d, i) => {
281
+ output += chalk.cyan(`${i + 1}. ${d.decision_text}\n`);
282
+ output += ` Date: ${d.timestamp}\n`;
283
+ output += ` Rationale: ${d.rationale || "N/A"}\n`;
284
+ if (d.alternatives_considered && d.alternatives_considered.length > 0) {
285
+ output += ` Alternatives: ${d.alternatives_considered.join(", ")}\n`;
286
+ }
287
+ output += "\n";
288
+ });
289
+ return output;
290
+ }
291
+ /**
292
+ * Handle mistakes command
293
+ */
294
+ async function handleMistakes(handlers, query, options) {
295
+ const args = { query };
296
+ if (typeof options.type === "string") {
297
+ args.mistake_type = options.type;
298
+ }
299
+ if (typeof options.limit === "string") {
300
+ args.limit = parseInt(options.limit, 10);
301
+ }
302
+ const result = await handlers.searchMistakes(args);
303
+ if (!result.mistakes || result.mistakes.length === 0) {
304
+ return chalk.yellow(`No mistakes found for: ${query}`);
305
+ }
306
+ let output = chalk.green(`\nFound ${result.mistakes.length} mistakes:\n\n`);
307
+ result.mistakes.forEach((m, i) => {
308
+ output += chalk.red(`${i + 1}. [${m.mistake_type}] ${m.what_went_wrong}\n`);
309
+ output += ` Date: ${m.timestamp}\n`;
310
+ output += chalk.green(` Fix: ${m.correction || m.user_correction_message || "N/A"}\n\n`);
311
+ });
312
+ return output;
313
+ }
314
+ /**
315
+ * Handle check command
316
+ */
317
+ async function handleCheck(handlers, filePath) {
318
+ const result = await handlers.checkBeforeModify({ file_path: filePath });
319
+ return chalk.green(`\nContext for: ${filePath}\n\n`) + JSON.stringify(result, null, 2);
320
+ }
321
+ /**
322
+ * Handle history command
323
+ */
324
+ async function handleHistory(handlers, filePath, options) {
325
+ const args = { file_path: filePath };
326
+ if (options["no-commits"]) {
327
+ args.include_commits = false;
328
+ }
329
+ if (options["no-decisions"]) {
330
+ args.include_decisions = false;
331
+ }
332
+ const result = await handlers.getFileEvolution(args);
333
+ return chalk.green(`\nFile evolution for: ${filePath}\n\n`) + JSON.stringify(result, null, 2);
334
+ }
335
+ /**
336
+ * Handle commits command
337
+ */
338
+ async function handleCommits(handlers, query, options) {
339
+ const args = {};
340
+ if (query) {
341
+ args.query = query;
342
+ }
343
+ if (typeof options.conversation === "string") {
344
+ args.conversation_id = options.conversation;
345
+ }
346
+ if (typeof options.limit === "string") {
347
+ args.limit = parseInt(options.limit, 10);
348
+ }
349
+ const result = await handlers.linkCommitsToConversations(args);
350
+ return chalk.green("\nCommits linked to conversations:\n\n") + JSON.stringify(result, null, 2);
351
+ }
352
+ /**
353
+ * Handle similar command
354
+ */
355
+ async function handleSimilar(handlers, query, options) {
356
+ const args = { query };
357
+ if (typeof options.limit === "string") {
358
+ args.limit = parseInt(options.limit, 10);
359
+ }
360
+ const result = await handlers.findSimilarSessions(args);
361
+ return chalk.green("\nSimilar sessions:\n\n") + JSON.stringify(result, null, 2);
362
+ }
363
+ /**
364
+ * Handle requirements command
365
+ */
366
+ async function handleRequirements(handlers, component, options) {
367
+ const args = { component };
368
+ if (typeof options.type === "string") {
369
+ args.type = options.type;
370
+ }
371
+ const result = await handlers.getRequirements(args);
372
+ return chalk.green(`\nRequirements for: ${component}\n\n`) + JSON.stringify(result, null, 2);
373
+ }
374
+ /**
375
+ * Handle tools command
376
+ */
377
+ async function handleTools(handlers, options) {
378
+ const args = {};
379
+ if (typeof options.file === "string") {
380
+ args.file_path = options.file;
381
+ }
382
+ if (typeof options.tool === "string") {
383
+ args.tool_name = options.tool;
384
+ }
385
+ if (typeof options.limit === "string") {
386
+ args.limit = parseInt(options.limit, 10);
387
+ }
388
+ const result = await handlers.getToolHistory(args);
389
+ return chalk.green("\nTool usage history:\n\n") + JSON.stringify(result, null, 2);
390
+ }
391
+ /**
392
+ * Handle docs command
393
+ */
394
+ async function handleDocs(handlers, options) {
395
+ const args = {
396
+ project_path: process.cwd(),
397
+ };
398
+ if (typeof options.scope === "string") {
399
+ args.scope = options.scope;
400
+ }
401
+ if (typeof options.module === "string") {
402
+ args.module_filter = options.module;
403
+ }
404
+ console.log(chalk.blue("Generating documentation..."));
405
+ const result = await handlers.generateDocumentation(args);
406
+ return chalk.green("\nโœ“ Documentation generated!\n\n") + JSON.stringify(result, null, 2);
407
+ }
408
+ /**
409
+ * Handle reset command
410
+ */
411
+ async function handleReset() {
412
+ console.log(chalk.red("โš ๏ธ WARNING: This will delete ALL indexed data!"));
413
+ console.log(chalk.yellow("Press Ctrl+C to cancel, or wait 5 seconds to continue..."));
414
+ await new Promise((resolve) => setTimeout(resolve, 5000));
415
+ const db = getSQLiteManager().getDatabase();
416
+ db.exec("DELETE FROM conversations");
417
+ db.exec("DELETE FROM messages");
418
+ db.exec("DELETE FROM decisions");
419
+ db.exec("DELETE FROM mistakes");
420
+ db.exec("DELETE FROM git_commits");
421
+ return chalk.green("\nโœ“ Database reset complete.\n");
422
+ }
423
+ /**
424
+ * Handle vacuum command
425
+ */
426
+ async function handleVacuum() {
427
+ const db = getSQLiteManager().getDatabase();
428
+ const beforeSize = db.prepare("PRAGMA page_count").get();
429
+ db.exec("VACUUM");
430
+ const afterSize = db.prepare("PRAGMA page_count").get();
431
+ const beforeKB = (beforeSize.page_count * 4096) / 1024;
432
+ const afterKB = (afterSize.page_count * 4096) / 1024;
433
+ return chalk.green(`\nโœ“ Database vacuumed: ${beforeKB.toFixed(1)}KB โ†’ ${afterKB.toFixed(1)}KB\n`);
434
+ }
435
+ /**
436
+ * Handle config show command
437
+ */
438
+ function handleConfigShow() {
439
+ const sources = ConfigManager.getConfigSources();
440
+ const configPath = ConfigManager.getConfigPath();
441
+ const configExists = ConfigManager.configExists();
442
+ let output = chalk.cyan("\n=== Embedding Configuration ===\n\n");
443
+ // Show effective config
444
+ output += chalk.bold("Current (Effective) Configuration:\n");
445
+ const table = new Table({
446
+ head: [chalk.cyan("Key"), chalk.cyan("Value")],
447
+ colWidths: [20, 50],
448
+ });
449
+ table.push(["Provider", sources.effective.provider], ["Model", sources.effective.model], ["Dimensions", String(sources.effective.dimensions || "auto")], ["Base URL", sources.effective.baseUrl || "N/A"], ["API Key", sources.effective.apiKey ? "***" + sources.effective.apiKey.slice(-4) : "N/A"]);
450
+ output += table.toString() + "\n\n";
451
+ // Show sources breakdown
452
+ output += chalk.bold("Configuration Sources:\n\n");
453
+ if (sources.home) {
454
+ output += chalk.green(`โœ“ Home Config: ${configPath}\n`);
455
+ output += ` Provider: ${sources.home.provider || "not set"}\n`;
456
+ output += ` Model: ${sources.home.model || "not set"}\n`;
457
+ output += ` Dimensions: ${sources.home.dimensions || "not set"}\n\n`;
458
+ }
459
+ else {
460
+ output += chalk.gray(` Home Config: ${configPath} (not found)\n\n`);
461
+ }
462
+ if (sources.project) {
463
+ output += chalk.green("โœ“ Project Config: .claude-memory-config.json\n");
464
+ output += ` Provider: ${sources.project.provider || "not set"}\n`;
465
+ output += ` Model: ${sources.project.model || "not set"}\n\n`;
466
+ }
467
+ if (Object.keys(sources.env).length > 0) {
468
+ output += chalk.green("โœ“ Environment Variables:\n");
469
+ if (sources.env.provider) {
470
+ output += ` EMBEDDING_PROVIDER=${sources.env.provider}\n`;
471
+ }
472
+ if (sources.env.model) {
473
+ output += ` EMBEDDING_MODEL=${sources.env.model}\n`;
474
+ }
475
+ if (sources.env.dimensions) {
476
+ output += ` EMBEDDING_DIMENSIONS=${sources.env.dimensions}\n`;
477
+ }
478
+ if (sources.env.baseUrl) {
479
+ output += ` EMBEDDING_BASE_URL=${sources.env.baseUrl}\n`;
480
+ }
481
+ if (sources.env.apiKey) {
482
+ output += ` OPENAI_API_KEY=***\n`;
483
+ }
484
+ output += "\n";
485
+ }
486
+ // Show usage instructions
487
+ output += chalk.bold("Usage:\n");
488
+ output += ` ${chalk.cyan("config")} Show this config\n`;
489
+ output += ` ${chalk.cyan("config <key> <value>")} Set config value\n`;
490
+ output += ` ${chalk.cyan("get <key>")} Get specific value\n`;
491
+ output += ` ${chalk.cyan("set <key> <value>")} Set specific value\n\n`;
492
+ output += chalk.bold("Valid Keys:\n");
493
+ output += ` ${chalk.cyan("provider")} ollama, transformers, openai\n`;
494
+ output += ` ${chalk.cyan("model")} Model name (e.g., mxbai-embed-large)\n`;
495
+ output += ` ${chalk.cyan("dimensions")} Embedding dimensions (e.g., 1024)\n`;
496
+ output += ` ${chalk.cyan("baseUrl")} Ollama base URL (default: http://localhost:11434)\n`;
497
+ output += ` ${chalk.cyan("apiKey")} OpenAI API key\n\n`;
498
+ output += chalk.gray(`Config file location: ${configPath}\n`);
499
+ if (!configExists) {
500
+ output += chalk.yellow("Config file will be created on first 'set' command.\n");
501
+ }
502
+ return output;
503
+ }
504
+ /**
505
+ * Handle config get command
506
+ */
507
+ function handleConfigGet(key) {
508
+ try {
509
+ const value = ConfigManager.getConfigValue(key);
510
+ if (value === undefined || value === null) {
511
+ return chalk.yellow(`Config key '${key}' is not set`);
512
+ }
513
+ // Mask API keys
514
+ if (key === "apiKey" || key === "api_key") {
515
+ const apiKey = value;
516
+ return chalk.green(`${key}: ***${apiKey.slice(-4)}`);
517
+ }
518
+ return chalk.green(`${key}: ${value}`);
519
+ }
520
+ catch (error) {
521
+ return chalk.red(`Error: ${error.message}`);
522
+ }
523
+ }
524
+ /**
525
+ * Handle config set command
526
+ */
527
+ function handleConfigSet(key, value) {
528
+ try {
529
+ ConfigManager.setConfigValue(key, value);
530
+ // Show confirmation with helpful info
531
+ let output = chalk.green(`โœ“ Config updated: ${key} = ${value}\n\n`);
532
+ // If setting dimensions, suggest matching models
533
+ if (key === "dimensions") {
534
+ const dims = parseInt(value, 10);
535
+ output += chalk.cyan("Models with matching dimensions:\n");
536
+ if (dims === 384) {
537
+ output += " - Xenova/all-MiniLM-L6-v2 (transformers)\n";
538
+ output += " - all-minilm (ollama)\n";
539
+ }
540
+ else if (dims === 768) {
541
+ output += " - nomic-embed-text (ollama)\n";
542
+ output += " - Xenova/all-mpnet-base-v2 (transformers)\n";
543
+ }
544
+ else if (dims === 1024) {
545
+ output += " - mxbai-embed-large (ollama) โญ default\n";
546
+ output += " - snowflake-arctic-embed (ollama)\n";
547
+ }
548
+ else if (dims === 1536) {
549
+ output += " - text-embedding-3-small (openai)\n";
550
+ output += " - text-embedding-ada-002 (openai)\n";
551
+ }
552
+ else if (dims === 3072) {
553
+ output += " - text-embedding-3-large (openai)\n";
554
+ }
555
+ output += "\n";
556
+ }
557
+ // If setting model, suggest dimensions
558
+ if (key === "model") {
559
+ const knownDims = ConfigManager.getKnownModelDimensions(value);
560
+ if (knownDims) {
561
+ output += chalk.cyan(`๐Ÿ’ก Tip: This model uses ${knownDims} dimensions\n`);
562
+ output += ` Run: ${chalk.green(`set dimensions ${knownDims}`)}\n\n`;
563
+ }
564
+ }
565
+ output += chalk.gray(`Config saved to: ${ConfigManager.getConfigPath()}\n`);
566
+ return output;
567
+ }
568
+ catch (error) {
569
+ return chalk.red(`Error: ${error.message}`);
570
+ }
571
+ }
572
+ //# sourceMappingURL=commands.js.map