@hasna/prompts 0.2.0 → 0.2.2
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 +205 -22
- package/dist/db/database.d.ts +1 -0
- package/dist/db/database.d.ts.map +1 -1
- package/dist/db/projects.d.ts +10 -0
- package/dist/db/projects.d.ts.map +1 -0
- package/dist/db/prompts.d.ts.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +120 -18
- package/dist/lib/ids.d.ts.map +1 -1
- package/dist/lib/search.d.ts.map +1 -1
- package/dist/mcp/index.js +202 -29
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +161 -19
- package/dist/types/index.d.ts +15 -0
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -2187,6 +2187,21 @@ function runMigrations(db) {
|
|
|
2187
2187
|
name: "003_pinned",
|
|
2188
2188
|
sql: `ALTER TABLE prompts ADD COLUMN pinned INTEGER NOT NULL DEFAULT 0;`
|
|
2189
2189
|
},
|
|
2190
|
+
{
|
|
2191
|
+
name: "004_projects",
|
|
2192
|
+
sql: `
|
|
2193
|
+
CREATE TABLE IF NOT EXISTS projects (
|
|
2194
|
+
id TEXT PRIMARY KEY,
|
|
2195
|
+
name TEXT NOT NULL UNIQUE,
|
|
2196
|
+
slug TEXT NOT NULL UNIQUE,
|
|
2197
|
+
description TEXT,
|
|
2198
|
+
path TEXT,
|
|
2199
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
2200
|
+
);
|
|
2201
|
+
ALTER TABLE prompts ADD COLUMN project_id TEXT REFERENCES projects(id) ON DELETE SET NULL;
|
|
2202
|
+
CREATE INDEX IF NOT EXISTS idx_prompts_project_id ON prompts(project_id);
|
|
2203
|
+
`
|
|
2204
|
+
},
|
|
2190
2205
|
{
|
|
2191
2206
|
name: "002_fts5",
|
|
2192
2207
|
sql: `
|
|
@@ -2227,6 +2242,24 @@ function runMigrations(db) {
|
|
|
2227
2242
|
db.run("INSERT INTO _migrations (name) VALUES (?)", [migration.name]);
|
|
2228
2243
|
}
|
|
2229
2244
|
}
|
|
2245
|
+
function resolveProject(db, idOrSlug) {
|
|
2246
|
+
const byId = db.query("SELECT id FROM projects WHERE id = ?").get(idOrSlug);
|
|
2247
|
+
if (byId)
|
|
2248
|
+
return byId.id;
|
|
2249
|
+
const bySlug = db.query("SELECT id FROM projects WHERE slug = ?").get(idOrSlug);
|
|
2250
|
+
if (bySlug)
|
|
2251
|
+
return bySlug.id;
|
|
2252
|
+
const byName = db.query("SELECT id FROM projects WHERE lower(name) = ?").get(idOrSlug.toLowerCase());
|
|
2253
|
+
if (byName)
|
|
2254
|
+
return byName.id;
|
|
2255
|
+
const byPrefix = db.query("SELECT id FROM projects WHERE id LIKE ? LIMIT 2").all(`${idOrSlug}%`);
|
|
2256
|
+
if (byPrefix.length === 1 && byPrefix[0])
|
|
2257
|
+
return byPrefix[0].id;
|
|
2258
|
+
const bySlugPrefix = db.query("SELECT id FROM projects WHERE slug LIKE ? LIMIT 2").all(`${idOrSlug}%`);
|
|
2259
|
+
if (bySlugPrefix.length === 1 && bySlugPrefix[0])
|
|
2260
|
+
return bySlugPrefix[0].id;
|
|
2261
|
+
return null;
|
|
2262
|
+
}
|
|
2230
2263
|
function hasFts(db) {
|
|
2231
2264
|
return db.query("SELECT 1 FROM sqlite_master WHERE type='table' AND name='prompts_fts'").get() !== null;
|
|
2232
2265
|
}
|
|
@@ -2266,25 +2299,24 @@ function uniqueSlug(baseSlug) {
|
|
|
2266
2299
|
}
|
|
2267
2300
|
return slug;
|
|
2268
2301
|
}
|
|
2302
|
+
var CHARS = "abcdefghijklmnopqrstuvwxyz0123456789";
|
|
2303
|
+
function nanoid(len) {
|
|
2304
|
+
let id = "";
|
|
2305
|
+
for (let i = 0;i < len; i++) {
|
|
2306
|
+
id += CHARS[Math.floor(Math.random() * CHARS.length)];
|
|
2307
|
+
}
|
|
2308
|
+
return id;
|
|
2309
|
+
}
|
|
2269
2310
|
function generatePromptId() {
|
|
2270
2311
|
const db = getDatabase();
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
next = parseInt(match[1], 10) + 1;
|
|
2277
|
-
}
|
|
2278
|
-
}
|
|
2279
|
-
return `PRMT-${String(next).padStart(5, "0")}`;
|
|
2312
|
+
let id;
|
|
2313
|
+
do {
|
|
2314
|
+
id = `prmt-${nanoid(8)}`;
|
|
2315
|
+
} while (db.query("SELECT 1 FROM prompts WHERE id = ?").get(id));
|
|
2316
|
+
return id;
|
|
2280
2317
|
}
|
|
2281
2318
|
function generateId(prefix) {
|
|
2282
|
-
|
|
2283
|
-
let id = prefix + "-";
|
|
2284
|
-
for (let i = 0;i < 8; i++) {
|
|
2285
|
-
id += chars[Math.floor(Math.random() * chars.length)];
|
|
2286
|
-
}
|
|
2287
|
-
return id;
|
|
2319
|
+
return `${prefix}-${nanoid(8)}`;
|
|
2288
2320
|
}
|
|
2289
2321
|
|
|
2290
2322
|
// src/db/collections.ts
|
|
@@ -2436,6 +2468,12 @@ class DuplicateSlugError extends Error {
|
|
|
2436
2468
|
this.name = "DuplicateSlugError";
|
|
2437
2469
|
}
|
|
2438
2470
|
}
|
|
2471
|
+
class ProjectNotFoundError extends Error {
|
|
2472
|
+
constructor(id) {
|
|
2473
|
+
super(`Project not found: ${id}`);
|
|
2474
|
+
this.name = "ProjectNotFoundError";
|
|
2475
|
+
}
|
|
2476
|
+
}
|
|
2439
2477
|
|
|
2440
2478
|
// src/db/prompts.ts
|
|
2441
2479
|
function rowToPrompt(row) {
|
|
@@ -2450,6 +2488,7 @@ function rowToPrompt(row) {
|
|
|
2450
2488
|
tags: JSON.parse(row["tags"] || "[]"),
|
|
2451
2489
|
variables: JSON.parse(row["variables"] || "[]"),
|
|
2452
2490
|
pinned: Boolean(row["pinned"]),
|
|
2491
|
+
project_id: row["project_id"] ?? null,
|
|
2453
2492
|
is_template: Boolean(row["is_template"]),
|
|
2454
2493
|
source: row["source"],
|
|
2455
2494
|
version: row["version"],
|
|
@@ -2473,11 +2512,12 @@ function createPrompt(input) {
|
|
|
2473
2512
|
ensureCollection(collection);
|
|
2474
2513
|
const tags = JSON.stringify(input.tags || []);
|
|
2475
2514
|
const source = input.source || "manual";
|
|
2515
|
+
const project_id = input.project_id ?? null;
|
|
2476
2516
|
const vars = extractVariables(input.body);
|
|
2477
2517
|
const variables = JSON.stringify(vars.map((v) => ({ name: v, required: true })));
|
|
2478
2518
|
const is_template = vars.length > 0 ? 1 : 0;
|
|
2479
|
-
db.run(`INSERT INTO prompts (id, name, slug, title, body, description, collection, tags, variables, is_template, source)
|
|
2480
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [id, name, slug, input.title, input.body, input.description ?? null, collection, tags, variables, is_template, source]);
|
|
2519
|
+
db.run(`INSERT INTO prompts (id, name, slug, title, body, description, collection, tags, variables, is_template, source, project_id)
|
|
2520
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [id, name, slug, input.title, input.body, input.description ?? null, collection, tags, variables, is_template, source, project_id]);
|
|
2481
2521
|
db.run(`INSERT INTO prompt_versions (id, prompt_id, body, version, changed_by)
|
|
2482
2522
|
VALUES (?, ?, ?, 1, ?)`, [generateId("VER"), id, input.body, input.changed_by ?? null]);
|
|
2483
2523
|
return getPrompt(id);
|
|
@@ -2521,10 +2561,16 @@ function listPrompts(filter = {}) {
|
|
|
2521
2561
|
params.push(`%"${tag}"%`);
|
|
2522
2562
|
}
|
|
2523
2563
|
}
|
|
2564
|
+
let orderBy = "pinned DESC, use_count DESC, updated_at DESC";
|
|
2565
|
+
if (filter.project_id !== undefined && filter.project_id !== null) {
|
|
2566
|
+
conditions.push("(project_id = ? OR project_id IS NULL)");
|
|
2567
|
+
params.push(filter.project_id);
|
|
2568
|
+
orderBy = `(CASE WHEN project_id = '${filter.project_id}' THEN 0 ELSE 1 END), pinned DESC, use_count DESC, updated_at DESC`;
|
|
2569
|
+
}
|
|
2524
2570
|
const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
2525
2571
|
const limit = filter.limit ?? 100;
|
|
2526
2572
|
const offset = filter.offset ?? 0;
|
|
2527
|
-
const rows = db.query(`SELECT * FROM prompts ${where} ORDER BY
|
|
2573
|
+
const rows = db.query(`SELECT * FROM prompts ${where} ORDER BY ${orderBy} LIMIT ? OFFSET ?`).all(...params, limit, offset);
|
|
2528
2574
|
return rows.map(rowToPrompt);
|
|
2529
2575
|
}
|
|
2530
2576
|
function updatePrompt(idOrSlug, input) {
|
|
@@ -2657,6 +2703,52 @@ function restoreVersion(promptId, version, changedBy) {
|
|
|
2657
2703
|
VALUES (?, ?, ?, ?, ?)`, [generateId("VER"), promptId, ver.body, newVersion, changedBy ?? null]);
|
|
2658
2704
|
}
|
|
2659
2705
|
|
|
2706
|
+
// src/db/projects.ts
|
|
2707
|
+
function rowToProject(row, promptCount) {
|
|
2708
|
+
return {
|
|
2709
|
+
id: row["id"],
|
|
2710
|
+
name: row["name"],
|
|
2711
|
+
slug: row["slug"],
|
|
2712
|
+
description: row["description"] ?? null,
|
|
2713
|
+
path: row["path"] ?? null,
|
|
2714
|
+
prompt_count: promptCount,
|
|
2715
|
+
created_at: row["created_at"]
|
|
2716
|
+
};
|
|
2717
|
+
}
|
|
2718
|
+
function createProject(input) {
|
|
2719
|
+
const db = getDatabase();
|
|
2720
|
+
const id = generateId("proj");
|
|
2721
|
+
const slug = generateSlug(input.name);
|
|
2722
|
+
db.run(`INSERT INTO projects (id, name, slug, description, path) VALUES (?, ?, ?, ?, ?)`, [id, input.name, slug, input.description ?? null, input.path ?? null]);
|
|
2723
|
+
return getProject(id);
|
|
2724
|
+
}
|
|
2725
|
+
function getProject(idOrSlug) {
|
|
2726
|
+
const db = getDatabase();
|
|
2727
|
+
const id = resolveProject(db, idOrSlug);
|
|
2728
|
+
if (!id)
|
|
2729
|
+
return null;
|
|
2730
|
+
const row = db.query("SELECT * FROM projects WHERE id = ?").get(id);
|
|
2731
|
+
if (!row)
|
|
2732
|
+
return null;
|
|
2733
|
+
const countRow = db.query("SELECT COUNT(*) as n FROM prompts WHERE project_id = ?").get(id);
|
|
2734
|
+
return rowToProject(row, countRow.n);
|
|
2735
|
+
}
|
|
2736
|
+
function listProjects() {
|
|
2737
|
+
const db = getDatabase();
|
|
2738
|
+
const rows = db.query("SELECT * FROM projects ORDER BY name ASC").all();
|
|
2739
|
+
return rows.map((row) => {
|
|
2740
|
+
const countRow = db.query("SELECT COUNT(*) as n FROM prompts WHERE project_id = ?").get(row["id"]);
|
|
2741
|
+
return rowToProject(row, countRow.n);
|
|
2742
|
+
});
|
|
2743
|
+
}
|
|
2744
|
+
function deleteProject(idOrSlug) {
|
|
2745
|
+
const db = getDatabase();
|
|
2746
|
+
const id = resolveProject(db, idOrSlug);
|
|
2747
|
+
if (!id)
|
|
2748
|
+
throw new ProjectNotFoundError(idOrSlug);
|
|
2749
|
+
db.run("DELETE FROM projects WHERE id = ?", [id]);
|
|
2750
|
+
}
|
|
2751
|
+
|
|
2660
2752
|
// src/lib/search.ts
|
|
2661
2753
|
function rowToSearchResult(row, snippet) {
|
|
2662
2754
|
return {
|
|
@@ -2671,6 +2763,7 @@ function rowToSearchResult(row, snippet) {
|
|
|
2671
2763
|
tags: JSON.parse(row["tags"] || "[]"),
|
|
2672
2764
|
variables: JSON.parse(row["variables"] || "[]"),
|
|
2673
2765
|
pinned: Boolean(row["pinned"]),
|
|
2766
|
+
project_id: row["project_id"] ?? null,
|
|
2674
2767
|
is_template: Boolean(row["is_template"]),
|
|
2675
2768
|
source: row["source"],
|
|
2676
2769
|
version: row["version"],
|
|
@@ -2714,6 +2807,10 @@ function searchPrompts(query, filter = {}) {
|
|
|
2714
2807
|
for (const tag of filter.tags)
|
|
2715
2808
|
params.push(`%"${tag}"%`);
|
|
2716
2809
|
}
|
|
2810
|
+
if (filter.project_id !== undefined && filter.project_id !== null) {
|
|
2811
|
+
conditions.push("(p.project_id = ? OR p.project_id IS NULL)");
|
|
2812
|
+
params.push(filter.project_id);
|
|
2813
|
+
}
|
|
2717
2814
|
const where = conditions.length > 0 ? `AND ${conditions.join(" AND ")}` : "";
|
|
2718
2815
|
const limit = filter.limit ?? 50;
|
|
2719
2816
|
const offset = filter.offset ?? 0;
|
|
@@ -2807,10 +2904,17 @@ function lintAll(prompts) {
|
|
|
2807
2904
|
// src/cli/index.tsx
|
|
2808
2905
|
var require2 = createRequire(import.meta.url);
|
|
2809
2906
|
var pkg = require2("../../package.json");
|
|
2810
|
-
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");
|
|
2907
|
+
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");
|
|
2811
2908
|
function isJson() {
|
|
2812
2909
|
return Boolean(program2.opts()["json"]);
|
|
2813
2910
|
}
|
|
2911
|
+
function getActiveProjectId() {
|
|
2912
|
+
const projectName = program2.opts()["project"] ?? process.env["PROMPTS_PROJECT"];
|
|
2913
|
+
if (!projectName)
|
|
2914
|
+
return null;
|
|
2915
|
+
const db = getDatabase();
|
|
2916
|
+
return resolveProject(db, projectName);
|
|
2917
|
+
}
|
|
2814
2918
|
function output(data) {
|
|
2815
2919
|
if (isJson()) {
|
|
2816
2920
|
console.log(JSON.stringify(data, null, 2));
|
|
@@ -2847,6 +2951,7 @@ program2.command("save <title>").description("Save a new prompt (or update exist
|
|
|
2847
2951
|
}
|
|
2848
2952
|
if (!body)
|
|
2849
2953
|
handleError("No body provided. Use --body, --file, or pipe via stdin.");
|
|
2954
|
+
const project_id = getActiveProjectId();
|
|
2850
2955
|
const { prompt, created, duplicate_warning } = upsertPrompt({
|
|
2851
2956
|
title,
|
|
2852
2957
|
body,
|
|
@@ -2855,7 +2960,8 @@ program2.command("save <title>").description("Save a new prompt (or update exist
|
|
|
2855
2960
|
collection: opts["collection"],
|
|
2856
2961
|
tags: opts["tags"] ? opts["tags"].split(",").map((t) => t.trim()) : [],
|
|
2857
2962
|
source: opts["source"] || "manual",
|
|
2858
|
-
changed_by: opts["agent"]
|
|
2963
|
+
changed_by: opts["agent"],
|
|
2964
|
+
project_id
|
|
2859
2965
|
}, Boolean(opts["force"]));
|
|
2860
2966
|
if (duplicate_warning && !isJson()) {
|
|
2861
2967
|
console.warn(chalk.yellow(`Warning: ${duplicate_warning}`));
|
|
@@ -2900,11 +3006,13 @@ program2.command("get <id>").description("Get prompt details without incrementin
|
|
|
2900
3006
|
});
|
|
2901
3007
|
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) => {
|
|
2902
3008
|
try {
|
|
3009
|
+
const project_id = getActiveProjectId();
|
|
2903
3010
|
let prompts = listPrompts({
|
|
2904
3011
|
collection: opts["collection"],
|
|
2905
3012
|
tags: opts["tags"] ? opts["tags"].split(",").map((t) => t.trim()) : undefined,
|
|
2906
3013
|
is_template: opts["templates"] ? true : undefined,
|
|
2907
|
-
limit: parseInt(opts["limit"]) || 50
|
|
3014
|
+
limit: parseInt(opts["limit"]) || 50,
|
|
3015
|
+
...project_id !== null ? { project_id } : {}
|
|
2908
3016
|
});
|
|
2909
3017
|
if (opts["recent"]) {
|
|
2910
3018
|
prompts = prompts.filter((p) => p.last_used_at !== null).sort((a, b) => (b.last_used_at ?? "").localeCompare(a.last_used_at ?? ""));
|
|
@@ -2925,10 +3033,12 @@ ${prompts.length} prompt(s)`));
|
|
|
2925
3033
|
});
|
|
2926
3034
|
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) => {
|
|
2927
3035
|
try {
|
|
3036
|
+
const project_id = getActiveProjectId();
|
|
2928
3037
|
const results = searchPrompts(query, {
|
|
2929
3038
|
collection: opts["collection"],
|
|
2930
3039
|
tags: opts["tags"] ? opts["tags"].split(",").map((t) => t.trim()) : undefined,
|
|
2931
|
-
limit: parseInt(opts["limit"] ?? "20") || 20
|
|
3040
|
+
limit: parseInt(opts["limit"] ?? "20") || 20,
|
|
3041
|
+
...project_id !== null ? { project_id } : {}
|
|
2932
3042
|
});
|
|
2933
3043
|
if (isJson()) {
|
|
2934
3044
|
output(results);
|
|
@@ -3317,4 +3427,77 @@ program2.command("copy <id>").description("Copy prompt body to clipboard and inc
|
|
|
3317
3427
|
handleError(e);
|
|
3318
3428
|
}
|
|
3319
3429
|
});
|
|
3430
|
+
var projectCmd = program2.command("project").description("Manage projects");
|
|
3431
|
+
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) => {
|
|
3432
|
+
try {
|
|
3433
|
+
const project = createProject({ name, description: opts["description"], path: opts["path"] });
|
|
3434
|
+
if (isJson())
|
|
3435
|
+
output(project);
|
|
3436
|
+
else {
|
|
3437
|
+
console.log(`${chalk.green("Created")} project ${chalk.bold(project.name)} \u2014 ${chalk.gray(project.slug)}`);
|
|
3438
|
+
if (project.description)
|
|
3439
|
+
console.log(chalk.gray(` ${project.description}`));
|
|
3440
|
+
}
|
|
3441
|
+
} catch (e) {
|
|
3442
|
+
handleError(e);
|
|
3443
|
+
}
|
|
3444
|
+
});
|
|
3445
|
+
projectCmd.command("list").description("List all projects").action(() => {
|
|
3446
|
+
try {
|
|
3447
|
+
const projects = listProjects();
|
|
3448
|
+
if (isJson()) {
|
|
3449
|
+
output(projects);
|
|
3450
|
+
return;
|
|
3451
|
+
}
|
|
3452
|
+
if (projects.length === 0) {
|
|
3453
|
+
console.log(chalk.gray("No projects."));
|
|
3454
|
+
return;
|
|
3455
|
+
}
|
|
3456
|
+
for (const p of projects) {
|
|
3457
|
+
console.log(`${chalk.bold(p.name)} ${chalk.gray(p.slug)} ${chalk.cyan(`${p.prompt_count} prompt(s)`)}`);
|
|
3458
|
+
if (p.description)
|
|
3459
|
+
console.log(chalk.gray(` ${p.description}`));
|
|
3460
|
+
}
|
|
3461
|
+
} catch (e) {
|
|
3462
|
+
handleError(e);
|
|
3463
|
+
}
|
|
3464
|
+
});
|
|
3465
|
+
projectCmd.command("get <id>").description("Get project details").action((id) => {
|
|
3466
|
+
try {
|
|
3467
|
+
const project = getProject(id);
|
|
3468
|
+
if (!project)
|
|
3469
|
+
handleError(`Project not found: ${id}`);
|
|
3470
|
+
output(isJson() ? project : `${chalk.bold(project.name)} ${chalk.gray(project.slug)} ${chalk.cyan(`${project.prompt_count} prompt(s)`)}`);
|
|
3471
|
+
} catch (e) {
|
|
3472
|
+
handleError(e);
|
|
3473
|
+
}
|
|
3474
|
+
});
|
|
3475
|
+
projectCmd.command("delete <id>").description("Delete a project (prompts become global)").option("-y, --yes", "Skip confirmation").action(async (id, opts) => {
|
|
3476
|
+
try {
|
|
3477
|
+
const project = getProject(id);
|
|
3478
|
+
if (!project)
|
|
3479
|
+
handleError(`Project not found: ${id}`);
|
|
3480
|
+
if (!opts.yes && !isJson()) {
|
|
3481
|
+
const { createInterface } = await import("readline");
|
|
3482
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
3483
|
+
await new Promise((resolve) => {
|
|
3484
|
+
rl.question(chalk.yellow(`Delete project "${project.name}"? Prompts will become global. [y/N] `), (ans) => {
|
|
3485
|
+
rl.close();
|
|
3486
|
+
if (ans.toLowerCase() !== "y") {
|
|
3487
|
+
console.log("Cancelled.");
|
|
3488
|
+
process.exit(0);
|
|
3489
|
+
}
|
|
3490
|
+
resolve();
|
|
3491
|
+
});
|
|
3492
|
+
});
|
|
3493
|
+
}
|
|
3494
|
+
deleteProject(id);
|
|
3495
|
+
if (isJson())
|
|
3496
|
+
output({ deleted: true, id: project.id });
|
|
3497
|
+
else
|
|
3498
|
+
console.log(chalk.red(`Deleted project ${project.name}`));
|
|
3499
|
+
} catch (e) {
|
|
3500
|
+
handleError(e);
|
|
3501
|
+
}
|
|
3502
|
+
});
|
|
3320
3503
|
program2.parse();
|
package/dist/db/database.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ export declare function getDbPath(): string;
|
|
|
3
3
|
export declare function getDatabase(): Database;
|
|
4
4
|
export declare function closeDatabase(): void;
|
|
5
5
|
export declare function resetDatabase(): void;
|
|
6
|
+
export declare function resolveProject(db: Database, idOrSlug: string): string | null;
|
|
6
7
|
export declare function hasFts(db: Database): boolean;
|
|
7
8
|
export declare function resolvePrompt(db: Database, idOrSlug: string): string | null;
|
|
8
9
|
//# sourceMappingURL=database.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/db/database.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAMrC,wBAAgB,SAAS,IAAI,MAAM,CAsBlC;AAED,wBAAgB,WAAW,IAAI,QAAQ,CAmBtC;AAED,wBAAgB,aAAa,IAAI,IAAI,CAKpC;AAGD,wBAAgB,aAAa,IAAI,IAAI,CAEpC;
|
|
1
|
+
{"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/db/database.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAMrC,wBAAgB,SAAS,IAAI,MAAM,CAsBlC;AAED,wBAAgB,WAAW,IAAI,QAAQ,CAmBtC;AAED,wBAAgB,aAAa,IAAI,IAAI,CAKpC;AAGD,wBAAgB,aAAa,IAAI,IAAI,CAEpC;AAqID,wBAAgB,cAAc,CAAC,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CA0B5E;AAED,wBAAgB,MAAM,CAAC,EAAE,EAAE,QAAQ,GAAG,OAAO,CAM5C;AAED,wBAAgB,aAAa,CAAC,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAkC3E"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Project } from "../types/index.js";
|
|
2
|
+
export declare function createProject(input: {
|
|
3
|
+
name: string;
|
|
4
|
+
description?: string;
|
|
5
|
+
path?: string;
|
|
6
|
+
}): Project;
|
|
7
|
+
export declare function getProject(idOrSlug: string): Project | null;
|
|
8
|
+
export declare function listProjects(): Project[];
|
|
9
|
+
export declare function deleteProject(idOrSlug: string): void;
|
|
10
|
+
//# sourceMappingURL=projects.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"projects.d.ts","sourceRoot":"","sources":["../../src/db/projects.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAA;AAehD,wBAAgB,aAAa,CAAC,KAAK,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAWnG;AAED,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAU3D;AAED,wBAAgB,YAAY,IAAI,OAAO,EAAE,CAOxC;AAED,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAKpD"}
|
package/dist/db/prompts.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../src/db/prompts.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,MAAM,EACN,iBAAiB,EACjB,iBAAiB,EACjB,iBAAiB,EAGlB,MAAM,mBAAmB,CAAA;
|
|
1
|
+
{"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../src/db/prompts.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,MAAM,EACN,iBAAiB,EACjB,iBAAiB,EACjB,iBAAiB,EAGlB,MAAM,mBAAmB,CAAA;AA2B1B,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,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,iBAAiB,GAAG,MAAM,CA8C/E;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAInD;AAED,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAQlD;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.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ export { listVersions, getVersion, restoreVersion } from "./db/versions.js";
|
|
|
3
3
|
export { listCollections, getCollection, ensureCollection, movePrompt } from "./db/collections.js";
|
|
4
4
|
export { registerAgent, listAgents } from "./db/agents.js";
|
|
5
5
|
export { getDatabase, getDbPath } from "./db/database.js";
|
|
6
|
+
export { createProject, getProject, listProjects, deleteProject } from "./db/projects.js";
|
|
6
7
|
export { searchPrompts, findSimilar } from "./lib/search.js";
|
|
7
8
|
export { extractVariables, extractVariableInfo, renderTemplate, validateVars } from "./lib/template.js";
|
|
8
9
|
export type { VariableInfo } from "./lib/template.js";
|
|
@@ -10,6 +11,6 @@ export { importFromJson, exportToJson } from "./lib/importer.js";
|
|
|
10
11
|
export { findDuplicates } from "./lib/duplicates.js";
|
|
11
12
|
export type { DuplicateMatch } from "./lib/duplicates.js";
|
|
12
13
|
export { generateSlug, uniqueSlug, generatePromptId } from "./lib/ids.js";
|
|
13
|
-
export type { Prompt, PromptVersion, Collection, Agent, TemplateVariable, PromptSource, CreatePromptInput, UpdatePromptInput, ListPromptsFilter, SearchResult, RenderResult, PromptStats, } from "./types/index.js";
|
|
14
|
-
export { PromptNotFoundError, VersionConflictError, DuplicateSlugError, TemplateRenderError, } from "./types/index.js";
|
|
14
|
+
export type { Prompt, PromptVersion, Collection, Agent, Project, TemplateVariable, PromptSource, CreatePromptInput, UpdatePromptInput, ListPromptsFilter, SearchResult, RenderResult, PromptStats, } from "./types/index.js";
|
|
15
|
+
export { PromptNotFoundError, VersionConflictError, DuplicateSlugError, TemplateRenderError, ProjectNotFoundError, } from "./types/index.js";
|
|
15
16
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,aAAa,EAAE,WAAW,EAAE,YAAY,EAAE,YAAY,EAAE,SAAS,EAAE,YAAY,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AACrK,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AAC3E,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAClG,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAC1D,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,aAAa,EAAE,WAAW,EAAE,YAAY,EAAE,YAAY,EAAE,SAAS,EAAE,YAAY,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AACrK,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AAC3E,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAClG,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAC1D,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AACzD,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAGzF,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAG5D,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AACvG,YAAY,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAGrD,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAChE,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AACpD,YAAY,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AAGzD,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAGzE,YAAY,EACV,MAAM,EACN,aAAa,EACb,UAAU,EACV,KAAK,EACL,OAAO,EACP,gBAAgB,EAChB,YAAY,EACZ,iBAAiB,EACjB,iBAAiB,EACjB,iBAAiB,EACjB,YAAY,EACZ,YAAY,EACZ,WAAW,GACZ,MAAM,kBAAkB,CAAA;AAEzB,OAAO,EACL,mBAAmB,EACnB,oBAAoB,EACpB,kBAAkB,EAClB,mBAAmB,EACnB,oBAAoB,GACrB,MAAM,kBAAkB,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -113,6 +113,21 @@ function runMigrations(db) {
|
|
|
113
113
|
name: "003_pinned",
|
|
114
114
|
sql: `ALTER TABLE prompts ADD COLUMN pinned INTEGER NOT NULL DEFAULT 0;`
|
|
115
115
|
},
|
|
116
|
+
{
|
|
117
|
+
name: "004_projects",
|
|
118
|
+
sql: `
|
|
119
|
+
CREATE TABLE IF NOT EXISTS projects (
|
|
120
|
+
id TEXT PRIMARY KEY,
|
|
121
|
+
name TEXT NOT NULL UNIQUE,
|
|
122
|
+
slug TEXT NOT NULL UNIQUE,
|
|
123
|
+
description TEXT,
|
|
124
|
+
path TEXT,
|
|
125
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
126
|
+
);
|
|
127
|
+
ALTER TABLE prompts ADD COLUMN project_id TEXT REFERENCES projects(id) ON DELETE SET NULL;
|
|
128
|
+
CREATE INDEX IF NOT EXISTS idx_prompts_project_id ON prompts(project_id);
|
|
129
|
+
`
|
|
130
|
+
},
|
|
116
131
|
{
|
|
117
132
|
name: "002_fts5",
|
|
118
133
|
sql: `
|
|
@@ -153,6 +168,24 @@ function runMigrations(db) {
|
|
|
153
168
|
db.run("INSERT INTO _migrations (name) VALUES (?)", [migration.name]);
|
|
154
169
|
}
|
|
155
170
|
}
|
|
171
|
+
function resolveProject(db, idOrSlug) {
|
|
172
|
+
const byId = db.query("SELECT id FROM projects WHERE id = ?").get(idOrSlug);
|
|
173
|
+
if (byId)
|
|
174
|
+
return byId.id;
|
|
175
|
+
const bySlug = db.query("SELECT id FROM projects WHERE slug = ?").get(idOrSlug);
|
|
176
|
+
if (bySlug)
|
|
177
|
+
return bySlug.id;
|
|
178
|
+
const byName = db.query("SELECT id FROM projects WHERE lower(name) = ?").get(idOrSlug.toLowerCase());
|
|
179
|
+
if (byName)
|
|
180
|
+
return byName.id;
|
|
181
|
+
const byPrefix = db.query("SELECT id FROM projects WHERE id LIKE ? LIMIT 2").all(`${idOrSlug}%`);
|
|
182
|
+
if (byPrefix.length === 1 && byPrefix[0])
|
|
183
|
+
return byPrefix[0].id;
|
|
184
|
+
const bySlugPrefix = db.query("SELECT id FROM projects WHERE slug LIKE ? LIMIT 2").all(`${idOrSlug}%`);
|
|
185
|
+
if (bySlugPrefix.length === 1 && bySlugPrefix[0])
|
|
186
|
+
return bySlugPrefix[0].id;
|
|
187
|
+
return null;
|
|
188
|
+
}
|
|
156
189
|
function hasFts(db) {
|
|
157
190
|
return db.query("SELECT 1 FROM sqlite_master WHERE type='table' AND name='prompts_fts'").get() !== null;
|
|
158
191
|
}
|
|
@@ -192,25 +225,24 @@ function uniqueSlug(baseSlug) {
|
|
|
192
225
|
}
|
|
193
226
|
return slug;
|
|
194
227
|
}
|
|
228
|
+
var CHARS = "abcdefghijklmnopqrstuvwxyz0123456789";
|
|
229
|
+
function nanoid(len) {
|
|
230
|
+
let id = "";
|
|
231
|
+
for (let i = 0;i < len; i++) {
|
|
232
|
+
id += CHARS[Math.floor(Math.random() * CHARS.length)];
|
|
233
|
+
}
|
|
234
|
+
return id;
|
|
235
|
+
}
|
|
195
236
|
function generatePromptId() {
|
|
196
237
|
const db = getDatabase();
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
next = parseInt(match[1], 10) + 1;
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
return `PRMT-${String(next).padStart(5, "0")}`;
|
|
238
|
+
let id;
|
|
239
|
+
do {
|
|
240
|
+
id = `prmt-${nanoid(8)}`;
|
|
241
|
+
} while (db.query("SELECT 1 FROM prompts WHERE id = ?").get(id));
|
|
242
|
+
return id;
|
|
206
243
|
}
|
|
207
244
|
function generateId(prefix) {
|
|
208
|
-
|
|
209
|
-
let id = prefix + "-";
|
|
210
|
-
for (let i = 0;i < 8; i++) {
|
|
211
|
-
id += chars[Math.floor(Math.random() * chars.length)];
|
|
212
|
-
}
|
|
213
|
-
return id;
|
|
245
|
+
return `${prefix}-${nanoid(8)}`;
|
|
214
246
|
}
|
|
215
247
|
|
|
216
248
|
// src/db/collections.ts
|
|
@@ -379,6 +411,13 @@ class TemplateRenderError extends Error {
|
|
|
379
411
|
}
|
|
380
412
|
}
|
|
381
413
|
|
|
414
|
+
class ProjectNotFoundError extends Error {
|
|
415
|
+
constructor(id) {
|
|
416
|
+
super(`Project not found: ${id}`);
|
|
417
|
+
this.name = "ProjectNotFoundError";
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
|
|
382
421
|
// src/db/prompts.ts
|
|
383
422
|
function rowToPrompt(row) {
|
|
384
423
|
return {
|
|
@@ -392,6 +431,7 @@ function rowToPrompt(row) {
|
|
|
392
431
|
tags: JSON.parse(row["tags"] || "[]"),
|
|
393
432
|
variables: JSON.parse(row["variables"] || "[]"),
|
|
394
433
|
pinned: Boolean(row["pinned"]),
|
|
434
|
+
project_id: row["project_id"] ?? null,
|
|
395
435
|
is_template: Boolean(row["is_template"]),
|
|
396
436
|
source: row["source"],
|
|
397
437
|
version: row["version"],
|
|
@@ -415,11 +455,12 @@ function createPrompt(input) {
|
|
|
415
455
|
ensureCollection(collection);
|
|
416
456
|
const tags = JSON.stringify(input.tags || []);
|
|
417
457
|
const source = input.source || "manual";
|
|
458
|
+
const project_id = input.project_id ?? null;
|
|
418
459
|
const vars = extractVariables(input.body);
|
|
419
460
|
const variables = JSON.stringify(vars.map((v) => ({ name: v, required: true })));
|
|
420
461
|
const is_template = vars.length > 0 ? 1 : 0;
|
|
421
|
-
db.run(`INSERT INTO prompts (id, name, slug, title, body, description, collection, tags, variables, is_template, source)
|
|
422
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [id, name, slug, input.title, input.body, input.description ?? null, collection, tags, variables, is_template, source]);
|
|
462
|
+
db.run(`INSERT INTO prompts (id, name, slug, title, body, description, collection, tags, variables, is_template, source, project_id)
|
|
463
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [id, name, slug, input.title, input.body, input.description ?? null, collection, tags, variables, is_template, source, project_id]);
|
|
423
464
|
db.run(`INSERT INTO prompt_versions (id, prompt_id, body, version, changed_by)
|
|
424
465
|
VALUES (?, ?, ?, 1, ?)`, [generateId("VER"), id, input.body, input.changed_by ?? null]);
|
|
425
466
|
return getPrompt(id);
|
|
@@ -463,10 +504,16 @@ function listPrompts(filter = {}) {
|
|
|
463
504
|
params.push(`%"${tag}"%`);
|
|
464
505
|
}
|
|
465
506
|
}
|
|
507
|
+
let orderBy = "pinned DESC, use_count DESC, updated_at DESC";
|
|
508
|
+
if (filter.project_id !== undefined && filter.project_id !== null) {
|
|
509
|
+
conditions.push("(project_id = ? OR project_id IS NULL)");
|
|
510
|
+
params.push(filter.project_id);
|
|
511
|
+
orderBy = `(CASE WHEN project_id = '${filter.project_id}' THEN 0 ELSE 1 END), pinned DESC, use_count DESC, updated_at DESC`;
|
|
512
|
+
}
|
|
466
513
|
const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
467
514
|
const limit = filter.limit ?? 100;
|
|
468
515
|
const offset = filter.offset ?? 0;
|
|
469
|
-
const rows = db.query(`SELECT * FROM prompts ${where} ORDER BY
|
|
516
|
+
const rows = db.query(`SELECT * FROM prompts ${where} ORDER BY ${orderBy} LIMIT ? OFFSET ?`).all(...params, limit, offset);
|
|
470
517
|
return rows.map(rowToPrompt);
|
|
471
518
|
}
|
|
472
519
|
function updatePrompt(idOrSlug, input) {
|
|
@@ -626,6 +673,51 @@ function listAgents() {
|
|
|
626
673
|
const rows = db.query("SELECT * FROM agents ORDER BY last_seen_at DESC").all();
|
|
627
674
|
return rows.map(rowToAgent);
|
|
628
675
|
}
|
|
676
|
+
// src/db/projects.ts
|
|
677
|
+
function rowToProject(row, promptCount) {
|
|
678
|
+
return {
|
|
679
|
+
id: row["id"],
|
|
680
|
+
name: row["name"],
|
|
681
|
+
slug: row["slug"],
|
|
682
|
+
description: row["description"] ?? null,
|
|
683
|
+
path: row["path"] ?? null,
|
|
684
|
+
prompt_count: promptCount,
|
|
685
|
+
created_at: row["created_at"]
|
|
686
|
+
};
|
|
687
|
+
}
|
|
688
|
+
function createProject(input) {
|
|
689
|
+
const db = getDatabase();
|
|
690
|
+
const id = generateId("proj");
|
|
691
|
+
const slug = generateSlug(input.name);
|
|
692
|
+
db.run(`INSERT INTO projects (id, name, slug, description, path) VALUES (?, ?, ?, ?, ?)`, [id, input.name, slug, input.description ?? null, input.path ?? null]);
|
|
693
|
+
return getProject(id);
|
|
694
|
+
}
|
|
695
|
+
function getProject(idOrSlug) {
|
|
696
|
+
const db = getDatabase();
|
|
697
|
+
const id = resolveProject(db, idOrSlug);
|
|
698
|
+
if (!id)
|
|
699
|
+
return null;
|
|
700
|
+
const row = db.query("SELECT * FROM projects WHERE id = ?").get(id);
|
|
701
|
+
if (!row)
|
|
702
|
+
return null;
|
|
703
|
+
const countRow = db.query("SELECT COUNT(*) as n FROM prompts WHERE project_id = ?").get(id);
|
|
704
|
+
return rowToProject(row, countRow.n);
|
|
705
|
+
}
|
|
706
|
+
function listProjects() {
|
|
707
|
+
const db = getDatabase();
|
|
708
|
+
const rows = db.query("SELECT * FROM projects ORDER BY name ASC").all();
|
|
709
|
+
return rows.map((row) => {
|
|
710
|
+
const countRow = db.query("SELECT COUNT(*) as n FROM prompts WHERE project_id = ?").get(row["id"]);
|
|
711
|
+
return rowToProject(row, countRow.n);
|
|
712
|
+
});
|
|
713
|
+
}
|
|
714
|
+
function deleteProject(idOrSlug) {
|
|
715
|
+
const db = getDatabase();
|
|
716
|
+
const id = resolveProject(db, idOrSlug);
|
|
717
|
+
if (!id)
|
|
718
|
+
throw new ProjectNotFoundError(idOrSlug);
|
|
719
|
+
db.run("DELETE FROM projects WHERE id = ?", [id]);
|
|
720
|
+
}
|
|
629
721
|
// src/lib/search.ts
|
|
630
722
|
function rowToSearchResult(row, snippet) {
|
|
631
723
|
return {
|
|
@@ -640,6 +732,7 @@ function rowToSearchResult(row, snippet) {
|
|
|
640
732
|
tags: JSON.parse(row["tags"] || "[]"),
|
|
641
733
|
variables: JSON.parse(row["variables"] || "[]"),
|
|
642
734
|
pinned: Boolean(row["pinned"]),
|
|
735
|
+
project_id: row["project_id"] ?? null,
|
|
643
736
|
is_template: Boolean(row["is_template"]),
|
|
644
737
|
source: row["source"],
|
|
645
738
|
version: row["version"],
|
|
@@ -683,6 +776,10 @@ function searchPrompts(query, filter = {}) {
|
|
|
683
776
|
for (const tag of filter.tags)
|
|
684
777
|
params.push(`%"${tag}"%`);
|
|
685
778
|
}
|
|
779
|
+
if (filter.project_id !== undefined && filter.project_id !== null) {
|
|
780
|
+
conditions.push("(p.project_id = ? OR p.project_id IS NULL)");
|
|
781
|
+
params.push(filter.project_id);
|
|
782
|
+
}
|
|
686
783
|
const where = conditions.length > 0 ? `AND ${conditions.join(" AND ")}` : "";
|
|
687
784
|
const limit = filter.limit ?? 50;
|
|
688
785
|
const offset = filter.offset ?? 0;
|
|
@@ -772,12 +869,14 @@ export {
|
|
|
772
869
|
movePrompt,
|
|
773
870
|
listVersions,
|
|
774
871
|
listPrompts,
|
|
872
|
+
listProjects,
|
|
775
873
|
listCollections,
|
|
776
874
|
listAgents,
|
|
777
875
|
importFromJson,
|
|
778
876
|
getVersion,
|
|
779
877
|
getPromptStats,
|
|
780
878
|
getPrompt,
|
|
879
|
+
getProject,
|
|
781
880
|
getDbPath,
|
|
782
881
|
getDatabase,
|
|
783
882
|
getCollection,
|
|
@@ -790,9 +889,12 @@ export {
|
|
|
790
889
|
exportToJson,
|
|
791
890
|
ensureCollection,
|
|
792
891
|
deletePrompt,
|
|
892
|
+
deleteProject,
|
|
793
893
|
createPrompt,
|
|
894
|
+
createProject,
|
|
794
895
|
VersionConflictError,
|
|
795
896
|
TemplateRenderError,
|
|
796
897
|
PromptNotFoundError,
|
|
898
|
+
ProjectNotFoundError,
|
|
797
899
|
DuplicateSlugError
|
|
798
900
|
};
|
package/dist/lib/ids.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ids.d.ts","sourceRoot":"","sources":["../../src/lib/ids.ts"],"names":[],"mappings":"AAEA,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAQlD;AAED,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CASnD;
|
|
1
|
+
{"version":3,"file":"ids.d.ts","sourceRoot":"","sources":["../../src/lib/ids.ts"],"names":[],"mappings":"AAEA,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAQlD;AAED,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CASnD;AAYD,wBAAgB,gBAAgB,IAAI,MAAM,CAOzC;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEjD"}
|
package/dist/lib/search.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/lib/search.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;
|
|
1
|
+
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/lib/search.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AAwCxE,wBAAgB,aAAa,CAC3B,KAAK,EAAE,MAAM,EACb,MAAM,GAAE,IAAI,CAAC,iBAAiB,EAAE,GAAG,CAAM,GACxC,YAAY,EAAE,CAwEhB;AAED,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,SAAI,GAAG,YAAY,EAAE,CAmCvE"}
|