plexmint 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,73 @@
1
+ # PlexMint CLI
2
+
3
+ Browse, install, and manage AI prompts from the [PlexMint](https://plexmint.com) marketplace — right from your terminal.
4
+
5
+ ## Quick Start
6
+
7
+ ```bash
8
+ # Browse the marketplace
9
+ npx plexmint browse
10
+
11
+ # Search for prompts
12
+ npx plexmint search "email copywriting"
13
+
14
+ # Get details on a specific prompt
15
+ npx plexmint info NUE-SEO01
16
+
17
+ # Install a prompt locally
18
+ npx plexmint install NUE-SEO01
19
+ ```
20
+
21
+ ## Installation
22
+
23
+ ```bash
24
+ # Run directly with npx (no install needed)
25
+ npx plexmint browse
26
+
27
+ # Or install globally
28
+ npm install -g plexmint
29
+ ```
30
+
31
+ ## Commands
32
+
33
+ | Command | Description |
34
+ |---------|-------------|
35
+ | `plexmint browse` | Browse the marketplace with filters |
36
+ | `plexmint search <query>` | Search prompts by keyword |
37
+ | `plexmint info <ticker>` | Get detailed prompt info |
38
+ | `plexmint install <ticker>` | Download prompt to `.plexmint/` |
39
+ | `plexmint login` | Authenticate with your account |
40
+ | `plexmint logout` | Remove stored credentials |
41
+ | `plexmint library` | View your purchased prompts |
42
+
43
+ ## Options
44
+
45
+ ### Search & Browse
46
+ - `--category` — Filter: business, writing, code, seo, design, education, data, social-media, personal
47
+ - `--model` — Filter: gpt-4o, gpt-5, claude-opus, claude-sonnet, gemini, midjourney, dall-e, etc.
48
+ - `--sort` — Sort: trending, top_rated, most_sales, newest, price_low, price_high
49
+ - `--limit` — Results per page (max 100)
50
+
51
+ ### Install
52
+ - `--dir` — Custom install directory (default: `.plexmint/`)
53
+ - `--force` — Overwrite existing installation
54
+
55
+ ### Login
56
+ - `--api-key` — Set API key directly without interactive prompt
57
+
58
+ ## What is PlexMint?
59
+
60
+ PlexMint is the AI prompt marketplace where **quality drives price**. Living Prompts start at $1.99 — reviews, demand, and reputation push the price up. Every prompt gets a stock-style ticker symbol (like NUE-SEO01) and a dynamic price that reflects real quality.
61
+
62
+ - **For developers**: Install prompts into your agent workflows via CLI
63
+ - **For AI agents**: Use the API to browse, purchase, and retrieve prompts programmatically
64
+ - **For sellers**: List your prompts and let the market determine their value
65
+
66
+ ## API
67
+
68
+ The CLI uses the PlexMint Agent API v1. Full OpenAPI spec available at:
69
+ https://plexmint.com/api/v1/openapi.json
70
+
71
+ ## License
72
+
73
+ MIT
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
package/dist/index.js ADDED
@@ -0,0 +1,720 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/index.ts
4
+ import { Command } from "commander";
5
+ import chalk7 from "chalk";
6
+
7
+ // src/commands/search.ts
8
+ import chalk from "chalk";
9
+ import ora from "ora";
10
+ import Table from "cli-table3";
11
+
12
+ // src/lib/api.ts
13
+ var DEFAULT_BASE_URL = "https://plexmint.com/api/v1";
14
+ var PlexMintClient = class {
15
+ baseUrl;
16
+ apiKey;
17
+ constructor(apiKey = null, baseUrl) {
18
+ this.apiKey = apiKey;
19
+ this.baseUrl = baseUrl || DEFAULT_BASE_URL;
20
+ }
21
+ async request(path, options = {}) {
22
+ const headers = {
23
+ "Content-Type": "application/json",
24
+ "User-Agent": "plexmint-cli/0.1.0",
25
+ ...options.headers
26
+ };
27
+ if (this.apiKey) {
28
+ headers["Authorization"] = `Bearer ${this.apiKey}`;
29
+ }
30
+ const res = await fetch(`${this.baseUrl}${path}`, {
31
+ ...options,
32
+ headers
33
+ });
34
+ const json = await res.json();
35
+ if (!res.ok || !json.success) {
36
+ const error = json;
37
+ throw new PlexMintApiError(
38
+ error.error || `Request failed with status ${res.status}`,
39
+ res.status,
40
+ json
41
+ );
42
+ }
43
+ return json;
44
+ }
45
+ /**
46
+ * Browse/search prompts
47
+ */
48
+ async browse(options = {}) {
49
+ const params = new URLSearchParams();
50
+ if (options.query) params.set("q", options.query);
51
+ if (options.category) params.set("category", options.category);
52
+ if (options.model) params.set("model", options.model);
53
+ if (options.sort) params.set("sort", options.sort);
54
+ if (options.limit) params.set("limit", options.limit.toString());
55
+ const qs = params.toString();
56
+ return this.request(`/prompts${qs ? `?${qs}` : ""}`);
57
+ }
58
+ /**
59
+ * Get a single prompt by ticker
60
+ */
61
+ async getPrompt(ticker) {
62
+ return this.request(
63
+ `/prompts?ticker=${encodeURIComponent(ticker.toUpperCase())}`
64
+ );
65
+ }
66
+ /**
67
+ * Initiate a purchase (requires API key)
68
+ */
69
+ async purchase(ticker) {
70
+ if (!this.apiKey) {
71
+ throw new PlexMintApiError(
72
+ "Authentication required. Run: plexmint login",
73
+ 401,
74
+ {}
75
+ );
76
+ }
77
+ return this.request("/purchase", {
78
+ method: "POST",
79
+ body: JSON.stringify({ ticker: ticker.toUpperCase() })
80
+ });
81
+ }
82
+ /**
83
+ * Get prompt content (requires purchase)
84
+ */
85
+ async getContent(ticker) {
86
+ if (!this.apiKey) {
87
+ throw new PlexMintApiError(
88
+ "Authentication required. Run: plexmint login",
89
+ 401,
90
+ {}
91
+ );
92
+ }
93
+ return this.request(
94
+ `/library/${encodeURIComponent(ticker.toUpperCase())}/content`
95
+ );
96
+ }
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
+ });
105
+ }
106
+ };
107
+ var PlexMintApiError = class extends Error {
108
+ status;
109
+ body;
110
+ constructor(message, status, body) {
111
+ super(message);
112
+ this.name = "PlexMintApiError";
113
+ this.status = status;
114
+ this.body = body;
115
+ }
116
+ };
117
+
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();
157
+ 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
165
+ });
166
+ spinner.stop();
167
+ const { items } = result.data;
168
+ if (items.length === 0) {
169
+ console.log(chalk.yellow(`
170
+ No prompts found for "${query}"
171
+ `));
172
+ return;
173
+ }
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
+ ]);
202
+ }
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"));
206
+ }
207
+ console.log(
208
+ chalk.gray(` Install a prompt: `) + chalk.white(`plexmint install <TICKER>
209
+ `)
210
+ );
211
+ } catch (error) {
212
+ spinner.stop();
213
+ if (error instanceof PlexMintApiError) {
214
+ console.error(chalk.red(`
215
+ Error: ${error.message}
216
+ `));
217
+ } else {
218
+ console.error(chalk.red(`
219
+ Connection error. Is plexmint.com reachable?
220
+ `));
221
+ }
222
+ process.exit(1);
223
+ }
224
+ }
225
+
226
+ // src/commands/browse.ts
227
+ import chalk2 from "chalk";
228
+ import ora2 from "ora";
229
+ import Table2 from "cli-table3";
230
+ async function browseCommand(options) {
231
+ const spinner = ora2("Browsing PlexMint marketplace...").start();
232
+ try {
233
+ const client = new PlexMintClient(getApiKey(), getBaseUrl());
234
+ const result = await client.browse({
235
+ category: options.category,
236
+ model: options.model,
237
+ sort: options.sort || "trending",
238
+ limit: options.limit ? parseInt(options.limit) : 20
239
+ });
240
+ spinner.stop();
241
+ const { items } = result.data;
242
+ if (items.length === 0) {
243
+ console.log(chalk2.yellow("\n No prompts found.\n"));
244
+ return;
245
+ }
246
+ const sortLabel = options.sort || "trending";
247
+ console.log(
248
+ chalk2.bold(`
249
+ PlexMint Marketplace`) + chalk2.gray(` \u2014 sorted by ${sortLabel}
250
+ `)
251
+ );
252
+ const table = new Table2({
253
+ 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")
260
+ ],
261
+ style: { head: [], border: ["gray"] },
262
+ colWidths: [14, 30, 14, 10, 10, 8]
263
+ });
264
+ for (const prompt2 of items) {
265
+ const price = parseFloat(prompt2.currentPrice);
266
+ const rating = parseFloat(prompt2.averageRating);
267
+ 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()
274
+ ]);
275
+ }
276
+ console.log(table.toString());
277
+ console.log(
278
+ chalk2.gray("\n Get details: ") + chalk2.white("plexmint info <TICKER>") + chalk2.gray(" | Install: ") + chalk2.white("plexmint install <TICKER>\n")
279
+ );
280
+ } catch (error) {
281
+ spinner.stop();
282
+ if (error instanceof PlexMintApiError) {
283
+ console.error(chalk2.red(`
284
+ Error: ${error.message}
285
+ `));
286
+ } else {
287
+ console.error(chalk2.red("\n Connection error. Is plexmint.com reachable?\n"));
288
+ }
289
+ process.exit(1);
290
+ }
291
+ }
292
+
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();
298
+ try {
299
+ const client = new PlexMintClient(getApiKey(), getBaseUrl());
300
+ const result = await client.getPrompt(ticker);
301
+ spinner.stop();
302
+ const p = result.data;
303
+ const price = parseFloat(p.currentPrice);
304
+ const rating = parseFloat(p.averageRating);
305
+ console.log("");
306
+ console.log(chalk3.bold.white(` ${p.title}`));
307
+ console.log(chalk3.gray(` ${p.ticker}`) + chalk3.gray(` \xB7 ${p.category}`));
308
+ console.log("");
309
+ console.log(chalk3.white(` ${p.description}`));
310
+ console.log("");
311
+ 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`)
313
+ );
314
+ console.log("");
315
+ 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);
318
+ }
319
+ if (p.tags && p.tags.length > 0) {
320
+ console.log(
321
+ chalk3.gray(" Tags: ") + p.tags.map((t) => chalk3.gray(`#${t}`)).join(" ")
322
+ );
323
+ }
324
+ if (p.seller) {
325
+ console.log(
326
+ chalk3.gray(" Seller: ") + chalk3.white(p.seller.name || p.seller.username || "\u2014") + (p.seller.username ? chalk3.gray(` (@${p.seller.username})`) : "")
327
+ );
328
+ }
329
+ if (p.tokenEstimate) {
330
+ console.log(chalk3.gray(` Tokens: ~${p.tokenEstimate}`));
331
+ }
332
+ 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"));
334
+ console.log(
335
+ chalk3.gray(" \u2502 ") + chalk3.white("Install:") + chalk3.gray(" \u2502")
336
+ );
337
+ const installCmd = `npx plexmint install ${p.ticker}`;
338
+ const padding = 39 - installCmd.length;
339
+ console.log(
340
+ chalk3.gray(" \u2502 ") + chalk3.cyan.bold(installCmd) + " ".repeat(Math.max(0, padding)) + chalk3.gray("\u2502")
341
+ );
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"));
343
+ console.log(
344
+ chalk3.gray("\n View on web: ") + chalk3.underline(`https://plexmint.com/prompt/${p.slug}
345
+ `)
346
+ );
347
+ } catch (error) {
348
+ spinner.stop();
349
+ if (error instanceof PlexMintApiError) {
350
+ if (error.status === 404) {
351
+ console.error(
352
+ chalk3.red(`
353
+ Prompt not found: ${ticker.toUpperCase()}
354
+ `)
355
+ );
356
+ } else {
357
+ console.error(chalk3.red(`
358
+ Error: ${error.message}
359
+ `));
360
+ }
361
+ } else {
362
+ console.error(chalk3.red("\n Connection error. Is plexmint.com reachable?\n"));
363
+ }
364
+ process.exit(1);
365
+ }
366
+ }
367
+
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) {
374
+ 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();
386
+ 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
+ }
451
+ 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
+ );
495
+ console.log("");
496
+ console.log(chalk4.green.bold(` \u2713 Installed ${data.ticker}`));
497
+ console.log(chalk4.gray(` ${data.title} v${data.version}`));
498
+ 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
+ }
513
+ console.log("");
514
+ } catch (error) {
515
+ spinner.stop();
516
+ if (error instanceof PlexMintApiError) {
517
+ if (error.status === 404) {
518
+ console.error(chalk4.red(`
519
+ Prompt not found: ${upperTicker}
520
+ `));
521
+ } else {
522
+ console.error(chalk4.red(`
523
+ Error: ${error.message}
524
+ `));
525
+ }
526
+ } else {
527
+ console.error(chalk4.red("\n Connection error. Is plexmint.com reachable?\n"));
528
+ }
529
+ process.exit(1);
530
+ }
531
+ }
532
+
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) ")
571
+ );
572
+ if (answer.toLowerCase() !== "y") {
573
+ console.log(chalk5.gray(" Cancelled.\n"));
574
+ return;
575
+ }
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);
627
+ }
628
+ } catch (error) {
629
+ spinner.stop();
630
+ 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(`
635
+ Error: ${error.message}
636
+ `));
637
+ }
638
+ } else {
639
+ console.error(
640
+ chalk5.red("\n Connection error. Is plexmint.com reachable?\n")
641
+ );
642
+ }
643
+ process.exit(1);
644
+ }
645
+ }
646
+ async function logoutCommand() {
647
+ clearAuth();
648
+ console.log(chalk5.green("\n \u2713 Logged out. API key removed.\n"));
649
+ }
650
+
651
+ // src/commands/library.ts
652
+ import chalk6 from "chalk";
653
+ import ora6 from "ora";
654
+ 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();
664
+ try {
665
+ const client = new PlexMintClient(getApiKey(), getBaseUrl());
666
+ 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"));
670
+ console.log("");
671
+ console.log(
672
+ chalk6.gray(
673
+ " View your purchased prompts at: "
674
+ ) + chalk6.cyan.underline("https://plexmint.com/library")
675
+ );
676
+ console.log("");
677
+ console.log(
678
+ chalk6.gray(" To download a purchased prompt locally:")
679
+ );
680
+ console.log(chalk6.white(" plexmint install <TICKER>\n"));
681
+ } catch (error) {
682
+ spinner.stop();
683
+ if (error instanceof PlexMintApiError) {
684
+ console.error(chalk6.red(`
685
+ Error: ${error.message}
686
+ `));
687
+ } else {
688
+ console.error(chalk6.red("\n Connection error.\n"));
689
+ }
690
+ process.exit(1);
691
+ }
692
+ }
693
+
694
+ // src/index.ts
695
+ 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);
708
+ program.action(() => {
709
+ console.log(BANNER);
710
+ console.log(chalk7.bold(" Quick Start:"));
711
+ 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"));
717
+ console.log("");
718
+ console.log(chalk7.gray(" Run ") + chalk7.white("plexmint --help") + chalk7.gray(" for all commands.\n"));
719
+ });
720
+ program.parse();
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "plexmint",
3
+ "version": "0.1.0",
4
+ "description": "PlexMint CLI — Browse, install, and manage AI prompts from your terminal",
5
+ "type": "module",
6
+ "bin": {
7
+ "plexmint": "./dist/index.js"
8
+ },
9
+ "files": [
10
+ "dist"
11
+ ],
12
+ "scripts": {
13
+ "build": "tsup src/index.ts --format esm --dts --clean",
14
+ "dev": "tsx src/index.ts",
15
+ "prepublishOnly": "npm run build"
16
+ },
17
+ "keywords": [
18
+ "ai",
19
+ "prompts",
20
+ "marketplace",
21
+ "agent",
22
+ "cli",
23
+ "living-prompts",
24
+ "plexmint"
25
+ ],
26
+ "author": "PlexMint <info@plexmint.com>",
27
+ "license": "MIT",
28
+ "repository": {
29
+ "type": "git",
30
+ "url": "https://github.com/nuesion/plexmint.git",
31
+ "directory": "packages/cli"
32
+ },
33
+ "homepage": "https://plexmint.com",
34
+ "engines": {
35
+ "node": ">=18.0.0"
36
+ },
37
+ "dependencies": {
38
+ "chalk": "^5.4.1",
39
+ "commander": "^13.1.0",
40
+ "conf": "^13.1.0",
41
+ "ora": "^8.2.0",
42
+ "cli-table3": "^0.6.5"
43
+ },
44
+ "devDependencies": {
45
+ "tsup": "^8.4.0",
46
+ "tsx": "^4.21.0",
47
+ "typescript": "^5.7.0",
48
+ "@types/node": "^20.0.0"
49
+ }
50
+ }