prompts.chat 0.0.7 → 0.0.8

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 (40) hide show
  1. package/bin/cli.js +2 -0
  2. package/dist/builder/{index.mjs → index.cjs} +42 -3
  3. package/dist/builder/index.cjs.map +1 -0
  4. package/dist/builder/index.js +2 -41
  5. package/dist/builder/index.js.map +1 -1
  6. package/dist/cli/index.js +1132 -0
  7. package/dist/cli/index.js.map +1 -0
  8. package/dist/{index.mjs → index.cjs} +72 -13
  9. package/dist/index.cjs.map +1 -0
  10. package/dist/{index.d.mts → index.d.cts} +5 -5
  11. package/dist/index.js +12 -71
  12. package/dist/index.js.map +1 -1
  13. package/dist/parser/{index.mjs → index.cjs} +32 -3
  14. package/dist/parser/{index.mjs.map → index.cjs.map} +1 -1
  15. package/dist/parser/{index.d.mts → index.d.cts} +1 -1
  16. package/dist/parser/index.js +2 -31
  17. package/dist/parser/index.js.map +1 -1
  18. package/dist/quality/{index.mjs → index.cjs} +31 -3
  19. package/dist/quality/{index.mjs.map → index.cjs.map} +1 -1
  20. package/dist/quality/{index.d.mts → index.d.cts} +1 -1
  21. package/dist/quality/index.js +2 -30
  22. package/dist/quality/index.js.map +1 -1
  23. package/dist/similarity/{index.mjs → index.cjs} +35 -3
  24. package/dist/similarity/{index.mjs.map → index.cjs.map} +1 -1
  25. package/dist/similarity/{index.d.mts → index.d.cts} +1 -1
  26. package/dist/similarity/index.js +2 -34
  27. package/dist/similarity/index.js.map +1 -1
  28. package/dist/variables/{index.mjs → index.cjs} +35 -3
  29. package/dist/variables/{index.mjs.map → index.cjs.map} +1 -1
  30. package/dist/variables/{index.d.mts → index.d.cts} +1 -1
  31. package/dist/variables/index.js +2 -34
  32. package/dist/variables/index.js.map +1 -1
  33. package/package.json +18 -1
  34. package/dist/builder/index.mjs.map +0 -1
  35. package/dist/index.mjs.map +0 -1
  36. /package/dist/builder/{index.d.mts → index.d.cts} +0 -0
  37. /package/dist/{index-BEIO8LCd.d.mts → index-BEIO8LCd.d.cts} +0 -0
  38. /package/dist/{index-CSHEKYfQ.d.mts → index-CSHEKYfQ.d.cts} +0 -0
  39. /package/dist/{index-D41E6D9X.d.mts → index-D41E6D9X.d.cts} +0 -0
  40. /package/dist/{index-DOz8zcA0.d.mts → index-DOz8zcA0.d.cts} +0 -0
