cccmemory 1.8.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.
Files changed (216) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +349 -0
  3. package/dist/ConversationMemory.d.ts +231 -0
  4. package/dist/ConversationMemory.d.ts.map +1 -0
  5. package/dist/ConversationMemory.js +357 -0
  6. package/dist/ConversationMemory.js.map +1 -0
  7. package/dist/cache/QueryCache.d.ts +215 -0
  8. package/dist/cache/QueryCache.d.ts.map +1 -0
  9. package/dist/cache/QueryCache.js +294 -0
  10. package/dist/cache/QueryCache.js.map +1 -0
  11. package/dist/cli/commands.d.ts +9 -0
  12. package/dist/cli/commands.d.ts.map +1 -0
  13. package/dist/cli/commands.js +954 -0
  14. package/dist/cli/commands.js.map +1 -0
  15. package/dist/cli/help.d.ts +16 -0
  16. package/dist/cli/help.d.ts.map +1 -0
  17. package/dist/cli/help.js +361 -0
  18. package/dist/cli/help.js.map +1 -0
  19. package/dist/cli/index.d.ts +30 -0
  20. package/dist/cli/index.d.ts.map +1 -0
  21. package/dist/cli/index.js +111 -0
  22. package/dist/cli/index.js.map +1 -0
  23. package/dist/context/ContextInjector.d.ts +38 -0
  24. package/dist/context/ContextInjector.d.ts.map +1 -0
  25. package/dist/context/ContextInjector.js +235 -0
  26. package/dist/context/ContextInjector.js.map +1 -0
  27. package/dist/documentation/CodeAnalyzer.d.ts +29 -0
  28. package/dist/documentation/CodeAnalyzer.d.ts.map +1 -0
  29. package/dist/documentation/CodeAnalyzer.js +122 -0
  30. package/dist/documentation/CodeAnalyzer.js.map +1 -0
  31. package/dist/documentation/ConversationAnalyzer.d.ts +19 -0
  32. package/dist/documentation/ConversationAnalyzer.d.ts.map +1 -0
  33. package/dist/documentation/ConversationAnalyzer.js +157 -0
  34. package/dist/documentation/ConversationAnalyzer.js.map +1 -0
  35. package/dist/documentation/CrossReferencer.d.ts +67 -0
  36. package/dist/documentation/CrossReferencer.d.ts.map +1 -0
  37. package/dist/documentation/CrossReferencer.js +247 -0
  38. package/dist/documentation/CrossReferencer.js.map +1 -0
  39. package/dist/documentation/DocumentationGenerator.d.ts +22 -0
  40. package/dist/documentation/DocumentationGenerator.d.ts.map +1 -0
  41. package/dist/documentation/DocumentationGenerator.js +57 -0
  42. package/dist/documentation/DocumentationGenerator.js.map +1 -0
  43. package/dist/documentation/MarkdownFormatter.d.ts +26 -0
  44. package/dist/documentation/MarkdownFormatter.d.ts.map +1 -0
  45. package/dist/documentation/MarkdownFormatter.js +301 -0
  46. package/dist/documentation/MarkdownFormatter.js.map +1 -0
  47. package/dist/documentation/types.d.ts +176 -0
  48. package/dist/documentation/types.d.ts.map +1 -0
  49. package/dist/documentation/types.js +5 -0
  50. package/dist/documentation/types.js.map +1 -0
  51. package/dist/embeddings/ConfigManager.d.ts +46 -0
  52. package/dist/embeddings/ConfigManager.d.ts.map +1 -0
  53. package/dist/embeddings/ConfigManager.js +177 -0
  54. package/dist/embeddings/ConfigManager.js.map +1 -0
  55. package/dist/embeddings/EmbeddingConfig.d.ts +39 -0
  56. package/dist/embeddings/EmbeddingConfig.d.ts.map +1 -0
  57. package/dist/embeddings/EmbeddingConfig.js +132 -0
  58. package/dist/embeddings/EmbeddingConfig.js.map +1 -0
  59. package/dist/embeddings/EmbeddingGenerator.d.ts +51 -0
  60. package/dist/embeddings/EmbeddingGenerator.d.ts.map +1 -0
  61. package/dist/embeddings/EmbeddingGenerator.js +157 -0
  62. package/dist/embeddings/EmbeddingGenerator.js.map +1 -0
  63. package/dist/embeddings/EmbeddingProvider.d.ts +34 -0
  64. package/dist/embeddings/EmbeddingProvider.d.ts.map +1 -0
  65. package/dist/embeddings/EmbeddingProvider.js +6 -0
  66. package/dist/embeddings/EmbeddingProvider.js.map +1 -0
  67. package/dist/embeddings/ModelRegistry.d.ts +48 -0
  68. package/dist/embeddings/ModelRegistry.d.ts.map +1 -0
  69. package/dist/embeddings/ModelRegistry.js +170 -0
  70. package/dist/embeddings/ModelRegistry.js.map +1 -0
  71. package/dist/embeddings/VectorStore.d.ts +114 -0
  72. package/dist/embeddings/VectorStore.d.ts.map +1 -0
  73. package/dist/embeddings/VectorStore.js +393 -0
  74. package/dist/embeddings/VectorStore.js.map +1 -0
  75. package/dist/embeddings/providers/OllamaEmbeddings.d.ts +38 -0
  76. package/dist/embeddings/providers/OllamaEmbeddings.d.ts.map +1 -0
  77. package/dist/embeddings/providers/OllamaEmbeddings.js +125 -0
  78. package/dist/embeddings/providers/OllamaEmbeddings.js.map +1 -0
  79. package/dist/embeddings/providers/OpenAIEmbeddings.d.ts +40 -0
  80. package/dist/embeddings/providers/OpenAIEmbeddings.d.ts.map +1 -0
  81. package/dist/embeddings/providers/OpenAIEmbeddings.js +129 -0
  82. package/dist/embeddings/providers/OpenAIEmbeddings.js.map +1 -0
  83. package/dist/embeddings/providers/TransformersEmbeddings.d.ts +38 -0
  84. package/dist/embeddings/providers/TransformersEmbeddings.d.ts.map +1 -0
  85. package/dist/embeddings/providers/TransformersEmbeddings.js +115 -0
  86. package/dist/embeddings/providers/TransformersEmbeddings.js.map +1 -0
  87. package/dist/handoff/SessionHandoffStore.d.ts +80 -0
  88. package/dist/handoff/SessionHandoffStore.d.ts.map +1 -0
  89. package/dist/handoff/SessionHandoffStore.js +314 -0
  90. package/dist/handoff/SessionHandoffStore.js.map +1 -0
  91. package/dist/index.d.ts +7 -0
  92. package/dist/index.d.ts.map +1 -0
  93. package/dist/index.js +115 -0
  94. package/dist/index.js.map +1 -0
  95. package/dist/mcp-server.d.ts +27 -0
  96. package/dist/mcp-server.d.ts.map +1 -0
  97. package/dist/mcp-server.js +157 -0
  98. package/dist/mcp-server.js.map +1 -0
  99. package/dist/memory/WorkingMemoryStore.d.ts +83 -0
  100. package/dist/memory/WorkingMemoryStore.d.ts.map +1 -0
  101. package/dist/memory/WorkingMemoryStore.js +318 -0
  102. package/dist/memory/WorkingMemoryStore.js.map +1 -0
  103. package/dist/memory/types.d.ts +192 -0
  104. package/dist/memory/types.d.ts.map +1 -0
  105. package/dist/memory/types.js +8 -0
  106. package/dist/memory/types.js.map +1 -0
  107. package/dist/parsers/CodexConversationParser.d.ts +51 -0
  108. package/dist/parsers/CodexConversationParser.d.ts.map +1 -0
  109. package/dist/parsers/CodexConversationParser.js +301 -0
  110. package/dist/parsers/CodexConversationParser.js.map +1 -0
  111. package/dist/parsers/ConversationParser.d.ts +286 -0
  112. package/dist/parsers/ConversationParser.d.ts.map +1 -0
  113. package/dist/parsers/ConversationParser.js +795 -0
  114. package/dist/parsers/ConversationParser.js.map +1 -0
  115. package/dist/parsers/DecisionExtractor.d.ts +144 -0
  116. package/dist/parsers/DecisionExtractor.d.ts.map +1 -0
  117. package/dist/parsers/DecisionExtractor.js +434 -0
  118. package/dist/parsers/DecisionExtractor.js.map +1 -0
  119. package/dist/parsers/GitIntegrator.d.ts +156 -0
  120. package/dist/parsers/GitIntegrator.d.ts.map +1 -0
  121. package/dist/parsers/GitIntegrator.js +348 -0
  122. package/dist/parsers/GitIntegrator.js.map +1 -0
  123. package/dist/parsers/MistakeExtractor.d.ts +151 -0
  124. package/dist/parsers/MistakeExtractor.d.ts.map +1 -0
  125. package/dist/parsers/MistakeExtractor.js +460 -0
  126. package/dist/parsers/MistakeExtractor.js.map +1 -0
  127. package/dist/parsers/RequirementsExtractor.d.ts +166 -0
  128. package/dist/parsers/RequirementsExtractor.d.ts.map +1 -0
  129. package/dist/parsers/RequirementsExtractor.js +338 -0
  130. package/dist/parsers/RequirementsExtractor.js.map +1 -0
  131. package/dist/realtime/ConversationWatcher.d.ts +87 -0
  132. package/dist/realtime/ConversationWatcher.d.ts.map +1 -0
  133. package/dist/realtime/ConversationWatcher.js +204 -0
  134. package/dist/realtime/ConversationWatcher.js.map +1 -0
  135. package/dist/realtime/IncrementalParser.d.ts +83 -0
  136. package/dist/realtime/IncrementalParser.d.ts.map +1 -0
  137. package/dist/realtime/IncrementalParser.js +232 -0
  138. package/dist/realtime/IncrementalParser.js.map +1 -0
  139. package/dist/realtime/LiveExtractor.d.ts +72 -0
  140. package/dist/realtime/LiveExtractor.d.ts.map +1 -0
  141. package/dist/realtime/LiveExtractor.js +288 -0
  142. package/dist/realtime/LiveExtractor.js.map +1 -0
  143. package/dist/search/SemanticSearch.d.ts +121 -0
  144. package/dist/search/SemanticSearch.d.ts.map +1 -0
  145. package/dist/search/SemanticSearch.js +823 -0
  146. package/dist/search/SemanticSearch.js.map +1 -0
  147. package/dist/storage/BackupManager.d.ts +58 -0
  148. package/dist/storage/BackupManager.d.ts.map +1 -0
  149. package/dist/storage/BackupManager.js +223 -0
  150. package/dist/storage/BackupManager.js.map +1 -0
  151. package/dist/storage/ConversationStorage.d.ts +341 -0
  152. package/dist/storage/ConversationStorage.d.ts.map +1 -0
  153. package/dist/storage/ConversationStorage.js +792 -0
  154. package/dist/storage/ConversationStorage.js.map +1 -0
  155. package/dist/storage/DeletionService.d.ts +70 -0
  156. package/dist/storage/DeletionService.d.ts.map +1 -0
  157. package/dist/storage/DeletionService.js +253 -0
  158. package/dist/storage/DeletionService.js.map +1 -0
  159. package/dist/storage/GlobalIndex.d.ts +133 -0
  160. package/dist/storage/GlobalIndex.d.ts.map +1 -0
  161. package/dist/storage/GlobalIndex.js +310 -0
  162. package/dist/storage/GlobalIndex.js.map +1 -0
  163. package/dist/storage/SQLiteManager.d.ts +114 -0
  164. package/dist/storage/SQLiteManager.d.ts.map +1 -0
  165. package/dist/storage/SQLiteManager.js +636 -0
  166. package/dist/storage/SQLiteManager.js.map +1 -0
  167. package/dist/storage/migrations.d.ts +54 -0
  168. package/dist/storage/migrations.d.ts.map +1 -0
  169. package/dist/storage/migrations.js +285 -0
  170. package/dist/storage/migrations.js.map +1 -0
  171. package/dist/storage/schema.sql +436 -0
  172. package/dist/tools/ToolDefinitions.d.ts +946 -0
  173. package/dist/tools/ToolDefinitions.d.ts.map +1 -0
  174. package/dist/tools/ToolDefinitions.js +937 -0
  175. package/dist/tools/ToolDefinitions.js.map +1 -0
  176. package/dist/tools/ToolHandlers.d.ts +791 -0
  177. package/dist/tools/ToolHandlers.d.ts.map +1 -0
  178. package/dist/tools/ToolHandlers.js +3262 -0
  179. package/dist/tools/ToolHandlers.js.map +1 -0
  180. package/dist/types/ToolTypes.d.ts +824 -0
  181. package/dist/types/ToolTypes.d.ts.map +1 -0
  182. package/dist/types/ToolTypes.js +6 -0
  183. package/dist/types/ToolTypes.js.map +1 -0
  184. package/dist/utils/Logger.d.ts +70 -0
  185. package/dist/utils/Logger.d.ts.map +1 -0
  186. package/dist/utils/Logger.js +131 -0
  187. package/dist/utils/Logger.js.map +1 -0
  188. package/dist/utils/McpConfig.d.ts +54 -0
  189. package/dist/utils/McpConfig.d.ts.map +1 -0
  190. package/dist/utils/McpConfig.js +136 -0
  191. package/dist/utils/McpConfig.js.map +1 -0
  192. package/dist/utils/ProjectMigration.d.ts +82 -0
  193. package/dist/utils/ProjectMigration.d.ts.map +1 -0
  194. package/dist/utils/ProjectMigration.js +416 -0
  195. package/dist/utils/ProjectMigration.js.map +1 -0
  196. package/dist/utils/constants.d.ts +75 -0
  197. package/dist/utils/constants.d.ts.map +1 -0
  198. package/dist/utils/constants.js +105 -0
  199. package/dist/utils/constants.js.map +1 -0
  200. package/dist/utils/safeJson.d.ts +37 -0
  201. package/dist/utils/safeJson.d.ts.map +1 -0
  202. package/dist/utils/safeJson.js +48 -0
  203. package/dist/utils/safeJson.js.map +1 -0
  204. package/dist/utils/sanitization.d.ts +45 -0
  205. package/dist/utils/sanitization.d.ts.map +1 -0
  206. package/dist/utils/sanitization.js +153 -0
  207. package/dist/utils/sanitization.js.map +1 -0
  208. package/dist/utils/worktree.d.ts +15 -0
  209. package/dist/utils/worktree.d.ts.map +1 -0
  210. package/dist/utils/worktree.js +86 -0
  211. package/dist/utils/worktree.js.map +1 -0
  212. package/package.json +98 -0
  213. package/scripts/changelog-check.sh +62 -0
  214. package/scripts/check-node.js +17 -0
  215. package/scripts/dev-config.js +56 -0
  216. package/scripts/postinstall.js +117 -0
