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 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 menu, or start chatting!');
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 Menu
195
- if (userInput.trim() === "/") {
230
+ // Handle Slash Commands
231
+ if (userInput.trim() === "/" || userInput.trim().startsWith("/")) {
196
232
  const currentModel = modelProvider.modelId;
197
- console.log("\n┌────────────────────────────────────────┐");
198
- console.log("│ AVAILABLE COMMANDS │");
199
- console.log("└────────────────────────────────────────┘\n");
200
- const { action } = await inquirer_1.default.prompt([
201
- {
202
- type: "list",
203
- name: "action",
204
- message: "Choose an option:",
205
- choices: [
206
- "1. Select Model",
207
- "2. Usage",
208
- "3. Tools",
209
- "4. Todos",
210
- "5. Clear Todos",
211
- "6. Context",
212
- "7. Clear History",
213
- "8. API Key",
214
- "9. Exit",
215
- ],
216
- },
217
- ]);
218
- // Select Model - Toggle between different models
219
- if (action === "1. Select Model") {
220
- // Fetch models from Groq API if not cached
221
- if (cachedModels.length === 0) {
222
- const spinner = (0, ora_1.default)("Fetching available models from Groq...").start();
223
- cachedModels = await (0, groq_models_1.fetchGroqModels)(apiKey);
224
- spinner.succeed(`Found ${cachedModels.length} models`);
225
- }
226
- // Group models by owner
227
- const grouped = (0, groq_models_1.groupModelsByOwner)(cachedModels);
228
- const modelChoices = [];
229
- // Build choices grouped by owner
230
- for (const [owner, models] of grouped) {
231
- modelChoices.push(new inquirer_1.default.Separator(`─── ${owner} ───`));
232
- for (const model of models) {
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
- const { selectedModel } = await inquirer_1.default.prompt([
243
- {
244
- type: "list",
245
- name: "selectedModel",
246
- message: `Select a model (current: ${currentModel}):`,
247
- choices: modelChoices,
248
- pageSize: 15,
249
- loop: false,
250
- },
251
- ]);
252
- if (selectedModel && selectedModel !== currentModel) {
253
- const oldModel = currentModel;
254
- (0, config_1.setActiveModel)(selectedModel);
255
- modelProvider.setModel(selectedModel);
256
- ui_1.log.success(`Switched to model: ${selectedModel}`);
257
- tracker_1.tracker.modelSwitch(oldModel, selectedModel, true);
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
- else if (selectedModel === currentModel) {
260
- ui_1.log.info(`Already using ${selectedModel}`);
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
- continue;
263
- }
264
- // Usage - Show model usage and stats
265
- if (action === "2. Usage") {
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
- const modelInfo = cachedModels.find((m) => m.id === currentModel);
277
- if (modelInfo) {
278
- console.log(` Provider: ${modelInfo.owned_by}`);
279
- console.log(` Context: ${(0, groq_models_1.formatContextWindow)(modelInfo.context_window)} tokens`);
280
- console.log(` Status: ${modelInfo.active ? "Active" : "Inactive"}`);
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
- // Handle direct slash commands
343
- if (userInput.startsWith("/")) {
344
- const cmd = userInput.trim().toLowerCase();
345
- if (cmd === "/exit" || cmd === "/quit")
346
- process.exit(0);
347
- if (cmd === "/clear") {
348
- chatHandler.clearHistory();
349
- ui_1.log.success("History cleared.");
350
- continue;
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
- if (cmd === "/context") {
353
- ui_1.log.info(contextMessage || "No context.");
354
- continue;
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
- if (cmd === "/tools") {
357
- console.log("\n📦 Available Tools:\n");
358
- console.log(toolRegistry.getToolDescriptions());
359
- console.log("");
360
- continue;
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
- if (cmd === "/todos") {
363
- const session = (0, config_2.getSessionData)();
364
- (0, ui_1.showTodoList)(session.todos);
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);