@hasna/prompts 0.3.17 → 0.3.19

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.
@@ -1 +1 @@
1
- {"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/prompts.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAOnC,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAsV7D"}
1
+ {"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/prompts.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAOnC,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAmW7D"}
@@ -1 +1 @@
1
- {"version":3,"file":"qol.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/qol.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAQnC,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAwX1D"}
1
+ {"version":3,"file":"qol.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/qol.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAQnC,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAkW1D"}
package/dist/cli/index.js CHANGED
@@ -12067,6 +12067,7 @@ function listPrompts(filter = {}) {
12067
12067
  const db = getDatabase();
12068
12068
  const conditions = [];
12069
12069
  const params = [];
12070
+ const orderParams = [];
12070
12071
  if (filter.collection) {
12071
12072
  conditions.push("collection = ?");
12072
12073
  params.push(filter.collection);
@@ -12090,18 +12091,20 @@ function listPrompts(filter = {}) {
12090
12091
  if (filter.project_id !== undefined && filter.project_id !== null) {
12091
12092
  conditions.push("(project_id = ? OR project_id IS NULL)");
12092
12093
  params.push(filter.project_id);
12093
- orderBy = `(CASE WHEN project_id = '${filter.project_id}' THEN 0 ELSE 1 END), pinned DESC, use_count DESC, updated_at DESC`;
12094
+ orderBy = "(CASE WHEN project_id = ? THEN 0 ELSE 1 END), pinned DESC, use_count DESC, updated_at DESC";
12095
+ orderParams.push(filter.project_id);
12094
12096
  }
12095
12097
  const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
12096
12098
  const limit = filter.limit ?? 20;
12097
12099
  const offset = filter.offset ?? 0;
12098
- const rows = db.query(`SELECT * FROM prompts ${where} ORDER BY ${orderBy} LIMIT ? OFFSET ?`).all(...params, limit, offset);
12100
+ const rows = db.query(`SELECT * FROM prompts ${where} ORDER BY ${orderBy} LIMIT ? OFFSET ?`).all(...params, ...orderParams, limit, offset);
12099
12101
  return rows.map(rowToPrompt);
12100
12102
  }
12101
12103
  function listPromptsSlim(filter = {}) {
12102
12104
  const db = getDatabase();
12103
12105
  const conditions = [];
12104
12106
  const params = [];
12107
+ const orderParams = [];
12105
12108
  if (filter.collection) {
12106
12109
  conditions.push("collection = ?");
12107
12110
  params.push(filter.collection);
@@ -12124,12 +12127,13 @@ function listPromptsSlim(filter = {}) {
12124
12127
  if (filter.project_id) {
12125
12128
  conditions.push("(project_id = ? OR project_id IS NULL)");
12126
12129
  params.push(filter.project_id);
12127
- orderBy = `(CASE WHEN project_id = '${filter.project_id}' THEN 0 ELSE 1 END), pinned DESC, use_count DESC, updated_at DESC`;
12130
+ orderBy = "(CASE WHEN project_id = ? THEN 0 ELSE 1 END), pinned DESC, use_count DESC, updated_at DESC";
12131
+ orderParams.push(filter.project_id);
12128
12132
  }
12129
12133
  const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
12130
12134
  const limit = filter.limit ?? 20;
12131
12135
  const offset = filter.offset ?? 0;
12132
- const rows = db.query(`SELECT id, slug, name, title, description, collection, tags, variables, is_template, source, pinned, next_prompt, expires_at, project_id, use_count, last_used_at, created_at, updated_at FROM prompts ${where} ORDER BY ${orderBy} LIMIT ? OFFSET ?`).all(...params, limit, offset);
12136
+ const rows = db.query(`SELECT id, slug, name, title, description, collection, tags, variables, is_template, source, pinned, next_prompt, expires_at, project_id, use_count, last_used_at, created_at, updated_at FROM prompts ${where} ORDER BY ${orderBy} LIMIT ? OFFSET ?`).all(...params, ...orderParams, limit, offset);
12133
12137
  return rows.map(rowToSlimPrompt);
12134
12138
  }
12135
12139
  function updatePrompt(idOrSlug, input) {
@@ -12183,16 +12187,22 @@ function usePrompt(idOrSlug) {
12183
12187
  db.run("INSERT INTO usage_log (id, prompt_id) VALUES (?, ?)", [generateId("UL"), prompt.id]);
12184
12188
  return requirePrompt(prompt.id);
12185
12189
  }
12186
- function getTrending(days = 7, limit = 10) {
12190
+ function getTrending(days = 7, limit = 10, projectId) {
12187
12191
  const db = getDatabase();
12188
12192
  const cutoff = new Date(Date.now() - days * 24 * 60 * 60 * 1000).toISOString();
12189
- return db.query(`SELECT p.id, p.slug, p.title, COUNT(ul.id) as uses
12193
+ const projectFilter = projectId ? "AND (p.project_id = ? OR p.project_id IS NULL)" : "";
12194
+ const rows = db.query(`SELECT p.id, p.slug, p.title, COUNT(ul.id) as uses
12190
12195
  FROM usage_log ul
12191
12196
  JOIN prompts p ON p.id = ul.prompt_id
12192
12197
  WHERE ul.used_at >= ?
12198
+ ${projectFilter}
12193
12199
  GROUP BY p.id
12194
12200
  ORDER BY uses DESC
12195
- LIMIT ?`).all(cutoff, limit);
12201
+ LIMIT ?`);
12202
+ if (projectId) {
12203
+ return rows.all(cutoff, projectId, limit);
12204
+ }
12205
+ return rows.all(cutoff, limit);
12196
12206
  }
12197
12207
  function setExpiry(idOrSlug, expiresAt) {
12198
12208
  const db = getDatabase();
@@ -13117,6 +13127,46 @@ function getActiveProjectId(program2) {
13117
13127
  const db = getDatabase();
13118
13128
  return resolveProject(db, projectName);
13119
13129
  }
13130
+ async function writeToClipboard(text) {
13131
+ const run = async (cmd) => {
13132
+ const proc = Bun.spawn(cmd, { stdin: "pipe", stdout: "ignore", stderr: "ignore" });
13133
+ proc.stdin.write(text);
13134
+ proc.stdin.end();
13135
+ const exitCode = await proc.exited;
13136
+ if (exitCode !== 0) {
13137
+ throw new Error(`Clipboard command failed: ${cmd[0]}`);
13138
+ }
13139
+ };
13140
+ if (process.platform === "darwin") {
13141
+ await run(["pbcopy"]);
13142
+ return;
13143
+ }
13144
+ if (process.platform === "linux") {
13145
+ const candidates = [
13146
+ ["xclip", "-selection", "clipboard"],
13147
+ ["xsel", "--clipboard", "--input"]
13148
+ ];
13149
+ const available = candidates.filter((cmd) => {
13150
+ const tool = cmd[0];
13151
+ if (!tool)
13152
+ return false;
13153
+ if (typeof Bun.which !== "function")
13154
+ return true;
13155
+ return Boolean(Bun.which(tool));
13156
+ });
13157
+ if (available.length === 0) {
13158
+ throw new Error("No clipboard tool found. Install xclip or xsel, or use `prompts use` / `prompts share` without clipboard.");
13159
+ }
13160
+ for (const cmd of available) {
13161
+ try {
13162
+ await run(cmd);
13163
+ return;
13164
+ } catch {}
13165
+ }
13166
+ throw new Error("Failed to copy to clipboard using available tools. Use `prompts use` or `prompts share` without clipboard.");
13167
+ }
13168
+ throw new Error("Clipboard is not supported on this platform. Use `prompts use` or `prompts share` without clipboard.");
13169
+ }
13120
13170
  function output(program2, data) {
13121
13171
  if (isJson(program2)) {
13122
13172
  console.log(JSON.stringify(data, null, 2));
@@ -13237,7 +13287,7 @@ function registerPromptCommands(program2) {
13237
13287
  handleError(program2, e);
13238
13288
  }
13239
13289
  });
13240
- 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) => {
13290
+ 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").option("-o, --offset <n>", "Skip first N results", "0").action((opts) => {
13241
13291
  try {
13242
13292
  const project_id = getActiveProjectId(program2);
13243
13293
  let prompts = listPrompts({
@@ -13245,6 +13295,7 @@ function registerPromptCommands(program2) {
13245
13295
  tags: opts["tags"] ? opts["tags"].split(",").map((t) => t.trim()) : undefined,
13246
13296
  is_template: opts["templates"] ? true : undefined,
13247
13297
  limit: parseInt(opts["limit"]) || 50,
13298
+ offset: parseInt(opts["offset"] ?? "0") || 0,
13248
13299
  ...project_id !== null ? { project_id } : {}
13249
13300
  });
13250
13301
  if (opts["recent"]) {
@@ -13264,13 +13315,14 @@ ${prompts.length} prompt(s)`));
13264
13315
  handleError(program2, e);
13265
13316
  }
13266
13317
  });
13267
- 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) => {
13318
+ 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").option("-o, --offset <n>", "Skip first N results", "0").action((query, opts) => {
13268
13319
  try {
13269
13320
  const project_id = getActiveProjectId(program2);
13270
13321
  const results = searchPrompts(query, {
13271
13322
  collection: opts["collection"],
13272
13323
  tags: opts["tags"] ? opts["tags"].split(",").map((t) => t.trim()) : undefined,
13273
13324
  limit: parseInt(opts["limit"] ?? "20") || 20,
13325
+ offset: parseInt(opts["offset"] ?? "0") || 0,
13274
13326
  ...project_id !== null ? { project_id } : {}
13275
13327
  });
13276
13328
  if (isJson(program2)) {
@@ -13317,9 +13369,16 @@ Warning: missing vars: ${result.missing_vars.join(", ")}`));
13317
13369
  handleError(program2, e);
13318
13370
  }
13319
13371
  });
13320
- program2.command("templates").description("List template prompts").option("-c, --collection <name>").action((opts) => {
13372
+ program2.command("templates").description("List template prompts").option("-c, --collection <name>").option("-n, --limit <n>", "Max results", "50").option("-o, --offset <n>", "Skip first N results", "0").action((opts) => {
13321
13373
  try {
13322
- const prompts = listPrompts({ is_template: true, collection: opts["collection"] });
13374
+ const project_id = getActiveProjectId(program2);
13375
+ const prompts = listPrompts({
13376
+ is_template: true,
13377
+ collection: opts["collection"],
13378
+ limit: parseInt(opts["limit"] ?? "50") || 50,
13379
+ offset: parseInt(opts["offset"] ?? "0") || 0,
13380
+ ...project_id !== null ? { project_id } : {}
13381
+ });
13323
13382
  if (isJson(program2)) {
13324
13383
  output(program2, prompts);
13325
13384
  } else if (prompts.length === 0) {
@@ -13653,7 +13712,7 @@ function registerQolCommands(program2) {
13653
13712
  handleError(program2, e);
13654
13713
  }
13655
13714
  });
13656
- program2.command("tag <id> [ops...]").description("Patch tags: +foo adds, -bar removes. Or --set foo,bar replaces all tags.").option("--set <tags>", "Replace all tags (comma-separated)").action((id, ops, opts) => {
13715
+ program2.command("tag <id>").description("Patch tags on a prompt. Use --add/--remove, or --set to replace all.").option("-a, --add <tags>", "Comma-separated tags to add").option("-r, --remove <tags>", "Comma-separated tags to remove").option("--set <tags>", "Replace all tags (comma-separated)").action((id, opts) => {
13657
13716
  try {
13658
13717
  const prompt = getPrompt(id);
13659
13718
  if (!prompt)
@@ -13664,19 +13723,16 @@ function registerQolCommands(program2) {
13664
13723
  tags = opts.set.split(",").map((t) => t.trim()).filter(Boolean);
13665
13724
  } else {
13666
13725
  tags = [...p.tags];
13667
- for (const op of ops) {
13668
- if (op.startsWith("+")) {
13669
- const tag = op.slice(1);
13670
- if (!tags.includes(tag))
13671
- tags.push(tag);
13672
- } else if (op.startsWith("-")) {
13673
- const tag = op.slice(1);
13674
- tags = tags.filter((t) => t !== tag);
13675
- } else {
13676
- if (!tags.includes(op))
13677
- tags.push(op);
13726
+ if (opts.add) {
13727
+ for (const t of opts.add.split(",").map((x) => x.trim()).filter(Boolean)) {
13728
+ if (!tags.includes(t))
13729
+ tags.push(t);
13678
13730
  }
13679
13731
  }
13732
+ if (opts.remove) {
13733
+ const toRemove = opts.remove.split(",").map((x) => x.trim());
13734
+ tags = tags.filter((t) => !toRemove.includes(t));
13735
+ }
13680
13736
  }
13681
13737
  updatePrompt(p.id, { tags });
13682
13738
  if (isJson(program2))
@@ -13707,27 +13763,7 @@ function registerQolCommands(program2) {
13707
13763
  const markdown = lines.join(`
13708
13764
  `);
13709
13765
  if (opts.clipboard) {
13710
- const { platform: platform2 } = process;
13711
- if (platform2 === "darwin") {
13712
- const proc = Bun.spawn(["pbcopy"], { stdin: "pipe" });
13713
- proc.stdin.write(markdown);
13714
- proc.stdin.end();
13715
- await proc.exited;
13716
- } else if (platform2 === "linux") {
13717
- try {
13718
- const proc = Bun.spawn(["xclip", "-selection", "clipboard"], { stdin: "pipe" });
13719
- proc.stdin.write(markdown);
13720
- proc.stdin.end();
13721
- await proc.exited;
13722
- } catch {
13723
- const proc = Bun.spawn(["xsel", "--clipboard", "--input"], { stdin: "pipe" });
13724
- proc.stdin.write(markdown);
13725
- proc.stdin.end();
13726
- await proc.exited;
13727
- }
13728
- } else {
13729
- handleError(program2, "Clipboard not supported on this platform.");
13730
- }
13766
+ await writeToClipboard(markdown);
13731
13767
  console.log(chalk4.green(`Copied ${chalk4.bold(p.slug)} to clipboard`));
13732
13768
  } else {
13733
13769
  if (isJson(program2))
@@ -13869,7 +13905,7 @@ function registerQolCommands(program2) {
13869
13905
  handleError(program2, e);
13870
13906
  }
13871
13907
  });
13872
- program2.command("bulk-tag [ops...] [ids...]").description("Patch tags on multiple prompts. Leading ops start with + or -, rest are IDs. Or pipe IDs via stdin.").helpOption("-h, --help").addHelpText("after", `
13908
+ program2.command("bulk-tag [args...]").description("Patch tags on multiple prompts. Args starting with +/- are tag ops; rest are IDs. Pipe IDs via stdin too.").addHelpText("after", `
13873
13909
  Examples:
13874
13910
  prompts bulk-tag +foo -bar PRMT-00001 PRMT-00002
13875
13911
  echo "PRMT-00001" | prompts bulk-tag +reviewed`).action(async (args) => {
@@ -14384,7 +14420,11 @@ By collection:`));
14384
14420
  program2.command("recent [n]").description("Show recently used prompts (default: 10)").action((n) => {
14385
14421
  try {
14386
14422
  const limit = parseInt(n ?? "10") || 10;
14387
- 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);
14423
+ const project_id = getActiveProjectId(program2);
14424
+ const prompts = listPrompts({
14425
+ limit,
14426
+ ...project_id !== null ? { project_id } : {}
14427
+ }).filter((p) => p.last_used_at !== null).sort((a, b) => (b.last_used_at ?? "").localeCompare(a.last_used_at ?? "")).slice(0, limit);
14388
14428
  if (isJson(program2)) {
14389
14429
  output(program2, prompts);
14390
14430
  return;
@@ -14403,7 +14443,12 @@ program2.command("recent [n]").description("Show recently used prompts (default:
14403
14443
  });
14404
14444
  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) => {
14405
14445
  try {
14406
- const prompts = listPrompts({ collection: opts["collection"], limit: 1e4 });
14446
+ const project_id = getActiveProjectId(program2);
14447
+ const prompts = listPrompts({
14448
+ collection: opts["collection"],
14449
+ limit: 1e4,
14450
+ ...project_id !== null ? { project_id } : {}
14451
+ });
14407
14452
  const results = lintAll(prompts);
14408
14453
  if (isJson(program2)) {
14409
14454
  output(program2, results);
@@ -14441,8 +14486,12 @@ ${results.length} prompt(s) with issues \u2014 ${errors} errors, ${warns} warnin
14441
14486
  program2.command("stale [days]").description("List prompts not used in N days (default: 30)").action((days) => {
14442
14487
  try {
14443
14488
  const threshold = parseInt(days ?? "30") || 30;
14489
+ const project_id = getActiveProjectId(program2);
14444
14490
  const cutoff = new Date(Date.now() - threshold * 24 * 60 * 60 * 1000).toISOString();
14445
- const all = listPrompts({ limit: 1e4 });
14491
+ const all = listPrompts({
14492
+ limit: 1e4,
14493
+ ...project_id !== null ? { project_id } : {}
14494
+ });
14446
14495
  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 ?? ""));
14447
14496
  const now = new Date().toISOString();
14448
14497
  const expired = all.filter((p) => p.expires_at !== null && p.expires_at < now);
@@ -14499,27 +14548,7 @@ program2.command("unpin <id>").description("Unpin a prompt").action((id) => {
14499
14548
  program2.command("copy <id>").description("Copy prompt body to clipboard and increment use counter").action(async (id) => {
14500
14549
  try {
14501
14550
  const prompt = usePrompt(id);
14502
- const { platform: platform2 } = process;
14503
- if (platform2 === "darwin") {
14504
- const proc = Bun.spawn(["pbcopy"], { stdin: "pipe" });
14505
- proc.stdin.write(prompt.body);
14506
- proc.stdin.end();
14507
- await proc.exited;
14508
- } else if (platform2 === "linux") {
14509
- try {
14510
- const proc = Bun.spawn(["xclip", "-selection", "clipboard"], { stdin: "pipe" });
14511
- proc.stdin.write(prompt.body);
14512
- proc.stdin.end();
14513
- await proc.exited;
14514
- } catch {
14515
- const proc = Bun.spawn(["xsel", "--clipboard", "--input"], { stdin: "pipe" });
14516
- proc.stdin.write(prompt.body);
14517
- proc.stdin.end();
14518
- await proc.exited;
14519
- }
14520
- } else {
14521
- handleError(program2, "Clipboard not supported on this platform. Use `prompts use` instead.");
14522
- }
14551
+ await writeToClipboard(prompt.body);
14523
14552
  if (isJson(program2))
14524
14553
  output(program2, { copied: true, id: prompt.id, slug: prompt.slug });
14525
14554
  else
@@ -14652,7 +14681,12 @@ ${report.issues.length} issue(s) \u2014 ${report.errors} errors, ${report.warnin
14652
14681
  });
14653
14682
  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) => {
14654
14683
  try {
14655
- const all = listPrompts({ collection: opts["collection"], limit: parseInt(opts["limit"] ?? "50") || 50 });
14684
+ const project_id = getActiveProjectId(program2);
14685
+ const all = listPrompts({
14686
+ collection: opts["collection"],
14687
+ limit: parseInt(opts["limit"] ?? "50") || 50,
14688
+ ...project_id !== null ? { project_id } : {}
14689
+ });
14656
14690
  const unused = all.filter((p) => p.use_count === 0).sort((a, b) => a.created_at.localeCompare(b.created_at));
14657
14691
  if (isJson(program2)) {
14658
14692
  output(program2, unused);
@@ -14672,7 +14706,8 @@ program2.command("unused").description("List prompts that have never been used (
14672
14706
  });
14673
14707
  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) => {
14674
14708
  try {
14675
- const results = getTrending(parseInt(opts["days"] ?? "7") || 7, parseInt(opts["limit"] ?? "10") || 10);
14709
+ const project_id = getActiveProjectId(program2);
14710
+ const results = getTrending(parseInt(opts["days"] ?? "7") || 7, parseInt(opts["limit"] ?? "10") || 10, project_id);
14676
14711
  if (isJson(program2)) {
14677
14712
  output(program2, results);
14678
14713
  return;
@@ -2,6 +2,7 @@ import { Command } from "commander";
2
2
  import type { Prompt } from "../types/index.js";
3
3
  export declare function isJson(program: Command): boolean;
4
4
  export declare function getActiveProjectId(program: Command): string | null;
5
+ export declare function writeToClipboard(text: string): Promise<void>;
5
6
  export declare function output(program: Command, data: unknown): void;
6
7
  export declare function handleError(program: Command, e: unknown): never;
7
8
  export declare function fmtPrompt(p: Prompt): string;
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/cli/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAGnC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAA;AAE/C,wBAAgB,MAAM,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAEhD;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAKlE;AAED,wBAAgB,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI,CAM5D;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,GAAG,KAAK,CAQ/D;AAED,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAK3C"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/cli/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAGnC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAA;AAE/C,wBAAgB,MAAM,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAEhD;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAKlE;AAED,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA8ClE;AAED,wBAAgB,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI,CAM5D;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,GAAG,KAAK,CAQ/D;AAED,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAK3C"}
@@ -9,7 +9,7 @@ export declare function listPromptsSlim(filter?: ListPromptsFilter): SlimPrompt[
9
9
  export declare function updatePrompt(idOrSlug: string, input: UpdatePromptInput): Prompt;
10
10
  export declare function deletePrompt(idOrSlug: string): void;
11
11
  export declare function usePrompt(idOrSlug: string): Prompt;
12
- export declare function getTrending(days?: number, limit?: number): Array<{
12
+ export declare function getTrending(days?: number, limit?: number, projectId?: string | null): Array<{
13
13
  id: string;
14
14
  slug: string;
15
15
  title: string;
@@ -1 +1 @@
1
- {"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../src/db/prompts.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,MAAM,EACN,UAAU,EACV,UAAU,EACV,iBAAiB,EACjB,iBAAiB,EACjB,iBAAiB,EAGlB,MAAM,mBAAmB,CAAA;AA2B1B,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,UAAU,CAWlH;AA2BD,wBAAgB,YAAY,CAAC,KAAK,EAAE,iBAAiB,GAAG,MAAM,CA0C7D;AAED,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAOzD;AAED,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAItD;AAED,wBAAgB,WAAW,CAAC,MAAM,GAAE,iBAAsB,GAAG,MAAM,EAAE,CA4CpE;AAED,yFAAyF;AACzF,wBAAgB,eAAe,CAAC,MAAM,GAAE,iBAAsB,GAAG,UAAU,EAAE,CA+B5E;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,iBAAiB,GAAG,MAAM,CAiD/E;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAInD;AAED,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CASlD;AAED,wBAAgB,WAAW,CAAC,IAAI,SAAI,EAAE,KAAK,SAAK,GAAG,KAAK,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAYlH;AAED,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAK5E;AAED,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAK/E;AAED,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,MAAM,CAKnE;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,iBAAiB,EAAE,KAAK,UAAQ,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,iBAAiB,CAAC,EAAE,MAAM,CAAA;CAAE,CA6BtI;AAED,wBAAgB,cAAc;;;;;YAOJ,MAAM;cAAQ,MAAM;cAAQ,MAAM;eAAS,MAAM;mBAAa,MAAM;;;YAGpE,MAAM;cAAQ,MAAM;cAAQ,MAAM;eAAS,MAAM;sBAAgB,MAAM;;;oBAG/D,MAAM;eAAS,MAAM;;;gBAGzB,MAAM;eAAS,MAAM;;EAGlD"}
1
+ {"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../src/db/prompts.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,MAAM,EACN,UAAU,EACV,UAAU,EACV,iBAAiB,EACjB,iBAAiB,EACjB,iBAAiB,EAGlB,MAAM,mBAAmB,CAAA;AA2B1B,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,UAAU,CAWlH;AA2BD,wBAAgB,YAAY,CAAC,KAAK,EAAE,iBAAiB,GAAG,MAAM,CA0C7D;AAED,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAOzD;AAED,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAItD;AAED,wBAAgB,WAAW,CAAC,MAAM,GAAE,iBAAsB,GAAG,MAAM,EAAE,CA8CpE;AAED,yFAAyF;AACzF,wBAAgB,eAAe,CAAC,MAAM,GAAE,iBAAsB,GAAG,UAAU,EAAE,CAiC5E;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,iBAAiB,GAAG,MAAM,CAiD/E;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAInD;AAED,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CASlD;AAED,wBAAgB,WAAW,CAAC,IAAI,SAAI,EAAE,KAAK,SAAK,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,KAAK,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAkB7I;AAED,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAK5E;AAED,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAK/E;AAED,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,MAAM,CAKnE;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,iBAAiB,EAAE,KAAK,UAAQ,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,iBAAiB,CAAC,EAAE,MAAM,CAAA;CAAE,CA6BtI;AAED,wBAAgB,cAAc;;;;;YAOJ,MAAM;cAAQ,MAAM;cAAQ,MAAM;eAAS,MAAM;mBAAa,MAAM;;;YAGpE,MAAM;cAAQ,MAAM;cAAQ,MAAM;eAAS,MAAM;sBAAgB,MAAM;;;oBAG/D,MAAM;eAAS,MAAM;;;gBAGzB,MAAM;eAAS,MAAM;;EAGlD"}
package/dist/index.js CHANGED
@@ -10100,6 +10100,7 @@ function listPrompts(filter = {}) {
10100
10100
  const db = getDatabase();
10101
10101
  const conditions = [];
10102
10102
  const params = [];
10103
+ const orderParams = [];
10103
10104
  if (filter.collection) {
10104
10105
  conditions.push("collection = ?");
10105
10106
  params.push(filter.collection);
@@ -10123,18 +10124,20 @@ function listPrompts(filter = {}) {
10123
10124
  if (filter.project_id !== undefined && filter.project_id !== null) {
10124
10125
  conditions.push("(project_id = ? OR project_id IS NULL)");
10125
10126
  params.push(filter.project_id);
10126
- orderBy = `(CASE WHEN project_id = '${filter.project_id}' THEN 0 ELSE 1 END), pinned DESC, use_count DESC, updated_at DESC`;
10127
+ orderBy = "(CASE WHEN project_id = ? THEN 0 ELSE 1 END), pinned DESC, use_count DESC, updated_at DESC";
10128
+ orderParams.push(filter.project_id);
10127
10129
  }
10128
10130
  const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
10129
10131
  const limit = filter.limit ?? 20;
10130
10132
  const offset = filter.offset ?? 0;
10131
- const rows = db.query(`SELECT * FROM prompts ${where} ORDER BY ${orderBy} LIMIT ? OFFSET ?`).all(...params, limit, offset);
10133
+ const rows = db.query(`SELECT * FROM prompts ${where} ORDER BY ${orderBy} LIMIT ? OFFSET ?`).all(...params, ...orderParams, limit, offset);
10132
10134
  return rows.map(rowToPrompt);
10133
10135
  }
10134
10136
  function listPromptsSlim(filter = {}) {
10135
10137
  const db = getDatabase();
10136
10138
  const conditions = [];
10137
10139
  const params = [];
10140
+ const orderParams = [];
10138
10141
  if (filter.collection) {
10139
10142
  conditions.push("collection = ?");
10140
10143
  params.push(filter.collection);
@@ -10157,12 +10160,13 @@ function listPromptsSlim(filter = {}) {
10157
10160
  if (filter.project_id) {
10158
10161
  conditions.push("(project_id = ? OR project_id IS NULL)");
10159
10162
  params.push(filter.project_id);
10160
- orderBy = `(CASE WHEN project_id = '${filter.project_id}' THEN 0 ELSE 1 END), pinned DESC, use_count DESC, updated_at DESC`;
10163
+ orderBy = "(CASE WHEN project_id = ? THEN 0 ELSE 1 END), pinned DESC, use_count DESC, updated_at DESC";
10164
+ orderParams.push(filter.project_id);
10161
10165
  }
10162
10166
  const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
10163
10167
  const limit = filter.limit ?? 20;
10164
10168
  const offset = filter.offset ?? 0;
10165
- const rows = db.query(`SELECT id, slug, name, title, description, collection, tags, variables, is_template, source, pinned, next_prompt, expires_at, project_id, use_count, last_used_at, created_at, updated_at FROM prompts ${where} ORDER BY ${orderBy} LIMIT ? OFFSET ?`).all(...params, limit, offset);
10169
+ const rows = db.query(`SELECT id, slug, name, title, description, collection, tags, variables, is_template, source, pinned, next_prompt, expires_at, project_id, use_count, last_used_at, created_at, updated_at FROM prompts ${where} ORDER BY ${orderBy} LIMIT ? OFFSET ?`).all(...params, ...orderParams, limit, offset);
10166
10170
  return rows.map(rowToSlimPrompt);
10167
10171
  }
10168
10172
  function updatePrompt(idOrSlug, input) {
package/dist/mcp/index.js CHANGED
@@ -14733,6 +14733,7 @@ function listPrompts(filter = {}) {
14733
14733
  const db = getDatabase();
14734
14734
  const conditions = [];
14735
14735
  const params = [];
14736
+ const orderParams = [];
14736
14737
  if (filter.collection) {
14737
14738
  conditions.push("collection = ?");
14738
14739
  params.push(filter.collection);
@@ -14756,18 +14757,20 @@ function listPrompts(filter = {}) {
14756
14757
  if (filter.project_id !== undefined && filter.project_id !== null) {
14757
14758
  conditions.push("(project_id = ? OR project_id IS NULL)");
14758
14759
  params.push(filter.project_id);
14759
- orderBy = `(CASE WHEN project_id = '${filter.project_id}' THEN 0 ELSE 1 END), pinned DESC, use_count DESC, updated_at DESC`;
14760
+ orderBy = "(CASE WHEN project_id = ? THEN 0 ELSE 1 END), pinned DESC, use_count DESC, updated_at DESC";
14761
+ orderParams.push(filter.project_id);
14760
14762
  }
14761
14763
  const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
14762
14764
  const limit = filter.limit ?? 20;
14763
14765
  const offset = filter.offset ?? 0;
14764
- const rows = db.query(`SELECT * FROM prompts ${where} ORDER BY ${orderBy} LIMIT ? OFFSET ?`).all(...params, limit, offset);
14766
+ const rows = db.query(`SELECT * FROM prompts ${where} ORDER BY ${orderBy} LIMIT ? OFFSET ?`).all(...params, ...orderParams, limit, offset);
14765
14767
  return rows.map(rowToPrompt);
14766
14768
  }
14767
14769
  function listPromptsSlim(filter = {}) {
14768
14770
  const db = getDatabase();
14769
14771
  const conditions = [];
14770
14772
  const params = [];
14773
+ const orderParams = [];
14771
14774
  if (filter.collection) {
14772
14775
  conditions.push("collection = ?");
14773
14776
  params.push(filter.collection);
@@ -14790,12 +14793,13 @@ function listPromptsSlim(filter = {}) {
14790
14793
  if (filter.project_id) {
14791
14794
  conditions.push("(project_id = ? OR project_id IS NULL)");
14792
14795
  params.push(filter.project_id);
14793
- orderBy = `(CASE WHEN project_id = '${filter.project_id}' THEN 0 ELSE 1 END), pinned DESC, use_count DESC, updated_at DESC`;
14796
+ orderBy = "(CASE WHEN project_id = ? THEN 0 ELSE 1 END), pinned DESC, use_count DESC, updated_at DESC";
14797
+ orderParams.push(filter.project_id);
14794
14798
  }
14795
14799
  const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
14796
14800
  const limit = filter.limit ?? 20;
14797
14801
  const offset = filter.offset ?? 0;
14798
- const rows = db.query(`SELECT id, slug, name, title, description, collection, tags, variables, is_template, source, pinned, next_prompt, expires_at, project_id, use_count, last_used_at, created_at, updated_at FROM prompts ${where} ORDER BY ${orderBy} LIMIT ? OFFSET ?`).all(...params, limit, offset);
14802
+ const rows = db.query(`SELECT id, slug, name, title, description, collection, tags, variables, is_template, source, pinned, next_prompt, expires_at, project_id, use_count, last_used_at, created_at, updated_at FROM prompts ${where} ORDER BY ${orderBy} LIMIT ? OFFSET ?`).all(...params, ...orderParams, limit, offset);
14799
14803
  return rows.map(rowToSlimPrompt);
14800
14804
  }
14801
14805
  function updatePrompt(idOrSlug, input) {
@@ -14849,16 +14853,22 @@ function usePrompt(idOrSlug) {
14849
14853
  db.run("INSERT INTO usage_log (id, prompt_id) VALUES (?, ?)", [generateId("UL"), prompt.id]);
14850
14854
  return requirePrompt(prompt.id);
14851
14855
  }
14852
- function getTrending(days = 7, limit = 10) {
14856
+ function getTrending(days = 7, limit = 10, projectId) {
14853
14857
  const db = getDatabase();
14854
14858
  const cutoff = new Date(Date.now() - days * 24 * 60 * 60 * 1000).toISOString();
14855
- return db.query(`SELECT p.id, p.slug, p.title, COUNT(ul.id) as uses
14859
+ const projectFilter = projectId ? "AND (p.project_id = ? OR p.project_id IS NULL)" : "";
14860
+ const rows = db.query(`SELECT p.id, p.slug, p.title, COUNT(ul.id) as uses
14856
14861
  FROM usage_log ul
14857
14862
  JOIN prompts p ON p.id = ul.prompt_id
14858
14863
  WHERE ul.used_at >= ?
14864
+ ${projectFilter}
14859
14865
  GROUP BY p.id
14860
14866
  ORDER BY uses DESC
14861
- LIMIT ?`).all(cutoff, limit);
14867
+ LIMIT ?`);
14868
+ if (projectId) {
14869
+ return rows.all(cutoff, projectId, limit);
14870
+ }
14871
+ return rows.all(cutoff, limit);
14862
14872
  }
14863
14873
  function setExpiry(idOrSlug, expiresAt) {
14864
14874
  const db = getDatabase();
@@ -10085,6 +10085,7 @@ function listPrompts(filter = {}) {
10085
10085
  const db = getDatabase();
10086
10086
  const conditions = [];
10087
10087
  const params = [];
10088
+ const orderParams = [];
10088
10089
  if (filter.collection) {
10089
10090
  conditions.push("collection = ?");
10090
10091
  params.push(filter.collection);
@@ -10108,18 +10109,20 @@ function listPrompts(filter = {}) {
10108
10109
  if (filter.project_id !== undefined && filter.project_id !== null) {
10109
10110
  conditions.push("(project_id = ? OR project_id IS NULL)");
10110
10111
  params.push(filter.project_id);
10111
- orderBy = `(CASE WHEN project_id = '${filter.project_id}' THEN 0 ELSE 1 END), pinned DESC, use_count DESC, updated_at DESC`;
10112
+ orderBy = "(CASE WHEN project_id = ? THEN 0 ELSE 1 END), pinned DESC, use_count DESC, updated_at DESC";
10113
+ orderParams.push(filter.project_id);
10112
10114
  }
10113
10115
  const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
10114
10116
  const limit = filter.limit ?? 20;
10115
10117
  const offset = filter.offset ?? 0;
10116
- const rows = db.query(`SELECT * FROM prompts ${where} ORDER BY ${orderBy} LIMIT ? OFFSET ?`).all(...params, limit, offset);
10118
+ const rows = db.query(`SELECT * FROM prompts ${where} ORDER BY ${orderBy} LIMIT ? OFFSET ?`).all(...params, ...orderParams, limit, offset);
10117
10119
  return rows.map(rowToPrompt);
10118
10120
  }
10119
10121
  function listPromptsSlim(filter = {}) {
10120
10122
  const db = getDatabase();
10121
10123
  const conditions = [];
10122
10124
  const params = [];
10125
+ const orderParams = [];
10123
10126
  if (filter.collection) {
10124
10127
  conditions.push("collection = ?");
10125
10128
  params.push(filter.collection);
@@ -10142,12 +10145,13 @@ function listPromptsSlim(filter = {}) {
10142
10145
  if (filter.project_id) {
10143
10146
  conditions.push("(project_id = ? OR project_id IS NULL)");
10144
10147
  params.push(filter.project_id);
10145
- orderBy = `(CASE WHEN project_id = '${filter.project_id}' THEN 0 ELSE 1 END), pinned DESC, use_count DESC, updated_at DESC`;
10148
+ orderBy = "(CASE WHEN project_id = ? THEN 0 ELSE 1 END), pinned DESC, use_count DESC, updated_at DESC";
10149
+ orderParams.push(filter.project_id);
10146
10150
  }
10147
10151
  const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
10148
10152
  const limit = filter.limit ?? 20;
10149
10153
  const offset = filter.offset ?? 0;
10150
- const rows = db.query(`SELECT id, slug, name, title, description, collection, tags, variables, is_template, source, pinned, next_prompt, expires_at, project_id, use_count, last_used_at, created_at, updated_at FROM prompts ${where} ORDER BY ${orderBy} LIMIT ? OFFSET ?`).all(...params, limit, offset);
10154
+ const rows = db.query(`SELECT id, slug, name, title, description, collection, tags, variables, is_template, source, pinned, next_prompt, expires_at, project_id, use_count, last_used_at, created_at, updated_at FROM prompts ${where} ORDER BY ${orderBy} LIMIT ? OFFSET ?`).all(...params, ...orderParams, limit, offset);
10151
10155
  return rows.map(rowToSlimPrompt);
10152
10156
  }
10153
10157
  function updatePrompt(idOrSlug, input) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/prompts",
3
- "version": "0.3.17",
3
+ "version": "0.3.19",
4
4
  "description": "Reusable prompt library for AI agents — CLI + MCP server + REST API + web dashboard",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",