@@ -0,0 +1,954 @@
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
+ import { getMcpStatus } from "../utils/McpConfig.js";
10
+ import { getModelsByProvider, getAllModels, getModelsByQuality, getRecommendedModel, modelExists } from "../embeddings/ModelRegistry.js";
11
+ import { readFileSync } from "fs";
12
+ import { join, dirname } from "path";
13
+ import { fileURLToPath } from "url";
14
+ import prompts from "prompts";
15
+ const __filename = fileURLToPath(import.meta.url);
16
+ const __dirname = dirname(__filename);
17
+ /**
18
+ * Get version from package.json
19
+ */
20
+ function getVersion() {
21
+ try {
22
+ const packageJsonPath = join(__dirname, "..", "..", "package.json");
23
+ const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
24
+ return packageJson.version;
25
+ }
26
+ catch (_error) {
27
+ return "unknown";
28
+ }
29
+ }
30
+ /**
31
+ * Parse command line arguments
32
+ */
33
+ function parseArgs(input) {
34
+ const parts = input.match(/(?:[^\s"]+|"[^"]*")+/g) || [];
35
+ const command = parts[0] || "";
36
+ const rest = parts.slice(1);
37
+ const args = [];
38
+ const options = {};
39
+ for (let i = 0; i < rest.length; i++) {
40
+ const part = rest[i];
41
+ if (part.startsWith("--")) {
42
+ const key = part.slice(2);
43
+ const nextPart = rest[i + 1];
44
+ if (nextPart && !nextPart.startsWith("--")) {
45
+ options[key] = nextPart.replace(/^"(.*)"$/, "$1");
46
+ i++;
47
+ }
48
+ else {
49
+ options[key] = true;
50
+ }
51
+ }
52
+ else {
53
+ args.push(part.replace(/^"(.*)"$/, "$1"));
54
+ }
55
+ }
56
+ return { command, args, options };
57
+ }
58
+ /**
59
+ * Execute a command
60
+ */
61
+ export async function executeCommand(input, handlers) {
62
+ const { command, args, options } = parseArgs(input);
63
+ // Handle exit commands
64
+ if (command === "exit" || command === "quit" || command === "q") {
65
+ return "exit";
66
+ }
67
+ // Handle clear
68
+ if (command === "clear") {
69
+ return "clear";
70
+ }
71
+ // Handle help
72
+ if (command === "help" || command === "?") {
73
+ if (args.length > 0) {
74
+ return showCommandHelp(args[0]);
75
+ }
76
+ return showHelp();
77
+ }
78
+ // Handle version
79
+ if (command === "version") {
80
+ return chalk.cyan(`CCCMemory v${getVersion()}`);
81
+ }
82
+ // Handle status/stats
83
+ if (command === "status" || command === "stats") {
84
+ return await handleStatus();
85
+ }
86
+ // Handle index
87
+ if (command === "index") {
88
+ return await handleIndex(handlers, options);
89
+ }
90
+ // Handle reindex
91
+ if (command === "reindex") {
92
+ return await handleReindex(handlers, options);
93
+ }
94
+ // Handle search
95
+ if (command === "search" || command === "find") {
96
+ if (args.length === 0) {
97
+ return chalk.yellow("Usage: search <query> [options]");
98
+ }
99
+ return await handleSearch(handlers, args.join(" "), options);
100
+ }
101
+ // Handle decisions
102
+ if (command === "decisions" || command === "why") {
103
+ if (args.length === 0) {
104
+ return chalk.yellow("Usage: decisions <topic> [options]");
105
+ }
106
+ return await handleDecisions(handlers, args.join(" "), options);
107
+ }
108
+ // Handle mistakes
109
+ if (command === "mistakes" || command === "errors") {
110
+ if (args.length === 0) {
111
+ return chalk.yellow("Usage: mistakes <query> [options]");
112
+ }
113
+ return await handleMistakes(handlers, args.join(" "), options);
114
+ }
115
+ // Handle check
116
+ if (command === "check") {
117
+ if (args.length === 0) {
118
+ return chalk.yellow("Usage: check <file>");
119
+ }
120
+ return await handleCheck(handlers, args[0]);
121
+ }
122
+ // Handle history/evolution
123
+ if (command === "history" || command === "evolution") {
124
+ if (args.length === 0) {
125
+ return chalk.yellow("Usage: history <file> [options]");
126
+ }
127
+ return await handleHistory(handlers, args[0], options);
128
+ }
129
+ // Handle commits/git
130
+ if (command === "commits" || command === "git") {
131
+ return await handleCommits(handlers, args.join(" "), options);
132
+ }
133
+ // Handle similar/related
134
+ if (command === "similar" || command === "related") {
135
+ if (args.length === 0) {
136
+ return chalk.yellow("Usage: similar <query> [options]");
137
+ }
138
+ return await handleSimilar(handlers, args.join(" "), options);
139
+ }
140
+ // Handle requirements/deps
141
+ if (command === "requirements" || command === "deps") {
142
+ if (args.length === 0) {
143
+ return chalk.yellow("Usage: requirements <component> [options]");
144
+ }
145
+ return await handleRequirements(handlers, args.join(" "), options);
146
+ }
147
+ // Handle tools
148
+ if (command === "tools" || command === "history-tools") {
149
+ return await handleTools(handlers, options);
150
+ }
151
+ // Handle docs/generate
152
+ if (command === "docs" || command === "generate") {
153
+ return await handleDocs(handlers, options);
154
+ }
155
+ // Handle reset
156
+ if (command === "reset") {
157
+ return await handleReset();
158
+ }
159
+ // Handle vacuum
160
+ if (command === "vacuum") {
161
+ return await handleVacuum();
162
+ }
163
+ // Handle config
164
+ if (command === "config") {
165
+ if (args.length === 0) {
166
+ return handleConfigShow();
167
+ }
168
+ else if (args.length === 2) {
169
+ return handleConfigSet(args[0], args[1]);
170
+ }
171
+ else {
172
+ return chalk.yellow("Usage: config (show current config)\n config <key> <value> (set config value)");
173
+ }
174
+ }
175
+ // Handle models
176
+ if (command === "models") {
177
+ return handleModels(args);
178
+ }
179
+ // Handle select-model (interactive)
180
+ if (command === "select-model" || command === "select") {
181
+ return await handleSelectModel();
182
+ }
183
+ // Handle get
184
+ if (command === "get") {
185
+ if (args.length === 0) {
186
+ return chalk.yellow("Usage: get <key>");
187
+ }
188
+ return handleConfigGet(args[0]);
189
+ }
190
+ // Handle set
191
+ if (command === "set") {
192
+ if (args.length < 2) {
193
+ return chalk.yellow("Usage: set <key> <value>");
194
+ }
195
+ return handleConfigSet(args[0], args[1]);
196
+ }
197
+ // Handle commands
198
+ if (command === "commands") {
199
+ return showHelp();
200
+ }
201
+ // Handle init-mcp
202
+ if (command === "init-mcp") {
203
+ return await handleInitMcp();
204
+ }
205
+ // Handle remove-mcp
206
+ if (command === "remove-mcp") {
207
+ return await handleRemoveMcp();
208
+ }
209
+ // Handle mcp-status
210
+ if (command === "mcp-status") {
211
+ return handleMcpStatus();
212
+ }
213
+ // Unknown command
214
+ return chalk.yellow(`Unknown command: ${command}\nType 'help' for available commands.`);
215
+ }
216
+ /**
217
+ * Handle status command
218
+ */
219
+ async function handleStatus() {
220
+ const dbManager = getSQLiteManager();
221
+ const db = dbManager.getDatabase();
222
+ const stats = dbManager.getStats();
223
+ const dbPath = stats.dbPath.replace(process.env.HOME || "", "~");
224
+ // Query counts from database
225
+ const conversations = db.prepare("SELECT COUNT(*) as count FROM conversations").get().count;
226
+ const messages = db.prepare("SELECT COUNT(*) as count FROM messages").get().count;
227
+ const decisions = db.prepare("SELECT COUNT(*) as count FROM decisions").get().count;
228
+ const mistakes = db.prepare("SELECT COUNT(*) as count FROM mistakes").get().count;
229
+ const commits = db.prepare("SELECT COUNT(*) as count FROM git_commits").get().count;
230
+ const embeddings = db.prepare("SELECT COUNT(*) as count FROM message_embeddings").get().count;
231
+ const table = new Table({
232
+ head: [chalk.cyan("Metric"), chalk.cyan("Value")],
233
+ colWidths: [30, 30],
234
+ });
235
+ 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")]);
236
+ let output = "\n" + table.toString() + "\n";
237
+ if (conversations === 0) {
238
+ output += "\n" + chalk.yellow("⚠️ No conversations indexed yet. Run 'index' to get started.\n");
239
+ }
240
+ return output;
241
+ }
242
+ /**
243
+ * Handle index command
244
+ */
245
+ async function handleIndex(handlers, options) {
246
+ const args = {
247
+ project_path: typeof options.project === "string" ? options.project : process.cwd(),
248
+ };
249
+ if (typeof options.session === "string") {
250
+ args.session_id = options.session;
251
+ }
252
+ if (options["exclude-mcp"]) {
253
+ args.exclude_mcp_conversations = "all-mcp";
254
+ }
255
+ if (options["include-mcp"]) {
256
+ args.exclude_mcp_conversations = false;
257
+ }
258
+ if (options["no-git"]) {
259
+ args.enable_git = false;
260
+ }
261
+ if (options.thinking) {
262
+ args.include_thinking = true;
263
+ }
264
+ console.log(chalk.blue("Indexing conversations..."));
265
+ const result = await handlers.indexConversations(args);
266
+ return chalk.green(`\n✓ Indexing complete!\n\n${JSON.stringify(result, null, 2)}`);
267
+ }
268
+ /**
269
+ * Handle reindex command
270
+ */
271
+ async function handleReindex(handlers, options) {
272
+ console.log(chalk.yellow("⚠️ This will clear all indexed data and re-index."));
273
+ console.log(chalk.yellow("Press Ctrl+C to cancel, or wait 3 seconds to continue..."));
274
+ await new Promise((resolve) => setTimeout(resolve, 3000));
275
+ // Clear database
276
+ const db = getSQLiteManager().getDatabase();
277
+ db.exec("DELETE FROM conversations");
278
+ db.exec("DELETE FROM messages");
279
+ db.exec("DELETE FROM decisions");
280
+ db.exec("DELETE FROM mistakes");
281
+ db.exec("DELETE FROM git_commits");
282
+ console.log(chalk.blue("Database cleared. Indexing conversations..."));
283
+ return await handleIndex(handlers, options);
284
+ }
285
+ /**
286
+ * Handle search command
287
+ */
288
+ async function handleSearch(handlers, query, options) {
289
+ const args = { query };
290
+ if (typeof options.limit === "string") {
291
+ args.limit = parseInt(options.limit, 10);
292
+ }
293
+ const result = await handlers.searchConversations(args);
294
+ if (!result.results || result.results.length === 0) {
295
+ return chalk.yellow(`No results found for: ${query}`);
296
+ }
297
+ let output = chalk.green(`\nFound ${result.results.length} results:\n\n`);
298
+ result.results.forEach((r, i) => {
299
+ output += chalk.cyan(`${i + 1}. `) + `[${r.timestamp}] Session ${r.conversation_id.slice(0, 8)}\n`;
300
+ output += ` ${r.snippet.slice(0, 200)}${r.snippet.length > 200 ? "..." : ""}\n`;
301
+ output += chalk.gray(` Similarity: ${(r.similarity * 100).toFixed(1)}%\n\n`);
302
+ });
303
+ return output;
304
+ }
305
+ /**
306
+ * Handle decisions command
307
+ */
308
+ async function handleDecisions(handlers, query, options) {
309
+ const args = { query };
310
+ if (typeof options.file === "string") {
311
+ args.file_path = options.file;
312
+ }
313
+ if (typeof options.limit === "string") {
314
+ args.limit = parseInt(options.limit, 10);
315
+ }
316
+ const result = await handlers.getDecisions(args);
317
+ if (!result.decisions || result.decisions.length === 0) {
318
+ return chalk.yellow(`No decisions found for: ${query}`);
319
+ }
320
+ let output = chalk.green(`\nFound ${result.decisions.length} decisions:\n\n`);
321
+ result.decisions.forEach((d, i) => {
322
+ output += chalk.cyan(`${i + 1}. ${d.decision_text}\n`);
323
+ output += ` Date: ${d.timestamp}\n`;
324
+ output += ` Rationale: ${d.rationale || "N/A"}\n`;
325
+ if (d.alternatives_considered && d.alternatives_considered.length > 0) {
326
+ output += ` Alternatives: ${d.alternatives_considered.join(", ")}\n`;
327
+ }
328
+ output += "\n";
329
+ });
330
+ return output;
331
+ }
332
+ /**
333
+ * Handle mistakes command
334
+ */
335
+ async function handleMistakes(handlers, query, options) {
336
+ const args = { query };
337
+ if (typeof options.type === "string") {
338
+ args.mistake_type = options.type;
339
+ }
340
+ if (typeof options.limit === "string") {
341
+ args.limit = parseInt(options.limit, 10);
342
+ }
343
+ const result = await handlers.searchMistakes(args);
344
+ if (!result.mistakes || result.mistakes.length === 0) {
345
+ return chalk.yellow(`No mistakes found for: ${query}`);
346
+ }
347
+ let output = chalk.green(`\nFound ${result.mistakes.length} mistakes:\n\n`);
348
+ result.mistakes.forEach((m, i) => {
349
+ output += chalk.red(`${i + 1}. [${m.mistake_type}] ${m.what_went_wrong}\n`);
350
+ output += ` Date: ${m.timestamp}\n`;
351
+ output += chalk.green(` Fix: ${m.correction || m.user_correction_message || "N/A"}\n\n`);
352
+ });
353
+ return output;
354
+ }
355
+ /**
356
+ * Handle check command
357
+ */
358
+ async function handleCheck(handlers, filePath) {
359
+ const result = await handlers.checkBeforeModify({ file_path: filePath });
360
+ return chalk.green(`\nContext for: ${filePath}\n\n`) + JSON.stringify(result, null, 2);
361
+ }
362
+ /**
363
+ * Handle history command
364
+ */
365
+ async function handleHistory(handlers, filePath, options) {
366
+ const args = { file_path: filePath };
367
+ if (options["no-commits"]) {
368
+ args.include_commits = false;
369
+ }
370
+ if (options["no-decisions"]) {
371
+ args.include_decisions = false;
372
+ }
373
+ const result = await handlers.getFileEvolution(args);
374
+ return chalk.green(`\nFile evolution for: ${filePath}\n\n`) + JSON.stringify(result, null, 2);
375
+ }
376
+ /**
377
+ * Handle commits command
378
+ */
379
+ async function handleCommits(handlers, query, options) {
380
+ const args = {};
381
+ if (query) {
382
+ args.query = query;
383
+ }
384
+ if (typeof options.conversation === "string") {
385
+ args.conversation_id = options.conversation;
386
+ }
387
+ if (typeof options.limit === "string") {
388
+ args.limit = parseInt(options.limit, 10);
389
+ }
390
+ const result = await handlers.linkCommitsToConversations(args);
391
+ return chalk.green("\nCommits linked to conversations:\n\n") + JSON.stringify(result, null, 2);
392
+ }
393
+ /**
394
+ * Handle similar command
395
+ */
396
+ async function handleSimilar(handlers, query, options) {
397
+ const args = { query };
398
+ if (typeof options.limit === "string") {
399
+ args.limit = parseInt(options.limit, 10);
400
+ }
401
+ const result = await handlers.findSimilarSessions(args);
402
+ return chalk.green("\nSimilar sessions:\n\n") + JSON.stringify(result, null, 2);
403
+ }
404
+ /**
405
+ * Handle requirements command
406
+ */
407
+ async function handleRequirements(handlers, component, options) {
408
+ const args = { component };
409
+ if (typeof options.type === "string") {
410
+ args.type = options.type;
411
+ }
412
+ const result = await handlers.getRequirements(args);
413
+ return chalk.green(`\nRequirements for: ${component}\n\n`) + JSON.stringify(result, null, 2);
414
+ }
415
+ /**
416
+ * Handle tools command
417
+ */
418
+ async function handleTools(handlers, options) {
419
+ const args = {};
420
+ if (typeof options.file === "string") {
421
+ args.file_path = options.file;
422
+ }
423
+ if (typeof options.tool === "string") {
424
+ args.tool_name = options.tool;
425
+ }
426
+ if (typeof options.limit === "string") {
427
+ args.limit = parseInt(options.limit, 10);
428
+ }
429
+ const result = await handlers.getToolHistory(args);
430
+ return chalk.green("\nTool usage history:\n\n") + JSON.stringify(result, null, 2);
431
+ }
432
+ /**
433
+ * Handle docs command
434
+ */
435
+ async function handleDocs(handlers, options) {
436
+ const args = {
437
+ project_path: process.cwd(),
438
+ };
439
+ if (typeof options.scope === "string") {
440
+ args.scope = options.scope;
441
+ }
442
+ if (typeof options.module === "string") {
443
+ args.module_filter = options.module;
444
+ }
445
+ console.log(chalk.blue("Generating documentation..."));
446
+ const result = await handlers.generateDocumentation(args);
447
+ return chalk.green("\n✓ Documentation generated!\n\n") + JSON.stringify(result, null, 2);
448
+ }
449
+ /**
450
+ * Handle reset command
451
+ */
452
+ async function handleReset() {
453
+ console.log(chalk.red("⚠️ WARNING: This will delete ALL indexed data!"));
454
+ console.log(chalk.yellow("Press Ctrl+C to cancel, or wait 5 seconds to continue..."));
455
+ await new Promise((resolve) => setTimeout(resolve, 5000));
456
+ const db = getSQLiteManager().getDatabase();
457
+ db.exec("DELETE FROM conversations");
458
+ db.exec("DELETE FROM messages");
459
+ db.exec("DELETE FROM decisions");
460
+ db.exec("DELETE FROM mistakes");
461
+ db.exec("DELETE FROM git_commits");
462
+ return chalk.green("\n✓ Database reset complete.\n");
463
+ }
464
+ /**
465
+ * Handle vacuum command
466
+ */
467
+ async function handleVacuum() {
468
+ const db = getSQLiteManager().getDatabase();
469
+ const beforeSize = db.prepare("PRAGMA page_count").get();
470
+ db.exec("VACUUM");
471
+ const afterSize = db.prepare("PRAGMA page_count").get();
472
+ const beforeKB = (beforeSize.page_count * 4096) / 1024;
473
+ const afterKB = (afterSize.page_count * 4096) / 1024;
474
+ return chalk.green(`\n✓ Database vacuumed: ${beforeKB.toFixed(1)}KB → ${afterKB.toFixed(1)}KB\n`);
475
+ }
476
+ /**
477
+ * Handle config show command
478
+ */
479
+ function handleConfigShow() {
480
+ const sources = ConfigManager.getConfigSources();
481
+ const configPath = ConfigManager.getConfigPath();
482
+ const configExists = ConfigManager.configExists();
483
+ let output = chalk.cyan("\n=== Embedding Configuration ===\n\n");
484
+ // Show effective config
485
+ output += chalk.bold("Current (Effective) Configuration:\n");
486
+ const table = new Table({
487
+ head: [chalk.cyan("Key"), chalk.cyan("Value")],
488
+ colWidths: [20, 50],
489
+ });
490
+ 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"]);
491
+ output += table.toString() + "\n\n";
492
+ // Show sources breakdown
493
+ output += chalk.bold("Configuration Sources:\n\n");
494
+ if (sources.home) {
495
+ output += chalk.green(`✓ Home Config: ${configPath}\n`);
496
+ output += ` Provider: ${sources.home.provider || "not set"}\n`;
497
+ output += ` Model: ${sources.home.model || "not set"}\n`;
498
+ output += ` Dimensions: ${sources.home.dimensions || "not set"}\n\n`;
499
+ }
500
+ else {
501
+ output += chalk.gray(` Home Config: ${configPath} (not found)\n\n`);
502
+ }
503
+ if (sources.project) {
504
+ output += chalk.green("✓ Project Config: .claude-memory-config.json\n");
505
+ output += ` Provider: ${sources.project.provider || "not set"}\n`;
506
+ output += ` Model: ${sources.project.model || "not set"}\n\n`;
507
+ }
508
+ if (Object.keys(sources.env).length > 0) {
509
+ output += chalk.green("✓ Environment Variables:\n");
510
+ if (sources.env.provider) {
511
+ output += ` EMBEDDING_PROVIDER=${sources.env.provider}\n`;
512
+ }
513
+ if (sources.env.model) {
514
+ output += ` EMBEDDING_MODEL=${sources.env.model}\n`;
515
+ }
516
+ if (sources.env.dimensions) {
517
+ output += ` EMBEDDING_DIMENSIONS=${sources.env.dimensions}\n`;
518
+ }
519
+ if (sources.env.baseUrl) {
520
+ output += ` EMBEDDING_BASE_URL=${sources.env.baseUrl}\n`;
521
+ }
522
+ if (sources.env.apiKey) {
523
+ output += ` OPENAI_API_KEY=***\n`;
524
+ }
525
+ output += "\n";
526
+ }
527
+ // Show usage instructions
528
+ output += chalk.bold("Usage:\n");
529
+ output += ` ${chalk.cyan("config")} Show this config\n`;
530
+ output += ` ${chalk.cyan("config <key> <value>")} Set config value\n`;
531
+ output += ` ${chalk.cyan("get <key>")} Get specific value\n`;
532
+ output += ` ${chalk.cyan("set <key> <value>")} Set specific value\n\n`;
533
+ output += chalk.bold("Valid Keys:\n");
534
+ output += ` ${chalk.cyan("provider")} ollama, transformers, openai\n`;
535
+ output += ` ${chalk.cyan("model")} Model name (e.g., mxbai-embed-large)\n`;
536
+ output += ` ${chalk.cyan("dimensions")} Embedding dimensions (e.g., 1024)\n`;
537
+ output += ` ${chalk.cyan("baseUrl")} Ollama base URL (default: http://localhost:11434)\n`;
538
+ output += ` ${chalk.cyan("apiKey")} OpenAI API key\n\n`;
539
+ // Show available models by provider using ModelRegistry
540
+ output += chalk.bold("Known Models by Provider:\n\n");
541
+ // Ollama models
542
+ output += chalk.yellow("Ollama (local):\n");
543
+ const ollamaModels = getModelsByProvider("ollama");
544
+ for (const model of ollamaModels) {
545
+ const suffix = model.installation ? ` ${chalk.dim(`(${model.description})`)}` : "";
546
+ output += ` ${model.name.padEnd(30)} ${model.dimensions.toString().padStart(4)} dims${suffix}\n`;
547
+ }
548
+ output += "\n";
549
+ // Transformers models
550
+ output += chalk.yellow("Transformers (offline):\n");
551
+ const transformersModels = getModelsByProvider("transformers");
552
+ for (const model of transformersModels) {
553
+ output += ` ${model.name.padEnd(30)} ${model.dimensions.toString().padStart(4)} dims ${chalk.dim(`(${model.description})`)}\n`;
554
+ }
555
+ output += "\n";
556
+ // OpenAI models
557
+ output += chalk.yellow("OpenAI (cloud):\n");
558
+ const openaiModels = getModelsByProvider("openai");
559
+ for (const model of openaiModels) {
560
+ const costSuffix = model.cost ? ` - ${model.cost}` : "";
561
+ output += ` ${model.name.padEnd(30)} ${model.dimensions.toString().padStart(4)} dims ${chalk.dim(`(${model.description}${costSuffix})`)}\n`;
562
+ }
563
+ output += "\n";
564
+ output += chalk.gray(`Config file location: ${configPath}\n`);
565
+ if (!configExists) {
566
+ output += chalk.yellow("Config file will be created on first 'set' command.\n");
567
+ }
568
+ return output;
569
+ }
570
+ /**
571
+ * Handle config get command
572
+ */
573
+ function handleConfigGet(key) {
574
+ try {
575
+ const value = ConfigManager.getConfigValue(key);
576
+ if (value === undefined || value === null) {
577
+ return chalk.yellow(`Config key '${key}' is not set`);
578
+ }
579
+ // Mask API keys
580
+ if (key === "apiKey" || key === "api_key") {
581
+ const apiKey = value;
582
+ return chalk.green(`${key}: ***${apiKey.slice(-4)}`);
583
+ }
584
+ return chalk.green(`${key}: ${value}`);
585
+ }
586
+ catch (error) {
587
+ return chalk.red(`Error: ${error.message}`);
588
+ }
589
+ }
590
+ /**
591
+ * Handle config set command
592
+ */
593
+ function handleConfigSet(key, value) {
594
+ try {
595
+ // Validate model name if setting model
596
+ if (key === "model") {
597
+ if (!modelExists(value)) {
598
+ let warning = chalk.yellow(`⚠️ Model '${value}' is not in the registry.\n\n`);
599
+ warning += chalk.gray("This might be a custom model. If so, make sure to also set the correct dimensions.\n\n");
600
+ warning += chalk.cyan("Known models:\n");
601
+ warning += chalk.gray(" Run 'models' to see all available models\n");
602
+ warning += chalk.gray(" Or 'models <provider>' to see provider-specific models\n\n");
603
+ warning += chalk.yellow("Proceeding with custom model...\n\n");
604
+ console.warn(warning);
605
+ }
606
+ }
607
+ ConfigManager.setConfigValue(key, value);
608
+ // Show confirmation with helpful info
609
+ let output = chalk.green(`✓ Config updated: ${key} = ${value}\n\n`);
610
+ // If setting dimensions, suggest matching models
611
+ if (key === "dimensions") {
612
+ const dims = parseInt(value, 10);
613
+ const matchingModels = getAllModels().filter(m => m.dimensions === dims);
614
+ if (matchingModels.length > 0) {
615
+ output += chalk.cyan("Models with matching dimensions:\n");
616
+ for (const model of matchingModels) {
617
+ output += ` - ${model.name} (${model.provider})\n`;
618
+ }
619
+ output += "\n";
620
+ }
621
+ }
622
+ // If setting model, suggest dimensions
623
+ if (key === "model") {
624
+ const knownDims = ConfigManager.getKnownModelDimensions(value);
625
+ if (knownDims) {
626
+ output += chalk.cyan(`💡 Tip: This model uses ${knownDims} dimensions\n`);
627
+ output += ` Run: ${chalk.green(`set dimensions ${knownDims}`)}\n\n`;
628
+ }
629
+ }
630
+ output += chalk.gray(`Config saved to: ${ConfigManager.getConfigPath()}\n`);
631
+ return output;
632
+ }
633
+ catch (error) {
634
+ return chalk.red(`Error: ${error.message}`);
635
+ }
636
+ }
637
+ /**
638
+ * Handle models command - List, filter, search models
639
+ * Usage:
640
+ * models - List all models
641
+ * models <provider> - Filter by provider (ollama, transformers, openai)
642
+ * models quality <tier> - Filter by quality (low, medium, high, highest)
643
+ * models recommend - Show recommended models for each provider
644
+ */
645
+ function handleModels(args) {
646
+ let output = "";
647
+ // No args: list all models
648
+ if (args.length === 0) {
649
+ output += chalk.bold("📚 All Available Embedding Models\n\n");
650
+ const allModels = getAllModels();
651
+ output += formatModelsTable(allModels);
652
+ output += "\n";
653
+ output += chalk.gray("💡 Tip: Use 'models <provider>' to filter by provider\n");
654
+ output += chalk.gray(" Or: 'models quality <tier>' to filter by quality\n");
655
+ output += chalk.gray(" Or: 'models recommend' to see recommendations\n");
656
+ return output;
657
+ }
658
+ const subcommand = args[0].toLowerCase();
659
+ // Filter by provider
660
+ if (["ollama", "transformers", "openai"].includes(subcommand)) {
661
+ const models = getModelsByProvider(subcommand);
662
+ output += chalk.bold(`📚 ${capitalize(subcommand)} Models\n\n`);
663
+ output += formatModelsTable(models);
664
+ // Show recommended model for this provider
665
+ const recommended = getRecommendedModel(subcommand);
666
+ if (recommended) {
667
+ output += "\n";
668
+ output += chalk.cyan(`⭐ Recommended: ${recommended.name} (${recommended.dimensions} dims, ${recommended.quality} quality)\n`);
669
+ }
670
+ return output;
671
+ }
672
+ // Filter by quality
673
+ if (subcommand === "quality") {
674
+ if (args.length < 2) {
675
+ return chalk.yellow("Usage: models quality <tier>\nTiers: low, medium, high, highest");
676
+ }
677
+ const quality = args[1].toLowerCase();
678
+ if (!["low", "medium", "high", "highest"].includes(quality)) {
679
+ return chalk.red(`Invalid quality tier: ${args[1]}\nValid tiers: low, medium, high, highest`);
680
+ }
681
+ const models = getModelsByQuality(quality);
682
+ output += chalk.bold(`📚 ${capitalize(quality)} Quality Models\n\n`);
683
+ output += formatModelsTable(models);
684
+ return output;
685
+ }
686
+ // Show recommended models
687
+ if (subcommand === "recommend" || subcommand === "recommended") {
688
+ output += chalk.bold("⭐ Recommended Models by Provider\n\n");
689
+ const providers = ["ollama", "transformers", "openai"];
690
+ for (const provider of providers) {
691
+ const recommended = getRecommendedModel(provider);
692
+ if (recommended) {
693
+ output += chalk.yellow(`${capitalize(provider)}:\n`);
694
+ output += ` ${chalk.green(recommended.name)} ${chalk.dim(`(${recommended.dimensions} dims, ${recommended.quality} quality)`)}\n`;
695
+ output += ` ${chalk.dim(recommended.description)}\n`;
696
+ if (recommended.installation) {
697
+ output += ` ${chalk.dim(`Install: ${recommended.installation}`)}\n`;
698
+ }
699
+ if (recommended.cost) {
700
+ output += ` ${chalk.dim(`Cost: ${recommended.cost}`)}\n`;
701
+ }
702
+ output += "\n";
703
+ }
704
+ }
705
+ return output;
706
+ }
707
+ return chalk.yellow(`Unknown models subcommand: ${subcommand}\n\nUsage:\n models - List all models\n models <provider> - Filter by provider (ollama, transformers, openai)\n models quality <tier> - Filter by quality\n models recommend - Show recommendations`);
708
+ }
709
+ /**
710
+ * Format models into a table
711
+ */
712
+ function formatModelsTable(models) {
713
+ const table = new Table({
714
+ head: [
715
+ chalk.cyan("Model"),
716
+ chalk.cyan("Provider"),
717
+ chalk.cyan("Dimensions"),
718
+ chalk.cyan("Quality"),
719
+ chalk.cyan("Description")
720
+ ],
721
+ colWidths: [35, 13, 12, 10, 45],
722
+ wordWrap: true,
723
+ });
724
+ for (const model of models) {
725
+ table.push([
726
+ model.name,
727
+ model.provider,
728
+ model.dimensions.toString(),
729
+ model.quality,
730
+ model.description
731
+ ]);
732
+ }
733
+ return table.toString();
734
+ }
735
+ /**
736
+ * Capitalize first letter
737
+ */
738
+ function capitalize(str) {
739
+ return str.charAt(0).toUpperCase() + str.slice(1);
740
+ }
741
+ /**
742
+ * Handle interactive model selection
743
+ */
744
+ async function handleSelectModel() {
745
+ try {
746
+ // Step 1: Choose provider
747
+ const providerResponse = await prompts({
748
+ type: "select",
749
+ name: "provider",
750
+ message: "Choose an embedding provider:",
751
+ choices: [
752
+ {
753
+ title: "Ollama (Local, High Quality)",
754
+ value: "ollama",
755
+ description: "Run models locally with Ollama. Requires: ollama serve"
756
+ },
757
+ {
758
+ title: "Transformers (Offline, No Setup)",
759
+ value: "transformers",
760
+ description: "Auto-download models, runs offline. No external setup needed."
761
+ },
762
+ {
763
+ title: "OpenAI (Cloud, Highest Quality)",
764
+ value: "openai",
765
+ description: "Cloud API with best quality. Requires API key and costs money."
766
+ }
767
+ ],
768
+ initial: 0,
769
+ });
770
+ if (!providerResponse.provider) {
771
+ return chalk.yellow("Selection cancelled");
772
+ }
773
+ const provider = providerResponse.provider;
774
+ // Step 2: Choose model from that provider
775
+ const models = getModelsByProvider(provider);
776
+ const modelChoices = models.map(m => ({
777
+ title: `${m.name} (${m.dimensions} dims, ${m.quality} quality)`,
778
+ value: m.name,
779
+ description: m.description + (m.installation ? ` - ${m.installation}` : "") + (m.cost ? ` - ${m.cost}` : "")
780
+ }));
781
+ // Highlight recommended model
782
+ const recommended = getRecommendedModel(provider);
783
+ if (recommended) {
784
+ const recIndex = modelChoices.findIndex(c => c.value === recommended.name);
785
+ if (recIndex >= 0) {
786
+ modelChoices[recIndex].title = `⭐ ${modelChoices[recIndex].title} (recommended)`;
787
+ }
788
+ }
789
+ const modelResponse = await prompts({
790
+ type: "select",
791
+ name: "model",
792
+ message: `Choose a model from ${capitalize(provider)}:`,
793
+ choices: modelChoices,
794
+ initial: 0,
795
+ });
796
+ if (!modelResponse.model) {
797
+ return chalk.yellow("Selection cancelled");
798
+ }
799
+ const modelName = modelResponse.model;
800
+ const selectedModel = models.find(m => m.name === modelName);
801
+ if (!selectedModel) {
802
+ return chalk.red("Error: Model not found");
803
+ }
804
+ // Step 3: Confirm and save
805
+ const confirmResponse = await prompts({
806
+ type: "confirm",
807
+ name: "confirm",
808
+ message: `Set ${selectedModel.name} as your embedding model?\n Provider: ${selectedModel.provider}\n Dimensions: ${selectedModel.dimensions}\n Quality: ${selectedModel.quality}`,
809
+ initial: true,
810
+ });
811
+ if (!confirmResponse.confirm) {
812
+ return chalk.yellow("Selection cancelled");
813
+ }
814
+ // Save configuration
815
+ ConfigManager.setConfigValue("provider", provider);
816
+ ConfigManager.setConfigValue("model", modelName);
817
+ ConfigManager.setConfigValue("dimensions", selectedModel.dimensions.toString());
818
+ let output = chalk.green(`✓ Configuration updated!\n\n`);
819
+ output += ` Provider: ${chalk.cyan(provider)}\n`;
820
+ output += ` Model: ${chalk.cyan(modelName)}\n`;
821
+ output += ` Dimensions: ${chalk.cyan(selectedModel.dimensions)}\n\n`;
822
+ // Add setup instructions
823
+ if (selectedModel.installation) {
824
+ output += chalk.yellow(`⚠️ Setup Required:\n`);
825
+ output += ` ${selectedModel.installation}\n\n`;
826
+ }
827
+ if (selectedModel.cost) {
828
+ output += chalk.yellow(`💰 Cost: ${selectedModel.cost}\n\n`);
829
+ }
830
+ output += chalk.dim("💡 Tip: You may need to reindex conversations for the new model:\n");
831
+ output += chalk.dim(" reset && index\n\n");
832
+ output += chalk.gray(`Config saved to: ${ConfigManager.getConfigPath()}\n`);
833
+ return output;
834
+ }
835
+ catch (error) {
836
+ if (error.message === "User force closed the prompt") {
837
+ return chalk.yellow("\nSelection cancelled");
838
+ }
839
+ return chalk.red(`Error: ${error.message}`);
840
+ }
841
+ }
842
+ /**
843
+ * Handle init-mcp command - Configure MCP server in ~/.claude.json
844
+ */
845
+ async function handleInitMcp() {
846
+ const { isMcpConfigured, addMcpServer } = await import("../utils/McpConfig.js");
847
+ try {
848
+ const { configured, configPath } = isMcpConfigured();
849
+ if (configured) {
850
+ return chalk.yellow(`✓ MCP server is already configured in ${configPath}\n`) +
851
+ chalk.dim(" Use 'mcp-status' to see configuration details\n");
852
+ }
853
+ // Configure the MCP server
854
+ addMcpServer();
855
+ let output = chalk.green("✅ Successfully configured cccmemory MCP server!\n\n");
856
+ output += chalk.cyan("Configuration added to: ") + chalk.white(`${configPath}\n\n`);
857
+ output += chalk.bold("🎉 Available MCP Tools:\n");
858
+ output += chalk.dim(" • index_conversations - Index conversation history\n");
859
+ output += chalk.dim(" • search_conversations - Search past conversations\n");
860
+ output += chalk.dim(" • get_decisions - Find design decisions\n");
861
+ output += chalk.dim(" • check_before_modify - Check file context before editing\n");
862
+ output += chalk.dim(" • get_file_evolution - Track file changes over time\n");
863
+ output += chalk.dim(" • and 10 more tools...\n\n");
864
+ output += chalk.yellow("💡 Restart Claude Code to load the new MCP server\n");
865
+ output += chalk.dim(" Run '/mcp' in Claude Code to list all available tools\n");
866
+ return output;
867
+ }
868
+ catch (error) {
869
+ return chalk.red(`❌ Failed to configure MCP server: ${error.message}\n\n`) +
870
+ chalk.yellow("Manual configuration:\n") +
871
+ chalk.dim(" Add this to ~/.claude.json under \"mcpServers\":\n") +
872
+ chalk.dim(" {\n") +
873
+ chalk.dim(" \"cccmemory\": {\n") +
874
+ chalk.dim(" \"type\": \"stdio\",\n") +
875
+ chalk.dim(" \"command\": \"cccmemory\",\n") +
876
+ chalk.dim(" \"args\": []\n") +
877
+ chalk.dim(" }\n") +
878
+ chalk.dim(" }\n");
879
+ }
880
+ }
881
+ /**
882
+ * Handle remove-mcp command - Remove MCP server configuration
883
+ */
884
+ async function handleRemoveMcp() {
885
+ const { isMcpConfigured, removeMcpServer } = await import("../utils/McpConfig.js");
886
+ const prompts = (await import("prompts")).default;
887
+ try {
888
+ const { configured, configPath } = isMcpConfigured();
889
+ if (!configured) {
890
+ return chalk.yellow("⚠️ MCP server is not configured\n") +
891
+ chalk.dim(" Nothing to remove\n");
892
+ }
893
+ // Confirm removal
894
+ const response = await prompts({
895
+ type: "confirm",
896
+ name: "confirm",
897
+ message: `Remove cccmemory MCP server from ${configPath}?`,
898
+ initial: false,
899
+ });
900
+ if (!response.confirm) {
901
+ return chalk.yellow("Removal cancelled\n");
902
+ }
903
+ // Remove the MCP server
904
+ removeMcpServer();
905
+ let output = chalk.green("✅ Successfully removed cccmemory MCP server\n\n");
906
+ output += chalk.cyan("Configuration removed from: ") + chalk.white(`${configPath}\n\n`);
907
+ output += chalk.yellow("💡 Restart Claude Code to apply changes\n");
908
+ output += chalk.dim(" Run 'init-mcp' to reconfigure if needed\n");
909
+ return output;
910
+ }
911
+ catch (error) {
912
+ if (error.message === "User force closed the prompt") {
913
+ return chalk.yellow("\nRemoval cancelled");
914
+ }
915
+ return chalk.red(`❌ Failed to remove MCP server: ${error.message}\n`);
916
+ }
917
+ }
918
+ /**
919
+ * Handle mcp-status command - Show MCP server configuration status
920
+ */
921
+ function handleMcpStatus() {
922
+ const status = getMcpStatus();
923
+ const table = new Table({
924
+ head: [chalk.cyan("Status"), chalk.cyan("Value")],
925
+ colWidths: [30, 50],
926
+ });
927
+ table.push(["Claude Config Exists", status.claudeConfigExists ? chalk.green("✓ Yes") : chalk.red("✗ No")], ["MCP Server Configured", status.mcpConfigured ? chalk.green("✓ Yes") : chalk.yellow("✗ No")], ["Command Installed", status.commandExists ? chalk.green("✓ Yes") : chalk.yellow("✗ No")]);
928
+ if (status.commandPath) {
929
+ table.push(["Command Path", chalk.dim(status.commandPath)]);
930
+ }
931
+ if (status.serverConfig) {
932
+ table.push(["Server Type", chalk.dim(status.serverConfig.type)], ["Server Command", chalk.dim(status.serverConfig.command)]);
933
+ }
934
+ let output = "\n" + table.toString() + "\n";
935
+ // Add recommendations
936
+ if (!status.claudeConfigExists) {
937
+ output += "\n" + chalk.yellow("⚠️ Claude Code configuration not found at ~/.claude.json\n");
938
+ output += chalk.dim(" Please install Claude Code first: https://claude.ai/download\n");
939
+ }
940
+ else if (!status.mcpConfigured) {
941
+ output += "\n" + chalk.yellow("⚠️ MCP server is not configured\n");
942
+ output += chalk.dim(" Run 'init-mcp' to configure automatically\n");
943
+ }
944
+ else if (!status.commandExists) {
945
+ output += "\n" + chalk.yellow("⚠️ Command not found in global npm bin\n");
946
+ output += chalk.dim(" Reinstall: npm install -g cccmemory\n");
947
+ }
948
+ else {
949
+ output += "\n" + chalk.green("✅ Everything looks good! MCP server is ready to use.\n");
950
+ output += chalk.dim(" Restart Claude Code if you haven't already\n");
951
+ }
952
+ return output;
953
+ }
954
+ //# sourceMappingURL=commands.js.map