plexmint 0.1.1 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +522 -494
  2. package/package.json +6 -5
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,31 +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());
55
134
  if (options.offset) params.set("offset", options.offset.toString());
56
135
  const qs = params.toString();
57
136
  return this.request(`/prompts${qs ? `?${qs}` : ""}`);
58
137
  }
59
- /**
60
- * Get a single prompt by ticker
61
- */
62
138
  async getPrompt(ticker) {
63
139
  return this.request(
64
- `/prompts?ticker=${encodeURIComponent(ticker.toUpperCase())}`
140
+ `/prompts/${encodeURIComponent(ticker.toUpperCase())}`
65
141
  );
66
142
  }
67
- /**
68
- * Initiate a purchase (requires API key)
69
- */
143
+ // ─── Commerce ───
70
144
  async purchase(ticker) {
71
145
  if (!this.apiKey) {
72
146
  throw new PlexMintApiError(
@@ -77,13 +151,13 @@ var PlexMintClient = class {
77
151
  }
78
152
  return this.request("/purchase", {
79
153
  method: "POST",
80
- body: JSON.stringify({ ticker: ticker.toUpperCase() })
154
+ body: JSON.stringify({
155
+ ticker: ticker.toUpperCase(),
156
+ payment_method: "wallet"
157
+ })
81
158
  });
82
159
  }
83
- /**
84
- * Get prompt content (requires purchase)
85
- */
86
- async getContent(ticker) {
160
+ async getWallet() {
87
161
  if (!this.apiKey) {
88
162
  throw new PlexMintApiError(
89
163
  "Authentication required. Run: plexmint login",
@@ -91,18 +165,17 @@ var PlexMintClient = class {
91
165
  {}
92
166
  );
93
167
  }
94
- return this.request(
95
- `/library/${encodeURIComponent(ticker.toUpperCase())}/content`
96
- );
168
+ return this.request("/wallet");
97
169
  }
98
- /**
99
- * Authenticate with email/password
100
- */
101
- async authenticate(email, password) {
102
- return this.request("/auth", {
103
- method: "POST",
104
- body: JSON.stringify({ email, password })
105
- });
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");
106
179
  }
107
180
  };
108
181
  var PlexMintApiError = class extends Error {
@@ -116,252 +189,307 @@ var PlexMintApiError = class extends Error {
116
189
  }
117
190
  };
118
191
 
119
- // src/lib/config.ts
120
- import Conf from "conf";
121
- var config = new Conf({
122
- projectName: "plexmint",
123
- defaults: {
124
- apiKey: null,
125
- baseUrl: "https://plexmint.com/api/v1",
126
- username: null,
127
- email: null
128
- }
129
- });
130
- function getApiKey() {
131
- return config.get("apiKey");
132
- }
133
- function setApiKey(key) {
134
- config.set("apiKey", key);
135
- }
136
- function getBaseUrl() {
137
- return config.get("baseUrl");
138
- }
139
- function setUserInfo(username, email) {
140
- config.set("username", username);
141
- config.set("email", email);
142
- }
143
- function clearAuth() {
144
- config.set("apiKey", null);
145
- config.set("username", null);
146
- config.set("email", null);
147
- }
148
- function isAuthenticated() {
149
- return !!config.get("apiKey");
150
- }
151
- function getConfigPath() {
152
- return config.path;
153
- }
154
-
155
- // src/commands/search.ts
156
- async function searchCommand(query, options) {
157
- 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();
158
237
  try {
159
- const client = new PlexMintClient(getApiKey(), getBaseUrl());
160
- const result = await client.browse({
161
- query,
162
- category: options.category,
163
- model: options.model,
164
- sort: options.sort || "trending",
165
- 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()
166
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) {
167
277
  spinner.stop();
168
- const { items } = result.data;
169
- if (items.length === 0) {
170
- console.log(chalk.yellow(`
171
- No prompts found for "${query}"
278
+ if (error instanceof PlexMintApiError) {
279
+ console.error(chalk2.red(`
280
+ Error: ${error.message}
172
281
  `));
173
- return;
282
+ } else {
283
+ console.error(
284
+ chalk2.red("\n Connection error. Is plexmint.com reachable?\n")
285
+ );
174
286
  }
175
- console.log(
176
- chalk.bold(`
177
- Found ${items.length} prompt${items.length > 1 ? "s" : ""}
178
- `)
179
- );
180
- const table = new Table({
181
- head: [
182
- chalk.cyan("Ticker"),
183
- chalk.cyan("Title"),
184
- chalk.cyan("Price"),
185
- chalk.cyan("Rating"),
186
- chalk.cyan("Sales"),
187
- chalk.cyan("Seller")
188
- ],
189
- style: { head: [], border: ["gray"] },
190
- colWidths: [14, 30, 10, 10, 8, 16]
191
- });
192
- for (const prompt2 of items) {
193
- const price = parseFloat(prompt2.currentPrice);
194
- const rating = parseFloat(prompt2.averageRating);
195
- table.push([
196
- chalk.bold(prompt2.ticker),
197
- prompt2.title.length > 28 ? prompt2.title.slice(0, 25) + "..." : prompt2.title,
198
- chalk.green(`$${price.toFixed(2)}`),
199
- rating > 0 ? chalk.yellow(`\u2605 ${rating.toFixed(1)}`) : chalk.gray("\u2014"),
200
- prompt2.salesCount.toString(),
201
- prompt2.seller?.username ? chalk.gray(`@${prompt2.seller.username}`) : chalk.gray("\u2014")
202
- ]);
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;
203
312
  }
204
- console.log(table.toString());
205
- if (result.data.hasMore) {
206
- 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."
207
328
  }
208
- console.log(
209
- chalk.gray(` Install a prompt: `) + chalk.white(`plexmint install <TICKER>
210
- `)
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
211
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("");
212
346
  } catch (error) {
213
347
  spinner.stop();
214
348
  if (error instanceof PlexMintApiError) {
215
- 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(`
216
353
  Error: ${error.message}
217
354
  `));
355
+ }
218
356
  } else {
219
- console.error(chalk.red(`
220
- Connection error. Is plexmint.com reachable?
221
- `));
357
+ console.error(
358
+ chalk3.red("\n Connection error. Is plexmint.com reachable?\n")
359
+ );
222
360
  }
223
361
  process.exit(1);
224
362
  }
225
363
  }
226
364
 
227
365
  // src/commands/browse.ts
228
- import chalk2 from "chalk";
229
- import ora2 from "ora";
230
- import Table2 from "cli-table3";
366
+ import chalk4 from "chalk";
367
+ import ora3 from "ora";
368
+ import Table from "cli-table3";
231
369
  async function browseCommand(options) {
232
- const spinner = ora2("Browsing PlexMint marketplace...").start();
370
+ const spinner = ora3("Browsing PlexMint marketplace...").start();
233
371
  try {
234
- const client = new PlexMintClient(getApiKey(), getBaseUrl());
235
- const limit = options.limit ? parseInt(options.limit) : 20;
236
- const page = options.page ? Math.max(1, parseInt(options.page)) : 1;
237
- const offset = (page - 1) * limit;
372
+ const client = new PlexMintClient(getApiKey());
238
373
  const result = await client.browse({
374
+ query: options.search,
239
375
  category: options.category,
240
- model: options.model,
241
376
  sort: options.sort || "trending",
242
- limit,
243
- offset
377
+ limit: 20
244
378
  });
245
379
  spinner.stop();
246
- const { items, hasMore } = result.data;
380
+ const { items, total } = result.data;
247
381
  if (items.length === 0) {
248
- if (page > 1) {
249
- console.log(chalk2.yellow("\n No more prompts. You've reached the end.\n"));
250
- } else {
251
- console.log(chalk2.yellow("\n No prompts found.\n"));
252
- }
382
+ console.log(chalk4.yellow("\n No prompts found.\n"));
253
383
  return;
254
384
  }
255
- 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}`);
256
389
  console.log(
257
- chalk2.bold(`
258
- PlexMint Marketplace`) + chalk2.gray(` \u2014 sorted by ${sortLabel}`) + chalk2.gray(` \u2014 page ${page}
259
- `)
390
+ chalk4.bold(`
391
+ PlexMint Marketplace`) + chalk4.gray(` \u2014 ${total} prompt${total !== 1 ? "s" : ""}`) + (filters.length > 0 ? chalk4.gray(` (${filters.join(", ")})`) : "") + "\n"
260
392
  );
261
- const table = new Table2({
393
+ const table = new Table({
262
394
  head: [
263
- chalk2.cyan("Ticker"),
264
- chalk2.cyan("Title"),
265
- chalk2.cyan("Category"),
266
- chalk2.cyan("Price"),
267
- chalk2.cyan("Rating"),
268
- chalk2.cyan("Sales")
395
+ mint("Ticker"),
396
+ mint("Title"),
397
+ mint("Price"),
398
+ mint("Rating"),
399
+ mint("Sales"),
400
+ mint("Seller")
269
401
  ],
270
402
  style: { head: [], border: ["gray"] },
271
- colWidths: [14, 30, 14, 10, 10, 8]
403
+ colWidths: [14, 30, 10, 10, 8, 16]
272
404
  });
273
- for (const prompt2 of items) {
274
- const price = parseFloat(prompt2.currentPrice);
275
- const rating = parseFloat(prompt2.averageRating);
405
+ for (const prompt of items) {
406
+ const price = parseFloat(prompt.currentPrice);
407
+ const rating = parseFloat(prompt.averageRating);
276
408
  table.push([
277
- chalk2.bold(prompt2.ticker),
278
- prompt2.title.length > 28 ? prompt2.title.slice(0, 25) + "..." : prompt2.title,
279
- prompt2.category,
280
- chalk2.green(`$${price.toFixed(2)}`),
281
- rating > 0 ? chalk2.yellow(`\u2605 ${rating.toFixed(1)}`) : chalk2.gray("\u2014"),
282
- 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")
283
415
  ]);
284
416
  }
285
417
  console.log(table.toString());
286
- const footer = [];
287
- if (page > 1) {
288
- footer.push(chalk2.gray(" \u25C0 Previous: ") + chalk2.white(`plexmint browse --page ${page - 1}`));
289
- }
290
- if (hasMore) {
291
- footer.push(chalk2.gray(" \u25B6 Next: ") + chalk2.white(`plexmint browse --page ${page + 1}`));
292
- }
293
- if (footer.length > 0) {
294
- console.log("");
295
- footer.forEach((f) => console.log(f));
296
- }
297
418
  console.log(
298
- 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")
299
420
  );
300
421
  } catch (error) {
301
422
  spinner.stop();
302
423
  if (error instanceof PlexMintApiError) {
303
- console.error(chalk2.red(`
424
+ console.error(chalk4.red(`
304
425
  Error: ${error.message}
305
426
  `));
306
427
  } else {
307
- 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
+ );
308
431
  }
309
432
  process.exit(1);
310
433
  }
311
434
  }
312
435
 
313
- // src/commands/info.ts
314
- import chalk3 from "chalk";
315
- import ora3 from "ora";
316
- async function infoCommand(ticker) {
317
- 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();
318
442
  try {
319
- const client = new PlexMintClient(getApiKey(), getBaseUrl());
320
- const result = await client.getPrompt(ticker);
443
+ const client = new PlexMintClient(getApiKey());
444
+ const result = await client.getPrompt(upperTicker);
321
445
  spinner.stop();
322
446
  const p = result.data;
323
447
  const price = parseFloat(p.currentPrice);
324
448
  const rating = parseFloat(p.averageRating);
325
449
  console.log("");
326
- console.log(chalk3.bold.white(` ${p.title}`));
327
- 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
+ );
328
454
  console.log("");
329
- console.log(chalk3.white(` ${p.description}`));
455
+ console.log(chalk5.white(` ${p.description}`));
330
456
  console.log("");
331
457
  console.log(
332
- 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`)
333
459
  );
334
460
  console.log("");
335
461
  if (p.models.length > 0) {
336
- const modelList = p.models.map((m) => m.isPrimary ? chalk3.cyan.bold(m.model) : chalk3.gray(m.model)).join(", ");
337
- 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);
338
466
  }
339
467
  if (p.tags && p.tags.length > 0) {
340
468
  console.log(
341
- chalk3.gray(" Tags: ") + p.tags.map((t) => chalk3.gray(`#${t}`)).join(" ")
469
+ chalk5.gray(" Tags: ") + p.tags.map((t) => chalk5.gray(`#${t}`)).join(" ")
342
470
  );
343
471
  }
344
472
  if (p.seller) {
345
473
  console.log(
346
- 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})`) : "")
347
475
  );
348
476
  }
349
477
  if (p.tokenEstimate) {
350
- console.log(chalk3.gray(` Tokens: ~${p.tokenEstimate}`));
478
+ console.log(chalk5.gray(` Tokens: ~${p.tokenEstimate}`));
351
479
  }
352
480
  console.log("");
353
- 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"));
354
482
  console.log(
355
- chalk3.gray(" \u2502 ") + chalk3.white("Install:") + chalk3.gray(" \u2502")
483
+ chalk5.gray(" \u2502 ") + chalk5.white("Buy this prompt:") + " ".repeat(25) + chalk5.gray("\u2502")
356
484
  );
357
- const installCmd = `npx plexmint install ${p.ticker}`;
358
- const padding = 39 - installCmd.length;
485
+ const buyCmd = `plexmint buy ${p.ticker}`;
486
+ const padding = 39 - buyCmd.length;
359
487
  console.log(
360
- 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")
361
489
  );
362
- 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"));
363
491
  console.log(
364
- 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}
365
493
  `)
366
494
  );
367
495
  } catch (error) {
@@ -369,372 +497,272 @@ async function infoCommand(ticker) {
369
497
  if (error instanceof PlexMintApiError) {
370
498
  if (error.status === 404) {
371
499
  console.error(
372
- chalk3.red(`
373
- Prompt not found: ${ticker.toUpperCase()}
500
+ chalk5.red(`
501
+ Prompt not found: ${upperTicker}
374
502
  `)
375
503
  );
376
504
  } else {
377
- console.error(chalk3.red(`
505
+ console.error(chalk5.red(`
378
506
  Error: ${error.message}
379
507
  `));
380
508
  }
381
509
  } else {
382
- 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
+ );
383
513
  }
384
514
  process.exit(1);
385
515
  }
386
516
  }
387
517
 
388
- // src/commands/install.ts
389
- import chalk4 from "chalk";
390
- import ora4 from "ora";
391
- import { writeFileSync, mkdirSync, existsSync } from "fs";
392
- import { join, resolve } from "path";
393
- 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();
394
523
  const upperTicker = ticker.toUpperCase();
395
- if (!isAuthenticated()) {
396
- console.log("");
397
- console.log(
398
- chalk4.yellow(" Authentication required to install prompts.")
399
- );
400
- console.log(
401
- chalk4.gray(" Run: ") + chalk4.white("plexmint login") + chalk4.gray(" first\n")
402
- );
403
- process.exit(1);
404
- }
405
- const spinner = ora4(`Looking up ${upperTicker}...`).start();
524
+ const spinner = ora5(`Purchasing ${upperTicker}...`).start();
406
525
  try {
407
- const client = new PlexMintClient(getApiKey(), getBaseUrl());
408
- let content;
409
- try {
410
- content = await client.getContent(upperTicker);
411
- spinner.text = `Downloading ${upperTicker}...`;
412
- } catch (error) {
413
- if (error instanceof PlexMintApiError && error.status === 403) {
414
- spinner.stop();
415
- const info = await client.getPrompt(upperTicker);
416
- const p = info.data;
417
- const price = parseFloat(p.currentPrice);
418
- console.log("");
419
- console.log(
420
- chalk4.yellow(` You haven't purchased ${upperTicker} yet.`)
421
- );
422
- console.log("");
423
- console.log(
424
- chalk4.white(` ${p.title}`) + chalk4.gray(` by ${p.seller?.username || "unknown"}`)
425
- );
426
- console.log(chalk4.green.bold(` $${price.toFixed(2)}`));
427
- console.log("");
428
- const purchaseSpinner = ora4("Locking price...").start();
429
- try {
430
- const purchase = await client.purchase(upperTicker);
431
- purchaseSpinner.stop();
432
- console.log(
433
- chalk4.green(` Price locked at $${purchase.data.lockedPrice} for ${purchase.data.lockDurationSeconds}s`)
434
- );
435
- console.log("");
436
- console.log(
437
- chalk4.white(" Complete your purchase here:")
438
- );
439
- console.log(
440
- chalk4.cyan.underline(` ${purchase.data.checkoutUrl}`)
441
- );
442
- console.log("");
443
- console.log(
444
- chalk4.gray(
445
- " After purchasing, run this command again to download.\n"
446
- )
447
- );
448
- } catch (purchaseError) {
449
- purchaseSpinner.stop();
450
- if (purchaseError instanceof PlexMintApiError) {
451
- if (purchaseError.status === 409) {
452
- console.log(
453
- chalk4.yellow(" You already own this prompt. Retrying download...\n")
454
- );
455
- content = await client.getContent(upperTicker);
456
- } else {
457
- console.error(chalk4.red(`
458
- Purchase error: ${purchaseError.message}
459
- `));
460
- process.exit(1);
461
- }
462
- } else {
463
- throw purchaseError;
464
- }
465
- }
466
- if (!content) return;
467
- } else {
468
- throw error;
469
- }
470
- }
526
+ const client = new PlexMintClient(getApiKey());
527
+ const result = await client.purchase(upperTicker);
471
528
  spinner.stop();
472
- const data = content.data;
473
- const installDir = resolve(options.dir || ".plexmint");
474
- if (!existsSync(installDir)) {
475
- mkdirSync(installDir, { recursive: true });
476
- }
477
- const promptDir = join(installDir, data.ticker.toLowerCase());
478
- if (!existsSync(promptDir)) {
479
- mkdirSync(promptDir, { recursive: true });
480
- }
481
- const promptFile = join(promptDir, "prompt.md");
482
- if (existsSync(promptFile) && !options.force) {
483
- console.log(
484
- chalk4.yellow(
485
- `
486
- ${upperTicker} is already installed. Use --force to overwrite.
487
- `
488
- )
489
- );
490
- return;
491
- }
492
- writeFileSync(promptFile, data.promptText, "utf-8");
493
- const metaFile = join(promptDir, "plexmint.json");
494
- writeFileSync(
495
- metaFile,
496
- JSON.stringify(
497
- {
498
- ticker: data.ticker,
499
- title: data.title,
500
- version: data.version,
501
- variables: data.variables,
502
- tips: data.tips,
503
- models: data.models,
504
- tokenEstimate: data.tokenEstimate,
505
- costPerCall: data.costPerCall,
506
- exampleInput: data.exampleInput,
507
- exampleOutput: data.exampleOutput,
508
- installedAt: (/* @__PURE__ */ new Date()).toISOString()
509
- },
510
- null,
511
- 2
512
- ),
513
- "utf-8"
514
- );
529
+ const { ticker: t, title, pricePaid, walletBalance } = result.data;
515
530
  console.log("");
516
- console.log(chalk4.green.bold(` \u2713 Installed ${data.ticker}`));
517
- console.log(chalk4.gray(` ${data.title} v${data.version}`));
531
+ console.log(mint(" \u2713 ") + chalk6.bold("Purchase complete!"));
518
532
  console.log("");
519
- console.log(chalk4.gray(" Files:"));
520
- console.log(chalk4.white(` ${promptFile}`) + chalk4.gray(" \u2014 prompt text"));
521
- console.log(chalk4.white(` ${metaFile}`) + chalk4.gray(" \u2014 metadata"));
522
- if (data.variables && data.variables.length > 0) {
523
- console.log("");
524
- console.log(chalk4.gray(" Variables:"));
525
- for (const v of data.variables) {
526
- console.log(chalk4.cyan(` {{${v}}}`));
527
- }
528
- }
529
- if (data.tips) {
530
- console.log("");
531
- console.log(chalk4.gray(" Tips: ") + chalk4.white(data.tips));
532
- }
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
+ );
533
540
  console.log("");
534
541
  } catch (error) {
535
542
  spinner.stop();
536
543
  if (error instanceof PlexMintApiError) {
537
- if (error.status === 404) {
538
- 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(`
539
562
  Prompt not found: ${upperTicker}
540
- `));
563
+ `)
564
+ );
541
565
  } else {
542
- console.error(chalk4.red(`
566
+ console.error(chalk6.red(`
543
567
  Error: ${error.message}
544
568
  `));
545
569
  }
546
570
  } else {
547
- 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
+ );
548
574
  }
549
575
  process.exit(1);
550
576
  }
551
577
  }
552
578
 
553
- // src/commands/login.ts
554
- import chalk5 from "chalk";
555
- import ora5 from "ora";
556
- import { createInterface } from "readline";
557
- function prompt(question, hide = false) {
558
- return new Promise((resolve2) => {
559
- const rl = createInterface({
560
- input: process.stdin,
561
- output: process.stdout
562
- });
563
- if (hide) {
564
- rl.question(question, (answer) => {
565
- rl.close();
566
- resolve2(answer);
567
- });
568
- } else {
569
- rl.question(question, (answer) => {
570
- rl.close();
571
- resolve2(answer);
572
- });
573
- }
574
- });
575
- }
576
- async function loginCommand(options) {
577
- console.log("");
578
- console.log(chalk5.bold(" PlexMint Login"));
579
- 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"));
580
- console.log("");
581
- if (options.apiKey) {
582
- setApiKey(options.apiKey);
583
- console.log(chalk5.green(" \u2713 API key saved."));
584
- console.log(chalk5.gray(` Config: ${getConfigPath()}
585
- `));
586
- return;
587
- }
588
- if (isAuthenticated()) {
589
- const answer = await prompt(
590
- 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}`)
591
597
  );
592
- if (answer.toLowerCase() !== "y") {
593
- console.log(chalk5.gray(" Cancelled.\n"));
598
+ console.log("");
599
+ if (transactions.length === 0) {
600
+ console.log(chalk7.gray(" No recent transactions.\n"));
594
601
  return;
595
602
  }
596
- clearAuth();
597
- }
598
- console.log(
599
- chalk5.gray(
600
- " Enter your PlexMint credentials to authenticate.\n Your API key will be stored locally.\n"
601
- )
602
- );
603
- const email = await prompt(chalk5.white(" Email: "));
604
- const password = await prompt(chalk5.white(" Password: "));
605
- if (!email || !password) {
606
- console.log(chalk5.red("\n Email and password are required.\n"));
607
- process.exit(1);
608
- }
609
- const spinner = ora5("Authenticating...").start();
610
- try {
611
- const client = new PlexMintClient(null, getBaseUrl());
612
- const result = await client.authenticate(email, password);
613
- spinner.stop();
614
- const { user, hasApiKey } = result.data;
615
- if (hasApiKey) {
616
- console.log(chalk5.green(`
617
- \u2713 Authenticated as ${user.username || user.email}`));
618
- console.log("");
619
- console.log(
620
- chalk5.white(" Enter your API key") + chalk5.gray(" (from Settings > API Keys):")
621
- );
622
- const key = await prompt(chalk5.white(" API Key: "));
623
- if (!key) {
624
- console.log(chalk5.red("\n API key is required.\n"));
625
- process.exit(1);
626
- }
627
- setApiKey(key);
628
- setUserInfo(user.username || "", email);
629
- console.log(chalk5.green("\n \u2713 Logged in successfully!"));
630
- console.log(chalk5.gray(` User: ${user.username || user.email}`));
631
- console.log(chalk5.gray(` Config: ${getConfigPath()}
632
- `));
633
- } else {
634
- console.log(chalk5.yellow(`
635
- \u2713 Credentials verified for ${user.email}`));
636
- console.log(
637
- chalk5.yellow(
638
- " No API key found. Generate one at https://plexmint.com/settings"
639
- )
640
- );
641
- console.log(
642
- chalk5.gray(
643
- "\n After generating a key, run: " + chalk5.white("plexmint login --api-key <YOUR_KEY>\n")
644
- )
645
- );
646
- 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
+ ]);
647
628
  }
629
+ console.log(table.toString());
630
+ console.log("");
648
631
  } catch (error) {
649
632
  spinner.stop();
650
633
  if (error instanceof PlexMintApiError) {
651
- if (error.status === 401) {
652
- console.error(chalk5.red("\n Invalid email or password.\n"));
653
- } else {
654
- console.error(chalk5.red(`
634
+ console.error(chalk7.red(`
655
635
  Error: ${error.message}
656
636
  `));
657
- }
658
637
  } else {
659
638
  console.error(
660
- chalk5.red("\n Connection error. Is plexmint.com reachable?\n")
639
+ chalk7.red("\n Connection error. Is plexmint.com reachable?\n")
661
640
  );
662
641
  }
663
642
  process.exit(1);
664
643
  }
665
644
  }
666
- async function logoutCommand() {
667
- clearAuth();
668
- console.log(chalk5.green("\n \u2713 Logged out. API key removed.\n"));
669
- }
670
645
 
671
646
  // src/commands/library.ts
672
- import chalk6 from "chalk";
673
- import ora6 from "ora";
647
+ import chalk8 from "chalk";
648
+ import ora7 from "ora";
649
+ import Table3 from "cli-table3";
674
650
  async function libraryCommand() {
675
- if (!isAuthenticated()) {
676
- console.log("");
677
- console.log(chalk6.yellow(" Authentication required to view your library."));
678
- console.log(
679
- chalk6.gray(" Run: ") + chalk6.white("plexmint login") + chalk6.gray(" first\n")
680
- );
681
- process.exit(1);
682
- }
683
- const spinner = ora6("Loading your library...").start();
651
+ requireAuth();
652
+ const spinner = ora7("Loading your library...").start();
684
653
  try {
685
- const client = new PlexMintClient(getApiKey(), getBaseUrl());
654
+ const client = new PlexMintClient(getApiKey());
655
+ const result = await client.getLibrary();
686
656
  spinner.stop();
687
- console.log("");
688
- console.log(chalk6.bold(" Your Library"));
689
- 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;
690
658
  console.log("");
691
659
  console.log(
692
- chalk6.gray(
693
- " View your purchased prompts at: "
694
- ) + chalk6.cyan.underline("https://plexmint.com/library")
660
+ chalk8.bold(" Your Library") + chalk8.gray(` \u2014 ${total} prompt${total !== 1 ? "s" : ""}`)
695
661
  );
696
662
  console.log("");
697
- console.log(
698
- chalk6.gray(" To download a purchased prompt locally:")
699
- );
700
- 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("");
701
695
  } catch (error) {
702
696
  spinner.stop();
703
697
  if (error instanceof PlexMintApiError) {
704
- console.error(chalk6.red(`
698
+ console.error(chalk8.red(`
705
699
  Error: ${error.message}
706
700
  `));
707
701
  } else {
708
- console.error(chalk6.red("\n Connection error.\n"));
702
+ console.error(
703
+ chalk8.red("\n Connection error. Is plexmint.com reachable?\n")
704
+ );
709
705
  }
710
706
  process.exit(1);
711
707
  }
712
708
  }
713
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
+
714
739
  // src/index.ts
715
740
  var program = new Command();
716
- var BANNER = `
717
- ${chalk7.bold.cyan("plex")}${chalk7.bold.green("mint")} ${chalk7.gray("\u2014 AI prompts that evolve")}
718
- ${chalk7.gray("https://plexmint.com")}
719
- `;
720
- program.name("plexmint").description("Browse, install, and manage AI prompts from the PlexMint marketplace").version("0.1.0").addHelpText("before", BANNER);
721
- 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").option("-p, --page <page>", "Page number", "1").action(searchCommand);
722
- 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").option("-p, --page <page>", "Page number", "1").action(browseCommand);
723
- program.command("info <ticker>").description("Get detailed info about a prompt by its ticker symbol").action(infoCommand);
724
- 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);
725
- program.command("login").description("Authenticate with your PlexMint account").option("--api-key <key>", "Set API key directly (skip interactive login)").action(loginCommand);
726
- program.command("logout").description("Remove stored API key").action(logoutCommand);
727
- 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);
728
750
  program.action(() => {
751
+ if (!isAuthenticated()) {
752
+ setupCommand();
753
+ return;
754
+ }
729
755
  console.log(BANNER);
730
- console.log(chalk7.bold(" Quick Start:"));
756
+ console.log(chalk10.bold(" Commands:"));
731
757
  console.log("");
732
- console.log(chalk7.gray(" Browse marketplace ") + chalk7.white("plexmint browse"));
733
- console.log(chalk7.gray(" Search prompts ") + chalk7.white('plexmint search "email copywriting"'));
734
- console.log(chalk7.gray(" Get prompt details ") + chalk7.white("plexmint info NUE-SEO01"));
735
- console.log(chalk7.gray(" Install a prompt ") + chalk7.white("plexmint install NUE-SEO01"));
736
- 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"));
737
765
  console.log("");
738
- 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"));
739
767
  });
740
768
  program.parse();
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "plexmint",
3
- "version": "0.1.1",
4
- "description": "PlexMint CLI — Browse, install, and manage AI prompts from your terminal",
3
+ "version": "0.2.1",
4
+ "description": "PlexMint CLI — Browse, buy, and manage AI prompts from your terminal",
5
5
  "type": "module",
6
6
  "bin": {
7
- "plexmint": "./dist/index.js"
7
+ "plexmint": "dist/index.js"
8
8
  },
9
9
  "files": [
10
10
  "dist"
@@ -27,7 +27,7 @@
27
27
  "license": "MIT",
28
28
  "repository": {
29
29
  "type": "git",
30
- "url": "https://github.com/nuesion/plexmint.git",
30
+ "url": "git+https://github.com/nuesion/plexmint.git",
31
31
  "directory": "packages/cli"
32
32
  },
33
33
  "homepage": "https://plexmint.com",
@@ -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",