megabuff 0.6.0 → 0.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/README.md +343 -281
- package/THEMES.md +150 -0
- package/dist/config.d.ts +10 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +15 -0
- package/dist/config.js.map +1 -1
- package/dist/index.js +456 -117
- package/dist/index.js.map +1 -1
- package/dist/theme-utils.d.ts +14 -0
- package/dist/theme-utils.d.ts.map +1 -0
- package/dist/theme-utils.js +30 -0
- package/dist/theme-utils.js.map +1 -0
- package/dist/themes.d.ts +22 -0
- package/dist/themes.d.ts.map +1 -0
- package/dist/themes.js +253 -0
- package/dist/themes.js.map +1 -0
- package/media/github-media-banner.png +0 -0
- package/megabuff-0.7.0.tgz +0 -0
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -6,9 +6,24 @@ import OpenAI from "openai";
|
|
|
6
6
|
import Anthropic from "@anthropic-ai/sdk";
|
|
7
7
|
import { GoogleGenerativeAI } from "@google/generative-ai";
|
|
8
8
|
import * as clipboardy from "clipboardy";
|
|
9
|
-
import
|
|
9
|
+
import chalk from "chalk";
|
|
10
|
+
import { getApiKeyInfo, setApiKey, removeApiKey, hasApiKey, getConfig, getProvider, setProvider, setModel, getModel, normalizeProvider, getProviderForModel, MODEL_PROVIDER_MAP, PROVIDERS, getThemeName, setThemeName } from "./config.js";
|
|
10
11
|
import { getDefaultModel } from "./models.js";
|
|
12
|
+
import { themes, getAllThemeNames, isValidTheme } from "./themes.js";
|
|
13
|
+
import { getCurrentTheme, clearThemeCache } from "./theme-utils.js";
|
|
11
14
|
const program = new Command();
|
|
15
|
+
// Initialize theme at startup
|
|
16
|
+
let theme = await getCurrentTheme();
|
|
17
|
+
// Configure help to use theme colors
|
|
18
|
+
program.configureHelp({
|
|
19
|
+
styleTitle: (str) => theme.colors.highlight(str),
|
|
20
|
+
styleCommandText: (str) => theme.colors.primary(str),
|
|
21
|
+
styleCommandDescription: (str) => theme.colors.secondary(str),
|
|
22
|
+
styleDescriptionText: (str) => theme.colors.secondary(str),
|
|
23
|
+
styleOptionText: (str) => theme.colors.info(str),
|
|
24
|
+
styleArgumentText: (str) => theme.colors.accent(str),
|
|
25
|
+
styleSubcommandText: (str) => theme.colors.primary(str),
|
|
26
|
+
});
|
|
12
27
|
function isDevMode() {
|
|
13
28
|
// `npm run dev` sets npm_lifecycle_event=dev
|
|
14
29
|
if (process.env.npm_lifecycle_event === "dev")
|
|
@@ -23,7 +38,7 @@ function debugLog(...args) {
|
|
|
23
38
|
if (!isDevMode())
|
|
24
39
|
return;
|
|
25
40
|
// stderr to avoid polluting stdout output/pipes
|
|
26
|
-
console.error("[megabuff:debug]", ...args);
|
|
41
|
+
console.error(theme.colors.dim("[megabuff:debug]"), ...args);
|
|
27
42
|
}
|
|
28
43
|
function maskSecret(secret) {
|
|
29
44
|
if (!secret)
|
|
@@ -74,7 +89,7 @@ async function getInput(inlinePrompt, options) {
|
|
|
74
89
|
output: process.stdout,
|
|
75
90
|
});
|
|
76
91
|
debugLog("input.source=interactive");
|
|
77
|
-
console.log("Enter your prompt (press Ctrl+D when done):");
|
|
92
|
+
console.log(theme.colors.primary("Enter your prompt (press Ctrl+D when done):"));
|
|
78
93
|
const lines = [];
|
|
79
94
|
rl.on("line", (line) => {
|
|
80
95
|
lines.push(line);
|
|
@@ -221,8 +236,8 @@ function createSpinner(message) {
|
|
|
221
236
|
let timer;
|
|
222
237
|
let lastLen = 0;
|
|
223
238
|
const render = (text) => {
|
|
224
|
-
const frame = frames[i++ % frames.length];
|
|
225
|
-
const line = `${frame} ${text}`;
|
|
239
|
+
const frame = theme.colors.primary(frames[i++ % frames.length]);
|
|
240
|
+
const line = `${frame} ${theme.colors.dim(text)}`;
|
|
226
241
|
const padded = line + " ".repeat(Math.max(0, lastLen - line.length));
|
|
227
242
|
lastLen = Math.max(lastLen, line.length);
|
|
228
243
|
process.stderr.write(`\r${padded}`);
|
|
@@ -241,7 +256,7 @@ function createSpinner(message) {
|
|
|
241
256
|
clearInterval(timer);
|
|
242
257
|
timer = undefined;
|
|
243
258
|
const text = finalText ?? message;
|
|
244
|
-
const padded = text + " ".repeat(Math.max(0, lastLen - text.length));
|
|
259
|
+
const padded = theme.colors.success(`✓ ${text}`) + " ".repeat(Math.max(0, lastLen - text.length));
|
|
245
260
|
process.stderr.write(`\r${padded}\n`);
|
|
246
261
|
},
|
|
247
262
|
fail(finalText) {
|
|
@@ -251,7 +266,7 @@ function createSpinner(message) {
|
|
|
251
266
|
clearInterval(timer);
|
|
252
267
|
timer = undefined;
|
|
253
268
|
const text = finalText ?? message;
|
|
254
|
-
const padded = text + " ".repeat(Math.max(0, lastLen - text.length));
|
|
269
|
+
const padded = theme.colors.error(`✗ ${text}`) + " ".repeat(Math.max(0, lastLen - text.length));
|
|
255
270
|
process.stderr.write(`\r${padded}\n`);
|
|
256
271
|
}
|
|
257
272
|
};
|
|
@@ -270,14 +285,14 @@ function formatProviderLabel(p) {
|
|
|
270
285
|
async function promptFirstRunConfig() {
|
|
271
286
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
272
287
|
try {
|
|
273
|
-
console.log("\
|
|
274
|
-
console.log("Select the provider that will supply the token:\n");
|
|
288
|
+
console.log(theme.colors.warning("\n⚡ No BYOK token configured yet."));
|
|
289
|
+
console.log(theme.colors.primary("Select the provider that will supply the token:\n"));
|
|
275
290
|
PROVIDERS.forEach((p, idx) => {
|
|
276
|
-
console.log(` ${idx + 1}) ${formatProviderLabel(p)}`);
|
|
291
|
+
console.log(theme.colors.secondary(` ${chalk.bold(idx + 1)}) ${formatProviderLabel(p)}`));
|
|
277
292
|
});
|
|
278
293
|
let provider;
|
|
279
294
|
while (!provider) {
|
|
280
|
-
const raw = await rl.question("\nProvider (number or name): ");
|
|
295
|
+
const raw = await rl.question(theme.colors.primary("\nProvider (number or name): "));
|
|
281
296
|
const trimmed = raw.trim();
|
|
282
297
|
const asNum = Number(trimmed);
|
|
283
298
|
if (Number.isFinite(asNum) && asNum >= 1 && asNum <= PROVIDERS.length) {
|
|
@@ -286,14 +301,14 @@ async function promptFirstRunConfig() {
|
|
|
286
301
|
}
|
|
287
302
|
provider = normalizeProvider(trimmed);
|
|
288
303
|
if (!provider) {
|
|
289
|
-
console.log(`Please choose one of: ${PROVIDERS.join(", ")}`);
|
|
304
|
+
console.log(theme.colors.warning(`Please choose one of: ${PROVIDERS.join(", ")}`));
|
|
290
305
|
}
|
|
291
306
|
}
|
|
292
|
-
const apiKey = (await rl.question("Enter your BYOK token: ")).trim();
|
|
307
|
+
const apiKey = (await rl.question(theme.colors.primary("Enter your BYOK token: "))).trim();
|
|
293
308
|
if (!apiKey) {
|
|
294
309
|
throw new Error("No token provided.");
|
|
295
310
|
}
|
|
296
|
-
const store = (await rl.question("Store in system keychain? (Y/n): ")).trim().toLowerCase();
|
|
311
|
+
const store = (await rl.question(theme.colors.primary("Store in system keychain? (Y/n): "))).trim().toLowerCase();
|
|
297
312
|
const useKeychain = store === "" || store === "y" || store === "yes";
|
|
298
313
|
if (!provider) {
|
|
299
314
|
throw new Error("No provider selected.");
|
|
@@ -308,24 +323,40 @@ async function promptFirstRunConfig() {
|
|
|
308
323
|
* Output the result based on options
|
|
309
324
|
*/
|
|
310
325
|
async function outputResult(original, optimized, options) {
|
|
326
|
+
// Calculate statistics
|
|
327
|
+
const originalWords = original.trim().split(/\s+/).length;
|
|
328
|
+
const optimizedWords = optimized.trim().split(/\s+/).length;
|
|
329
|
+
const wordDiff = optimizedWords - originalWords;
|
|
330
|
+
const wordDiffPercent = originalWords > 0 ? ((wordDiff / originalWords) * 100).toFixed(1) : "0";
|
|
331
|
+
const wordDiffSign = wordDiff > 0 ? "+" : "";
|
|
311
332
|
// Copy to clipboard by default (unless --no-copy is used)
|
|
312
333
|
if (options.copy !== false) {
|
|
313
334
|
try {
|
|
314
335
|
await clipboardy.default.write(optimized);
|
|
315
|
-
console.error("✓ Copied to clipboard — press Ctrl+V (or Paste) to use the optimized prompt");
|
|
316
336
|
console.error("");
|
|
317
|
-
console.error("
|
|
337
|
+
console.error(theme.colors.primary("╭─────────────────────────────────────────────────╮"));
|
|
338
|
+
console.error(theme.colors.primary("│") + theme.colors.success(" ✓ Copied to clipboard! ") + theme.colors.primary("│"));
|
|
339
|
+
console.error(theme.colors.primary("╰─────────────────────────────────────────────────╯"));
|
|
340
|
+
console.error(theme.colors.dim(" Press ") + theme.colors.accent("Ctrl+V") + theme.colors.dim(" to paste your optimized prompt"));
|
|
341
|
+
console.error("");
|
|
342
|
+
console.error(theme.colors.dim(" 📊 Stats: ") + theme.colors.info(`${originalWords} → ${optimizedWords} words `) +
|
|
343
|
+
theme.colors.dim("(") + (wordDiff > 0 ? theme.colors.warning : theme.colors.success)(`${wordDiffSign}${wordDiffPercent}%`) + theme.colors.dim(")"));
|
|
344
|
+
console.error("");
|
|
345
|
+
console.error(theme.colors.primary("─".repeat(50)));
|
|
318
346
|
console.error("");
|
|
319
347
|
}
|
|
320
348
|
catch (error) {
|
|
321
349
|
const errMsg = error instanceof Error ? error.message : String(error);
|
|
322
|
-
console.error(`⚠ Failed to copy to clipboard: ${errMsg}`);
|
|
350
|
+
console.error(theme.colors.warning(`⚠ Failed to copy to clipboard: ${errMsg}`));
|
|
323
351
|
}
|
|
324
352
|
}
|
|
325
353
|
// If output file specified, write to file
|
|
326
354
|
if (options.output) {
|
|
327
355
|
await fs.writeFile(options.output, optimized, "utf-8");
|
|
328
|
-
console.error(
|
|
356
|
+
console.error("");
|
|
357
|
+
console.error(theme.colors.success(`✓ Optimized prompt saved to: `) + theme.colors.highlight(options.output));
|
|
358
|
+
console.error(theme.colors.dim(` ${optimizedWords} words • ${optimized.length} characters`));
|
|
359
|
+
console.error("");
|
|
329
360
|
// Still print to stdout for piping
|
|
330
361
|
if (!options.interactive) {
|
|
331
362
|
console.log(optimized);
|
|
@@ -334,19 +365,62 @@ async function outputResult(original, optimized, options) {
|
|
|
334
365
|
}
|
|
335
366
|
// If interactive mode, show comparison
|
|
336
367
|
if (options.interactive) {
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
console.log("
|
|
340
|
-
console.log(
|
|
341
|
-
console.log("
|
|
342
|
-
console.log("
|
|
343
|
-
console.log("
|
|
344
|
-
|
|
345
|
-
|
|
368
|
+
const termWidth = process.stdout.columns || 80;
|
|
369
|
+
const boxWidth = Math.min(termWidth - 4, 100);
|
|
370
|
+
console.log("");
|
|
371
|
+
console.log(theme.colors.primary("╭" + "─".repeat(boxWidth - 2) + "╮"));
|
|
372
|
+
console.log(theme.colors.primary("│") + theme.colors.highlight(" 📝 ORIGINAL PROMPT ".padEnd(boxWidth - 2)) + theme.colors.primary("│"));
|
|
373
|
+
console.log(theme.colors.primary("╰" + "─".repeat(boxWidth - 2) + "╯"));
|
|
374
|
+
console.log("");
|
|
375
|
+
// Word wrap the original prompt
|
|
376
|
+
const originalLines = wrapText(original, boxWidth - 4);
|
|
377
|
+
originalLines.forEach(line => {
|
|
378
|
+
console.log(theme.colors.dim(" ") + theme.colors.secondary(line));
|
|
379
|
+
});
|
|
380
|
+
console.log("");
|
|
381
|
+
console.log(theme.colors.dim(" 📊 ") + theme.colors.info(`${originalWords} words`) + theme.colors.dim(" • ") + theme.colors.info(`${original.length} chars`));
|
|
382
|
+
console.log("");
|
|
383
|
+
console.log(theme.colors.success("╭" + "─".repeat(boxWidth - 2) + "╮"));
|
|
384
|
+
console.log(theme.colors.success("│") + theme.colors.highlight(" ✨ OPTIMIZED PROMPT ".padEnd(boxWidth - 2)) + theme.colors.success("│"));
|
|
385
|
+
console.log(theme.colors.success("╰" + "─".repeat(boxWidth - 2) + "╯"));
|
|
386
|
+
console.log("");
|
|
387
|
+
// Word wrap the optimized prompt
|
|
388
|
+
const optimizedLines = wrapText(optimized, boxWidth - 4);
|
|
389
|
+
optimizedLines.forEach(line => {
|
|
390
|
+
console.log(theme.colors.dim(" ") + theme.colors.primary(line));
|
|
391
|
+
});
|
|
392
|
+
console.log("");
|
|
393
|
+
console.log(theme.colors.dim(" 📊 ") + theme.colors.info(`${optimizedWords} words`) + theme.colors.dim(" • ") + theme.colors.info(`${optimized.length} chars`) +
|
|
394
|
+
theme.colors.dim(" • ") + (wordDiff > 0 ? theme.colors.warning : theme.colors.success)(`${wordDiffSign}${wordDiff} words (${wordDiffSign}${wordDiffPercent}%)`));
|
|
395
|
+
console.log("");
|
|
346
396
|
return;
|
|
347
397
|
}
|
|
348
398
|
// Default: print to stdout (pipeable)
|
|
349
399
|
console.log(optimized);
|
|
400
|
+
console.error("");
|
|
401
|
+
console.error(theme.colors.primary("─".repeat(50)));
|
|
402
|
+
console.error("");
|
|
403
|
+
}
|
|
404
|
+
/**
|
|
405
|
+
* Simple word wrap utility
|
|
406
|
+
*/
|
|
407
|
+
function wrapText(text, maxWidth) {
|
|
408
|
+
const words = text.split(/\s+/);
|
|
409
|
+
const lines = [];
|
|
410
|
+
let currentLine = "";
|
|
411
|
+
for (const word of words) {
|
|
412
|
+
if (currentLine.length + word.length + 1 <= maxWidth) {
|
|
413
|
+
currentLine += (currentLine ? " " : "") + word;
|
|
414
|
+
}
|
|
415
|
+
else {
|
|
416
|
+
if (currentLine)
|
|
417
|
+
lines.push(currentLine);
|
|
418
|
+
currentLine = word;
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
if (currentLine)
|
|
422
|
+
lines.push(currentLine);
|
|
423
|
+
return lines;
|
|
350
424
|
}
|
|
351
425
|
// Helper function to get available models by provider
|
|
352
426
|
function getModelsByProvider(provider) {
|
|
@@ -358,24 +432,24 @@ function getModelsByProvider(provider) {
|
|
|
358
432
|
async function interactiveConfig() {
|
|
359
433
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
360
434
|
try {
|
|
361
|
-
console.log("\n╭─────────────────────────────────────╮");
|
|
362
|
-
console.log("│ MegaBuff Configuration Setup │");
|
|
363
|
-
console.log("╰─────────────────────────────────────╯\n");
|
|
364
|
-
console.log("What would you like to configure?\n");
|
|
365
|
-
console.log("
|
|
366
|
-
console.log("
|
|
367
|
-
console.log("
|
|
368
|
-
console.log("
|
|
369
|
-
console.log("
|
|
370
|
-
const choice = await rl.question("Enter your choice (1-5): ");
|
|
435
|
+
console.log(theme.colors.primary("\n╭─────────────────────────────────────╮"));
|
|
436
|
+
console.log(theme.colors.primary("│") + theme.colors.highlight(" MegaBuff Configuration Setup ") + theme.colors.primary("│"));
|
|
437
|
+
console.log(theme.colors.primary("╰─────────────────────────────────────╯\n"));
|
|
438
|
+
console.log(theme.colors.secondary("What would you like to configure?\n"));
|
|
439
|
+
console.log(theme.colors.secondary(` ${chalk.bold("1)")} Set API token for a provider`));
|
|
440
|
+
console.log(theme.colors.secondary(` ${chalk.bold("2)")} Set default provider`));
|
|
441
|
+
console.log(theme.colors.secondary(` ${chalk.bold("3)")} Set model (auto-selects provider)`));
|
|
442
|
+
console.log(theme.colors.secondary(` ${chalk.bold("4)")} View current configuration`));
|
|
443
|
+
console.log(theme.colors.secondary(` ${chalk.bold("5)")} Exit\n`));
|
|
444
|
+
const choice = await rl.question(theme.colors.primary("Enter your choice (1-5): "));
|
|
371
445
|
switch (choice.trim()) {
|
|
372
446
|
case "1": {
|
|
373
447
|
// Set token
|
|
374
|
-
console.log("\nSelect provider:\n");
|
|
448
|
+
console.log(theme.colors.primary("\nSelect provider:\n"));
|
|
375
449
|
PROVIDERS.forEach((p, idx) => {
|
|
376
|
-
console.log(` ${idx + 1}) ${formatProviderLabel(p)}`);
|
|
450
|
+
console.log(theme.colors.secondary(` ${chalk.bold(idx + 1)}) ${formatProviderLabel(p)}`));
|
|
377
451
|
});
|
|
378
|
-
const providerChoice = await rl.question("\nProvider (number or name): ");
|
|
452
|
+
const providerChoice = await rl.question(theme.colors.primary("\nProvider (number or name): "));
|
|
379
453
|
const providerNum = Number(providerChoice);
|
|
380
454
|
let provider;
|
|
381
455
|
if (Number.isFinite(providerNum) && providerNum >= 1 && providerNum <= PROVIDERS.length) {
|
|
@@ -385,30 +459,30 @@ async function interactiveConfig() {
|
|
|
385
459
|
provider = normalizeProvider(providerChoice);
|
|
386
460
|
}
|
|
387
461
|
if (!provider) {
|
|
388
|
-
console.error(`Error: Invalid provider. Valid options: ${PROVIDERS.join(", ")}`);
|
|
462
|
+
console.error(theme.colors.error(`Error: Invalid provider. Valid options: ${PROVIDERS.join(", ")}`));
|
|
389
463
|
process.exit(1);
|
|
390
464
|
}
|
|
391
|
-
const token = (await rl.question("Enter your API token: ")).trim();
|
|
465
|
+
const token = (await rl.question(theme.colors.primary("Enter your API token: "))).trim();
|
|
392
466
|
if (!token) {
|
|
393
|
-
console.error("Error: No token provided");
|
|
467
|
+
console.error(theme.colors.error("Error: No token provided"));
|
|
394
468
|
process.exit(1);
|
|
395
469
|
}
|
|
396
|
-
const store = (await rl.question("Store in system keychain? (Y/n): ")).trim().toLowerCase();
|
|
470
|
+
const store = (await rl.question(theme.colors.primary("Store in system keychain? (Y/n): "))).trim().toLowerCase();
|
|
397
471
|
const useKeychain = store === "" || store === "y" || store === "yes";
|
|
398
472
|
await setApiKey(provider, token, useKeychain);
|
|
399
|
-
console.log(`\n✓ ${provider} token saved
|
|
473
|
+
console.log(theme.colors.success(`\n✓ ${provider} token saved`) + theme.colors.dim(useKeychain ? " securely in system keychain" : " to config file"));
|
|
400
474
|
if (!useKeychain) {
|
|
401
|
-
console.log(" Tip: Run with --keychain flag next time for more secure storage");
|
|
475
|
+
console.log(theme.colors.dim(" Tip: Run with --keychain flag next time for more secure storage"));
|
|
402
476
|
}
|
|
403
477
|
break;
|
|
404
478
|
}
|
|
405
479
|
case "2": {
|
|
406
480
|
// Set default provider
|
|
407
|
-
console.log("\nSelect default provider:\n");
|
|
481
|
+
console.log(theme.colors.primary("\nSelect default provider:\n"));
|
|
408
482
|
PROVIDERS.forEach((p, idx) => {
|
|
409
|
-
console.log(` ${idx + 1}) ${formatProviderLabel(p)}`);
|
|
483
|
+
console.log(theme.colors.secondary(` ${chalk.bold(idx + 1)}) ${formatProviderLabel(p)}`));
|
|
410
484
|
});
|
|
411
|
-
const providerChoice = await rl.question("\nProvider (number or name): ");
|
|
485
|
+
const providerChoice = await rl.question(theme.colors.primary("\nProvider (number or name): "));
|
|
412
486
|
const providerNum = Number(providerChoice);
|
|
413
487
|
let provider;
|
|
414
488
|
if (Number.isFinite(providerNum) && providerNum >= 1 && providerNum <= PROVIDERS.length) {
|
|
@@ -418,38 +492,38 @@ async function interactiveConfig() {
|
|
|
418
492
|
provider = normalizeProvider(providerChoice);
|
|
419
493
|
}
|
|
420
494
|
if (!provider) {
|
|
421
|
-
console.error(`Error: Invalid provider. Valid options: ${PROVIDERS.join(", ")}`);
|
|
495
|
+
console.error(theme.colors.error(`Error: Invalid provider. Valid options: ${PROVIDERS.join(", ")}`));
|
|
422
496
|
process.exit(1);
|
|
423
497
|
}
|
|
424
498
|
await setProvider(provider);
|
|
425
|
-
console.log(`\n✓ Default provider set to:
|
|
499
|
+
console.log(theme.colors.success(`\n✓ Default provider set to: `) + theme.colors.highlight(provider));
|
|
426
500
|
break;
|
|
427
501
|
}
|
|
428
502
|
case "3": {
|
|
429
503
|
// Set model (auto-selects provider)
|
|
430
|
-
console.log("\nAvailable models by provider:\n");
|
|
504
|
+
console.log(theme.colors.primary("\nAvailable models by provider:\n"));
|
|
431
505
|
PROVIDERS.forEach((provider) => {
|
|
432
506
|
const models = getModelsByProvider(provider);
|
|
433
507
|
if (models.length > 0) {
|
|
434
|
-
console.log(`${formatProviderName(provider)}:`);
|
|
435
|
-
models.forEach(model => console.log(` - ${model}`));
|
|
508
|
+
console.log(theme.colors.warning(`${formatProviderName(provider)}:`));
|
|
509
|
+
models.forEach(model => console.log(theme.colors.secondary(` - ${model}`)));
|
|
436
510
|
console.log();
|
|
437
511
|
}
|
|
438
512
|
});
|
|
439
|
-
const modelInput = (await rl.question("Enter model name: ")).trim();
|
|
513
|
+
const modelInput = (await rl.question(theme.colors.primary("Enter model name: "))).trim();
|
|
440
514
|
if (!modelInput) {
|
|
441
|
-
console.error("Error: No model provided");
|
|
515
|
+
console.error(theme.colors.error("Error: No model provided"));
|
|
442
516
|
process.exit(1);
|
|
443
517
|
}
|
|
444
518
|
const provider = getProviderForModel(modelInput);
|
|
445
519
|
if (!provider) {
|
|
446
|
-
console.error(`Error: Unknown model '${modelInput}'`);
|
|
447
|
-
console.error("Tip: Use one of the models listed above");
|
|
520
|
+
console.error(theme.colors.error(`Error: Unknown model '${modelInput}'`));
|
|
521
|
+
console.error(theme.colors.warning("Tip: Use one of the models listed above"));
|
|
448
522
|
process.exit(1);
|
|
449
523
|
}
|
|
450
524
|
await setModel(modelInput);
|
|
451
|
-
console.log(`\n✓ Model set to:
|
|
452
|
-
console.log(`✓ Provider auto-set to:
|
|
525
|
+
console.log(theme.colors.success(`\n✓ Model set to: `) + theme.colors.highlight(modelInput));
|
|
526
|
+
console.log(theme.colors.success(`✓ Provider auto-set to: `) + theme.colors.highlight(provider));
|
|
453
527
|
break;
|
|
454
528
|
}
|
|
455
529
|
case "4": {
|
|
@@ -458,26 +532,29 @@ async function interactiveConfig() {
|
|
|
458
532
|
const currentProvider = await getProvider();
|
|
459
533
|
const currentModel = await getModel();
|
|
460
534
|
const effectiveModel = currentModel ?? getDefaultModel(currentProvider);
|
|
535
|
+
const currentThemeName = await getThemeName();
|
|
536
|
+
const currentTheme = themes[currentThemeName];
|
|
461
537
|
const providerStatuses = await Promise.all(PROVIDERS.map(async (p) => [p, await hasApiKey(p)]));
|
|
462
|
-
console.log("\n╭─────────────────────────────────────╮");
|
|
463
|
-
console.log("│ Current Configuration │");
|
|
464
|
-
console.log("╰─────────────────────────────────────╯\n");
|
|
465
|
-
console.log(`Provider:
|
|
466
|
-
console.log(`Model:
|
|
467
|
-
console.log(`Storage:
|
|
468
|
-
console.log(
|
|
538
|
+
console.log(theme.colors.primary("\n╭─────────────────────────────────────╮"));
|
|
539
|
+
console.log(theme.colors.primary("│") + theme.colors.highlight(" Current Configuration ") + theme.colors.primary("│"));
|
|
540
|
+
console.log(theme.colors.primary("╰─────────────────────────────────────╯\n"));
|
|
541
|
+
console.log(theme.colors.secondary(`Provider: `) + theme.colors.highlight(currentProvider));
|
|
542
|
+
console.log(theme.colors.secondary(`Model: `) + theme.colors.highlight(currentModel ? effectiveModel : `${effectiveModel}`) + theme.colors.dim(currentModel ? "" : " (default for provider)"));
|
|
543
|
+
console.log(theme.colors.secondary(`Storage: `) + theme.colors.highlight(config.useKeychain ? "System Keychain" : "Config File"));
|
|
544
|
+
console.log(theme.colors.secondary(`Theme: `) + theme.colors.highlight(currentTheme.name));
|
|
545
|
+
console.log(theme.colors.secondary("\nAPI Tokens:"));
|
|
469
546
|
for (const [p, ok] of providerStatuses) {
|
|
470
|
-
console.log(` ${p}: ${ok ? "✓ Configured" : "✗ Not configured"}`);
|
|
547
|
+
console.log(` ${theme.colors.secondary(p)}: ${ok ? theme.colors.success("✓ Configured") : theme.colors.dim("✗ Not configured")}`);
|
|
471
548
|
}
|
|
472
|
-
console.log(`\nConfig file: ~/.megabuff/config.json`);
|
|
549
|
+
console.log(theme.colors.dim(`\nConfig file: ~/.megabuff/config.json`));
|
|
473
550
|
break;
|
|
474
551
|
}
|
|
475
552
|
case "5": {
|
|
476
|
-
console.log("\nExiting...");
|
|
553
|
+
console.log(theme.colors.primary("\nExiting..."));
|
|
477
554
|
break;
|
|
478
555
|
}
|
|
479
556
|
default: {
|
|
480
|
-
console.error("Invalid choice. Please enter 1-5.");
|
|
557
|
+
console.error(theme.colors.error("Invalid choice. Please enter 1-5."));
|
|
481
558
|
process.exit(1);
|
|
482
559
|
}
|
|
483
560
|
}
|
|
@@ -496,11 +573,15 @@ const configCmd = program
|
|
|
496
573
|
await interactiveConfig();
|
|
497
574
|
}
|
|
498
575
|
else {
|
|
499
|
-
console.error("
|
|
500
|
-
console.error("
|
|
501
|
-
console.error("
|
|
502
|
-
console.error("
|
|
503
|
-
console.error("
|
|
576
|
+
console.error("");
|
|
577
|
+
console.error(theme.colors.error("❌ Error: ") + theme.colors.warning("Interactive mode requires a TTY"));
|
|
578
|
+
console.error("");
|
|
579
|
+
console.error(theme.colors.dim(" Use these subcommands instead:"));
|
|
580
|
+
console.error(theme.colors.accent(" megabuff config token <token> --provider <provider>"));
|
|
581
|
+
console.error(theme.colors.accent(" megabuff config provider <provider>"));
|
|
582
|
+
console.error(theme.colors.accent(" megabuff config model <model>"));
|
|
583
|
+
console.error(theme.colors.accent(" megabuff config show"));
|
|
584
|
+
console.error("");
|
|
504
585
|
process.exit(1);
|
|
505
586
|
}
|
|
506
587
|
});
|
|
@@ -514,38 +595,55 @@ configCmd
|
|
|
514
595
|
try {
|
|
515
596
|
const provider = normalizeProvider(options.provider);
|
|
516
597
|
if (!provider) {
|
|
517
|
-
console.error(
|
|
598
|
+
console.error("");
|
|
599
|
+
console.error(theme.colors.error("❌ Error: ") + theme.colors.warning(`Invalid provider '${options.provider}'`));
|
|
600
|
+
console.error("");
|
|
601
|
+
console.error(theme.colors.dim(" Valid providers: ") + theme.colors.info(PROVIDERS.join(", ")));
|
|
602
|
+
console.error("");
|
|
518
603
|
process.exit(1);
|
|
519
604
|
}
|
|
520
605
|
let finalToken = token;
|
|
521
606
|
if (!finalToken) {
|
|
522
607
|
if (!process.stdin.isTTY) {
|
|
523
|
-
console.error("
|
|
608
|
+
console.error("");
|
|
609
|
+
console.error(theme.colors.error("❌ Error: ") + theme.colors.warning("Missing token argument"));
|
|
610
|
+
console.error("");
|
|
611
|
+
console.error(theme.colors.dim(" Provide it inline or run in an interactive terminal"));
|
|
612
|
+
console.error("");
|
|
524
613
|
process.exit(1);
|
|
525
614
|
}
|
|
526
615
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
527
616
|
try {
|
|
528
|
-
finalToken = (await rl.question("Enter your API token: ")).trim();
|
|
617
|
+
finalToken = (await rl.question(theme.colors.primary("🔑 Enter your API token: "))).trim();
|
|
529
618
|
}
|
|
530
619
|
finally {
|
|
531
620
|
rl.close();
|
|
532
621
|
}
|
|
533
622
|
}
|
|
534
623
|
if (!finalToken) {
|
|
535
|
-
console.error("
|
|
624
|
+
console.error("");
|
|
625
|
+
console.error(theme.colors.error("❌ Error: ") + theme.colors.warning("No token provided"));
|
|
626
|
+
console.error("");
|
|
536
627
|
process.exit(1);
|
|
537
628
|
}
|
|
538
629
|
await setApiKey(provider, finalToken, options.keychain || false);
|
|
630
|
+
console.error("");
|
|
539
631
|
if (options.keychain) {
|
|
540
|
-
console.log(`✓ ${provider} token saved securely
|
|
632
|
+
console.log(theme.colors.success(`✓ ${formatProviderName(provider)} token saved securely! 🔐`));
|
|
633
|
+
console.log(theme.colors.dim(" Stored in system keychain for maximum security"));
|
|
541
634
|
}
|
|
542
635
|
else {
|
|
543
|
-
console.log(`✓ ${provider} token saved
|
|
544
|
-
console.log("
|
|
636
|
+
console.log(theme.colors.success(`✓ ${formatProviderName(provider)} token saved! 💾`));
|
|
637
|
+
console.log(theme.colors.dim(" Stored in ") + theme.colors.accent("~/.megabuff/config.json"));
|
|
638
|
+
console.log("");
|
|
639
|
+
console.log(theme.colors.info(" 💡 Tip: ") + theme.colors.dim("Use ") + theme.colors.accent("--keychain") + theme.colors.dim(" flag for more secure storage"));
|
|
545
640
|
}
|
|
641
|
+
console.error("");
|
|
546
642
|
}
|
|
547
643
|
catch (error) {
|
|
548
|
-
console.error(
|
|
644
|
+
console.error("");
|
|
645
|
+
console.error(theme.colors.error("❌ Error: ") + theme.colors.warning(error instanceof Error ? error.message : String(error)));
|
|
646
|
+
console.error("");
|
|
549
647
|
process.exit(1);
|
|
550
648
|
}
|
|
551
649
|
});
|
|
@@ -557,19 +655,33 @@ configCmd
|
|
|
557
655
|
try {
|
|
558
656
|
if (!providerArg) {
|
|
559
657
|
const p = await getProvider();
|
|
560
|
-
|
|
658
|
+
const providerEmoji = p === "openai" ? "🤖" : p === "anthropic" ? "🧠" : p === "google" ? "✨" : "🔧";
|
|
659
|
+
console.log("");
|
|
660
|
+
console.log(theme.colors.dim(" Current default provider:"));
|
|
661
|
+
console.log(theme.colors.primary(` ${providerEmoji} `) + theme.colors.highlight(formatProviderName(p)));
|
|
662
|
+
console.log("");
|
|
561
663
|
return;
|
|
562
664
|
}
|
|
563
665
|
const p = normalizeProvider(providerArg);
|
|
564
666
|
if (!p) {
|
|
565
|
-
console.error(
|
|
667
|
+
console.error("");
|
|
668
|
+
console.error(theme.colors.error("❌ Error: ") + theme.colors.warning(`Invalid provider '${providerArg}'`));
|
|
669
|
+
console.error("");
|
|
670
|
+
console.error(theme.colors.dim(" Valid providers: ") + theme.colors.info(PROVIDERS.join(", ")));
|
|
671
|
+
console.error("");
|
|
566
672
|
process.exit(1);
|
|
567
673
|
}
|
|
568
674
|
await setProvider(p);
|
|
569
|
-
|
|
675
|
+
const providerEmoji = p === "openai" ? "🤖" : p === "anthropic" ? "🧠" : p === "google" ? "✨" : "🔧";
|
|
676
|
+
console.log("");
|
|
677
|
+
console.log(theme.colors.success(`✓ Default provider updated!`));
|
|
678
|
+
console.log(theme.colors.dim(" Now using: ") + theme.colors.highlight(`${providerEmoji} ${formatProviderName(p)}`));
|
|
679
|
+
console.log("");
|
|
570
680
|
}
|
|
571
681
|
catch (error) {
|
|
572
|
-
console.error(
|
|
682
|
+
console.error("");
|
|
683
|
+
console.error(theme.colors.error("❌ Error: ") + theme.colors.warning(error instanceof Error ? error.message : String(error)));
|
|
684
|
+
console.error("");
|
|
573
685
|
process.exit(1);
|
|
574
686
|
}
|
|
575
687
|
});
|
|
@@ -583,29 +695,44 @@ configCmd
|
|
|
583
695
|
const m = await getModel();
|
|
584
696
|
const p = await getProvider();
|
|
585
697
|
const effectiveModel = m ?? getDefaultModel(p);
|
|
586
|
-
|
|
587
|
-
console.log(
|
|
698
|
+
const providerEmoji = p === "openai" ? "🤖" : p === "anthropic" ? "🧠" : p === "google" ? "✨" : "🔧";
|
|
699
|
+
console.log("");
|
|
700
|
+
console.log(theme.colors.dim(" Current configuration:"));
|
|
701
|
+
console.log(theme.colors.primary(` ${providerEmoji} Model: `) + theme.colors.highlight(effectiveModel) + theme.colors.dim(m ? "" : " (default)"));
|
|
702
|
+
console.log(theme.colors.dim(` Provider: `) + theme.colors.info(formatProviderName(p)));
|
|
703
|
+
console.log("");
|
|
588
704
|
return;
|
|
589
705
|
}
|
|
590
706
|
const provider = getProviderForModel(modelArg);
|
|
591
707
|
if (!provider) {
|
|
592
|
-
console.error(
|
|
593
|
-
console.error("
|
|
708
|
+
console.error("");
|
|
709
|
+
console.error(theme.colors.error("❌ Error: ") + theme.colors.warning(`Unknown model '${modelArg}'`));
|
|
710
|
+
console.error("");
|
|
711
|
+
console.error(theme.colors.dim(" Available models:"));
|
|
712
|
+
console.error("");
|
|
594
713
|
PROVIDERS.forEach(p => {
|
|
595
714
|
const models = getModelsByProvider(p);
|
|
596
715
|
if (models.length > 0) {
|
|
597
|
-
|
|
598
|
-
|
|
716
|
+
const providerEmoji = p === "openai" ? "🤖" : p === "anthropic" ? "🧠" : p === "google" ? "✨" : "🔧";
|
|
717
|
+
console.error(theme.colors.primary(` ${providerEmoji} ${formatProviderName(p)}:`));
|
|
718
|
+
models.forEach(m => console.error(theme.colors.dim(` • `) + theme.colors.info(m)));
|
|
719
|
+
console.error("");
|
|
599
720
|
}
|
|
600
721
|
});
|
|
601
722
|
process.exit(1);
|
|
602
723
|
}
|
|
603
724
|
await setModel(modelArg);
|
|
604
|
-
|
|
605
|
-
console.log(
|
|
725
|
+
const providerEmoji = provider === "openai" ? "🤖" : provider === "anthropic" ? "🧠" : provider === "google" ? "✨" : "🔧";
|
|
726
|
+
console.log("");
|
|
727
|
+
console.log(theme.colors.success(`✓ Configuration updated!`));
|
|
728
|
+
console.log(theme.colors.dim(" Model: ") + theme.colors.highlight(modelArg));
|
|
729
|
+
console.log(theme.colors.dim(" Provider: ") + theme.colors.highlight(`${providerEmoji} ${formatProviderName(provider)}`));
|
|
730
|
+
console.log("");
|
|
606
731
|
}
|
|
607
732
|
catch (error) {
|
|
608
|
-
console.error(
|
|
733
|
+
console.error("");
|
|
734
|
+
console.error(theme.colors.error("❌ Error: ") + theme.colors.warning(error instanceof Error ? error.message : String(error)));
|
|
735
|
+
console.error("");
|
|
609
736
|
process.exit(1);
|
|
610
737
|
}
|
|
611
738
|
});
|
|
@@ -618,19 +745,34 @@ configCmd
|
|
|
618
745
|
const selectedProvider = await getProvider();
|
|
619
746
|
const selectedModel = await getModel();
|
|
620
747
|
const effectiveModel = selectedModel ?? getDefaultModel(selectedProvider);
|
|
748
|
+
const currentThemeName = await getThemeName();
|
|
749
|
+
const currentTheme = themes[currentThemeName];
|
|
621
750
|
const providerStatuses = await Promise.all(PROVIDERS.map(async (p) => [p, await hasApiKey(p)]));
|
|
622
|
-
|
|
623
|
-
console.log(
|
|
624
|
-
console.log(
|
|
625
|
-
console.log(
|
|
626
|
-
console.log("
|
|
751
|
+
const providerEmoji = selectedProvider === "openai" ? "🤖" : selectedProvider === "anthropic" ? "🧠" : selectedProvider === "google" ? "✨" : "🔧";
|
|
752
|
+
console.log("");
|
|
753
|
+
console.log(theme.colors.primary("╭────────────────────────────────────────────╮"));
|
|
754
|
+
console.log(theme.colors.primary("│") + theme.colors.highlight(" ⚙️ MegaBuff Configuration ") + theme.colors.primary("│"));
|
|
755
|
+
console.log(theme.colors.primary("╰────────────────────────────────────────────╯"));
|
|
756
|
+
console.log("");
|
|
757
|
+
console.log(theme.colors.dim(" Active Settings:"));
|
|
758
|
+
console.log(theme.colors.primary(` ${providerEmoji} Provider: `) + theme.colors.highlight(formatProviderName(selectedProvider)));
|
|
759
|
+
console.log(theme.colors.primary(` 🎯 Model: `) + theme.colors.highlight(effectiveModel) + theme.colors.dim(selectedModel ? "" : " (default)"));
|
|
760
|
+
console.log(theme.colors.primary(` 💾 Storage: `) + theme.colors.highlight(config.useKeychain ? "System Keychain 🔐" : "Config File"));
|
|
761
|
+
console.log(theme.colors.primary(` 🎨 Theme: `) + theme.colors.highlight(currentTheme.name));
|
|
762
|
+
console.log("");
|
|
763
|
+
console.log(theme.colors.dim(" API Token Status:"));
|
|
627
764
|
for (const [p, ok] of providerStatuses) {
|
|
628
|
-
|
|
765
|
+
const emoji = p === "openai" ? "🤖" : p === "anthropic" ? "🧠" : p === "google" ? "✨" : "🔧";
|
|
766
|
+
console.log(` ${emoji} ${theme.colors.secondary(formatProviderName(p).padEnd(16))}: ${ok ? theme.colors.success("✓ Configured") : theme.colors.dim("✗ Not configured")}`);
|
|
629
767
|
}
|
|
630
|
-
console.log(
|
|
768
|
+
console.log("");
|
|
769
|
+
console.log(theme.colors.dim(" 📁 Config location: ") + theme.colors.accent("~/.megabuff/config.json"));
|
|
770
|
+
console.log("");
|
|
631
771
|
}
|
|
632
772
|
catch (error) {
|
|
633
|
-
console.error(
|
|
773
|
+
console.error("");
|
|
774
|
+
console.error(theme.colors.error("❌ Error: ") + theme.colors.warning(error instanceof Error ? error.message : String(error)));
|
|
775
|
+
console.error("");
|
|
634
776
|
process.exit(1);
|
|
635
777
|
}
|
|
636
778
|
});
|
|
@@ -642,10 +784,190 @@ configCmd
|
|
|
642
784
|
try {
|
|
643
785
|
const provider = await getProvider(options.provider);
|
|
644
786
|
await removeApiKey(provider);
|
|
645
|
-
console.log(
|
|
787
|
+
console.log("");
|
|
788
|
+
console.log(theme.colors.success(`✓ ${formatProviderName(provider)} token removed successfully! 🗑️`));
|
|
789
|
+
console.log(theme.colors.dim(" Cleared from config file and system keychain"));
|
|
790
|
+
console.log("");
|
|
646
791
|
}
|
|
647
792
|
catch (error) {
|
|
648
|
-
console.error(
|
|
793
|
+
console.error("");
|
|
794
|
+
console.error(theme.colors.error("❌ Error: ") + theme.colors.warning(error instanceof Error ? error.message : String(error)));
|
|
795
|
+
console.error("");
|
|
796
|
+
process.exit(1);
|
|
797
|
+
}
|
|
798
|
+
});
|
|
799
|
+
// Theme command
|
|
800
|
+
const themeCmd = program
|
|
801
|
+
.command("theme")
|
|
802
|
+
.description("Manage color themes")
|
|
803
|
+
.action(async () => {
|
|
804
|
+
// Show current theme when no subcommand
|
|
805
|
+
const currentThemeName = await getThemeName();
|
|
806
|
+
const currentTheme = themes[currentThemeName];
|
|
807
|
+
const { colors } = currentTheme;
|
|
808
|
+
console.log("");
|
|
809
|
+
console.log(theme.colors.primary("╭────────────────────────────────────────────╮"));
|
|
810
|
+
console.log(theme.colors.primary("│") + theme.colors.highlight(" 🎨 Current Theme ") + theme.colors.primary("│"));
|
|
811
|
+
console.log(theme.colors.primary("╰────────────────────────────────────────────╯"));
|
|
812
|
+
console.log("");
|
|
813
|
+
console.log(theme.colors.primary(` Theme: `) + theme.colors.highlight(currentTheme.name));
|
|
814
|
+
console.log(theme.colors.dim(` ${currentTheme.description}`));
|
|
815
|
+
console.log("");
|
|
816
|
+
console.log(theme.colors.dim(" Color preview:"));
|
|
817
|
+
const preview = [
|
|
818
|
+
colors.primary("primary"),
|
|
819
|
+
colors.success("success"),
|
|
820
|
+
colors.error("error"),
|
|
821
|
+
colors.warning("warning"),
|
|
822
|
+
colors.info("info"),
|
|
823
|
+
colors.accent("accent")
|
|
824
|
+
].join(" ");
|
|
825
|
+
console.log(` ${preview}`);
|
|
826
|
+
console.log("");
|
|
827
|
+
console.log(theme.colors.dim(" 💡 Commands:"));
|
|
828
|
+
console.log(theme.colors.accent(" megabuff theme list") + theme.colors.dim(" - See all themes"));
|
|
829
|
+
console.log(theme.colors.accent(" megabuff theme set <name>") + theme.colors.dim(" - Change theme"));
|
|
830
|
+
console.log("");
|
|
831
|
+
});
|
|
832
|
+
themeCmd
|
|
833
|
+
.command("list")
|
|
834
|
+
.description("List all available themes")
|
|
835
|
+
.action(async () => {
|
|
836
|
+
const currentTheme = await getThemeName();
|
|
837
|
+
const themeNames = getAllThemeNames();
|
|
838
|
+
console.log("");
|
|
839
|
+
console.log(theme.colors.primary("╭────────────────────────────────────────────────────────────────────╮"));
|
|
840
|
+
console.log(theme.colors.primary("│") + theme.colors.highlight(" 🎨 Available Themes ") + theme.colors.primary("│"));
|
|
841
|
+
console.log(theme.colors.primary("╰────────────────────────────────────────────────────────────────────╯"));
|
|
842
|
+
console.log("");
|
|
843
|
+
for (const themeName of themeNames) {
|
|
844
|
+
const t = themes[themeName];
|
|
845
|
+
const isCurrent = themeName === currentTheme;
|
|
846
|
+
const { colors } = t;
|
|
847
|
+
// Theme name with indicator if current
|
|
848
|
+
if (isCurrent) {
|
|
849
|
+
console.log(colors.success(` ● ${t.name}`) + theme.colors.dim(" ⭐ (active)"));
|
|
850
|
+
}
|
|
851
|
+
else {
|
|
852
|
+
console.log(colors.primary(` ${t.name}`));
|
|
853
|
+
}
|
|
854
|
+
console.log(colors.dim(` ${t.description}`));
|
|
855
|
+
// Show color preview
|
|
856
|
+
const preview = [
|
|
857
|
+
colors.primary("primary"),
|
|
858
|
+
colors.success("success"),
|
|
859
|
+
colors.error("error"),
|
|
860
|
+
colors.warning("warning"),
|
|
861
|
+
colors.info("info"),
|
|
862
|
+
colors.accent("accent")
|
|
863
|
+
].join(" ");
|
|
864
|
+
console.log(` ${preview}`);
|
|
865
|
+
console.log();
|
|
866
|
+
}
|
|
867
|
+
console.log(theme.colors.dim(` To change theme: `) + theme.colors.accent(`megabuff theme set <theme-name>`));
|
|
868
|
+
console.log(theme.colors.dim(` To preview theme: `) + theme.colors.accent(`megabuff theme preview <theme-name>`));
|
|
869
|
+
console.log("");
|
|
870
|
+
});
|
|
871
|
+
themeCmd
|
|
872
|
+
.command("set")
|
|
873
|
+
.description("Set the active theme")
|
|
874
|
+
.argument("<theme>", "Theme name")
|
|
875
|
+
.action(async (themeName) => {
|
|
876
|
+
try {
|
|
877
|
+
const normalizedTheme = themeName.toLowerCase();
|
|
878
|
+
if (!isValidTheme(normalizedTheme)) {
|
|
879
|
+
console.error("");
|
|
880
|
+
console.error(theme.colors.error("❌ Error: ") + theme.colors.warning(`Unknown theme '${themeName}'`));
|
|
881
|
+
console.error("");
|
|
882
|
+
console.error(theme.colors.dim(" Available themes:"));
|
|
883
|
+
getAllThemeNames().forEach(name => {
|
|
884
|
+
console.error(theme.colors.info(` • ${name}`));
|
|
885
|
+
});
|
|
886
|
+
console.error("");
|
|
887
|
+
process.exit(1);
|
|
888
|
+
}
|
|
889
|
+
await setThemeName(normalizedTheme);
|
|
890
|
+
clearThemeCache(); // Clear cache so next command uses new theme
|
|
891
|
+
const newTheme = themes[normalizedTheme];
|
|
892
|
+
const { colors } = newTheme;
|
|
893
|
+
console.log("");
|
|
894
|
+
console.log(colors.success(`✓ Theme changed successfully! 🎨`));
|
|
895
|
+
console.log(colors.dim(` Now using: `) + colors.highlight(newTheme.name));
|
|
896
|
+
console.log(colors.dim(` ${newTheme.description}`));
|
|
897
|
+
// Show preview
|
|
898
|
+
console.log("");
|
|
899
|
+
console.log(colors.dim(" Color preview:"));
|
|
900
|
+
const preview = [
|
|
901
|
+
colors.primary("primary"),
|
|
902
|
+
colors.success("success"),
|
|
903
|
+
colors.error("error"),
|
|
904
|
+
colors.warning("warning"),
|
|
905
|
+
colors.info("info"),
|
|
906
|
+
colors.accent("accent")
|
|
907
|
+
].join(" ");
|
|
908
|
+
console.log(` ${preview}`);
|
|
909
|
+
console.log("");
|
|
910
|
+
}
|
|
911
|
+
catch (error) {
|
|
912
|
+
console.error("");
|
|
913
|
+
console.error(theme.colors.error("❌ Error: ") + theme.colors.warning(error instanceof Error ? error.message : String(error)));
|
|
914
|
+
console.error("");
|
|
915
|
+
process.exit(1);
|
|
916
|
+
}
|
|
917
|
+
});
|
|
918
|
+
themeCmd
|
|
919
|
+
.command("preview")
|
|
920
|
+
.description("Preview a theme without setting it")
|
|
921
|
+
.argument("<theme>", "Theme name to preview")
|
|
922
|
+
.action(async (themeName) => {
|
|
923
|
+
try {
|
|
924
|
+
const normalizedTheme = themeName.toLowerCase();
|
|
925
|
+
if (!isValidTheme(normalizedTheme)) {
|
|
926
|
+
console.error("");
|
|
927
|
+
console.error(theme.colors.error("❌ Error: ") + theme.colors.warning(`Unknown theme '${themeName}'`));
|
|
928
|
+
console.error("");
|
|
929
|
+
console.error(theme.colors.dim(" Available themes:"));
|
|
930
|
+
getAllThemeNames().forEach(name => {
|
|
931
|
+
console.error(theme.colors.info(` • ${name}`));
|
|
932
|
+
});
|
|
933
|
+
console.error("");
|
|
934
|
+
process.exit(1);
|
|
935
|
+
}
|
|
936
|
+
const previewTheme = themes[normalizedTheme];
|
|
937
|
+
const { colors } = previewTheme;
|
|
938
|
+
console.log("");
|
|
939
|
+
console.log(colors.primary("╭────────────────────────────────────────────────────────╮"));
|
|
940
|
+
console.log(colors.primary("│") + colors.highlight(` 🎨 ${previewTheme.name} Theme Preview `.padEnd(55)) + colors.primary("│"));
|
|
941
|
+
console.log(colors.primary("╰────────────────────────────────────────────────────────╯"));
|
|
942
|
+
console.log("");
|
|
943
|
+
console.log(colors.dim(` ${previewTheme.description}`));
|
|
944
|
+
console.log("");
|
|
945
|
+
console.log(colors.dim(" Color Palette:"));
|
|
946
|
+
console.log("");
|
|
947
|
+
console.log(colors.primary(" ● Primary text and headings"));
|
|
948
|
+
console.log(colors.secondary(" ● Secondary text and descriptions"));
|
|
949
|
+
console.log(colors.success(" ✓ Success messages and confirmations"));
|
|
950
|
+
console.log(colors.error(" ✗ Error messages and warnings"));
|
|
951
|
+
console.log(colors.warning(" ⚠ Warning and important notes"));
|
|
952
|
+
console.log(colors.info(" ℹ Info messages and details"));
|
|
953
|
+
console.log(colors.highlight(" ★ Highlighted and emphasized text"));
|
|
954
|
+
console.log(colors.accent(" ◆ Accent colors and special elements"));
|
|
955
|
+
console.log(colors.dim(" ○ Dimmed and secondary information"));
|
|
956
|
+
console.log("");
|
|
957
|
+
const currentTheme = await getThemeName();
|
|
958
|
+
if (currentTheme !== normalizedTheme) {
|
|
959
|
+
console.log(colors.dim(" To activate this theme: ") + colors.accent(`megabuff theme set ${normalizedTheme}`));
|
|
960
|
+
console.log("");
|
|
961
|
+
}
|
|
962
|
+
else {
|
|
963
|
+
console.log(colors.success(" ⭐ This is your current active theme!"));
|
|
964
|
+
console.log("");
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
catch (error) {
|
|
968
|
+
console.error("");
|
|
969
|
+
console.error(theme.colors.error("❌ Error: ") + theme.colors.warning(error instanceof Error ? error.message : String(error)));
|
|
970
|
+
console.error("");
|
|
649
971
|
process.exit(1);
|
|
650
972
|
}
|
|
651
973
|
});
|
|
@@ -669,7 +991,10 @@ program
|
|
|
669
991
|
});
|
|
670
992
|
const original = await getInput(inlinePrompt, options);
|
|
671
993
|
if (!original.trim()) {
|
|
672
|
-
console.error("
|
|
994
|
+
console.error("");
|
|
995
|
+
console.error(theme.colors.error("❌ Error: ") + theme.colors.warning("No prompt provided"));
|
|
996
|
+
console.error(theme.colors.dim(" Provide a prompt inline, via --file, or through stdin"));
|
|
997
|
+
console.error("");
|
|
673
998
|
process.exit(1);
|
|
674
999
|
}
|
|
675
1000
|
let provider = await getProvider(options.provider);
|
|
@@ -688,16 +1013,23 @@ program
|
|
|
688
1013
|
debugLog("token.resolved.afterFirstRun", { provider, source, token: maskSecret(apiKey) });
|
|
689
1014
|
}
|
|
690
1015
|
if (!apiKey) {
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
1016
|
+
console.error("");
|
|
1017
|
+
console.error(theme.colors.error("❌ Error: ") + theme.colors.warning(`No API key configured for ${formatProviderName(provider)}`));
|
|
1018
|
+
console.error("");
|
|
1019
|
+
console.error(theme.colors.dim(" Configure your API key using:"));
|
|
1020
|
+
console.error(theme.colors.accent(` megabuff config set --provider ${provider} <your-api-key>`));
|
|
1021
|
+
console.error("");
|
|
1022
|
+
console.error(theme.colors.dim(" Or set an environment variable for this provider"));
|
|
1023
|
+
console.error("");
|
|
1024
|
+
process.exit(1);
|
|
694
1025
|
}
|
|
695
1026
|
// Get the configured model (if any) for this provider
|
|
696
1027
|
const configuredModel = await getModel();
|
|
697
1028
|
const modelToUse = configuredModel && getProviderForModel(configuredModel) === provider ? configuredModel : undefined;
|
|
698
1029
|
debugLog("model.selected", { configuredModel, modelToUse, provider });
|
|
699
1030
|
// Route to the appropriate provider's optimization function
|
|
700
|
-
const
|
|
1031
|
+
const providerEmoji = provider === "openai" ? "🤖" : provider === "anthropic" ? "🧠" : "✨";
|
|
1032
|
+
const spinner = createSpinner(`${providerEmoji} Optimizing your prompt with ${formatProviderName(provider)}${modelToUse ? ` (${modelToUse})` : ""}...`);
|
|
701
1033
|
spinner.start();
|
|
702
1034
|
let optimized;
|
|
703
1035
|
const t0 = Date.now();
|
|
@@ -712,21 +1044,28 @@ program
|
|
|
712
1044
|
optimized = await optimizePromptGemini(original, apiKey, modelToUse);
|
|
713
1045
|
}
|
|
714
1046
|
else {
|
|
715
|
-
|
|
716
|
-
|
|
1047
|
+
console.error("");
|
|
1048
|
+
console.error(theme.colors.error("❌ Error: ") + theme.colors.warning(`Provider '${provider}' is not supported for optimization`));
|
|
1049
|
+
console.error("");
|
|
1050
|
+
console.error(theme.colors.dim(" Supported providers: ") + theme.colors.info("openai, anthropic, google"));
|
|
1051
|
+
console.error("");
|
|
1052
|
+
process.exit(1);
|
|
717
1053
|
}
|
|
1054
|
+
const duration = ((Date.now() - t0) / 1000).toFixed(1);
|
|
718
1055
|
debugLog("optimize.done", { provider, ms: Date.now() - t0, optimizedLength: optimized.length });
|
|
719
|
-
spinner.stop(
|
|
1056
|
+
spinner.stop(`✨ Optimization complete in ${duration}s!`);
|
|
720
1057
|
}
|
|
721
1058
|
catch (e) {
|
|
722
1059
|
debugLog("optimize.error", { provider, ms: Date.now() - t0, error: e instanceof Error ? e.message : String(e) });
|
|
723
|
-
spinner.fail(
|
|
1060
|
+
spinner.fail(`💥 Optimization failed with ${formatProviderName(provider)}`);
|
|
724
1061
|
throw e;
|
|
725
1062
|
}
|
|
726
1063
|
await outputResult(original, optimized, options);
|
|
727
1064
|
}
|
|
728
1065
|
catch (error) {
|
|
729
|
-
console.error(
|
|
1066
|
+
console.error("");
|
|
1067
|
+
console.error(theme.colors.error("❌ Error: ") + theme.colors.warning(error instanceof Error ? error.message : String(error)));
|
|
1068
|
+
console.error("");
|
|
730
1069
|
process.exit(1);
|
|
731
1070
|
}
|
|
732
1071
|
});
|