terminalmarket 0.4.1 → 0.5.1
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 +28 -0
- package/bin/tm.js +225 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -71,6 +71,30 @@ tm reviews <store-id> # View store reviews
|
|
|
71
71
|
tm review <store-id> <rating> [comment] # Leave a review (1-5 stars)
|
|
72
72
|
```
|
|
73
73
|
|
|
74
|
+
### AI Services
|
|
75
|
+
|
|
76
|
+
Run AI models directly from the terminal using credits.
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
tm ai list # List available AI models
|
|
80
|
+
tm ai run <model> <input> # Run an AI model
|
|
81
|
+
tm ai credits # Check your credit balance
|
|
82
|
+
tm ai topup <amount> # Add credits ($5 minimum)
|
|
83
|
+
tm ai history # View usage history
|
|
84
|
+
|
|
85
|
+
# Shortcuts
|
|
86
|
+
tm credits # Check credits (shortcut)
|
|
87
|
+
tm topup <amount> # Add credits (shortcut)
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Example:
|
|
91
|
+
```bash
|
|
92
|
+
tm ai list # See available models
|
|
93
|
+
tm ai topup 10 # Add $10 credits
|
|
94
|
+
tm ai run text-rewrite "Fix this text" # Run AI model
|
|
95
|
+
tm ai credits # Check remaining balance
|
|
96
|
+
```
|
|
97
|
+
|
|
74
98
|
### Service Types
|
|
75
99
|
|
|
76
100
|
Products have different service types:
|
|
@@ -165,6 +189,10 @@ tm orders
|
|
|
165
189
|
- `POST /api/cart/clear` — Clear cart
|
|
166
190
|
- `GET /api/orders` — Get orders
|
|
167
191
|
- `POST /api/stores/:id/reviews` — Leave review
|
|
192
|
+
- `GET /api/credits` — Get AI credits balance
|
|
193
|
+
- `POST /api/credits/topup` — Create Stripe checkout for credits
|
|
194
|
+
- `POST /api/ai/run/:model` — Run AI model
|
|
195
|
+
- `GET /api/ai/history` — Get AI usage history
|
|
168
196
|
- `POST /api/clicks` — Track clicks
|
|
169
197
|
- `POST /api/intents` — Create purchase intent
|
|
170
198
|
|
package/bin/tm.js
CHANGED
|
@@ -13,7 +13,7 @@ const program = new Command();
|
|
|
13
13
|
program
|
|
14
14
|
.name("tm")
|
|
15
15
|
.description("TerminalMarket CLI — marketplace for developers")
|
|
16
|
-
.version("0.
|
|
16
|
+
.version("0.5.0");
|
|
17
17
|
|
|
18
18
|
// -----------------
|
|
19
19
|
// config
|
|
@@ -461,6 +461,230 @@ program
|
|
|
461
461
|
}
|
|
462
462
|
});
|
|
463
463
|
|
|
464
|
+
// -----------------
|
|
465
|
+
// AI commands
|
|
466
|
+
// -----------------
|
|
467
|
+
const ai = program
|
|
468
|
+
.command("ai")
|
|
469
|
+
.description("AI services - run AI models with credits");
|
|
470
|
+
|
|
471
|
+
ai
|
|
472
|
+
.command("list")
|
|
473
|
+
.alias("ls")
|
|
474
|
+
.description("List available AI models")
|
|
475
|
+
.action(async () => {
|
|
476
|
+
try {
|
|
477
|
+
const data = await apiGet("/ai/models");
|
|
478
|
+
const { models, categories } = data;
|
|
479
|
+
|
|
480
|
+
if (!models || models.length === 0) {
|
|
481
|
+
console.log(chalk.yellow("No AI models available yet."));
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
console.log(chalk.bold("Available AI Models"));
|
|
486
|
+
console.log("");
|
|
487
|
+
|
|
488
|
+
const catMap = new Map((categories || []).map(c => [c.id, c]));
|
|
489
|
+
|
|
490
|
+
// Group by category
|
|
491
|
+
const grouped = {};
|
|
492
|
+
for (const model of models) {
|
|
493
|
+
const cat = catMap.get(model.categoryId);
|
|
494
|
+
const catName = cat ? cat.name : "Other";
|
|
495
|
+
if (!grouped[catName]) grouped[catName] = [];
|
|
496
|
+
grouped[catName].push(model);
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
for (const [catName, catModels] of Object.entries(grouped)) {
|
|
500
|
+
console.log(chalk.cyan.bold(`${catName}:`));
|
|
501
|
+
for (const model of catModels) {
|
|
502
|
+
const price = parseFloat(model.pricePerRun).toFixed(4);
|
|
503
|
+
console.log(` ${chalk.white(model.slug.padEnd(25))} $${price} ${chalk.dim(model.outputType)}`);
|
|
504
|
+
if (model.description) {
|
|
505
|
+
console.log(` ${chalk.dim(model.description)}`);
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
console.log("");
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
console.log(chalk.dim("Run: tm ai run <model> <input>"));
|
|
512
|
+
} catch (e) {
|
|
513
|
+
console.error(chalk.red(e?.message || String(e)));
|
|
514
|
+
process.exitCode = 1;
|
|
515
|
+
}
|
|
516
|
+
});
|
|
517
|
+
|
|
518
|
+
ai
|
|
519
|
+
.command("run <model> [input...]")
|
|
520
|
+
.description("Run an AI model")
|
|
521
|
+
.action(async (model, input) => {
|
|
522
|
+
try {
|
|
523
|
+
const inputText = input.join(" ");
|
|
524
|
+
if (!inputText) {
|
|
525
|
+
console.error(chalk.red("Input is required. Usage: tm ai run <model> <input>"));
|
|
526
|
+
return;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
const result = await apiPost(`/ai/run/${model}`, { input: inputText });
|
|
530
|
+
|
|
531
|
+
console.log(chalk.bold("AI Result"));
|
|
532
|
+
console.log("");
|
|
533
|
+
|
|
534
|
+
if (result.output?.message) {
|
|
535
|
+
console.log(result.output.message);
|
|
536
|
+
}
|
|
537
|
+
if (result.output?.note) {
|
|
538
|
+
console.log(chalk.dim(result.output.note));
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
console.log("");
|
|
542
|
+
console.log(`${chalk.dim("credits used:")} $${result.creditsUsed.toFixed(4)}`);
|
|
543
|
+
console.log(`${chalk.dim("new balance:")} $${result.newBalance}`);
|
|
544
|
+
} catch (e) {
|
|
545
|
+
if (e?.message?.includes("402") || e?.message?.includes("Insufficient")) {
|
|
546
|
+
console.error(chalk.red("Insufficient credits. Use 'tm ai topup <amount>' to add credits."));
|
|
547
|
+
} else {
|
|
548
|
+
console.error(chalk.red(e?.message || String(e)));
|
|
549
|
+
}
|
|
550
|
+
process.exitCode = 1;
|
|
551
|
+
}
|
|
552
|
+
});
|
|
553
|
+
|
|
554
|
+
ai
|
|
555
|
+
.command("credits")
|
|
556
|
+
.alias("balance")
|
|
557
|
+
.description("Check your AI credit balance")
|
|
558
|
+
.action(async () => {
|
|
559
|
+
try {
|
|
560
|
+
const credits = await apiGet("/credits");
|
|
561
|
+
|
|
562
|
+
console.log(chalk.bold("AI Credits"));
|
|
563
|
+
console.log("");
|
|
564
|
+
console.log(`${chalk.dim("balance:")} $${parseFloat(credits.balance).toFixed(4)}`);
|
|
565
|
+
console.log(`${chalk.dim("purchased:")} $${parseFloat(credits.totalPurchased).toFixed(2)}`);
|
|
566
|
+
console.log(`${chalk.dim("spent:")} $${parseFloat(credits.totalSpent).toFixed(4)}`);
|
|
567
|
+
console.log("");
|
|
568
|
+
console.log(chalk.dim("Top up: tm ai topup <amount>"));
|
|
569
|
+
} catch (e) {
|
|
570
|
+
if (e?.message?.includes("401") || e?.message?.includes("Login")) {
|
|
571
|
+
console.log(chalk.yellow("Please login first: tm login <email> <password>"));
|
|
572
|
+
} else {
|
|
573
|
+
console.error(chalk.red(e?.message || String(e)));
|
|
574
|
+
process.exitCode = 1;
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
});
|
|
578
|
+
|
|
579
|
+
ai
|
|
580
|
+
.command("topup <amount>")
|
|
581
|
+
.alias("add")
|
|
582
|
+
.description("Add credits to your account ($5 minimum)")
|
|
583
|
+
.action(async (amount) => {
|
|
584
|
+
try {
|
|
585
|
+
const amountNum = parseFloat(amount);
|
|
586
|
+
if (isNaN(amountNum) || amountNum < 5) {
|
|
587
|
+
console.error(chalk.red("Minimum top-up is $5"));
|
|
588
|
+
return;
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
const result = await apiPost("/credits/topup", { amount: amountNum });
|
|
592
|
+
|
|
593
|
+
console.log(chalk.green("Payment link created!"));
|
|
594
|
+
console.log("");
|
|
595
|
+
console.log("Open this link to complete payment:");
|
|
596
|
+
console.log(chalk.cyan(result.url));
|
|
597
|
+
console.log("");
|
|
598
|
+
console.log(chalk.dim("Credits will be added after payment."));
|
|
599
|
+
|
|
600
|
+
// Try to open in browser
|
|
601
|
+
try {
|
|
602
|
+
await open(result.url);
|
|
603
|
+
console.log(chalk.dim("(Opening in browser...)"));
|
|
604
|
+
} catch {}
|
|
605
|
+
} catch (e) {
|
|
606
|
+
if (e?.message?.includes("401") || e?.message?.includes("Login")) {
|
|
607
|
+
console.log(chalk.yellow("Please login first: tm login <email> <password>"));
|
|
608
|
+
} else {
|
|
609
|
+
console.error(chalk.red(e?.message || String(e)));
|
|
610
|
+
process.exitCode = 1;
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
});
|
|
614
|
+
|
|
615
|
+
ai
|
|
616
|
+
.command("history")
|
|
617
|
+
.description("View your AI usage history")
|
|
618
|
+
.option("-l, --limit <n>", "Limit results", "20")
|
|
619
|
+
.action(async (opts) => {
|
|
620
|
+
try {
|
|
621
|
+
const logs = await apiGet("/ai/history");
|
|
622
|
+
const limit = parseInt(opts.limit) || 20;
|
|
623
|
+
|
|
624
|
+
if (!logs || logs.length === 0) {
|
|
625
|
+
console.log(chalk.yellow("No AI usage history yet."));
|
|
626
|
+
console.log(chalk.dim("Try: tm ai run <model> <input>"));
|
|
627
|
+
return;
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
console.log(chalk.bold("AI Usage History"));
|
|
631
|
+
console.log("");
|
|
632
|
+
|
|
633
|
+
logs.slice(0, limit).forEach(log => {
|
|
634
|
+
const date = new Date(log.createdAt).toLocaleDateString();
|
|
635
|
+
const credits = parseFloat(log.creditsCharged).toFixed(4);
|
|
636
|
+
const statusColor = log.status === "completed" ? chalk.green :
|
|
637
|
+
log.status === "failed" ? chalk.red : chalk.yellow;
|
|
638
|
+
|
|
639
|
+
console.log(`${date} Model #${log.modelId} $${credits} ${statusColor(log.status)}`);
|
|
640
|
+
});
|
|
641
|
+
} catch (e) {
|
|
642
|
+
if (e?.message?.includes("401") || e?.message?.includes("Login")) {
|
|
643
|
+
console.log(chalk.yellow("Please login first: tm login <email> <password>"));
|
|
644
|
+
} else {
|
|
645
|
+
console.error(chalk.red(e?.message || String(e)));
|
|
646
|
+
process.exitCode = 1;
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
});
|
|
650
|
+
|
|
651
|
+
// Shortcuts for AI commands
|
|
652
|
+
program
|
|
653
|
+
.command("credits")
|
|
654
|
+
.description("Check AI credits (shortcut)")
|
|
655
|
+
.action(async () => {
|
|
656
|
+
try {
|
|
657
|
+
const credits = await apiGet("/credits");
|
|
658
|
+
console.log(chalk.bold("AI Credits"));
|
|
659
|
+
console.log(`${chalk.dim("balance:")} $${parseFloat(credits.balance).toFixed(4)}`);
|
|
660
|
+
console.log(chalk.dim("Top up: tm ai topup <amount>"));
|
|
661
|
+
} catch (e) {
|
|
662
|
+
if (e?.message?.includes("401")) {
|
|
663
|
+
console.log(chalk.yellow("Please login first."));
|
|
664
|
+
} else {
|
|
665
|
+
console.error(chalk.red(e?.message || String(e)));
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
});
|
|
669
|
+
|
|
670
|
+
program
|
|
671
|
+
.command("topup <amount>")
|
|
672
|
+
.description("Add AI credits (shortcut)")
|
|
673
|
+
.action(async (amount) => {
|
|
674
|
+
const amountNum = parseFloat(amount);
|
|
675
|
+
if (isNaN(amountNum) || amountNum < 5) {
|
|
676
|
+
console.error(chalk.red("Minimum top-up is $5"));
|
|
677
|
+
return;
|
|
678
|
+
}
|
|
679
|
+
try {
|
|
680
|
+
const result = await apiPost("/credits/topup", { amount: amountNum });
|
|
681
|
+
console.log(chalk.green("Payment link: ") + chalk.cyan(result.url));
|
|
682
|
+
try { await open(result.url); } catch {}
|
|
683
|
+
} catch (e) {
|
|
684
|
+
console.error(chalk.red(e?.message || String(e)));
|
|
685
|
+
}
|
|
686
|
+
});
|
|
687
|
+
|
|
464
688
|
// -----------------
|
|
465
689
|
// categories
|
|
466
690
|
// -----------------
|