@cerefox/memory 1.7.0 → 1.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENT_GUIDE.md +4 -4
- package/dist/bin/cerefox.js +213 -96
- package/dist/server-assets/_shared/ef-meta/index.ts +2 -2
- package/dist/server-assets/db/migrations/0025_drop_orphaned_overloads.sql +16 -0
- package/dist/server-assets/db/migrations/0026_metadata_guard_and_dead_links.sql +46 -0
- package/dist/server-assets/db/migrations/0027_drop_archived_search_artifacts.sql +172 -0
- package/dist/server-assets/db/rpcs.sql +185 -23
- package/dist/server-assets/db/schema.sql +20 -4
- package/docs/guides/cli.md +21 -0
- package/docs/guides/upgrading.md +9 -0
- package/package.json +2 -2
package/dist/bin/cerefox.js
CHANGED
|
@@ -7438,7 +7438,7 @@ var exports_meta = {};
|
|
|
7438
7438
|
__export(exports_meta, {
|
|
7439
7439
|
PKG_VERSION: () => PKG_VERSION
|
|
7440
7440
|
});
|
|
7441
|
-
var PKG_VERSION = "1.
|
|
7441
|
+
var PKG_VERSION = "1.8.0";
|
|
7442
7442
|
var init_meta = () => {};
|
|
7443
7443
|
|
|
7444
7444
|
// ../../_shared/config/paths.ts
|
|
@@ -25743,7 +25743,7 @@ var init_bundled_docs = __esm(() => {
|
|
|
25743
25743
|
});
|
|
25744
25744
|
|
|
25745
25745
|
// ../../_shared/ef-meta/index.ts
|
|
25746
|
-
var EF_VERSION = "1.
|
|
25746
|
+
var EF_VERSION = "1.8.0", CEREFOX_VERSION = "1.8.0", EF_LAST_CHANGED = "1.7.0";
|
|
25747
25747
|
var init_ef_meta = () => {};
|
|
25748
25748
|
|
|
25749
25749
|
// ../../_shared/compatibility/index.ts
|
|
@@ -41592,10 +41592,10 @@ var require_flate = __commonJS((exports) => {
|
|
|
41592
41592
|
var GenericWorker = require_GenericWorker();
|
|
41593
41593
|
var ARRAY_TYPE = USE_TYPEDARRAY ? "uint8array" : "array";
|
|
41594
41594
|
exports.magic = "\b\x00";
|
|
41595
|
-
function FlateWorker(
|
|
41596
|
-
GenericWorker.call(this, "FlateWorker/" +
|
|
41595
|
+
function FlateWorker(action20, options) {
|
|
41596
|
+
GenericWorker.call(this, "FlateWorker/" + action20);
|
|
41597
41597
|
this._pako = null;
|
|
41598
|
-
this._pakoAction =
|
|
41598
|
+
this._pakoAction = action20;
|
|
41599
41599
|
this._pakoOptions = options;
|
|
41600
41600
|
this.meta = {};
|
|
41601
41601
|
}
|
|
@@ -57699,11 +57699,11 @@ async function runSyncSelfDocs(options = {}) {
|
|
|
57699
57699
|
printTable(outcomes.filter((o) => o.status === "error").map((o) => ({ topic: o.topic, error: o.detail.slice(0, 100) })));
|
|
57700
57700
|
}
|
|
57701
57701
|
}
|
|
57702
|
-
async function
|
|
57702
|
+
async function action22(options) {
|
|
57703
57703
|
await runSyncSelfDocs(options);
|
|
57704
57704
|
}
|
|
57705
57705
|
function registerSyncSelfDocs(program2) {
|
|
57706
|
-
program2.command("sync-self-docs").description("Ingest bundled Cerefox docs under the _cerefox-self-docs project.").option("--dry-run", "List what would be ingested without writing.").option("--project <name>", "Override the target project name.", "_cerefox-self-docs").action(
|
|
57706
|
+
program2.command("sync-self-docs").description("Ingest bundled Cerefox docs under the _cerefox-self-docs project.").option("--dry-run", "List what would be ingested without writing.").option("--project <name>", "Override the target project name.", "_cerefox-self-docs").action(action22);
|
|
57707
57707
|
}
|
|
57708
57708
|
var init_sync_self_docs = __esm(() => {
|
|
57709
57709
|
init_cli_core();
|
|
@@ -72797,11 +72797,48 @@ function registerDeleteDoc(program2) {
|
|
|
72797
72797
|
program2.command("delete-doc").description("Soft-delete a document (recoverable via the web UI trash).").argument("<document-id>", "UUID of the document to delete.").option("--reason <text>", "Optional reason recorded in the audit log.").option("-a, --author <name>", "Caller identity (audit log).").option("--author-type <type>", "'user' or 'agent' (default: user).", "user").option("--yes", "Skip the confirmation prompt.").action(action7);
|
|
72798
72798
|
}
|
|
72799
72799
|
|
|
72800
|
+
// src/cli/commands/document-dead-links.ts
|
|
72801
|
+
init_cli_core();
|
|
72802
|
+
init_client();
|
|
72803
|
+
var SERVER_BEHIND = "The sweep did not run: this server has no cerefox_find_dead_links (needs schema 0.12.2). " + "Run `cerefox server deploy`, then retry.";
|
|
72804
|
+
async function action8(options) {
|
|
72805
|
+
const client = getClient();
|
|
72806
|
+
let rows;
|
|
72807
|
+
try {
|
|
72808
|
+
rows = await client.rpc("cerefox_find_dead_links", {});
|
|
72809
|
+
} catch (e) {
|
|
72810
|
+
const message = e instanceof Error ? e.message : String(e);
|
|
72811
|
+
if (isMissingFunctionError(message, "cerefox_find_dead_links")) {
|
|
72812
|
+
throw systemError(SERVER_BEHIND);
|
|
72813
|
+
}
|
|
72814
|
+
throw e;
|
|
72815
|
+
}
|
|
72816
|
+
if (rows === null)
|
|
72817
|
+
throw systemError(SERVER_BEHIND);
|
|
72818
|
+
if (options.json) {
|
|
72819
|
+
printJson(rows);
|
|
72820
|
+
return;
|
|
72821
|
+
}
|
|
72822
|
+
if (rows.length === 0) {
|
|
72823
|
+
println(c.green("✓ No dead document links found."));
|
|
72824
|
+
return;
|
|
72825
|
+
}
|
|
72826
|
+
println(c.yellow(`${rows.length} dead link(s) across ${new Set(rows.map((r) => r.document_id)).size} document(s):`));
|
|
72827
|
+
for (const r of rows) {
|
|
72828
|
+
println(` ${r.document_title} (${r.document_id})`);
|
|
72829
|
+
println(c.dim(` → [Text](${r.dead_link_id}) ×${r.occurrences} — target no longer exists`));
|
|
72830
|
+
}
|
|
72831
|
+
println(c.dim(`Fix each by editing the linking document (correct the id, remove the link, or backtick it as an example). ` + `The write-time guard prevents NEW dead links; these predate it or lost their target to a purge.`));
|
|
72832
|
+
}
|
|
72833
|
+
function registerDocumentDeadLinks(program2) {
|
|
72834
|
+
program2.command("dead-links").description("Find [Text](uuid) links whose target document no longer exists (#214 phase 2).").option("--json", "Machine-readable output.").action(action8);
|
|
72835
|
+
}
|
|
72836
|
+
|
|
72800
72837
|
// src/cli/commands/delete-project.ts
|
|
72801
72838
|
init_cli_core();
|
|
72802
72839
|
init_client();
|
|
72803
72840
|
var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
72804
|
-
async function
|
|
72841
|
+
async function action9(target, options) {
|
|
72805
72842
|
const client = getClient();
|
|
72806
72843
|
const isUuid = UUID_RE.test(target);
|
|
72807
72844
|
const lookup = isUuid ? client.raw.from("cerefox_projects").select("id, name, description").eq("id", target).maybeSingle() : client.raw.from("cerefox_projects").select("id, name, description").eq("name", target).maybeSingle();
|
|
@@ -72837,7 +72874,7 @@ async function action8(target, options) {
|
|
|
72837
72874
|
println(c.green(`✓ Deleted project "${project.name}" (id: ${project.id}).`));
|
|
72838
72875
|
}
|
|
72839
72876
|
function registerDeleteProject(program2) {
|
|
72840
|
-
program2.command("delete-project").description("Delete an empty project (use --force to remove a non-empty one).").argument("<name-or-id>", "Project name (exact match) or UUID.").option("--yes", "Skip the confirmation prompt.").option("--force", "Allow deletion when documents are still linked to the project.").action(
|
|
72877
|
+
program2.command("delete-project").description("Delete an empty project (use --force to remove a non-empty one).").argument("<name-or-id>", "Project name (exact match) or UUID.").option("--yes", "Skip the confirmation prompt.").option("--force", "Allow deletion when documents are still linked to the project.").action(action9);
|
|
72841
72878
|
}
|
|
72842
72879
|
|
|
72843
72880
|
// src/cli/commands/deploy-server.ts
|
|
@@ -72951,7 +72988,13 @@ async function migrationStatus(opts) {
|
|
|
72951
72988
|
}
|
|
72952
72989
|
async function runDbMigrate(opts) {
|
|
72953
72990
|
const log = opts.log ?? (() => {});
|
|
72954
|
-
const sql = src_default(opts.dbUrl, {
|
|
72991
|
+
const sql = src_default(opts.dbUrl, {
|
|
72992
|
+
prepare: false,
|
|
72993
|
+
onnotice: (n) => {
|
|
72994
|
+
if (n.message)
|
|
72995
|
+
log(` ↳ ${n.message}`);
|
|
72996
|
+
}
|
|
72997
|
+
});
|
|
72955
72998
|
try {
|
|
72956
72999
|
await sql.unsafe(BOOTSTRAP_MIGRATIONS_SQL);
|
|
72957
73000
|
const allFiles = listMigrationFiles(opts.assets.migrationsDir);
|
|
@@ -73043,7 +73086,7 @@ function listEdgeFunctions(functionsDir) {
|
|
|
73043
73086
|
return [];
|
|
73044
73087
|
return readdirSync2(functionsDir, { withFileTypes: true }).filter((e) => e.isDirectory() && e.name.startsWith("cerefox-")).map((e) => e.name).sort();
|
|
73045
73088
|
}
|
|
73046
|
-
async function
|
|
73089
|
+
async function action10(options) {
|
|
73047
73090
|
const settings = loadSettings();
|
|
73048
73091
|
const assets = resolveServerAssets();
|
|
73049
73092
|
const doSchema = !options.functionsOnly;
|
|
@@ -73258,7 +73301,7 @@ Proceed with deployment to Supabase?`, true);
|
|
|
73258
73301
|
println(c.dim("Verify with: cerefox doctor"));
|
|
73259
73302
|
}
|
|
73260
73303
|
function registerDeployServer(program2) {
|
|
73261
|
-
program2.command("deploy-server").description("Deploy/update the Cerefox server side (schema + RPCs + Edge Functions) on Supabase.").option("--dry-run", "Print the plan + pre-flight without deploying.").option("--schema-only", "Deploy/update only the schema + RPCs (skip Edge Functions).").option("--functions-only", "Deploy only the Edge Functions (skip the schema/RPCs).").option("--project-ref <ref>", "Supabase project ref for Edge Function deploys (default: derived from CEREFOX_SUPABASE_URL).").option("--yes", "Non-interactive (skip the deployment confirmation).").action(
|
|
73304
|
+
program2.command("deploy-server").description("Deploy/update the Cerefox server side (schema + RPCs + Edge Functions) on Supabase.").option("--dry-run", "Print the plan + pre-flight without deploying.").option("--schema-only", "Deploy/update only the schema + RPCs (skip Edge Functions).").option("--functions-only", "Deploy only the Edge Functions (skip the schema/RPCs).").option("--project-ref <ref>", "Supabase project ref for Edge Function deploys (default: derived from CEREFOX_SUPABASE_URL).").option("--yes", "Non-interactive (skip the deployment confirmation).").action(action10);
|
|
73262
73305
|
}
|
|
73263
73306
|
|
|
73264
73307
|
// src/cli/commands/document-edit.ts
|
|
@@ -73278,7 +73321,7 @@ function parseMetaPair(pair) {
|
|
|
73278
73321
|
}
|
|
73279
73322
|
return [key, value];
|
|
73280
73323
|
}
|
|
73281
|
-
async function
|
|
73324
|
+
async function action11(documentId, options) {
|
|
73282
73325
|
const hasTitle = options.title !== undefined;
|
|
73283
73326
|
const sets = options.setMeta ?? [];
|
|
73284
73327
|
const unsets = options.unsetMeta ?? [];
|
|
@@ -73296,18 +73339,41 @@ async function action10(documentId, options) {
|
|
|
73296
73339
|
if (doc.deleted_at) {
|
|
73297
73340
|
throw userError(`Document ${documentId} is soft-deleted — restore it first (cerefox document restore).`);
|
|
73298
73341
|
}
|
|
73299
|
-
const
|
|
73300
|
-
for (const pair of sets) {
|
|
73301
|
-
const [k, v] = parseMetaPair(pair);
|
|
73302
|
-
metadata[k] = v;
|
|
73303
|
-
}
|
|
73304
|
-
for (const k of unsets)
|
|
73305
|
-
delete metadata[k.trim()];
|
|
73342
|
+
const metaTouched = sets.length > 0 || unsets.length > 0;
|
|
73306
73343
|
const newTitle = hasTitle ? options.title.trim() : doc.title;
|
|
73307
73344
|
const titleChanged = newTitle !== doc.title;
|
|
73308
|
-
const
|
|
73309
|
-
|
|
73310
|
-
|
|
73345
|
+
const author = resolveAuthor(options.author);
|
|
73346
|
+
const authorType = resolveAuthorType(options.authorType);
|
|
73347
|
+
if (author === "unknown") {
|
|
73348
|
+
warn("No --author / CEREFOX_AUTHOR_NAME set — audit log will record this write as 'unknown'.");
|
|
73349
|
+
}
|
|
73350
|
+
if (metaTouched) {
|
|
73351
|
+
const patch = {};
|
|
73352
|
+
for (const pair of sets) {
|
|
73353
|
+
const [k, v] = parseMetaPair(pair);
|
|
73354
|
+
patch[k] = v;
|
|
73355
|
+
}
|
|
73356
|
+
for (const k of unsets)
|
|
73357
|
+
patch[k.trim()] = null;
|
|
73358
|
+
const { error: metaErr } = await client.raw.rpc("cerefox_set_document_metadata", {
|
|
73359
|
+
p_document_id: documentId,
|
|
73360
|
+
p_metadata: patch,
|
|
73361
|
+
p_replace: false,
|
|
73362
|
+
p_author: author,
|
|
73363
|
+
p_author_type: authorType
|
|
73364
|
+
});
|
|
73365
|
+
if (metaErr) {
|
|
73366
|
+
if (metaErr.message?.includes("CEREFOX_BAD_METADATA")) {
|
|
73367
|
+
throw userError(`Document ${documentId} has non-object metadata; a patch cannot repair it. ` + `Repair it first with: cerefox document set-metadata ${documentId} --replace --json '<the intended object>'`);
|
|
73368
|
+
}
|
|
73369
|
+
throw systemError(`Metadata update failed: ${metaErr.message}`);
|
|
73370
|
+
}
|
|
73371
|
+
}
|
|
73372
|
+
if (hasTitle) {
|
|
73373
|
+
const { error: updErr } = await client.raw.from("cerefox_documents").update({ title: newTitle, updated_at: new Date().toISOString() }).eq("id", documentId);
|
|
73374
|
+
if (updErr)
|
|
73375
|
+
throw systemError(`Update failed: ${updErr.message}`);
|
|
73376
|
+
}
|
|
73311
73377
|
if (titleChanged) {
|
|
73312
73378
|
const { error: ftsErr } = await client.raw.rpc("cerefox_update_chunk_fts", {
|
|
73313
73379
|
p_document_id: documentId,
|
|
@@ -73316,18 +73382,15 @@ async function action10(documentId, options) {
|
|
|
73316
73382
|
if (ftsErr)
|
|
73317
73383
|
throw systemError(`Title updated but FTS refresh failed: ${ftsErr.message}`);
|
|
73318
73384
|
}
|
|
73319
|
-
|
|
73320
|
-
|
|
73321
|
-
|
|
73322
|
-
|
|
73385
|
+
if (titleChanged) {
|
|
73386
|
+
await client.raw.rpc("cerefox_create_audit_entry", {
|
|
73387
|
+
p_document_id: documentId,
|
|
73388
|
+
p_operation: "update-metadata",
|
|
73389
|
+
p_author: author,
|
|
73390
|
+
p_author_type: authorType,
|
|
73391
|
+
p_description: "Edited title"
|
|
73392
|
+
});
|
|
73323
73393
|
}
|
|
73324
|
-
await client.raw.rpc("cerefox_create_audit_entry", {
|
|
73325
|
-
p_document_id: documentId,
|
|
73326
|
-
p_operation: "update-metadata",
|
|
73327
|
-
p_author: author,
|
|
73328
|
-
p_author_type: authorType,
|
|
73329
|
-
p_description: `Edited${titleChanged ? " title" : ""}` + (sets.length ? ` · set ${sets.length} meta key(s)` : "") + (unsets.length ? ` · unset ${unsets.length} meta key(s)` : "")
|
|
73330
|
-
});
|
|
73331
73394
|
println(c.green(`✓ Edited "${newTitle}" (id: ${documentId}).`));
|
|
73332
73395
|
if (titleChanged) {
|
|
73333
73396
|
println(c.dim(" Title changed: FTS refreshed; semantic embeddings update on next `cerefox server reindex`."));
|
|
@@ -73337,13 +73400,13 @@ function collect(value, prev) {
|
|
|
73337
73400
|
return [...prev, value];
|
|
73338
73401
|
}
|
|
73339
73402
|
function registerDocumentEdit(parent) {
|
|
73340
|
-
parent.command("edit").description("Edit a document's title and/or metadata (non-destructive patch). Content edits: `document ingest --document-id <id> --update`.").argument("<document-id>", "UUID of the document.").option("--title <title>", "New title (refreshes FTS; re-embed on next reindex).").option("--set-meta <key=value>", "Set/overwrite a metadata key (repeatable). Value is JSON-parsed when possible.", collect, []).option("--unset-meta <key>", "Remove a metadata key (repeatable).", collect, []).option("-a, --author <name>", "Caller identity (audit log).").option("--author-type <type>", "'user' or 'agent' (default: user).", "user").action(
|
|
73403
|
+
parent.command("edit").description("Edit a document's title and/or metadata (non-destructive patch). Content edits: `document ingest --document-id <id> --update`.").argument("<document-id>", "UUID of the document.").option("--title <title>", "New title (refreshes FTS; re-embed on next reindex).").option("--set-meta <key=value>", "Set/overwrite a metadata key (repeatable). Value is JSON-parsed when possible.", collect, []).option("--unset-meta <key>", "Remove a metadata key (repeatable).", collect, []).option("-a, --author <name>", "Caller identity (audit log).").option("--author-type <type>", "'user' or 'agent' (default: user).", "user").action(action11);
|
|
73341
73404
|
}
|
|
73342
73405
|
|
|
73343
73406
|
// src/cli/commands/document-restore.ts
|
|
73344
73407
|
init_cli_core();
|
|
73345
73408
|
init_client();
|
|
73346
|
-
async function
|
|
73409
|
+
async function action12(documentId, options) {
|
|
73347
73410
|
const client = getClient();
|
|
73348
73411
|
const { data: doc, error } = await client.raw.from("cerefox_documents").select("id, title, deleted_at").eq("id", documentId).maybeSingle();
|
|
73349
73412
|
if (error)
|
|
@@ -73397,13 +73460,13 @@ async function action11(documentId, options) {
|
|
|
73397
73460
|
}
|
|
73398
73461
|
}
|
|
73399
73462
|
function registerDocumentRestore(parent) {
|
|
73400
|
-
parent.command("restore").description("Restore a soft-deleted document from the trash (inverse of `document delete`).").argument("<document-id>", "UUID of the soft-deleted document.").option("--reason <text>", "Optional reason recorded in the audit log.").option("-a, --author <name>", "Caller identity (audit log).").option("--author-type <type>", "'user' or 'agent' (default: user).", "user").action(
|
|
73463
|
+
parent.command("restore").description("Restore a soft-deleted document from the trash (inverse of `document delete`).").argument("<document-id>", "UUID of the soft-deleted document.").option("--reason <text>", "Optional reason recorded in the audit log.").option("-a, --author <name>", "Caller identity (audit log).").option("--author-type <type>", "'user' or 'agent' (default: user).", "user").action(action12);
|
|
73401
73464
|
}
|
|
73402
73465
|
|
|
73403
73466
|
// src/cli/commands/document-set-metadata.ts
|
|
73404
73467
|
init_cli_core();
|
|
73405
73468
|
init_client();
|
|
73406
|
-
async function
|
|
73469
|
+
async function action13(documentId, options) {
|
|
73407
73470
|
const patch = {};
|
|
73408
73471
|
if (options.json) {
|
|
73409
73472
|
let parsed;
|
|
@@ -73475,14 +73538,14 @@ async function action12(documentId, options) {
|
|
|
73475
73538
|
println(c.dim(" Content untouched — no new version, no re-embedding."));
|
|
73476
73539
|
}
|
|
73477
73540
|
function registerDocumentSetMetadata(parent) {
|
|
73478
|
-
parent.command("set-metadata").description("Change a document's metadata without resending its content (merges by default).").argument("<document-id>", "UUID of the document.").option("-s, --set <key=value...>", "Set a key. Repeatable. Values are stored as JSON strings; quote to force JSON parsing.").option("-r, --remove <key...>", "Remove a key. Repeatable. (Sends a JSON null.)").option("--json <object>", "A JSON object of keys to set; a null value removes that key.").option("--replace", "Set the metadata to EXACTLY what was given, discarding every key not listed. Default is merge.").option("-a, --author <name>", "Caller identity (audit log).").option("--author-type <type>", "'user' or 'agent' (default: user).", "user").option("--json-out", "Emit the result as JSON.").action(
|
|
73541
|
+
parent.command("set-metadata").description("Change a document's metadata without resending its content (merges by default).").argument("<document-id>", "UUID of the document.").option("-s, --set <key=value...>", "Set a key. Repeatable. Values are stored as JSON strings; quote to force JSON parsing.").option("-r, --remove <key...>", "Remove a key. Repeatable. (Sends a JSON null.)").option("--json <object>", "A JSON object of keys to set; a null value removes that key.").option("--replace", "Set the metadata to EXACTLY what was given, discarding every key not listed. Default is merge.").option("-a, --author <name>", "Caller identity (audit log).").option("--author-type <type>", "'user' or 'agent' (default: user).", "user").option("--json-out", "Emit the result as JSON.").action(action13);
|
|
73479
73542
|
}
|
|
73480
73543
|
|
|
73481
73544
|
// src/cli/commands/document-set-projects.ts
|
|
73482
73545
|
init_cli_core();
|
|
73483
73546
|
init__projects();
|
|
73484
73547
|
init_client();
|
|
73485
|
-
async function
|
|
73548
|
+
async function action14(documentId, projectNames, options) {
|
|
73486
73549
|
const names = projectNames ?? [];
|
|
73487
73550
|
if (options.clear && names.length > 0) {
|
|
73488
73551
|
throw userError("Pass either project names or --clear, not both.", "Use --clear on its own to remove the document from all projects.");
|
|
@@ -73512,7 +73575,7 @@ async function action13(documentId, projectNames, options) {
|
|
|
73512
73575
|
println(c.dim(" This REPLACED the previous set — any project not listed is no longer associated."));
|
|
73513
73576
|
}
|
|
73514
73577
|
function registerDocumentSetProjects(parent) {
|
|
73515
|
-
parent.command("set-projects").description("Replace a document's project memberships with exactly the given set (or --clear to remove all).").argument("<document-id>", "UUID of the document.").argument("[project-names...]", "Project names to set (created if missing). Omit and pass --clear to remove all.").option("--clear", "Remove the document from all projects.").option("-a, --author <name>", "Caller identity (audit log).").option("--author-type <type>", "'user' or 'agent' (default: user).", "user").action(
|
|
73578
|
+
parent.command("set-projects").description("Replace a document's project memberships with exactly the given set (or --clear to remove all).").argument("<document-id>", "UUID of the document.").argument("[project-names...]", "Project names to set (created if missing). Omit and pass --clear to remove all.").option("--clear", "Remove the document from all projects.").option("-a, --author <name>", "Caller identity (audit log).").option("--author-type <type>", "'user' or 'agent' (default: user).", "user").action(action14);
|
|
73516
73579
|
}
|
|
73517
73580
|
|
|
73518
73581
|
// src/cli/commands/guides.ts
|
|
@@ -73562,7 +73625,7 @@ function registerGuides(parent) {
|
|
|
73562
73625
|
// src/cli/commands/project-create.ts
|
|
73563
73626
|
init_cli_core();
|
|
73564
73627
|
init_client();
|
|
73565
|
-
async function
|
|
73628
|
+
async function action15(name, options) {
|
|
73566
73629
|
const trimmed = name.trim();
|
|
73567
73630
|
if (!trimmed)
|
|
73568
73631
|
throw userError("Project name is required.");
|
|
@@ -73574,14 +73637,14 @@ async function action14(name, options) {
|
|
|
73574
73637
|
println(c.green(`✓ Created project "${data.name}" (id: ${data.id}).`));
|
|
73575
73638
|
}
|
|
73576
73639
|
function registerProjectCreate(parent) {
|
|
73577
|
-
parent.command("create").description("Create a new (empty) project.").argument("<name>", "Project name (must be unique).").option("--description <text>", "Optional project description.").action(
|
|
73640
|
+
parent.command("create").description("Create a new (empty) project.").argument("<name>", "Project name (must be unique).").option("--description <text>", "Optional project description.").action(action15);
|
|
73578
73641
|
}
|
|
73579
73642
|
|
|
73580
73643
|
// src/cli/commands/project-edit.ts
|
|
73581
73644
|
init_cli_core();
|
|
73582
73645
|
init_client();
|
|
73583
73646
|
var UUID_RE2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
73584
|
-
async function
|
|
73647
|
+
async function action16(target, options) {
|
|
73585
73648
|
const update = {};
|
|
73586
73649
|
if (options.name !== undefined) {
|
|
73587
73650
|
const n = options.name.trim();
|
|
@@ -73608,7 +73671,7 @@ async function action15(target, options) {
|
|
|
73608
73671
|
println(c.green(`✓ Updated project "${data.name}" (id: ${data.id}).`));
|
|
73609
73672
|
}
|
|
73610
73673
|
function registerProjectEdit(parent) {
|
|
73611
|
-
parent.command("edit").description("Rename a project and/or change its description.").argument("<name-or-id>", "Project name (exact match) or UUID.").option("--name <new-name>", "New project name.").option("--description <text>", "New project description.").action(
|
|
73674
|
+
parent.command("edit").description("Rename a project and/or change its description.").argument("<name-or-id>", "Project name (exact match) or UUID.").option("--name <new-name>", "New project name.").option("--description <text>", "New project description.").action(action16);
|
|
73612
73675
|
}
|
|
73613
73676
|
|
|
73614
73677
|
// src/cli/commands/version-archive.ts
|
|
@@ -77430,14 +77493,9 @@ async function checkEmbedderMismatch() {
|
|
|
77430
77493
|
};
|
|
77431
77494
|
}
|
|
77432
77495
|
}
|
|
77433
|
-
|
|
77434
|
-
async function checkContentFormat() {
|
|
77435
|
-
const settings = loadSettings();
|
|
77436
|
-
if (!settings.supabaseUrl || !settings.supabaseKey) {
|
|
77437
|
-
return { name: CONTENT_FORMAT_CHECK_NAME, status: "skipped", detail: "Supabase config missing; skipped." };
|
|
77438
|
-
}
|
|
77496
|
+
async function probeRpcJson(settings, fn) {
|
|
77439
77497
|
try {
|
|
77440
|
-
const url = `${settings.supabaseUrl.replace(/\/$/, "")}/rest/v1/rpc
|
|
77498
|
+
const url = `${settings.supabaseUrl.replace(/\/$/, "")}/rest/v1/rpc/${fn}`;
|
|
77441
77499
|
const resp = await fetch(url, {
|
|
77442
77500
|
method: "POST",
|
|
77443
77501
|
headers: {
|
|
@@ -77447,14 +77505,38 @@ async function checkContentFormat() {
|
|
|
77447
77505
|
},
|
|
77448
77506
|
body: "{}"
|
|
77449
77507
|
});
|
|
77450
|
-
if (
|
|
77508
|
+
if (resp.status === 404)
|
|
77509
|
+
return { kind: "absent" };
|
|
77510
|
+
if (!resp.ok)
|
|
77511
|
+
return { kind: "error", detail: `HTTP ${resp.status}` };
|
|
77512
|
+
return { kind: "ok", rows: await resp.json() };
|
|
77513
|
+
} catch (err) {
|
|
77514
|
+
return { kind: "error", detail: err instanceof Error ? err.message : String(err) };
|
|
77515
|
+
}
|
|
77516
|
+
}
|
|
77517
|
+
var CONTENT_FORMAT_CHECK_NAME = "content format";
|
|
77518
|
+
async function checkContentFormat() {
|
|
77519
|
+
const settings = loadSettings();
|
|
77520
|
+
if (!settings.supabaseUrl || !settings.supabaseKey) {
|
|
77521
|
+
return { name: CONTENT_FORMAT_CHECK_NAME, status: "skipped", detail: "Supabase config missing; skipped." };
|
|
77522
|
+
}
|
|
77523
|
+
{
|
|
77524
|
+
const probe = await probeRpcJson(settings, "cerefox_content_format_stats");
|
|
77525
|
+
if (probe.kind === "absent") {
|
|
77451
77526
|
return {
|
|
77452
77527
|
name: CONTENT_FORMAT_CHECK_NAME,
|
|
77453
77528
|
status: "skipped",
|
|
77454
|
-
detail:
|
|
77529
|
+
detail: "format stats unavailable; deploy schema 0.8.0 to enable."
|
|
77455
77530
|
};
|
|
77456
77531
|
}
|
|
77457
|
-
|
|
77532
|
+
if (probe.kind === "error") {
|
|
77533
|
+
return {
|
|
77534
|
+
name: CONTENT_FORMAT_CHECK_NAME,
|
|
77535
|
+
status: "skipped",
|
|
77536
|
+
detail: `content-format check skipped (${probe.detail}).`
|
|
77537
|
+
};
|
|
77538
|
+
}
|
|
77539
|
+
const rows = probe.rows;
|
|
77458
77540
|
const legacy = rows[0]?.legacy_docs ?? 0;
|
|
77459
77541
|
const total = rows[0]?.total_docs ?? 0;
|
|
77460
77542
|
if (legacy === 0) {
|
|
@@ -77470,13 +77552,39 @@ async function checkContentFormat() {
|
|
|
77470
77552
|
detail: `${legacy} of ${total} document(s) use the legacy reconstruction format (format 1).`,
|
|
77471
77553
|
hint: "Harmless — they auto-convert on next edit. To convert them all now: `cerefox server migrate-format` (re-embeds, so try `--dry-run` first). To read what chunk formats are: `cerefox guides show content-format`."
|
|
77472
77554
|
};
|
|
77473
|
-
}
|
|
77555
|
+
}
|
|
77556
|
+
}
|
|
77557
|
+
var METADATA_HEALTH_CHECK_NAME = "metadata health";
|
|
77558
|
+
async function checkMetadataHealth() {
|
|
77559
|
+
const settings = loadSettings();
|
|
77560
|
+
if (!settings.supabaseUrl || !settings.supabaseKey) {
|
|
77561
|
+
return { name: METADATA_HEALTH_CHECK_NAME, status: "skipped", detail: "Supabase config missing; skipped." };
|
|
77562
|
+
}
|
|
77563
|
+
const probe = await probeRpcJson(settings, "cerefox_metadata_health");
|
|
77564
|
+
if (probe.kind === "absent") {
|
|
77474
77565
|
return {
|
|
77475
|
-
name:
|
|
77566
|
+
name: METADATA_HEALTH_CHECK_NAME,
|
|
77567
|
+
status: "skipped",
|
|
77568
|
+
detail: "metadata-health RPC not deployed; deploy schema 0.12.2 to enable."
|
|
77569
|
+
};
|
|
77570
|
+
}
|
|
77571
|
+
if (probe.kind === "error") {
|
|
77572
|
+
return {
|
|
77573
|
+
name: METADATA_HEALTH_CHECK_NAME,
|
|
77476
77574
|
status: "skipped",
|
|
77477
|
-
detail: `
|
|
77575
|
+
detail: `metadata-health check skipped (${probe.detail}).`
|
|
77478
77576
|
};
|
|
77479
77577
|
}
|
|
77578
|
+
if (probe.rows.length === 0) {
|
|
77579
|
+
return { name: METADATA_HEALTH_CHECK_NAME, status: "ok", detail: "all document metadata is well-formed" };
|
|
77580
|
+
}
|
|
77581
|
+
const sample = probe.rows.slice(0, 3).map((r) => `"${r.document_title}" (${r.metadata_type})`).join(", ");
|
|
77582
|
+
return {
|
|
77583
|
+
name: METADATA_HEALTH_CHECK_NAME,
|
|
77584
|
+
status: "skipped",
|
|
77585
|
+
detail: `${probe.rows.length} document(s) hold non-object metadata: ${sample}${probe.rows.length > 3 ? ", …" : ""}.`,
|
|
77586
|
+
hint: "Writes that would merge onto these rows are refused (#212). Repair each with `cerefox document set-metadata <id> --replace --json '<the intended object>'`."
|
|
77587
|
+
};
|
|
77480
77588
|
}
|
|
77481
77589
|
function hasCerefoxInJsonFile(path) {
|
|
77482
77590
|
if (!existsSync10(path))
|
|
@@ -77687,6 +77795,7 @@ async function runAllChecks(opts = {}) {
|
|
|
77687
77795
|
{ name: "schema + RPCs", phase: "Reading schema + RPC version", run: () => checkSchemaVersion() },
|
|
77688
77796
|
{ name: "embedder", phase: "Checking embedder consistency", run: () => checkEmbedderMismatch() },
|
|
77689
77797
|
{ name: "content format", phase: "Checking chunk reconstruction format", run: () => checkContentFormat() },
|
|
77798
|
+
{ name: "metadata health", phase: "Checking metadata well-formedness", run: () => checkMetadataHealth() },
|
|
77690
77799
|
{ name: "edge functions", phase: "Probing Edge Function versions", run: () => checkEdgeFunctionsCompat() },
|
|
77691
77800
|
{ name: "postgres", phase: "Probing Postgres DDL endpoint", run: () => checkPostgres() },
|
|
77692
77801
|
{ name: "mcp clients", phase: "Scanning MCP client configs", run: () => checkMcpConfigs() }
|
|
@@ -77715,7 +77824,7 @@ function symbol(status) {
|
|
|
77715
77824
|
return cErr.dim("ℹ");
|
|
77716
77825
|
}
|
|
77717
77826
|
}
|
|
77718
|
-
async function
|
|
77827
|
+
async function action17(options) {
|
|
77719
77828
|
const useSpinner = !options.json && process.stderr.isTTY;
|
|
77720
77829
|
const spinner = useSpinner ? ora({ text: "Starting checks…", spinner: "dots", stream: process.stderr }).start() : null;
|
|
77721
77830
|
const results = await runAllChecks({
|
|
@@ -77757,6 +77866,10 @@ async function action16(options) {
|
|
|
77757
77866
|
}
|
|
77758
77867
|
if (remediation) {
|
|
77759
77868
|
println(cErr.yellow("→ " + remediation));
|
|
77869
|
+
const configDir = (process.env.CEREFOX_CONFIG_DIR ?? "").trim();
|
|
77870
|
+
if (configDir) {
|
|
77871
|
+
println(cErr.dim(` (this doctor ran against CEREFOX_CONFIG_DIR=${configDir} — ` + `prefix the command above the same way, or use your environment alias, ` + `or a bare \`cerefox\` will act on your DEFAULT environment instead)`));
|
|
77872
|
+
}
|
|
77760
77873
|
println("");
|
|
77761
77874
|
}
|
|
77762
77875
|
}
|
|
@@ -77779,13 +77892,13 @@ async function action16(options) {
|
|
|
77779
77892
|
process.exit(1);
|
|
77780
77893
|
}
|
|
77781
77894
|
function registerDoctor(program2) {
|
|
77782
|
-
program2.command("doctor").description("Run diagnostic checks against the installed Cerefox.").option("--json", "Emit machine-readable JSON (no colours, structured output).").option("--strict", "Exit non-zero when any check warns (default: only errors fail).").action(
|
|
77895
|
+
program2.command("doctor").description("Run diagnostic checks against the installed Cerefox.").option("--json", "Emit machine-readable JSON (no colours, structured output).").option("--strict", "Exit non-zero when any check warns (default: only errors fail).").action(action17);
|
|
77783
77896
|
}
|
|
77784
77897
|
|
|
77785
77898
|
// src/cli/commands/get-audit-log.ts
|
|
77786
77899
|
init_cli_core();
|
|
77787
77900
|
init_client();
|
|
77788
|
-
async function
|
|
77901
|
+
async function action18(options) {
|
|
77789
77902
|
const limit = parsePositiveInt(options.limit, "--limit", 50);
|
|
77790
77903
|
const client = getClient();
|
|
77791
77904
|
const data = await client.rpc("cerefox_list_audit_entries", {
|
|
@@ -77823,7 +77936,7 @@ async function action17(options) {
|
|
|
77823
77936
|
})));
|
|
77824
77937
|
}
|
|
77825
77938
|
function registerGetAuditLog(program2) {
|
|
77826
|
-
program2.command("get-audit-log").description("Query the audit log with optional filters.").option("-d, --document-id <uuid>", "Filter by document.").option("-a, --author <name>", "Filter by author.").option("-o, --operation <type>", "Filter by operation: create, update-content, update-metadata, delete, restore.").option("--since <iso>", "Lower-bound ISO timestamp.").option("--until <iso>", "Upper-bound ISO timestamp.").option("-l, --limit <n>", "Maximum entries (max 200).", "50").option("-r, --requestor <name>", "Agent / user name (usage log).").option("--json", "Emit machine-readable JSON.").action(
|
|
77939
|
+
program2.command("get-audit-log").description("Query the audit log with optional filters.").option("-d, --document-id <uuid>", "Filter by document.").option("-a, --author <name>", "Filter by author.").option("-o, --operation <type>", "Filter by operation: create, update-content, update-metadata, delete, restore.").option("--since <iso>", "Lower-bound ISO timestamp.").option("--until <iso>", "Upper-bound ISO timestamp.").option("-l, --limit <n>", "Maximum entries (max 200).", "50").option("-r, --requestor <name>", "Agent / user name (usage log).").option("--json", "Emit machine-readable JSON.").action(action18);
|
|
77827
77940
|
}
|
|
77828
77941
|
|
|
77829
77942
|
// src/cli/commands/relation.ts
|
|
@@ -77959,7 +78072,7 @@ init_cli_core();
|
|
|
77959
78072
|
init_cli_core();
|
|
77960
78073
|
init_partial_edits();
|
|
77961
78074
|
init_client();
|
|
77962
|
-
async function
|
|
78075
|
+
async function action19(documentId, options) {
|
|
77963
78076
|
const section = (options.section ?? "").trim() || null;
|
|
77964
78077
|
if (section && options.outline) {
|
|
77965
78078
|
throw userError("Pass either --outline (the whole structure) or --section (one section's text), not both.");
|
|
@@ -78056,7 +78169,7 @@ async function action18(documentId, options) {
|
|
|
78056
78169
|
println(doc.full_content);
|
|
78057
78170
|
}
|
|
78058
78171
|
function registerGetDoc(program2) {
|
|
78059
|
-
program2.command("get-doc").description("Retrieve the full content of a document by ID.").argument("<document-id>", "UUID of the document.").option("--version-id <uuid>", "Specific archived version (default: current).").option("-r, --requestor <name>", "Agent / user name (usage log).").option("--json", "Emit machine-readable JSON.").option("--outline", "Show the heading structure, per-section sizes and content_hash instead of the content. Cheap, and the paths are the anchors the edit commands take.").option("--section <anchor>", "Show ONE section's text instead of the whole document: exactly what a replace_section on this anchor would overwrite. Pass the bare heading line when it is unique, or the full ' > ' path from --outline when it repeats.").option("--section-part <part>", "own_body | subtree — only when the target section has child sections, where 'the end' means two different places. You are told (with both options) whenever it is needed.").action(
|
|
78172
|
+
program2.command("get-doc").description("Retrieve the full content of a document by ID.").argument("<document-id>", "UUID of the document.").option("--version-id <uuid>", "Specific archived version (default: current).").option("-r, --requestor <name>", "Agent / user name (usage log).").option("--json", "Emit machine-readable JSON.").option("--outline", "Show the heading structure, per-section sizes and content_hash instead of the content. Cheap, and the paths are the anchors the edit commands take.").option("--section <anchor>", "Show ONE section's text instead of the whole document: exactly what a replace_section on this anchor would overwrite. Pass the bare heading line when it is unique, or the full ' > ' path from --outline when it repeats.").option("--section-part <part>", "own_body | subtree — only when the target section has child sections, where 'the end' means two different places. You are told (with both options) whenever it is needed.").action(action19);
|
|
78060
78173
|
}
|
|
78061
78174
|
|
|
78062
78175
|
// src/cli/commands/ingest.ts
|
|
@@ -78720,7 +78833,7 @@ async function readContent(path, paste) {
|
|
|
78720
78833
|
const titleFromPath = basename2(path, extname3(path));
|
|
78721
78834
|
return { content, titleFromPath };
|
|
78722
78835
|
}
|
|
78723
|
-
async function
|
|
78836
|
+
async function action20(path, options) {
|
|
78724
78837
|
const { content, titleFromPath } = await readContent(path, Boolean(options.paste));
|
|
78725
78838
|
const updatingById = Boolean(options.documentId);
|
|
78726
78839
|
let title = options.title ?? (updatingById ? null : titleFromPath);
|
|
@@ -78811,7 +78924,7 @@ async function action19(path, options) {
|
|
|
78811
78924
|
}
|
|
78812
78925
|
}
|
|
78813
78926
|
function registerIngest(program2) {
|
|
78814
|
-
program2.command("ingest").description("Ingest a file (or stdin paste) into the knowledge base.").argument("[path]", "Path to the file to ingest. Omit when using --paste.").option("--paste", "Read content from stdin instead of a file.").option("-t, --title <title>", "Document title (required with --paste; defaults to filename without extension).").option("-p, --project-name <name>", "Single project membership (non-destructive on update).").option("-P, --project-names <names>", "Comma-separated full project membership set (destructive replace on update).").option("-m, --metadata <json>", "JSON metadata object.").option("--source <label>", 'Origin label. Omit it on an update and the document keeps the source it already has (#193); omit it on a create and it is recorded as "cli".').option("-u, --update-if-exists", "Update an existing doc with the same title.").option("-i, --document-id <uuid>", "Update a specific document by UUID (overrides --update-if-exists).").option("--expected-content-hash <sha256>", "Optimistic-concurrency token: the content_hash of the version this edit is based on (shown by `document get` / `search`). Required on content updates unless --last-write-wins.").option("--last-write-wins", "Skip the concurrency check and overwrite regardless of concurrent changes (recorded in the audit log).").option("-a, --author <name>", "Caller identity (audit log).").option("--author-type <type>", "'user' or 'agent' (default: user).", "user").action(
|
|
78927
|
+
program2.command("ingest").description("Ingest a file (or stdin paste) into the knowledge base.").argument("[path]", "Path to the file to ingest. Omit when using --paste.").option("--paste", "Read content from stdin instead of a file.").option("-t, --title <title>", "Document title (required with --paste; defaults to filename without extension).").option("-p, --project-name <name>", "Single project membership (non-destructive on update).").option("-P, --project-names <names>", "Comma-separated full project membership set (destructive replace on update).").option("-m, --metadata <json>", "JSON metadata object.").option("--source <label>", 'Origin label. Omit it on an update and the document keeps the source it already has (#193); omit it on a create and it is recorded as "cli".').option("-u, --update-if-exists", "Update an existing doc with the same title.").option("-i, --document-id <uuid>", "Update a specific document by UUID (overrides --update-if-exists).").option("--expected-content-hash <sha256>", "Optimistic-concurrency token: the content_hash of the version this edit is based on (shown by `document get` / `search`). Required on content updates unless --last-write-wins.").option("--last-write-wins", "Skip the concurrency check and overwrite regardless of concurrent changes (recorded in the audit log).").option("-a, --author <name>", "Caller identity (audit log).").option("--author-type <type>", "'user' or 'agent' (default: user).", "user").action(action20);
|
|
78815
78928
|
}
|
|
78816
78929
|
|
|
78817
78930
|
// src/cli/commands/document-partial-edit.ts
|
|
@@ -78914,7 +79027,7 @@ function walk(dir, extensions) {
|
|
|
78914
79027
|
}
|
|
78915
79028
|
return files;
|
|
78916
79029
|
}
|
|
78917
|
-
async function
|
|
79030
|
+
async function action21(dir, options) {
|
|
78918
79031
|
const extensions = new Set((options.extensions ?? ".md,.txt").split(",").map((e) => e.trim().toLowerCase()).map((e) => e.startsWith(".") ? e : "." + e).filter((e) => e.length > 0));
|
|
78919
79032
|
const files = walk(dir, extensions);
|
|
78920
79033
|
if (files.length === 0) {
|
|
@@ -78989,7 +79102,7 @@ async function action20(dir, options) {
|
|
|
78989
79102
|
}
|
|
78990
79103
|
}
|
|
78991
79104
|
function registerIngestDir(program2) {
|
|
78992
|
-
program2.command("ingest-dir").description("Recursively ingest a directory of markdown / text files.").argument("<dir>", "Root directory to walk.").option("-p, --project-name <name>", "Project membership for all ingested docs.").option("-m, --metadata <json>", "JSON metadata applied to every doc.").option("--source <label>", 'Origin label. Omit it and each matched document keeps the source it already has (#193); newly created ones are recorded as "cli".').option("-u, --update-if-exists", "Update an existing doc with the same title.").option("-a, --author <name>", "Caller identity (audit log).").option("--author-type <type>", "'user' or 'agent' (default: user).", "user").option("-e, --extensions <list>", "Comma-separated file extensions to ingest.", ".md,.txt").action(
|
|
79105
|
+
program2.command("ingest-dir").description("Recursively ingest a directory of markdown / text files.").argument("<dir>", "Root directory to walk.").option("-p, --project-name <name>", "Project membership for all ingested docs.").option("-m, --metadata <json>", "JSON metadata applied to every doc.").option("--source <label>", 'Origin label. Omit it and each matched document keeps the source it already has (#193); newly created ones are recorded as "cli".').option("-u, --update-if-exists", "Update an existing doc with the same title.").option("-a, --author <name>", "Caller identity (audit log).").option("--author-type <type>", "'user' or 'agent' (default: user).", "user").option("-e, --extensions <list>", "Comma-separated file extensions to ingest.", ".md,.txt").action(action21);
|
|
78993
79106
|
}
|
|
78994
79107
|
|
|
78995
79108
|
// src/cli/commands/init.ts
|
|
@@ -79320,7 +79433,7 @@ function writeAnswersTo(target, answers) {
|
|
|
79320
79433
|
}
|
|
79321
79434
|
}
|
|
79322
79435
|
}
|
|
79323
|
-
async function
|
|
79436
|
+
async function action23(options) {
|
|
79324
79437
|
const homeEnv = join11(homedir7(), USER_STATE_DIR_NAME, ".env");
|
|
79325
79438
|
const cwdEnv = join11(process.cwd(), ".env");
|
|
79326
79439
|
const explicitDir = (process.env.CEREFOX_CONFIG_DIR ?? "").trim();
|
|
@@ -79429,13 +79542,13 @@ async function action22(options) {
|
|
|
79429
79542
|
await postWriteLifecycle(target, options);
|
|
79430
79543
|
}
|
|
79431
79544
|
function registerInit(program2) {
|
|
79432
|
-
program2.command("init").description("Interactive first-run setup (config, schema deploy stub, optional MCP wiring).").option("-c, --config <file>", "Non-interactive mode: read answers from a JSON file.").option("--force", "Overwrite existing configuration without prompting.").option("--skip-schema", "Skip the schema deploy step.").option("--skip-self-docs", "Skip the bundled self-doc ingest.").option("--skip-agent-config", "Skip the optional MCP agent wiring.").action(
|
|
79545
|
+
program2.command("init").description("Interactive first-run setup (config, schema deploy stub, optional MCP wiring).").option("-c, --config <file>", "Non-interactive mode: read answers from a JSON file.").option("--force", "Overwrite existing configuration without prompting.").option("--skip-schema", "Skip the schema deploy step.").option("--skip-self-docs", "Skip the bundled self-doc ingest.").option("--skip-agent-config", "Skip the optional MCP agent wiring.").action(action23);
|
|
79433
79546
|
}
|
|
79434
79547
|
|
|
79435
79548
|
// src/cli/commands/list-docs.ts
|
|
79436
79549
|
init_cli_core();
|
|
79437
79550
|
init_client();
|
|
79438
|
-
async function
|
|
79551
|
+
async function action24(options) {
|
|
79439
79552
|
const deleted = !!options.deleted;
|
|
79440
79553
|
const limit = parsePositiveInt(options.limit, "--limit", 100);
|
|
79441
79554
|
const client = getClient();
|
|
@@ -79491,13 +79604,13 @@ async function action23(options) {
|
|
|
79491
79604
|
}));
|
|
79492
79605
|
}
|
|
79493
79606
|
function registerListDocs(program2) {
|
|
79494
|
-
program2.command("list-docs").description("List documents in the knowledge base.").option("-p, --project <name>", "Filter to a specific project.").option("-l, --limit <n>", "Maximum docs to return.", "100").option("--deleted", "List soft-deleted (trashed) documents instead of active ones.").option("--json", "Emit machine-readable JSON.").action(
|
|
79607
|
+
program2.command("list-docs").description("List documents in the knowledge base.").option("-p, --project <name>", "Filter to a specific project.").option("-l, --limit <n>", "Maximum docs to return.", "100").option("--deleted", "List soft-deleted (trashed) documents instead of active ones.").option("--json", "Emit machine-readable JSON.").action(action24);
|
|
79495
79608
|
}
|
|
79496
79609
|
|
|
79497
79610
|
// src/cli/commands/list-metadata-keys.ts
|
|
79498
79611
|
init_cli_core();
|
|
79499
79612
|
init_client();
|
|
79500
|
-
async function
|
|
79613
|
+
async function action25(options) {
|
|
79501
79614
|
const client = getClient();
|
|
79502
79615
|
const data = await client.rpc("cerefox_list_metadata_keys");
|
|
79503
79616
|
if (data === null) {
|
|
@@ -79525,13 +79638,13 @@ async function action24(options) {
|
|
|
79525
79638
|
})));
|
|
79526
79639
|
}
|
|
79527
79640
|
function registerListMetadataKeys(program2) {
|
|
79528
|
-
program2.command("list-metadata-keys").description("List all metadata keys with document counts and example values.").option("-r, --requestor <name>", "Agent / user name (usage log).").option("--json", "Emit machine-readable JSON.").action(
|
|
79641
|
+
program2.command("list-metadata-keys").description("List all metadata keys with document counts and example values.").option("-r, --requestor <name>", "Agent / user name (usage log).").option("--json", "Emit machine-readable JSON.").action(action25);
|
|
79529
79642
|
}
|
|
79530
79643
|
|
|
79531
79644
|
// src/cli/commands/list-projects.ts
|
|
79532
79645
|
init_cli_core();
|
|
79533
79646
|
init_client();
|
|
79534
|
-
async function
|
|
79647
|
+
async function action26(options) {
|
|
79535
79648
|
const client = getClient();
|
|
79536
79649
|
const { data, error: error2 } = await client.raw.from("cerefox_projects").select("id, name, description, created_at").order("name", { ascending: true });
|
|
79537
79650
|
if (error2) {
|
|
@@ -79560,13 +79673,13 @@ async function action25(options) {
|
|
|
79560
79673
|
})), "(no projects)");
|
|
79561
79674
|
}
|
|
79562
79675
|
function registerListProjects(program2) {
|
|
79563
|
-
program2.command("list-projects").description("List all projects in the knowledge base.").option("-r, --requestor <name>", "Agent / user name (usage log).").option("--json", "Emit machine-readable JSON.").action(
|
|
79676
|
+
program2.command("list-projects").description("List all projects in the knowledge base.").option("-r, --requestor <name>", "Agent / user name (usage log).").option("--json", "Emit machine-readable JSON.").action(action26);
|
|
79564
79677
|
}
|
|
79565
79678
|
|
|
79566
79679
|
// src/cli/commands/list-versions.ts
|
|
79567
79680
|
init_cli_core();
|
|
79568
79681
|
init_client();
|
|
79569
|
-
async function
|
|
79682
|
+
async function action27(documentId, options) {
|
|
79570
79683
|
const client = getClient();
|
|
79571
79684
|
const data = await client.rpc("cerefox_list_document_versions", {
|
|
79572
79685
|
p_document_id: documentId
|
|
@@ -79607,7 +79720,7 @@ async function action26(documentId, options) {
|
|
|
79607
79720
|
})));
|
|
79608
79721
|
}
|
|
79609
79722
|
function registerListVersions(program2) {
|
|
79610
|
-
program2.command("list-versions").description("List archived versions of a document.").argument("<document-id>", "UUID of the document.").option("-r, --requestor <name>", "Agent / user name (usage log).").option("--json", "Emit machine-readable JSON.").action(
|
|
79723
|
+
program2.command("list-versions").description("List archived versions of a document.").argument("<document-id>", "UUID of the document.").option("-r, --requestor <name>", "Agent / user name (usage log).").option("--json", "Emit machine-readable JSON.").action(action27);
|
|
79611
79724
|
}
|
|
79612
79725
|
|
|
79613
79726
|
// src/cli/commands/mcp.ts
|
|
@@ -79639,7 +79752,7 @@ function registerEmbedderWarmup(program2) {
|
|
|
79639
79752
|
// src/cli/commands/metadata-search.ts
|
|
79640
79753
|
init_cli_core();
|
|
79641
79754
|
init_client();
|
|
79642
|
-
async function
|
|
79755
|
+
async function action28(options) {
|
|
79643
79756
|
const metadataFilter = parseJsonObjectArg(options.metadataFilter, "--metadata-filter") ?? {};
|
|
79644
79757
|
if (Object.keys(metadataFilter).length === 0 && !options.projectName && !options.updatedSince && !options.createdSince) {
|
|
79645
79758
|
throw userError("Provide at least one of: --metadata-filter, --project-name, --updated-since, or --created-since.", `Examples: --metadata-filter '{"type":"decision-log"}' · --project-name "research" (lists that project's docs).`);
|
|
@@ -79702,7 +79815,7 @@ async function action27(options) {
|
|
|
79702
79815
|
}
|
|
79703
79816
|
}
|
|
79704
79817
|
function registerMetadataSearch(program2) {
|
|
79705
|
-
program2.command("metadata-search").description("Find or list documents by metadata, project, or time criteria (no text query).").option("-f, --metadata-filter <json>", "JSON object; only docs whose metadata contains ALL pairs are returned. Optional — omit to list by --project-name / time range alone (at least one criterion is required).").option("-p, --project-name <name>", "Filter to a specific project.").option("--updated-since <iso>", "Only docs updated on/after this ISO timestamp.").option("--created-since <iso>", "Only docs created on/after this ISO timestamp.").option("--include-content", "Include full document text in results.").option("-l, --limit <n>", "Maximum docs to return.", "10").option("--max-bytes <n>", "Response size budget in bytes (with --include-content).", "200000").option("-r, --requestor <name>", "Agent / user name (usage log).").option("--json", "Emit machine-readable JSON.").action(
|
|
79818
|
+
program2.command("metadata-search").description("Find or list documents by metadata, project, or time criteria (no text query).").option("-f, --metadata-filter <json>", "JSON object; only docs whose metadata contains ALL pairs are returned. Optional — omit to list by --project-name / time range alone (at least one criterion is required).").option("-p, --project-name <name>", "Filter to a specific project.").option("--updated-since <iso>", "Only docs updated on/after this ISO timestamp.").option("--created-since <iso>", "Only docs created on/after this ISO timestamp.").option("--include-content", "Include full document text in results.").option("-l, --limit <n>", "Maximum docs to return.", "10").option("--max-bytes <n>", "Response size budget in bytes (with --include-content).", "200000").option("-r, --requestor <name>", "Agent / user name (usage log).").option("--json", "Emit machine-readable JSON.").action(action28);
|
|
79706
79819
|
}
|
|
79707
79820
|
|
|
79708
79821
|
// src/cli/commands/reindex.ts
|
|
@@ -79728,7 +79841,7 @@ function warnLargeBulkWrite(opts) {
|
|
|
79728
79841
|
}
|
|
79729
79842
|
|
|
79730
79843
|
// src/cli/commands/reindex.ts
|
|
79731
|
-
async function
|
|
79844
|
+
async function action29(options) {
|
|
79732
79845
|
const settings = loadSettings();
|
|
79733
79846
|
if (!settings.supabaseUrl || !settings.supabaseKey) {
|
|
79734
79847
|
throw userError("Supabase credentials not configured — run `cerefox init` first.");
|
|
@@ -79818,7 +79931,7 @@ ${c2.content}`;
|
|
|
79818
79931
|
}
|
|
79819
79932
|
}
|
|
79820
79933
|
function registerReindex(program2) {
|
|
79821
|
-
program2.command("reindex").description("Re-embed existing document chunks (v0.7+).").option("--all", "Reindex every chunk regardless of embedder.").option("--batch <n>", "Chunks per OpenAI batch call. Capped at 96 internally.", "32").option("--dry-run", "Show counts without re-embedding.").option("-i, --document-id <uuid>", "Limit reindex to a single document.").action(
|
|
79934
|
+
program2.command("reindex").description("Re-embed existing document chunks (v0.7+).").option("--all", "Reindex every chunk regardless of embedder.").option("--batch <n>", "Chunks per OpenAI batch call. Capped at 96 internally.", "32").option("--dry-run", "Show counts without re-embedding.").option("-i, --document-id <uuid>", "Limit reindex to a single document.").action(action29);
|
|
79822
79935
|
}
|
|
79823
79936
|
|
|
79824
79937
|
// src/cli/commands/migrate-format.ts
|
|
@@ -79826,7 +79939,7 @@ init_cli_core();
|
|
|
79826
79939
|
init_config();
|
|
79827
79940
|
init_client();
|
|
79828
79941
|
var CURRENT_FORMAT = 2;
|
|
79829
|
-
async function
|
|
79942
|
+
async function action30(options) {
|
|
79830
79943
|
const settings = loadSettings();
|
|
79831
79944
|
const client = getClient();
|
|
79832
79945
|
const supabase = client.raw;
|
|
@@ -79953,7 +80066,7 @@ async function action29(options) {
|
|
|
79953
80066
|
}
|
|
79954
80067
|
}
|
|
79955
80068
|
function registerMigrateFormat(program2) {
|
|
79956
|
-
program2.command("migrate-format").description("Convert legacy-format documents to the current chunk format (re-chunks + re-embeds).").option("--dry-run", "Report how many documents would be converted; write nothing.").option("-l, --limit <n>", "Convert at most N documents (re-run to continue).").option("--document-id <uuid>", "Convert a single document.").option("--author <name>", "Recorded in the audit log for each conversion.").action(
|
|
80069
|
+
program2.command("migrate-format").description("Convert legacy-format documents to the current chunk format (re-chunks + re-embeds).").option("--dry-run", "Report how many documents would be converted; write nothing.").option("-l, --limit <n>", "Convert at most N documents (re-run to continue).").option("--document-id <uuid>", "Convert a single document.").option("--author <name>", "Recorded in the audit log for each conversion.").action(action30);
|
|
79957
80070
|
}
|
|
79958
80071
|
|
|
79959
80072
|
// src/cli/commands/restore.ts
|
|
@@ -79983,7 +80096,7 @@ function resolveBackupFile(target) {
|
|
|
79983
80096
|
}
|
|
79984
80097
|
return join12(path, candidates[0].name);
|
|
79985
80098
|
}
|
|
79986
|
-
async function
|
|
80099
|
+
async function action31(target, options) {
|
|
79987
80100
|
const file = resolveBackupFile(target);
|
|
79988
80101
|
let payload;
|
|
79989
80102
|
try {
|
|
@@ -80118,7 +80231,7 @@ async function action30(target, options) {
|
|
|
80118
80231
|
}
|
|
80119
80232
|
}
|
|
80120
80233
|
function registerRestore(program2) {
|
|
80121
|
-
program2.command("restore").description("Restore a JSON-snapshot backup into the knowledge base.").argument("<snapshot>", "Backup file (or directory; most recent is picked) produced by `cerefox backup`.").option("--dry-run", "Print what would be restored without writing.").option("-p, --project-name <name>", "Reserved for future use; currently ignored. Project memberships are restored from the backup itself (format 2+).").action(
|
|
80234
|
+
program2.command("restore").description("Restore a JSON-snapshot backup into the knowledge base.").argument("<snapshot>", "Backup file (or directory; most recent is picked) produced by `cerefox backup`.").option("--dry-run", "Print what would be restored without writing.").option("-p, --project-name <name>", "Reserved for future use; currently ignored. Project memberships are restored from the backup itself (format 2+).").action(action31);
|
|
80122
80235
|
}
|
|
80123
80236
|
|
|
80124
80237
|
// src/cli/commands/search.ts
|
|
@@ -80143,7 +80256,7 @@ async function embedQuery(query) {
|
|
|
80143
80256
|
}
|
|
80144
80257
|
|
|
80145
80258
|
// src/cli/commands/search.ts
|
|
80146
|
-
async function
|
|
80259
|
+
async function action32(query, options) {
|
|
80147
80260
|
if (!query || query.trim() === "") {
|
|
80148
80261
|
throw userError("Empty query.");
|
|
80149
80262
|
}
|
|
@@ -80309,7 +80422,7 @@ async function action31(query, options) {
|
|
|
80309
80422
|
}
|
|
80310
80423
|
}
|
|
80311
80424
|
function registerSearch(program2) {
|
|
80312
|
-
program2.command("search").description("Search the knowledge base (hybrid FTS + semantic).").argument("<query>", "Natural-language search query.").option("-c, --match-count <n>", "Maximum number of documents to return.", "5").option("-p, --project-name <name>", "Filter results to a specific project.").option("-f, --metadata-filter <json>", "JSON containment filter; only docs whose metadata contains ALL pairs are returned.").option("--mode <mode>", "Search mode: docs (default), hybrid, fts.", "docs").option("--alpha <float>", "Semantic weight 0..1 (default: CEREFOX_SEARCH_ALPHA; else 0.7).").option("--min-score <float>", "Minimum cosine similarity threshold (default: CEREFOX_MIN_SEARCH_SCORE; else 0.5, or 0.6 with the local embedder).").option("--min-term-coverage <float>", "OR-fallback keyword matches must cover at least this fraction of the query's meaningful terms to count as confident hits (default: CEREFOX_MIN_TERM_COVERAGE; else the server default 0.5; needs schema ≥ 0.9.1).").option("--max-bytes <n>", "Response size budget in bytes (default: CEREFOX_MAX_RESPONSE_BYTES or 200000).").option("-r, --requestor <name>", "Agent / user name (recorded in usage log).").option("--json", "Emit machine-readable JSON instead of the default text.").option("--only-metadata", "List matching docs (id, score, chunks, chars, partial/full) WITHOUT their content — like the web UI's collapsed result list. Grab a [id:…] then `cerefox document get <id>`.").action(
|
|
80425
|
+
program2.command("search").description("Search the knowledge base (hybrid FTS + semantic).").argument("<query>", "Natural-language search query.").option("-c, --match-count <n>", "Maximum number of documents to return.", "5").option("-p, --project-name <name>", "Filter results to a specific project.").option("-f, --metadata-filter <json>", "JSON containment filter; only docs whose metadata contains ALL pairs are returned.").option("--mode <mode>", "Search mode: docs (default), hybrid, fts.", "docs").option("--alpha <float>", "Semantic weight 0..1 (default: CEREFOX_SEARCH_ALPHA; else 0.7).").option("--min-score <float>", "Minimum cosine similarity threshold (default: CEREFOX_MIN_SEARCH_SCORE; else 0.5, or 0.6 with the local embedder).").option("--min-term-coverage <float>", "OR-fallback keyword matches must cover at least this fraction of the query's meaningful terms to count as confident hits (default: CEREFOX_MIN_TERM_COVERAGE; else the server default 0.5; needs schema ≥ 0.9.1).").option("--max-bytes <n>", "Response size budget in bytes (default: CEREFOX_MAX_RESPONSE_BYTES or 200000).").option("-r, --requestor <name>", "Agent / user name (recorded in usage log).").option("--json", "Emit machine-readable JSON instead of the default text.").option("--only-metadata", "List matching docs (id, score, chunks, chars, partial/full) WITHOUT their content — like the web UI's collapsed result list. Grab a [id:…] then `cerefox document get <id>`.").action(action32);
|
|
80313
80426
|
}
|
|
80314
80427
|
|
|
80315
80428
|
// src/cli/commands/self-update.ts
|
|
@@ -80356,7 +80469,7 @@ async function fetchLatestVersion() {
|
|
|
80356
80469
|
}
|
|
80357
80470
|
return body.version;
|
|
80358
80471
|
}
|
|
80359
|
-
async function
|
|
80472
|
+
async function action33(options) {
|
|
80360
80473
|
let target;
|
|
80361
80474
|
try {
|
|
80362
80475
|
target = options.version ?? await fetchLatestVersion();
|
|
@@ -80409,7 +80522,7 @@ async function action32(options) {
|
|
|
80409
80522
|
}
|
|
80410
80523
|
function registerSelfUpdate(program2) {
|
|
80411
80524
|
const desc = "Upgrade Cerefox in place. Alias: `cerefox upgrade`.";
|
|
80412
|
-
const declaration = (cmd) => cmd.description(desc).option("--check", "Print current vs latest; do nothing.").option("--yes", "Non-interactive (skip confirmation).").option("--version <version>", "Pin a specific version (e.g. 0.5.1 or 0.6.0-rc.1).").action(
|
|
80525
|
+
const declaration = (cmd) => cmd.description(desc).option("--check", "Print current vs latest; do nothing.").option("--yes", "Non-interactive (skip confirmation).").option("--version <version>", "Pin a specific version (e.g. 0.5.1 or 0.6.0-rc.1).").action(action33);
|
|
80413
80526
|
declaration(program2.command("self-update"));
|
|
80414
80527
|
declaration(program2.command("upgrade"));
|
|
80415
80528
|
}
|
|
@@ -80428,7 +80541,7 @@ function symbol2(status) {
|
|
|
80428
80541
|
return cErr.dim("ℹ");
|
|
80429
80542
|
}
|
|
80430
80543
|
}
|
|
80431
|
-
async function
|
|
80544
|
+
async function action34(options) {
|
|
80432
80545
|
const useSpinner = !options.json && process.stderr.isTTY;
|
|
80433
80546
|
const spinner = useSpinner ? ora({ text: "Starting checks…", spinner: "dots", stream: process.stderr }).start() : null;
|
|
80434
80547
|
const results = await runFastChecks({
|
|
@@ -80449,7 +80562,7 @@ async function action33(options) {
|
|
|
80449
80562
|
}
|
|
80450
80563
|
}
|
|
80451
80564
|
function registerStatus(program2) {
|
|
80452
|
-
program2.command("status").description("Quick sanity check (fast subset of `cerefox doctor`).").option("--json", "Emit machine-readable JSON.").action(
|
|
80565
|
+
program2.command("status").description("Quick sanity check (fast subset of `cerefox doctor`).").option("--json", "Emit machine-readable JSON.").action(action34);
|
|
80453
80566
|
}
|
|
80454
80567
|
|
|
80455
80568
|
// src/cli/commands/token.ts
|
|
@@ -80482,10 +80595,10 @@ function upsertEnvVar(path, key, value, opts = {}) {
|
|
|
80482
80595
|
}
|
|
80483
80596
|
const re = new RegExp(`^(\\s*)${escapeRegExp(key)}=.*$`, "m");
|
|
80484
80597
|
let next;
|
|
80485
|
-
let
|
|
80598
|
+
let action35;
|
|
80486
80599
|
if (re.test(original)) {
|
|
80487
80600
|
next = original.replace(re, `$1${line}`);
|
|
80488
|
-
|
|
80601
|
+
action35 = "updated";
|
|
80489
80602
|
} else {
|
|
80490
80603
|
const base = original.endsWith(`
|
|
80491
80604
|
`) ? original : `${original}
|
|
@@ -80493,10 +80606,10 @@ function upsertEnvVar(path, key, value, opts = {}) {
|
|
|
80493
80606
|
next = `${base}
|
|
80494
80607
|
${header}${line}
|
|
80495
80608
|
`;
|
|
80496
|
-
|
|
80609
|
+
action35 = "added";
|
|
80497
80610
|
}
|
|
80498
80611
|
writeFileSync5(path, next);
|
|
80499
|
-
return { path, action:
|
|
80612
|
+
return { path, action: action35, backupPath };
|
|
80500
80613
|
}
|
|
80501
80614
|
function readEnvVar(path, key) {
|
|
80502
80615
|
if (!existsSync14(path))
|
|
@@ -85069,6 +85182,9 @@ function registerDocumentWriteRoutes(app, ctx) {
|
|
|
85069
85182
|
const title = String(body.title ?? "").trim();
|
|
85070
85183
|
const content = String(body.content ?? "");
|
|
85071
85184
|
const projectIds = Array.isArray(body.project_ids) ? body.project_ids : [];
|
|
85185
|
+
if (body.metadata !== undefined && body.metadata !== null && (typeof body.metadata !== "object" || Array.isArray(body.metadata))) {
|
|
85186
|
+
return c2.json({ success: false, error: "metadata must be a JSON object of key/value pairs" }, 400);
|
|
85187
|
+
}
|
|
85072
85188
|
const metadata = body.metadata ?? {};
|
|
85073
85189
|
const doc2 = await getCurrentDoc(ctx, documentId);
|
|
85074
85190
|
if (!doc2) {
|
|
@@ -86334,6 +86450,7 @@ Learn more:
|
|
|
86334
86450
|
moveInto(document2, registerGetDoc, "get");
|
|
86335
86451
|
moveInto(document2, registerListDocs, "list");
|
|
86336
86452
|
moveInto(document2, registerDeleteDoc, "delete");
|
|
86453
|
+
moveInto(document2, registerDocumentDeadLinks, "dead-links");
|
|
86337
86454
|
registerDocumentRestore(document2);
|
|
86338
86455
|
registerDocumentEdit(document2);
|
|
86339
86456
|
registerDocumentSetProjects(document2);
|