@@ -0,0 +1,1132 @@
1
+ #!/usr/bin/env node
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __esm = (fn, res) => function __init() {
5
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
6
+ };
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+
12
+ // src/cli/platforms.ts
13
+ var platforms_exports = {};
14
+ __export(platforms_exports, {
15
+ buildUrl: () => buildUrl,
16
+ chatPlatforms: () => chatPlatforms,
17
+ codePlatforms: () => codePlatforms
18
+ });
19
+ function buildUrl(platformId, baseUrl, promptText, promptTitle, promptDescription) {
20
+ const encoded = encodeURIComponent(promptText);
21
+ switch (platformId) {
22
+ case "cursor":
23
+ return `${baseUrl}?text=${encoded}`;
24
+ case "goose": {
25
+ const config = JSON.stringify({
26
+ version: "1.0.0",
27
+ title: promptTitle || "Prompt",
28
+ description: promptDescription || "",
29
+ instructions: "This is a prompt imported from prompts.chat.",
30
+ prompt: promptText,
31
+ activities: ["Do it now"]
32
+ });
33
+ const base64Config = Buffer.from(config).toString("base64");
34
+ return `${baseUrl}?config=${base64Config}`;
35
+ }
36
+ case "bolt":
37
+ return `${baseUrl}?prompt=${encoded}`;
38
+ case "chatgpt":
39
+ return `${baseUrl}/?q=${encoded}`;
40
+ case "claude":
41
+ return `${baseUrl}?q=${encoded}`;
42
+ case "github-copilot":
43
+ case "github-copilot-agents":
44
+ return `${baseUrl}?prompt=${encoded}`;
45
+ case "ai2sql":
46
+ return `${baseUrl}&prompt=${encoded}`;
47
+ case "fal":
48
+ return `${baseUrl}?prompt=${encoded}`;
49
+ case "grok":
50
+ case "grok-deepsearch":
51
+ case "grok-think":
52
+ return `${baseUrl}&q=${encoded}`;
53
+ case "huggingface":
54
+ return `${baseUrl}/?prompt=${encoded}`;
55
+ case "lovable":
56
+ return `${baseUrl}/?autosubmit=true#prompt=${encoded}`;
57
+ case "mistral":
58
+ return `${baseUrl}?q=${encoded}`;
59
+ case "perplexity":
60
+ return `${baseUrl}/search?q=${encoded}`;
61
+ case "phind":
62
+ return `${baseUrl}/search?q=${encoded}`;
63
+ case "v0":
64
+ return `${baseUrl}?q=${encoded}`;
65
+ case "you":
66
+ return `${baseUrl}/search?q=${encoded}`;
67
+ default:
68
+ return `${baseUrl}?q=${encoded}`;
69
+ }
70
+ }
71
+ var codePlatforms, chatPlatforms;
72
+ var init_platforms = __esm({
73
+ "src/cli/platforms.ts"() {
74
+ "use strict";
75
+ codePlatforms = [
76
+ { id: "windsurf", name: "Windsurf", baseUrl: "windsurf://", isDeeplink: true, supportsQuerystring: false },
77
+ { id: "vscode", name: "VS Code", baseUrl: "vscode://", isDeeplink: true, supportsQuerystring: false },
78
+ { id: "vscode-insiders", name: "VS Code Insiders", baseUrl: "vscode-insiders://", isDeeplink: true, supportsQuerystring: false },
79
+ { id: "cursor", name: "Cursor", baseUrl: "cursor://anysphere.cursor-deeplink/prompt", isDeeplink: true },
80
+ { id: "goose", name: "Goose", baseUrl: "goose://recipe", isDeeplink: true },
81
+ { id: "github-copilot", name: "GitHub Copilot Chat", baseUrl: "https://github.com/copilot" },
82
+ { id: "github-copilot-agents", name: "GitHub Copilot Agents", baseUrl: "https://github.com/copilot/agents" },
83
+ { id: "bolt", name: "Bolt", baseUrl: "https://bolt.new" },
84
+ { id: "lovable", name: "Lovable", baseUrl: "https://lovable.dev" },
85
+ { id: "v0", name: "v0", baseUrl: "https://v0.dev/chat" },
86
+ { id: "ai2sql", name: "AI2SQL", baseUrl: "https://builder.ai2sql.io/dashboard/builder-all-lp?tab=generate" }
87
+ ];
88
+ chatPlatforms = [
89
+ { id: "chatgpt", name: "ChatGPT", baseUrl: "https://chatgpt.com" },
90
+ { id: "claude", name: "Claude", baseUrl: "https://claude.ai/new" },
91
+ { id: "copilot", name: "Microsoft Copilot", baseUrl: "https://copilot.microsoft.com", supportsQuerystring: false },
92
+ { id: "deepseek", name: "DeepSeek", baseUrl: "https://chat.deepseek.com", supportsQuerystring: false },
93
+ { id: "fal", name: "fal.ai Sandbox", baseUrl: "https://fal.ai/sandbox" },
94
+ { id: "gemini", name: "Gemini", baseUrl: "https://gemini.google.com/app", supportsQuerystring: false },
95
+ { id: "grok", name: "Grok", baseUrl: "https://grok.com/chat?reasoningMode=none" },
96
+ { id: "grok-deepsearch", name: "Grok Deep Search", baseUrl: "https://grok.com/chat?reasoningMode=deepsearch" },
97
+ { id: "grok-think", name: "Grok Think", baseUrl: "https://grok.com/chat?reasoningMode=think" },
98
+ { id: "huggingface", name: "HuggingChat", baseUrl: "https://huggingface.co/chat" },
99
+ { id: "llama", name: "Meta AI", baseUrl: "https://www.meta.ai" },
100
+ { id: "manus", name: "Manus", baseUrl: "https://manus.im/app" },
101
+ { id: "mistral", name: "Le Chat", baseUrl: "https://chat.mistral.ai/chat" },
102
+ { id: "perplexity", name: "Perplexity", baseUrl: "https://www.perplexity.ai" },
103
+ { id: "phind", name: "Phind", baseUrl: "https://www.phind.com" },
104
+ { id: "pi", name: "Pi", baseUrl: "https://pi.ai", supportsQuerystring: false },
105
+ { id: "poe", name: "Poe", baseUrl: "https://poe.com", supportsQuerystring: false },
106
+ { id: "you", name: "You.com", baseUrl: "https://you.com" }
107
+ ];
108
+ }
109
+ });
110
+
111
+ // src/cli/index.tsx
112
+ import { useState as useState4 } from "react";
113
+ import { render } from "ink";
114
+ import meow from "meow";
115
+ import clipboardy from "clipboardy";
116
+
117
+ // src/cli/components/PromptList.tsx
118
+ import { useState, useEffect, useRef } from "react";
119
+ import { Box, Text, useInput, useApp, useStdout } from "ink";
120
+ import Spinner from "ink-spinner";
121
+ import TextInput from "ink-text-input";
122
+
123
+ // src/cli/api.ts
124
+ import { existsSync, readFileSync, writeFileSync, mkdirSync } from "fs";
125
+ import { homedir } from "os";
126
+ import { join } from "path";
127
+ var PROMPTS_URL = "https://prompts.chat/prompts.json";
128
+ var CACHE_DIR = join(homedir(), ".prompts-chat");
129
+ var CACHE_FILE = join(CACHE_DIR, "prompts.json");
130
+ var cachedPrompts = null;
131
+ function ensureCacheDir() {
132
+ if (!existsSync(CACHE_DIR)) {
133
+ mkdirSync(CACHE_DIR, { recursive: true });
134
+ }
135
+ }
136
+ function loadFromCache() {
137
+ try {
138
+ if (existsSync(CACHE_FILE)) {
139
+ const data = JSON.parse(readFileSync(CACHE_FILE, "utf-8"));
140
+ return data.prompts;
141
+ }
142
+ } catch {
143
+ }
144
+ return null;
145
+ }
146
+ function saveToCache(prompts) {
147
+ try {
148
+ ensureCacheDir();
149
+ const data = { prompts, fetchedAt: Date.now() };
150
+ writeFileSync(CACHE_FILE, JSON.stringify(data));
151
+ } catch {
152
+ }
153
+ }
154
+ async function loadPrompts() {
155
+ if (cachedPrompts) {
156
+ return cachedPrompts;
157
+ }
158
+ try {
159
+ const response = await fetch(PROMPTS_URL);
160
+ if (response.ok) {
161
+ const data = await response.json();
162
+ cachedPrompts = data.prompts;
163
+ saveToCache(cachedPrompts);
164
+ return cachedPrompts;
165
+ }
166
+ } catch {
167
+ }
168
+ const cached = loadFromCache();
169
+ if (cached) {
170
+ cachedPrompts = cached;
171
+ return cachedPrompts;
172
+ }
173
+ throw new Error("No prompts available. Please check your internet connection.");
174
+ }
175
+ function getCategories(prompts) {
176
+ const categoryMap = /* @__PURE__ */ new Map();
177
+ for (const prompt of prompts) {
178
+ if (prompt.category) {
179
+ const existing = categoryMap.get(prompt.category.slug);
180
+ if (existing) {
181
+ existing.count++;
182
+ } else {
183
+ categoryMap.set(prompt.category.slug, {
184
+ id: prompt.category.id,
185
+ name: prompt.category.name,
186
+ slug: prompt.category.slug,
187
+ count: 1
188
+ });
189
+ }
190
+ }
191
+ }
192
+ return Array.from(categoryMap.values()).sort((a, b) => a.name.localeCompare(b.name));
193
+ }
194
+ function filterPrompts(prompts, options) {
195
+ let filtered = prompts;
196
+ if (options.q) {
197
+ const query = options.q.toLowerCase();
198
+ filtered = filtered.filter(
199
+ (p) => p.title.toLowerCase().includes(query) || p.content.toLowerCase().includes(query) || p.description?.toLowerCase().includes(query) || p.author.username.toLowerCase().includes(query) || p.author.name?.toLowerCase().includes(query) || p.tags.some((t) => t.name.toLowerCase().includes(query) || t.slug.toLowerCase().includes(query))
200
+ );
201
+ }
202
+ if (options.category) {
203
+ filtered = filtered.filter((p) => p.category?.slug === options.category);
204
+ }
205
+ const total = filtered.length;
206
+ const page = options.page || 1;
207
+ const perPage = options.perPage || 20;
208
+ const totalPages = Math.ceil(total / perPage);
209
+ const start = (page - 1) * perPage;
210
+ const paged = filtered.slice(start, start + perPage);
211
+ return { prompts: paged, total, page, perPage, totalPages };
212
+ }
213
+
214
+ // src/cli/components/PromptList.tsx
215
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
216
+ function PromptList({
217
+ onSelect,
218
+ onQuit,
219
+ searchQuery,
220
+ onSearchChange,
221
+ page,
222
+ onPageChange,
223
+ selectedCategory,
224
+ onCategoryChange,
225
+ selectedIndex,
226
+ onIndexChange
227
+ }) {
228
+ const { exit } = useApp();
229
+ const { stdout } = useStdout();
230
+ const allPromptsRef = useRef([]);
231
+ const [prompts, setPrompts] = useState([]);
232
+ const [loading, setLoading] = useState(true);
233
+ const [error, setError] = useState(null);
234
+ const [localSearchQuery, setLocalSearchQuery] = useState(searchQuery);
235
+ const [isSearching, setIsSearching] = useState(false);
236
+ const [totalPages, setTotalPages] = useState(1);
237
+ const [total, setTotal] = useState(0);
238
+ const [viewMode, setViewMode] = useState("list");
239
+ const [categories, setCategories] = useState([]);
240
+ const [categoryIndex, setCategoryIndex] = useState(0);
241
+ const [categorySearchQuery, setCategorySearchQuery] = useState("");
242
+ const [isSearchingCategories, setIsSearchingCategories] = useState(false);
243
+ const terminalHeight = stdout?.rows || 24;
244
+ const terminalWidth = stdout?.columns || 80;
245
+ const headerLines = 3;
246
+ const footerLines = 2;
247
+ const listHeight = Math.max(terminalHeight - headerLines - footerLines, 5);
248
+ const perPage = listHeight;
249
+ useEffect(() => {
250
+ initializePrompts();
251
+ }, []);
252
+ useEffect(() => {
253
+ if (allPromptsRef.current.length > 0) {
254
+ applyFilters();
255
+ }
256
+ }, [page, searchQuery, selectedCategory, perPage]);
257
+ async function initializePrompts() {
258
+ setLoading(true);
259
+ setError(null);
260
+ try {
261
+ const all = await loadPrompts();
262
+ allPromptsRef.current = all;
263
+ setCategories(getCategories(all));
264
+ applyFilters();
265
+ } catch (err) {
266
+ setError(err instanceof Error ? err.message : "Failed to load prompts");
267
+ } finally {
268
+ setLoading(false);
269
+ }
270
+ }
271
+ function applyFilters() {
272
+ const result = filterPrompts(allPromptsRef.current, {
273
+ q: searchQuery || void 0,
274
+ category: selectedCategory || void 0,
275
+ page,
276
+ perPage
277
+ });
278
+ setPrompts(result.prompts);
279
+ setTotalPages(result.totalPages);
280
+ setTotal(result.total);
281
+ }
282
+ useInput((input, key) => {
283
+ if (isSearching) {
284
+ if (key.escape) {
285
+ setIsSearching(false);
286
+ setLocalSearchQuery(searchQuery);
287
+ }
288
+ return;
289
+ }
290
+ if (isSearchingCategories) {
291
+ if (key.escape) {
292
+ setIsSearchingCategories(false);
293
+ setCategorySearchQuery("");
294
+ }
295
+ return;
296
+ }
297
+ if (viewMode === "categories") {
298
+ if (key.escape || input === "b") {
299
+ setViewMode("list");
300
+ setCategorySearchQuery("");
301
+ return;
302
+ }
303
+ if (input === "/") {
304
+ setIsSearchingCategories(true);
305
+ return;
306
+ }
307
+ if (key.upArrow || input === "k") {
308
+ setCategoryIndex((i) => Math.max(0, i - 1));
309
+ return;
310
+ }
311
+ if (key.downArrow || input === "j") {
312
+ const filteredCats = categorySearchQuery ? categories.filter((c) => c.name.toLowerCase().includes(categorySearchQuery.toLowerCase())) : categories;
313
+ const maxIndex = categorySearchQuery ? filteredCats.length - 1 : filteredCats.length;
314
+ setCategoryIndex((i) => Math.min(maxIndex, i + 1));
315
+ return;
316
+ }
317
+ if (key.return) {
318
+ const filteredCats = categorySearchQuery ? categories.filter((c) => c.name.toLowerCase().includes(categorySearchQuery.toLowerCase())) : categories;
319
+ if (categorySearchQuery) {
320
+ if (filteredCats[categoryIndex]) {
321
+ onCategoryChange(filteredCats[categoryIndex].slug);
322
+ }
323
+ } else {
324
+ if (categoryIndex === 0) {
325
+ onCategoryChange(null);
326
+ } else if (filteredCats[categoryIndex - 1]) {
327
+ onCategoryChange(filteredCats[categoryIndex - 1].slug);
328
+ }
329
+ }
330
+ setViewMode("list");
331
+ setCategorySearchQuery("");
332
+ return;
333
+ }
334
+ return;
335
+ }
336
+ if (input === "q" || key.escape) {
337
+ onQuit();
338
+ exit();
339
+ return;
340
+ }
341
+ if (input === "/") {
342
+ setIsSearching(true);
343
+ return;
344
+ }
345
+ if (input === "c") {
346
+ setViewMode("categories");
347
+ setCategoryIndex(selectedCategory ? categories.findIndex((c) => c.slug === selectedCategory) + 1 : 0);
348
+ return;
349
+ }
350
+ if (key.upArrow || input === "k") {
351
+ onIndexChange(Math.max(0, selectedIndex - 1));
352
+ }
353
+ if (key.downArrow || input === "j") {
354
+ onIndexChange(Math.min(prompts.length - 1, selectedIndex + 1));
355
+ }
356
+ if (key.return && prompts[selectedIndex]) {
357
+ onSelect(prompts[selectedIndex]);
358
+ }
359
+ if (input === "n" && page < totalPages) {
360
+ onPageChange(page + 1);
361
+ }
362
+ if (input === "p" && page > 1) {
363
+ onPageChange(page - 1);
364
+ }
365
+ if (input === "r") {
366
+ initializePrompts();
367
+ }
368
+ });
369
+ const handleSearchSubmit = (value) => {
370
+ onSearchChange(value);
371
+ setLocalSearchQuery(value);
372
+ setIsSearching(false);
373
+ };
374
+ const handleCategorySearchSubmit = (value) => {
375
+ setCategorySearchQuery(value);
376
+ setCategoryIndex(0);
377
+ setIsSearchingCategories(false);
378
+ };
379
+ const filteredCategories = categorySearchQuery ? categories.filter((c) => c.name.toLowerCase().includes(categorySearchQuery.toLowerCase())) : categories;
380
+ const maxTitleLength = terminalWidth - 30;
381
+ if (error) {
382
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", height: terminalHeight, padding: 1, children: [
383
+ /* @__PURE__ */ jsxs(Text, { color: "red", children: [
384
+ "Error: ",
385
+ error
386
+ ] }),
387
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Press 'r' to retry, 'q' to quit" })
388
+ ] });
389
+ }
390
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", height: terminalHeight, children: [
391
+ /* @__PURE__ */ jsxs(Box, { paddingX: 1, marginBottom: 0, children: [
392
+ /* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "\u26A1 prompts.chat" }),
393
+ /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
394
+ " \u2014 ",
395
+ total,
396
+ " prompts"
397
+ ] }),
398
+ selectedCategory && /* @__PURE__ */ jsxs(Fragment, { children: [
399
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: " \xB7 " }),
400
+ /* @__PURE__ */ jsx(Text, { color: "magenta", children: selectedCategory })
401
+ ] }),
402
+ searchQuery && !isSearching && /* @__PURE__ */ jsxs(Fragment, { children: [
403
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: " \xB7 " }),
404
+ /* @__PURE__ */ jsx(Text, { color: "yellow", children: searchQuery })
405
+ ] })
406
+ ] }),
407
+ isSearching && /* @__PURE__ */ jsxs(Box, { paddingX: 1, children: [
408
+ /* @__PURE__ */ jsx(Text, { color: "yellow", children: "Search: " }),
409
+ /* @__PURE__ */ jsx(
410
+ TextInput,
411
+ {
412
+ value: localSearchQuery,
413
+ onChange: setLocalSearchQuery,
414
+ onSubmit: handleSearchSubmit,
415
+ placeholder: "Type to search..."
416
+ }
417
+ )
418
+ ] }),
419
+ viewMode === "categories" && /* @__PURE__ */ jsxs(Box, { flexDirection: "column", flexGrow: 1, paddingX: 1, children: [
420
+ /* @__PURE__ */ jsxs(Box, { marginBottom: 1, children: [
421
+ /* @__PURE__ */ jsx(Text, { bold: true, color: "magenta", children: "Select Category" }),
422
+ categorySearchQuery && !isSearchingCategories && /* @__PURE__ */ jsxs(Fragment, { children: [
423
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: " \xB7 " }),
424
+ /* @__PURE__ */ jsx(Text, { color: "yellow", children: categorySearchQuery })
425
+ ] })
426
+ ] }),
427
+ isSearchingCategories && /* @__PURE__ */ jsxs(Box, { marginBottom: 1, children: [
428
+ /* @__PURE__ */ jsx(Text, { color: "yellow", children: "Search: " }),
429
+ /* @__PURE__ */ jsx(
430
+ TextInput,
431
+ {
432
+ value: categorySearchQuery,
433
+ onChange: setCategorySearchQuery,
434
+ onSubmit: handleCategorySearchSubmit,
435
+ placeholder: "Type to filter..."
436
+ }
437
+ )
438
+ ] }),
439
+ categories.length === 0 ? /* @__PURE__ */ jsxs(Box, { children: [
440
+ /* @__PURE__ */ jsx(Text, { color: "green", children: /* @__PURE__ */ jsx(Spinner, { type: "dots" }) }),
441
+ /* @__PURE__ */ jsx(Text, { children: " Loading categories..." })
442
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
443
+ !categorySearchQuery && /* @__PURE__ */ jsxs(Box, { children: [
444
+ /* @__PURE__ */ jsx(Text, { color: categoryIndex === 0 ? "cyan" : void 0, children: categoryIndex === 0 ? "\u276F " : " " }),
445
+ /* @__PURE__ */ jsx(Text, { color: categoryIndex === 0 ? "cyan" : void 0, bold: categoryIndex === 0, children: "All Categories" })
446
+ ] }),
447
+ filteredCategories.slice(0, listHeight - 1).map((cat, index) => {
448
+ const adjustedIndex = categorySearchQuery ? index : index + 1;
449
+ return /* @__PURE__ */ jsxs(Box, { children: [
450
+ /* @__PURE__ */ jsx(Text, { color: adjustedIndex === categoryIndex ? "cyan" : void 0, children: adjustedIndex === categoryIndex ? "\u276F " : " " }),
451
+ /* @__PURE__ */ jsx(
452
+ Text,
453
+ {
454
+ color: adjustedIndex === categoryIndex ? "cyan" : void 0,
455
+ bold: adjustedIndex === categoryIndex,
456
+ children: cat.name
457
+ }
458
+ ),
459
+ cat.count > 0 && /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
460
+ " (",
461
+ cat.count,
462
+ ")"
463
+ ] })
464
+ ] }, cat.id);
465
+ })
466
+ ] })
467
+ ] }),
468
+ viewMode === "list" && /* @__PURE__ */ jsx(Box, { flexDirection: "column", flexGrow: 1, paddingX: 1, children: loading ? /* @__PURE__ */ jsxs(Box, { children: [
469
+ /* @__PURE__ */ jsx(Text, { color: "green", children: /* @__PURE__ */ jsx(Spinner, { type: "dots" }) }),
470
+ /* @__PURE__ */ jsx(Text, { children: " Loading prompts..." })
471
+ ] }) : prompts.slice(0, listHeight).map((prompt, index) => /* @__PURE__ */ jsxs(Box, { children: [
472
+ /* @__PURE__ */ jsx(Text, { color: index === selectedIndex ? "cyan" : void 0, children: index === selectedIndex ? "\u276F " : " " }),
473
+ /* @__PURE__ */ jsxs(
474
+ Text,
475
+ {
476
+ color: index === selectedIndex ? "cyan" : void 0,
477
+ bold: index === selectedIndex,
478
+ children: [
479
+ prompt.title.slice(0, maxTitleLength),
480
+ prompt.title.length > maxTitleLength ? "\u2026" : ""
481
+ ]
482
+ }
483
+ ),
484
+ /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
485
+ " @",
486
+ prompt.author.username
487
+ ] }),
488
+ prompt.voteCount > 0 && /* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
489
+ " \u2B06 ",
490
+ prompt.voteCount
491
+ ] })
492
+ ] }, prompt.id)) }),
493
+ /* @__PURE__ */ jsxs(Box, { paddingX: 1, justifyContent: "space-between", children: [
494
+ viewMode === "categories" ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "j/k nav \xB7 Enter select \xB7 / search \xB7 b back" }) : /* @__PURE__ */ jsx(Text, { dimColor: true, children: "j/k nav \xB7 Enter select \xB7 / search \xB7 c category \xB7 n/p pages \xB7 q quit" }),
495
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: viewMode === "list" ? `${page}/${totalPages}` : "" })
496
+ ] })
497
+ ] });
498
+ }
499
+
500
+ // src/cli/components/PromptDetail.tsx
501
+ import { useState as useState3, useEffect as useEffect2, useMemo } from "react";
502
+ import { Box as Box3, Text as Text3, useInput as useInput3, useApp as useApp2, useStdout as useStdout3 } from "ink";
503
+ import TextInput2 from "ink-text-input";
504
+
505
+ // src/variables/index.ts
506
+ function extractVariables(text) {
507
+ const regex = /\$\{([a-zA-Z_][a-zA-Z0-9_\s]*?)(?::([^}]*))?\}/g;
508
+ const variables = [];
509
+ let match;
510
+ while ((match = regex.exec(text)) !== null) {
511
+ variables.push({
512
+ name: match[1].trim(),
513
+ defaultValue: match[2]?.trim()
514
+ });
515
+ }
516
+ return variables;
517
+ }
518
+ function compile(template, values, options = {}) {
519
+ const { useDefaults = true } = options;
520
+ return template.replace(
521
+ /\$\{([a-zA-Z_][a-zA-Z0-9_\s]*?)(?::([^}]*))?\}/g,
522
+ (match, name, defaultValue) => {
523
+ const trimmedName = name.trim();
524
+ if (trimmedName in values) {
525
+ return values[trimmedName];
526
+ }
527
+ if (useDefaults && defaultValue !== void 0) {
528
+ return defaultValue.trim();
529
+ }
530
+ return match;
531
+ }
532
+ );
533
+ }
534
+
535
+ // src/cli/components/RunPrompt.tsx
536
+ init_platforms();
537
+ import { useState as useState2 } from "react";
538
+ import { Box as Box2, Text as Text2, useInput as useInput2, useStdout as useStdout2 } from "ink";
539
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
540
+ function RunPrompt({ content, title, description, promptType, mediaUrl, onRun, onCopyAndOpen, onBack }) {
541
+ const { stdout } = useStdout2();
542
+ const [tab, setTab] = useState2("chat");
543
+ const [selectedIndex, setSelectedIndex] = useState2(0);
544
+ const terminalHeight = stdout?.rows || 24;
545
+ const terminalWidth = stdout?.columns || 80;
546
+ const platforms = tab === "chat" ? chatPlatforms : codePlatforms;
547
+ const previewLength = terminalWidth - 6;
548
+ const contentPreview = content.replace(/\n/g, " ").slice(0, previewLength);
549
+ const isMediaType = promptType === "IMAGE" || promptType === "VIDEO" || promptType === "AUDIO";
550
+ useInput2((input, key) => {
551
+ if (key.escape || input === "b") {
552
+ onBack();
553
+ return;
554
+ }
555
+ if (key.leftArrow || key.rightArrow || input === "h" || input === "l") {
556
+ setTab(tab === "chat" ? "code" : "chat");
557
+ setSelectedIndex(0);
558
+ return;
559
+ }
560
+ if (key.upArrow || input === "k") {
561
+ setSelectedIndex((i) => Math.max(0, i - 1));
562
+ }
563
+ if (key.downArrow || input === "j") {
564
+ setSelectedIndex((i) => Math.min(platforms.length - 1, i + 1));
565
+ }
566
+ if (key.return) {
567
+ const platform = platforms[selectedIndex];
568
+ if (platform.supportsQuerystring === false) {
569
+ onCopyAndOpen(content, platform);
570
+ } else {
571
+ const url = buildUrl(platform.id, platform.baseUrl, content, title, description);
572
+ onRun(url, platform);
573
+ }
574
+ }
575
+ });
576
+ return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", height: terminalHeight, children: [
577
+ /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", paddingX: 1, marginBottom: 1, children: [
578
+ /* @__PURE__ */ jsxs2(Box2, { children: [
579
+ /* @__PURE__ */ jsx2(Text2, { bold: true, color: "green", children: "\u25B6 Run: " }),
580
+ /* @__PURE__ */ jsx2(Text2, { bold: true, color: "cyan", children: title || "Untitled" }),
581
+ isMediaType && /* @__PURE__ */ jsxs2(Text2, { color: "magenta", children: [
582
+ " [",
583
+ promptType,
584
+ "]"
585
+ ] })
586
+ ] }),
587
+ /* @__PURE__ */ jsx2(Box2, { children: /* @__PURE__ */ jsxs2(Text2, { dimColor: true, children: [
588
+ contentPreview,
589
+ content.length > previewLength ? "\u2026" : ""
590
+ ] }) })
591
+ ] }),
592
+ /* @__PURE__ */ jsxs2(Box2, { paddingX: 1, marginBottom: 1, children: [
593
+ /* @__PURE__ */ jsx2(
594
+ Text2,
595
+ {
596
+ color: tab === "chat" ? "cyan" : "gray",
597
+ bold: tab === "chat",
598
+ underline: tab === "chat",
599
+ children: "Chat"
600
+ }
601
+ ),
602
+ /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: " " }),
603
+ /* @__PURE__ */ jsx2(
604
+ Text2,
605
+ {
606
+ color: tab === "code" ? "cyan" : "gray",
607
+ bold: tab === "code",
608
+ underline: tab === "code",
609
+ children: "Code"
610
+ }
611
+ ),
612
+ /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: " h/l to switch" })
613
+ ] }),
614
+ /* @__PURE__ */ jsx2(Box2, { flexDirection: "column", flexGrow: 1, paddingX: 1, children: platforms.map((platform, index) => /* @__PURE__ */ jsxs2(Box2, { children: [
615
+ /* @__PURE__ */ jsx2(Text2, { color: index === selectedIndex ? "cyan" : void 0, children: index === selectedIndex ? "\u276F " : " " }),
616
+ platform.supportsQuerystring === false ? /* @__PURE__ */ jsx2(Text2, { color: "yellow", children: "\u25D0 " }) : /* @__PURE__ */ jsx2(Text2, { color: "green", children: "\u26A1 " }),
617
+ /* @__PURE__ */ jsx2(
618
+ Text2,
619
+ {
620
+ color: index === selectedIndex ? "cyan" : void 0,
621
+ bold: index === selectedIndex,
622
+ children: platform.name
623
+ }
624
+ ),
625
+ platform.supportsQuerystring === false && /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: " (copy & open)" })
626
+ ] }, platform.id)) }),
627
+ /* @__PURE__ */ jsxs2(Box2, { paddingX: 1, justifyContent: "space-between", children: [
628
+ /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "j/k select \xB7 Enter run \xB7 h/l tab \xB7 b back" }),
629
+ /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "\u26A1 direct \xB7 \u25D0 copy+open" })
630
+ ] })
631
+ ] });
632
+ }
633
+
634
+ // src/cli/components/PromptDetail.tsx
635
+ import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
636
+ function HighlightedLine({ text }) {
637
+ const parts = text.split(/(\$\{[^}]+\})/g);
638
+ return /* @__PURE__ */ jsx3(Text3, { children: parts.map((part, i) => {
639
+ if (part.match(/^\$\{[^}]+\}$/)) {
640
+ return /* @__PURE__ */ jsx3(Text3, { color: "yellow", bold: true, children: part }, i);
641
+ }
642
+ return /* @__PURE__ */ jsx3(Text3, { children: part }, i);
643
+ }) });
644
+ }
645
+ function wrapText(text, width) {
646
+ const lines = [];
647
+ const rawLines = text.split("\n");
648
+ for (const rawLine of rawLines) {
649
+ if (rawLine.length <= width) {
650
+ lines.push(rawLine);
651
+ } else {
652
+ let remaining = rawLine;
653
+ while (remaining.length > width) {
654
+ let breakPoint = remaining.lastIndexOf(" ", width);
655
+ if (breakPoint === -1 || breakPoint < width / 2) {
656
+ breakPoint = width;
657
+ }
658
+ lines.push(remaining.slice(0, breakPoint));
659
+ remaining = remaining.slice(breakPoint).trimStart();
660
+ }
661
+ if (remaining) {
662
+ lines.push(remaining);
663
+ }
664
+ }
665
+ }
666
+ return lines;
667
+ }
668
+ function PromptDetail({ prompt, onBack, onCopy }) {
669
+ const { exit } = useApp2();
670
+ const { stdout } = useStdout3();
671
+ const [viewMode, setViewMode] = useState3("detail");
672
+ const [variables, setVariables] = useState3([]);
673
+ const [variableValues, setVariableValues] = useState3({});
674
+ const [currentVarIndex, setCurrentVarIndex] = useState3(0);
675
+ const [currentInput, setCurrentInput] = useState3("");
676
+ const [compiledContent, setCompiledContent] = useState3("");
677
+ const [pendingPlatform, setPendingPlatform] = useState3(null);
678
+ const [runAction, setRunAction] = useState3("run");
679
+ const [scrollOffset, setScrollOffset] = useState3(0);
680
+ const [imagePreview, setImagePreview] = useState3(null);
681
+ const [loadingImage, setLoadingImage] = useState3(false);
682
+ const terminalHeight = stdout?.rows || 24;
683
+ const terminalWidth = stdout?.columns || 80;
684
+ const headerLines = 8;
685
+ const footerLines = 2;
686
+ const contentHeight = Math.max(terminalHeight - headerLines - footerLines, 5);
687
+ useEffect2(() => {
688
+ const vars = extractVariables(prompt.content);
689
+ setVariables(vars);
690
+ const defaults = {};
691
+ vars.forEach((v) => {
692
+ if (v.defaultValue) defaults[v.name] = v.defaultValue;
693
+ });
694
+ setVariableValues(defaults);
695
+ }, [prompt]);
696
+ const contentLines = useMemo(() => {
697
+ if (!prompt) return [];
698
+ const parsedContent = prompt.content.replace(/\\n/g, "\n");
699
+ return wrapText(parsedContent, terminalWidth - 6);
700
+ }, [prompt, terminalWidth]);
701
+ const maxScroll = Math.max(0, contentLines.length - contentHeight);
702
+ const isMediaType = prompt?.type === "IMAGE" || prompt?.type === "VIDEO" || prompt?.type === "AUDIO";
703
+ const hasMedia = isMediaType && prompt?.mediaUrl;
704
+ async function loadImagePreview() {
705
+ if (!prompt?.mediaUrl || loadingImage) return;
706
+ setLoadingImage(true);
707
+ try {
708
+ const terminalImage = await import("terminal-image");
709
+ const response = await fetch(prompt.mediaUrl);
710
+ const buffer = Buffer.from(await response.arrayBuffer());
711
+ const image = await terminalImage.default.buffer(buffer, {
712
+ width: terminalWidth - 4,
713
+ height: terminalHeight - 4,
714
+ preserveAspectRatio: true
715
+ });
716
+ setImagePreview(image);
717
+ setViewMode("preview");
718
+ } catch {
719
+ setImagePreview("[Could not load image]");
720
+ } finally {
721
+ setLoadingImage(false);
722
+ }
723
+ }
724
+ useInput3((input, key) => {
725
+ if (viewMode === "run" || viewMode === "run-variables") {
726
+ return;
727
+ }
728
+ if (viewMode === "variables") {
729
+ if (key.escape) {
730
+ setViewMode("detail");
731
+ setCurrentVarIndex(0);
732
+ setCurrentInput("");
733
+ }
734
+ return;
735
+ }
736
+ if (viewMode === "copied") {
737
+ if (key.escape || input === "b" || key.return) {
738
+ setViewMode("detail");
739
+ }
740
+ return;
741
+ }
742
+ if (viewMode === "preview") {
743
+ if (key.escape || input === "b") {
744
+ setImagePreview(null);
745
+ setViewMode("detail");
746
+ }
747
+ return;
748
+ }
749
+ if (viewMode === "detail") {
750
+ if (input === "j" || key.downArrow) {
751
+ setScrollOffset((prev) => Math.min(prev + 1, maxScroll));
752
+ return;
753
+ }
754
+ if (input === "k" || key.upArrow) {
755
+ setScrollOffset((prev) => Math.max(prev - 1, 0));
756
+ return;
757
+ }
758
+ if (input === "D" || key.pageDown) {
759
+ setScrollOffset((prev) => Math.min(prev + Math.floor(contentHeight / 2), maxScroll));
760
+ return;
761
+ }
762
+ if (input === "U" || key.pageUp) {
763
+ setScrollOffset((prev) => Math.max(prev - Math.floor(contentHeight / 2), 0));
764
+ return;
765
+ }
766
+ if (input === "g") {
767
+ setScrollOffset(0);
768
+ return;
769
+ }
770
+ if (input === "G") {
771
+ setScrollOffset(maxScroll);
772
+ return;
773
+ }
774
+ }
775
+ if (key.escape || input === "b") {
776
+ onBack();
777
+ return;
778
+ }
779
+ if (input === "q") {
780
+ exit();
781
+ return;
782
+ }
783
+ if (input === "r" && prompt) {
784
+ setScrollOffset(0);
785
+ setViewMode("run");
786
+ return;
787
+ }
788
+ if (input === "c" && prompt) {
789
+ if (variables.length > 0) {
790
+ setViewMode("variables");
791
+ setCurrentVarIndex(0);
792
+ setCurrentInput(variableValues[variables[0].name] || "");
793
+ } else {
794
+ handleCopy(prompt.content);
795
+ }
796
+ }
797
+ if (input === "C" && prompt) {
798
+ handleCopy(prompt.content);
799
+ }
800
+ if (input === "o" && prompt) {
801
+ import("open").then(({ default: open }) => {
802
+ open(`https://prompts.chat/prompts/${prompt.id}_${prompt.slug}`);
803
+ });
804
+ }
805
+ if (input === "u" && prompt) {
806
+ import("open").then(({ default: open }) => {
807
+ open(`https://prompts.chat/@${prompt.author.username}`);
808
+ });
809
+ }
810
+ if (input === "p" && hasMedia) {
811
+ loadImagePreview();
812
+ }
813
+ });
814
+ function handleCopy(content) {
815
+ onCopy(content);
816
+ setCompiledContent(content);
817
+ setViewMode("copied");
818
+ }
819
+ function handleRun(url, platform) {
820
+ import("open").then(({ default: open }) => {
821
+ open(url);
822
+ });
823
+ setViewMode("detail");
824
+ }
825
+ function handleCopyAndOpen(content, platform) {
826
+ if (variables.length > 0) {
827
+ setPendingPlatform(platform);
828
+ setRunAction("copy");
829
+ setViewMode("run-variables");
830
+ setCurrentVarIndex(0);
831
+ setCurrentInput(variableValues[variables[0].name] || "");
832
+ } else {
833
+ onCopy(content);
834
+ import("open").then(({ default: open }) => {
835
+ open(platform.baseUrl);
836
+ });
837
+ setViewMode("detail");
838
+ }
839
+ }
840
+ function handleRunWithVariables(url, platform) {
841
+ if (variables.length > 0) {
842
+ setPendingPlatform(platform);
843
+ setRunAction("run");
844
+ setViewMode("run-variables");
845
+ setCurrentVarIndex(0);
846
+ setCurrentInput(variableValues[variables[0].name] || "");
847
+ } else {
848
+ handleRun(url, platform);
849
+ }
850
+ }
851
+ function handleVariableSubmit(value) {
852
+ const varName = variables[currentVarIndex].name;
853
+ const newValues = { ...variableValues, [varName]: value };
854
+ setVariableValues(newValues);
855
+ if (currentVarIndex < variables.length - 1) {
856
+ setCurrentVarIndex(currentVarIndex + 1);
857
+ setCurrentInput(newValues[variables[currentVarIndex + 1].name] || "");
858
+ } else {
859
+ const compiled = compile(prompt.content, newValues, { useDefaults: true });
860
+ if (viewMode === "run-variables" && pendingPlatform) {
861
+ if (runAction === "copy") {
862
+ onCopy(compiled);
863
+ import("open").then(({ default: open }) => {
864
+ open(pendingPlatform.baseUrl);
865
+ });
866
+ } else {
867
+ Promise.resolve().then(() => (init_platforms(), platforms_exports)).then(({ buildUrl: buildUrl2 }) => {
868
+ const url = buildUrl2(pendingPlatform.id, pendingPlatform.baseUrl, compiled, prompt.title, prompt.description || void 0);
869
+ import("open").then(({ default: open }) => {
870
+ open(url);
871
+ });
872
+ });
873
+ }
874
+ setPendingPlatform(null);
875
+ setViewMode("detail");
876
+ } else {
877
+ handleCopy(compiled);
878
+ }
879
+ }
880
+ }
881
+ const showCopiedMessage = viewMode === "copied";
882
+ if (viewMode === "preview" && imagePreview) {
883
+ return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", height: terminalHeight, children: [
884
+ /* @__PURE__ */ jsxs3(Box3, { paddingX: 1, marginBottom: 1, children: [
885
+ /* @__PURE__ */ jsx3(Text3, { bold: true, color: "magenta", children: "\u{1F4F7} Image Preview" }),
886
+ /* @__PURE__ */ jsxs3(Text3, { dimColor: true, children: [
887
+ " \xB7 ",
888
+ prompt.title
889
+ ] })
890
+ ] }),
891
+ /* @__PURE__ */ jsx3(Box3, { flexDirection: "column", flexGrow: 1, paddingX: 1, children: /* @__PURE__ */ jsx3(Text3, { children: imagePreview }) }),
892
+ /* @__PURE__ */ jsx3(Box3, { paddingX: 1, children: /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "b back" }) })
893
+ ] });
894
+ }
895
+ if (viewMode === "run") {
896
+ return /* @__PURE__ */ jsx3(
897
+ RunPrompt,
898
+ {
899
+ content: prompt.content,
900
+ title: prompt.title,
901
+ description: prompt.description || void 0,
902
+ promptType: prompt.type,
903
+ mediaUrl: prompt.mediaUrl,
904
+ onRun: handleRunWithVariables,
905
+ onCopyAndOpen: handleCopyAndOpen,
906
+ onBack: () => setViewMode("detail")
907
+ }
908
+ );
909
+ }
910
+ const isFillingVariables = viewMode === "variables" || viewMode === "run-variables";
911
+ const isRunMode = viewMode === "run-variables";
912
+ const currentVar = isFillingVariables ? variables[currentVarIndex] : null;
913
+ const tags = prompt.tags.map((t) => t.name).join(", ");
914
+ const inlineSectionHeight = isFillingVariables ? 3 : showCopiedMessage ? 1 : 0;
915
+ const adjustedContentHeight = contentHeight - inlineSectionHeight;
916
+ const visibleLines = contentLines.slice(scrollOffset, scrollOffset + adjustedContentHeight);
917
+ const adjustedMaxScroll = Math.max(0, contentLines.length - adjustedContentHeight);
918
+ const showScrollIndicator = contentLines.length > adjustedContentHeight;
919
+ const scrollPercent = adjustedMaxScroll > 0 ? Math.round(scrollOffset / adjustedMaxScroll * 100) : 100;
920
+ return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", height: terminalHeight, children: [
921
+ /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", paddingX: 1, children: [
922
+ /* @__PURE__ */ jsxs3(Box3, { marginBottom: 0, flexDirection: "column", children: [
923
+ /* @__PURE__ */ jsx3(Text3, { bold: true, color: "cyan", children: prompt.title }),
924
+ /* @__PURE__ */ jsxs3(Box3, { children: [
925
+ /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "by " }),
926
+ /* @__PURE__ */ jsxs3(Text3, { color: "yellow", children: [
927
+ "@",
928
+ prompt.author.username
929
+ ] }),
930
+ prompt.author.verified && /* @__PURE__ */ jsx3(Text3, { color: "blue", children: " \u2713" }),
931
+ /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: " \xB7 " }),
932
+ /* @__PURE__ */ jsxs3(Text3, { color: "green", children: [
933
+ "\u2B06 ",
934
+ prompt.voteCount
935
+ ] }),
936
+ prompt.category && /* @__PURE__ */ jsxs3(Fragment2, { children: [
937
+ /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: " \xB7 " }),
938
+ /* @__PURE__ */ jsx3(Text3, { color: "magenta", children: prompt.category.name })
939
+ ] })
940
+ ] })
941
+ ] }),
942
+ prompt.description && /* @__PURE__ */ jsx3(Box3, { children: /* @__PURE__ */ jsx3(Text3, { italic: true, dimColor: true, children: prompt.description.slice(0, terminalWidth - 4) }) }),
943
+ (tags || variables.length > 0) && /* @__PURE__ */ jsxs3(Box3, { children: [
944
+ tags && /* @__PURE__ */ jsxs3(Fragment2, { children: [
945
+ /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "Tags: " }),
946
+ /* @__PURE__ */ jsx3(Text3, { color: "blue", children: tags })
947
+ ] }),
948
+ tags && variables.length > 0 && /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: " \xB7 " }),
949
+ variables.length > 0 && /* @__PURE__ */ jsxs3(Fragment2, { children: [
950
+ /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "Vars: " }),
951
+ /* @__PURE__ */ jsx3(Text3, { color: "yellow", children: variables.map((v) => v.name).join(", ") })
952
+ ] })
953
+ ] })
954
+ ] }),
955
+ /* @__PURE__ */ jsx3(
956
+ Box3,
957
+ {
958
+ flexDirection: "column",
959
+ borderStyle: "round",
960
+ borderColor: "gray",
961
+ paddingX: 1,
962
+ flexGrow: 1,
963
+ marginX: 1,
964
+ overflow: "hidden",
965
+ children: visibleLines.map((line, i) => /* @__PURE__ */ jsx3(Box3, { children: line ? /* @__PURE__ */ jsx3(HighlightedLine, { text: line }) : /* @__PURE__ */ jsx3(Text3, { children: " " }) }, scrollOffset + i))
966
+ }
967
+ ),
968
+ isFillingVariables && currentVar && /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", paddingX: 1, borderStyle: "round", borderColor: isRunMode ? "green" : "cyan", marginX: 1, children: [
969
+ /* @__PURE__ */ jsxs3(Box3, { children: [
970
+ /* @__PURE__ */ jsx3(Text3, { bold: true, color: isRunMode ? "green" : "cyan", children: isRunMode ? "\u25B6 " : "" }),
971
+ /* @__PURE__ */ jsxs3(Text3, { color: "yellow", children: [
972
+ "$",
973
+ `{${currentVar.name}}`
974
+ ] }),
975
+ /* @__PURE__ */ jsxs3(Text3, { dimColor: true, children: [
976
+ " (",
977
+ currentVarIndex + 1,
978
+ "/",
979
+ variables.length,
980
+ ")"
981
+ ] }),
982
+ currentVar.defaultValue && /* @__PURE__ */ jsxs3(Text3, { dimColor: true, children: [
983
+ " default: ",
984
+ currentVar.defaultValue
985
+ ] })
986
+ ] }),
987
+ /* @__PURE__ */ jsxs3(Box3, { children: [
988
+ /* @__PURE__ */ jsx3(Text3, { color: "cyan", children: "\u2192 " }),
989
+ /* @__PURE__ */ jsx3(
990
+ TextInput2,
991
+ {
992
+ value: currentInput,
993
+ onChange: setCurrentInput,
994
+ onSubmit: handleVariableSubmit,
995
+ placeholder: currentVar.defaultValue || "Enter value..."
996
+ }
997
+ )
998
+ ] })
999
+ ] }),
1000
+ showCopiedMessage && /* @__PURE__ */ jsxs3(Box3, { paddingX: 1, marginX: 1, children: [
1001
+ /* @__PURE__ */ jsx3(Text3, { color: "green", bold: true, children: "\u2713 Copied to clipboard!" }),
1002
+ /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: " Press any key to continue" })
1003
+ ] }),
1004
+ loadingImage && /* @__PURE__ */ jsx3(Box3, { paddingX: 1, marginX: 1, children: /* @__PURE__ */ jsx3(Text3, { color: "yellow", children: "Loading image preview..." }) }),
1005
+ /* @__PURE__ */ jsxs3(Box3, { paddingX: 1, justifyContent: "space-between", children: [
1006
+ isFillingVariables ? /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "Enter confirm \xB7 Esc cancel" }) : /* @__PURE__ */ jsxs3(Text3, { dimColor: true, children: [
1007
+ "r run \xB7 c copy \xB7 o open \xB7 u user",
1008
+ hasMedia ? " \xB7 p preview" : "",
1009
+ " \xB7 b back \xB7 q quit"
1010
+ ] }),
1011
+ showScrollIndicator && !isFillingVariables && /* @__PURE__ */ jsxs3(Text3, { dimColor: true, children: [
1012
+ "j/k scroll \xB7 ",
1013
+ scrollPercent,
1014
+ "%"
1015
+ ] })
1016
+ ] })
1017
+ ] });
1018
+ }
1019
+
1020
+ // src/cli/index.tsx
1021
+ import { jsx as jsx4 } from "react/jsx-runtime";
1022
+ function App() {
1023
+ const [state, setState] = useState4({
1024
+ view: "list",
1025
+ selectedPrompt: null,
1026
+ searchQuery: "",
1027
+ page: 1,
1028
+ selectedCategory: null,
1029
+ selectedIndex: 0
1030
+ });
1031
+ const handleSelectPrompt = (prompt) => {
1032
+ setState((prev) => ({
1033
+ ...prev,
1034
+ view: "detail",
1035
+ selectedPrompt: prompt
1036
+ }));
1037
+ };
1038
+ const handleBack = () => {
1039
+ setState((prev) => ({
1040
+ ...prev,
1041
+ view: "list",
1042
+ selectedPrompt: null
1043
+ }));
1044
+ };
1045
+ const handleSearchChange = (query) => {
1046
+ setState((prev) => ({ ...prev, searchQuery: query, page: 1 }));
1047
+ };
1048
+ const handlePageChange = (page) => {
1049
+ setState((prev) => ({ ...prev, page }));
1050
+ };
1051
+ const handleCategoryChange = (category) => {
1052
+ setState((prev) => ({ ...prev, selectedCategory: category, page: 1, selectedIndex: 0 }));
1053
+ };
1054
+ const handleIndexChange = (index) => {
1055
+ setState((prev) => ({ ...prev, selectedIndex: index }));
1056
+ };
1057
+ const handleCopy = async (content) => {
1058
+ try {
1059
+ await clipboardy.write(content);
1060
+ } catch {
1061
+ }
1062
+ };
1063
+ const handleQuit = () => {
1064
+ process.exit(0);
1065
+ };
1066
+ if (state.view === "detail" && state.selectedPrompt) {
1067
+ return /* @__PURE__ */ jsx4(
1068
+ PromptDetail,
1069
+ {
1070
+ prompt: state.selectedPrompt,
1071
+ onBack: handleBack,
1072
+ onCopy: handleCopy
1073
+ }
1074
+ );
1075
+ }
1076
+ return /* @__PURE__ */ jsx4(
1077
+ PromptList,
1078
+ {
1079
+ onSelect: handleSelectPrompt,
1080
+ onQuit: handleQuit,
1081
+ searchQuery: state.searchQuery,
1082
+ onSearchChange: handleSearchChange,
1083
+ page: state.page,
1084
+ onPageChange: handlePageChange,
1085
+ selectedCategory: state.selectedCategory,
1086
+ onCategoryChange: handleCategoryChange,
1087
+ selectedIndex: state.selectedIndex,
1088
+ onIndexChange: handleIndexChange
1089
+ }
1090
+ );
1091
+ }
1092
+ var cli = meow(`
1093
+ Usage
1094
+ $ prompts-chat
1095
+
1096
+ Commands
1097
+ (default) Launch interactive TUI
1098
+
1099
+ Options
1100
+ --help Show this help
1101
+ --version Show version
1102
+
1103
+ Navigation
1104
+ \u2191/\u2193 or j/k Navigate list
1105
+ Enter Select prompt
1106
+ / Search prompts
1107
+ n/p Next/Previous page
1108
+ r Run prompt (open in ChatGPT, Claude, etc.)
1109
+ c Copy prompt (with variable filling)
1110
+ C Copy raw prompt
1111
+ o Open in browser
1112
+ b Go back
1113
+ q Quit
1114
+
1115
+ Examples
1116
+ $ npx prompts.chat
1117
+ $ prompts-chat
1118
+ `, {
1119
+ importMeta: import.meta,
1120
+ flags: {}
1121
+ });
1122
+ function main() {
1123
+ console.clear();
1124
+ const { waitUntilExit } = render(/* @__PURE__ */ jsx4(App, {}), {
1125
+ exitOnCtrlC: true
1126
+ });
1127
+ waitUntilExit().then(() => {
1128
+ console.clear();
1129
+ });
1130
+ }
1131
+ main();
1132
+ //# sourceMappingURL=index.js.map