@hasna/prompts 0.3.11 → 0.3.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli/index.js
CHANGED
|
@@ -11770,6 +11770,35 @@ var init_ids = __esm(() => {
|
|
|
11770
11770
|
init_database();
|
|
11771
11771
|
});
|
|
11772
11772
|
|
|
11773
|
+
// src/types/index.ts
|
|
11774
|
+
var PromptNotFoundError, VersionConflictError, DuplicateSlugError, ProjectNotFoundError;
|
|
11775
|
+
var init_types2 = __esm(() => {
|
|
11776
|
+
PromptNotFoundError = class PromptNotFoundError extends Error {
|
|
11777
|
+
constructor(id) {
|
|
11778
|
+
super(`Prompt not found: ${id}`);
|
|
11779
|
+
this.name = "PromptNotFoundError";
|
|
11780
|
+
}
|
|
11781
|
+
};
|
|
11782
|
+
VersionConflictError = class VersionConflictError extends Error {
|
|
11783
|
+
constructor(id) {
|
|
11784
|
+
super(`Version conflict on prompt: ${id}`);
|
|
11785
|
+
this.name = "VersionConflictError";
|
|
11786
|
+
}
|
|
11787
|
+
};
|
|
11788
|
+
DuplicateSlugError = class DuplicateSlugError extends Error {
|
|
11789
|
+
constructor(slug) {
|
|
11790
|
+
super(`A prompt with slug "${slug}" already exists`);
|
|
11791
|
+
this.name = "DuplicateSlugError";
|
|
11792
|
+
}
|
|
11793
|
+
};
|
|
11794
|
+
ProjectNotFoundError = class ProjectNotFoundError extends Error {
|
|
11795
|
+
constructor(id) {
|
|
11796
|
+
super(`Project not found: ${id}`);
|
|
11797
|
+
this.name = "ProjectNotFoundError";
|
|
11798
|
+
}
|
|
11799
|
+
};
|
|
11800
|
+
});
|
|
11801
|
+
|
|
11773
11802
|
// src/db/collections.ts
|
|
11774
11803
|
function rowToCollection(row) {
|
|
11775
11804
|
return {
|
|
@@ -11908,35 +11937,6 @@ var init_template = __esm(() => {
|
|
|
11908
11937
|
VAR_PATTERN = /\{\{\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*(?:\|\s*(.*?)\s*)?\}\}/g;
|
|
11909
11938
|
});
|
|
11910
11939
|
|
|
11911
|
-
// src/types/index.ts
|
|
11912
|
-
var PromptNotFoundError, VersionConflictError, DuplicateSlugError, ProjectNotFoundError;
|
|
11913
|
-
var init_types2 = __esm(() => {
|
|
11914
|
-
PromptNotFoundError = class PromptNotFoundError extends Error {
|
|
11915
|
-
constructor(id) {
|
|
11916
|
-
super(`Prompt not found: ${id}`);
|
|
11917
|
-
this.name = "PromptNotFoundError";
|
|
11918
|
-
}
|
|
11919
|
-
};
|
|
11920
|
-
VersionConflictError = class VersionConflictError extends Error {
|
|
11921
|
-
constructor(id) {
|
|
11922
|
-
super(`Version conflict on prompt: ${id}`);
|
|
11923
|
-
this.name = "VersionConflictError";
|
|
11924
|
-
}
|
|
11925
|
-
};
|
|
11926
|
-
DuplicateSlugError = class DuplicateSlugError extends Error {
|
|
11927
|
-
constructor(slug) {
|
|
11928
|
-
super(`A prompt with slug "${slug}" already exists`);
|
|
11929
|
-
this.name = "DuplicateSlugError";
|
|
11930
|
-
}
|
|
11931
|
-
};
|
|
11932
|
-
ProjectNotFoundError = class ProjectNotFoundError extends Error {
|
|
11933
|
-
constructor(id) {
|
|
11934
|
-
super(`Project not found: ${id}`);
|
|
11935
|
-
this.name = "ProjectNotFoundError";
|
|
11936
|
-
}
|
|
11937
|
-
};
|
|
11938
|
-
});
|
|
11939
|
-
|
|
11940
11940
|
// src/db/prompts.ts
|
|
11941
11941
|
function rowToPrompt(row) {
|
|
11942
11942
|
return {
|
|
@@ -12338,8 +12338,7 @@ var {
|
|
|
12338
12338
|
} = import__.default;
|
|
12339
12339
|
|
|
12340
12340
|
// src/cli/index.tsx
|
|
12341
|
-
|
|
12342
|
-
import chalk from "chalk";
|
|
12341
|
+
import chalk3 from "chalk";
|
|
12343
12342
|
import { createRequire as createRequire2 } from "module";
|
|
12344
12343
|
|
|
12345
12344
|
// src/db/versions.ts
|
|
@@ -12437,154 +12436,7 @@ function deleteProject(idOrSlug) {
|
|
|
12437
12436
|
}
|
|
12438
12437
|
|
|
12439
12438
|
// src/cli/index.tsx
|
|
12440
|
-
init_database();
|
|
12441
|
-
|
|
12442
|
-
// src/lib/search.ts
|
|
12443
|
-
init_database();
|
|
12444
12439
|
init_prompts();
|
|
12445
|
-
function rowToSearchResult(row, snippet) {
|
|
12446
|
-
return {
|
|
12447
|
-
prompt: {
|
|
12448
|
-
id: row["id"],
|
|
12449
|
-
name: row["name"],
|
|
12450
|
-
slug: row["slug"],
|
|
12451
|
-
title: row["title"],
|
|
12452
|
-
body: row["body"],
|
|
12453
|
-
description: row["description"] ?? null,
|
|
12454
|
-
collection: row["collection"],
|
|
12455
|
-
tags: JSON.parse(row["tags"] || "[]"),
|
|
12456
|
-
variables: JSON.parse(row["variables"] || "[]"),
|
|
12457
|
-
pinned: Boolean(row["pinned"]),
|
|
12458
|
-
next_prompt: row["next_prompt"] ?? null,
|
|
12459
|
-
expires_at: row["expires_at"] ?? null,
|
|
12460
|
-
project_id: row["project_id"] ?? null,
|
|
12461
|
-
is_template: Boolean(row["is_template"]),
|
|
12462
|
-
source: row["source"],
|
|
12463
|
-
version: row["version"],
|
|
12464
|
-
use_count: row["use_count"],
|
|
12465
|
-
last_used_at: row["last_used_at"] ?? null,
|
|
12466
|
-
created_at: row["created_at"],
|
|
12467
|
-
updated_at: row["updated_at"]
|
|
12468
|
-
},
|
|
12469
|
-
score: row["score"] ?? 1,
|
|
12470
|
-
snippet
|
|
12471
|
-
};
|
|
12472
|
-
}
|
|
12473
|
-
function escapeFtsQuery(q) {
|
|
12474
|
-
return q.trim().split(/\s+/).filter(Boolean).map((w) => `"${w.replace(/"/g, '""')}"*`).join(" ");
|
|
12475
|
-
}
|
|
12476
|
-
function searchPrompts(query, filter = {}) {
|
|
12477
|
-
const db = getDatabase();
|
|
12478
|
-
if (!query.trim()) {
|
|
12479
|
-
const prompts = listPrompts(filter);
|
|
12480
|
-
return prompts.map((p) => ({ prompt: p, score: 1 }));
|
|
12481
|
-
}
|
|
12482
|
-
if (hasFts(db)) {
|
|
12483
|
-
const ftsQuery = escapeFtsQuery(query);
|
|
12484
|
-
const conditions = [];
|
|
12485
|
-
const params = [];
|
|
12486
|
-
if (filter.collection) {
|
|
12487
|
-
conditions.push("p.collection = ?");
|
|
12488
|
-
params.push(filter.collection);
|
|
12489
|
-
}
|
|
12490
|
-
if (filter.is_template !== undefined) {
|
|
12491
|
-
conditions.push("p.is_template = ?");
|
|
12492
|
-
params.push(filter.is_template ? 1 : 0);
|
|
12493
|
-
}
|
|
12494
|
-
if (filter.source) {
|
|
12495
|
-
conditions.push("p.source = ?");
|
|
12496
|
-
params.push(filter.source);
|
|
12497
|
-
}
|
|
12498
|
-
if (filter.tags && filter.tags.length > 0) {
|
|
12499
|
-
const tagConds = filter.tags.map(() => "p.tags LIKE ?");
|
|
12500
|
-
conditions.push(`(${tagConds.join(" OR ")})`);
|
|
12501
|
-
for (const tag of filter.tags)
|
|
12502
|
-
params.push(`%"${tag}"%`);
|
|
12503
|
-
}
|
|
12504
|
-
if (filter.project_id !== undefined && filter.project_id !== null) {
|
|
12505
|
-
conditions.push("(p.project_id = ? OR p.project_id IS NULL)");
|
|
12506
|
-
params.push(filter.project_id);
|
|
12507
|
-
}
|
|
12508
|
-
const where = conditions.length > 0 ? `AND ${conditions.join(" AND ")}` : "";
|
|
12509
|
-
const limit = filter.limit ?? 50;
|
|
12510
|
-
const offset = filter.offset ?? 0;
|
|
12511
|
-
try {
|
|
12512
|
-
const rows2 = db.query(`SELECT p.*, bm25(prompts_fts) as score,
|
|
12513
|
-
snippet(prompts_fts, 2, '[', ']', '...', 10) as snippet
|
|
12514
|
-
FROM prompts p
|
|
12515
|
-
INNER JOIN prompts_fts ON prompts_fts.rowid = p.rowid
|
|
12516
|
-
WHERE prompts_fts MATCH ?
|
|
12517
|
-
${where}
|
|
12518
|
-
ORDER BY bm25(prompts_fts)
|
|
12519
|
-
LIMIT ? OFFSET ?`).all(ftsQuery, ...params, limit, offset);
|
|
12520
|
-
return rows2.map((r) => rowToSearchResult(r, r["snippet"]));
|
|
12521
|
-
} catch {}
|
|
12522
|
-
}
|
|
12523
|
-
const like = `%${query}%`;
|
|
12524
|
-
const rows = db.query(`SELECT *, 1 as score FROM prompts
|
|
12525
|
-
WHERE (name LIKE ? OR slug LIKE ? OR title LIKE ? OR body LIKE ? OR description LIKE ? OR tags LIKE ?)
|
|
12526
|
-
ORDER BY use_count DESC, updated_at DESC
|
|
12527
|
-
LIMIT ? OFFSET ?`).all(like, like, like, like, like, like, filter.limit ?? 10, filter.offset ?? 0);
|
|
12528
|
-
return rows.map((r) => rowToSearchResult(r));
|
|
12529
|
-
}
|
|
12530
|
-
function findSimilar(promptId, limit = 5) {
|
|
12531
|
-
const db = getDatabase();
|
|
12532
|
-
const prompt = db.query("SELECT * FROM prompts WHERE id = ?").get(promptId);
|
|
12533
|
-
if (!prompt)
|
|
12534
|
-
return [];
|
|
12535
|
-
const tags = JSON.parse(prompt["tags"] || "[]");
|
|
12536
|
-
const collection = prompt["collection"];
|
|
12537
|
-
if (tags.length === 0) {
|
|
12538
|
-
const rows = db.query("SELECT *, 1 as score FROM prompts WHERE collection = ? AND id != ? ORDER BY use_count DESC LIMIT ?").all(collection, promptId, limit);
|
|
12539
|
-
return rows.map((r) => rowToSearchResult(r));
|
|
12540
|
-
}
|
|
12541
|
-
const allRows = db.query("SELECT * FROM prompts WHERE id != ?").all(promptId);
|
|
12542
|
-
const scored = allRows.map((row) => {
|
|
12543
|
-
const rowTags = JSON.parse(row["tags"] || "[]");
|
|
12544
|
-
const overlap = rowTags.filter((t) => tags.includes(t)).length;
|
|
12545
|
-
const sameCollection = row["collection"] === collection ? 1 : 0;
|
|
12546
|
-
return { row, score: overlap * 2 + sameCollection };
|
|
12547
|
-
});
|
|
12548
|
-
return scored.filter((s) => s.score > 0).sort((a, b) => b.score - a.score).slice(0, limit).map((s) => rowToSearchResult(s.row, undefined));
|
|
12549
|
-
}
|
|
12550
|
-
|
|
12551
|
-
// src/cli/index.tsx
|
|
12552
|
-
init_template();
|
|
12553
|
-
init_importer();
|
|
12554
|
-
|
|
12555
|
-
// src/lib/lint.ts
|
|
12556
|
-
function lintPrompt(p) {
|
|
12557
|
-
const issues = [];
|
|
12558
|
-
const issue = (severity, rule, message) => ({
|
|
12559
|
-
prompt_id: p.id,
|
|
12560
|
-
slug: p.slug,
|
|
12561
|
-
severity,
|
|
12562
|
-
rule,
|
|
12563
|
-
message
|
|
12564
|
-
});
|
|
12565
|
-
if (!p.description) {
|
|
12566
|
-
issues.push(issue("warn", "missing-description", "No description provided"));
|
|
12567
|
-
}
|
|
12568
|
-
if (p.body.trim().length < 10) {
|
|
12569
|
-
issues.push(issue("error", "body-too-short", `Body is only ${p.body.trim().length} characters`));
|
|
12570
|
-
}
|
|
12571
|
-
if (p.tags.length === 0) {
|
|
12572
|
-
issues.push(issue("info", "no-tags", "No tags \u2014 prompt will be harder to discover"));
|
|
12573
|
-
}
|
|
12574
|
-
if (p.is_template) {
|
|
12575
|
-
const undocumented = p.variables.filter((v) => !v.description || v.description.trim() === "");
|
|
12576
|
-
if (undocumented.length > 0) {
|
|
12577
|
-
issues.push(issue("warn", "undocumented-vars", `Template variables without description: ${undocumented.map((v) => v.name).join(", ")}`));
|
|
12578
|
-
}
|
|
12579
|
-
}
|
|
12580
|
-
if (p.collection === "default" && p.use_count === 0) {
|
|
12581
|
-
issues.push(issue("info", "uncollected", "In default collection and never used \u2014 consider organizing"));
|
|
12582
|
-
}
|
|
12583
|
-
return issues;
|
|
12584
|
-
}
|
|
12585
|
-
function lintAll(prompts) {
|
|
12586
|
-
return prompts.map((p) => ({ prompt: p, issues: lintPrompt(p) })).filter((r) => r.issues.length > 0);
|
|
12587
|
-
}
|
|
12588
12440
|
|
|
12589
12441
|
// src/db/schedules.ts
|
|
12590
12442
|
init_database();
|
|
@@ -12997,30 +12849,66 @@ function diffTexts(a, b) {
|
|
|
12997
12849
|
return trace;
|
|
12998
12850
|
}
|
|
12999
12851
|
|
|
12852
|
+
// src/lib/lint.ts
|
|
12853
|
+
function lintPrompt(p) {
|
|
12854
|
+
const issues = [];
|
|
12855
|
+
const issue = (severity, rule, message) => ({
|
|
12856
|
+
prompt_id: p.id,
|
|
12857
|
+
slug: p.slug,
|
|
12858
|
+
severity,
|
|
12859
|
+
rule,
|
|
12860
|
+
message
|
|
12861
|
+
});
|
|
12862
|
+
if (!p.description) {
|
|
12863
|
+
issues.push(issue("warn", "missing-description", "No description provided"));
|
|
12864
|
+
}
|
|
12865
|
+
if (p.body.trim().length < 10) {
|
|
12866
|
+
issues.push(issue("error", "body-too-short", `Body is only ${p.body.trim().length} characters`));
|
|
12867
|
+
}
|
|
12868
|
+
if (p.tags.length === 0) {
|
|
12869
|
+
issues.push(issue("info", "no-tags", "No tags \u2014 prompt will be harder to discover"));
|
|
12870
|
+
}
|
|
12871
|
+
if (p.is_template) {
|
|
12872
|
+
const undocumented = p.variables.filter((v) => !v.description || v.description.trim() === "");
|
|
12873
|
+
if (undocumented.length > 0) {
|
|
12874
|
+
issues.push(issue("warn", "undocumented-vars", `Template variables without description: ${undocumented.map((v) => v.name).join(", ")}`));
|
|
12875
|
+
}
|
|
12876
|
+
}
|
|
12877
|
+
if (p.collection === "default" && p.use_count === 0) {
|
|
12878
|
+
issues.push(issue("info", "uncollected", "In default collection and never used \u2014 consider organizing"));
|
|
12879
|
+
}
|
|
12880
|
+
return issues;
|
|
12881
|
+
}
|
|
12882
|
+
function lintAll(prompts) {
|
|
12883
|
+
return prompts.map((p) => ({ prompt: p, issues: lintPrompt(p) })).filter((r) => r.issues.length > 0);
|
|
12884
|
+
}
|
|
12885
|
+
|
|
13000
12886
|
// src/cli/index.tsx
|
|
13001
|
-
|
|
13002
|
-
|
|
13003
|
-
|
|
13004
|
-
|
|
12887
|
+
init_importer();
|
|
12888
|
+
|
|
12889
|
+
// src/cli/utils.ts
|
|
12890
|
+
init_database();
|
|
12891
|
+
import chalk from "chalk";
|
|
12892
|
+
function isJson(program2) {
|
|
13005
12893
|
return Boolean(program2.opts()["json"]);
|
|
13006
12894
|
}
|
|
13007
|
-
function getActiveProjectId() {
|
|
12895
|
+
function getActiveProjectId(program2) {
|
|
13008
12896
|
const projectName = program2.opts()["project"] ?? process.env["PROMPTS_PROJECT"];
|
|
13009
12897
|
if (!projectName)
|
|
13010
12898
|
return null;
|
|
13011
12899
|
const db = getDatabase();
|
|
13012
12900
|
return resolveProject(db, projectName);
|
|
13013
12901
|
}
|
|
13014
|
-
function output(data) {
|
|
13015
|
-
if (isJson()) {
|
|
12902
|
+
function output(program2, data) {
|
|
12903
|
+
if (isJson(program2)) {
|
|
13016
12904
|
console.log(JSON.stringify(data, null, 2));
|
|
13017
12905
|
} else {
|
|
13018
12906
|
console.log(data);
|
|
13019
12907
|
}
|
|
13020
12908
|
}
|
|
13021
|
-
function handleError(e) {
|
|
12909
|
+
function handleError(program2, e) {
|
|
13022
12910
|
const msg = e instanceof Error ? e.message : String(e);
|
|
13023
|
-
if (isJson()) {
|
|
12911
|
+
if (isJson(program2)) {
|
|
13024
12912
|
console.log(JSON.stringify({ error: msg }));
|
|
13025
12913
|
} else {
|
|
13026
12914
|
console.error(chalk.red("Error: " + msg));
|
|
@@ -13033,322 +12921,468 @@ function fmtPrompt(p) {
|
|
|
13033
12921
|
const pin = p.pinned ? chalk.yellow(" \uD83D\uDCCC") : "";
|
|
13034
12922
|
return `${chalk.bold(p.id)} ${chalk.green(p.slug)}${template}${pin} ${p.title}${tags} ${chalk.gray(p.collection)}`;
|
|
13035
12923
|
}
|
|
13036
|
-
|
|
13037
|
-
|
|
13038
|
-
|
|
13039
|
-
|
|
13040
|
-
|
|
13041
|
-
|
|
13042
|
-
|
|
13043
|
-
|
|
13044
|
-
|
|
13045
|
-
|
|
13046
|
-
|
|
13047
|
-
|
|
13048
|
-
|
|
13049
|
-
|
|
13050
|
-
|
|
13051
|
-
|
|
13052
|
-
|
|
13053
|
-
|
|
13054
|
-
|
|
13055
|
-
|
|
13056
|
-
|
|
13057
|
-
|
|
13058
|
-
|
|
13059
|
-
|
|
13060
|
-
|
|
13061
|
-
|
|
13062
|
-
|
|
13063
|
-
|
|
13064
|
-
|
|
13065
|
-
|
|
13066
|
-
|
|
13067
|
-
|
|
13068
|
-
|
|
13069
|
-
|
|
13070
|
-
|
|
13071
|
-
|
|
13072
|
-
|
|
13073
|
-
|
|
13074
|
-
|
|
13075
|
-
|
|
13076
|
-
|
|
13077
|
-
|
|
13078
|
-
|
|
13079
|
-
|
|
13080
|
-
|
|
13081
|
-
|
|
13082
|
-
|
|
13083
|
-
|
|
13084
|
-
|
|
13085
|
-
|
|
13086
|
-
|
|
13087
|
-
|
|
13088
|
-
let body = prompt.body;
|
|
13089
|
-
if (opts.edit) {
|
|
13090
|
-
const editor = process.env["EDITOR"] ?? process.env["VISUAL"] ?? "nano";
|
|
13091
|
-
const { writeFileSync: writeFileSync2, readFileSync: readFileSync2, unlinkSync } = await import("fs");
|
|
13092
|
-
const { tmpdir } = await import("os");
|
|
13093
|
-
const { join: join7 } = await import("path");
|
|
13094
|
-
const tmp = join7(tmpdir(), `prompts-${prompt.id}-${Date.now()}.md`);
|
|
13095
|
-
writeFileSync2(tmp, body);
|
|
13096
|
-
const proc = Bun.spawnSync([editor, tmp], { stdio: ["inherit", "inherit", "inherit"] });
|
|
13097
|
-
if (proc.exitCode === 0) {
|
|
13098
|
-
body = readFileSync2(tmp, "utf-8");
|
|
13099
|
-
}
|
|
13100
|
-
try {
|
|
13101
|
-
unlinkSync(tmp);
|
|
13102
|
-
} catch {}
|
|
12924
|
+
|
|
12925
|
+
// src/cli/commands/prompts.tsx
|
|
12926
|
+
init_prompts();
|
|
12927
|
+
import chalk2 from "chalk";
|
|
12928
|
+
|
|
12929
|
+
// src/lib/search.ts
|
|
12930
|
+
init_database();
|
|
12931
|
+
init_prompts();
|
|
12932
|
+
function rowToSearchResult(row, snippet) {
|
|
12933
|
+
return {
|
|
12934
|
+
prompt: {
|
|
12935
|
+
id: row["id"],
|
|
12936
|
+
name: row["name"],
|
|
12937
|
+
slug: row["slug"],
|
|
12938
|
+
title: row["title"],
|
|
12939
|
+
body: row["body"],
|
|
12940
|
+
description: row["description"] ?? null,
|
|
12941
|
+
collection: row["collection"],
|
|
12942
|
+
tags: JSON.parse(row["tags"] || "[]"),
|
|
12943
|
+
variables: JSON.parse(row["variables"] || "[]"),
|
|
12944
|
+
pinned: Boolean(row["pinned"]),
|
|
12945
|
+
next_prompt: row["next_prompt"] ?? null,
|
|
12946
|
+
expires_at: row["expires_at"] ?? null,
|
|
12947
|
+
project_id: row["project_id"] ?? null,
|
|
12948
|
+
is_template: Boolean(row["is_template"]),
|
|
12949
|
+
source: row["source"],
|
|
12950
|
+
version: row["version"],
|
|
12951
|
+
use_count: row["use_count"],
|
|
12952
|
+
last_used_at: row["last_used_at"] ?? null,
|
|
12953
|
+
created_at: row["created_at"],
|
|
12954
|
+
updated_at: row["updated_at"]
|
|
12955
|
+
},
|
|
12956
|
+
score: row["score"] ?? 1,
|
|
12957
|
+
snippet
|
|
12958
|
+
};
|
|
12959
|
+
}
|
|
12960
|
+
function escapeFtsQuery(q) {
|
|
12961
|
+
return q.trim().split(/\s+/).filter(Boolean).map((w) => `"${w.replace(/"/g, '""')}"*`).join(" ");
|
|
12962
|
+
}
|
|
12963
|
+
function searchPrompts(query, filter = {}) {
|
|
12964
|
+
const db = getDatabase();
|
|
12965
|
+
if (!query.trim()) {
|
|
12966
|
+
const prompts = listPrompts(filter);
|
|
12967
|
+
return prompts.map((p) => ({ prompt: p, score: 1 }));
|
|
12968
|
+
}
|
|
12969
|
+
if (hasFts(db)) {
|
|
12970
|
+
const ftsQuery = escapeFtsQuery(query);
|
|
12971
|
+
const conditions = [];
|
|
12972
|
+
const params = [];
|
|
12973
|
+
if (filter.collection) {
|
|
12974
|
+
conditions.push("p.collection = ?");
|
|
12975
|
+
params.push(filter.collection);
|
|
13103
12976
|
}
|
|
13104
|
-
if (
|
|
13105
|
-
|
|
13106
|
-
|
|
13107
|
-
console.log(body);
|
|
13108
|
-
if (prompt.next_prompt) {
|
|
13109
|
-
console.error(chalk.gray(`
|
|
13110
|
-
\u2192 next: ${chalk.bold(prompt.next_prompt)}`));
|
|
13111
|
-
}
|
|
12977
|
+
if (filter.is_template !== undefined) {
|
|
12978
|
+
conditions.push("p.is_template = ?");
|
|
12979
|
+
params.push(filter.is_template ? 1 : 0);
|
|
13112
12980
|
}
|
|
13113
|
-
|
|
13114
|
-
|
|
12981
|
+
if (filter.source) {
|
|
12982
|
+
conditions.push("p.source = ?");
|
|
12983
|
+
params.push(filter.source);
|
|
12984
|
+
}
|
|
12985
|
+
if (filter.tags && filter.tags.length > 0) {
|
|
12986
|
+
const tagConds = filter.tags.map(() => "p.tags LIKE ?");
|
|
12987
|
+
conditions.push(`(${tagConds.join(" OR ")})`);
|
|
12988
|
+
for (const tag of filter.tags)
|
|
12989
|
+
params.push(`%"${tag}"%`);
|
|
12990
|
+
}
|
|
12991
|
+
if (filter.project_id !== undefined && filter.project_id !== null) {
|
|
12992
|
+
conditions.push("(p.project_id = ? OR p.project_id IS NULL)");
|
|
12993
|
+
params.push(filter.project_id);
|
|
12994
|
+
}
|
|
12995
|
+
const where = conditions.length > 0 ? `AND ${conditions.join(" AND ")}` : "";
|
|
12996
|
+
const limit = filter.limit ?? 50;
|
|
12997
|
+
const offset = filter.offset ?? 0;
|
|
12998
|
+
try {
|
|
12999
|
+
const rows2 = db.query(`SELECT p.*, bm25(prompts_fts) as score,
|
|
13000
|
+
snippet(prompts_fts, 2, '[', ']', '...', 10) as snippet
|
|
13001
|
+
FROM prompts p
|
|
13002
|
+
INNER JOIN prompts_fts ON prompts_fts.rowid = p.rowid
|
|
13003
|
+
WHERE prompts_fts MATCH ?
|
|
13004
|
+
${where}
|
|
13005
|
+
ORDER BY bm25(prompts_fts)
|
|
13006
|
+
LIMIT ? OFFSET ?`).all(ftsQuery, ...params, limit, offset);
|
|
13007
|
+
return rows2.map((r) => rowToSearchResult(r, r["snippet"]));
|
|
13008
|
+
} catch {}
|
|
13115
13009
|
}
|
|
13116
|
-
}
|
|
13117
|
-
|
|
13118
|
-
|
|
13119
|
-
|
|
13120
|
-
|
|
13121
|
-
|
|
13122
|
-
|
|
13123
|
-
|
|
13124
|
-
|
|
13010
|
+
const like = `%${query}%`;
|
|
13011
|
+
const rows = db.query(`SELECT *, 1 as score FROM prompts
|
|
13012
|
+
WHERE (name LIKE ? OR slug LIKE ? OR title LIKE ? OR body LIKE ? OR description LIKE ? OR tags LIKE ?)
|
|
13013
|
+
ORDER BY use_count DESC, updated_at DESC
|
|
13014
|
+
LIMIT ? OFFSET ?`).all(like, like, like, like, like, like, filter.limit ?? 10, filter.offset ?? 0);
|
|
13015
|
+
return rows.map((r) => rowToSearchResult(r));
|
|
13016
|
+
}
|
|
13017
|
+
function findSimilar(promptId, limit = 5) {
|
|
13018
|
+
const db = getDatabase();
|
|
13019
|
+
const prompt = db.query("SELECT * FROM prompts WHERE id = ?").get(promptId);
|
|
13020
|
+
if (!prompt)
|
|
13021
|
+
return [];
|
|
13022
|
+
const tags = JSON.parse(prompt["tags"] || "[]");
|
|
13023
|
+
const collection = prompt["collection"];
|
|
13024
|
+
if (tags.length === 0) {
|
|
13025
|
+
const rows = db.query("SELECT *, 1 as score FROM prompts WHERE collection = ? AND id != ? ORDER BY use_count DESC LIMIT ?").all(collection, promptId, limit);
|
|
13026
|
+
return rows.map((r) => rowToSearchResult(r));
|
|
13125
13027
|
}
|
|
13126
|
-
|
|
13127
|
-
|
|
13128
|
-
|
|
13129
|
-
const
|
|
13130
|
-
|
|
13131
|
-
|
|
13132
|
-
|
|
13133
|
-
|
|
13134
|
-
|
|
13135
|
-
|
|
13136
|
-
|
|
13137
|
-
|
|
13138
|
-
|
|
13028
|
+
const allRows = db.query("SELECT * FROM prompts WHERE id != ?").all(promptId);
|
|
13029
|
+
const scored = allRows.map((row) => {
|
|
13030
|
+
const rowTags = JSON.parse(row["tags"] || "[]");
|
|
13031
|
+
const overlap = rowTags.filter((t) => tags.includes(t)).length;
|
|
13032
|
+
const sameCollection = row["collection"] === collection ? 1 : 0;
|
|
13033
|
+
return { row, score: overlap * 2 + sameCollection };
|
|
13034
|
+
});
|
|
13035
|
+
return scored.filter((s) => s.score > 0).sort((a, b) => b.score - a.score).slice(0, limit).map((s) => rowToSearchResult(s.row, undefined));
|
|
13036
|
+
}
|
|
13037
|
+
|
|
13038
|
+
// src/cli/commands/prompts.tsx
|
|
13039
|
+
init_template();
|
|
13040
|
+
function registerPromptCommands(program2) {
|
|
13041
|
+
program2.command("save <title>").description("Save a new prompt (or update existing by slug)").option("-b, --body <body>", "Prompt body (use - to read from stdin)").option("-f, --file <path>", "Read body from file").option("-s, --slug <slug>", "Custom slug").option("-d, --description <desc>", "Short description").option("-c, --collection <name>", "Collection", "default").option("-t, --tags <tags>", "Comma-separated tags").option("--source <source>", "Source: manual|ai-session|imported", "manual").option("--agent <name>", "Agent name (for attribution)").option("--force", "Save even if a similar prompt already exists").option("--pin", "Pin immediately so it appears first in all lists").action(async (title, opts) => {
|
|
13042
|
+
try {
|
|
13043
|
+
let body = opts["body"] ?? "";
|
|
13044
|
+
if (opts["file"]) {
|
|
13045
|
+
const { readFileSync: readFileSync2 } = await import("fs");
|
|
13046
|
+
body = readFileSync2(opts["file"], "utf-8");
|
|
13047
|
+
} else if (opts["body"] === "-" || !opts["body"] && !opts["file"]) {
|
|
13048
|
+
const chunks = [];
|
|
13049
|
+
for await (const chunk of process.stdin)
|
|
13050
|
+
chunks.push(chunk);
|
|
13051
|
+
body = Buffer.concat(chunks).toString("utf-8").trim();
|
|
13052
|
+
}
|
|
13053
|
+
if (!body)
|
|
13054
|
+
handleError(program2, "No body provided. Use --body, --file, or pipe via stdin.");
|
|
13055
|
+
const project_id = getActiveProjectId(program2);
|
|
13056
|
+
const { prompt, created, duplicate_warning } = upsertPrompt({
|
|
13057
|
+
title,
|
|
13058
|
+
body,
|
|
13059
|
+
slug: opts["slug"],
|
|
13060
|
+
description: opts["description"],
|
|
13061
|
+
collection: opts["collection"],
|
|
13062
|
+
tags: opts["tags"] ? opts["tags"].split(",").map((t) => t.trim()) : [],
|
|
13063
|
+
source: opts["source"] || "manual",
|
|
13064
|
+
changed_by: opts["agent"],
|
|
13065
|
+
project_id
|
|
13066
|
+
}, Boolean(opts["force"]));
|
|
13067
|
+
if (duplicate_warning && !isJson(program2)) {
|
|
13068
|
+
console.warn(chalk2.yellow(`Warning: ${duplicate_warning}`));
|
|
13069
|
+
}
|
|
13070
|
+
if (opts["pin"])
|
|
13071
|
+
pinPrompt(prompt.id, true);
|
|
13072
|
+
if (isJson(program2)) {
|
|
13073
|
+
output(program2, opts["pin"] ? { ...prompt, pinned: true } : prompt);
|
|
13074
|
+
} else {
|
|
13075
|
+
const action = created ? chalk2.green("Created") : chalk2.yellow("Updated");
|
|
13076
|
+
console.log(`${action} ${chalk2.bold(prompt.id)} \u2014 ${chalk2.green(prompt.slug)}`);
|
|
13077
|
+
console.log(chalk2.gray(` Title: ${prompt.title}`));
|
|
13078
|
+
console.log(chalk2.gray(` Collection: ${prompt.collection}`));
|
|
13079
|
+
if (opts["pin"])
|
|
13080
|
+
console.log(chalk2.yellow(" \uD83D\uDCCC Pinned"));
|
|
13081
|
+
if (prompt.is_template) {
|
|
13082
|
+
const vars = extractVariableInfo(prompt.body);
|
|
13083
|
+
console.log(chalk2.cyan(` Template vars: ${vars.map((v) => v.name).join(", ")}`));
|
|
13084
|
+
}
|
|
13085
|
+
}
|
|
13086
|
+
} catch (e) {
|
|
13087
|
+
handleError(program2, e);
|
|
13139
13088
|
}
|
|
13140
|
-
|
|
13141
|
-
|
|
13142
|
-
|
|
13143
|
-
|
|
13144
|
-
|
|
13145
|
-
|
|
13146
|
-
|
|
13147
|
-
|
|
13089
|
+
});
|
|
13090
|
+
program2.command("use <id>").description("Get a prompt's body and increment its use counter").option("--edit", "Open in $EDITOR for quick tweaks before printing").action(async (id, opts) => {
|
|
13091
|
+
try {
|
|
13092
|
+
const prompt = usePrompt(id);
|
|
13093
|
+
let body = prompt.body;
|
|
13094
|
+
if (opts.edit) {
|
|
13095
|
+
const editor = process.env["EDITOR"] ?? process.env["VISUAL"] ?? "nano";
|
|
13096
|
+
const { writeFileSync: writeFileSync2, readFileSync: readFileSync2, unlinkSync } = await import("fs");
|
|
13097
|
+
const { tmpdir } = await import("os");
|
|
13098
|
+
const { join: join7 } = await import("path");
|
|
13099
|
+
const tmp = join7(tmpdir(), `prompts-${prompt.id}-${Date.now()}.md`);
|
|
13100
|
+
writeFileSync2(tmp, body);
|
|
13101
|
+
const proc = Bun.spawnSync([editor, tmp], { stdio: ["inherit", "inherit", "inherit"] });
|
|
13102
|
+
if (proc.exitCode === 0) {
|
|
13103
|
+
body = readFileSync2(tmp, "utf-8");
|
|
13104
|
+
}
|
|
13105
|
+
try {
|
|
13106
|
+
unlinkSync(tmp);
|
|
13107
|
+
} catch {}
|
|
13108
|
+
}
|
|
13109
|
+
if (isJson(program2)) {
|
|
13110
|
+
output(program2, { ...prompt, body });
|
|
13111
|
+
} else {
|
|
13112
|
+
console.log(body);
|
|
13113
|
+
if (prompt.next_prompt) {
|
|
13114
|
+
console.error(chalk2.gray(`
|
|
13115
|
+
\u2192 next: ${chalk2.bold(prompt.next_prompt)}`));
|
|
13116
|
+
}
|
|
13117
|
+
}
|
|
13118
|
+
} catch (e) {
|
|
13119
|
+
handleError(program2, e);
|
|
13120
|
+
}
|
|
13121
|
+
});
|
|
13122
|
+
program2.command("get <id>").description("Get prompt details without incrementing use counter").action((id) => {
|
|
13123
|
+
try {
|
|
13124
|
+
const prompt = getPrompt(id);
|
|
13125
|
+
if (!prompt)
|
|
13126
|
+
handleError(program2, `Prompt not found: ${id}`);
|
|
13127
|
+
output(program2, isJson(program2) ? prompt : fmtPrompt(prompt));
|
|
13128
|
+
} catch (e) {
|
|
13129
|
+
handleError(program2, e);
|
|
13130
|
+
}
|
|
13131
|
+
});
|
|
13132
|
+
program2.command("list").description("List prompts").option("-c, --collection <name>", "Filter by collection").option("-t, --tags <tags>", "Filter by tags (comma-separated)").option("--templates", "Show only templates").option("--recent", "Sort by recently used").option("-n, --limit <n>", "Max results", "50").action((opts) => {
|
|
13133
|
+
try {
|
|
13134
|
+
const project_id = getActiveProjectId(program2);
|
|
13135
|
+
let prompts = listPrompts({
|
|
13136
|
+
collection: opts["collection"],
|
|
13137
|
+
tags: opts["tags"] ? opts["tags"].split(",").map((t) => t.trim()) : undefined,
|
|
13138
|
+
is_template: opts["templates"] ? true : undefined,
|
|
13139
|
+
limit: parseInt(opts["limit"]) || 50,
|
|
13140
|
+
...project_id !== null ? { project_id } : {}
|
|
13141
|
+
});
|
|
13142
|
+
if (opts["recent"]) {
|
|
13143
|
+
prompts = prompts.filter((p) => p.last_used_at !== null).sort((a, b) => (b.last_used_at ?? "").localeCompare(a.last_used_at ?? ""));
|
|
13144
|
+
}
|
|
13145
|
+
if (isJson(program2)) {
|
|
13146
|
+
output(program2, prompts);
|
|
13147
|
+
} else if (prompts.length === 0) {
|
|
13148
|
+
console.log(chalk2.gray("No prompts found."));
|
|
13149
|
+
} else {
|
|
13150
|
+
for (const p of prompts)
|
|
13151
|
+
console.log(fmtPrompt(p));
|
|
13152
|
+
console.log(chalk2.gray(`
|
|
13148
13153
|
${prompts.length} prompt(s)`));
|
|
13154
|
+
}
|
|
13155
|
+
} catch (e) {
|
|
13156
|
+
handleError(program2, e);
|
|
13149
13157
|
}
|
|
13150
|
-
}
|
|
13151
|
-
|
|
13152
|
-
|
|
13153
|
-
|
|
13154
|
-
|
|
13155
|
-
|
|
13156
|
-
|
|
13157
|
-
|
|
13158
|
-
|
|
13159
|
-
|
|
13160
|
-
|
|
13161
|
-
|
|
13162
|
-
|
|
13163
|
-
|
|
13164
|
-
|
|
13165
|
-
|
|
13166
|
-
|
|
13167
|
-
|
|
13168
|
-
|
|
13169
|
-
|
|
13170
|
-
|
|
13171
|
-
const highlighted = r.snippet.replace(/\[([^\]]+)\]/g, (_m, word) => chalk.yellowBright(word));
|
|
13172
|
-
console.log(chalk.gray(" ") + chalk.gray(highlighted));
|
|
13158
|
+
});
|
|
13159
|
+
program2.command("search <query>").description("Full-text search across prompts (FTS5)").option("-c, --collection <name>").option("-t, --tags <tags>").option("-n, --limit <n>", "Max results", "20").action((query, opts) => {
|
|
13160
|
+
try {
|
|
13161
|
+
const project_id = getActiveProjectId(program2);
|
|
13162
|
+
const results = searchPrompts(query, {
|
|
13163
|
+
collection: opts["collection"],
|
|
13164
|
+
tags: opts["tags"] ? opts["tags"].split(",").map((t) => t.trim()) : undefined,
|
|
13165
|
+
limit: parseInt(opts["limit"] ?? "20") || 20,
|
|
13166
|
+
...project_id !== null ? { project_id } : {}
|
|
13167
|
+
});
|
|
13168
|
+
if (isJson(program2)) {
|
|
13169
|
+
output(program2, results);
|
|
13170
|
+
} else if (results.length === 0) {
|
|
13171
|
+
console.log(chalk2.gray("No results."));
|
|
13172
|
+
} else {
|
|
13173
|
+
for (const r of results) {
|
|
13174
|
+
console.log(fmtPrompt(r.prompt));
|
|
13175
|
+
if (r.snippet) {
|
|
13176
|
+
const highlighted = r.snippet.replace(/\[([^\]]+)\]/g, (_m, word) => chalk2.yellowBright(word));
|
|
13177
|
+
console.log(chalk2.gray(" ") + chalk2.gray(highlighted));
|
|
13178
|
+
}
|
|
13173
13179
|
}
|
|
13174
|
-
|
|
13175
|
-
console.log(chalk.gray(`
|
|
13180
|
+
console.log(chalk2.gray(`
|
|
13176
13181
|
${results.length} result(s)`));
|
|
13182
|
+
}
|
|
13183
|
+
} catch (e) {
|
|
13184
|
+
handleError(program2, e);
|
|
13177
13185
|
}
|
|
13178
|
-
}
|
|
13179
|
-
|
|
13180
|
-
|
|
13181
|
-
|
|
13182
|
-
|
|
13183
|
-
|
|
13184
|
-
|
|
13185
|
-
|
|
13186
|
-
|
|
13187
|
-
|
|
13188
|
-
|
|
13189
|
-
|
|
13190
|
-
|
|
13191
|
-
|
|
13192
|
-
|
|
13193
|
-
|
|
13194
|
-
|
|
13195
|
-
|
|
13196
|
-
console.log(result.rendered);
|
|
13197
|
-
if (result.missing_vars.length > 0)
|
|
13198
|
-
console.error(chalk.yellow(`
|
|
13186
|
+
});
|
|
13187
|
+
program2.command("render <id>").description("Render a template prompt by filling in {{variables}}").option("-v, --var <assignments...>", "Variable assignments as key=value").action((id, opts) => {
|
|
13188
|
+
try {
|
|
13189
|
+
const prompt = usePrompt(id);
|
|
13190
|
+
const vars = {};
|
|
13191
|
+
for (const assignment of opts.var ?? []) {
|
|
13192
|
+
const eq = assignment.indexOf("=");
|
|
13193
|
+
if (eq === -1)
|
|
13194
|
+
handleError(program2, `Invalid var format: ${assignment}. Use key=value`);
|
|
13195
|
+
vars[assignment.slice(0, eq)] = assignment.slice(eq + 1);
|
|
13196
|
+
}
|
|
13197
|
+
const result = renderTemplate(prompt.body, vars);
|
|
13198
|
+
if (isJson(program2)) {
|
|
13199
|
+
output(program2, result);
|
|
13200
|
+
} else {
|
|
13201
|
+
console.log(result.rendered);
|
|
13202
|
+
if (result.missing_vars.length > 0)
|
|
13203
|
+
console.error(chalk2.yellow(`
|
|
13199
13204
|
Warning: missing vars: ${result.missing_vars.join(", ")}`));
|
|
13200
|
-
|
|
13201
|
-
|
|
13205
|
+
if (result.used_defaults.length > 0)
|
|
13206
|
+
console.error(chalk2.gray(`Used defaults: ${result.used_defaults.join(", ")}`));
|
|
13207
|
+
}
|
|
13208
|
+
} catch (e) {
|
|
13209
|
+
handleError(program2, e);
|
|
13202
13210
|
}
|
|
13203
|
-
}
|
|
13204
|
-
|
|
13205
|
-
|
|
13206
|
-
});
|
|
13207
|
-
|
|
13208
|
-
|
|
13209
|
-
|
|
13210
|
-
|
|
13211
|
-
|
|
13212
|
-
|
|
13213
|
-
|
|
13214
|
-
|
|
13215
|
-
|
|
13216
|
-
|
|
13217
|
-
console.log(fmtPrompt(p));
|
|
13218
|
-
console.log(chalk.cyan(` vars: ${vars.map((v) => v.required ? v.name : `${v.name}?`).join(", ")}`));
|
|
13211
|
+
});
|
|
13212
|
+
program2.command("templates").description("List template prompts").option("-c, --collection <name>").action((opts) => {
|
|
13213
|
+
try {
|
|
13214
|
+
const prompts = listPrompts({ is_template: true, collection: opts["collection"] });
|
|
13215
|
+
if (isJson(program2)) {
|
|
13216
|
+
output(program2, prompts);
|
|
13217
|
+
} else if (prompts.length === 0) {
|
|
13218
|
+
console.log(chalk2.gray("No templates found."));
|
|
13219
|
+
} else {
|
|
13220
|
+
for (const p of prompts) {
|
|
13221
|
+
const vars = extractVariableInfo(p.body);
|
|
13222
|
+
console.log(fmtPrompt(p));
|
|
13223
|
+
console.log(chalk2.cyan(` vars: ${vars.map((v) => v.required ? v.name : `${v.name}?`).join(", ")}`));
|
|
13224
|
+
}
|
|
13219
13225
|
}
|
|
13226
|
+
} catch (e) {
|
|
13227
|
+
handleError(program2, e);
|
|
13220
13228
|
}
|
|
13221
|
-
}
|
|
13222
|
-
|
|
13223
|
-
|
|
13224
|
-
|
|
13225
|
-
|
|
13226
|
-
|
|
13227
|
-
|
|
13228
|
-
|
|
13229
|
-
|
|
13230
|
-
|
|
13231
|
-
|
|
13232
|
-
|
|
13233
|
-
|
|
13234
|
-
|
|
13235
|
-
|
|
13236
|
-
|
|
13237
|
-
|
|
13238
|
-
|
|
13239
|
-
const def = v.default !== null ? chalk.gray(` (default: "${v.default}")`) : "";
|
|
13240
|
-
console.log(` ${chalk.bold(v.name)} ${req}${def}`);
|
|
13229
|
+
});
|
|
13230
|
+
program2.command("inspect <id>").description("Show a prompt's variables (for templates)").action((id) => {
|
|
13231
|
+
try {
|
|
13232
|
+
const prompt = getPrompt(id);
|
|
13233
|
+
if (!prompt)
|
|
13234
|
+
handleError(program2, `Prompt not found: ${id}`);
|
|
13235
|
+
const vars = extractVariableInfo(prompt.body);
|
|
13236
|
+
if (isJson(program2)) {
|
|
13237
|
+
output(program2, vars);
|
|
13238
|
+
} else if (vars.length === 0) {
|
|
13239
|
+
console.log(chalk2.gray("No template variables found."));
|
|
13240
|
+
} else {
|
|
13241
|
+
console.log(chalk2.bold(`Variables for ${prompt.slug}:`));
|
|
13242
|
+
for (const v of vars) {
|
|
13243
|
+
const req = v.required ? chalk2.red("required") : chalk2.green("optional");
|
|
13244
|
+
const def = v.default !== null ? chalk2.gray(` (default: "${v.default}")`) : "";
|
|
13245
|
+
console.log(` ${chalk2.bold(v.name)} ${req}${def}`);
|
|
13246
|
+
}
|
|
13241
13247
|
}
|
|
13248
|
+
} catch (e) {
|
|
13249
|
+
handleError(program2, e);
|
|
13242
13250
|
}
|
|
13243
|
-
}
|
|
13244
|
-
|
|
13245
|
-
|
|
13246
|
-
|
|
13247
|
-
|
|
13248
|
-
|
|
13249
|
-
|
|
13250
|
-
|
|
13251
|
-
|
|
13252
|
-
|
|
13253
|
-
collection: opts["collection"] ?? undefined,
|
|
13254
|
-
tags: opts["tags"] ? opts["tags"].split(",").map((t) => t.trim()) : undefined,
|
|
13255
|
-
changed_by: opts["agent"] ?? undefined
|
|
13256
|
-
});
|
|
13257
|
-
if (isJson())
|
|
13258
|
-
output(prompt);
|
|
13259
|
-
else
|
|
13260
|
-
console.log(`${chalk.yellow("Updated")} ${chalk.bold(prompt.id)} \u2014 ${chalk.green(prompt.slug)}`);
|
|
13261
|
-
} catch (e) {
|
|
13262
|
-
handleError(e);
|
|
13263
|
-
}
|
|
13264
|
-
});
|
|
13265
|
-
program2.command("delete <id>").description("Delete a prompt").option("-y, --yes", "Skip confirmation").action(async (id, opts) => {
|
|
13266
|
-
try {
|
|
13267
|
-
const prompt = getPrompt(id);
|
|
13268
|
-
if (!prompt)
|
|
13269
|
-
handleError(`Prompt not found: ${id}`);
|
|
13270
|
-
if (!opts.yes && !isJson()) {
|
|
13271
|
-
const { createInterface } = await import("readline");
|
|
13272
|
-
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
13273
|
-
await new Promise((resolve) => {
|
|
13274
|
-
rl.question(chalk.yellow(`Delete "${prompt.slug}"? [y/N] `), (ans) => {
|
|
13275
|
-
rl.close();
|
|
13276
|
-
if (ans.toLowerCase() !== "y") {
|
|
13277
|
-
console.log("Cancelled.");
|
|
13278
|
-
process.exit(0);
|
|
13279
|
-
}
|
|
13280
|
-
resolve();
|
|
13281
|
-
});
|
|
13251
|
+
});
|
|
13252
|
+
program2.command("update <id>").description("Update a prompt's fields").option("--title <title>").option("-b, --body <body>").option("-d, --description <desc>").option("-c, --collection <name>").option("-t, --tags <tags>").option("--agent <name>").action((id, opts) => {
|
|
13253
|
+
try {
|
|
13254
|
+
const prompt = updatePrompt(id, {
|
|
13255
|
+
title: opts["title"] ?? undefined,
|
|
13256
|
+
body: opts["body"] ?? undefined,
|
|
13257
|
+
description: opts["description"] ?? undefined,
|
|
13258
|
+
collection: opts["collection"] ?? undefined,
|
|
13259
|
+
tags: opts["tags"] ? opts["tags"].split(",").map((t) => t.trim()) : undefined,
|
|
13260
|
+
changed_by: opts["agent"] ?? undefined
|
|
13282
13261
|
});
|
|
13262
|
+
if (isJson(program2))
|
|
13263
|
+
output(program2, prompt);
|
|
13264
|
+
else
|
|
13265
|
+
console.log(`${chalk2.yellow("Updated")} ${chalk2.bold(prompt.id)} \u2014 ${chalk2.green(prompt.slug)}`);
|
|
13266
|
+
} catch (e) {
|
|
13267
|
+
handleError(program2, e);
|
|
13283
13268
|
}
|
|
13284
|
-
|
|
13285
|
-
|
|
13286
|
-
|
|
13287
|
-
|
|
13288
|
-
|
|
13289
|
-
|
|
13290
|
-
|
|
13291
|
-
|
|
13292
|
-
});
|
|
13269
|
+
});
|
|
13270
|
+
program2.command("delete <id>").description("Delete a prompt").option("-y, --yes", "Skip confirmation").action(async (id, opts) => {
|
|
13271
|
+
try {
|
|
13272
|
+
const prompt = getPrompt(id);
|
|
13273
|
+
if (!prompt)
|
|
13274
|
+
handleError(program2, `Prompt not found: ${id}`);
|
|
13275
|
+
if (!opts.yes && !isJson(program2)) {
|
|
13276
|
+
const { createInterface } = await import("readline");
|
|
13277
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
13278
|
+
await new Promise((resolve) => {
|
|
13279
|
+
rl.question(chalk2.yellow(`Delete "${prompt.slug}"? [y/N] `), (ans) => {
|
|
13280
|
+
rl.close();
|
|
13281
|
+
if (ans.toLowerCase() !== "y") {
|
|
13282
|
+
console.log("Cancelled.");
|
|
13283
|
+
process.exit(0);
|
|
13284
|
+
}
|
|
13285
|
+
resolve();
|
|
13286
|
+
});
|
|
13287
|
+
});
|
|
13288
|
+
}
|
|
13289
|
+
deletePrompt(id);
|
|
13290
|
+
if (isJson(program2))
|
|
13291
|
+
output(program2, { deleted: true, id: prompt.id });
|
|
13292
|
+
else
|
|
13293
|
+
console.log(chalk2.red(`Deleted ${prompt.slug}`));
|
|
13294
|
+
} catch (e) {
|
|
13295
|
+
handleError(program2, e);
|
|
13296
|
+
}
|
|
13297
|
+
});
|
|
13298
|
+
program2.command("similar <id>").description("Find prompts similar to a given prompt (by tag overlap and collection)").option("-n, --limit <n>", "Max results", "5").action((id, opts) => {
|
|
13299
|
+
try {
|
|
13300
|
+
const prompt = getPrompt(id);
|
|
13301
|
+
if (!prompt)
|
|
13302
|
+
handleError(program2, `Prompt not found: ${id}`);
|
|
13303
|
+
const results = findSimilar(prompt.id, parseInt(opts["limit"] ?? "5") || 5);
|
|
13304
|
+
if (isJson(program2)) {
|
|
13305
|
+
output(program2, results);
|
|
13306
|
+
return;
|
|
13307
|
+
}
|
|
13308
|
+
if (results.length === 0) {
|
|
13309
|
+
console.log(chalk2.gray("No similar prompts found."));
|
|
13310
|
+
return;
|
|
13311
|
+
}
|
|
13312
|
+
for (const r of results) {
|
|
13313
|
+
const score = chalk2.gray(`${Math.round(r.score * 100)}%`);
|
|
13314
|
+
console.log(`${fmtPrompt(r.prompt)} ${score}`);
|
|
13315
|
+
}
|
|
13316
|
+
} catch (e) {
|
|
13317
|
+
handleError(program2, e);
|
|
13318
|
+
}
|
|
13319
|
+
});
|
|
13320
|
+
}
|
|
13321
|
+
|
|
13322
|
+
// src/cli/index.tsx
|
|
13323
|
+
var require2 = createRequire2(import.meta.url);
|
|
13324
|
+
var pkg = require2("../../package.json");
|
|
13325
|
+
var program2 = new Command().name("prompts").version(pkg.version).description("Reusable prompt library \u2014 save, search, render prompts from any AI session").option("--json", "Output as JSON").option("--project <name>", "Active project (name, slug, or ID) for scoped operations");
|
|
13326
|
+
registerPromptCommands(program2);
|
|
13293
13327
|
program2.command("history <id>").description("Show version history for a prompt").action((id) => {
|
|
13294
13328
|
try {
|
|
13295
13329
|
const prompt = getPrompt(id);
|
|
13296
13330
|
if (!prompt)
|
|
13297
|
-
handleError(`Prompt not found: ${id}`);
|
|
13331
|
+
handleError(program2, `Prompt not found: ${id}`);
|
|
13298
13332
|
const versions = listVersions(prompt.id);
|
|
13299
|
-
if (isJson()) {
|
|
13300
|
-
output(versions);
|
|
13333
|
+
if (isJson(program2)) {
|
|
13334
|
+
output(program2, versions);
|
|
13301
13335
|
} else {
|
|
13302
|
-
console.log(
|
|
13336
|
+
console.log(chalk3.bold(`Version history for ${prompt.slug}:`));
|
|
13303
13337
|
for (const v of versions) {
|
|
13304
|
-
const current = v.version === prompt.version ?
|
|
13305
|
-
const by = v.changed_by ?
|
|
13306
|
-
console.log(` v${v.version} ${
|
|
13338
|
+
const current = v.version === prompt.version ? chalk3.green(" \u2190 current") : "";
|
|
13339
|
+
const by = v.changed_by ? chalk3.gray(` by ${v.changed_by}`) : "";
|
|
13340
|
+
console.log(` v${v.version} ${chalk3.gray(v.created_at)}${by}${current}`);
|
|
13307
13341
|
}
|
|
13308
13342
|
}
|
|
13309
13343
|
} catch (e) {
|
|
13310
|
-
handleError(e);
|
|
13344
|
+
handleError(program2, e);
|
|
13311
13345
|
}
|
|
13312
13346
|
});
|
|
13313
13347
|
program2.command("restore <id> <version>").description("Restore a prompt to a previous version").option("--agent <name>").action((id, version, opts) => {
|
|
13314
13348
|
try {
|
|
13315
13349
|
const prompt = getPrompt(id);
|
|
13316
13350
|
if (!prompt)
|
|
13317
|
-
handleError(`Prompt not found: ${id}`);
|
|
13351
|
+
handleError(program2, `Prompt not found: ${id}`);
|
|
13318
13352
|
restoreVersion(prompt.id, parseInt(version), opts["agent"]);
|
|
13319
|
-
if (isJson())
|
|
13320
|
-
output({ restored: true, id: prompt.id, version: parseInt(version) });
|
|
13353
|
+
if (isJson(program2))
|
|
13354
|
+
output(program2, { restored: true, id: prompt.id, version: parseInt(version) });
|
|
13321
13355
|
else
|
|
13322
|
-
console.log(
|
|
13356
|
+
console.log(chalk3.green(`Restored ${prompt.slug} to v${version}`));
|
|
13323
13357
|
} catch (e) {
|
|
13324
|
-
handleError(e);
|
|
13358
|
+
handleError(program2, e);
|
|
13325
13359
|
}
|
|
13326
13360
|
});
|
|
13327
13361
|
program2.command("collections").description("List all collections").action(() => {
|
|
13328
13362
|
try {
|
|
13329
13363
|
const cols = listCollections();
|
|
13330
|
-
if (isJson()) {
|
|
13331
|
-
output(cols);
|
|
13364
|
+
if (isJson(program2)) {
|
|
13365
|
+
output(program2, cols);
|
|
13332
13366
|
} else {
|
|
13333
13367
|
for (const c of cols) {
|
|
13334
|
-
console.log(`${
|
|
13368
|
+
console.log(`${chalk3.bold(c.name)} ${chalk3.gray(`${c.prompt_count} prompt(s)`)}`);
|
|
13335
13369
|
if (c.description)
|
|
13336
|
-
console.log(
|
|
13370
|
+
console.log(chalk3.gray(" " + c.description));
|
|
13337
13371
|
}
|
|
13338
13372
|
}
|
|
13339
13373
|
} catch (e) {
|
|
13340
|
-
handleError(e);
|
|
13374
|
+
handleError(program2, e);
|
|
13341
13375
|
}
|
|
13342
13376
|
});
|
|
13343
13377
|
program2.command("move <id> <collection>").description("Move a prompt to a different collection").action((id, collection) => {
|
|
13344
13378
|
try {
|
|
13345
13379
|
movePrompt(id, collection);
|
|
13346
|
-
if (isJson())
|
|
13347
|
-
output({ moved: true, id, collection });
|
|
13380
|
+
if (isJson(program2))
|
|
13381
|
+
output(program2, { moved: true, id, collection });
|
|
13348
13382
|
else
|
|
13349
|
-
console.log(`${
|
|
13383
|
+
console.log(`${chalk3.green("Moved")} ${id} \u2192 ${chalk3.bold(collection)}`);
|
|
13350
13384
|
} catch (e) {
|
|
13351
|
-
handleError(e);
|
|
13385
|
+
handleError(program2, e);
|
|
13352
13386
|
}
|
|
13353
13387
|
});
|
|
13354
13388
|
program2.command("export").description("Export prompts as JSON").option("-c, --collection <name>").option("-o, --output <file>", "Write to file instead of stdout").action(async (opts) => {
|
|
@@ -13358,12 +13392,12 @@ program2.command("export").description("Export prompts as JSON").option("-c, --c
|
|
|
13358
13392
|
if (opts["output"]) {
|
|
13359
13393
|
const { writeFileSync: writeFileSync2 } = await import("fs");
|
|
13360
13394
|
writeFileSync2(opts["output"], json);
|
|
13361
|
-
console.log(
|
|
13395
|
+
console.log(chalk3.green(`Exported ${data.prompts.length} prompt(s) to ${opts["output"]}`));
|
|
13362
13396
|
} else {
|
|
13363
13397
|
console.log(json);
|
|
13364
13398
|
}
|
|
13365
13399
|
} catch (e) {
|
|
13366
|
-
handleError(e);
|
|
13400
|
+
handleError(program2, e);
|
|
13367
13401
|
}
|
|
13368
13402
|
});
|
|
13369
13403
|
program2.command("import <file>").description("Import prompts from a JSON file").option("--agent <name>").action(async (file, opts) => {
|
|
@@ -13372,100 +13406,100 @@ program2.command("import <file>").description("Import prompts from a JSON file")
|
|
|
13372
13406
|
const raw = JSON.parse(readFileSync2(file, "utf-8"));
|
|
13373
13407
|
const items = Array.isArray(raw) ? raw : raw.prompts ?? [];
|
|
13374
13408
|
const results = importFromJson(items, opts["agent"]);
|
|
13375
|
-
if (isJson())
|
|
13376
|
-
output(results);
|
|
13409
|
+
if (isJson(program2))
|
|
13410
|
+
output(program2, results);
|
|
13377
13411
|
else {
|
|
13378
|
-
console.log(
|
|
13412
|
+
console.log(chalk3.green(`Created: ${results.created}, Updated: ${results.updated}`));
|
|
13379
13413
|
if (results.errors.length > 0) {
|
|
13380
|
-
console.error(
|
|
13414
|
+
console.error(chalk3.red(`Errors: ${results.errors.length}`));
|
|
13381
13415
|
for (const e of results.errors)
|
|
13382
|
-
console.error(
|
|
13416
|
+
console.error(chalk3.red(` ${e.item}: ${e.error}`));
|
|
13383
13417
|
}
|
|
13384
13418
|
}
|
|
13385
13419
|
} catch (e) {
|
|
13386
|
-
handleError(e);
|
|
13420
|
+
handleError(program2, e);
|
|
13387
13421
|
}
|
|
13388
13422
|
});
|
|
13389
13423
|
program2.command("stats").description("Show usage statistics").action(() => {
|
|
13390
13424
|
try {
|
|
13391
13425
|
const stats = getPromptStats();
|
|
13392
|
-
if (isJson()) {
|
|
13393
|
-
output(stats);
|
|
13426
|
+
if (isJson(program2)) {
|
|
13427
|
+
output(program2, stats);
|
|
13394
13428
|
} else {
|
|
13395
|
-
console.log(
|
|
13429
|
+
console.log(chalk3.bold("Prompt Stats"));
|
|
13396
13430
|
console.log(` Total: ${stats.total_prompts} Templates: ${stats.total_templates} Collections: ${stats.total_collections}`);
|
|
13397
13431
|
if (stats.most_used.length > 0) {
|
|
13398
|
-
console.log(
|
|
13432
|
+
console.log(chalk3.bold(`
|
|
13399
13433
|
Most used:`));
|
|
13400
13434
|
for (const p of stats.most_used)
|
|
13401
|
-
console.log(` ${
|
|
13435
|
+
console.log(` ${chalk3.green(p.slug)} ${chalk3.gray(`${p.use_count}\xD7`)}`);
|
|
13402
13436
|
}
|
|
13403
13437
|
if (stats.by_collection.length > 0) {
|
|
13404
|
-
console.log(
|
|
13438
|
+
console.log(chalk3.bold(`
|
|
13405
13439
|
By collection:`));
|
|
13406
13440
|
for (const c of stats.by_collection)
|
|
13407
|
-
console.log(` ${
|
|
13441
|
+
console.log(` ${chalk3.bold(c.collection)} ${chalk3.gray(`${c.count}`)}`);
|
|
13408
13442
|
}
|
|
13409
13443
|
}
|
|
13410
13444
|
} catch (e) {
|
|
13411
|
-
handleError(e);
|
|
13445
|
+
handleError(program2, e);
|
|
13412
13446
|
}
|
|
13413
13447
|
});
|
|
13414
13448
|
program2.command("recent [n]").description("Show recently used prompts (default: 10)").action((n) => {
|
|
13415
13449
|
try {
|
|
13416
13450
|
const limit = parseInt(n ?? "10") || 10;
|
|
13417
13451
|
const prompts = listPrompts({ limit }).filter((p) => p.last_used_at !== null).sort((a, b) => (b.last_used_at ?? "").localeCompare(a.last_used_at ?? "")).slice(0, limit);
|
|
13418
|
-
if (isJson()) {
|
|
13419
|
-
output(prompts);
|
|
13452
|
+
if (isJson(program2)) {
|
|
13453
|
+
output(program2, prompts);
|
|
13420
13454
|
return;
|
|
13421
13455
|
}
|
|
13422
13456
|
if (prompts.length === 0) {
|
|
13423
|
-
console.log(
|
|
13457
|
+
console.log(chalk3.gray("No recently used prompts."));
|
|
13424
13458
|
return;
|
|
13425
13459
|
}
|
|
13426
13460
|
for (const p of prompts) {
|
|
13427
|
-
const ago =
|
|
13428
|
-
console.log(`${
|
|
13461
|
+
const ago = chalk3.gray(new Date(p.last_used_at).toLocaleString());
|
|
13462
|
+
console.log(`${chalk3.bold(p.id)} ${chalk3.green(p.slug)} ${p.title} ${ago}`);
|
|
13429
13463
|
}
|
|
13430
13464
|
} catch (e) {
|
|
13431
|
-
handleError(e);
|
|
13465
|
+
handleError(program2, e);
|
|
13432
13466
|
}
|
|
13433
13467
|
});
|
|
13434
13468
|
program2.command("lint").description("Check prompt quality: missing descriptions, undocumented vars, short bodies, no tags").option("-c, --collection <name>", "Lint only this collection").action((opts) => {
|
|
13435
13469
|
try {
|
|
13436
13470
|
const prompts = listPrompts({ collection: opts["collection"], limit: 1e4 });
|
|
13437
13471
|
const results = lintAll(prompts);
|
|
13438
|
-
if (isJson()) {
|
|
13439
|
-
output(results);
|
|
13472
|
+
if (isJson(program2)) {
|
|
13473
|
+
output(program2, results);
|
|
13440
13474
|
return;
|
|
13441
13475
|
}
|
|
13442
13476
|
if (results.length === 0) {
|
|
13443
|
-
console.log(
|
|
13477
|
+
console.log(chalk3.green("\u2713 All prompts pass lint."));
|
|
13444
13478
|
return;
|
|
13445
13479
|
}
|
|
13446
13480
|
let errors = 0, warns = 0, infos = 0;
|
|
13447
13481
|
for (const { prompt: p, issues } of results) {
|
|
13448
13482
|
console.log(`
|
|
13449
|
-
${
|
|
13483
|
+
${chalk3.bold(p.slug)} ${chalk3.gray(p.id)}`);
|
|
13450
13484
|
for (const issue of issues) {
|
|
13451
13485
|
if (issue.severity === "error") {
|
|
13452
|
-
console.log(
|
|
13486
|
+
console.log(chalk3.red(` \u2717 [${issue.rule}] ${issue.message}`));
|
|
13453
13487
|
errors++;
|
|
13454
13488
|
} else if (issue.severity === "warn") {
|
|
13455
|
-
console.log(
|
|
13489
|
+
console.log(chalk3.yellow(` \u26A0 [${issue.rule}] ${issue.message}`));
|
|
13456
13490
|
warns++;
|
|
13457
13491
|
} else {
|
|
13458
|
-
console.log(
|
|
13492
|
+
console.log(chalk3.gray(` \u2139 [${issue.rule}] ${issue.message}`));
|
|
13459
13493
|
infos++;
|
|
13460
13494
|
}
|
|
13461
13495
|
}
|
|
13462
13496
|
}
|
|
13463
|
-
console.log(
|
|
13497
|
+
console.log(chalk3.bold(`
|
|
13464
13498
|
${results.length} prompt(s) with issues \u2014 ${errors} errors, ${warns} warnings, ${infos} info`));
|
|
13465
13499
|
if (errors > 0)
|
|
13466
13500
|
process.exit(1);
|
|
13467
13501
|
} catch (e) {
|
|
13468
|
-
handleError(e);
|
|
13502
|
+
handleError(program2, e);
|
|
13469
13503
|
}
|
|
13470
13504
|
});
|
|
13471
13505
|
program2.command("stale [days]").description("List prompts not used in N days (default: 30)").action((days) => {
|
|
@@ -13476,54 +13510,54 @@ program2.command("stale [days]").description("List prompts not used in N days (d
|
|
|
13476
13510
|
const stale = all.filter((p) => p.last_used_at === null || p.last_used_at < cutoff).sort((a, b) => (a.last_used_at ?? "").localeCompare(b.last_used_at ?? ""));
|
|
13477
13511
|
const now = new Date().toISOString();
|
|
13478
13512
|
const expired = all.filter((p) => p.expires_at !== null && p.expires_at < now);
|
|
13479
|
-
if (isJson()) {
|
|
13480
|
-
output({ stale, expired });
|
|
13513
|
+
if (isJson(program2)) {
|
|
13514
|
+
output(program2, { stale, expired });
|
|
13481
13515
|
return;
|
|
13482
13516
|
}
|
|
13483
13517
|
if (expired.length > 0) {
|
|
13484
|
-
console.log(
|
|
13518
|
+
console.log(chalk3.red(`
|
|
13485
13519
|
Expired (${expired.length}):`));
|
|
13486
13520
|
for (const p of expired)
|
|
13487
|
-
console.log(
|
|
13521
|
+
console.log(chalk3.red(` \u2717 ${p.slug}`) + chalk3.gray(` expired ${new Date(p.expires_at).toLocaleDateString()}`));
|
|
13488
13522
|
}
|
|
13489
13523
|
if (stale.length === 0 && expired.length === 0) {
|
|
13490
|
-
console.log(
|
|
13524
|
+
console.log(chalk3.green(`No stale prompts (threshold: ${threshold} days).`));
|
|
13491
13525
|
return;
|
|
13492
13526
|
}
|
|
13493
13527
|
if (stale.length > 0) {
|
|
13494
|
-
console.log(
|
|
13528
|
+
console.log(chalk3.bold(`
|
|
13495
13529
|
Stale prompts (not used in ${threshold}+ days):`));
|
|
13496
13530
|
for (const p of stale) {
|
|
13497
|
-
const last = p.last_used_at ?
|
|
13498
|
-
console.log(` ${
|
|
13531
|
+
const last = p.last_used_at ? chalk3.gray(new Date(p.last_used_at).toLocaleDateString()) : chalk3.red("never");
|
|
13532
|
+
console.log(` ${chalk3.green(p.slug)} ${chalk3.gray(`${p.use_count}\xD7`)} last used: ${last}`);
|
|
13499
13533
|
}
|
|
13500
13534
|
}
|
|
13501
|
-
console.log(
|
|
13535
|
+
console.log(chalk3.gray(`
|
|
13502
13536
|
${stale.length} stale prompt(s)`));
|
|
13503
13537
|
} catch (e) {
|
|
13504
|
-
handleError(e);
|
|
13538
|
+
handleError(program2, e);
|
|
13505
13539
|
}
|
|
13506
13540
|
});
|
|
13507
13541
|
program2.command("pin <id>").description("Pin a prompt so it always appears first in lists").action((id) => {
|
|
13508
13542
|
try {
|
|
13509
13543
|
const p = pinPrompt(id, true);
|
|
13510
|
-
if (isJson())
|
|
13511
|
-
output(p);
|
|
13544
|
+
if (isJson(program2))
|
|
13545
|
+
output(program2, p);
|
|
13512
13546
|
else
|
|
13513
|
-
console.log(
|
|
13547
|
+
console.log(chalk3.yellow(`\uD83D\uDCCC Pinned ${chalk3.bold(p.slug)}`));
|
|
13514
13548
|
} catch (e) {
|
|
13515
|
-
handleError(e);
|
|
13549
|
+
handleError(program2, e);
|
|
13516
13550
|
}
|
|
13517
13551
|
});
|
|
13518
13552
|
program2.command("unpin <id>").description("Unpin a prompt").action((id) => {
|
|
13519
13553
|
try {
|
|
13520
13554
|
const p = pinPrompt(id, false);
|
|
13521
|
-
if (isJson())
|
|
13522
|
-
output(p);
|
|
13555
|
+
if (isJson(program2))
|
|
13556
|
+
output(program2, p);
|
|
13523
13557
|
else
|
|
13524
|
-
console.log(
|
|
13558
|
+
console.log(chalk3.gray(`Unpinned ${chalk3.bold(p.slug)}`));
|
|
13525
13559
|
} catch (e) {
|
|
13526
|
-
handleError(e);
|
|
13560
|
+
handleError(program2, e);
|
|
13527
13561
|
}
|
|
13528
13562
|
});
|
|
13529
13563
|
program2.command("copy <id>").description("Copy prompt body to clipboard and increment use counter").action(async (id) => {
|
|
@@ -13548,96 +13582,96 @@ program2.command("copy <id>").description("Copy prompt body to clipboard and inc
|
|
|
13548
13582
|
await proc.exited;
|
|
13549
13583
|
}
|
|
13550
13584
|
} else {
|
|
13551
|
-
handleError("Clipboard not supported on this platform. Use `prompts use` instead.");
|
|
13585
|
+
handleError(program2, "Clipboard not supported on this platform. Use `prompts use` instead.");
|
|
13552
13586
|
}
|
|
13553
|
-
if (isJson())
|
|
13554
|
-
output({ copied: true, id: prompt.id, slug: prompt.slug });
|
|
13587
|
+
if (isJson(program2))
|
|
13588
|
+
output(program2, { copied: true, id: prompt.id, slug: prompt.slug });
|
|
13555
13589
|
else
|
|
13556
|
-
console.log(
|
|
13590
|
+
console.log(chalk3.green(`Copied ${chalk3.bold(prompt.slug)} to clipboard`));
|
|
13557
13591
|
} catch (e) {
|
|
13558
|
-
handleError(e);
|
|
13592
|
+
handleError(program2, e);
|
|
13559
13593
|
}
|
|
13560
13594
|
});
|
|
13561
13595
|
var projectCmd = program2.command("project").description("Manage projects");
|
|
13562
13596
|
projectCmd.command("create <name>").description("Create a new project").option("-d, --description <desc>", "Short description").option("--path <path>", "Filesystem path this project maps to").action((name, opts) => {
|
|
13563
13597
|
try {
|
|
13564
13598
|
const project = createProject({ name, description: opts["description"], path: opts["path"] });
|
|
13565
|
-
if (isJson())
|
|
13566
|
-
output(project);
|
|
13599
|
+
if (isJson(program2))
|
|
13600
|
+
output(program2, project);
|
|
13567
13601
|
else {
|
|
13568
|
-
console.log(`${
|
|
13602
|
+
console.log(`${chalk3.green("Created")} project ${chalk3.bold(project.name)} \u2014 ${chalk3.gray(project.slug)}`);
|
|
13569
13603
|
if (project.description)
|
|
13570
|
-
console.log(
|
|
13604
|
+
console.log(chalk3.gray(` ${project.description}`));
|
|
13571
13605
|
}
|
|
13572
13606
|
} catch (e) {
|
|
13573
|
-
handleError(e);
|
|
13607
|
+
handleError(program2, e);
|
|
13574
13608
|
}
|
|
13575
13609
|
});
|
|
13576
13610
|
projectCmd.command("list").description("List all projects").action(() => {
|
|
13577
13611
|
try {
|
|
13578
13612
|
const projects = listProjects();
|
|
13579
|
-
if (isJson()) {
|
|
13580
|
-
output(projects);
|
|
13613
|
+
if (isJson(program2)) {
|
|
13614
|
+
output(program2, projects);
|
|
13581
13615
|
return;
|
|
13582
13616
|
}
|
|
13583
13617
|
if (projects.length === 0) {
|
|
13584
|
-
console.log(
|
|
13618
|
+
console.log(chalk3.gray("No projects."));
|
|
13585
13619
|
return;
|
|
13586
13620
|
}
|
|
13587
13621
|
for (const p of projects) {
|
|
13588
|
-
console.log(`${
|
|
13622
|
+
console.log(`${chalk3.bold(p.name)} ${chalk3.gray(p.slug)} ${chalk3.cyan(`${p.prompt_count} prompt(s)`)}`);
|
|
13589
13623
|
if (p.description)
|
|
13590
|
-
console.log(
|
|
13624
|
+
console.log(chalk3.gray(` ${p.description}`));
|
|
13591
13625
|
}
|
|
13592
13626
|
} catch (e) {
|
|
13593
|
-
handleError(e);
|
|
13627
|
+
handleError(program2, e);
|
|
13594
13628
|
}
|
|
13595
13629
|
});
|
|
13596
13630
|
projectCmd.command("get <id>").description("Get project details").action((id) => {
|
|
13597
13631
|
try {
|
|
13598
13632
|
const project = getProject(id);
|
|
13599
13633
|
if (!project)
|
|
13600
|
-
handleError(`Project not found: ${id}`);
|
|
13601
|
-
output(isJson() ? project : `${
|
|
13634
|
+
handleError(program2, `Project not found: ${id}`);
|
|
13635
|
+
output(program2, isJson(program2) ? project : `${chalk3.bold(project.name)} ${chalk3.gray(project.slug)} ${chalk3.cyan(`${project.prompt_count} prompt(s)`)}`);
|
|
13602
13636
|
} catch (e) {
|
|
13603
|
-
handleError(e);
|
|
13637
|
+
handleError(program2, e);
|
|
13604
13638
|
}
|
|
13605
13639
|
});
|
|
13606
13640
|
projectCmd.command("prompts <id>").description("List all prompts for a project (project-scoped + globals)").option("-n, --limit <n>", "Max results", "100").action((id, opts) => {
|
|
13607
13641
|
try {
|
|
13608
13642
|
const project = getProject(id);
|
|
13609
13643
|
if (!project)
|
|
13610
|
-
handleError(`Project not found: ${id}`);
|
|
13644
|
+
handleError(program2, `Project not found: ${id}`);
|
|
13611
13645
|
const prompts = listPrompts({ project_id: project.id, limit: parseInt(opts["limit"] ?? "100") || 100 });
|
|
13612
|
-
if (isJson()) {
|
|
13613
|
-
output(prompts);
|
|
13646
|
+
if (isJson(program2)) {
|
|
13647
|
+
output(program2, prompts);
|
|
13614
13648
|
return;
|
|
13615
13649
|
}
|
|
13616
13650
|
if (prompts.length === 0) {
|
|
13617
|
-
console.log(
|
|
13651
|
+
console.log(chalk3.gray("No prompts."));
|
|
13618
13652
|
return;
|
|
13619
13653
|
}
|
|
13620
|
-
console.log(
|
|
13654
|
+
console.log(chalk3.bold(`Prompts for project: ${project.name}`));
|
|
13621
13655
|
for (const p of prompts) {
|
|
13622
|
-
const scope = p.project_id ?
|
|
13656
|
+
const scope = p.project_id ? chalk3.cyan(" [project]") : chalk3.gray(" [global]");
|
|
13623
13657
|
console.log(fmtPrompt(p) + scope);
|
|
13624
13658
|
}
|
|
13625
|
-
console.log(
|
|
13659
|
+
console.log(chalk3.gray(`
|
|
13626
13660
|
${prompts.length} prompt(s)`));
|
|
13627
13661
|
} catch (e) {
|
|
13628
|
-
handleError(e);
|
|
13662
|
+
handleError(program2, e);
|
|
13629
13663
|
}
|
|
13630
13664
|
});
|
|
13631
13665
|
projectCmd.command("delete <id>").description("Delete a project (prompts become global)").option("-y, --yes", "Skip confirmation").action(async (id, opts) => {
|
|
13632
13666
|
try {
|
|
13633
13667
|
const project = getProject(id);
|
|
13634
13668
|
if (!project)
|
|
13635
|
-
handleError(`Project not found: ${id}`);
|
|
13636
|
-
if (!opts.yes && !isJson()) {
|
|
13669
|
+
handleError(program2, `Project not found: ${id}`);
|
|
13670
|
+
if (!opts.yes && !isJson(program2)) {
|
|
13637
13671
|
const { createInterface } = await import("readline");
|
|
13638
13672
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
13639
13673
|
await new Promise((resolve) => {
|
|
13640
|
-
rl.question(
|
|
13674
|
+
rl.question(chalk3.yellow(`Delete project "${project.name}"? Prompts will become global. [y/N] `), (ans) => {
|
|
13641
13675
|
rl.close();
|
|
13642
13676
|
if (ans.toLowerCase() !== "y") {
|
|
13643
13677
|
console.log("Cancelled.");
|
|
@@ -13648,94 +13682,94 @@ projectCmd.command("delete <id>").description("Delete a project (prompts become
|
|
|
13648
13682
|
});
|
|
13649
13683
|
}
|
|
13650
13684
|
deleteProject(id);
|
|
13651
|
-
if (isJson())
|
|
13652
|
-
output({ deleted: true, id: project.id });
|
|
13685
|
+
if (isJson(program2))
|
|
13686
|
+
output(program2, { deleted: true, id: project.id });
|
|
13653
13687
|
else
|
|
13654
|
-
console.log(
|
|
13688
|
+
console.log(chalk3.red(`Deleted project ${project.name}`));
|
|
13655
13689
|
} catch (e) {
|
|
13656
|
-
handleError(e);
|
|
13690
|
+
handleError(program2, e);
|
|
13657
13691
|
}
|
|
13658
13692
|
});
|
|
13659
13693
|
program2.command("audit").description("Check for orphaned project refs, empty collections, missing history, near-duplicate slugs, expired prompts").action(() => {
|
|
13660
13694
|
try {
|
|
13661
13695
|
const report = runAudit();
|
|
13662
|
-
if (isJson()) {
|
|
13663
|
-
output(report);
|
|
13696
|
+
if (isJson(program2)) {
|
|
13697
|
+
output(program2, report);
|
|
13664
13698
|
return;
|
|
13665
13699
|
}
|
|
13666
13700
|
if (report.issues.length === 0) {
|
|
13667
|
-
console.log(
|
|
13701
|
+
console.log(chalk3.green("\u2713 No audit issues found."));
|
|
13668
13702
|
return;
|
|
13669
13703
|
}
|
|
13670
13704
|
for (const issue of report.issues) {
|
|
13671
|
-
const sym = issue.severity === "error" ?
|
|
13672
|
-
const slug = issue.slug ?
|
|
13705
|
+
const sym = issue.severity === "error" ? chalk3.red("\u2717") : issue.severity === "warn" ? chalk3.yellow("\u26A0") : chalk3.gray("\u2139");
|
|
13706
|
+
const slug = issue.slug ? chalk3.green(` ${issue.slug}`) : "";
|
|
13673
13707
|
console.log(`${sym}${slug} ${issue.message}`);
|
|
13674
13708
|
}
|
|
13675
|
-
console.log(
|
|
13709
|
+
console.log(chalk3.bold(`
|
|
13676
13710
|
${report.issues.length} issue(s) \u2014 ${report.errors} errors, ${report.warnings} warnings, ${report.info} info`));
|
|
13677
13711
|
if (report.errors > 0)
|
|
13678
13712
|
process.exit(1);
|
|
13679
13713
|
} catch (e) {
|
|
13680
|
-
handleError(e);
|
|
13714
|
+
handleError(program2, e);
|
|
13681
13715
|
}
|
|
13682
13716
|
});
|
|
13683
13717
|
program2.command("unused").description("List prompts that have never been used (use_count = 0)").option("-c, --collection <name>").option("-n, --limit <n>", "Max results", "50").action((opts) => {
|
|
13684
13718
|
try {
|
|
13685
13719
|
const all = listPrompts({ collection: opts["collection"], limit: parseInt(opts["limit"] ?? "50") || 50 });
|
|
13686
13720
|
const unused = all.filter((p) => p.use_count === 0).sort((a, b) => a.created_at.localeCompare(b.created_at));
|
|
13687
|
-
if (isJson()) {
|
|
13688
|
-
output(unused);
|
|
13721
|
+
if (isJson(program2)) {
|
|
13722
|
+
output(program2, unused);
|
|
13689
13723
|
return;
|
|
13690
13724
|
}
|
|
13691
13725
|
if (unused.length === 0) {
|
|
13692
|
-
console.log(
|
|
13726
|
+
console.log(chalk3.green("All prompts have been used at least once."));
|
|
13693
13727
|
return;
|
|
13694
13728
|
}
|
|
13695
|
-
console.log(
|
|
13729
|
+
console.log(chalk3.bold(`Unused prompts (${unused.length}):`));
|
|
13696
13730
|
for (const p of unused) {
|
|
13697
|
-
console.log(` ${fmtPrompt(p)} ${
|
|
13731
|
+
console.log(` ${fmtPrompt(p)} ${chalk3.gray(`created ${new Date(p.created_at).toLocaleDateString()}`)}`);
|
|
13698
13732
|
}
|
|
13699
13733
|
} catch (e) {
|
|
13700
|
-
handleError(e);
|
|
13734
|
+
handleError(program2, e);
|
|
13701
13735
|
}
|
|
13702
13736
|
});
|
|
13703
13737
|
program2.command("trending").description("Most used prompts in the last N days").option("--days <n>", "Lookback window in days", "7").option("-n, --limit <n>", "Max results", "10").action((opts) => {
|
|
13704
13738
|
try {
|
|
13705
13739
|
const results = getTrending(parseInt(opts["days"] ?? "7") || 7, parseInt(opts["limit"] ?? "10") || 10);
|
|
13706
|
-
if (isJson()) {
|
|
13707
|
-
output(results);
|
|
13740
|
+
if (isJson(program2)) {
|
|
13741
|
+
output(program2, results);
|
|
13708
13742
|
return;
|
|
13709
13743
|
}
|
|
13710
13744
|
if (results.length === 0) {
|
|
13711
|
-
console.log(
|
|
13745
|
+
console.log(chalk3.gray("No usage data yet."));
|
|
13712
13746
|
return;
|
|
13713
13747
|
}
|
|
13714
|
-
console.log(
|
|
13748
|
+
console.log(chalk3.bold(`Trending (last ${opts["days"] ?? "7"} days):`));
|
|
13715
13749
|
for (const r of results) {
|
|
13716
|
-
console.log(` ${
|
|
13750
|
+
console.log(` ${chalk3.green(r.slug)} ${chalk3.bold(String(r.uses))}\xD7 ${chalk3.gray(r.title)}`);
|
|
13717
13751
|
}
|
|
13718
13752
|
} catch (e) {
|
|
13719
|
-
handleError(e);
|
|
13753
|
+
handleError(program2, e);
|
|
13720
13754
|
}
|
|
13721
13755
|
});
|
|
13722
13756
|
program2.command("expire <id> [date]").description("Set expiry date for a prompt (ISO date, e.g. 2026-12-31). Use 'none' to clear.").action((id, date) => {
|
|
13723
13757
|
try {
|
|
13724
13758
|
const expiresAt = !date || date === "none" ? null : new Date(date).toISOString();
|
|
13725
13759
|
const p = setExpiry(id, expiresAt);
|
|
13726
|
-
if (isJson())
|
|
13727
|
-
output(p);
|
|
13760
|
+
if (isJson(program2))
|
|
13761
|
+
output(program2, p);
|
|
13728
13762
|
else
|
|
13729
|
-
console.log(expiresAt ?
|
|
13763
|
+
console.log(expiresAt ? chalk3.yellow(`Expires ${p.slug} on ${new Date(expiresAt).toLocaleDateString()}`) : chalk3.gray(`Cleared expiry for ${p.slug}`));
|
|
13730
13764
|
} catch (e) {
|
|
13731
|
-
handleError(e);
|
|
13765
|
+
handleError(program2, e);
|
|
13732
13766
|
}
|
|
13733
13767
|
});
|
|
13734
13768
|
program2.command("duplicate <id>").description("Clone a prompt with a new slug").option("-s, --to <slug>", "New slug (auto-generated if omitted)").option("--title <title>", "New title (defaults to 'Copy of <original>')").action((id, opts) => {
|
|
13735
13769
|
try {
|
|
13736
13770
|
const source = getPrompt(id);
|
|
13737
13771
|
if (!source)
|
|
13738
|
-
handleError(`Prompt not found: ${id}`);
|
|
13772
|
+
handleError(program2, `Prompt not found: ${id}`);
|
|
13739
13773
|
const p = source;
|
|
13740
13774
|
const { prompt } = upsertPrompt({
|
|
13741
13775
|
title: opts["title"] ?? `Copy of ${p.title}`,
|
|
@@ -13746,43 +13780,43 @@ program2.command("duplicate <id>").description("Clone a prompt with a new slug")
|
|
|
13746
13780
|
tags: p.tags,
|
|
13747
13781
|
source: "manual"
|
|
13748
13782
|
});
|
|
13749
|
-
if (isJson())
|
|
13750
|
-
output(prompt);
|
|
13783
|
+
if (isJson(program2))
|
|
13784
|
+
output(program2, prompt);
|
|
13751
13785
|
else
|
|
13752
|
-
console.log(`${
|
|
13786
|
+
console.log(`${chalk3.green("Duplicated")} ${chalk3.bold(p.slug)} \u2192 ${chalk3.bold(prompt.slug)}`);
|
|
13753
13787
|
} catch (e) {
|
|
13754
|
-
handleError(e);
|
|
13788
|
+
handleError(program2, e);
|
|
13755
13789
|
}
|
|
13756
13790
|
});
|
|
13757
13791
|
program2.command("diff <id> <v1> [v2]").description("Show diff between two versions of a prompt (v2 defaults to current)").action((id, v1, v2) => {
|
|
13758
13792
|
try {
|
|
13759
13793
|
const prompt = getPrompt(id);
|
|
13760
13794
|
if (!prompt)
|
|
13761
|
-
handleError(`Prompt not found: ${id}`);
|
|
13795
|
+
handleError(program2, `Prompt not found: ${id}`);
|
|
13762
13796
|
const versions = listVersions(prompt.id);
|
|
13763
13797
|
const versionA = versions.find((v) => v.version === parseInt(v1));
|
|
13764
13798
|
if (!versionA)
|
|
13765
|
-
handleError(`Version ${v1} not found`);
|
|
13799
|
+
handleError(program2, `Version ${v1} not found`);
|
|
13766
13800
|
const bodyB = v2 ? versions.find((v) => v.version === parseInt(v2))?.body ?? null : prompt.body;
|
|
13767
13801
|
if (bodyB === null)
|
|
13768
|
-
handleError(`Version ${v2} not found`);
|
|
13802
|
+
handleError(program2, `Version ${v2} not found`);
|
|
13769
13803
|
const lines = diffTexts(versionA.body, bodyB);
|
|
13770
|
-
if (isJson()) {
|
|
13771
|
-
output(lines);
|
|
13804
|
+
if (isJson(program2)) {
|
|
13805
|
+
output(program2, lines);
|
|
13772
13806
|
return;
|
|
13773
13807
|
}
|
|
13774
13808
|
const label2 = v2 ? `v${v2}` : "current";
|
|
13775
|
-
console.log(
|
|
13809
|
+
console.log(chalk3.bold(`${prompt.slug}: v${v1} \u2192 ${label2}`));
|
|
13776
13810
|
for (const l of lines) {
|
|
13777
13811
|
if (l.type === "added")
|
|
13778
|
-
console.log(
|
|
13812
|
+
console.log(chalk3.green(`+ ${l.content}`));
|
|
13779
13813
|
else if (l.type === "removed")
|
|
13780
|
-
console.log(
|
|
13814
|
+
console.log(chalk3.red(`- ${l.content}`));
|
|
13781
13815
|
else
|
|
13782
|
-
console.log(
|
|
13816
|
+
console.log(chalk3.gray(` ${l.content}`));
|
|
13783
13817
|
}
|
|
13784
13818
|
} catch (e) {
|
|
13785
|
-
handleError(e);
|
|
13819
|
+
handleError(program2, e);
|
|
13786
13820
|
}
|
|
13787
13821
|
});
|
|
13788
13822
|
program2.command("chain <id> [next]").description("Set the next prompt in a chain, or show the chain for a prompt. Use 'none' to clear.").action((id, next) => {
|
|
@@ -13790,15 +13824,15 @@ program2.command("chain <id> [next]").description("Set the next prompt in a chai
|
|
|
13790
13824
|
if (next !== undefined) {
|
|
13791
13825
|
const nextSlug = next === "none" ? null : next;
|
|
13792
13826
|
const p = setNextPrompt(id, nextSlug);
|
|
13793
|
-
if (isJson())
|
|
13794
|
-
output(p);
|
|
13827
|
+
if (isJson(program2))
|
|
13828
|
+
output(program2, p);
|
|
13795
13829
|
else
|
|
13796
|
-
console.log(nextSlug ? `${
|
|
13830
|
+
console.log(nextSlug ? `${chalk3.green(p.slug)} \u2192 ${chalk3.bold(nextSlug)}` : chalk3.gray(`Cleared chain for ${p.slug}`));
|
|
13797
13831
|
return;
|
|
13798
13832
|
}
|
|
13799
13833
|
const prompt = getPrompt(id);
|
|
13800
13834
|
if (!prompt)
|
|
13801
|
-
handleError(`Prompt not found: ${id}`);
|
|
13835
|
+
handleError(program2, `Prompt not found: ${id}`);
|
|
13802
13836
|
const chain = [];
|
|
13803
13837
|
let cur = prompt;
|
|
13804
13838
|
const seen = new Set;
|
|
@@ -13807,35 +13841,13 @@ program2.command("chain <id> [next]").description("Set the next prompt in a chai
|
|
|
13807
13841
|
seen.add(cur.id);
|
|
13808
13842
|
cur = cur.next_prompt ? getPrompt(cur.next_prompt) : null;
|
|
13809
13843
|
}
|
|
13810
|
-
if (isJson()) {
|
|
13811
|
-
output(chain);
|
|
13844
|
+
if (isJson(program2)) {
|
|
13845
|
+
output(program2, chain);
|
|
13812
13846
|
return;
|
|
13813
13847
|
}
|
|
13814
|
-
console.log(chain.map((c) =>
|
|
13815
|
-
} catch (e) {
|
|
13816
|
-
handleError(e);
|
|
13817
|
-
}
|
|
13818
|
-
});
|
|
13819
|
-
program2.command("similar <id>").description("Find prompts similar to a given prompt (by tag overlap and collection)").option("-n, --limit <n>", "Max results", "5").action((id, opts) => {
|
|
13820
|
-
try {
|
|
13821
|
-
const prompt = getPrompt(id);
|
|
13822
|
-
if (!prompt)
|
|
13823
|
-
handleError(`Prompt not found: ${id}`);
|
|
13824
|
-
const results = findSimilar(prompt.id, parseInt(opts["limit"] ?? "5") || 5);
|
|
13825
|
-
if (isJson()) {
|
|
13826
|
-
output(results);
|
|
13827
|
-
return;
|
|
13828
|
-
}
|
|
13829
|
-
if (results.length === 0) {
|
|
13830
|
-
console.log(chalk.gray("No similar prompts found."));
|
|
13831
|
-
return;
|
|
13832
|
-
}
|
|
13833
|
-
for (const r of results) {
|
|
13834
|
-
const score = chalk.gray(`${Math.round(r.score * 100)}%`);
|
|
13835
|
-
console.log(`${fmtPrompt(r.prompt)} ${score}`);
|
|
13836
|
-
}
|
|
13848
|
+
console.log(chain.map((c) => chalk3.green(c.slug)).join(chalk3.gray(" \u2192 ")));
|
|
13837
13849
|
} catch (e) {
|
|
13838
|
-
handleError(e);
|
|
13850
|
+
handleError(program2, e);
|
|
13839
13851
|
}
|
|
13840
13852
|
});
|
|
13841
13853
|
program2.command("completion [shell]").description("Output shell completion script (zsh or bash)").action((shell) => {
|
|
@@ -13845,7 +13857,7 @@ program2.command("completion [shell]").description("Output shell completion scri
|
|
|
13845
13857
|
} else if (sh === "bash") {
|
|
13846
13858
|
console.log(generateBashCompletion());
|
|
13847
13859
|
} else {
|
|
13848
|
-
handleError(`Unknown shell: ${sh}. Use 'zsh' or 'bash'.`);
|
|
13860
|
+
handleError(program2, `Unknown shell: ${sh}. Use 'zsh' or 'bash'.`);
|
|
13849
13861
|
}
|
|
13850
13862
|
});
|
|
13851
13863
|
program2.command("watch [dir]").description("Watch a directory for .md changes and auto-import prompts (default: .prompts/)").option("-c, --collection <name>", "Collection to import into", "watched").option("--agent <name>", "Attribution").action(async (dir, opts) => {
|
|
@@ -13854,7 +13866,7 @@ program2.command("watch [dir]").description("Watch a directory for .md changes a
|
|
|
13854
13866
|
const watchDir = resolve(dir ?? join7(process.cwd(), ".prompts"));
|
|
13855
13867
|
if (!existsSync5(watchDir))
|
|
13856
13868
|
mkdirSync4(watchDir, { recursive: true });
|
|
13857
|
-
console.log(
|
|
13869
|
+
console.log(chalk3.bold(`Watching ${watchDir} for .md changes\u2026`) + chalk3.gray(" (Ctrl+C to stop)"));
|
|
13858
13870
|
const { importFromMarkdown: importFromMarkdown2 } = await Promise.resolve().then(() => (init_importer(), exports_importer));
|
|
13859
13871
|
const { readFileSync: readFileSync2 } = await import("fs");
|
|
13860
13872
|
const fsWatch = (await import("fs")).watch;
|
|
@@ -13865,10 +13877,10 @@ program2.command("watch [dir]").description("Watch a directory for .md changes a
|
|
|
13865
13877
|
try {
|
|
13866
13878
|
const content = readFileSync2(filePath, "utf-8");
|
|
13867
13879
|
const result = importFromMarkdown2([{ filename, content }], opts["agent"]);
|
|
13868
|
-
const action = result.created > 0 ?
|
|
13869
|
-
console.log(`${action}: ${
|
|
13880
|
+
const action = result.created > 0 ? chalk3.green("Created") : chalk3.yellow("Updated");
|
|
13881
|
+
console.log(`${action}: ${chalk3.bold(filename.replace(".md", ""))} ${chalk3.gray(new Date().toLocaleTimeString())}`);
|
|
13870
13882
|
} catch {
|
|
13871
|
-
console.error(
|
|
13883
|
+
console.error(chalk3.red(`Failed to import: ${filename}`));
|
|
13872
13884
|
}
|
|
13873
13885
|
});
|
|
13874
13886
|
await new Promise(() => {});
|
|
@@ -13876,37 +13888,37 @@ program2.command("watch [dir]").description("Watch a directory for .md changes a
|
|
|
13876
13888
|
program2.command("import-slash-commands").description("Auto-scan .claude/commands, .codex/skills, .gemini/extensions and import all prompts").option("--dir <path>", "Root dir to scan (default: cwd)", process.cwd()).option("--agent <name>", "Attribution").action((opts) => {
|
|
13877
13889
|
try {
|
|
13878
13890
|
const { scanned, imported } = scanAndImportSlashCommands(opts["dir"] ?? process.cwd(), opts["agent"]);
|
|
13879
|
-
if (isJson()) {
|
|
13880
|
-
output({ scanned, imported });
|
|
13891
|
+
if (isJson(program2)) {
|
|
13892
|
+
output(program2, { scanned, imported });
|
|
13881
13893
|
return;
|
|
13882
13894
|
}
|
|
13883
13895
|
if (scanned.length === 0) {
|
|
13884
|
-
console.log(
|
|
13896
|
+
console.log(chalk3.gray("No slash command files found."));
|
|
13885
13897
|
return;
|
|
13886
13898
|
}
|
|
13887
|
-
console.log(
|
|
13899
|
+
console.log(chalk3.bold(`Scanned ${scanned.length} file(s):`));
|
|
13888
13900
|
for (const s of scanned)
|
|
13889
|
-
console.log(
|
|
13901
|
+
console.log(chalk3.gray(` ${s.source}/${s.file}`));
|
|
13890
13902
|
console.log(`
|
|
13891
|
-
${
|
|
13903
|
+
${chalk3.green(`Created: ${imported.created}`)} ${chalk3.yellow(`Updated: ${imported.updated}`)}`);
|
|
13892
13904
|
if (imported.errors.length > 0) {
|
|
13893
13905
|
for (const e of imported.errors)
|
|
13894
|
-
console.error(
|
|
13906
|
+
console.error(chalk3.red(` \u2717 ${e.item}: ${e.error}`));
|
|
13895
13907
|
}
|
|
13896
13908
|
} catch (e) {
|
|
13897
|
-
handleError(e);
|
|
13909
|
+
handleError(program2, e);
|
|
13898
13910
|
}
|
|
13899
13911
|
});
|
|
13900
13912
|
program2.command("remove <id>").alias("rm").alias("uninstall").description("Remove a prompt (alias for delete)").option("-y, --yes", "Skip confirmation").action(async (id, opts) => {
|
|
13901
13913
|
try {
|
|
13902
13914
|
const prompt = getPrompt(id);
|
|
13903
13915
|
if (!prompt)
|
|
13904
|
-
handleError(`Prompt not found: ${id}`);
|
|
13905
|
-
if (!opts.yes && !isJson()) {
|
|
13916
|
+
handleError(program2, `Prompt not found: ${id}`);
|
|
13917
|
+
if (!opts.yes && !isJson(program2)) {
|
|
13906
13918
|
const { createInterface } = await import("readline");
|
|
13907
13919
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
13908
13920
|
await new Promise((resolve) => {
|
|
13909
|
-
rl.question(
|
|
13921
|
+
rl.question(chalk3.yellow(`Remove "${prompt.slug}"? [y/N] `), (ans) => {
|
|
13910
13922
|
rl.close();
|
|
13911
13923
|
if (ans.toLowerCase() !== "y") {
|
|
13912
13924
|
console.log("Cancelled.");
|
|
@@ -13917,12 +13929,12 @@ program2.command("remove <id>").alias("rm").alias("uninstall").description("Remo
|
|
|
13917
13929
|
});
|
|
13918
13930
|
}
|
|
13919
13931
|
deletePrompt(id);
|
|
13920
|
-
if (isJson())
|
|
13921
|
-
output({ deleted: true, id: prompt.id });
|
|
13932
|
+
if (isJson(program2))
|
|
13933
|
+
output(program2, { deleted: true, id: prompt.id });
|
|
13922
13934
|
else
|
|
13923
|
-
console.log(
|
|
13935
|
+
console.log(chalk3.red(`Removed ${prompt.slug}`));
|
|
13924
13936
|
} catch (e) {
|
|
13925
|
-
handleError(e);
|
|
13937
|
+
handleError(program2, e);
|
|
13926
13938
|
}
|
|
13927
13939
|
});
|
|
13928
13940
|
var scheduleCmd = program2.command("schedule").description("Manage prompt schedules");
|
|
@@ -13930,81 +13942,81 @@ scheduleCmd.command("add <id> <cron>").description("Schedule a prompt to run on
|
|
|
13930
13942
|
try {
|
|
13931
13943
|
const cronError = validateCron(cron);
|
|
13932
13944
|
if (cronError)
|
|
13933
|
-
handleError(`Invalid cron: ${cronError}`);
|
|
13945
|
+
handleError(program2, `Invalid cron: ${cronError}`);
|
|
13934
13946
|
const prompt = getPrompt(id);
|
|
13935
13947
|
if (!prompt)
|
|
13936
|
-
handleError(`Prompt not found: ${id}`);
|
|
13948
|
+
handleError(program2, `Prompt not found: ${id}`);
|
|
13937
13949
|
const vars = opts.vars ? JSON.parse(opts.vars) : undefined;
|
|
13938
13950
|
const schedule = createSchedule({ prompt_id: prompt.id, prompt_slug: prompt.slug, cron, vars, agent_id: opts.agent });
|
|
13939
|
-
if (isJson()) {
|
|
13940
|
-
output(schedule);
|
|
13951
|
+
if (isJson(program2)) {
|
|
13952
|
+
output(program2, schedule);
|
|
13941
13953
|
return;
|
|
13942
13954
|
}
|
|
13943
|
-
console.log(
|
|
13955
|
+
console.log(chalk3.green(`Scheduled "${prompt.slug}" [${schedule.id}]`));
|
|
13944
13956
|
console.log(` Cron: ${cron}`);
|
|
13945
13957
|
console.log(` Next run: ${schedule.next_run_at}`);
|
|
13946
13958
|
} catch (e) {
|
|
13947
|
-
handleError(e);
|
|
13959
|
+
handleError(program2, e);
|
|
13948
13960
|
}
|
|
13949
13961
|
});
|
|
13950
13962
|
scheduleCmd.command("list [id]").description("List schedules, optionally filtered by prompt ID").action((id) => {
|
|
13951
13963
|
try {
|
|
13952
13964
|
const schedules = listSchedules(id);
|
|
13953
|
-
if (isJson()) {
|
|
13954
|
-
output(schedules);
|
|
13965
|
+
if (isJson(program2)) {
|
|
13966
|
+
output(program2, schedules);
|
|
13955
13967
|
return;
|
|
13956
13968
|
}
|
|
13957
13969
|
if (!schedules.length) {
|
|
13958
|
-
console.log(
|
|
13970
|
+
console.log(chalk3.gray("No schedules."));
|
|
13959
13971
|
return;
|
|
13960
13972
|
}
|
|
13961
13973
|
for (const s of schedules) {
|
|
13962
|
-
console.log(`${
|
|
13974
|
+
console.log(`${chalk3.bold(s.id)} ${chalk3.cyan(s.prompt_slug)} cron:${s.cron} next:${s.next_run_at} runs:${s.run_count}`);
|
|
13963
13975
|
}
|
|
13964
13976
|
} catch (e) {
|
|
13965
|
-
handleError(e);
|
|
13977
|
+
handleError(program2, e);
|
|
13966
13978
|
}
|
|
13967
13979
|
});
|
|
13968
13980
|
scheduleCmd.command("remove <scheduleId>").alias("delete").description("Remove a prompt schedule").action((scheduleId) => {
|
|
13969
13981
|
try {
|
|
13970
13982
|
deleteSchedule(scheduleId);
|
|
13971
|
-
if (isJson())
|
|
13972
|
-
output({ deleted: true, id: scheduleId });
|
|
13983
|
+
if (isJson(program2))
|
|
13984
|
+
output(program2, { deleted: true, id: scheduleId });
|
|
13973
13985
|
else
|
|
13974
|
-
console.log(
|
|
13986
|
+
console.log(chalk3.red(`Removed schedule ${scheduleId}`));
|
|
13975
13987
|
} catch (e) {
|
|
13976
|
-
handleError(e);
|
|
13988
|
+
handleError(program2, e);
|
|
13977
13989
|
}
|
|
13978
13990
|
});
|
|
13979
13991
|
scheduleCmd.command("due").description("Show and execute all due schedules").option("--dry-run", "Show due prompts without marking them as ran").action((opts) => {
|
|
13980
13992
|
try {
|
|
13981
13993
|
const due = getDueSchedules();
|
|
13982
13994
|
if (!due.length) {
|
|
13983
|
-
console.log(
|
|
13995
|
+
console.log(chalk3.gray("No prompts due."));
|
|
13984
13996
|
return;
|
|
13985
13997
|
}
|
|
13986
|
-
if (isJson()) {
|
|
13987
|
-
output(due);
|
|
13998
|
+
if (isJson(program2)) {
|
|
13999
|
+
output(program2, due);
|
|
13988
14000
|
return;
|
|
13989
14001
|
}
|
|
13990
14002
|
for (const d of due) {
|
|
13991
|
-
console.log(
|
|
14003
|
+
console.log(chalk3.bold(`
|
|
13992
14004
|
[${d.id}] ${d.prompt_slug}`));
|
|
13993
|
-
console.log(
|
|
13994
|
-
console.log(
|
|
14005
|
+
console.log(chalk3.gray(`Next run: ${d.next_run_at} | Runs: ${d.run_count}`));
|
|
14006
|
+
console.log(chalk3.white(d.rendered));
|
|
13995
14007
|
}
|
|
13996
14008
|
if (!opts.dryRun)
|
|
13997
|
-
console.log(
|
|
14009
|
+
console.log(chalk3.green(`
|
|
13998
14010
|
\u2713 Marked ${due.length} schedule(s) as ran.`));
|
|
13999
14011
|
} catch (e) {
|
|
14000
|
-
handleError(e);
|
|
14012
|
+
handleError(program2, e);
|
|
14001
14013
|
}
|
|
14002
14014
|
});
|
|
14003
14015
|
scheduleCmd.command("next <cron>").description("Preview when a cron expression will fire").option("-n, --count <n>", "Number of runs to show", "5").action((cron, opts) => {
|
|
14004
14016
|
try {
|
|
14005
14017
|
const cronError = validateCron(cron);
|
|
14006
14018
|
if (cronError)
|
|
14007
|
-
handleError(`Invalid cron: ${cronError}`);
|
|
14019
|
+
handleError(program2, `Invalid cron: ${cronError}`);
|
|
14008
14020
|
const count = parseInt(opts.count ?? "5", 10);
|
|
14009
14021
|
const runs = [];
|
|
14010
14022
|
let from = new Date;
|
|
@@ -14013,15 +14025,15 @@ scheduleCmd.command("next <cron>").description("Preview when a cron expression w
|
|
|
14013
14025
|
runs.push(next.toISOString());
|
|
14014
14026
|
from = next;
|
|
14015
14027
|
}
|
|
14016
|
-
if (isJson()) {
|
|
14017
|
-
output({ cron, next_runs: runs });
|
|
14028
|
+
if (isJson(program2)) {
|
|
14029
|
+
output(program2, { cron, next_runs: runs });
|
|
14018
14030
|
return;
|
|
14019
14031
|
}
|
|
14020
|
-
console.log(
|
|
14032
|
+
console.log(chalk3.bold(`Next ${count} runs for "${cron}":`));
|
|
14021
14033
|
for (const r of runs)
|
|
14022
14034
|
console.log(` ${r}`);
|
|
14023
14035
|
} catch (e) {
|
|
14024
|
-
handleError(e);
|
|
14036
|
+
handleError(program2, e);
|
|
14025
14037
|
}
|
|
14026
14038
|
});
|
|
14027
14039
|
program2.parse();
|