plexmint 0.1.0 → 0.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 +523 -475
- package/package.json +4 -3
package/dist/index.js
CHANGED
|
@@ -2,32 +2,95 @@
|
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
4
|
import { Command } from "commander";
|
|
5
|
-
import
|
|
5
|
+
import chalk10 from "chalk";
|
|
6
|
+
|
|
7
|
+
// src/lib/config.ts
|
|
8
|
+
import { readFileSync, writeFileSync, mkdirSync, existsSync } from "fs";
|
|
9
|
+
import { join } from "path";
|
|
10
|
+
import { homedir } from "os";
|
|
11
|
+
var CONFIG_DIR = join(homedir(), ".plexmint");
|
|
12
|
+
var CONFIG_FILE = join(CONFIG_DIR, "config.json");
|
|
13
|
+
function ensureConfigDir() {
|
|
14
|
+
if (!existsSync(CONFIG_DIR)) {
|
|
15
|
+
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
function readConfig() {
|
|
19
|
+
try {
|
|
20
|
+
if (!existsSync(CONFIG_FILE)) {
|
|
21
|
+
return {};
|
|
22
|
+
}
|
|
23
|
+
const raw = readFileSync(CONFIG_FILE, "utf-8");
|
|
24
|
+
return JSON.parse(raw);
|
|
25
|
+
} catch {
|
|
26
|
+
return {};
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function writeConfig(config) {
|
|
30
|
+
ensureConfigDir();
|
|
31
|
+
writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
32
|
+
}
|
|
33
|
+
function getApiKey() {
|
|
34
|
+
return readConfig().apiKey;
|
|
35
|
+
}
|
|
36
|
+
function setAuth(apiKey, email, name) {
|
|
37
|
+
writeConfig({ apiKey, email, name });
|
|
38
|
+
}
|
|
39
|
+
function clearAuth() {
|
|
40
|
+
writeConfig({});
|
|
41
|
+
}
|
|
42
|
+
function isAuthenticated() {
|
|
43
|
+
return !!readConfig().apiKey;
|
|
44
|
+
}
|
|
45
|
+
function getConfigPath() {
|
|
46
|
+
return CONFIG_FILE;
|
|
47
|
+
}
|
|
6
48
|
|
|
7
|
-
// src/
|
|
49
|
+
// src/lib/ui.ts
|
|
8
50
|
import chalk from "chalk";
|
|
51
|
+
var mint = chalk.hex("#00D68F");
|
|
52
|
+
var mintBold = chalk.hex("#00D68F").bold;
|
|
53
|
+
var BANNER = `
|
|
54
|
+
${chalk.bold.white("plex")}${mintBold("mint")} ${chalk.gray("\u2014 AI prompts that evolve")}
|
|
55
|
+
${chalk.gray("https://plexmint.com")}
|
|
56
|
+
`;
|
|
57
|
+
function requireAuth() {
|
|
58
|
+
if (!isAuthenticated()) {
|
|
59
|
+
console.log("");
|
|
60
|
+
console.log(chalk.yellow(" Not logged in."));
|
|
61
|
+
console.log(
|
|
62
|
+
chalk.gray(" Run ") + chalk.white("plexmint setup") + chalk.gray(" to create an account, or ") + chalk.white("plexmint login") + chalk.gray(" to sign in.\n")
|
|
63
|
+
);
|
|
64
|
+
process.exit(1);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
function formatPrice(price) {
|
|
68
|
+
const n = typeof price === "string" ? parseFloat(price) : price;
|
|
69
|
+
return `$${n.toFixed(2)}`;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// src/commands/setup.ts
|
|
73
|
+
import chalk2 from "chalk";
|
|
9
74
|
import ora from "ora";
|
|
10
|
-
import
|
|
75
|
+
import inquirer from "inquirer";
|
|
11
76
|
|
|
12
77
|
// src/lib/api.ts
|
|
13
|
-
var
|
|
78
|
+
var BASE_URL = "https://plexmint.com/api/v1";
|
|
14
79
|
var PlexMintClient = class {
|
|
15
|
-
baseUrl;
|
|
16
80
|
apiKey;
|
|
17
|
-
constructor(apiKey
|
|
81
|
+
constructor(apiKey) {
|
|
18
82
|
this.apiKey = apiKey;
|
|
19
|
-
this.baseUrl = baseUrl || DEFAULT_BASE_URL;
|
|
20
83
|
}
|
|
21
84
|
async request(path, options = {}) {
|
|
22
85
|
const headers = {
|
|
23
86
|
"Content-Type": "application/json",
|
|
24
|
-
"User-Agent": "plexmint-cli/0.
|
|
87
|
+
"User-Agent": "plexmint-cli/0.2.0",
|
|
25
88
|
...options.headers
|
|
26
89
|
};
|
|
27
90
|
if (this.apiKey) {
|
|
28
91
|
headers["Authorization"] = `Bearer ${this.apiKey}`;
|
|
29
92
|
}
|
|
30
|
-
const res = await fetch(`${
|
|
93
|
+
const res = await fetch(`${BASE_URL}${path}`, {
|
|
31
94
|
...options,
|
|
32
95
|
headers
|
|
33
96
|
});
|
|
@@ -42,30 +105,42 @@ var PlexMintClient = class {
|
|
|
42
105
|
}
|
|
43
106
|
return json;
|
|
44
107
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
108
|
+
// ─── Auth ───
|
|
109
|
+
async register(data) {
|
|
110
|
+
return this.request("/register", {
|
|
111
|
+
method: "POST",
|
|
112
|
+
body: JSON.stringify(data)
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
async verify(email, code) {
|
|
116
|
+
return this.request("/verify", {
|
|
117
|
+
method: "POST",
|
|
118
|
+
body: JSON.stringify({ email, code })
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
async login(email, password) {
|
|
122
|
+
return this.request("/login", {
|
|
123
|
+
method: "POST",
|
|
124
|
+
body: JSON.stringify({ email, password })
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
// ─── Prompts ───
|
|
48
128
|
async browse(options = {}) {
|
|
49
129
|
const params = new URLSearchParams();
|
|
50
|
-
if (options.query) params.set("
|
|
130
|
+
if (options.query) params.set("search", options.query);
|
|
51
131
|
if (options.category) params.set("category", options.category);
|
|
52
|
-
if (options.model) params.set("model", options.model);
|
|
53
132
|
if (options.sort) params.set("sort", options.sort);
|
|
54
133
|
if (options.limit) params.set("limit", options.limit.toString());
|
|
134
|
+
if (options.offset) params.set("offset", options.offset.toString());
|
|
55
135
|
const qs = params.toString();
|
|
56
136
|
return this.request(`/prompts${qs ? `?${qs}` : ""}`);
|
|
57
137
|
}
|
|
58
|
-
/**
|
|
59
|
-
* Get a single prompt by ticker
|
|
60
|
-
*/
|
|
61
138
|
async getPrompt(ticker) {
|
|
62
139
|
return this.request(
|
|
63
|
-
`/prompts
|
|
140
|
+
`/prompts/${encodeURIComponent(ticker.toUpperCase())}`
|
|
64
141
|
);
|
|
65
142
|
}
|
|
66
|
-
|
|
67
|
-
* Initiate a purchase (requires API key)
|
|
68
|
-
*/
|
|
143
|
+
// ─── Commerce ───
|
|
69
144
|
async purchase(ticker) {
|
|
70
145
|
if (!this.apiKey) {
|
|
71
146
|
throw new PlexMintApiError(
|
|
@@ -76,13 +151,13 @@ var PlexMintClient = class {
|
|
|
76
151
|
}
|
|
77
152
|
return this.request("/purchase", {
|
|
78
153
|
method: "POST",
|
|
79
|
-
body: JSON.stringify({
|
|
154
|
+
body: JSON.stringify({
|
|
155
|
+
ticker: ticker.toUpperCase(),
|
|
156
|
+
payment_method: "wallet"
|
|
157
|
+
})
|
|
80
158
|
});
|
|
81
159
|
}
|
|
82
|
-
|
|
83
|
-
* Get prompt content (requires purchase)
|
|
84
|
-
*/
|
|
85
|
-
async getContent(ticker) {
|
|
160
|
+
async getWallet() {
|
|
86
161
|
if (!this.apiKey) {
|
|
87
162
|
throw new PlexMintApiError(
|
|
88
163
|
"Authentication required. Run: plexmint login",
|
|
@@ -90,18 +165,17 @@ var PlexMintClient = class {
|
|
|
90
165
|
{}
|
|
91
166
|
);
|
|
92
167
|
}
|
|
93
|
-
return this.request(
|
|
94
|
-
`/library/${encodeURIComponent(ticker.toUpperCase())}/content`
|
|
95
|
-
);
|
|
168
|
+
return this.request("/wallet");
|
|
96
169
|
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
}
|
|
170
|
+
async getLibrary() {
|
|
171
|
+
if (!this.apiKey) {
|
|
172
|
+
throw new PlexMintApiError(
|
|
173
|
+
"Authentication required. Run: plexmint login",
|
|
174
|
+
401,
|
|
175
|
+
{}
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
return this.request("/library");
|
|
105
179
|
}
|
|
106
180
|
};
|
|
107
181
|
var PlexMintApiError = class extends Error {
|
|
@@ -115,233 +189,307 @@ var PlexMintApiError = class extends Error {
|
|
|
115
189
|
}
|
|
116
190
|
};
|
|
117
191
|
|
|
118
|
-
// src/
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
192
|
+
// src/commands/setup.ts
|
|
193
|
+
async function setupCommand() {
|
|
194
|
+
console.log("");
|
|
195
|
+
console.log(mintBold(" PlexMint Setup"));
|
|
196
|
+
console.log(chalk2.gray(" Create your account and start browsing AI prompts."));
|
|
197
|
+
console.log("");
|
|
198
|
+
const answers = await inquirer.prompt([
|
|
199
|
+
{
|
|
200
|
+
type: "input",
|
|
201
|
+
name: "name",
|
|
202
|
+
message: "Your name:",
|
|
203
|
+
validate: (v) => v.trim().length > 0 || "Name is required."
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
type: "input",
|
|
207
|
+
name: "email",
|
|
208
|
+
message: "Email:",
|
|
209
|
+
validate: (v) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(v) || "Enter a valid email address."
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
type: "password",
|
|
213
|
+
name: "password",
|
|
214
|
+
message: "Password:",
|
|
215
|
+
mask: "*",
|
|
216
|
+
validate: (v) => v.length >= 8 || "Password must be at least 8 characters."
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
type: "password",
|
|
220
|
+
name: "confirmPassword",
|
|
221
|
+
message: "Confirm password:",
|
|
222
|
+
mask: "*",
|
|
223
|
+
validate: (v, a) => {
|
|
224
|
+
if (!a) return "Confirm your password.";
|
|
225
|
+
return v === a.password || "Passwords do not match.";
|
|
226
|
+
}
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
type: "input",
|
|
230
|
+
name: "tickerPrefix",
|
|
231
|
+
message: "Ticker prefix (2-5 uppercase letters, e.g. NUE):",
|
|
232
|
+
transformer: (v) => v.toUpperCase(),
|
|
233
|
+
validate: (v) => /^[A-Z]{2,5}$/i.test(v.trim()) || "Enter 2-5 letters (e.g. NUE, ACME)."
|
|
234
|
+
}
|
|
235
|
+
]);
|
|
236
|
+
const spinner = ora("Creating your account...").start();
|
|
157
237
|
try {
|
|
158
|
-
const client = new PlexMintClient(
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
limit: options.limit ? parseInt(options.limit) : 12
|
|
238
|
+
const client = new PlexMintClient();
|
|
239
|
+
await client.register({
|
|
240
|
+
name: answers.name.trim(),
|
|
241
|
+
email: answers.email.trim().toLowerCase(),
|
|
242
|
+
password: answers.password,
|
|
243
|
+
tickerPrefix: answers.tickerPrefix.trim().toUpperCase()
|
|
165
244
|
});
|
|
245
|
+
spinner.succeed("Account created! Check your email for a verification code.");
|
|
246
|
+
console.log("");
|
|
247
|
+
const { code } = await inquirer.prompt([
|
|
248
|
+
{
|
|
249
|
+
type: "input",
|
|
250
|
+
name: "code",
|
|
251
|
+
message: "Enter 6-digit verification code:",
|
|
252
|
+
validate: (v) => /^\d{6}$/.test(v.trim()) || "Enter the 6-digit code from your email."
|
|
253
|
+
}
|
|
254
|
+
]);
|
|
255
|
+
const verifySpinner = ora("Verifying...").start();
|
|
256
|
+
const result = await client.verify(
|
|
257
|
+
answers.email.trim().toLowerCase(),
|
|
258
|
+
code.trim()
|
|
259
|
+
);
|
|
260
|
+
verifySpinner.stop();
|
|
261
|
+
const { apiKey, user } = result.data;
|
|
262
|
+
setAuth(apiKey, user.email, user.name);
|
|
263
|
+
console.log("");
|
|
264
|
+
console.log(mint(" \u2713 ") + chalk2.bold("Account verified!"));
|
|
265
|
+
console.log("");
|
|
266
|
+
console.log(chalk2.gray(" Name: ") + chalk2.white(user.name));
|
|
267
|
+
console.log(chalk2.gray(" Email: ") + chalk2.white(user.email));
|
|
268
|
+
console.log(chalk2.gray(" Ticker Prefix: ") + chalk2.white(user.tickerPrefix));
|
|
269
|
+
console.log(chalk2.gray(" API Key: ") + chalk2.white(apiKey));
|
|
270
|
+
console.log(chalk2.gray(" Config: ") + chalk2.white(getConfigPath()));
|
|
271
|
+
console.log("");
|
|
272
|
+
console.log(
|
|
273
|
+
chalk2.gray(" Get started: ") + chalk2.white("plexmint browse") + chalk2.gray(" or ") + chalk2.white("plexmint --help")
|
|
274
|
+
);
|
|
275
|
+
console.log("");
|
|
276
|
+
} catch (error) {
|
|
166
277
|
spinner.stop();
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
No prompts found for "${query}"
|
|
278
|
+
if (error instanceof PlexMintApiError) {
|
|
279
|
+
console.error(chalk2.red(`
|
|
280
|
+
Error: ${error.message}
|
|
171
281
|
`));
|
|
172
|
-
|
|
282
|
+
} else {
|
|
283
|
+
console.error(
|
|
284
|
+
chalk2.red("\n Connection error. Is plexmint.com reachable?\n")
|
|
285
|
+
);
|
|
173
286
|
}
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
prompt2.salesCount.toString(),
|
|
200
|
-
prompt2.seller?.username ? chalk.gray(`@${prompt2.seller.username}`) : chalk.gray("\u2014")
|
|
201
|
-
]);
|
|
287
|
+
process.exit(1);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// src/commands/login.ts
|
|
292
|
+
import chalk3 from "chalk";
|
|
293
|
+
import ora2 from "ora";
|
|
294
|
+
import inquirer2 from "inquirer";
|
|
295
|
+
async function loginCommand() {
|
|
296
|
+
console.log("");
|
|
297
|
+
console.log(chalk3.bold(" PlexMint Login"));
|
|
298
|
+
console.log(chalk3.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
299
|
+
console.log("");
|
|
300
|
+
if (isAuthenticated()) {
|
|
301
|
+
const { proceed } = await inquirer2.prompt([
|
|
302
|
+
{
|
|
303
|
+
type: "confirm",
|
|
304
|
+
name: "proceed",
|
|
305
|
+
message: "Already logged in. Re-authenticate?",
|
|
306
|
+
default: false
|
|
307
|
+
}
|
|
308
|
+
]);
|
|
309
|
+
if (!proceed) {
|
|
310
|
+
console.log(chalk3.gray(" Cancelled.\n"));
|
|
311
|
+
return;
|
|
202
312
|
}
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
313
|
+
clearAuth();
|
|
314
|
+
}
|
|
315
|
+
const answers = await inquirer2.prompt([
|
|
316
|
+
{
|
|
317
|
+
type: "input",
|
|
318
|
+
name: "email",
|
|
319
|
+
message: "Email:",
|
|
320
|
+
validate: (v) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(v) || "Enter a valid email."
|
|
321
|
+
},
|
|
322
|
+
{
|
|
323
|
+
type: "password",
|
|
324
|
+
name: "password",
|
|
325
|
+
message: "Password:",
|
|
326
|
+
mask: "*",
|
|
327
|
+
validate: (v) => v.length > 0 || "Password is required."
|
|
206
328
|
}
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
329
|
+
]);
|
|
330
|
+
const spinner = ora2("Logging in...").start();
|
|
331
|
+
try {
|
|
332
|
+
const client = new PlexMintClient();
|
|
333
|
+
const result = await client.login(
|
|
334
|
+
answers.email.trim().toLowerCase(),
|
|
335
|
+
answers.password
|
|
210
336
|
);
|
|
337
|
+
spinner.stop();
|
|
338
|
+
const { apiKey, user } = result.data;
|
|
339
|
+
setAuth(apiKey, user.email, user.name);
|
|
340
|
+
console.log("");
|
|
341
|
+
console.log(mint(" \u2713 ") + chalk3.bold("Logged in!"));
|
|
342
|
+
console.log(chalk3.gray(" Name: ") + chalk3.white(user.name));
|
|
343
|
+
console.log(chalk3.gray(" Email: ") + chalk3.white(user.email));
|
|
344
|
+
console.log(chalk3.gray(" Config: ") + chalk3.white(getConfigPath()));
|
|
345
|
+
console.log("");
|
|
211
346
|
} catch (error) {
|
|
212
347
|
spinner.stop();
|
|
213
348
|
if (error instanceof PlexMintApiError) {
|
|
214
|
-
|
|
349
|
+
if (error.status === 401) {
|
|
350
|
+
console.error(chalk3.red("\n Invalid email or password.\n"));
|
|
351
|
+
} else {
|
|
352
|
+
console.error(chalk3.red(`
|
|
215
353
|
Error: ${error.message}
|
|
216
354
|
`));
|
|
355
|
+
}
|
|
217
356
|
} else {
|
|
218
|
-
console.error(
|
|
219
|
-
Connection error. Is plexmint.com reachable
|
|
220
|
-
|
|
357
|
+
console.error(
|
|
358
|
+
chalk3.red("\n Connection error. Is plexmint.com reachable?\n")
|
|
359
|
+
);
|
|
221
360
|
}
|
|
222
361
|
process.exit(1);
|
|
223
362
|
}
|
|
224
363
|
}
|
|
225
364
|
|
|
226
365
|
// src/commands/browse.ts
|
|
227
|
-
import
|
|
228
|
-
import
|
|
229
|
-
import
|
|
366
|
+
import chalk4 from "chalk";
|
|
367
|
+
import ora3 from "ora";
|
|
368
|
+
import Table from "cli-table3";
|
|
230
369
|
async function browseCommand(options) {
|
|
231
|
-
const spinner =
|
|
370
|
+
const spinner = ora3("Browsing PlexMint marketplace...").start();
|
|
232
371
|
try {
|
|
233
|
-
const client = new PlexMintClient(getApiKey()
|
|
372
|
+
const client = new PlexMintClient(getApiKey());
|
|
234
373
|
const result = await client.browse({
|
|
374
|
+
query: options.search,
|
|
235
375
|
category: options.category,
|
|
236
|
-
model: options.model,
|
|
237
376
|
sort: options.sort || "trending",
|
|
238
|
-
limit:
|
|
377
|
+
limit: 20
|
|
239
378
|
});
|
|
240
379
|
spinner.stop();
|
|
241
|
-
const { items } = result.data;
|
|
380
|
+
const { items, total } = result.data;
|
|
242
381
|
if (items.length === 0) {
|
|
243
|
-
console.log(
|
|
382
|
+
console.log(chalk4.yellow("\n No prompts found.\n"));
|
|
244
383
|
return;
|
|
245
384
|
}
|
|
246
|
-
const
|
|
385
|
+
const filters = [];
|
|
386
|
+
if (options.category) filters.push(`category: ${options.category}`);
|
|
387
|
+
if (options.search) filters.push(`search: "${options.search}"`);
|
|
388
|
+
if (options.sort) filters.push(`sort: ${options.sort}`);
|
|
247
389
|
console.log(
|
|
248
|
-
|
|
249
|
-
PlexMint Marketplace`) +
|
|
250
|
-
`)
|
|
390
|
+
chalk4.bold(`
|
|
391
|
+
PlexMint Marketplace`) + chalk4.gray(` \u2014 ${total} prompt${total !== 1 ? "s" : ""}`) + (filters.length > 0 ? chalk4.gray(` (${filters.join(", ")})`) : "") + "\n"
|
|
251
392
|
);
|
|
252
|
-
const table = new
|
|
393
|
+
const table = new Table({
|
|
253
394
|
head: [
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
395
|
+
mint("Ticker"),
|
|
396
|
+
mint("Title"),
|
|
397
|
+
mint("Price"),
|
|
398
|
+
mint("Rating"),
|
|
399
|
+
mint("Sales"),
|
|
400
|
+
mint("Seller")
|
|
260
401
|
],
|
|
261
402
|
style: { head: [], border: ["gray"] },
|
|
262
|
-
colWidths: [14, 30,
|
|
403
|
+
colWidths: [14, 30, 10, 10, 8, 16]
|
|
263
404
|
});
|
|
264
|
-
for (const
|
|
265
|
-
const price = parseFloat(
|
|
266
|
-
const rating = parseFloat(
|
|
405
|
+
for (const prompt of items) {
|
|
406
|
+
const price = parseFloat(prompt.currentPrice);
|
|
407
|
+
const rating = parseFloat(prompt.averageRating);
|
|
267
408
|
table.push([
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
409
|
+
chalk4.bold(prompt.ticker),
|
|
410
|
+
prompt.title.length > 28 ? prompt.title.slice(0, 25) + "..." : prompt.title,
|
|
411
|
+
mint(formatPrice(price)),
|
|
412
|
+
rating > 0 ? chalk4.yellow(`\u2605 ${rating.toFixed(1)}`) : chalk4.gray("\u2014"),
|
|
413
|
+
prompt.salesCount.toString(),
|
|
414
|
+
prompt.seller?.username ? chalk4.gray(`@${prompt.seller.username}`) : chalk4.gray("\u2014")
|
|
274
415
|
]);
|
|
275
416
|
}
|
|
276
417
|
console.log(table.toString());
|
|
277
418
|
console.log(
|
|
278
|
-
|
|
419
|
+
chalk4.gray("\n View details: ") + chalk4.white("plexmint view <TICKER>") + chalk4.gray(" | Buy: ") + chalk4.white("plexmint buy <TICKER>\n")
|
|
279
420
|
);
|
|
280
421
|
} catch (error) {
|
|
281
422
|
spinner.stop();
|
|
282
423
|
if (error instanceof PlexMintApiError) {
|
|
283
|
-
console.error(
|
|
424
|
+
console.error(chalk4.red(`
|
|
284
425
|
Error: ${error.message}
|
|
285
426
|
`));
|
|
286
427
|
} else {
|
|
287
|
-
console.error(
|
|
428
|
+
console.error(
|
|
429
|
+
chalk4.red("\n Connection error. Is plexmint.com reachable?\n")
|
|
430
|
+
);
|
|
288
431
|
}
|
|
289
432
|
process.exit(1);
|
|
290
433
|
}
|
|
291
434
|
}
|
|
292
435
|
|
|
293
|
-
// src/commands/
|
|
294
|
-
import
|
|
295
|
-
import
|
|
296
|
-
async function
|
|
297
|
-
const
|
|
436
|
+
// src/commands/view.ts
|
|
437
|
+
import chalk5 from "chalk";
|
|
438
|
+
import ora4 from "ora";
|
|
439
|
+
async function viewCommand(ticker) {
|
|
440
|
+
const upperTicker = ticker.toUpperCase();
|
|
441
|
+
const spinner = ora4(`Looking up ${upperTicker}...`).start();
|
|
298
442
|
try {
|
|
299
|
-
const client = new PlexMintClient(getApiKey()
|
|
300
|
-
const result = await client.getPrompt(
|
|
443
|
+
const client = new PlexMintClient(getApiKey());
|
|
444
|
+
const result = await client.getPrompt(upperTicker);
|
|
301
445
|
spinner.stop();
|
|
302
446
|
const p = result.data;
|
|
303
447
|
const price = parseFloat(p.currentPrice);
|
|
304
448
|
const rating = parseFloat(p.averageRating);
|
|
305
449
|
console.log("");
|
|
306
|
-
console.log(
|
|
307
|
-
console.log(
|
|
450
|
+
console.log(chalk5.bold.white(` ${p.title}`));
|
|
451
|
+
console.log(
|
|
452
|
+
mint(p.ticker) + chalk5.gray(` \xB7 ${p.category}`)
|
|
453
|
+
);
|
|
308
454
|
console.log("");
|
|
309
|
-
console.log(
|
|
455
|
+
console.log(chalk5.white(` ${p.description}`));
|
|
310
456
|
console.log("");
|
|
311
457
|
console.log(
|
|
312
|
-
|
|
458
|
+
mint.bold(` ${formatPrice(price)}`) + chalk5.gray(" \xB7 ") + (rating > 0 ? chalk5.yellow(`\u2605 ${rating.toFixed(1)}`) : chalk5.gray("No ratings")) + chalk5.gray(" \xB7 ") + chalk5.white(`${p.salesCount} sold`) + chalk5.gray(" \xB7 ") + chalk5.white(`${p.reviewCount} reviews`)
|
|
313
459
|
);
|
|
314
460
|
console.log("");
|
|
315
461
|
if (p.models.length > 0) {
|
|
316
|
-
const modelList = p.models.map(
|
|
317
|
-
|
|
462
|
+
const modelList = p.models.map(
|
|
463
|
+
(m) => m.isPrimary ? chalk5.cyan.bold(m.model) : chalk5.gray(m.model)
|
|
464
|
+
).join(", ");
|
|
465
|
+
console.log(chalk5.gray(" Models: ") + modelList);
|
|
318
466
|
}
|
|
319
467
|
if (p.tags && p.tags.length > 0) {
|
|
320
468
|
console.log(
|
|
321
|
-
|
|
469
|
+
chalk5.gray(" Tags: ") + p.tags.map((t) => chalk5.gray(`#${t}`)).join(" ")
|
|
322
470
|
);
|
|
323
471
|
}
|
|
324
472
|
if (p.seller) {
|
|
325
473
|
console.log(
|
|
326
|
-
|
|
474
|
+
chalk5.gray(" Seller: ") + chalk5.white(p.seller.name || p.seller.username || "\u2014") + (p.seller.username ? chalk5.gray(` (@${p.seller.username})`) : "")
|
|
327
475
|
);
|
|
328
476
|
}
|
|
329
477
|
if (p.tokenEstimate) {
|
|
330
|
-
console.log(
|
|
478
|
+
console.log(chalk5.gray(` Tokens: ~${p.tokenEstimate}`));
|
|
331
479
|
}
|
|
332
480
|
console.log("");
|
|
333
|
-
console.log(
|
|
481
|
+
console.log(chalk5.gray(" \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510"));
|
|
334
482
|
console.log(
|
|
335
|
-
|
|
483
|
+
chalk5.gray(" \u2502 ") + chalk5.white("Buy this prompt:") + " ".repeat(25) + chalk5.gray("\u2502")
|
|
336
484
|
);
|
|
337
|
-
const
|
|
338
|
-
const padding = 39 -
|
|
485
|
+
const buyCmd = `plexmint buy ${p.ticker}`;
|
|
486
|
+
const padding = 39 - buyCmd.length;
|
|
339
487
|
console.log(
|
|
340
|
-
|
|
488
|
+
chalk5.gray(" \u2502 ") + mint.bold(buyCmd) + " ".repeat(Math.max(0, padding)) + chalk5.gray("\u2502")
|
|
341
489
|
);
|
|
342
|
-
console.log(
|
|
490
|
+
console.log(chalk5.gray(" \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518"));
|
|
343
491
|
console.log(
|
|
344
|
-
|
|
492
|
+
chalk5.gray("\n View on web: ") + chalk5.underline(`https://plexmint.com/prompt/${p.slug}
|
|
345
493
|
`)
|
|
346
494
|
);
|
|
347
495
|
} catch (error) {
|
|
@@ -349,372 +497,272 @@ async function infoCommand(ticker) {
|
|
|
349
497
|
if (error instanceof PlexMintApiError) {
|
|
350
498
|
if (error.status === 404) {
|
|
351
499
|
console.error(
|
|
352
|
-
|
|
353
|
-
Prompt not found: ${
|
|
500
|
+
chalk5.red(`
|
|
501
|
+
Prompt not found: ${upperTicker}
|
|
354
502
|
`)
|
|
355
503
|
);
|
|
356
504
|
} else {
|
|
357
|
-
console.error(
|
|
505
|
+
console.error(chalk5.red(`
|
|
358
506
|
Error: ${error.message}
|
|
359
507
|
`));
|
|
360
508
|
}
|
|
361
509
|
} else {
|
|
362
|
-
console.error(
|
|
510
|
+
console.error(
|
|
511
|
+
chalk5.red("\n Connection error. Is plexmint.com reachable?\n")
|
|
512
|
+
);
|
|
363
513
|
}
|
|
364
514
|
process.exit(1);
|
|
365
515
|
}
|
|
366
516
|
}
|
|
367
517
|
|
|
368
|
-
// src/commands/
|
|
369
|
-
import
|
|
370
|
-
import
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
async function installCommand(ticker, options) {
|
|
518
|
+
// src/commands/buy.ts
|
|
519
|
+
import chalk6 from "chalk";
|
|
520
|
+
import ora5 from "ora";
|
|
521
|
+
async function buyCommand(ticker) {
|
|
522
|
+
requireAuth();
|
|
374
523
|
const upperTicker = ticker.toUpperCase();
|
|
375
|
-
|
|
376
|
-
console.log("");
|
|
377
|
-
console.log(
|
|
378
|
-
chalk4.yellow(" Authentication required to install prompts.")
|
|
379
|
-
);
|
|
380
|
-
console.log(
|
|
381
|
-
chalk4.gray(" Run: ") + chalk4.white("plexmint login") + chalk4.gray(" first\n")
|
|
382
|
-
);
|
|
383
|
-
process.exit(1);
|
|
384
|
-
}
|
|
385
|
-
const spinner = ora4(`Looking up ${upperTicker}...`).start();
|
|
524
|
+
const spinner = ora5(`Purchasing ${upperTicker}...`).start();
|
|
386
525
|
try {
|
|
387
|
-
const client = new PlexMintClient(getApiKey()
|
|
388
|
-
|
|
389
|
-
try {
|
|
390
|
-
content = await client.getContent(upperTicker);
|
|
391
|
-
spinner.text = `Downloading ${upperTicker}...`;
|
|
392
|
-
} catch (error) {
|
|
393
|
-
if (error instanceof PlexMintApiError && error.status === 403) {
|
|
394
|
-
spinner.stop();
|
|
395
|
-
const info = await client.getPrompt(upperTicker);
|
|
396
|
-
const p = info.data;
|
|
397
|
-
const price = parseFloat(p.currentPrice);
|
|
398
|
-
console.log("");
|
|
399
|
-
console.log(
|
|
400
|
-
chalk4.yellow(` You haven't purchased ${upperTicker} yet.`)
|
|
401
|
-
);
|
|
402
|
-
console.log("");
|
|
403
|
-
console.log(
|
|
404
|
-
chalk4.white(` ${p.title}`) + chalk4.gray(` by ${p.seller?.username || "unknown"}`)
|
|
405
|
-
);
|
|
406
|
-
console.log(chalk4.green.bold(` $${price.toFixed(2)}`));
|
|
407
|
-
console.log("");
|
|
408
|
-
const purchaseSpinner = ora4("Locking price...").start();
|
|
409
|
-
try {
|
|
410
|
-
const purchase = await client.purchase(upperTicker);
|
|
411
|
-
purchaseSpinner.stop();
|
|
412
|
-
console.log(
|
|
413
|
-
chalk4.green(` Price locked at $${purchase.data.lockedPrice} for ${purchase.data.lockDurationSeconds}s`)
|
|
414
|
-
);
|
|
415
|
-
console.log("");
|
|
416
|
-
console.log(
|
|
417
|
-
chalk4.white(" Complete your purchase here:")
|
|
418
|
-
);
|
|
419
|
-
console.log(
|
|
420
|
-
chalk4.cyan.underline(` ${purchase.data.checkoutUrl}`)
|
|
421
|
-
);
|
|
422
|
-
console.log("");
|
|
423
|
-
console.log(
|
|
424
|
-
chalk4.gray(
|
|
425
|
-
" After purchasing, run this command again to download.\n"
|
|
426
|
-
)
|
|
427
|
-
);
|
|
428
|
-
} catch (purchaseError) {
|
|
429
|
-
purchaseSpinner.stop();
|
|
430
|
-
if (purchaseError instanceof PlexMintApiError) {
|
|
431
|
-
if (purchaseError.status === 409) {
|
|
432
|
-
console.log(
|
|
433
|
-
chalk4.yellow(" You already own this prompt. Retrying download...\n")
|
|
434
|
-
);
|
|
435
|
-
content = await client.getContent(upperTicker);
|
|
436
|
-
} else {
|
|
437
|
-
console.error(chalk4.red(`
|
|
438
|
-
Purchase error: ${purchaseError.message}
|
|
439
|
-
`));
|
|
440
|
-
process.exit(1);
|
|
441
|
-
}
|
|
442
|
-
} else {
|
|
443
|
-
throw purchaseError;
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
if (!content) return;
|
|
447
|
-
} else {
|
|
448
|
-
throw error;
|
|
449
|
-
}
|
|
450
|
-
}
|
|
526
|
+
const client = new PlexMintClient(getApiKey());
|
|
527
|
+
const result = await client.purchase(upperTicker);
|
|
451
528
|
spinner.stop();
|
|
452
|
-
const
|
|
453
|
-
const installDir = resolve(options.dir || ".plexmint");
|
|
454
|
-
if (!existsSync(installDir)) {
|
|
455
|
-
mkdirSync(installDir, { recursive: true });
|
|
456
|
-
}
|
|
457
|
-
const promptDir = join(installDir, data.ticker.toLowerCase());
|
|
458
|
-
if (!existsSync(promptDir)) {
|
|
459
|
-
mkdirSync(promptDir, { recursive: true });
|
|
460
|
-
}
|
|
461
|
-
const promptFile = join(promptDir, "prompt.md");
|
|
462
|
-
if (existsSync(promptFile) && !options.force) {
|
|
463
|
-
console.log(
|
|
464
|
-
chalk4.yellow(
|
|
465
|
-
`
|
|
466
|
-
${upperTicker} is already installed. Use --force to overwrite.
|
|
467
|
-
`
|
|
468
|
-
)
|
|
469
|
-
);
|
|
470
|
-
return;
|
|
471
|
-
}
|
|
472
|
-
writeFileSync(promptFile, data.promptText, "utf-8");
|
|
473
|
-
const metaFile = join(promptDir, "plexmint.json");
|
|
474
|
-
writeFileSync(
|
|
475
|
-
metaFile,
|
|
476
|
-
JSON.stringify(
|
|
477
|
-
{
|
|
478
|
-
ticker: data.ticker,
|
|
479
|
-
title: data.title,
|
|
480
|
-
version: data.version,
|
|
481
|
-
variables: data.variables,
|
|
482
|
-
tips: data.tips,
|
|
483
|
-
models: data.models,
|
|
484
|
-
tokenEstimate: data.tokenEstimate,
|
|
485
|
-
costPerCall: data.costPerCall,
|
|
486
|
-
exampleInput: data.exampleInput,
|
|
487
|
-
exampleOutput: data.exampleOutput,
|
|
488
|
-
installedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
489
|
-
},
|
|
490
|
-
null,
|
|
491
|
-
2
|
|
492
|
-
),
|
|
493
|
-
"utf-8"
|
|
494
|
-
);
|
|
529
|
+
const { ticker: t, title, pricePaid, walletBalance } = result.data;
|
|
495
530
|
console.log("");
|
|
496
|
-
console.log(
|
|
497
|
-
console.log(chalk4.gray(` ${data.title} v${data.version}`));
|
|
531
|
+
console.log(mint(" \u2713 ") + chalk6.bold("Purchase complete!"));
|
|
498
532
|
console.log("");
|
|
499
|
-
console.log(
|
|
500
|
-
console.log(
|
|
501
|
-
console.log(
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
console.log(chalk4.cyan(` {{${v}}}`));
|
|
507
|
-
}
|
|
508
|
-
}
|
|
509
|
-
if (data.tips) {
|
|
510
|
-
console.log("");
|
|
511
|
-
console.log(chalk4.gray(" Tips: ") + chalk4.white(data.tips));
|
|
512
|
-
}
|
|
533
|
+
console.log(chalk6.gray(" Prompt: ") + chalk6.white(`${title} (${t})`));
|
|
534
|
+
console.log(chalk6.gray(" Price paid: ") + mint(formatPrice(pricePaid)));
|
|
535
|
+
console.log(chalk6.gray(" Wallet balance: ") + chalk6.white(formatPrice(walletBalance)));
|
|
536
|
+
console.log("");
|
|
537
|
+
console.log(
|
|
538
|
+
chalk6.gray(" View in your library: ") + chalk6.white("plexmint library")
|
|
539
|
+
);
|
|
513
540
|
console.log("");
|
|
514
541
|
} catch (error) {
|
|
515
542
|
spinner.stop();
|
|
516
543
|
if (error instanceof PlexMintApiError) {
|
|
517
|
-
if (error.status ===
|
|
518
|
-
console.
|
|
544
|
+
if (error.status === 409) {
|
|
545
|
+
console.log(
|
|
546
|
+
chalk6.yellow(`
|
|
547
|
+
You already own ${upperTicker}.
|
|
548
|
+
`)
|
|
549
|
+
);
|
|
550
|
+
console.log(
|
|
551
|
+
chalk6.gray(" View your library: ") + chalk6.white("plexmint library\n")
|
|
552
|
+
);
|
|
553
|
+
} else if (error.status === 402) {
|
|
554
|
+
console.error(
|
|
555
|
+
chalk6.red(`
|
|
556
|
+
Insufficient wallet balance.`) + chalk6.gray(` Add funds at https://plexmint.com/wallet
|
|
557
|
+
`)
|
|
558
|
+
);
|
|
559
|
+
} else if (error.status === 404) {
|
|
560
|
+
console.error(
|
|
561
|
+
chalk6.red(`
|
|
519
562
|
Prompt not found: ${upperTicker}
|
|
520
|
-
`)
|
|
563
|
+
`)
|
|
564
|
+
);
|
|
521
565
|
} else {
|
|
522
|
-
console.error(
|
|
566
|
+
console.error(chalk6.red(`
|
|
523
567
|
Error: ${error.message}
|
|
524
568
|
`));
|
|
525
569
|
}
|
|
526
570
|
} else {
|
|
527
|
-
console.error(
|
|
571
|
+
console.error(
|
|
572
|
+
chalk6.red("\n Connection error. Is plexmint.com reachable?\n")
|
|
573
|
+
);
|
|
528
574
|
}
|
|
529
575
|
process.exit(1);
|
|
530
576
|
}
|
|
531
577
|
}
|
|
532
578
|
|
|
533
|
-
// src/commands/
|
|
534
|
-
import
|
|
535
|
-
import
|
|
536
|
-
import
|
|
537
|
-
function
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
resolve2(answer);
|
|
552
|
-
});
|
|
553
|
-
}
|
|
554
|
-
});
|
|
555
|
-
}
|
|
556
|
-
async function loginCommand(options) {
|
|
557
|
-
console.log("");
|
|
558
|
-
console.log(chalk5.bold(" PlexMint Login"));
|
|
559
|
-
console.log(chalk5.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
560
|
-
console.log("");
|
|
561
|
-
if (options.apiKey) {
|
|
562
|
-
setApiKey(options.apiKey);
|
|
563
|
-
console.log(chalk5.green(" \u2713 API key saved."));
|
|
564
|
-
console.log(chalk5.gray(` Config: ${getConfigPath()}
|
|
565
|
-
`));
|
|
566
|
-
return;
|
|
567
|
-
}
|
|
568
|
-
if (isAuthenticated()) {
|
|
569
|
-
const answer = await prompt(
|
|
570
|
-
chalk5.yellow(" Already logged in. Re-authenticate? (y/N) ")
|
|
579
|
+
// src/commands/wallet.ts
|
|
580
|
+
import chalk7 from "chalk";
|
|
581
|
+
import ora6 from "ora";
|
|
582
|
+
import Table2 from "cli-table3";
|
|
583
|
+
async function walletCommand() {
|
|
584
|
+
requireAuth();
|
|
585
|
+
const spinner = ora6("Loading wallet...").start();
|
|
586
|
+
try {
|
|
587
|
+
const client = new PlexMintClient(getApiKey());
|
|
588
|
+
const result = await client.getWallet();
|
|
589
|
+
spinner.stop();
|
|
590
|
+
const { balance, currency, transactions } = result.data;
|
|
591
|
+
console.log("");
|
|
592
|
+
console.log(chalk7.bold(" Wallet"));
|
|
593
|
+
console.log(chalk7.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
594
|
+
console.log("");
|
|
595
|
+
console.log(
|
|
596
|
+
chalk7.gray(" Balance: ") + mint.bold(formatPrice(balance)) + chalk7.gray(` ${currency}`)
|
|
571
597
|
);
|
|
572
|
-
|
|
573
|
-
|
|
598
|
+
console.log("");
|
|
599
|
+
if (transactions.length === 0) {
|
|
600
|
+
console.log(chalk7.gray(" No recent transactions.\n"));
|
|
574
601
|
return;
|
|
575
602
|
}
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
);
|
|
602
|
-
const key = await prompt(chalk5.white(" API Key: "));
|
|
603
|
-
if (!key) {
|
|
604
|
-
console.log(chalk5.red("\n API key is required.\n"));
|
|
605
|
-
process.exit(1);
|
|
606
|
-
}
|
|
607
|
-
setApiKey(key);
|
|
608
|
-
setUserInfo(user.username || "", email);
|
|
609
|
-
console.log(chalk5.green("\n \u2713 Logged in successfully!"));
|
|
610
|
-
console.log(chalk5.gray(` User: ${user.username || user.email}`));
|
|
611
|
-
console.log(chalk5.gray(` Config: ${getConfigPath()}
|
|
612
|
-
`));
|
|
613
|
-
} else {
|
|
614
|
-
console.log(chalk5.yellow(`
|
|
615
|
-
\u2713 Credentials verified for ${user.email}`));
|
|
616
|
-
console.log(
|
|
617
|
-
chalk5.yellow(
|
|
618
|
-
" No API key found. Generate one at https://plexmint.com/settings"
|
|
619
|
-
)
|
|
620
|
-
);
|
|
621
|
-
console.log(
|
|
622
|
-
chalk5.gray(
|
|
623
|
-
"\n After generating a key, run: " + chalk5.white("plexmint login --api-key <YOUR_KEY>\n")
|
|
624
|
-
)
|
|
625
|
-
);
|
|
626
|
-
setUserInfo(user.username || "", email);
|
|
603
|
+
console.log(chalk7.bold(" Recent Transactions"));
|
|
604
|
+
console.log("");
|
|
605
|
+
const table = new Table2({
|
|
606
|
+
head: [
|
|
607
|
+
mint("Date"),
|
|
608
|
+
mint("Type"),
|
|
609
|
+
mint("Amount"),
|
|
610
|
+
mint("Description")
|
|
611
|
+
],
|
|
612
|
+
style: { head: [], border: ["gray"] },
|
|
613
|
+
colWidths: [14, 12, 12, 40]
|
|
614
|
+
});
|
|
615
|
+
for (const tx of transactions) {
|
|
616
|
+
const amount = parseFloat(tx.amount);
|
|
617
|
+
const isCredit = amount >= 0;
|
|
618
|
+
const date = new Date(tx.createdAt).toLocaleDateString("en-US", {
|
|
619
|
+
month: "short",
|
|
620
|
+
day: "numeric"
|
|
621
|
+
});
|
|
622
|
+
table.push([
|
|
623
|
+
chalk7.gray(date),
|
|
624
|
+
tx.type,
|
|
625
|
+
isCredit ? mint(`+${formatPrice(amount)}`) : chalk7.red(`-${formatPrice(Math.abs(amount))}`),
|
|
626
|
+
tx.description.length > 38 ? tx.description.slice(0, 35) + "..." : tx.description
|
|
627
|
+
]);
|
|
627
628
|
}
|
|
629
|
+
console.log(table.toString());
|
|
630
|
+
console.log("");
|
|
628
631
|
} catch (error) {
|
|
629
632
|
spinner.stop();
|
|
630
633
|
if (error instanceof PlexMintApiError) {
|
|
631
|
-
|
|
632
|
-
console.error(chalk5.red("\n Invalid email or password.\n"));
|
|
633
|
-
} else {
|
|
634
|
-
console.error(chalk5.red(`
|
|
634
|
+
console.error(chalk7.red(`
|
|
635
635
|
Error: ${error.message}
|
|
636
636
|
`));
|
|
637
|
-
}
|
|
638
637
|
} else {
|
|
639
638
|
console.error(
|
|
640
|
-
|
|
639
|
+
chalk7.red("\n Connection error. Is plexmint.com reachable?\n")
|
|
641
640
|
);
|
|
642
641
|
}
|
|
643
642
|
process.exit(1);
|
|
644
643
|
}
|
|
645
644
|
}
|
|
646
|
-
async function logoutCommand() {
|
|
647
|
-
clearAuth();
|
|
648
|
-
console.log(chalk5.green("\n \u2713 Logged out. API key removed.\n"));
|
|
649
|
-
}
|
|
650
645
|
|
|
651
646
|
// src/commands/library.ts
|
|
652
|
-
import
|
|
653
|
-
import
|
|
647
|
+
import chalk8 from "chalk";
|
|
648
|
+
import ora7 from "ora";
|
|
649
|
+
import Table3 from "cli-table3";
|
|
654
650
|
async function libraryCommand() {
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
console.log(chalk6.yellow(" Authentication required to view your library."));
|
|
658
|
-
console.log(
|
|
659
|
-
chalk6.gray(" Run: ") + chalk6.white("plexmint login") + chalk6.gray(" first\n")
|
|
660
|
-
);
|
|
661
|
-
process.exit(1);
|
|
662
|
-
}
|
|
663
|
-
const spinner = ora6("Loading your library...").start();
|
|
651
|
+
requireAuth();
|
|
652
|
+
const spinner = ora7("Loading your library...").start();
|
|
664
653
|
try {
|
|
665
|
-
const client = new PlexMintClient(getApiKey()
|
|
654
|
+
const client = new PlexMintClient(getApiKey());
|
|
655
|
+
const result = await client.getLibrary();
|
|
666
656
|
spinner.stop();
|
|
667
|
-
|
|
668
|
-
console.log(chalk6.bold(" Your Library"));
|
|
669
|
-
console.log(chalk6.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
657
|
+
const { items, total } = result.data;
|
|
670
658
|
console.log("");
|
|
671
659
|
console.log(
|
|
672
|
-
|
|
673
|
-
" View your purchased prompts at: "
|
|
674
|
-
) + chalk6.cyan.underline("https://plexmint.com/library")
|
|
660
|
+
chalk8.bold(" Your Library") + chalk8.gray(` \u2014 ${total} prompt${total !== 1 ? "s" : ""}`)
|
|
675
661
|
);
|
|
676
662
|
console.log("");
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
663
|
+
if (items.length === 0) {
|
|
664
|
+
console.log(chalk8.gray(" No prompts yet. Browse the marketplace:"));
|
|
665
|
+
console.log(chalk8.white(" plexmint browse\n"));
|
|
666
|
+
return;
|
|
667
|
+
}
|
|
668
|
+
const table = new Table3({
|
|
669
|
+
head: [
|
|
670
|
+
mint("Ticker"),
|
|
671
|
+
mint("Title"),
|
|
672
|
+
mint("Category"),
|
|
673
|
+
mint("Version"),
|
|
674
|
+
mint("Purchased")
|
|
675
|
+
],
|
|
676
|
+
style: { head: [], border: ["gray"] },
|
|
677
|
+
colWidths: [14, 32, 14, 10, 14]
|
|
678
|
+
});
|
|
679
|
+
for (const item of items) {
|
|
680
|
+
const date = new Date(item.purchasedAt).toLocaleDateString("en-US", {
|
|
681
|
+
month: "short",
|
|
682
|
+
day: "numeric",
|
|
683
|
+
year: "numeric"
|
|
684
|
+
});
|
|
685
|
+
table.push([
|
|
686
|
+
chalk8.bold(item.ticker),
|
|
687
|
+
item.title.length > 30 ? item.title.slice(0, 27) + "..." : item.title,
|
|
688
|
+
item.category,
|
|
689
|
+
`v${item.version}`,
|
|
690
|
+
chalk8.gray(date)
|
|
691
|
+
]);
|
|
692
|
+
}
|
|
693
|
+
console.log(table.toString());
|
|
694
|
+
console.log("");
|
|
681
695
|
} catch (error) {
|
|
682
696
|
spinner.stop();
|
|
683
697
|
if (error instanceof PlexMintApiError) {
|
|
684
|
-
console.error(
|
|
698
|
+
console.error(chalk8.red(`
|
|
685
699
|
Error: ${error.message}
|
|
686
700
|
`));
|
|
687
701
|
} else {
|
|
688
|
-
console.error(
|
|
702
|
+
console.error(
|
|
703
|
+
chalk8.red("\n Connection error. Is plexmint.com reachable?\n")
|
|
704
|
+
);
|
|
689
705
|
}
|
|
690
706
|
process.exit(1);
|
|
691
707
|
}
|
|
692
708
|
}
|
|
693
709
|
|
|
710
|
+
// src/commands/whoami.ts
|
|
711
|
+
import chalk9 from "chalk";
|
|
712
|
+
function whoamiCommand() {
|
|
713
|
+
if (!isAuthenticated()) {
|
|
714
|
+
console.log(chalk9.yellow("\n Not logged in.\n"));
|
|
715
|
+
console.log(
|
|
716
|
+
chalk9.gray(" Run ") + chalk9.white("plexmint setup") + chalk9.gray(" or ") + chalk9.white("plexmint login") + chalk9.gray(" to authenticate.\n")
|
|
717
|
+
);
|
|
718
|
+
return;
|
|
719
|
+
}
|
|
720
|
+
const config = readConfig();
|
|
721
|
+
console.log("");
|
|
722
|
+
console.log(mint(" \u2713 ") + chalk9.bold("Authenticated"));
|
|
723
|
+
console.log("");
|
|
724
|
+
if (config.name) {
|
|
725
|
+
console.log(chalk9.gray(" Name: ") + chalk9.white(config.name));
|
|
726
|
+
}
|
|
727
|
+
if (config.email) {
|
|
728
|
+
console.log(chalk9.gray(" Email: ") + chalk9.white(config.email));
|
|
729
|
+
}
|
|
730
|
+
if (config.apiKey) {
|
|
731
|
+
const key = config.apiKey;
|
|
732
|
+
const masked = key.length > 16 ? key.slice(0, 8) + "..." + key.slice(-4) : key.slice(0, 4) + "...";
|
|
733
|
+
console.log(chalk9.gray(" API Key: ") + chalk9.white(masked));
|
|
734
|
+
}
|
|
735
|
+
console.log(chalk9.gray(" Config: ") + chalk9.white(getConfigPath()));
|
|
736
|
+
console.log("");
|
|
737
|
+
}
|
|
738
|
+
|
|
694
739
|
// src/index.ts
|
|
695
740
|
var program = new Command();
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
program.
|
|
701
|
-
program.command("
|
|
702
|
-
program.command("
|
|
703
|
-
program.command("
|
|
704
|
-
program.command("
|
|
705
|
-
program.command("login").description("Authenticate with your PlexMint account").option("--api-key <key>", "Set API key directly (skip interactive login)").action(loginCommand);
|
|
706
|
-
program.command("logout").description("Remove stored API key").action(logoutCommand);
|
|
707
|
-
program.command("library").description("View your purchased prompts").action(libraryCommand);
|
|
741
|
+
program.name("plexmint").description("Browse, buy, and manage AI prompts from the PlexMint marketplace").version("0.2.0").addHelpText("before", BANNER);
|
|
742
|
+
program.command("setup").description("Create a PlexMint account (interactive wizard)").action(setupCommand);
|
|
743
|
+
program.command("login").description("Sign in to your PlexMint account").action(loginCommand);
|
|
744
|
+
program.command("browse").description("Browse the PlexMint marketplace").option("-c, --category <category>", "Filter by category").option("-s, --sort <sort>", "Sort order (trending, top_rated, most_sales, newest, price_low, price_high)", "trending").option("--search <query>", "Search by keyword").action(browseCommand);
|
|
745
|
+
program.command("view <ticker>").description("View full details for a prompt by ticker").action(viewCommand);
|
|
746
|
+
program.command("buy <ticker>").description("Purchase a prompt using your wallet balance").action(buyCommand);
|
|
747
|
+
program.command("wallet").description("View your wallet balance and transactions").action(walletCommand);
|
|
748
|
+
program.command("library").description("List your purchased prompts").action(libraryCommand);
|
|
749
|
+
program.command("whoami").description("Show current authenticated user").action(whoamiCommand);
|
|
708
750
|
program.action(() => {
|
|
751
|
+
if (!isAuthenticated()) {
|
|
752
|
+
setupCommand();
|
|
753
|
+
return;
|
|
754
|
+
}
|
|
709
755
|
console.log(BANNER);
|
|
710
|
-
console.log(
|
|
756
|
+
console.log(chalk10.bold(" Commands:"));
|
|
711
757
|
console.log("");
|
|
712
|
-
console.log(
|
|
713
|
-
console.log(
|
|
714
|
-
console.log(
|
|
715
|
-
console.log(
|
|
716
|
-
console.log(
|
|
758
|
+
console.log(chalk10.gray(" Browse marketplace ") + chalk10.white("plexmint browse"));
|
|
759
|
+
console.log(chalk10.gray(" Search prompts ") + chalk10.white('plexmint browse --search "email copywriting"'));
|
|
760
|
+
console.log(chalk10.gray(" View prompt details ") + chalk10.white("plexmint view <TICKER>"));
|
|
761
|
+
console.log(chalk10.gray(" Buy a prompt ") + chalk10.white("plexmint buy <TICKER>"));
|
|
762
|
+
console.log(chalk10.gray(" Your wallet ") + chalk10.white("plexmint wallet"));
|
|
763
|
+
console.log(chalk10.gray(" Your library ") + chalk10.white("plexmint library"));
|
|
764
|
+
console.log(chalk10.gray(" Current user ") + chalk10.white("plexmint whoami"));
|
|
717
765
|
console.log("");
|
|
718
|
-
console.log(
|
|
766
|
+
console.log(chalk10.gray(" Run ") + chalk10.white("plexmint --help") + chalk10.gray(" for all options.\n"));
|
|
719
767
|
});
|
|
720
768
|
program.parse();
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "plexmint",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "PlexMint CLI — Browse,
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "PlexMint CLI — Browse, buy, and manage AI prompts from your terminal",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"plexmint": "./dist/index.js"
|
|
@@ -37,11 +37,12 @@
|
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"chalk": "^5.4.1",
|
|
39
39
|
"commander": "^13.1.0",
|
|
40
|
-
"
|
|
40
|
+
"inquirer": "^12.3.0",
|
|
41
41
|
"ora": "^8.2.0",
|
|
42
42
|
"cli-table3": "^0.6.5"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
|
+
"@types/inquirer": "^9.0.7",
|
|
45
46
|
"tsup": "^8.4.0",
|
|
46
47
|
"tsx": "^4.21.0",
|
|
47
48
|
"typescript": "^5.7.0",
|