prab-cli 1.0.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +249 -163
- package/dist/lib/chat-handler.js +128 -23
- package/dist/lib/config.js +12 -12
- package/dist/lib/context.js +7 -12
- package/dist/lib/groq-models.js +3 -3
- package/dist/lib/groq.js +6 -6
- package/dist/lib/safety.js +29 -34
- package/dist/lib/slash-commands.js +94 -0
- package/dist/lib/tracker.js +74 -72
- package/dist/lib/ui.js +219 -101
- package/package.json +27 -3
package/dist/index.js
CHANGED
|
@@ -1,5 +1,38 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
"use strict";
|
|
3
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4
|
+
if (k2 === undefined) k2 = k;
|
|
5
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
6
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
7
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
8
|
+
}
|
|
9
|
+
Object.defineProperty(o, k2, desc);
|
|
10
|
+
}) : (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
o[k2] = m[k];
|
|
13
|
+
}));
|
|
14
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
15
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
16
|
+
}) : function(o, v) {
|
|
17
|
+
o["default"] = v;
|
|
18
|
+
});
|
|
19
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
20
|
+
var ownKeys = function(o) {
|
|
21
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
22
|
+
var ar = [];
|
|
23
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
24
|
+
return ar;
|
|
25
|
+
};
|
|
26
|
+
return ownKeys(o);
|
|
27
|
+
};
|
|
28
|
+
return function (mod) {
|
|
29
|
+
if (mod && mod.__esModule) return mod;
|
|
30
|
+
var result = {};
|
|
31
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
32
|
+
__setModuleDefault(result, mod);
|
|
33
|
+
return result;
|
|
34
|
+
};
|
|
35
|
+
})();
|
|
3
36
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
4
37
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
38
|
};
|
|
@@ -10,6 +43,8 @@ const config_1 = require("./lib/config");
|
|
|
10
43
|
const context_1 = require("./lib/context");
|
|
11
44
|
const ui_1 = require("./lib/ui");
|
|
12
45
|
const config_2 = require("./lib/config");
|
|
46
|
+
const slash_commands_1 = require("./lib/slash-commands");
|
|
47
|
+
const select_1 = __importStar(require("@inquirer/select"));
|
|
13
48
|
const ora_1 = __importDefault(require("ora"));
|
|
14
49
|
// Import tool system
|
|
15
50
|
const base_1 = require("./lib/tools/base");
|
|
@@ -25,6 +60,7 @@ const groq_models_1 = require("./lib/groq-models");
|
|
|
25
60
|
// Import chat handler and safety
|
|
26
61
|
const chat_handler_1 = require("./lib/chat-handler");
|
|
27
62
|
const safety_1 = require("./lib/safety");
|
|
63
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
28
64
|
const tracker_1 = require("./lib/tracker");
|
|
29
65
|
// Cache for available models
|
|
30
66
|
let cachedModels = [];
|
|
@@ -176,7 +212,7 @@ program.action(async () => {
|
|
|
176
212
|
}
|
|
177
213
|
// Initialize chat handler
|
|
178
214
|
const chatHandler = new chat_handler_1.ChatHandler(toolRegistry, toolExecutor, modelProvider, contextMessage);
|
|
179
|
-
ui_1.log.info('Type "/" for commands
|
|
215
|
+
ui_1.log.info('Type "/" for commands (searchable), or start chatting!');
|
|
180
216
|
// Display any existing todos
|
|
181
217
|
const session = (0, config_2.getSessionData)();
|
|
182
218
|
if (session.todos && session.todos.length > 0) {
|
|
@@ -191,184 +227,234 @@ program.action(async () => {
|
|
|
191
227
|
message: ">",
|
|
192
228
|
},
|
|
193
229
|
]);
|
|
194
|
-
// Handle Slash Commands
|
|
195
|
-
if (userInput.trim() === "/") {
|
|
230
|
+
// Handle Slash Commands
|
|
231
|
+
if (userInput.trim() === "/" || userInput.trim().startsWith("/")) {
|
|
196
232
|
const currentModel = modelProvider.modelId;
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
"
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
const isCurrent = model.id === currentModel;
|
|
234
|
-
const ctx = (0, groq_models_1.formatContextWindow)(model.context_window);
|
|
235
|
-
modelChoices.push({
|
|
236
|
-
name: `${isCurrent ? "✓ " : " "}${model.id} (${ctx} ctx)`,
|
|
237
|
-
value: model.id,
|
|
238
|
-
short: model.id,
|
|
233
|
+
// Show the searchable slash command menu
|
|
234
|
+
const action = await (0, slash_commands_1.showSlashCommandMenu)();
|
|
235
|
+
if (!action) {
|
|
236
|
+
// User cancelled
|
|
237
|
+
continue;
|
|
238
|
+
}
|
|
239
|
+
// Execute the selected command
|
|
240
|
+
switch (action) {
|
|
241
|
+
case "model": {
|
|
242
|
+
// Fetch models from Groq API if not cached
|
|
243
|
+
if (cachedModels.length === 0) {
|
|
244
|
+
const spinner = (0, ora_1.default)("Fetching available models from Groq...").start();
|
|
245
|
+
cachedModels = await (0, groq_models_1.fetchGroqModels)(apiKey);
|
|
246
|
+
spinner.succeed(`Found ${cachedModels.length} models`);
|
|
247
|
+
}
|
|
248
|
+
// Group models by owner
|
|
249
|
+
const grouped = (0, groq_models_1.groupModelsByOwner)(cachedModels);
|
|
250
|
+
const modelChoices = [];
|
|
251
|
+
// Build choices grouped by owner
|
|
252
|
+
for (const [owner, models] of grouped) {
|
|
253
|
+
modelChoices.push(new select_1.Separator(`─── ${owner} ───`));
|
|
254
|
+
for (const model of models) {
|
|
255
|
+
const isCurrent = model.id === currentModel;
|
|
256
|
+
const ctx = (0, groq_models_1.formatContextWindow)(model.context_window);
|
|
257
|
+
modelChoices.push({
|
|
258
|
+
name: `${isCurrent ? "✓ " : " "}${model.id} (${ctx} ctx)`,
|
|
259
|
+
value: model.id,
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
try {
|
|
264
|
+
const selectedModel = await (0, select_1.default)({
|
|
265
|
+
message: `Select a model (current: ${currentModel}):`,
|
|
266
|
+
choices: modelChoices,
|
|
267
|
+
pageSize: 15,
|
|
268
|
+
loop: false,
|
|
239
269
|
});
|
|
270
|
+
if (selectedModel && selectedModel !== currentModel) {
|
|
271
|
+
const oldModel = currentModel;
|
|
272
|
+
(0, config_1.setActiveModel)(selectedModel);
|
|
273
|
+
modelProvider.setModel(selectedModel);
|
|
274
|
+
ui_1.log.success(`Switched to model: ${selectedModel}`);
|
|
275
|
+
tracker_1.tracker.modelSwitch(oldModel, selectedModel, true);
|
|
276
|
+
}
|
|
277
|
+
else if (selectedModel === currentModel) {
|
|
278
|
+
ui_1.log.info(`Already using ${selectedModel}`);
|
|
279
|
+
}
|
|
240
280
|
}
|
|
281
|
+
catch (e) {
|
|
282
|
+
// User cancelled with Ctrl+C
|
|
283
|
+
}
|
|
284
|
+
break;
|
|
241
285
|
}
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
const
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
286
|
+
case "usage": {
|
|
287
|
+
console.log("\n┌─────────────────────────────────────┐");
|
|
288
|
+
console.log("│ MODEL INFO │");
|
|
289
|
+
console.log("└─────────────────────────────────────┘\n");
|
|
290
|
+
console.log(` Current Model: ${currentModel}`);
|
|
291
|
+
// Find model in cache and show details
|
|
292
|
+
if (cachedModels.length === 0) {
|
|
293
|
+
const spinner = (0, ora_1.default)("Fetching model info...").start();
|
|
294
|
+
cachedModels = await (0, groq_models_1.fetchGroqModels)(apiKey);
|
|
295
|
+
spinner.stop();
|
|
296
|
+
}
|
|
297
|
+
const modelInfo = cachedModels.find((m) => m.id === currentModel);
|
|
298
|
+
if (modelInfo) {
|
|
299
|
+
console.log(` Provider: ${modelInfo.owned_by}`);
|
|
300
|
+
console.log(` Context: ${(0, groq_models_1.formatContextWindow)(modelInfo.context_window)} tokens`);
|
|
301
|
+
console.log(` Status: ${modelInfo.active ? "Active" : "Inactive"}`);
|
|
302
|
+
}
|
|
303
|
+
console.log("\n┌─────────────────────────────────────┐");
|
|
304
|
+
console.log("│ TOKEN CONSUMPTION │");
|
|
305
|
+
console.log("└─────────────────────────────────────┘\n");
|
|
306
|
+
const usageStats = chatHandler.getUsageStats();
|
|
307
|
+
console.log(` Prompt Tokens: ${usageStats.promptTokens.toLocaleString()}`);
|
|
308
|
+
console.log(` Completion Tokens: ${usageStats.completionTokens.toLocaleString()}`);
|
|
309
|
+
console.log(` Total Tokens: ${usageStats.totalTokens.toLocaleString()}`);
|
|
310
|
+
console.log(` API Requests: ${usageStats.requestCount}`);
|
|
311
|
+
console.log("\n┌─────────────────────────────────────┐");
|
|
312
|
+
console.log("│ SESSION STATS │");
|
|
313
|
+
console.log("└─────────────────────────────────────┘\n");
|
|
314
|
+
console.log(` Messages: ${chatHandler.getMessageCount()}`);
|
|
315
|
+
console.log(` Tools: ${toolRegistry.count()} available`);
|
|
316
|
+
console.log(` Session ID: ${tracker_1.tracker.getSessionId()}`);
|
|
317
|
+
console.log("");
|
|
318
|
+
break;
|
|
258
319
|
}
|
|
259
|
-
|
|
260
|
-
|
|
320
|
+
case "tools": {
|
|
321
|
+
console.log("\n┌─────────────────────────────────────┐");
|
|
322
|
+
console.log("│ AVAILABLE TOOLS │");
|
|
323
|
+
console.log("└─────────────────────────────────────┘\n");
|
|
324
|
+
console.log(toolRegistry.getToolDescriptions());
|
|
325
|
+
console.log("");
|
|
326
|
+
break;
|
|
261
327
|
}
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
console.log("\n┌─────────────────────────────────────┐");
|
|
267
|
-
console.log("│ MODEL USAGE │");
|
|
268
|
-
console.log("└─────────────────────────────────────┘\n");
|
|
269
|
-
console.log(` Current Model: ${currentModel}`);
|
|
270
|
-
// Find model in cache and show details
|
|
271
|
-
if (cachedModels.length === 0) {
|
|
272
|
-
const spinner = (0, ora_1.default)("Fetching model info...").start();
|
|
273
|
-
cachedModels = await (0, groq_models_1.fetchGroqModels)(apiKey);
|
|
274
|
-
spinner.stop();
|
|
328
|
+
case "todos": {
|
|
329
|
+
const session = (0, config_2.getSessionData)();
|
|
330
|
+
(0, ui_1.showTodoList)(session.todos);
|
|
331
|
+
break;
|
|
275
332
|
}
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
333
|
+
case "clear-todos": {
|
|
334
|
+
(0, config_1.clearSessionData)();
|
|
335
|
+
ui_1.log.success("Todos cleared.");
|
|
336
|
+
break;
|
|
337
|
+
}
|
|
338
|
+
case "context": {
|
|
339
|
+
console.log("\n┌─────────────────────────────────────┐");
|
|
340
|
+
console.log("│ FILE CONTEXT │");
|
|
341
|
+
console.log("└─────────────────────────────────────┘\n");
|
|
342
|
+
console.log(contextMessage || " No context loaded.");
|
|
343
|
+
console.log("");
|
|
344
|
+
break;
|
|
345
|
+
}
|
|
346
|
+
case "clear": {
|
|
347
|
+
chatHandler.clearHistory();
|
|
348
|
+
ui_1.log.success("Chat history cleared.");
|
|
349
|
+
break;
|
|
350
|
+
}
|
|
351
|
+
case "api-key": {
|
|
352
|
+
const { key } = await inquirer_1.default.prompt([
|
|
353
|
+
{
|
|
354
|
+
type: "password",
|
|
355
|
+
name: "key",
|
|
356
|
+
message: "Enter new API Key:",
|
|
357
|
+
mask: "*",
|
|
358
|
+
},
|
|
359
|
+
]);
|
|
360
|
+
(0, config_1.setApiKey)(key.trim());
|
|
361
|
+
apiKey = key.trim();
|
|
362
|
+
modelProvider.initialize(key.trim(), modelConfig.modelId);
|
|
363
|
+
cachedModels = []; // Clear model cache
|
|
364
|
+
ui_1.log.success("API Key updated.");
|
|
365
|
+
break;
|
|
366
|
+
}
|
|
367
|
+
case "exit": {
|
|
368
|
+
process.exit(0);
|
|
281
369
|
}
|
|
282
|
-
console.log("\n┌─────────────────────────────────────┐");
|
|
283
|
-
console.log("│ SESSION STATS │");
|
|
284
|
-
console.log("└─────────────────────────────────────┘\n");
|
|
285
|
-
console.log(` Messages: ${chatHandler.getMessageCount()}`);
|
|
286
|
-
console.log(` Tools: ${toolRegistry.count()} available`);
|
|
287
|
-
console.log(` Session ID: ${tracker_1.tracker.getSessionId()}`);
|
|
288
|
-
console.log("");
|
|
289
|
-
continue;
|
|
290
|
-
}
|
|
291
|
-
if (action === "3. Tools") {
|
|
292
|
-
console.log("\n┌─────────────────────────────────────┐");
|
|
293
|
-
console.log("│ AVAILABLE TOOLS │");
|
|
294
|
-
console.log("└─────────────────────────────────────┘\n");
|
|
295
|
-
console.log(toolRegistry.getToolDescriptions());
|
|
296
|
-
console.log("");
|
|
297
|
-
continue;
|
|
298
|
-
}
|
|
299
|
-
if (action === "4. Todos") {
|
|
300
|
-
const session = (0, config_2.getSessionData)();
|
|
301
|
-
(0, ui_1.showTodoList)(session.todos);
|
|
302
|
-
continue;
|
|
303
|
-
}
|
|
304
|
-
if (action === "5. Clear Todos") {
|
|
305
|
-
(0, config_1.clearSessionData)();
|
|
306
|
-
ui_1.log.success("Todos cleared.");
|
|
307
|
-
continue;
|
|
308
|
-
}
|
|
309
|
-
if (action === "6. Context") {
|
|
310
|
-
console.log("\n┌─────────────────────────────────────┐");
|
|
311
|
-
console.log("│ FILE CONTEXT │");
|
|
312
|
-
console.log("└─────────────────────────────────────┘\n");
|
|
313
|
-
console.log(contextMessage || " No context loaded.");
|
|
314
|
-
console.log("");
|
|
315
|
-
continue;
|
|
316
|
-
}
|
|
317
|
-
if (action === "7. Clear History") {
|
|
318
|
-
chatHandler.clearHistory();
|
|
319
|
-
ui_1.log.success("Chat history cleared.");
|
|
320
|
-
continue;
|
|
321
|
-
}
|
|
322
|
-
if (action === "8. API Key") {
|
|
323
|
-
const { key } = await inquirer_1.default.prompt([
|
|
324
|
-
{
|
|
325
|
-
type: "password",
|
|
326
|
-
name: "key",
|
|
327
|
-
message: "Enter new API Key:",
|
|
328
|
-
mask: "*",
|
|
329
|
-
},
|
|
330
|
-
]);
|
|
331
|
-
(0, config_1.setApiKey)(key.trim());
|
|
332
|
-
apiKey = key.trim();
|
|
333
|
-
modelProvider.initialize(key.trim(), modelConfig.modelId);
|
|
334
|
-
cachedModels = []; // Clear model cache
|
|
335
|
-
ui_1.log.success("API Key updated.");
|
|
336
|
-
continue;
|
|
337
370
|
}
|
|
338
|
-
if (action === "9. Exit")
|
|
339
|
-
process.exit(0);
|
|
340
371
|
continue;
|
|
341
372
|
}
|
|
342
|
-
//
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
373
|
+
// Process user input with chat handler
|
|
374
|
+
const result = await chatHandler.processUserInput(userInput);
|
|
375
|
+
// Handle model errors - offer to switch models
|
|
376
|
+
if (!result.success && result.isModelError) {
|
|
377
|
+
console.log("");
|
|
378
|
+
console.log(chalk_1.default.yellow("┌─────────────────────────────────────────────────────┐"));
|
|
379
|
+
console.log(chalk_1.default.yellow("│") +
|
|
380
|
+
chalk_1.default.red.bold(" Model Error Detected ") +
|
|
381
|
+
chalk_1.default.yellow("│"));
|
|
382
|
+
console.log(chalk_1.default.yellow("└─────────────────────────────────────────────────────┘"));
|
|
383
|
+
const errorMessages = {
|
|
384
|
+
rate_limit: "Rate limit exceeded. The model is receiving too many requests.",
|
|
385
|
+
model_unavailable: "Model is currently unavailable or overloaded.",
|
|
386
|
+
auth_error: "Authentication error. Please check your API key.",
|
|
387
|
+
unknown: "An error occurred with the current model.",
|
|
388
|
+
};
|
|
389
|
+
console.log(chalk_1.default.dim(` ${errorMessages[result.errorType || "unknown"]}`));
|
|
390
|
+
console.log("");
|
|
391
|
+
console.log(chalk_1.default.cyan(" Would you like to switch to a different model?"));
|
|
392
|
+
console.log("");
|
|
393
|
+
// Fetch models if not cached
|
|
394
|
+
if (cachedModels.length === 0) {
|
|
395
|
+
const spinner = (0, ora_1.default)("Fetching available models...").start();
|
|
396
|
+
cachedModels = await (0, groq_models_1.fetchGroqModels)(apiKey);
|
|
397
|
+
spinner.succeed(`Found ${cachedModels.length} models`);
|
|
351
398
|
}
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
399
|
+
// Filter out the current model and build choices
|
|
400
|
+
const currentModel = modelProvider.modelId;
|
|
401
|
+
const availableModels = cachedModels.filter((m) => m.id !== currentModel);
|
|
402
|
+
const grouped = (0, groq_models_1.groupModelsByOwner)(availableModels);
|
|
403
|
+
const modelChoices = [];
|
|
404
|
+
// Add "Cancel" option first
|
|
405
|
+
modelChoices.push({
|
|
406
|
+
name: chalk_1.default.dim(" Cancel (keep current model)"),
|
|
407
|
+
value: "__cancel__",
|
|
408
|
+
});
|
|
409
|
+
modelChoices.push(new select_1.Separator("─── Available Models ───"));
|
|
410
|
+
for (const [owner, models] of grouped) {
|
|
411
|
+
modelChoices.push(new select_1.Separator(`─── ${owner} ───`));
|
|
412
|
+
for (const model of models) {
|
|
413
|
+
const ctx = (0, groq_models_1.formatContextWindow)(model.context_window);
|
|
414
|
+
modelChoices.push({
|
|
415
|
+
name: ` ${model.id} (${ctx} ctx)`,
|
|
416
|
+
value: model.id,
|
|
417
|
+
});
|
|
418
|
+
}
|
|
355
419
|
}
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
420
|
+
try {
|
|
421
|
+
const selectedModel = await (0, select_1.default)({
|
|
422
|
+
message: "Select a model to switch to:",
|
|
423
|
+
choices: modelChoices,
|
|
424
|
+
pageSize: 12,
|
|
425
|
+
loop: false,
|
|
426
|
+
});
|
|
427
|
+
if (selectedModel && selectedModel !== "__cancel__") {
|
|
428
|
+
const oldModel = currentModel;
|
|
429
|
+
(0, config_1.setActiveModel)(selectedModel);
|
|
430
|
+
modelProvider.setModel(selectedModel);
|
|
431
|
+
chatHandler.updateModelProvider(modelProvider);
|
|
432
|
+
ui_1.log.success(`Switched to model: ${selectedModel}`);
|
|
433
|
+
tracker_1.tracker.modelSwitch(oldModel, selectedModel, true);
|
|
434
|
+
// Ask if user wants to retry the last message
|
|
435
|
+
console.log("");
|
|
436
|
+
const { retry } = await inquirer_1.default.prompt([
|
|
437
|
+
{
|
|
438
|
+
type: "confirm",
|
|
439
|
+
name: "retry",
|
|
440
|
+
message: "Retry your last message with the new model?",
|
|
441
|
+
default: true,
|
|
442
|
+
},
|
|
443
|
+
]);
|
|
444
|
+
if (retry) {
|
|
445
|
+
console.log(chalk_1.default.dim("Retrying with new model..."));
|
|
446
|
+
await chatHandler.processUserInput(userInput);
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
else {
|
|
450
|
+
ui_1.log.info("Keeping current model. You can try again or switch models with /model");
|
|
451
|
+
}
|
|
361
452
|
}
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
continue;
|
|
453
|
+
catch (e) {
|
|
454
|
+
// User cancelled with Ctrl+C
|
|
455
|
+
ui_1.log.info("Model switch cancelled.");
|
|
366
456
|
}
|
|
367
|
-
ui_1.log.warning(`Unknown command: ${cmd}. Type "/" for menu.`);
|
|
368
|
-
continue;
|
|
369
457
|
}
|
|
370
|
-
// Process user input with chat handler
|
|
371
|
-
await chatHandler.processUserInput(userInput);
|
|
372
458
|
}
|
|
373
459
|
});
|
|
374
460
|
program.parse(process.argv);
|