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.
- package/LICENSE +21 -0
- package/README.md +349 -0
- package/dist/ConversationMemory.d.ts +231 -0
- package/dist/ConversationMemory.d.ts.map +1 -0
- package/dist/ConversationMemory.js +357 -0
- package/dist/ConversationMemory.js.map +1 -0
- package/dist/cache/QueryCache.d.ts +215 -0
- package/dist/cache/QueryCache.d.ts.map +1 -0
- package/dist/cache/QueryCache.js +294 -0
- package/dist/cache/QueryCache.js.map +1 -0
- package/dist/cli/commands.d.ts +9 -0
- package/dist/cli/commands.d.ts.map +1 -0
- package/dist/cli/commands.js +954 -0
- package/dist/cli/commands.js.map +1 -0
- package/dist/cli/help.d.ts +16 -0
- package/dist/cli/help.d.ts.map +1 -0
- package/dist/cli/help.js +361 -0
- package/dist/cli/help.js.map +1 -0
- package/dist/cli/index.d.ts +30 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +111 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/context/ContextInjector.d.ts +38 -0
- package/dist/context/ContextInjector.d.ts.map +1 -0
- package/dist/context/ContextInjector.js +235 -0
- package/dist/context/ContextInjector.js.map +1 -0
- package/dist/documentation/CodeAnalyzer.d.ts +29 -0
- package/dist/documentation/CodeAnalyzer.d.ts.map +1 -0
- package/dist/documentation/CodeAnalyzer.js +122 -0
- package/dist/documentation/CodeAnalyzer.js.map +1 -0
- package/dist/documentation/ConversationAnalyzer.d.ts +19 -0
- package/dist/documentation/ConversationAnalyzer.d.ts.map +1 -0
- package/dist/documentation/ConversationAnalyzer.js +157 -0
- package/dist/documentation/ConversationAnalyzer.js.map +1 -0
- package/dist/documentation/CrossReferencer.d.ts +67 -0
- package/dist/documentation/CrossReferencer.d.ts.map +1 -0
- package/dist/documentation/CrossReferencer.js +247 -0
- package/dist/documentation/CrossReferencer.js.map +1 -0
- package/dist/documentation/DocumentationGenerator.d.ts +22 -0
- package/dist/documentation/DocumentationGenerator.d.ts.map +1 -0
- package/dist/documentation/DocumentationGenerator.js +57 -0
- package/dist/documentation/DocumentationGenerator.js.map +1 -0
- package/dist/documentation/MarkdownFormatter.d.ts +26 -0
- package/dist/documentation/MarkdownFormatter.d.ts.map +1 -0
- package/dist/documentation/MarkdownFormatter.js +301 -0
- package/dist/documentation/MarkdownFormatter.js.map +1 -0
- package/dist/documentation/types.d.ts +176 -0
- package/dist/documentation/types.d.ts.map +1 -0
- package/dist/documentation/types.js +5 -0
- package/dist/documentation/types.js.map +1 -0
- package/dist/embeddings/ConfigManager.d.ts +46 -0
- package/dist/embeddings/ConfigManager.d.ts.map +1 -0
- package/dist/embeddings/ConfigManager.js +177 -0
- package/dist/embeddings/ConfigManager.js.map +1 -0
- package/dist/embeddings/EmbeddingConfig.d.ts +39 -0
- package/dist/embeddings/EmbeddingConfig.d.ts.map +1 -0
- package/dist/embeddings/EmbeddingConfig.js +132 -0
- package/dist/embeddings/EmbeddingConfig.js.map +1 -0
- package/dist/embeddings/EmbeddingGenerator.d.ts +51 -0
- package/dist/embeddings/EmbeddingGenerator.d.ts.map +1 -0
- package/dist/embeddings/EmbeddingGenerator.js +157 -0
- package/dist/embeddings/EmbeddingGenerator.js.map +1 -0
- package/dist/embeddings/EmbeddingProvider.d.ts +34 -0
- package/dist/embeddings/EmbeddingProvider.d.ts.map +1 -0
- package/dist/embeddings/EmbeddingProvider.js +6 -0
- package/dist/embeddings/EmbeddingProvider.js.map +1 -0
- package/dist/embeddings/ModelRegistry.d.ts +48 -0
- package/dist/embeddings/ModelRegistry.d.ts.map +1 -0
- package/dist/embeddings/ModelRegistry.js +170 -0
- package/dist/embeddings/ModelRegistry.js.map +1 -0
- package/dist/embeddings/VectorStore.d.ts +114 -0
- package/dist/embeddings/VectorStore.d.ts.map +1 -0
- package/dist/embeddings/VectorStore.js +393 -0
- package/dist/embeddings/VectorStore.js.map +1 -0
- package/dist/embeddings/providers/OllamaEmbeddings.d.ts +38 -0
- package/dist/embeddings/providers/OllamaEmbeddings.d.ts.map +1 -0
- package/dist/embeddings/providers/OllamaEmbeddings.js +125 -0
- package/dist/embeddings/providers/OllamaEmbeddings.js.map +1 -0
- package/dist/embeddings/providers/OpenAIEmbeddings.d.ts +40 -0
- package/dist/embeddings/providers/OpenAIEmbeddings.d.ts.map +1 -0
- package/dist/embeddings/providers/OpenAIEmbeddings.js +129 -0
- package/dist/embeddings/providers/OpenAIEmbeddings.js.map +1 -0
- package/dist/embeddings/providers/TransformersEmbeddings.d.ts +38 -0
- package/dist/embeddings/providers/TransformersEmbeddings.d.ts.map +1 -0
- package/dist/embeddings/providers/TransformersEmbeddings.js +115 -0
- package/dist/embeddings/providers/TransformersEmbeddings.js.map +1 -0
- package/dist/handoff/SessionHandoffStore.d.ts +80 -0
- package/dist/handoff/SessionHandoffStore.d.ts.map +1 -0
- package/dist/handoff/SessionHandoffStore.js +314 -0
- package/dist/handoff/SessionHandoffStore.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +115 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp-server.d.ts +27 -0
- package/dist/mcp-server.d.ts.map +1 -0
- package/dist/mcp-server.js +157 -0
- package/dist/mcp-server.js.map +1 -0
- package/dist/memory/WorkingMemoryStore.d.ts +83 -0
- package/dist/memory/WorkingMemoryStore.d.ts.map +1 -0
- package/dist/memory/WorkingMemoryStore.js +318 -0
- package/dist/memory/WorkingMemoryStore.js.map +1 -0
- package/dist/memory/types.d.ts +192 -0
- package/dist/memory/types.d.ts.map +1 -0
- package/dist/memory/types.js +8 -0
- package/dist/memory/types.js.map +1 -0
- package/dist/parsers/CodexConversationParser.d.ts +51 -0
- package/dist/parsers/CodexConversationParser.d.ts.map +1 -0
- package/dist/parsers/CodexConversationParser.js +301 -0
- package/dist/parsers/CodexConversationParser.js.map +1 -0
- package/dist/parsers/ConversationParser.d.ts +286 -0
- package/dist/parsers/ConversationParser.d.ts.map +1 -0
- package/dist/parsers/ConversationParser.js +795 -0
- package/dist/parsers/ConversationParser.js.map +1 -0
- package/dist/parsers/DecisionExtractor.d.ts +144 -0
- package/dist/parsers/DecisionExtractor.d.ts.map +1 -0
- package/dist/parsers/DecisionExtractor.js +434 -0
- package/dist/parsers/DecisionExtractor.js.map +1 -0
- package/dist/parsers/GitIntegrator.d.ts +156 -0
- package/dist/parsers/GitIntegrator.d.ts.map +1 -0
- package/dist/parsers/GitIntegrator.js +348 -0
- package/dist/parsers/GitIntegrator.js.map +1 -0
- package/dist/parsers/MistakeExtractor.d.ts +151 -0
- package/dist/parsers/MistakeExtractor.d.ts.map +1 -0
- package/dist/parsers/MistakeExtractor.js +460 -0
- package/dist/parsers/MistakeExtractor.js.map +1 -0
- package/dist/parsers/RequirementsExtractor.d.ts +166 -0
- package/dist/parsers/RequirementsExtractor.d.ts.map +1 -0
- package/dist/parsers/RequirementsExtractor.js +338 -0
- package/dist/parsers/RequirementsExtractor.js.map +1 -0
- package/dist/realtime/ConversationWatcher.d.ts +87 -0
- package/dist/realtime/ConversationWatcher.d.ts.map +1 -0
- package/dist/realtime/ConversationWatcher.js +204 -0
- package/dist/realtime/ConversationWatcher.js.map +1 -0
- package/dist/realtime/IncrementalParser.d.ts +83 -0
- package/dist/realtime/IncrementalParser.d.ts.map +1 -0
- package/dist/realtime/IncrementalParser.js +232 -0
- package/dist/realtime/IncrementalParser.js.map +1 -0
- package/dist/realtime/LiveExtractor.d.ts +72 -0
- package/dist/realtime/LiveExtractor.d.ts.map +1 -0
- package/dist/realtime/LiveExtractor.js +288 -0
- package/dist/realtime/LiveExtractor.js.map +1 -0
- package/dist/search/SemanticSearch.d.ts +121 -0
- package/dist/search/SemanticSearch.d.ts.map +1 -0
- package/dist/search/SemanticSearch.js +823 -0
- package/dist/search/SemanticSearch.js.map +1 -0
- package/dist/storage/BackupManager.d.ts +58 -0
- package/dist/storage/BackupManager.d.ts.map +1 -0
- package/dist/storage/BackupManager.js +223 -0
- package/dist/storage/BackupManager.js.map +1 -0
- package/dist/storage/ConversationStorage.d.ts +341 -0
- package/dist/storage/ConversationStorage.d.ts.map +1 -0
- package/dist/storage/ConversationStorage.js +792 -0
- package/dist/storage/ConversationStorage.js.map +1 -0
- package/dist/storage/DeletionService.d.ts +70 -0
- package/dist/storage/DeletionService.d.ts.map +1 -0
- package/dist/storage/DeletionService.js +253 -0
- package/dist/storage/DeletionService.js.map +1 -0
- package/dist/storage/GlobalIndex.d.ts +133 -0
- package/dist/storage/GlobalIndex.d.ts.map +1 -0
- package/dist/storage/GlobalIndex.js +310 -0
- package/dist/storage/GlobalIndex.js.map +1 -0
- package/dist/storage/SQLiteManager.d.ts +114 -0
- package/dist/storage/SQLiteManager.d.ts.map +1 -0
- package/dist/storage/SQLiteManager.js +636 -0
- package/dist/storage/SQLiteManager.js.map +1 -0
- package/dist/storage/migrations.d.ts +54 -0
- package/dist/storage/migrations.d.ts.map +1 -0
- package/dist/storage/migrations.js +285 -0
- package/dist/storage/migrations.js.map +1 -0
- package/dist/storage/schema.sql +436 -0
- package/dist/tools/ToolDefinitions.d.ts +946 -0
- package/dist/tools/ToolDefinitions.d.ts.map +1 -0
- package/dist/tools/ToolDefinitions.js +937 -0
- package/dist/tools/ToolDefinitions.js.map +1 -0
- package/dist/tools/ToolHandlers.d.ts +791 -0
- package/dist/tools/ToolHandlers.d.ts.map +1 -0
- package/dist/tools/ToolHandlers.js +3262 -0
- package/dist/tools/ToolHandlers.js.map +1 -0
- package/dist/types/ToolTypes.d.ts +824 -0
- package/dist/types/ToolTypes.d.ts.map +1 -0
- package/dist/types/ToolTypes.js +6 -0
- package/dist/types/ToolTypes.js.map +1 -0
- package/dist/utils/Logger.d.ts +70 -0
- package/dist/utils/Logger.d.ts.map +1 -0
- package/dist/utils/Logger.js +131 -0
- package/dist/utils/Logger.js.map +1 -0
- package/dist/utils/McpConfig.d.ts +54 -0
- package/dist/utils/McpConfig.d.ts.map +1 -0
- package/dist/utils/McpConfig.js +136 -0
- package/dist/utils/McpConfig.js.map +1 -0
- package/dist/utils/ProjectMigration.d.ts +82 -0
- package/dist/utils/ProjectMigration.d.ts.map +1 -0
- package/dist/utils/ProjectMigration.js +416 -0
- package/dist/utils/ProjectMigration.js.map +1 -0
- package/dist/utils/constants.d.ts +75 -0
- package/dist/utils/constants.d.ts.map +1 -0
- package/dist/utils/constants.js +105 -0
- package/dist/utils/constants.js.map +1 -0
- package/dist/utils/safeJson.d.ts +37 -0
- package/dist/utils/safeJson.d.ts.map +1 -0
- package/dist/utils/safeJson.js +48 -0
- package/dist/utils/safeJson.js.map +1 -0
- package/dist/utils/sanitization.d.ts +45 -0
- package/dist/utils/sanitization.d.ts.map +1 -0
- package/dist/utils/sanitization.js +153 -0
- package/dist/utils/sanitization.js.map +1 -0
- package/dist/utils/worktree.d.ts +15 -0
- package/dist/utils/worktree.d.ts.map +1 -0
- package/dist/utils/worktree.js +86 -0
- package/dist/utils/worktree.js.map +1 -0
- package/package.json +98 -0
- package/scripts/changelog-check.sh +62 -0
- package/scripts/check-node.js +17 -0
- package/scripts/dev-config.js +56 -0
- 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
|