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.
Files changed (2) hide show
  1. package/dist/index.js +523 -475
  2. 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 chalk7 from "chalk";
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/commands/search.ts
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 Table from "cli-table3";
75
+ import inquirer from "inquirer";
11
76
 
12
77
  // src/lib/api.ts
13
- var DEFAULT_BASE_URL = "https://plexmint.com/api/v1";
78
+ var BASE_URL = "https://plexmint.com/api/v1";
14
79
  var PlexMintClient = class {
15
- baseUrl;
16
80
  apiKey;
17
- constructor(apiKey = null, baseUrl) {
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.1.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(`${this.baseUrl}${path}`, {
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
- * Browse/search prompts
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("q", options.query);
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?ticker=${encodeURIComponent(ticker.toUpperCase())}`
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({ ticker: ticker.toUpperCase() })
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
- * Authenticate with email/password
99
- */
100
- async authenticate(email, password) {
101
- return this.request("/auth", {
102
- method: "POST",
103
- body: JSON.stringify({ email, password })
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/lib/config.ts
119
- import Conf from "conf";
120
- var config = new Conf({
121
- projectName: "plexmint",
122
- defaults: {
123
- apiKey: null,
124
- baseUrl: "https://plexmint.com/api/v1",
125
- username: null,
126
- email: null
127
- }
128
- });
129
- function getApiKey() {
130
- return config.get("apiKey");
131
- }
132
- function setApiKey(key) {
133
- config.set("apiKey", key);
134
- }
135
- function getBaseUrl() {
136
- return config.get("baseUrl");
137
- }
138
- function setUserInfo(username, email) {
139
- config.set("username", username);
140
- config.set("email", email);
141
- }
142
- function clearAuth() {
143
- config.set("apiKey", null);
144
- config.set("username", null);
145
- config.set("email", null);
146
- }
147
- function isAuthenticated() {
148
- return !!config.get("apiKey");
149
- }
150
- function getConfigPath() {
151
- return config.path;
152
- }
153
-
154
- // src/commands/search.ts
155
- async function searchCommand(query, options) {
156
- const spinner = ora(`Searching for "${query}"...`).start();
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(getApiKey(), getBaseUrl());
159
- const result = await client.browse({
160
- query,
161
- category: options.category,
162
- model: options.model,
163
- sort: options.sort || "trending",
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
- const { items } = result.data;
168
- if (items.length === 0) {
169
- console.log(chalk.yellow(`
170
- No prompts found for "${query}"
278
+ if (error instanceof PlexMintApiError) {
279
+ console.error(chalk2.red(`
280
+ Error: ${error.message}
171
281
  `));
172
- return;
282
+ } else {
283
+ console.error(
284
+ chalk2.red("\n Connection error. Is plexmint.com reachable?\n")
285
+ );
173
286
  }
174
- console.log(
175
- chalk.bold(`
176
- Found ${items.length} prompt${items.length > 1 ? "s" : ""}
177
- `)
178
- );
179
- const table = new Table({
180
- head: [
181
- chalk.cyan("Ticker"),
182
- chalk.cyan("Title"),
183
- chalk.cyan("Price"),
184
- chalk.cyan("Rating"),
185
- chalk.cyan("Sales"),
186
- chalk.cyan("Seller")
187
- ],
188
- style: { head: [], border: ["gray"] },
189
- colWidths: [14, 30, 10, 10, 8, 16]
190
- });
191
- for (const prompt2 of items) {
192
- const price = parseFloat(prompt2.currentPrice);
193
- const rating = parseFloat(prompt2.averageRating);
194
- table.push([
195
- chalk.bold(prompt2.ticker),
196
- prompt2.title.length > 28 ? prompt2.title.slice(0, 25) + "..." : prompt2.title,
197
- chalk.green(`$${price.toFixed(2)}`),
198
- rating > 0 ? chalk.yellow(`\u2605 ${rating.toFixed(1)}`) : chalk.gray("\u2014"),
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
- console.log(table.toString());
204
- if (result.data.hasMore) {
205
- console.log(chalk.gray("\n More results available. Use --limit to see more.\n"));
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
- console.log(
208
- chalk.gray(` Install a prompt: `) + chalk.white(`plexmint install <TICKER>
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
- console.error(chalk.red(`
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(chalk.red(`
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 chalk2 from "chalk";
228
- import ora2 from "ora";
229
- import Table2 from "cli-table3";
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 = ora2("Browsing PlexMint marketplace...").start();
370
+ const spinner = ora3("Browsing PlexMint marketplace...").start();
232
371
  try {
233
- const client = new PlexMintClient(getApiKey(), getBaseUrl());
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: options.limit ? parseInt(options.limit) : 20
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(chalk2.yellow("\n No prompts found.\n"));
382
+ console.log(chalk4.yellow("\n No prompts found.\n"));
244
383
  return;
245
384
  }
246
- const sortLabel = options.sort || "trending";
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
- chalk2.bold(`
249
- PlexMint Marketplace`) + chalk2.gray(` \u2014 sorted by ${sortLabel}
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 Table2({
393
+ const table = new Table({
253
394
  head: [
254
- chalk2.cyan("Ticker"),
255
- chalk2.cyan("Title"),
256
- chalk2.cyan("Category"),
257
- chalk2.cyan("Price"),
258
- chalk2.cyan("Rating"),
259
- chalk2.cyan("Sales")
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, 14, 10, 10, 8]
403
+ colWidths: [14, 30, 10, 10, 8, 16]
263
404
  });
264
- for (const prompt2 of items) {
265
- const price = parseFloat(prompt2.currentPrice);
266
- const rating = parseFloat(prompt2.averageRating);
405
+ for (const prompt of items) {
406
+ const price = parseFloat(prompt.currentPrice);
407
+ const rating = parseFloat(prompt.averageRating);
267
408
  table.push([
268
- chalk2.bold(prompt2.ticker),
269
- prompt2.title.length > 28 ? prompt2.title.slice(0, 25) + "..." : prompt2.title,
270
- prompt2.category,
271
- chalk2.green(`$${price.toFixed(2)}`),
272
- rating > 0 ? chalk2.yellow(`\u2605 ${rating.toFixed(1)}`) : chalk2.gray("\u2014"),
273
- prompt2.salesCount.toString()
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
- chalk2.gray("\n Get details: ") + chalk2.white("plexmint info <TICKER>") + chalk2.gray(" | Install: ") + chalk2.white("plexmint install <TICKER>\n")
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(chalk2.red(`
424
+ console.error(chalk4.red(`
284
425
  Error: ${error.message}
285
426
  `));
286
427
  } else {
287
- console.error(chalk2.red("\n Connection error. Is plexmint.com reachable?\n"));
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/info.ts
294
- import chalk3 from "chalk";
295
- import ora3 from "ora";
296
- async function infoCommand(ticker) {
297
- const spinner = ora3(`Looking up ${ticker.toUpperCase()}...`).start();
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(), getBaseUrl());
300
- const result = await client.getPrompt(ticker);
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(chalk3.bold.white(` ${p.title}`));
307
- console.log(chalk3.gray(` ${p.ticker}`) + chalk3.gray(` \xB7 ${p.category}`));
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(chalk3.white(` ${p.description}`));
455
+ console.log(chalk5.white(` ${p.description}`));
310
456
  console.log("");
311
457
  console.log(
312
- chalk3.green.bold(` $${price.toFixed(2)}`) + chalk3.gray(" \xB7 ") + (rating > 0 ? chalk3.yellow(`\u2605 ${rating.toFixed(1)}`) : chalk3.gray("No ratings")) + chalk3.gray(" \xB7 ") + chalk3.white(`${p.salesCount} sold`) + chalk3.gray(" \xB7 ") + chalk3.white(`${p.reviewCount} reviews`)
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((m) => m.isPrimary ? chalk3.cyan.bold(m.model) : chalk3.gray(m.model)).join(", ");
317
- console.log(chalk3.gray(" Models: ") + modelList);
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
- chalk3.gray(" Tags: ") + p.tags.map((t) => chalk3.gray(`#${t}`)).join(" ")
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
- chalk3.gray(" Seller: ") + chalk3.white(p.seller.name || p.seller.username || "\u2014") + (p.seller.username ? chalk3.gray(` (@${p.seller.username})`) : "")
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(chalk3.gray(` Tokens: ~${p.tokenEstimate}`));
478
+ console.log(chalk5.gray(` Tokens: ~${p.tokenEstimate}`));
331
479
  }
332
480
  console.log("");
333
- console.log(chalk3.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"));
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
- chalk3.gray(" \u2502 ") + chalk3.white("Install:") + chalk3.gray(" \u2502")
483
+ chalk5.gray(" \u2502 ") + chalk5.white("Buy this prompt:") + " ".repeat(25) + chalk5.gray("\u2502")
336
484
  );
337
- const installCmd = `npx plexmint install ${p.ticker}`;
338
- const padding = 39 - installCmd.length;
485
+ const buyCmd = `plexmint buy ${p.ticker}`;
486
+ const padding = 39 - buyCmd.length;
339
487
  console.log(
340
- chalk3.gray(" \u2502 ") + chalk3.cyan.bold(installCmd) + " ".repeat(Math.max(0, padding)) + chalk3.gray("\u2502")
488
+ chalk5.gray(" \u2502 ") + mint.bold(buyCmd) + " ".repeat(Math.max(0, padding)) + chalk5.gray("\u2502")
341
489
  );
342
- console.log(chalk3.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"));
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
- chalk3.gray("\n View on web: ") + chalk3.underline(`https://plexmint.com/prompt/${p.slug}
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
- chalk3.red(`
353
- Prompt not found: ${ticker.toUpperCase()}
500
+ chalk5.red(`
501
+ Prompt not found: ${upperTicker}
354
502
  `)
355
503
  );
356
504
  } else {
357
- console.error(chalk3.red(`
505
+ console.error(chalk5.red(`
358
506
  Error: ${error.message}
359
507
  `));
360
508
  }
361
509
  } else {
362
- console.error(chalk3.red("\n Connection error. Is plexmint.com reachable?\n"));
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/install.ts
369
- import chalk4 from "chalk";
370
- import ora4 from "ora";
371
- import { writeFileSync, mkdirSync, existsSync } from "fs";
372
- import { join, resolve } from "path";
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
- if (!isAuthenticated()) {
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(), getBaseUrl());
388
- let content;
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 data = content.data;
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(chalk4.green.bold(` \u2713 Installed ${data.ticker}`));
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(chalk4.gray(" Files:"));
500
- console.log(chalk4.white(` ${promptFile}`) + chalk4.gray(" \u2014 prompt text"));
501
- console.log(chalk4.white(` ${metaFile}`) + chalk4.gray(" \u2014 metadata"));
502
- if (data.variables && data.variables.length > 0) {
503
- console.log("");
504
- console.log(chalk4.gray(" Variables:"));
505
- for (const v of data.variables) {
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 === 404) {
518
- console.error(chalk4.red(`
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(chalk4.red(`
566
+ console.error(chalk6.red(`
523
567
  Error: ${error.message}
524
568
  `));
525
569
  }
526
570
  } else {
527
- console.error(chalk4.red("\n Connection error. Is plexmint.com reachable?\n"));
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/login.ts
534
- import chalk5 from "chalk";
535
- import ora5 from "ora";
536
- import { createInterface } from "readline";
537
- function prompt(question, hide = false) {
538
- return new Promise((resolve2) => {
539
- const rl = createInterface({
540
- input: process.stdin,
541
- output: process.stdout
542
- });
543
- if (hide) {
544
- rl.question(question, (answer) => {
545
- rl.close();
546
- resolve2(answer);
547
- });
548
- } else {
549
- rl.question(question, (answer) => {
550
- rl.close();
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
- if (answer.toLowerCase() !== "y") {
573
- console.log(chalk5.gray(" Cancelled.\n"));
598
+ console.log("");
599
+ if (transactions.length === 0) {
600
+ console.log(chalk7.gray(" No recent transactions.\n"));
574
601
  return;
575
602
  }
576
- clearAuth();
577
- }
578
- console.log(
579
- chalk5.gray(
580
- " Enter your PlexMint credentials to authenticate.\n Your API key will be stored locally.\n"
581
- )
582
- );
583
- const email = await prompt(chalk5.white(" Email: "));
584
- const password = await prompt(chalk5.white(" Password: "));
585
- if (!email || !password) {
586
- console.log(chalk5.red("\n Email and password are required.\n"));
587
- process.exit(1);
588
- }
589
- const spinner = ora5("Authenticating...").start();
590
- try {
591
- const client = new PlexMintClient(null, getBaseUrl());
592
- const result = await client.authenticate(email, password);
593
- spinner.stop();
594
- const { user, hasApiKey } = result.data;
595
- if (hasApiKey) {
596
- console.log(chalk5.green(`
597
- \u2713 Authenticated as ${user.username || user.email}`));
598
- console.log("");
599
- console.log(
600
- chalk5.white(" Enter your API key") + chalk5.gray(" (from Settings > API Keys):")
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
- if (error.status === 401) {
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
- chalk5.red("\n Connection error. Is plexmint.com reachable?\n")
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 chalk6 from "chalk";
653
- import ora6 from "ora";
647
+ import chalk8 from "chalk";
648
+ import ora7 from "ora";
649
+ import Table3 from "cli-table3";
654
650
  async function libraryCommand() {
655
- if (!isAuthenticated()) {
656
- console.log("");
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(), getBaseUrl());
654
+ const client = new PlexMintClient(getApiKey());
655
+ const result = await client.getLibrary();
666
656
  spinner.stop();
667
- console.log("");
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
- chalk6.gray(
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
- console.log(
678
- chalk6.gray(" To download a purchased prompt locally:")
679
- );
680
- console.log(chalk6.white(" plexmint install <TICKER>\n"));
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(chalk6.red(`
698
+ console.error(chalk8.red(`
685
699
  Error: ${error.message}
686
700
  `));
687
701
  } else {
688
- console.error(chalk6.red("\n Connection error.\n"));
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
- var BANNER = `
697
- ${chalk7.bold.cyan("plex")}${chalk7.bold.green("mint")} ${chalk7.gray("\u2014 AI prompts that evolve")}
698
- ${chalk7.gray("https://plexmint.com")}
699
- `;
700
- program.name("plexmint").description("Browse, install, and manage AI prompts from the PlexMint marketplace").version("0.1.0").addHelpText("before", BANNER);
701
- program.command("search <query>").description("Search for prompts by keyword").option("-c, --category <category>", "Filter by category (business, writing, code, seo, design, education, data, social-media, personal)").option("-m, --model <model>", "Filter by AI model (gpt-4o, claude-opus, claude-sonnet, gemini, midjourney, etc.)").option("-s, --sort <sort>", "Sort order (trending, top_rated, most_sales, newest, price_low, price_high)", "trending").option("-l, --limit <limit>", "Number of results (max 100)", "12").action(searchCommand);
702
- program.command("browse").description("Browse the PlexMint marketplace").option("-c, --category <category>", "Filter by category").option("-m, --model <model>", "Filter by AI model").option("-s, --sort <sort>", "Sort order", "trending").option("-l, --limit <limit>", "Number of results", "20").action(browseCommand);
703
- program.command("info <ticker>").description("Get detailed info about a prompt by its ticker symbol").action(infoCommand);
704
- program.command("install <ticker>").description("Install a prompt locally (downloads to .plexmint/ directory)").option("-d, --dir <directory>", "Install directory (default: .plexmint)").option("-f, --force", "Overwrite if already installed").action(installCommand);
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(chalk7.bold(" Quick Start:"));
756
+ console.log(chalk10.bold(" Commands:"));
711
757
  console.log("");
712
- console.log(chalk7.gray(" Browse marketplace ") + chalk7.white("plexmint browse"));
713
- console.log(chalk7.gray(" Search prompts ") + chalk7.white('plexmint search "email copywriting"'));
714
- console.log(chalk7.gray(" Get prompt details ") + chalk7.white("plexmint info NUE-SEO01"));
715
- console.log(chalk7.gray(" Install a prompt ") + chalk7.white("plexmint install NUE-SEO01"));
716
- console.log(chalk7.gray(" Login to your account ") + chalk7.white("plexmint login"));
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(chalk7.gray(" Run ") + chalk7.white("plexmint --help") + chalk7.gray(" for all commands.\n"));
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.1.0",
4
- "description": "PlexMint CLI — Browse, install, and manage AI prompts from your terminal",
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
- "conf": "^13.1.0",
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",