@cerefox/memory 0.7.2 → 0.8.1
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/bin/cerefox.js +1357 -361
- package/dist/frontend/assets/{index-BzAPcCXA.js → index-CAp2_lFX.js} +2 -2
- package/dist/frontend/assets/index-CAp2_lFX.js.map +1 -0
- package/dist/frontend/index.html +1 -1
- package/dist/server-assets/_shared/ef-meta/index.ts +97 -0
- package/dist/server-assets/_shared/embeddings/index.ts +175 -0
- package/dist/server-assets/_shared/mcp-tools/_chunker.ts +187 -0
- package/dist/server-assets/_shared/mcp-tools/_projects.ts +121 -0
- package/dist/server-assets/_shared/mcp-tools/_utils.ts +73 -0
- package/dist/server-assets/_shared/mcp-tools/audit-log.ts +95 -0
- package/dist/server-assets/_shared/mcp-tools/get-document.ts +73 -0
- package/dist/server-assets/_shared/mcp-tools/get-help-content.ts +26 -0
- package/dist/server-assets/_shared/mcp-tools/get-help.ts +90 -0
- package/dist/server-assets/_shared/mcp-tools/index.ts +67 -0
- package/dist/server-assets/_shared/mcp-tools/ingest.ts +315 -0
- package/dist/server-assets/_shared/mcp-tools/list-metadata-keys.ts +55 -0
- package/dist/server-assets/_shared/mcp-tools/list-projects.ts +59 -0
- package/dist/server-assets/_shared/mcp-tools/list-versions.ts +72 -0
- package/dist/server-assets/_shared/mcp-tools/metadata-search.ts +154 -0
- package/dist/server-assets/_shared/mcp-tools/search.ts +193 -0
- package/dist/server-assets/_shared/mcp-tools/set-document-projects.ts +163 -0
- package/dist/server-assets/_shared/mcp-tools/types.ts +92 -0
- package/dist/server-assets/db/migrations/0003_add_document_versions.sql +91 -0
- package/dist/server-assets/db/migrations/0004_add_audit_log_review_status_archived.sql +71 -0
- package/dist/server-assets/db/migrations/0005_metadata_search.sql +628 -0
- package/dist/server-assets/db/migrations/0006_usage_log.sql +255 -0
- package/dist/server-assets/db/migrations/0007_usage_log_requestor.sql +178 -0
- package/dist/server-assets/db/migrations/0008_soft_delete.sql +130 -0
- package/dist/server-assets/db/migrations/0009_audit_log_restore_operation.sql +20 -0
- package/dist/server-assets/db/migrations/0010_requestor_enforcement_config.sql +12 -0
- package/dist/server-assets/db/migrations/0011_title_boosting.sql +48 -0
- package/dist/server-assets/db/rpcs.sql +1723 -0
- package/dist/server-assets/db/schema.sql +380 -0
- package/dist/server-assets/supabase/functions/cerefox-get-audit-log/index.ts +117 -0
- package/dist/server-assets/supabase/functions/cerefox-get-document/index.ts +138 -0
- package/dist/server-assets/supabase/functions/cerefox-ingest/index.ts +819 -0
- package/dist/server-assets/supabase/functions/cerefox-list-projects/index.ts +96 -0
- package/dist/server-assets/supabase/functions/cerefox-list-versions/index.ts +113 -0
- package/dist/server-assets/supabase/functions/cerefox-mcp/index.ts +294 -0
- package/dist/server-assets/supabase/functions/cerefox-mcp/shared.ts +42 -0
- package/dist/server-assets/supabase/functions/cerefox-metadata/index.ts +99 -0
- package/dist/server-assets/supabase/functions/cerefox-metadata-search/index.ts +146 -0
- package/dist/server-assets/supabase/functions/cerefox-search/index.ts +382 -0
- package/docs/guides/connect-agents.md +78 -3
- package/docs/guides/migration-v0.5.md +50 -0
- package/docs/guides/quickstart.md +6 -2
- package/package.json +3 -2
- package/dist/frontend/assets/index-BzAPcCXA.js.map +0 -1
package/dist/bin/cerefox.js
CHANGED
|
@@ -182,6 +182,10 @@ function printTable(rows, emptyMessage = "(no rows)") {
|
|
|
182
182
|
println(line(headers.map((h) => String(row[h] ?? ""))));
|
|
183
183
|
}
|
|
184
184
|
}
|
|
185
|
+
function localTimestamp(d = new Date) {
|
|
186
|
+
const p = (n, w = 2) => String(n).padStart(w, "0");
|
|
187
|
+
return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())} ` + `${p(d.getHours())}:${p(d.getMinutes())}:${p(d.getSeconds())}.${p(d.getMilliseconds(), 3)}`;
|
|
188
|
+
}
|
|
185
189
|
function eprintln(line = "") {
|
|
186
190
|
process.stderr.write(line + `
|
|
187
191
|
`);
|
|
@@ -5315,6 +5319,7 @@ __export(exports_cli_core, {
|
|
|
5315
5319
|
parseFloat01: () => parseFloat01,
|
|
5316
5320
|
ok: () => ok,
|
|
5317
5321
|
notFound: () => notFound,
|
|
5322
|
+
localTimestamp: () => localTimestamp,
|
|
5318
5323
|
info: () => info,
|
|
5319
5324
|
errorln: () => errorln,
|
|
5320
5325
|
eprintln: () => eprintln,
|
|
@@ -7179,7 +7184,7 @@ var exports_meta = {};
|
|
|
7179
7184
|
__export(exports_meta, {
|
|
7180
7185
|
PKG_VERSION: () => PKG_VERSION
|
|
7181
7186
|
});
|
|
7182
|
-
var PKG_VERSION = "0.
|
|
7187
|
+
var PKG_VERSION = "0.8.1";
|
|
7183
7188
|
var init_meta = () => {};
|
|
7184
7189
|
|
|
7185
7190
|
// ../../node_modules/.bun/tslib@2.8.1/node_modules/tslib/tslib.js
|
|
@@ -22585,6 +22590,7 @@ function loadSettings(opts = {}) {
|
|
|
22585
22590
|
return {
|
|
22586
22591
|
supabaseUrl: env2.CEREFOX_SUPABASE_URL ?? "",
|
|
22587
22592
|
supabaseKey: env2.CEREFOX_SUPABASE_KEY ?? "",
|
|
22593
|
+
supabaseAnonKey: env2.CEREFOX_SUPABASE_ANON_KEY ?? "",
|
|
22588
22594
|
databaseUrl: env2.CEREFOX_DATABASE_URL ?? "",
|
|
22589
22595
|
openaiApiKey: env2.CEREFOX_OPENAI_API_KEY ?? env2.OPENAI_API_KEY ?? "",
|
|
22590
22596
|
fireworksApiKey: env2.CEREFOX_FIREWORKS_API_KEY ?? ""
|
|
@@ -22631,99 +22637,6 @@ var init_client = __esm(() => {
|
|
|
22631
22637
|
init_cli_core();
|
|
22632
22638
|
});
|
|
22633
22639
|
|
|
22634
|
-
// src/cli/util/bundled-docs.ts
|
|
22635
|
-
import { existsSync as existsSync4, readdirSync, readFileSync as readFileSync4, statSync } from "node:fs";
|
|
22636
|
-
import { dirname as dirname2, join as join4, resolve as resolve2 } from "node:path";
|
|
22637
|
-
import { fileURLToPath } from "node:url";
|
|
22638
|
-
function findPackageRoot() {
|
|
22639
|
-
let dir = dirname2(fileURLToPath(import.meta.url));
|
|
22640
|
-
for (let i = 0;i < 10; i++) {
|
|
22641
|
-
const pkgJson = join4(dir, "package.json");
|
|
22642
|
-
if (existsSync4(pkgJson)) {
|
|
22643
|
-
try {
|
|
22644
|
-
const parsed = JSON.parse(readFileSync4(pkgJson, "utf8"));
|
|
22645
|
-
if (parsed.name === "@cerefox/memory")
|
|
22646
|
-
return dir;
|
|
22647
|
-
} catch {}
|
|
22648
|
-
}
|
|
22649
|
-
const parent = dirname2(dir);
|
|
22650
|
-
if (parent === dir)
|
|
22651
|
-
break;
|
|
22652
|
-
dir = parent;
|
|
22653
|
-
}
|
|
22654
|
-
return resolve2(dirname2(fileURLToPath(import.meta.url)), "..", "..", "..");
|
|
22655
|
-
}
|
|
22656
|
-
function bundledDocsDir() {
|
|
22657
|
-
const inPackage = join4(PACKAGE_ROOT, "docs");
|
|
22658
|
-
if (existsSync4(inPackage))
|
|
22659
|
-
return inPackage;
|
|
22660
|
-
return resolve2(PACKAGE_ROOT, "..", "..", "docs");
|
|
22661
|
-
}
|
|
22662
|
-
function agentGuidePath() {
|
|
22663
|
-
const candidates = [
|
|
22664
|
-
join4(PACKAGE_ROOT, "AGENT_GUIDE.md"),
|
|
22665
|
-
resolve2(PACKAGE_ROOT, "..", "..", "AGENT_GUIDE.md")
|
|
22666
|
-
];
|
|
22667
|
-
for (const c2 of candidates)
|
|
22668
|
-
if (existsSync4(c2))
|
|
22669
|
-
return c2;
|
|
22670
|
-
return null;
|
|
22671
|
-
}
|
|
22672
|
-
function agentQuickReferencePath() {
|
|
22673
|
-
const candidates = [
|
|
22674
|
-
join4(PACKAGE_ROOT, "AGENT_QUICK_REFERENCE.md"),
|
|
22675
|
-
resolve2(PACKAGE_ROOT, "..", "..", "AGENT_QUICK_REFERENCE.md")
|
|
22676
|
-
];
|
|
22677
|
-
for (const c2 of candidates)
|
|
22678
|
-
if (existsSync4(c2))
|
|
22679
|
-
return c2;
|
|
22680
|
-
return null;
|
|
22681
|
-
}
|
|
22682
|
-
function listBundledDocs() {
|
|
22683
|
-
const entries = [];
|
|
22684
|
-
const docsDir = bundledDocsDir();
|
|
22685
|
-
const guidesDir = join4(docsDir, "guides");
|
|
22686
|
-
if (existsSync4(guidesDir) && statSync(guidesDir).isDirectory()) {
|
|
22687
|
-
for (const name of readdirSync(guidesDir)) {
|
|
22688
|
-
if (!name.endsWith(".md"))
|
|
22689
|
-
continue;
|
|
22690
|
-
const full = join4(guidesDir, name);
|
|
22691
|
-
entries.push({
|
|
22692
|
-
topic: name.replace(/\.md$/, ""),
|
|
22693
|
-
path: full,
|
|
22694
|
-
size: statSync(full).size
|
|
22695
|
-
});
|
|
22696
|
-
}
|
|
22697
|
-
}
|
|
22698
|
-
const ag = agentGuidePath();
|
|
22699
|
-
if (ag)
|
|
22700
|
-
entries.push({ topic: "agent-guide", path: ag, size: statSync(ag).size });
|
|
22701
|
-
const aqr = agentQuickReferencePath();
|
|
22702
|
-
if (aqr) {
|
|
22703
|
-
entries.push({
|
|
22704
|
-
topic: "agent-quick-reference",
|
|
22705
|
-
path: aqr,
|
|
22706
|
-
size: statSync(aqr).size
|
|
22707
|
-
});
|
|
22708
|
-
}
|
|
22709
|
-
entries.sort((a, b) => a.topic.localeCompare(b.topic));
|
|
22710
|
-
return entries;
|
|
22711
|
-
}
|
|
22712
|
-
function readBundledDoc(topic) {
|
|
22713
|
-
const entry = listBundledDocs().find((d) => d.topic === topic);
|
|
22714
|
-
if (!entry)
|
|
22715
|
-
return null;
|
|
22716
|
-
return {
|
|
22717
|
-
topic: entry.topic,
|
|
22718
|
-
path: entry.path,
|
|
22719
|
-
content: readFileSync4(entry.path, "utf8")
|
|
22720
|
-
};
|
|
22721
|
-
}
|
|
22722
|
-
var PACKAGE_ROOT;
|
|
22723
|
-
var init_bundled_docs = __esm(() => {
|
|
22724
|
-
PACKAGE_ROOT = findPackageRoot();
|
|
22725
|
-
});
|
|
22726
|
-
|
|
22727
22640
|
// ../../node_modules/.bun/postgres@3.4.9/node_modules/postgres/src/query.js
|
|
22728
22641
|
function cachedError(xs) {
|
|
22729
22642
|
if (originCache.has(xs))
|
|
@@ -22742,9 +22655,9 @@ var init_query = __esm(() => {
|
|
|
22742
22655
|
CLOSE = {};
|
|
22743
22656
|
Query = class Query extends Promise {
|
|
22744
22657
|
constructor(strings, args, handler, canceller, options = {}) {
|
|
22745
|
-
let
|
|
22658
|
+
let resolve2, reject;
|
|
22746
22659
|
super((a, b) => {
|
|
22747
|
-
|
|
22660
|
+
resolve2 = a;
|
|
22748
22661
|
reject = b;
|
|
22749
22662
|
});
|
|
22750
22663
|
this.tagged = Array.isArray(strings.raw);
|
|
@@ -22755,7 +22668,7 @@ var init_query = __esm(() => {
|
|
|
22755
22668
|
this.options = options;
|
|
22756
22669
|
this.state = null;
|
|
22757
22670
|
this.statement = null;
|
|
22758
|
-
this.resolve = (x) => (this.active = false,
|
|
22671
|
+
this.resolve = (x) => (this.active = false, resolve2(x));
|
|
22759
22672
|
this.reject = (x) => (this.active = false, reject(x));
|
|
22760
22673
|
this.active = false;
|
|
22761
22674
|
this.cancelled = null;
|
|
@@ -22803,12 +22716,12 @@ var init_query = __esm(() => {
|
|
|
22803
22716
|
if (this.executed && !this.active)
|
|
22804
22717
|
return { done: true };
|
|
22805
22718
|
prev && prev();
|
|
22806
|
-
const promise = new Promise((
|
|
22719
|
+
const promise = new Promise((resolve2, reject) => {
|
|
22807
22720
|
this.cursorFn = (value) => {
|
|
22808
|
-
|
|
22721
|
+
resolve2({ value, done: false });
|
|
22809
22722
|
return new Promise((r) => prev = r);
|
|
22810
22723
|
};
|
|
22811
|
-
this.resolve = () => (this.active = false,
|
|
22724
|
+
this.resolve = () => (this.active = false, resolve2({ done: true }));
|
|
22812
22725
|
this.reject = (x) => (this.active = false, reject(x));
|
|
22813
22726
|
});
|
|
22814
22727
|
this.execute();
|
|
@@ -22867,31 +22780,31 @@ var init_query = __esm(() => {
|
|
|
22867
22780
|
// ../../node_modules/.bun/postgres@3.4.9/node_modules/postgres/src/errors.js
|
|
22868
22781
|
function connection(x, options, socket) {
|
|
22869
22782
|
const { host, port } = socket || options;
|
|
22870
|
-
const
|
|
22783
|
+
const error = Object.assign(new Error("write " + x + " " + (options.path || host + ":" + port)), {
|
|
22871
22784
|
code: x,
|
|
22872
22785
|
errno: x,
|
|
22873
22786
|
address: options.path || host
|
|
22874
22787
|
}, options.path ? {} : { port });
|
|
22875
|
-
Error.captureStackTrace(
|
|
22876
|
-
return
|
|
22788
|
+
Error.captureStackTrace(error, connection);
|
|
22789
|
+
return error;
|
|
22877
22790
|
}
|
|
22878
22791
|
function postgres(x) {
|
|
22879
|
-
const
|
|
22880
|
-
Error.captureStackTrace(
|
|
22881
|
-
return
|
|
22792
|
+
const error = new PostgresError(x);
|
|
22793
|
+
Error.captureStackTrace(error, postgres);
|
|
22794
|
+
return error;
|
|
22882
22795
|
}
|
|
22883
22796
|
function generic(code, message) {
|
|
22884
|
-
const
|
|
22885
|
-
Error.captureStackTrace(
|
|
22886
|
-
return
|
|
22797
|
+
const error = Object.assign(new Error(code + ": " + message), { code });
|
|
22798
|
+
Error.captureStackTrace(error, generic);
|
|
22799
|
+
return error;
|
|
22887
22800
|
}
|
|
22888
22801
|
function notSupported(x) {
|
|
22889
|
-
const
|
|
22802
|
+
const error = Object.assign(new Error(x + " (B) is not supported"), {
|
|
22890
22803
|
code: "MESSAGE_NOT_SUPPORTED",
|
|
22891
22804
|
name: x
|
|
22892
22805
|
});
|
|
22893
|
-
Error.captureStackTrace(
|
|
22894
|
-
return
|
|
22806
|
+
Error.captureStackTrace(error, notSupported);
|
|
22807
|
+
return error;
|
|
22895
22808
|
}
|
|
22896
22809
|
var PostgresError, Errors;
|
|
22897
22810
|
var init_errors2 = __esm(() => {
|
|
@@ -23239,7 +23152,7 @@ function fit(x) {
|
|
|
23239
23152
|
prev.copy(buffer);
|
|
23240
23153
|
}
|
|
23241
23154
|
}
|
|
23242
|
-
function
|
|
23155
|
+
function reset() {
|
|
23243
23156
|
b.i = 0;
|
|
23244
23157
|
return b;
|
|
23245
23158
|
}
|
|
@@ -23255,7 +23168,7 @@ var init_bytes = __esm(() => {
|
|
|
23255
23168
|
};
|
|
23256
23169
|
return acc;
|
|
23257
23170
|
}, {});
|
|
23258
|
-
b = Object.assign(
|
|
23171
|
+
b = Object.assign(reset, messages, {
|
|
23259
23172
|
N: String.fromCharCode(0),
|
|
23260
23173
|
i: 0,
|
|
23261
23174
|
inc(x) {
|
|
@@ -23354,22 +23267,22 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
|
|
|
23354
23267
|
try {
|
|
23355
23268
|
x = options.socket ? await Promise.resolve(options.socket(options)) : new net.Socket;
|
|
23356
23269
|
} catch (e) {
|
|
23357
|
-
|
|
23270
|
+
error(e);
|
|
23358
23271
|
return;
|
|
23359
23272
|
}
|
|
23360
|
-
x.on("error",
|
|
23273
|
+
x.on("error", error);
|
|
23361
23274
|
x.on("close", closed);
|
|
23362
23275
|
x.on("drain", drain);
|
|
23363
23276
|
return x;
|
|
23364
23277
|
}
|
|
23365
|
-
async function cancel({ pid, secret },
|
|
23278
|
+
async function cancel({ pid, secret }, resolve2, reject) {
|
|
23366
23279
|
try {
|
|
23367
23280
|
cancelMessage = bytes_default().i32(16).i32(80877102).i32(pid).i32(secret).end(16);
|
|
23368
23281
|
await connect();
|
|
23369
23282
|
socket.once("error", reject);
|
|
23370
|
-
socket.once("close",
|
|
23371
|
-
} catch (
|
|
23372
|
-
reject(
|
|
23283
|
+
socket.once("close", resolve2);
|
|
23284
|
+
} catch (error2) {
|
|
23285
|
+
reject(error2);
|
|
23373
23286
|
}
|
|
23374
23287
|
}
|
|
23375
23288
|
function execute(q) {
|
|
@@ -23384,9 +23297,9 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
|
|
|
23384
23297
|
query ? sent.push(q) : (query = q, query.active = true);
|
|
23385
23298
|
build(q);
|
|
23386
23299
|
return write(toBuffer(q)) && !q.describeFirst && !q.cursorFn && sent.length < max_pipeline && (!q.options.onexecute || q.options.onexecute(connection2));
|
|
23387
|
-
} catch (
|
|
23300
|
+
} catch (error2) {
|
|
23388
23301
|
sent.length === 0 && write(Sync);
|
|
23389
|
-
errored(
|
|
23302
|
+
errored(error2);
|
|
23390
23303
|
return true;
|
|
23391
23304
|
}
|
|
23392
23305
|
}
|
|
@@ -23465,7 +23378,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
|
|
|
23465
23378
|
socket.removeAllListeners();
|
|
23466
23379
|
socket = tls.connect(options2);
|
|
23467
23380
|
socket.on("secureConnect", connected);
|
|
23468
|
-
socket.on("error",
|
|
23381
|
+
socket.on("error", error);
|
|
23469
23382
|
socket.on("close", closed);
|
|
23470
23383
|
socket.on("drain", drain);
|
|
23471
23384
|
}
|
|
@@ -23531,10 +23444,10 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
|
|
|
23531
23444
|
const s = StartupMessage();
|
|
23532
23445
|
write(s);
|
|
23533
23446
|
} catch (err) {
|
|
23534
|
-
|
|
23447
|
+
error(err);
|
|
23535
23448
|
}
|
|
23536
23449
|
}
|
|
23537
|
-
function
|
|
23450
|
+
function error(err) {
|
|
23538
23451
|
if (connection2.queue === queues.connecting && options.host[retries + 1])
|
|
23539
23452
|
return;
|
|
23540
23453
|
errored(err);
|
|
@@ -23567,7 +23480,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
|
|
|
23567
23480
|
function terminate() {
|
|
23568
23481
|
terminated = true;
|
|
23569
23482
|
if (stream || query || initial || sent.length)
|
|
23570
|
-
|
|
23483
|
+
error(Errors.connection("CONNECTION_DESTROYED", options));
|
|
23571
23484
|
clearImmediate(nextWriteTimer);
|
|
23572
23485
|
if (socket) {
|
|
23573
23486
|
socket.removeListener("data", data);
|
|
@@ -23590,7 +23503,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
|
|
|
23590
23503
|
socket = null;
|
|
23591
23504
|
if (initial)
|
|
23592
23505
|
return reconnect();
|
|
23593
|
-
!hadError && (query || sent.length) &&
|
|
23506
|
+
!hadError && (query || sent.length) && error(Errors.connection("CONNECTION_CLOSED", options, socket));
|
|
23594
23507
|
closedTime = performance.now();
|
|
23595
23508
|
hadError && options.shared.retries++;
|
|
23596
23509
|
delay = (typeof backoff === "function" ? backoff(options.shared.retries) : backoff) * 1000;
|
|
@@ -23814,9 +23727,9 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
|
|
|
23814
23727
|
errored(Errors.postgres(parseError(x)));
|
|
23815
23728
|
}
|
|
23816
23729
|
}
|
|
23817
|
-
function retry(q,
|
|
23730
|
+
function retry(q, error2) {
|
|
23818
23731
|
delete statements[q.signature];
|
|
23819
|
-
q.retried =
|
|
23732
|
+
q.retried = error2;
|
|
23820
23733
|
execute(q);
|
|
23821
23734
|
}
|
|
23822
23735
|
function NotificationResponse(x) {
|
|
@@ -23847,9 +23760,9 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
|
|
|
23847
23760
|
write(chunk2, encoding, callback) {
|
|
23848
23761
|
socket.write(bytes_default().d().raw(chunk2).end(), callback);
|
|
23849
23762
|
},
|
|
23850
|
-
destroy(
|
|
23851
|
-
callback(
|
|
23852
|
-
socket.write(bytes_default().f().str(
|
|
23763
|
+
destroy(error2, callback) {
|
|
23764
|
+
callback(error2);
|
|
23765
|
+
socket.write(bytes_default().f().str(error2 + bytes_default.N).end());
|
|
23853
23766
|
stream = null;
|
|
23854
23767
|
},
|
|
23855
23768
|
final(callback) {
|
|
@@ -23877,9 +23790,9 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
|
|
|
23877
23790
|
write(chunk2, encoding, callback) {
|
|
23878
23791
|
socket.write(bytes_default().d().raw(chunk2).end(), callback);
|
|
23879
23792
|
},
|
|
23880
|
-
destroy(
|
|
23881
|
-
callback(
|
|
23882
|
-
socket.write(bytes_default().f().str(
|
|
23793
|
+
destroy(error2, callback) {
|
|
23794
|
+
callback(error2);
|
|
23795
|
+
socket.write(bytes_default().f().str(error2 + bytes_default.N).end());
|
|
23883
23796
|
stream = null;
|
|
23884
23797
|
},
|
|
23885
23798
|
final(callback) {
|
|
@@ -23955,15 +23868,15 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
|
|
|
23955
23868
|
}
|
|
23956
23869
|
}
|
|
23957
23870
|
function parseError(x) {
|
|
23958
|
-
const
|
|
23871
|
+
const error = {};
|
|
23959
23872
|
let start = 5;
|
|
23960
23873
|
for (let i = 5;i < x.length - 1; i++) {
|
|
23961
23874
|
if (x[i] === 0) {
|
|
23962
|
-
|
|
23875
|
+
error[errorFields[x[start]]] = x.toString("utf8", start + 1, i);
|
|
23963
23876
|
start = i + 1;
|
|
23964
23877
|
}
|
|
23965
23878
|
}
|
|
23966
|
-
return
|
|
23879
|
+
return error;
|
|
23967
23880
|
}
|
|
23968
23881
|
function md5(x) {
|
|
23969
23882
|
return crypto2.createHash("md5").update(x).digest("hex");
|
|
@@ -24109,10 +24022,10 @@ function Subscribe(postgres2, options) {
|
|
|
24109
24022
|
lsn: Buffer.concat(x.consistent_point.split("/").map((x2) => Buffer.from(("00000000" + x2).slice(-8), "hex")))
|
|
24110
24023
|
};
|
|
24111
24024
|
stream2.on("data", data);
|
|
24112
|
-
stream2.on("error",
|
|
24025
|
+
stream2.on("error", error);
|
|
24113
24026
|
stream2.on("close", sql2.close);
|
|
24114
24027
|
return { stream: stream2, state: xs.state };
|
|
24115
|
-
function
|
|
24028
|
+
function error(e) {
|
|
24116
24029
|
console.error("Unexpected error during logical streaming - reconnecting", e);
|
|
24117
24030
|
}
|
|
24118
24031
|
function data(x2) {
|
|
@@ -24240,7 +24153,7 @@ var noop2 = () => {};
|
|
|
24240
24153
|
// ../../node_modules/.bun/postgres@3.4.9/node_modules/postgres/src/large.js
|
|
24241
24154
|
import Stream2 from "stream";
|
|
24242
24155
|
function largeObject(sql, oid, mode = 131072 | 262144) {
|
|
24243
|
-
return new Promise(async (
|
|
24156
|
+
return new Promise(async (resolve2, reject) => {
|
|
24244
24157
|
await sql.begin(async (sql2) => {
|
|
24245
24158
|
let finish;
|
|
24246
24159
|
!oid && ([{ oid }] = await sql2`select lo_creat(-1) as oid`);
|
|
@@ -24266,7 +24179,7 @@ function largeObject(sql, oid, mode = 131072 | 262144) {
|
|
|
24266
24179
|
) seek
|
|
24267
24180
|
`
|
|
24268
24181
|
};
|
|
24269
|
-
|
|
24182
|
+
resolve2(lo);
|
|
24270
24183
|
return new Promise(async (r) => finish = r);
|
|
24271
24184
|
async function readable({
|
|
24272
24185
|
highWaterMark = 2048 * 8,
|
|
@@ -24309,7 +24222,7 @@ var exports_src = {};
|
|
|
24309
24222
|
__export(exports_src, {
|
|
24310
24223
|
default: () => src_default
|
|
24311
24224
|
});
|
|
24312
|
-
import
|
|
24225
|
+
import os from "os";
|
|
24313
24226
|
import fs from "fs";
|
|
24314
24227
|
function Postgres(a, b2) {
|
|
24315
24228
|
const options = parseOptions(a, b2), subscribe = options.no_subscribe || Subscribe(Postgres, { ...options });
|
|
@@ -24426,8 +24339,8 @@ function Postgres(a, b2) {
|
|
|
24426
24339
|
}
|
|
24427
24340
|
async function reserve() {
|
|
24428
24341
|
const queue = queue_default();
|
|
24429
|
-
const c2 = open.length ? open.shift() : await new Promise((
|
|
24430
|
-
const query = { reserve:
|
|
24342
|
+
const c2 = open.length ? open.shift() : await new Promise((resolve2, reject) => {
|
|
24343
|
+
const query = { reserve: resolve2, reject };
|
|
24431
24344
|
queries.push(query);
|
|
24432
24345
|
closed.length && connect(closed.shift(), query);
|
|
24433
24346
|
});
|
|
@@ -24454,8 +24367,8 @@ function Postgres(a, b2) {
|
|
|
24454
24367
|
scope(connection2, fn),
|
|
24455
24368
|
new Promise((_, reject) => connection2.onclose = reject)
|
|
24456
24369
|
]);
|
|
24457
|
-
} catch (
|
|
24458
|
-
throw
|
|
24370
|
+
} catch (error) {
|
|
24371
|
+
throw error;
|
|
24459
24372
|
}
|
|
24460
24373
|
async function scope(c2, fn2, name) {
|
|
24461
24374
|
const sql2 = Sql(handler2);
|
|
@@ -24464,9 +24377,9 @@ function Postgres(a, b2) {
|
|
|
24464
24377
|
let uncaughtError, result;
|
|
24465
24378
|
name && await sql2`savepoint ${sql2(name)}`;
|
|
24466
24379
|
try {
|
|
24467
|
-
result = await new Promise((
|
|
24380
|
+
result = await new Promise((resolve2, reject) => {
|
|
24468
24381
|
const x = fn2(sql2);
|
|
24469
|
-
Promise.resolve(Array.isArray(x) ? Promise.all(x) : x).then(
|
|
24382
|
+
Promise.resolve(Array.isArray(x) ? Promise.all(x) : x).then(resolve2, reject);
|
|
24470
24383
|
});
|
|
24471
24384
|
if (uncaughtError)
|
|
24472
24385
|
throw uncaughtError;
|
|
@@ -24523,8 +24436,8 @@ function Postgres(a, b2) {
|
|
|
24523
24436
|
return c2.execute(query) ? move(c2, busy) : move(c2, full);
|
|
24524
24437
|
}
|
|
24525
24438
|
function cancel(query) {
|
|
24526
|
-
return new Promise((
|
|
24527
|
-
query.state ? query.active ? connection_default(options).cancel(query.state,
|
|
24439
|
+
return new Promise((resolve2, reject) => {
|
|
24440
|
+
query.state ? query.active ? connection_default(options).cancel(query.state, resolve2, reject) : query.cancelled = { resolve: resolve2, reject } : (queries.remove(query), query.cancelled = true, query.reject(Errors.generic("57014", "canceling statement due to user request")), resolve2());
|
|
24528
24441
|
});
|
|
24529
24442
|
}
|
|
24530
24443
|
async function end({ timeout = null } = {}) {
|
|
@@ -24540,11 +24453,11 @@ function Postgres(a, b2) {
|
|
|
24540
24453
|
async function close() {
|
|
24541
24454
|
await Promise.all(connections.map((c2) => c2.end()));
|
|
24542
24455
|
}
|
|
24543
|
-
async function destroy(
|
|
24456
|
+
async function destroy(resolve2) {
|
|
24544
24457
|
await Promise.all(connections.map((c2) => c2.terminate()));
|
|
24545
24458
|
while (queries.length)
|
|
24546
24459
|
queries.shift().reject(Errors.connection("CONNECTION_DESTROYED", options));
|
|
24547
|
-
|
|
24460
|
+
resolve2();
|
|
24548
24461
|
}
|
|
24549
24462
|
function connect(c2, query) {
|
|
24550
24463
|
move(c2, connecting);
|
|
@@ -24577,7 +24490,7 @@ function Postgres(a, b2) {
|
|
|
24577
24490
|
function parseOptions(a, b2) {
|
|
24578
24491
|
if (a && a.shared)
|
|
24579
24492
|
return a;
|
|
24580
|
-
const
|
|
24493
|
+
const env3 = process.env, o = (!a || typeof a === "string" ? b2 : a) || {}, { url, multihost } = parseUrl(a), query = [...url.searchParams].reduce((a2, [b3, c2]) => (a2[b3] = c2, a2), {}), host = o.hostname || o.host || multihost || url.hostname || env3.PGHOST || "localhost", port = o.port || url.port || env3.PGPORT || 5432, user = o.user || o.username || url.username || env3.PGUSERNAME || env3.PGUSER || osUsername();
|
|
24581
24494
|
o.no_prepare && (o.prepare = false);
|
|
24582
24495
|
query.sslmode && (query.ssl = query.sslmode, delete query.sslmode);
|
|
24583
24496
|
"timeout" in o && (console.log("The timeout option is deprecated, use idle_timeout instead"), o.idle_timeout = o.timeout);
|
|
@@ -24603,21 +24516,21 @@ function parseOptions(a, b2) {
|
|
|
24603
24516
|
host: Array.isArray(host) ? host : host.split(",").map((x) => x.split(":")[0]),
|
|
24604
24517
|
port: Array.isArray(port) ? port : host.split(",").map((x) => parseInt(x.split(":")[1] || port)),
|
|
24605
24518
|
path: o.path || host.indexOf("/") > -1 && host + "/.s.PGSQL." + port,
|
|
24606
|
-
database: o.database || o.db || (url.pathname || "").slice(1) ||
|
|
24519
|
+
database: o.database || o.db || (url.pathname || "").slice(1) || env3.PGDATABASE || user,
|
|
24607
24520
|
user,
|
|
24608
|
-
pass: o.pass || o.password || url.password ||
|
|
24521
|
+
pass: o.pass || o.password || url.password || env3.PGPASSWORD || "",
|
|
24609
24522
|
...Object.entries(defaults).reduce((acc, [k, d]) => {
|
|
24610
|
-
const value = k in o ? o[k] : (k in query) ? query[k] === "disable" || query[k] === "false" ? false : query[k] :
|
|
24523
|
+
const value = k in o ? o[k] : (k in query) ? query[k] === "disable" || query[k] === "false" ? false : query[k] : env3["PG" + k.toUpperCase()] || d;
|
|
24611
24524
|
acc[k] = typeof value === "string" && ints.includes(k) ? +value : value;
|
|
24612
24525
|
return acc;
|
|
24613
24526
|
}, {}),
|
|
24614
24527
|
connection: {
|
|
24615
|
-
application_name:
|
|
24528
|
+
application_name: env3.PGAPPNAME || "postgres.js",
|
|
24616
24529
|
...o.connection,
|
|
24617
24530
|
...Object.entries(query).reduce((acc, [k, v]) => ((k in defaults) || (acc[k] = v), acc), {})
|
|
24618
24531
|
},
|
|
24619
24532
|
types: o.types || {},
|
|
24620
|
-
target_session_attrs: tsa(o, url,
|
|
24533
|
+
target_session_attrs: tsa(o, url, env3),
|
|
24621
24534
|
onnotice: o.onnotice,
|
|
24622
24535
|
onnotify: o.onnotify,
|
|
24623
24536
|
onclose: o.onclose,
|
|
@@ -24629,8 +24542,8 @@ function parseOptions(a, b2) {
|
|
|
24629
24542
|
...mergeUserTypes(o.types)
|
|
24630
24543
|
};
|
|
24631
24544
|
}
|
|
24632
|
-
function tsa(o, url,
|
|
24633
|
-
const x = o.target_session_attrs || url.searchParams.get("target_session_attrs") ||
|
|
24545
|
+
function tsa(o, url, env3) {
|
|
24546
|
+
const x = o.target_session_attrs || url.searchParams.get("target_session_attrs") || env3.PGTARGETSESSIONATTRS;
|
|
24634
24547
|
if (!x || ["read-write", "read-only", "primary", "standby", "prefer-standby"].includes(x))
|
|
24635
24548
|
return x;
|
|
24636
24549
|
throw new Error("target_session_attrs " + x + " is not supported");
|
|
@@ -24680,7 +24593,7 @@ function parseUrl(url) {
|
|
|
24680
24593
|
}
|
|
24681
24594
|
function osUsername() {
|
|
24682
24595
|
try {
|
|
24683
|
-
return
|
|
24596
|
+
return os.userInfo().username;
|
|
24684
24597
|
} catch (_) {
|
|
24685
24598
|
return process.env.USERNAME || process.env.USER || process.env.LOGNAME;
|
|
24686
24599
|
}
|
|
@@ -24714,6 +24627,99 @@ var init_src = __esm(() => {
|
|
|
24714
24627
|
src_default = Postgres;
|
|
24715
24628
|
});
|
|
24716
24629
|
|
|
24630
|
+
// src/cli/util/bundled-docs.ts
|
|
24631
|
+
import { existsSync as existsSync7, readdirSync as readdirSync3, readFileSync as readFileSync5, statSync } from "node:fs";
|
|
24632
|
+
import { dirname as dirname3, join as join6, resolve as resolve2 } from "node:path";
|
|
24633
|
+
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
24634
|
+
function findPackageRoot() {
|
|
24635
|
+
let dir = dirname3(fileURLToPath2(import.meta.url));
|
|
24636
|
+
for (let i = 0;i < 10; i++) {
|
|
24637
|
+
const pkgJson = join6(dir, "package.json");
|
|
24638
|
+
if (existsSync7(pkgJson)) {
|
|
24639
|
+
try {
|
|
24640
|
+
const parsed = JSON.parse(readFileSync5(pkgJson, "utf8"));
|
|
24641
|
+
if (parsed.name === "@cerefox/memory")
|
|
24642
|
+
return dir;
|
|
24643
|
+
} catch {}
|
|
24644
|
+
}
|
|
24645
|
+
const parent = dirname3(dir);
|
|
24646
|
+
if (parent === dir)
|
|
24647
|
+
break;
|
|
24648
|
+
dir = parent;
|
|
24649
|
+
}
|
|
24650
|
+
return resolve2(dirname3(fileURLToPath2(import.meta.url)), "..", "..", "..");
|
|
24651
|
+
}
|
|
24652
|
+
function bundledDocsDir() {
|
|
24653
|
+
const inPackage = join6(PACKAGE_ROOT, "docs");
|
|
24654
|
+
if (existsSync7(inPackage))
|
|
24655
|
+
return inPackage;
|
|
24656
|
+
return resolve2(PACKAGE_ROOT, "..", "..", "docs");
|
|
24657
|
+
}
|
|
24658
|
+
function agentGuidePath() {
|
|
24659
|
+
const candidates = [
|
|
24660
|
+
join6(PACKAGE_ROOT, "AGENT_GUIDE.md"),
|
|
24661
|
+
resolve2(PACKAGE_ROOT, "..", "..", "AGENT_GUIDE.md")
|
|
24662
|
+
];
|
|
24663
|
+
for (const c2 of candidates)
|
|
24664
|
+
if (existsSync7(c2))
|
|
24665
|
+
return c2;
|
|
24666
|
+
return null;
|
|
24667
|
+
}
|
|
24668
|
+
function agentQuickReferencePath() {
|
|
24669
|
+
const candidates = [
|
|
24670
|
+
join6(PACKAGE_ROOT, "AGENT_QUICK_REFERENCE.md"),
|
|
24671
|
+
resolve2(PACKAGE_ROOT, "..", "..", "AGENT_QUICK_REFERENCE.md")
|
|
24672
|
+
];
|
|
24673
|
+
for (const c2 of candidates)
|
|
24674
|
+
if (existsSync7(c2))
|
|
24675
|
+
return c2;
|
|
24676
|
+
return null;
|
|
24677
|
+
}
|
|
24678
|
+
function listBundledDocs() {
|
|
24679
|
+
const entries = [];
|
|
24680
|
+
const docsDir = bundledDocsDir();
|
|
24681
|
+
const guidesDir = join6(docsDir, "guides");
|
|
24682
|
+
if (existsSync7(guidesDir) && statSync(guidesDir).isDirectory()) {
|
|
24683
|
+
for (const name of readdirSync3(guidesDir)) {
|
|
24684
|
+
if (!name.endsWith(".md"))
|
|
24685
|
+
continue;
|
|
24686
|
+
const full = join6(guidesDir, name);
|
|
24687
|
+
entries.push({
|
|
24688
|
+
topic: name.replace(/\.md$/, ""),
|
|
24689
|
+
path: full,
|
|
24690
|
+
size: statSync(full).size
|
|
24691
|
+
});
|
|
24692
|
+
}
|
|
24693
|
+
}
|
|
24694
|
+
const ag = agentGuidePath();
|
|
24695
|
+
if (ag)
|
|
24696
|
+
entries.push({ topic: "agent-guide", path: ag, size: statSync(ag).size });
|
|
24697
|
+
const aqr = agentQuickReferencePath();
|
|
24698
|
+
if (aqr) {
|
|
24699
|
+
entries.push({
|
|
24700
|
+
topic: "agent-quick-reference",
|
|
24701
|
+
path: aqr,
|
|
24702
|
+
size: statSync(aqr).size
|
|
24703
|
+
});
|
|
24704
|
+
}
|
|
24705
|
+
entries.sort((a, b2) => a.topic.localeCompare(b2.topic));
|
|
24706
|
+
return entries;
|
|
24707
|
+
}
|
|
24708
|
+
function readBundledDoc(topic) {
|
|
24709
|
+
const entry = listBundledDocs().find((d) => d.topic === topic);
|
|
24710
|
+
if (!entry)
|
|
24711
|
+
return null;
|
|
24712
|
+
return {
|
|
24713
|
+
topic: entry.topic,
|
|
24714
|
+
path: entry.path,
|
|
24715
|
+
content: readFileSync5(entry.path, "utf8")
|
|
24716
|
+
};
|
|
24717
|
+
}
|
|
24718
|
+
var PACKAGE_ROOT;
|
|
24719
|
+
var init_bundled_docs = __esm(() => {
|
|
24720
|
+
PACKAGE_ROOT = findPackageRoot();
|
|
24721
|
+
});
|
|
24722
|
+
|
|
24717
24723
|
// ../../_shared/embeddings/index.ts
|
|
24718
24724
|
async function getEmbedding(text, apiKey) {
|
|
24719
24725
|
let lastError = null;
|
|
@@ -26752,7 +26758,7 @@ __export(exports_sync_self_docs, {
|
|
|
26752
26758
|
runSyncSelfDocs: () => runSyncSelfDocs,
|
|
26753
26759
|
registerSyncSelfDocs: () => registerSyncSelfDocs
|
|
26754
26760
|
});
|
|
26755
|
-
import { readFileSync as
|
|
26761
|
+
import { readFileSync as readFileSync9 } from "node:fs";
|
|
26756
26762
|
import { basename as basename4, extname as extname4 } from "node:path";
|
|
26757
26763
|
async function runSyncSelfDocs(options = {}) {
|
|
26758
26764
|
const project = options.project ?? "_cerefox-self-docs";
|
|
@@ -26779,7 +26785,7 @@ async function runSyncSelfDocs(options = {}) {
|
|
|
26779
26785
|
const authorType = resolveAuthorType("agent");
|
|
26780
26786
|
const outcomes = [];
|
|
26781
26787
|
for (const doc of docs) {
|
|
26782
|
-
const content =
|
|
26788
|
+
const content = readFileSync9(doc.path, "utf8");
|
|
26783
26789
|
const m = content.match(/^#\s+(.+)$/m);
|
|
26784
26790
|
const title = m ? m[1].trim() : basename4(doc.path, extname4(doc.path));
|
|
26785
26791
|
try {
|
|
@@ -26813,11 +26819,11 @@ async function runSyncSelfDocs(options = {}) {
|
|
|
26813
26819
|
printTable(outcomes.filter((o) => o.status === "error").map((o) => ({ topic: o.topic, error: o.detail.slice(0, 100) })));
|
|
26814
26820
|
}
|
|
26815
26821
|
}
|
|
26816
|
-
async function
|
|
26822
|
+
async function action15(options) {
|
|
26817
26823
|
await runSyncSelfDocs(options);
|
|
26818
26824
|
}
|
|
26819
26825
|
function registerSyncSelfDocs(program2) {
|
|
26820
|
-
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(
|
|
26826
|
+
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(action15);
|
|
26821
26827
|
}
|
|
26822
26828
|
var init_sync_self_docs = __esm(() => {
|
|
26823
26829
|
init_cli_core();
|
|
@@ -41527,18 +41533,472 @@ function registerDeleteDoc(program2) {
|
|
|
41527
41533
|
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(action6);
|
|
41528
41534
|
}
|
|
41529
41535
|
|
|
41536
|
+
// src/cli/commands/delete-project.ts
|
|
41537
|
+
init_cli_core();
|
|
41538
|
+
init_client();
|
|
41539
|
+
var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
41540
|
+
async function action7(target, options) {
|
|
41541
|
+
const client = getClient();
|
|
41542
|
+
const isUuid = UUID_RE.test(target);
|
|
41543
|
+
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();
|
|
41544
|
+
const { data: project, error } = await lookup;
|
|
41545
|
+
if (error) {
|
|
41546
|
+
throw systemError(`Project lookup failed: ${error.message}`);
|
|
41547
|
+
}
|
|
41548
|
+
if (!project) {
|
|
41549
|
+
throw notFound(`Project "${target}" not found.`);
|
|
41550
|
+
}
|
|
41551
|
+
const { count, error: countErr } = await client.raw.from("cerefox_document_projects").select("*", { count: "exact", head: true }).eq("project_id", project.id);
|
|
41552
|
+
if (countErr) {
|
|
41553
|
+
throw systemError(`Could not count documents in project: ${countErr.message}`);
|
|
41554
|
+
}
|
|
41555
|
+
const docCount = count ?? 0;
|
|
41556
|
+
if (docCount > 0 && !options.force) {
|
|
41557
|
+
throw userError(`Project "${project.name}" still has ${docCount} document link(s).`, "Pass --force to delete the project anyway (documents remain; only the project row is removed).");
|
|
41558
|
+
}
|
|
41559
|
+
println(c.yellow("About to delete project:"));
|
|
41560
|
+
println(` ${project.name}`);
|
|
41561
|
+
println(c.dim(` ${project.id} · ${docCount} doc link(s)`));
|
|
41562
|
+
if (!options.yes) {
|
|
41563
|
+
const ok2 = await confirm("Continue?", true);
|
|
41564
|
+
if (!ok2) {
|
|
41565
|
+
println(c.dim("Aborted."));
|
|
41566
|
+
return;
|
|
41567
|
+
}
|
|
41568
|
+
}
|
|
41569
|
+
const { error: delErr } = await client.raw.from("cerefox_projects").delete().eq("id", project.id);
|
|
41570
|
+
if (delErr) {
|
|
41571
|
+
throw systemError(`Delete failed: ${delErr.message}`);
|
|
41572
|
+
}
|
|
41573
|
+
println(c.green(`✓ Deleted project "${project.name}" (id: ${project.id}).`));
|
|
41574
|
+
}
|
|
41575
|
+
function registerDeleteProject(program2) {
|
|
41576
|
+
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(action7);
|
|
41577
|
+
}
|
|
41578
|
+
|
|
41579
|
+
// src/cli/commands/deploy-server.ts
|
|
41580
|
+
init_cli_core();
|
|
41581
|
+
init_config();
|
|
41582
|
+
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
41583
|
+
import { existsSync as existsSync6 } from "node:fs";
|
|
41584
|
+
import { readdirSync as readdirSync2 } from "node:fs";
|
|
41585
|
+
|
|
41586
|
+
// ../../_shared/server-assets/index.ts
|
|
41587
|
+
import { existsSync as existsSync4 } from "node:fs";
|
|
41588
|
+
import { dirname as dirname2, join as join4 } from "node:path";
|
|
41589
|
+
import { fileURLToPath } from "node:url";
|
|
41590
|
+
import { cwd as processCwd2 } from "node:process";
|
|
41591
|
+
function moduleDir() {
|
|
41592
|
+
return dirname2(fileURLToPath(import.meta.url));
|
|
41593
|
+
}
|
|
41594
|
+
function bundledServerAssets(serverAssetsRoot) {
|
|
41595
|
+
return {
|
|
41596
|
+
schemaFile: join4(serverAssetsRoot, "db", "schema.sql"),
|
|
41597
|
+
rpcsFile: join4(serverAssetsRoot, "db", "rpcs.sql"),
|
|
41598
|
+
migrationsDir: join4(serverAssetsRoot, "db", "migrations"),
|
|
41599
|
+
functionsDir: join4(serverAssetsRoot, "supabase", "functions"),
|
|
41600
|
+
layout: "bundled"
|
|
41601
|
+
};
|
|
41602
|
+
}
|
|
41603
|
+
function sourceServerAssets(repoRoot) {
|
|
41604
|
+
const dbDir = join4(repoRoot, "src", "cerefox", "db");
|
|
41605
|
+
return {
|
|
41606
|
+
schemaFile: join4(dbDir, "schema.sql"),
|
|
41607
|
+
rpcsFile: join4(dbDir, "rpcs.sql"),
|
|
41608
|
+
migrationsDir: join4(dbDir, "migrations"),
|
|
41609
|
+
functionsDir: join4(repoRoot, "supabase", "functions"),
|
|
41610
|
+
layout: "source"
|
|
41611
|
+
};
|
|
41612
|
+
}
|
|
41613
|
+
function serverAssetsUsable(p) {
|
|
41614
|
+
return existsSync4(p.schemaFile) && existsSync4(p.rpcsFile);
|
|
41615
|
+
}
|
|
41616
|
+
function resolveServerAssets(opts = {}) {
|
|
41617
|
+
if (opts.assetsDir) {
|
|
41618
|
+
return { ...bundledServerAssets(opts.assetsDir), layout: "explicit" };
|
|
41619
|
+
}
|
|
41620
|
+
const here = opts.moduleDirOverride ?? moduleDir();
|
|
41621
|
+
const cwd = opts.cwd ?? processCwd2();
|
|
41622
|
+
const candidates = [
|
|
41623
|
+
bundledServerAssets(join4(here, "..", "server-assets")),
|
|
41624
|
+
sourceServerAssets(join4(here, "..", "..")),
|
|
41625
|
+
sourceServerAssets(cwd)
|
|
41626
|
+
];
|
|
41627
|
+
for (const candidate of candidates) {
|
|
41628
|
+
if (serverAssetsUsable(candidate))
|
|
41629
|
+
return candidate;
|
|
41630
|
+
}
|
|
41631
|
+
return sourceServerAssets(join4(here, "..", ".."));
|
|
41632
|
+
}
|
|
41633
|
+
|
|
41634
|
+
// ../../_shared/db-deploy/index.ts
|
|
41635
|
+
init_src();
|
|
41636
|
+
import { existsSync as existsSync5, readFileSync as readFileSync4, readdirSync } from "node:fs";
|
|
41637
|
+
import { join as join5 } from "node:path";
|
|
41638
|
+
var RESET_SQL = `
|
|
41639
|
+
DROP TABLE IF EXISTS cerefox_chunks CASCADE;
|
|
41640
|
+
DROP TABLE IF EXISTS cerefox_documents CASCADE;
|
|
41641
|
+
DROP TABLE IF EXISTS cerefox_projects CASCADE;
|
|
41642
|
+
DROP TABLE IF EXISTS cerefox_migrations CASCADE;
|
|
41643
|
+
DROP FUNCTION IF EXISTS cerefox_set_updated_at CASCADE;
|
|
41644
|
+
DROP FUNCTION IF EXISTS cerefox_hybrid_search CASCADE;
|
|
41645
|
+
DROP FUNCTION IF EXISTS cerefox_fts_search CASCADE;
|
|
41646
|
+
DROP FUNCTION IF EXISTS cerefox_semantic_search CASCADE;
|
|
41647
|
+
DROP FUNCTION IF EXISTS cerefox_reconstruct_doc CASCADE;
|
|
41648
|
+
`;
|
|
41649
|
+
var EXTENSIONS_SQL = `
|
|
41650
|
+
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
|
|
41651
|
+
CREATE EXTENSION IF NOT EXISTS "vector";
|
|
41652
|
+
`;
|
|
41653
|
+
function listMigrationFiles(migrationsDir) {
|
|
41654
|
+
if (!existsSync5(migrationsDir))
|
|
41655
|
+
return [];
|
|
41656
|
+
return readdirSync(migrationsDir).filter((n) => n.endsWith(".sql")).sort();
|
|
41657
|
+
}
|
|
41658
|
+
function buildDeploySteps(assets, opts = {}) {
|
|
41659
|
+
const schemaSql = readFileSync4(assets.schemaFile, "utf8");
|
|
41660
|
+
const rpcsSql = readFileSync4(assets.rpcsFile, "utf8");
|
|
41661
|
+
const steps = [];
|
|
41662
|
+
if (opts.reset) {
|
|
41663
|
+
steps.push({ label: "Reset: drop existing Cerefox objects", sql: RESET_SQL });
|
|
41664
|
+
}
|
|
41665
|
+
steps.push({ label: "Enable extensions (uuid-ossp, vector/pgvector)", sql: EXTENSIONS_SQL }, { label: "Apply schema (tables, indexes, triggers)", sql: schemaSql }, { label: "Apply RPCs (search functions)", sql: rpcsSql });
|
|
41666
|
+
const migrationFiles = listMigrationFiles(assets.migrationsDir);
|
|
41667
|
+
if (migrationFiles.length > 0) {
|
|
41668
|
+
const values2 = migrationFiles.map((n) => `('${n.replace(/'/g, "''")}')`).join(", ");
|
|
41669
|
+
steps.push({
|
|
41670
|
+
label: "Stamp migration files as already applied",
|
|
41671
|
+
sql: `INSERT INTO cerefox_migrations (filename) VALUES ${values2} ON CONFLICT (filename) DO NOTHING;`
|
|
41672
|
+
});
|
|
41673
|
+
}
|
|
41674
|
+
return steps;
|
|
41675
|
+
}
|
|
41676
|
+
async function runDbDeploy(opts) {
|
|
41677
|
+
const log = opts.log ?? (() => {});
|
|
41678
|
+
const steps = buildDeploySteps(opts.assets, { reset: opts.reset });
|
|
41679
|
+
if (opts.dryRun) {
|
|
41680
|
+
for (const step of steps) {
|
|
41681
|
+
log(`▶ ${step.label}… (dry-run, not executed)`);
|
|
41682
|
+
}
|
|
41683
|
+
return { ok: true, stepsRun: steps.length };
|
|
41684
|
+
}
|
|
41685
|
+
const sql = src_default(opts.dbUrl, { prepare: false, onnotice: () => {} });
|
|
41686
|
+
let stepsRun = 0;
|
|
41687
|
+
try {
|
|
41688
|
+
for (const step of steps) {
|
|
41689
|
+
log(`▶ ${step.label}…`);
|
|
41690
|
+
try {
|
|
41691
|
+
await sql.unsafe(step.sql);
|
|
41692
|
+
stepsRun++;
|
|
41693
|
+
} catch (err) {
|
|
41694
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
41695
|
+
return { ok: false, stepsRun, failedStep: step.label, error: message };
|
|
41696
|
+
}
|
|
41697
|
+
}
|
|
41698
|
+
return { ok: true, stepsRun };
|
|
41699
|
+
} finally {
|
|
41700
|
+
await sql.end({ timeout: 5 }).catch(() => {});
|
|
41701
|
+
}
|
|
41702
|
+
}
|
|
41703
|
+
var BOOTSTRAP_MIGRATIONS_SQL = `
|
|
41704
|
+
CREATE TABLE IF NOT EXISTS cerefox_migrations (
|
|
41705
|
+
id SERIAL PRIMARY KEY,
|
|
41706
|
+
filename TEXT NOT NULL UNIQUE,
|
|
41707
|
+
applied_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
41708
|
+
);
|
|
41709
|
+
`;
|
|
41710
|
+
async function detectExistingSchema(dbUrl) {
|
|
41711
|
+
const sql = src_default(dbUrl, { prepare: false, onnotice: () => {} });
|
|
41712
|
+
try {
|
|
41713
|
+
const rows = await sql`SELECT to_regclass('public.cerefox_documents') AS t`;
|
|
41714
|
+
return rows[0]?.t != null;
|
|
41715
|
+
} finally {
|
|
41716
|
+
await sql.end({ timeout: 5 }).catch(() => {});
|
|
41717
|
+
}
|
|
41718
|
+
}
|
|
41719
|
+
async function migrationStatus(opts) {
|
|
41720
|
+
const sql = src_default(opts.dbUrl, { prepare: false, onnotice: () => {} });
|
|
41721
|
+
try {
|
|
41722
|
+
await sql.unsafe(BOOTSTRAP_MIGRATIONS_SQL);
|
|
41723
|
+
const all = listMigrationFiles(opts.assets.migrationsDir);
|
|
41724
|
+
const appliedRows = await sql`SELECT filename FROM cerefox_migrations ORDER BY filename`;
|
|
41725
|
+
const appliedSet = new Set(appliedRows.map((r) => r.filename));
|
|
41726
|
+
return {
|
|
41727
|
+
all,
|
|
41728
|
+
applied: all.filter((f) => appliedSet.has(f)),
|
|
41729
|
+
pending: all.filter((f) => !appliedSet.has(f))
|
|
41730
|
+
};
|
|
41731
|
+
} finally {
|
|
41732
|
+
await sql.end({ timeout: 5 }).catch(() => {});
|
|
41733
|
+
}
|
|
41734
|
+
}
|
|
41735
|
+
async function runDbMigrate(opts) {
|
|
41736
|
+
const log = opts.log ?? (() => {});
|
|
41737
|
+
const sql = src_default(opts.dbUrl, { prepare: false, onnotice: () => {} });
|
|
41738
|
+
try {
|
|
41739
|
+
await sql.unsafe(BOOTSTRAP_MIGRATIONS_SQL);
|
|
41740
|
+
const allFiles = listMigrationFiles(opts.assets.migrationsDir);
|
|
41741
|
+
const appliedRows = await sql`SELECT filename FROM cerefox_migrations ORDER BY filename`;
|
|
41742
|
+
const appliedSet = new Set(appliedRows.map((r) => r.filename));
|
|
41743
|
+
const pending = allFiles.filter((f) => !appliedSet.has(f));
|
|
41744
|
+
if (pending.length === 0)
|
|
41745
|
+
return { ok: true, applied: [], pending: [] };
|
|
41746
|
+
if (opts.dryRun) {
|
|
41747
|
+
for (const f of pending)
|
|
41748
|
+
log(`Would apply ${f}`);
|
|
41749
|
+
return { ok: true, applied: [], pending };
|
|
41750
|
+
}
|
|
41751
|
+
const applied = [];
|
|
41752
|
+
for (const f of pending) {
|
|
41753
|
+
const body = readFileSync4(join5(opts.assets.migrationsDir, f), "utf8");
|
|
41754
|
+
log(`Applying ${f}…`);
|
|
41755
|
+
try {
|
|
41756
|
+
await sql.begin(async (tx) => {
|
|
41757
|
+
await tx.unsafe(body);
|
|
41758
|
+
await tx`INSERT INTO cerefox_migrations (filename) VALUES (${f}) ON CONFLICT DO NOTHING`;
|
|
41759
|
+
});
|
|
41760
|
+
applied.push(f);
|
|
41761
|
+
} catch (err) {
|
|
41762
|
+
return {
|
|
41763
|
+
ok: false,
|
|
41764
|
+
applied,
|
|
41765
|
+
pending,
|
|
41766
|
+
failedFile: f,
|
|
41767
|
+
error: err instanceof Error ? err.message : String(err)
|
|
41768
|
+
};
|
|
41769
|
+
}
|
|
41770
|
+
}
|
|
41771
|
+
return { ok: true, applied, pending };
|
|
41772
|
+
} finally {
|
|
41773
|
+
await sql.end({ timeout: 5 }).catch(() => {});
|
|
41774
|
+
}
|
|
41775
|
+
}
|
|
41776
|
+
async function applyRpcs(opts) {
|
|
41777
|
+
const log = opts.log ?? (() => {});
|
|
41778
|
+
log("Refresh RPCs (rpcs.sql)…");
|
|
41779
|
+
if (opts.dryRun)
|
|
41780
|
+
return { ok: true };
|
|
41781
|
+
const rpcsSql = readFileSync4(opts.assets.rpcsFile, "utf8");
|
|
41782
|
+
const sql = src_default(opts.dbUrl, { prepare: false, onnotice: () => {} });
|
|
41783
|
+
try {
|
|
41784
|
+
await sql.unsafe(rpcsSql);
|
|
41785
|
+
return { ok: true };
|
|
41786
|
+
} catch (err) {
|
|
41787
|
+
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
41788
|
+
} finally {
|
|
41789
|
+
await sql.end({ timeout: 5 }).catch(() => {});
|
|
41790
|
+
}
|
|
41791
|
+
}
|
|
41792
|
+
|
|
41793
|
+
// src/cli/commands/deploy-server.ts
|
|
41794
|
+
function commandSucceeds(cmd, args) {
|
|
41795
|
+
try {
|
|
41796
|
+
const r = spawnSync2(cmd, args, { encoding: "utf8", timeout: 15000 });
|
|
41797
|
+
return r.status === 0;
|
|
41798
|
+
} catch {
|
|
41799
|
+
return false;
|
|
41800
|
+
}
|
|
41801
|
+
}
|
|
41802
|
+
function listEdgeFunctions(functionsDir) {
|
|
41803
|
+
if (!existsSync6(functionsDir))
|
|
41804
|
+
return [];
|
|
41805
|
+
return readdirSync2(functionsDir, { withFileTypes: true }).filter((e) => e.isDirectory() && e.name.startsWith("cerefox-")).map((e) => e.name).sort();
|
|
41806
|
+
}
|
|
41807
|
+
async function action8(options) {
|
|
41808
|
+
const settings = loadSettings();
|
|
41809
|
+
const assets = resolveServerAssets();
|
|
41810
|
+
const doSchema = !options.functionsOnly;
|
|
41811
|
+
const doFunctions = !options.schemaOnly;
|
|
41812
|
+
const checks = [];
|
|
41813
|
+
if (doSchema) {
|
|
41814
|
+
checks.push({
|
|
41815
|
+
label: "CEREFOX_DATABASE_URL is set (Session Pooler, port 5432)",
|
|
41816
|
+
ok: Boolean(settings.databaseUrl),
|
|
41817
|
+
remediation: "Set CEREFOX_DATABASE_URL in your .env. Use the Session Pooler URI " + "(port 5432, username postgres.<project-ref>, ?sslmode=require). " + "See docs/guides/setup-supabase.md → Connection pooling."
|
|
41818
|
+
});
|
|
41819
|
+
checks.push({
|
|
41820
|
+
label: "Bundled schema assets present",
|
|
41821
|
+
ok: existsSync6(assets.schemaFile) && existsSync6(assets.rpcsFile),
|
|
41822
|
+
remediation: "Schema files not found. Reinstall the package, or run from a repo " + "clone (src/cerefox/db/)."
|
|
41823
|
+
});
|
|
41824
|
+
}
|
|
41825
|
+
let efNames = [];
|
|
41826
|
+
if (doFunctions) {
|
|
41827
|
+
efNames = listEdgeFunctions(assets.functionsDir);
|
|
41828
|
+
checks.push({
|
|
41829
|
+
label: "Bundled Edge Function sources present",
|
|
41830
|
+
ok: efNames.length > 0,
|
|
41831
|
+
remediation: "Edge Function sources not found under the bundled assets. Reinstall " + "the package, or run from a repo clone (supabase/functions/)."
|
|
41832
|
+
});
|
|
41833
|
+
checks.push({
|
|
41834
|
+
label: "Supabase CLI reachable (`npx supabase --version`)",
|
|
41835
|
+
ok: commandSucceeds("npx", ["--yes", "supabase", "--version"]),
|
|
41836
|
+
remediation: "Install Node 20+ (npx ships with it) from nodejs.org, then re-run. " + "`cerefox deploy-server` shells out to the Supabase CLI via npx."
|
|
41837
|
+
});
|
|
41838
|
+
checks.push({
|
|
41839
|
+
label: "Supabase project linked (`npx supabase link`)",
|
|
41840
|
+
ok: existsSync6("supabase/config.toml") || existsSync6(".supabase/config.toml"),
|
|
41841
|
+
remediation: `Authenticate + link your project (one-time, from any working dir):
|
|
41842
|
+
` + ` npx supabase login
|
|
41843
|
+
` + ` npx supabase link --project-ref <your-project-ref>
|
|
41844
|
+
` + " Your project ref is in the dashboard URL: " + "https://supabase.com/dashboard/project/<project-ref>"
|
|
41845
|
+
});
|
|
41846
|
+
}
|
|
41847
|
+
const failed = checks.filter((ch) => !ch.ok);
|
|
41848
|
+
println(c.bold("Cerefox deploy-server — pre-flight"));
|
|
41849
|
+
for (const ch of checks) {
|
|
41850
|
+
println(` ${ch.ok ? c.green("✓") : c.red("✗")} ${ch.label}`);
|
|
41851
|
+
}
|
|
41852
|
+
if (failed.length > 0) {
|
|
41853
|
+
eprintln("");
|
|
41854
|
+
eprintln(c.red(`Cannot deploy yet — ${failed.length} prerequisite(s) missing:`));
|
|
41855
|
+
for (const ch of failed) {
|
|
41856
|
+
eprintln(`
|
|
41857
|
+
${c.red("✗")} ${ch.label}`);
|
|
41858
|
+
eprintln(c.dim(` → ${ch.remediation}`));
|
|
41859
|
+
}
|
|
41860
|
+
eprintln("\nFix the above and re-run `cerefox deploy-server` (it's idempotent).");
|
|
41861
|
+
process.exit(1);
|
|
41862
|
+
}
|
|
41863
|
+
println(c.green(`
|
|
41864
|
+
✓ All prerequisites satisfied.`));
|
|
41865
|
+
let schemaMode = "unknown";
|
|
41866
|
+
let pending = [];
|
|
41867
|
+
if (doSchema) {
|
|
41868
|
+
try {
|
|
41869
|
+
const exists = await detectExistingSchema(settings.databaseUrl);
|
|
41870
|
+
schemaMode = exists ? "existing" : "fresh";
|
|
41871
|
+
if (exists) {
|
|
41872
|
+
pending = (await migrationStatus({ dbUrl: settings.databaseUrl, assets })).pending;
|
|
41873
|
+
}
|
|
41874
|
+
} catch (err) {
|
|
41875
|
+
if (!options.dryRun) {
|
|
41876
|
+
eprintln(c.red(`
|
|
41877
|
+
✗ Could not connect to the database: ${err instanceof Error ? err.message : String(err)}`));
|
|
41878
|
+
eprintln(c.dim(" Verify CEREFOX_DATABASE_URL (Session Pooler, port 5432)."));
|
|
41879
|
+
process.exit(1);
|
|
41880
|
+
}
|
|
41881
|
+
}
|
|
41882
|
+
}
|
|
41883
|
+
const planLines = [];
|
|
41884
|
+
if (doSchema) {
|
|
41885
|
+
if (schemaMode === "fresh") {
|
|
41886
|
+
planLines.push(` • Deploy fresh schema + RPCs to ${settings.supabaseUrl || "your Supabase database"}`);
|
|
41887
|
+
} else if (schemaMode === "existing") {
|
|
41888
|
+
planLines.push(` • Update existing schema: apply ${pending.length} pending migration(s) + refresh RPCs`);
|
|
41889
|
+
for (const f of pending)
|
|
41890
|
+
planLines.push(c.dim(` – ${f}`));
|
|
41891
|
+
} else {
|
|
41892
|
+
planLines.push(` • Schema + RPCs (fresh or update — couldn't probe the DB)`);
|
|
41893
|
+
}
|
|
41894
|
+
}
|
|
41895
|
+
if (doFunctions) {
|
|
41896
|
+
planLines.push(` • Deploy ${efNames.length} Edge Function(s): ${efNames.join(", ")}`);
|
|
41897
|
+
}
|
|
41898
|
+
println(c.bold(`
|
|
41899
|
+
Plan:`));
|
|
41900
|
+
for (const line of planLines)
|
|
41901
|
+
println(line);
|
|
41902
|
+
if (options.dryRun) {
|
|
41903
|
+
println(c.yellow(`
|
|
41904
|
+
⚠ --dry-run: nothing was deployed.`));
|
|
41905
|
+
process.exit(0);
|
|
41906
|
+
}
|
|
41907
|
+
const proceed = await confirm(`
|
|
41908
|
+
Proceed with deployment to Supabase?`, true);
|
|
41909
|
+
if (!proceed) {
|
|
41910
|
+
println(c.dim("Aborted."));
|
|
41911
|
+
process.exit(0);
|
|
41912
|
+
}
|
|
41913
|
+
if (doSchema) {
|
|
41914
|
+
if (schemaMode === "fresh") {
|
|
41915
|
+
println(c.bold(`
|
|
41916
|
+
▶ Deploying fresh schema + RPCs…`));
|
|
41917
|
+
const result = await runDbDeploy({
|
|
41918
|
+
dbUrl: settings.databaseUrl,
|
|
41919
|
+
assets,
|
|
41920
|
+
log: (line) => println(c.dim(` ${line}`))
|
|
41921
|
+
});
|
|
41922
|
+
if (!result.ok) {
|
|
41923
|
+
eprintln(c.red(`
|
|
41924
|
+
✗ Schema deploy failed at "${result.failedStep}": ${result.error}`));
|
|
41925
|
+
process.exit(1);
|
|
41926
|
+
}
|
|
41927
|
+
println(c.green(` ✓ Fresh schema deployed (${result.stepsRun} steps).`));
|
|
41928
|
+
} else {
|
|
41929
|
+
println(c.bold(`
|
|
41930
|
+
▶ Updating existing schema (migrations + RPC refresh)…`));
|
|
41931
|
+
const mig = await runDbMigrate({
|
|
41932
|
+
dbUrl: settings.databaseUrl,
|
|
41933
|
+
assets,
|
|
41934
|
+
log: (line) => println(c.dim(` ${line}`))
|
|
41935
|
+
});
|
|
41936
|
+
if (!mig.ok) {
|
|
41937
|
+
eprintln(c.red(`
|
|
41938
|
+
✗ Migration "${mig.failedFile}" failed: ${mig.error}`));
|
|
41939
|
+
eprintln(c.dim(" Earlier migrations in this run were committed. Fix + re-run."));
|
|
41940
|
+
process.exit(1);
|
|
41941
|
+
}
|
|
41942
|
+
const rpcs = await applyRpcs({
|
|
41943
|
+
dbUrl: settings.databaseUrl,
|
|
41944
|
+
assets,
|
|
41945
|
+
log: (line) => println(c.dim(` ${line}`))
|
|
41946
|
+
});
|
|
41947
|
+
if (!rpcs.ok) {
|
|
41948
|
+
eprintln(c.red(`
|
|
41949
|
+
✗ RPC refresh failed: ${rpcs.error}`));
|
|
41950
|
+
process.exit(1);
|
|
41951
|
+
}
|
|
41952
|
+
println(c.green(` ✓ Applied ${mig.applied.length} migration(s); RPCs refreshed.`));
|
|
41953
|
+
}
|
|
41954
|
+
}
|
|
41955
|
+
if (doFunctions) {
|
|
41956
|
+
println(c.bold(`
|
|
41957
|
+
▶ Deploying ${efNames.length} Edge Function(s)…`));
|
|
41958
|
+
let efOk = 0;
|
|
41959
|
+
const efFailed = [];
|
|
41960
|
+
for (const ef of efNames) {
|
|
41961
|
+
info(` deploying ${ef}…`);
|
|
41962
|
+
const workdir = assets.functionsDir.replace(/\/functions$/, "").replace(/\/supabase$/, "");
|
|
41963
|
+
const r = spawnSync2("npx", ["--yes", "supabase", "functions", "deploy", ef], {
|
|
41964
|
+
encoding: "utf8",
|
|
41965
|
+
stdio: "inherit",
|
|
41966
|
+
cwd: workdir,
|
|
41967
|
+
timeout: 120000
|
|
41968
|
+
});
|
|
41969
|
+
if (r.status === 0)
|
|
41970
|
+
efOk++;
|
|
41971
|
+
else
|
|
41972
|
+
efFailed.push(ef);
|
|
41973
|
+
}
|
|
41974
|
+
if (efFailed.length > 0) {
|
|
41975
|
+
eprintln(c.red(`
|
|
41976
|
+
✗ ${efFailed.length} Edge Function(s) failed: ${efFailed.join(", ")}`));
|
|
41977
|
+
eprintln(c.dim(" Re-run `cerefox deploy-server --functions-only` after fixing the cause."));
|
|
41978
|
+
process.exit(1);
|
|
41979
|
+
}
|
|
41980
|
+
println(c.green(` ✓ Deployed ${efOk} Edge Function(s).`));
|
|
41981
|
+
}
|
|
41982
|
+
println(c.green(`
|
|
41983
|
+
✓ Server deploy complete.`));
|
|
41984
|
+
println(c.dim("Verify with: cerefox doctor"));
|
|
41985
|
+
}
|
|
41986
|
+
function registerDeployServer(program2) {
|
|
41987
|
+
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).").action(action8);
|
|
41988
|
+
}
|
|
41989
|
+
|
|
41530
41990
|
// src/cli/commands/docs.ts
|
|
41531
41991
|
init_cli_core();
|
|
41532
41992
|
init_bundled_docs();
|
|
41533
|
-
import { spawnSync as
|
|
41993
|
+
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
41534
41994
|
function openInBrowser(path) {
|
|
41535
41995
|
const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
|
|
41536
|
-
const result =
|
|
41996
|
+
const result = spawnSync3(cmd, [path], { stdio: "ignore" });
|
|
41537
41997
|
if (result.status !== 0) {
|
|
41538
41998
|
println(c.dim(`(could not auto-open; the file is at: ${path})`));
|
|
41539
41999
|
}
|
|
41540
42000
|
}
|
|
41541
|
-
function
|
|
42001
|
+
function action9(topic, options) {
|
|
41542
42002
|
const docs = listBundledDocs();
|
|
41543
42003
|
if (options.list || !topic && !options.print) {
|
|
41544
42004
|
if (docs.length === 0) {
|
|
@@ -41567,7 +42027,7 @@ function action7(topic, options) {
|
|
|
41567
42027
|
openInBrowser(doc.path);
|
|
41568
42028
|
}
|
|
41569
42029
|
function registerDocs(program2) {
|
|
41570
|
-
program2.command("docs").description("Open bundled Cerefox docs in your browser (or print to stdout).").argument("[topic]", "Doc topic (e.g. quickstart, connect-agents). Omit for the index.").option("--print", "Print to stdout instead of opening a browser.").option("--list", "List available topics.").action(
|
|
42030
|
+
program2.command("docs").description("Open bundled Cerefox docs in your browser (or print to stdout).").argument("[topic]", "Doc topic (e.g. quickstart, connect-agents). Omit for the index.").option("--print", "Print to stdout instead of opening a browser.").option("--list", "List available topics.").action(action9);
|
|
41571
42031
|
}
|
|
41572
42032
|
|
|
41573
42033
|
// ../../node_modules/.bun/ora@9.4.0/node_modules/ora/index.js
|
|
@@ -41753,7 +42213,7 @@ var ansi_styles_default = ansiStyles;
|
|
|
41753
42213
|
|
|
41754
42214
|
// ../../node_modules/.bun/chalk@5.6.2/node_modules/chalk/source/vendor/supports-color/index.js
|
|
41755
42215
|
import process2 from "node:process";
|
|
41756
|
-
import
|
|
42216
|
+
import os2 from "node:os";
|
|
41757
42217
|
import tty from "node:tty";
|
|
41758
42218
|
function hasFlag(flag, argv = globalThis.Deno ? globalThis.Deno.args : process2.argv) {
|
|
41759
42219
|
const prefix = flag.startsWith("-") ? "" : flag.length === 1 ? "-" : "--";
|
|
@@ -41818,7 +42278,7 @@ function _supportsColor(haveStream, { streamIsTTY, sniffFlags = true } = {}) {
|
|
|
41818
42278
|
return min;
|
|
41819
42279
|
}
|
|
41820
42280
|
if (process2.platform === "win32") {
|
|
41821
|
-
const osRelease =
|
|
42281
|
+
const osRelease = os2.release().split(".");
|
|
41822
42282
|
if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
|
|
41823
42283
|
return Number(osRelease[2]) >= 14931 ? 3 : 2;
|
|
41824
42284
|
}
|
|
@@ -44132,7 +44592,7 @@ var format = (open, close) => {
|
|
|
44132
44592
|
return result;
|
|
44133
44593
|
};
|
|
44134
44594
|
};
|
|
44135
|
-
var
|
|
44595
|
+
var reset2 = format(0, 0);
|
|
44136
44596
|
var bold = format(1, 22);
|
|
44137
44597
|
var dim = format(2, 22);
|
|
44138
44598
|
var italic = format(3, 23);
|
|
@@ -44959,9 +45419,105 @@ init_cli_core();
|
|
|
44959
45419
|
init_meta();
|
|
44960
45420
|
init_config();
|
|
44961
45421
|
init_config();
|
|
44962
|
-
import { existsSync as
|
|
45422
|
+
import { existsSync as existsSync8, readFileSync as readFileSync6, realpathSync, statSync as statSync2 } from "node:fs";
|
|
44963
45423
|
import { homedir as homedir4 } from "node:os";
|
|
44964
|
-
import { join as
|
|
45424
|
+
import { join as join7 } from "node:path";
|
|
45425
|
+
|
|
45426
|
+
// ../../_shared/compatibility/index.ts
|
|
45427
|
+
var COMPATIBILITY = {
|
|
45428
|
+
minSchema: "0.3.1",
|
|
45429
|
+
minEdgeFunctions: "0.6.0"
|
|
45430
|
+
};
|
|
45431
|
+
function compareSemver(a, b2) {
|
|
45432
|
+
const norm = (v) => v.split(/[.-]/).slice(0, 3).map((p) => Number.parseInt(p, 10)).map((n) => Number.isFinite(n) ? n : 0);
|
|
45433
|
+
const pa = norm(a);
|
|
45434
|
+
const pb = norm(b2);
|
|
45435
|
+
for (let i = 0;i < 3; i++) {
|
|
45436
|
+
const x = pa[i] ?? 0;
|
|
45437
|
+
const y = pb[i] ?? 0;
|
|
45438
|
+
if (x !== y)
|
|
45439
|
+
return x < y ? -1 : 1;
|
|
45440
|
+
}
|
|
45441
|
+
return 0;
|
|
45442
|
+
}
|
|
45443
|
+
function classifyCompat(deployed, min, bundled) {
|
|
45444
|
+
if (!deployed)
|
|
45445
|
+
return "unknown";
|
|
45446
|
+
if (compareSemver(deployed, min) < 0)
|
|
45447
|
+
return "below-min";
|
|
45448
|
+
if (bundled && compareSemver(deployed, bundled) < 0)
|
|
45449
|
+
return "above-min-but-old";
|
|
45450
|
+
return "ok";
|
|
45451
|
+
}
|
|
45452
|
+
function aggregatorUrlFor(supabaseUrl) {
|
|
45453
|
+
const base = supabaseUrl.replace(/\/$/, "");
|
|
45454
|
+
return `${base}/functions/v1/cerefox-mcp/version?peers=true`;
|
|
45455
|
+
}
|
|
45456
|
+
async function checkServerCompatibility(opts) {
|
|
45457
|
+
const fetchImpl = opts.fetchImpl ?? fetch;
|
|
45458
|
+
const result = {
|
|
45459
|
+
schema: { deployed: null, min: COMPATIBILITY.minSchema, level: "unknown" },
|
|
45460
|
+
edgeFunctions: {
|
|
45461
|
+
deployed: null,
|
|
45462
|
+
min: COMPATIBILITY.minEdgeFunctions,
|
|
45463
|
+
level: "unknown",
|
|
45464
|
+
errors: []
|
|
45465
|
+
},
|
|
45466
|
+
blocking: false,
|
|
45467
|
+
efProbeSkipped: false
|
|
45468
|
+
};
|
|
45469
|
+
if (!opts.bearer) {
|
|
45470
|
+
result.efProbeSkipped = true;
|
|
45471
|
+
result.efSkipReason = "No anon JWT (CEREFOX_SUPABASE_ANON_KEY) configured; Edge Function version check skipped.";
|
|
45472
|
+
return result;
|
|
45473
|
+
}
|
|
45474
|
+
let agg = null;
|
|
45475
|
+
try {
|
|
45476
|
+
const ctrl = new AbortController;
|
|
45477
|
+
const timer2 = setTimeout(() => ctrl.abort(), opts.timeoutMs ?? 6000);
|
|
45478
|
+
try {
|
|
45479
|
+
const resp = await fetchImpl(opts.aggregatorUrl, {
|
|
45480
|
+
method: "GET",
|
|
45481
|
+
headers: { Authorization: `Bearer ${opts.bearer}`, apikey: opts.bearer },
|
|
45482
|
+
signal: ctrl.signal
|
|
45483
|
+
});
|
|
45484
|
+
if (resp.ok) {
|
|
45485
|
+
agg = await resp.json();
|
|
45486
|
+
} else {
|
|
45487
|
+
result.efProbeSkipped = true;
|
|
45488
|
+
result.efSkipReason = resp.status === 404 || resp.status === 405 ? "Edge Functions predate v0.8 (no /version route). Redeploy with `cerefox deploy-server --functions-only` to enable version checks." : `Aggregator returned HTTP ${resp.status}; Edge Function version check skipped.`;
|
|
45489
|
+
}
|
|
45490
|
+
} finally {
|
|
45491
|
+
clearTimeout(timer2);
|
|
45492
|
+
}
|
|
45493
|
+
} catch (err) {
|
|
45494
|
+
result.efProbeSkipped = true;
|
|
45495
|
+
result.efSkipReason = `Could not reach the version aggregator: ${err instanceof Error ? err.message : String(err)}`;
|
|
45496
|
+
}
|
|
45497
|
+
if (!agg)
|
|
45498
|
+
return result;
|
|
45499
|
+
result.schema.deployed = agg.schema ?? null;
|
|
45500
|
+
result.schema.level = classifyCompat(result.schema.deployed, COMPATIBILITY.minSchema, opts.bundledSchema);
|
|
45501
|
+
const versions = [];
|
|
45502
|
+
if (agg.version)
|
|
45503
|
+
versions.push(agg.version);
|
|
45504
|
+
for (const ef of agg.efs ?? [])
|
|
45505
|
+
versions.push(ef.version);
|
|
45506
|
+
result.edgeFunctions.errors = agg.errors ?? [];
|
|
45507
|
+
if (versions.length > 0) {
|
|
45508
|
+
const weakest = versions.reduce((lo, v) => compareSemver(v, lo) < 0 ? v : lo);
|
|
45509
|
+
result.edgeFunctions.deployed = weakest;
|
|
45510
|
+
result.edgeFunctions.level = classifyCompat(weakest, COMPATIBILITY.minEdgeFunctions, opts.bundledEf);
|
|
45511
|
+
} else {
|
|
45512
|
+
result.edgeFunctions.level = "unknown";
|
|
45513
|
+
result.efProbeSkipped = true;
|
|
45514
|
+
result.efSkipReason = "Aggregator reported no Edge Function versions; check skipped.";
|
|
45515
|
+
}
|
|
45516
|
+
result.blocking = result.schema.level === "below-min" || result.edgeFunctions.level === "below-min";
|
|
45517
|
+
return result;
|
|
45518
|
+
}
|
|
45519
|
+
|
|
45520
|
+
// src/cli/util/checks.ts
|
|
44965
45521
|
function checkBinary() {
|
|
44966
45522
|
return {
|
|
44967
45523
|
name: "binary",
|
|
@@ -45012,7 +45568,7 @@ function checkConfig() {
|
|
|
45012
45568
|
hint: "Run `cerefox init` to bootstrap."
|
|
45013
45569
|
};
|
|
45014
45570
|
}
|
|
45015
|
-
if (!
|
|
45571
|
+
if (!existsSync8(envPath)) {
|
|
45016
45572
|
return {
|
|
45017
45573
|
name: "config",
|
|
45018
45574
|
status: "error",
|
|
@@ -45136,11 +45692,24 @@ async function checkOpenAI() {
|
|
|
45136
45692
|
};
|
|
45137
45693
|
}
|
|
45138
45694
|
}
|
|
45695
|
+
var SCHEMA_VERSION_RE = /^--\s*@version:\s*(\S+)/m;
|
|
45696
|
+
function readBundledSchemaVersion() {
|
|
45697
|
+
try {
|
|
45698
|
+
const assets = resolveServerAssets();
|
|
45699
|
+
if (!existsSync8(assets.schemaFile))
|
|
45700
|
+
return null;
|
|
45701
|
+
const m = readFileSync6(assets.schemaFile, "utf8").match(SCHEMA_VERSION_RE);
|
|
45702
|
+
return m ? m[1] : null;
|
|
45703
|
+
} catch {
|
|
45704
|
+
return null;
|
|
45705
|
+
}
|
|
45706
|
+
}
|
|
45707
|
+
var SCHEMA_CHECK_NAME = "schema + RPCs";
|
|
45139
45708
|
async function checkSchemaVersion() {
|
|
45140
45709
|
const settings = loadSettings();
|
|
45141
45710
|
if (!settings.supabaseUrl || !settings.supabaseKey) {
|
|
45142
45711
|
return {
|
|
45143
|
-
name:
|
|
45712
|
+
name: SCHEMA_CHECK_NAME,
|
|
45144
45713
|
status: "skipped",
|
|
45145
45714
|
detail: "Supabase config missing; skipped."
|
|
45146
45715
|
};
|
|
@@ -45158,31 +45727,50 @@ async function checkSchemaVersion() {
|
|
|
45158
45727
|
});
|
|
45159
45728
|
if (!resp.ok) {
|
|
45160
45729
|
return {
|
|
45161
|
-
name:
|
|
45730
|
+
name: SCHEMA_CHECK_NAME,
|
|
45162
45731
|
status: "error",
|
|
45163
|
-
detail: `cerefox_schema_version returned ${resp.status}
|
|
45164
|
-
hint: "Deploy the schema
|
|
45732
|
+
detail: `cerefox_schema_version returned ${resp.status} — schema not deployed.`,
|
|
45733
|
+
hint: "Deploy the schema + RPCs (see remediation below)."
|
|
45165
45734
|
};
|
|
45166
45735
|
}
|
|
45167
45736
|
const deployed = await resp.json();
|
|
45168
|
-
|
|
45169
|
-
|
|
45170
|
-
|
|
45171
|
-
|
|
45172
|
-
|
|
45737
|
+
const bundled = readBundledSchemaVersion();
|
|
45738
|
+
const level = classifyCompat(deployed, COMPATIBILITY.minSchema, bundled);
|
|
45739
|
+
switch (level) {
|
|
45740
|
+
case "below-min":
|
|
45741
|
+
return {
|
|
45742
|
+
name: SCHEMA_CHECK_NAME,
|
|
45743
|
+
status: "error",
|
|
45744
|
+
detail: `Deployed schema v${deployed} is below the required minimum v${COMPATIBILITY.minSchema}.`,
|
|
45745
|
+
hint: "Update the schema + RPCs (see remediation below)."
|
|
45746
|
+
};
|
|
45747
|
+
case "above-min-but-old":
|
|
45748
|
+
return {
|
|
45749
|
+
name: SCHEMA_CHECK_NAME,
|
|
45750
|
+
status: "warn",
|
|
45751
|
+
detail: `Deployed schema v${deployed} works but is older than this client's bundled v${bundled}.`,
|
|
45752
|
+
hint: "Update the schema + RPCs (see remediation below)."
|
|
45753
|
+
};
|
|
45754
|
+
default:
|
|
45755
|
+
return {
|
|
45756
|
+
name: SCHEMA_CHECK_NAME,
|
|
45757
|
+
status: "ok",
|
|
45758
|
+
detail: `cerefox_schema_version() → "${deployed}"${bundled ? ` (bundled v${bundled})` : ""}`
|
|
45759
|
+
};
|
|
45760
|
+
}
|
|
45173
45761
|
} catch (err) {
|
|
45174
45762
|
return {
|
|
45175
|
-
name:
|
|
45763
|
+
name: SCHEMA_CHECK_NAME,
|
|
45176
45764
|
status: "error",
|
|
45177
45765
|
detail: `Schema version probe failed: ${err instanceof Error ? err.message : String(err)}`
|
|
45178
45766
|
};
|
|
45179
45767
|
}
|
|
45180
45768
|
}
|
|
45181
45769
|
function hasCerefoxInJsonFile(path) {
|
|
45182
|
-
if (!
|
|
45770
|
+
if (!existsSync8(path))
|
|
45183
45771
|
return false;
|
|
45184
45772
|
try {
|
|
45185
|
-
const parsed = JSON.parse(
|
|
45773
|
+
const parsed = JSON.parse(readFileSync6(path, "utf8"));
|
|
45186
45774
|
const mcpServers = parsed.mcpServers;
|
|
45187
45775
|
return Boolean(mcpServers && typeof mcpServers === "object" && "cerefox" in mcpServers);
|
|
45188
45776
|
} catch {
|
|
@@ -45191,9 +45779,9 @@ function hasCerefoxInJsonFile(path) {
|
|
|
45191
45779
|
}
|
|
45192
45780
|
function checkMcpConfigs() {
|
|
45193
45781
|
const home = homedir4();
|
|
45194
|
-
const claudeCodeUser =
|
|
45195
|
-
const claudeCodeProj =
|
|
45196
|
-
const claudeDesktop = process.platform === "darwin" ?
|
|
45782
|
+
const claudeCodeUser = join7(home, ".claude.json");
|
|
45783
|
+
const claudeCodeProj = join7(process.cwd(), ".mcp.json");
|
|
45784
|
+
const claudeDesktop = process.platform === "darwin" ? join7(home, "Library", "Application Support", "Claude", "claude_desktop_config.json") : process.platform === "win32" ? join7(process.env.APPDATA ?? "", "Claude", "claude_desktop_config.json") : join7(home, ".config", "Claude", "claude_desktop_config.json");
|
|
45197
45785
|
const found = [];
|
|
45198
45786
|
if (hasCerefoxInJsonFile(claudeCodeUser))
|
|
45199
45787
|
found.push("Claude Code (user)");
|
|
@@ -45217,9 +45805,9 @@ function checkMcpConfigs() {
|
|
|
45217
45805
|
}
|
|
45218
45806
|
function checkLegacyShadowEnv() {
|
|
45219
45807
|
const home = homedir4();
|
|
45220
|
-
const homeEnv =
|
|
45221
|
-
const cwdEnv =
|
|
45222
|
-
if (!
|
|
45808
|
+
const homeEnv = join7(home, USER_STATE_DIR_NAME, ".env");
|
|
45809
|
+
const cwdEnv = join7(process.cwd(), ".env");
|
|
45810
|
+
if (!existsSync8(homeEnv) || !existsSync8(cwdEnv))
|
|
45223
45811
|
return null;
|
|
45224
45812
|
try {
|
|
45225
45813
|
if (realpathSync(homeEnv) === realpathSync(cwdEnv))
|
|
@@ -45278,6 +45866,68 @@ async function checkPostgres() {
|
|
|
45278
45866
|
await sql.end({ timeout: 1 }).catch(() => {});
|
|
45279
45867
|
}
|
|
45280
45868
|
}
|
|
45869
|
+
async function checkEdgeFunctionsCompat() {
|
|
45870
|
+
const settings = loadSettings();
|
|
45871
|
+
if (!settings.supabaseUrl) {
|
|
45872
|
+
return {
|
|
45873
|
+
name: "edge functions",
|
|
45874
|
+
status: "skipped",
|
|
45875
|
+
detail: "Supabase URL not set; EF version check skipped."
|
|
45876
|
+
};
|
|
45877
|
+
}
|
|
45878
|
+
if (!settings.supabaseAnonKey) {
|
|
45879
|
+
return {
|
|
45880
|
+
name: "edge functions",
|
|
45881
|
+
status: "skipped",
|
|
45882
|
+
detail: "No CEREFOX_SUPABASE_ANON_KEY set; EF version check skipped.",
|
|
45883
|
+
hint: "Set the legacy anon JWT (eyJ…) to enable client↔server version checks."
|
|
45884
|
+
};
|
|
45885
|
+
}
|
|
45886
|
+
let compat;
|
|
45887
|
+
try {
|
|
45888
|
+
compat = await checkServerCompatibility({
|
|
45889
|
+
aggregatorUrl: aggregatorUrlFor(settings.supabaseUrl),
|
|
45890
|
+
bearer: settings.supabaseAnonKey,
|
|
45891
|
+
bundledEf: PKG_VERSION
|
|
45892
|
+
});
|
|
45893
|
+
} catch (err) {
|
|
45894
|
+
return {
|
|
45895
|
+
name: "edge functions",
|
|
45896
|
+
status: "skipped",
|
|
45897
|
+
detail: `Version probe failed: ${err instanceof Error ? err.message : String(err)}`
|
|
45898
|
+
};
|
|
45899
|
+
}
|
|
45900
|
+
if (compat.efProbeSkipped) {
|
|
45901
|
+
return {
|
|
45902
|
+
name: "edge functions",
|
|
45903
|
+
status: "skipped",
|
|
45904
|
+
detail: compat.efSkipReason ?? "EF version check skipped."
|
|
45905
|
+
};
|
|
45906
|
+
}
|
|
45907
|
+
const deployed = compat.edgeFunctions.deployed ?? "unknown";
|
|
45908
|
+
switch (compat.edgeFunctions.level) {
|
|
45909
|
+
case "below-min":
|
|
45910
|
+
return {
|
|
45911
|
+
name: "edge functions",
|
|
45912
|
+
status: "error",
|
|
45913
|
+
detail: `Deployed EF v${deployed} is below the required minimum v${compat.edgeFunctions.min}.`,
|
|
45914
|
+
hint: "Update the Edge Functions (see remediation below)."
|
|
45915
|
+
};
|
|
45916
|
+
case "above-min-but-old":
|
|
45917
|
+
return {
|
|
45918
|
+
name: "edge functions",
|
|
45919
|
+
status: "warn",
|
|
45920
|
+
detail: `Deployed EF v${deployed} works but is older than this client (v${PKG_VERSION}).`,
|
|
45921
|
+
hint: "Update the Edge Functions (see remediation below)."
|
|
45922
|
+
};
|
|
45923
|
+
default:
|
|
45924
|
+
return {
|
|
45925
|
+
name: "edge functions",
|
|
45926
|
+
status: "ok",
|
|
45927
|
+
detail: `Deployed EF v${deployed} (≥ required v${compat.edgeFunctions.min}).`
|
|
45928
|
+
};
|
|
45929
|
+
}
|
|
45930
|
+
}
|
|
45281
45931
|
async function runSteps(steps, opts) {
|
|
45282
45932
|
const results = [];
|
|
45283
45933
|
for (let i = 0;i < steps.length; i++) {
|
|
@@ -45303,7 +45953,8 @@ async function runAllChecks(opts = {}) {
|
|
|
45303
45953
|
{ name: "legacy env", phase: "Checking legacy env shadowing", run: () => checkLegacyShadowEnv() },
|
|
45304
45954
|
{ name: "supabase", phase: "Probing Supabase Data API", run: () => checkSupabase() },
|
|
45305
45955
|
{ name: "openai", phase: "Probing OpenAI embeddings", run: () => checkOpenAI() },
|
|
45306
|
-
{ name: "schema", phase: "Reading schema version", run: () => checkSchemaVersion() },
|
|
45956
|
+
{ name: "schema + RPCs", phase: "Reading schema + RPC version", run: () => checkSchemaVersion() },
|
|
45957
|
+
{ name: "edge functions", phase: "Probing Edge Function versions", run: () => checkEdgeFunctionsCompat() },
|
|
45307
45958
|
{ name: "postgres", phase: "Probing Postgres DDL endpoint", run: () => checkPostgres() },
|
|
45308
45959
|
{ name: "mcp clients", phase: "Scanning MCP client configs", run: () => checkMcpConfigs() }
|
|
45309
45960
|
];
|
|
@@ -45331,7 +45982,7 @@ function symbol(status) {
|
|
|
45331
45982
|
return cErr.dim("ℹ");
|
|
45332
45983
|
}
|
|
45333
45984
|
}
|
|
45334
|
-
async function
|
|
45985
|
+
async function action10(options) {
|
|
45335
45986
|
const useSpinner = !options.json && process.stderr.isTTY;
|
|
45336
45987
|
const spinner = useSpinner ? ora({ text: "Starting checks…", spinner: "dots", stream: process.stderr }).start() : null;
|
|
45337
45988
|
const results = await runAllChecks({
|
|
@@ -45355,6 +46006,26 @@ async function action8(options) {
|
|
|
45355
46006
|
}
|
|
45356
46007
|
println("");
|
|
45357
46008
|
}
|
|
46009
|
+
if (!options.json) {
|
|
46010
|
+
const stale = (name) => {
|
|
46011
|
+
const r = results.find((x) => x.name === name);
|
|
46012
|
+
return r != null && (r.status === "error" || r.status === "warn");
|
|
46013
|
+
};
|
|
46014
|
+
const needsSchema = stale("schema + RPCs");
|
|
46015
|
+
const needsEf = stale("edge functions");
|
|
46016
|
+
let remediation = null;
|
|
46017
|
+
if (needsSchema && needsEf) {
|
|
46018
|
+
remediation = "Update the server (schema + RPCs + Edge Functions): cerefox deploy-server";
|
|
46019
|
+
} else if (needsSchema) {
|
|
46020
|
+
remediation = "Update the schema + RPCs: cerefox deploy-server --schema-only";
|
|
46021
|
+
} else if (needsEf) {
|
|
46022
|
+
remediation = "Update the Edge Functions: cerefox deploy-server --functions-only";
|
|
46023
|
+
}
|
|
46024
|
+
if (remediation) {
|
|
46025
|
+
println(cErr.yellow("→ " + remediation));
|
|
46026
|
+
println("");
|
|
46027
|
+
}
|
|
46028
|
+
}
|
|
45358
46029
|
const errCount = results.filter((r) => r.status === "error").length;
|
|
45359
46030
|
const warnCount = results.filter((r) => r.status === "warn").length;
|
|
45360
46031
|
if (errCount > 0) {
|
|
@@ -45368,13 +46039,13 @@ async function action8(options) {
|
|
|
45368
46039
|
}
|
|
45369
46040
|
}
|
|
45370
46041
|
function registerDoctor(program2) {
|
|
45371
|
-
program2.command("doctor").description("Run diagnostic checks against the installed Cerefox.").option("--json", "Emit machine-readable JSON (no colours, structured output).").action(
|
|
46042
|
+
program2.command("doctor").description("Run diagnostic checks against the installed Cerefox.").option("--json", "Emit machine-readable JSON (no colours, structured output).").action(action10);
|
|
45372
46043
|
}
|
|
45373
46044
|
|
|
45374
46045
|
// src/cli/commands/get-audit-log.ts
|
|
45375
46046
|
init_cli_core();
|
|
45376
46047
|
init_client();
|
|
45377
|
-
async function
|
|
46048
|
+
async function action11(options) {
|
|
45378
46049
|
const limit = parsePositiveInt(options.limit, "--limit", 50);
|
|
45379
46050
|
const client = getClient();
|
|
45380
46051
|
const data = await client.rpc("cerefox_list_audit_entries", {
|
|
@@ -45412,14 +46083,14 @@ async function action9(options) {
|
|
|
45412
46083
|
})));
|
|
45413
46084
|
}
|
|
45414
46085
|
function registerGetAuditLog(program2) {
|
|
45415
|
-
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(
|
|
46086
|
+
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(action11);
|
|
45416
46087
|
}
|
|
45417
46088
|
|
|
45418
46089
|
// src/cli/commands/get-doc.ts
|
|
45419
46090
|
init_cli_core();
|
|
45420
46091
|
init_cli_core();
|
|
45421
46092
|
init_client();
|
|
45422
|
-
async function
|
|
46093
|
+
async function action12(documentId, options) {
|
|
45423
46094
|
const client = getClient();
|
|
45424
46095
|
const rows = await client.rpc("cerefox_get_document", {
|
|
45425
46096
|
p_document_id: documentId,
|
|
@@ -45449,18 +46120,18 @@ async function action10(documentId, options) {
|
|
|
45449
46120
|
println(doc.full_content);
|
|
45450
46121
|
}
|
|
45451
46122
|
function registerGetDoc(program2) {
|
|
45452
|
-
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.").action(
|
|
46123
|
+
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.").action(action12);
|
|
45453
46124
|
}
|
|
45454
46125
|
|
|
45455
46126
|
// src/cli/commands/ingest.ts
|
|
45456
46127
|
init_dist4();
|
|
45457
46128
|
init_cli_core();
|
|
45458
46129
|
init_config();
|
|
45459
|
-
import { readFileSync as
|
|
46130
|
+
import { readFileSync as readFileSync8 } from "node:fs";
|
|
45460
46131
|
import { basename as basename2, extname as extname2 } from "node:path";
|
|
45461
46132
|
|
|
45462
46133
|
// src/ingestion/pipeline.ts
|
|
45463
|
-
import { readFileSync as
|
|
46134
|
+
import { readFileSync as readFileSync7 } from "node:fs";
|
|
45464
46135
|
import { basename, extname, resolve as resolve3 } from "node:path";
|
|
45465
46136
|
|
|
45466
46137
|
// ../../_shared/ingest/chunker.ts
|
|
@@ -46144,7 +46815,7 @@ ${c2.content}`);
|
|
|
46144
46815
|
};
|
|
46145
46816
|
}
|
|
46146
46817
|
async ingestFile(path, opts = {}) {
|
|
46147
|
-
const text =
|
|
46818
|
+
const text = readFileSync7(path, "utf8");
|
|
46148
46819
|
const absPath = resolve3(path);
|
|
46149
46820
|
const stem = basename(absPath, extname(absPath));
|
|
46150
46821
|
return this.ingestText({
|
|
@@ -46178,7 +46849,7 @@ async function readContent(path, paste) {
|
|
|
46178
46849
|
}
|
|
46179
46850
|
let content;
|
|
46180
46851
|
try {
|
|
46181
|
-
content =
|
|
46852
|
+
content = readFileSync8(path, "utf8");
|
|
46182
46853
|
} catch (err) {
|
|
46183
46854
|
const msg = err instanceof Error ? err.message : String(err);
|
|
46184
46855
|
throw userError(`Cannot read ${path}: ${msg}`);
|
|
@@ -46186,7 +46857,7 @@ async function readContent(path, paste) {
|
|
|
46186
46857
|
const titleFromPath = basename2(path, extname2(path));
|
|
46187
46858
|
return { content, titleFromPath };
|
|
46188
46859
|
}
|
|
46189
|
-
async function
|
|
46860
|
+
async function action13(path, options) {
|
|
46190
46861
|
const { content, titleFromPath } = await readContent(path, Boolean(options.paste));
|
|
46191
46862
|
const title = options.title ?? titleFromPath;
|
|
46192
46863
|
if (!title || title.trim() === "") {
|
|
@@ -46258,7 +46929,7 @@ async function action11(path, options) {
|
|
|
46258
46929
|
}
|
|
46259
46930
|
}
|
|
46260
46931
|
function registerIngest(program2) {
|
|
46261
|
-
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 (default: cli).", "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("-a, --author <name>", "Caller identity (audit log).").option("--author-type <type>", "'user' or 'agent' (default: user).", "user").action(
|
|
46932
|
+
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 (default: cli).", "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("-a, --author <name>", "Caller identity (audit log).").option("--author-type <type>", "'user' or 'agent' (default: user).", "user").action(action13);
|
|
46262
46933
|
}
|
|
46263
46934
|
|
|
46264
46935
|
// src/cli/commands/ingest-dir.ts
|
|
@@ -46266,18 +46937,18 @@ init_dist4();
|
|
|
46266
46937
|
init_cli_core();
|
|
46267
46938
|
init_config();
|
|
46268
46939
|
var import_cli_progress = __toESM(require_cli_progress(), 1);
|
|
46269
|
-
import { readdirSync as
|
|
46270
|
-
import { basename as basename3, extname as extname3, join as
|
|
46940
|
+
import { readdirSync as readdirSync4, statSync as statSync3 } from "node:fs";
|
|
46941
|
+
import { basename as basename3, extname as extname3, join as join8 } from "node:path";
|
|
46271
46942
|
function walk(dir, extensions) {
|
|
46272
46943
|
let entries;
|
|
46273
46944
|
try {
|
|
46274
|
-
entries =
|
|
46945
|
+
entries = readdirSync4(dir);
|
|
46275
46946
|
} catch (err) {
|
|
46276
46947
|
throw userError(`Cannot read directory ${dir}: ${err instanceof Error ? err.message : String(err)}`);
|
|
46277
46948
|
}
|
|
46278
46949
|
const files = [];
|
|
46279
46950
|
for (const name of entries) {
|
|
46280
|
-
const full =
|
|
46951
|
+
const full = join8(dir, name);
|
|
46281
46952
|
let stat;
|
|
46282
46953
|
try {
|
|
46283
46954
|
stat = statSync3(full);
|
|
@@ -46294,7 +46965,7 @@ function walk(dir, extensions) {
|
|
|
46294
46965
|
}
|
|
46295
46966
|
return files;
|
|
46296
46967
|
}
|
|
46297
|
-
async function
|
|
46968
|
+
async function action14(dir, options) {
|
|
46298
46969
|
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));
|
|
46299
46970
|
const files = walk(dir, extensions);
|
|
46300
46971
|
if (files.length === 0) {
|
|
@@ -46367,29 +47038,30 @@ async function action12(dir, options) {
|
|
|
46367
47038
|
}
|
|
46368
47039
|
}
|
|
46369
47040
|
function registerIngestDir(program2) {
|
|
46370
|
-
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 (default: cli).", "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(
|
|
47041
|
+
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 (default: cli).", "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(action14);
|
|
46371
47042
|
}
|
|
46372
47043
|
|
|
46373
47044
|
// src/cli/commands/init.ts
|
|
46374
47045
|
init_cli_core();
|
|
46375
47046
|
init_config();
|
|
47047
|
+
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
46376
47048
|
import {
|
|
46377
47049
|
chmodSync,
|
|
46378
47050
|
copyFileSync as copyFileSync2,
|
|
46379
|
-
existsSync as
|
|
47051
|
+
existsSync as existsSync9,
|
|
46380
47052
|
mkdirSync as mkdirSync3,
|
|
46381
|
-
readFileSync as
|
|
47053
|
+
readFileSync as readFileSync10,
|
|
46382
47054
|
writeFileSync as writeFileSync3
|
|
46383
47055
|
} from "node:fs";
|
|
46384
47056
|
import { homedir as homedir5 } from "node:os";
|
|
46385
|
-
import { dirname as
|
|
47057
|
+
import { dirname as dirname4, join as join9 } from "node:path";
|
|
46386
47058
|
async function readConfigFile(path) {
|
|
46387
|
-
if (!
|
|
47059
|
+
if (!existsSync9(path)) {
|
|
46388
47060
|
throw userError(`--config file not found: ${path}`);
|
|
46389
47061
|
}
|
|
46390
47062
|
let parsed;
|
|
46391
47063
|
try {
|
|
46392
|
-
parsed = JSON.parse(
|
|
47064
|
+
parsed = JSON.parse(readFileSync10(path, "utf8"));
|
|
46393
47065
|
} catch (err) {
|
|
46394
47066
|
throw userError(`--config: invalid JSON in ${path}: ${err instanceof Error ? err.message : String(err)}`);
|
|
46395
47067
|
}
|
|
@@ -46431,7 +47103,7 @@ function parseDotEnvFile(content) {
|
|
|
46431
47103
|
return map;
|
|
46432
47104
|
}
|
|
46433
47105
|
function answersFromEnvFile(path) {
|
|
46434
|
-
const parsed = parseDotEnvFile(
|
|
47106
|
+
const parsed = parseDotEnvFile(readFileSync10(path, "utf8"));
|
|
46435
47107
|
const required = ["CEREFOX_SUPABASE_URL", "CEREFOX_SUPABASE_KEY", "OPENAI_API_KEY"];
|
|
46436
47108
|
for (const key of required) {
|
|
46437
47109
|
if (!parsed[key] || parsed[key].trim() === "") {
|
|
@@ -46592,14 +47264,60 @@ async function promptMigrationChoice() {
|
|
|
46592
47264
|
const ch = choice.trim().toLowerCase() || "c";
|
|
46593
47265
|
return ch;
|
|
46594
47266
|
}
|
|
46595
|
-
async function
|
|
46596
|
-
|
|
47267
|
+
async function probeSchemaVersion(url, key) {
|
|
47268
|
+
try {
|
|
47269
|
+
const resp = await fetch(`${url.replace(/\/$/, "")}/rest/v1/rpc/cerefox_schema_version`, {
|
|
47270
|
+
method: "POST",
|
|
47271
|
+
headers: { "Content-Type": "application/json", apikey: key, Authorization: `Bearer ${key}` },
|
|
47272
|
+
body: "{}"
|
|
47273
|
+
});
|
|
47274
|
+
if (!resp.ok)
|
|
47275
|
+
return null;
|
|
47276
|
+
const data = await resp.json();
|
|
47277
|
+
return typeof data === "string" ? data : null;
|
|
47278
|
+
} catch {
|
|
47279
|
+
return null;
|
|
47280
|
+
}
|
|
47281
|
+
}
|
|
47282
|
+
function launchDeployServer(extraArgs = []) {
|
|
47283
|
+
const r = spawnSync4(process.execPath, [process.argv[1], "deploy-server", ...extraArgs], {
|
|
47284
|
+
stdio: "inherit"
|
|
47285
|
+
});
|
|
47286
|
+
return r.status ?? 1;
|
|
47287
|
+
}
|
|
47288
|
+
async function maybeOfferServerDeploy() {
|
|
47289
|
+
const settings = loadSettings();
|
|
47290
|
+
if (!settings.supabaseUrl || !settings.supabaseKey)
|
|
47291
|
+
return;
|
|
47292
|
+
const deployed = await probeSchemaVersion(settings.supabaseUrl, settings.supabaseKey);
|
|
47293
|
+
if (deployed === null) {
|
|
47294
|
+
println(c.bold("Schema deploy"));
|
|
47295
|
+
println(c.dim(" No Cerefox schema detected on this Supabase project."));
|
|
47296
|
+
const yes = await confirm(" Deploy the server now (schema + RPCs + Edge Functions)?", false);
|
|
47297
|
+
if (yes)
|
|
47298
|
+
launchDeployServer();
|
|
47299
|
+
else
|
|
47300
|
+
println(c.dim(" Skipped. Run `cerefox deploy-server` later (or `cerefox doctor` to recheck)."));
|
|
47301
|
+
println("");
|
|
47302
|
+
return;
|
|
47303
|
+
}
|
|
47304
|
+
if (compareSemver(deployed, COMPATIBILITY.minSchema) < 0) {
|
|
46597
47305
|
println(c.bold("Schema deploy"));
|
|
46598
|
-
println(c.
|
|
46599
|
-
|
|
46600
|
-
|
|
46601
|
-
|
|
47306
|
+
println(c.yellow(` Deployed schema v${deployed} is below the required v${COMPATIBILITY.minSchema}.`));
|
|
47307
|
+
const yes = await confirm(" Update the server now (applies pending migrations, refreshes RPCs + EFs)?", true);
|
|
47308
|
+
if (yes)
|
|
47309
|
+
launchDeployServer();
|
|
47310
|
+
else
|
|
47311
|
+
println(c.dim(" Skipped. Run `cerefox deploy-server` when ready."));
|
|
46602
47312
|
println("");
|
|
47313
|
+
return;
|
|
47314
|
+
}
|
|
47315
|
+
println(c.dim(`Schema v${deployed} already deployed (≥ required v${COMPATIBILITY.minSchema}).`));
|
|
47316
|
+
println("");
|
|
47317
|
+
}
|
|
47318
|
+
async function postWriteLifecycle(envPath, options) {
|
|
47319
|
+
if (!options.skipSchema) {
|
|
47320
|
+
await maybeOfferServerDeploy();
|
|
46603
47321
|
}
|
|
46604
47322
|
if (!options.skipSelfDocs) {
|
|
46605
47323
|
println(c.bold("Self-doc ingest"));
|
|
@@ -46640,7 +47358,7 @@ async function postWriteLifecycle(envPath, options) {
|
|
|
46640
47358
|
println(c.dim(` Config in effect: ${envPath}`));
|
|
46641
47359
|
}
|
|
46642
47360
|
function writeAnswersTo(target, answers) {
|
|
46643
|
-
mkdirSync3(
|
|
47361
|
+
mkdirSync3(dirname4(target), { recursive: true });
|
|
46644
47362
|
writeFileSync3(target, buildEnvFile(answers), "utf8");
|
|
46645
47363
|
if (process.platform !== "win32") {
|
|
46646
47364
|
try {
|
|
@@ -46650,13 +47368,13 @@ function writeAnswersTo(target, answers) {
|
|
|
46650
47368
|
}
|
|
46651
47369
|
}
|
|
46652
47370
|
}
|
|
46653
|
-
async function
|
|
46654
|
-
const homeEnv =
|
|
46655
|
-
const cwdEnv =
|
|
47371
|
+
async function action16(options) {
|
|
47372
|
+
const homeEnv = join9(homedir5(), USER_STATE_DIR_NAME, ".env");
|
|
47373
|
+
const cwdEnv = join9(process.cwd(), ".env");
|
|
46656
47374
|
const explicitDir = (process.env.CEREFOX_CONFIG_DIR ?? "").trim();
|
|
46657
47375
|
if (explicitDir) {
|
|
46658
47376
|
const target2 = resolveEnvFile();
|
|
46659
|
-
if (
|
|
47377
|
+
if (existsSync9(target2) && !options.force) {
|
|
46660
47378
|
println(c.yellow(`⚠ Config already exists at ${target2}.`));
|
|
46661
47379
|
const ok2 = await confirm("Overwrite?", true);
|
|
46662
47380
|
if (!ok2) {
|
|
@@ -46678,7 +47396,7 @@ async function action14(options) {
|
|
|
46678
47396
|
await postWriteLifecycle(target2, options);
|
|
46679
47397
|
return;
|
|
46680
47398
|
}
|
|
46681
|
-
if (
|
|
47399
|
+
if (existsSync9(homeEnv) && !options.force) {
|
|
46682
47400
|
println(c.yellow(`⚠ Config already exists at ${homeEnv}.`));
|
|
46683
47401
|
const ok2 = await confirm("Overwrite?", true);
|
|
46684
47402
|
if (!ok2) {
|
|
@@ -46699,12 +47417,12 @@ async function action14(options) {
|
|
|
46699
47417
|
await postWriteLifecycle(homeEnv, options);
|
|
46700
47418
|
return;
|
|
46701
47419
|
}
|
|
46702
|
-
if (
|
|
47420
|
+
if (existsSync9(cwdEnv) && !options.force && !options.config) {
|
|
46703
47421
|
printMigrationMenu(cwdEnv, homeEnv);
|
|
46704
47422
|
const ch = await promptMigrationChoice();
|
|
46705
47423
|
println("");
|
|
46706
47424
|
if (ch === "c") {
|
|
46707
|
-
mkdirSync3(
|
|
47425
|
+
mkdirSync3(dirname4(homeEnv), { recursive: true });
|
|
46708
47426
|
copyFileSync2(cwdEnv, homeEnv);
|
|
46709
47427
|
if (process.platform !== "win32") {
|
|
46710
47428
|
try {
|
|
@@ -46759,13 +47477,13 @@ async function action14(options) {
|
|
|
46759
47477
|
await postWriteLifecycle(target, options);
|
|
46760
47478
|
}
|
|
46761
47479
|
function registerInit(program2) {
|
|
46762
|
-
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(
|
|
47480
|
+
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(action16);
|
|
46763
47481
|
}
|
|
46764
47482
|
|
|
46765
47483
|
// src/cli/commands/list-docs.ts
|
|
46766
47484
|
init_cli_core();
|
|
46767
47485
|
init_client();
|
|
46768
|
-
async function
|
|
47486
|
+
async function action17(options) {
|
|
46769
47487
|
const limit = parsePositiveInt(options.limit, "--limit", 100);
|
|
46770
47488
|
const client = getClient();
|
|
46771
47489
|
let projectId;
|
|
@@ -46820,13 +47538,13 @@ async function action15(options) {
|
|
|
46820
47538
|
})));
|
|
46821
47539
|
}
|
|
46822
47540
|
function registerListDocs(program2) {
|
|
46823
|
-
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("--json", "Emit machine-readable JSON.").action(
|
|
47541
|
+
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("--json", "Emit machine-readable JSON.").action(action17);
|
|
46824
47542
|
}
|
|
46825
47543
|
|
|
46826
47544
|
// src/cli/commands/list-metadata-keys.ts
|
|
46827
47545
|
init_cli_core();
|
|
46828
47546
|
init_client();
|
|
46829
|
-
async function
|
|
47547
|
+
async function action18(options) {
|
|
46830
47548
|
const client = getClient();
|
|
46831
47549
|
const data = await client.rpc("cerefox_list_metadata_keys");
|
|
46832
47550
|
if (data === null) {
|
|
@@ -46854,13 +47572,13 @@ async function action16(options) {
|
|
|
46854
47572
|
})));
|
|
46855
47573
|
}
|
|
46856
47574
|
function registerListMetadataKeys(program2) {
|
|
46857
|
-
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(
|
|
47575
|
+
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(action18);
|
|
46858
47576
|
}
|
|
46859
47577
|
|
|
46860
47578
|
// src/cli/commands/list-projects.ts
|
|
46861
47579
|
init_cli_core();
|
|
46862
47580
|
init_client();
|
|
46863
|
-
async function
|
|
47581
|
+
async function action19(options) {
|
|
46864
47582
|
const client = getClient();
|
|
46865
47583
|
const { data, error: error2 } = await client.raw.from("cerefox_projects").select("id, name, description, created_at").order("name", { ascending: true });
|
|
46866
47584
|
if (error2) {
|
|
@@ -46889,13 +47607,13 @@ async function action17(options) {
|
|
|
46889
47607
|
})), "(no projects)");
|
|
46890
47608
|
}
|
|
46891
47609
|
function registerListProjects(program2) {
|
|
46892
|
-
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(
|
|
47610
|
+
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(action19);
|
|
46893
47611
|
}
|
|
46894
47612
|
|
|
46895
47613
|
// src/cli/commands/list-versions.ts
|
|
46896
47614
|
init_cli_core();
|
|
46897
47615
|
init_client();
|
|
46898
|
-
async function
|
|
47616
|
+
async function action20(documentId, options) {
|
|
46899
47617
|
const client = getClient();
|
|
46900
47618
|
const data = await client.rpc("cerefox_list_document_versions", {
|
|
46901
47619
|
p_document_id: documentId
|
|
@@ -46936,7 +47654,7 @@ async function action18(documentId, options) {
|
|
|
46936
47654
|
})));
|
|
46937
47655
|
}
|
|
46938
47656
|
function registerListVersions(program2) {
|
|
46939
|
-
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(
|
|
47657
|
+
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(action20);
|
|
46940
47658
|
}
|
|
46941
47659
|
|
|
46942
47660
|
// src/cli/commands/mcp.ts
|
|
@@ -46951,7 +47669,7 @@ function registerMcp(program2) {
|
|
|
46951
47669
|
// src/cli/commands/metadata-search.ts
|
|
46952
47670
|
init_cli_core();
|
|
46953
47671
|
init_client();
|
|
46954
|
-
async function
|
|
47672
|
+
async function action21(options) {
|
|
46955
47673
|
const metadataFilter = parseJsonObjectArg(options.metadataFilter, "--metadata-filter");
|
|
46956
47674
|
if (!metadataFilter || Object.keys(metadataFilter).length === 0) {
|
|
46957
47675
|
throw userError("--metadata-filter is required and must be a non-empty JSON object.", `Example: --metadata-filter '{"type":"decision-log"}'.`);
|
|
@@ -47014,7 +47732,7 @@ async function action19(options) {
|
|
|
47014
47732
|
}
|
|
47015
47733
|
}
|
|
47016
47734
|
function registerMetadataSearch(program2) {
|
|
47017
|
-
program2.command("metadata-search").description("Find documents by metadata criteria (no text query).").requiredOption("-f, --metadata-filter <json>", "JSON object; only docs whose metadata contains ALL pairs are returned.").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(
|
|
47735
|
+
program2.command("metadata-search").description("Find documents by metadata criteria (no text query).").requiredOption("-f, --metadata-filter <json>", "JSON object; only docs whose metadata contains ALL pairs are returned.").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(action21);
|
|
47018
47736
|
}
|
|
47019
47737
|
|
|
47020
47738
|
// src/cli/commands/reindex.ts
|
|
@@ -47022,7 +47740,7 @@ init_dist4();
|
|
|
47022
47740
|
init_cli_core();
|
|
47023
47741
|
init_config();
|
|
47024
47742
|
var DEFAULT_MODEL = "text-embedding-3-small";
|
|
47025
|
-
async function
|
|
47743
|
+
async function action22(options) {
|
|
47026
47744
|
const settings = loadSettings();
|
|
47027
47745
|
if (!settings.supabaseUrl || !settings.supabaseKey) {
|
|
47028
47746
|
throw userError("Supabase credentials not configured — run `cerefox init` first.");
|
|
@@ -47101,41 +47819,41 @@ ${c2.content}`;
|
|
|
47101
47819
|
}
|
|
47102
47820
|
}
|
|
47103
47821
|
function registerReindex(program2) {
|
|
47104
|
-
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(
|
|
47822
|
+
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(action22);
|
|
47105
47823
|
}
|
|
47106
47824
|
|
|
47107
47825
|
// src/cli/commands/restore.ts
|
|
47108
47826
|
init_cli_core();
|
|
47109
47827
|
init_client();
|
|
47110
|
-
import { existsSync as
|
|
47828
|
+
import { existsSync as existsSync10, readFileSync as readFileSync11, readdirSync as readdirSync5, statSync as statSync4 } from "node:fs";
|
|
47111
47829
|
import { homedir as homedir6 } from "node:os";
|
|
47112
|
-
import { join as
|
|
47830
|
+
import { join as join10, resolve as resolve4 } from "node:path";
|
|
47113
47831
|
function expandHome2(path) {
|
|
47114
47832
|
if (path === "~")
|
|
47115
47833
|
return homedir6();
|
|
47116
47834
|
if (path.startsWith("~/"))
|
|
47117
|
-
return
|
|
47835
|
+
return join10(homedir6(), path.slice(2));
|
|
47118
47836
|
return path;
|
|
47119
47837
|
}
|
|
47120
47838
|
function resolveBackupFile(target) {
|
|
47121
47839
|
const path = resolve4(expandHome2(target));
|
|
47122
|
-
if (!
|
|
47840
|
+
if (!existsSync10(path)) {
|
|
47123
47841
|
throw userError(`Backup path not found: ${target}`);
|
|
47124
47842
|
}
|
|
47125
47843
|
const stat = statSync4(path);
|
|
47126
47844
|
if (stat.isFile())
|
|
47127
47845
|
return path;
|
|
47128
|
-
const candidates =
|
|
47846
|
+
const candidates = readdirSync5(path).filter((n) => n.endsWith(".json") && n.startsWith("cerefox-")).map((n) => ({ name: n, mtime: statSync4(join10(path, n)).mtimeMs })).sort((a, b2) => b2.mtime - a.mtime);
|
|
47129
47847
|
if (candidates.length === 0) {
|
|
47130
47848
|
throw userError(`No cerefox-*.json files in ${path}`);
|
|
47131
47849
|
}
|
|
47132
|
-
return
|
|
47850
|
+
return join10(path, candidates[0].name);
|
|
47133
47851
|
}
|
|
47134
|
-
async function
|
|
47852
|
+
async function action23(target, options) {
|
|
47135
47853
|
const file = resolveBackupFile(target);
|
|
47136
47854
|
let payload;
|
|
47137
47855
|
try {
|
|
47138
|
-
payload = JSON.parse(
|
|
47856
|
+
payload = JSON.parse(readFileSync11(file, "utf8"));
|
|
47139
47857
|
} catch (err) {
|
|
47140
47858
|
throw userError(`Could not parse backup file ${file}: ${err instanceof Error ? err.message : String(err)}`);
|
|
47141
47859
|
}
|
|
@@ -47187,7 +47905,7 @@ async function action21(target, options) {
|
|
|
47187
47905
|
}
|
|
47188
47906
|
}
|
|
47189
47907
|
function registerRestore(program2) {
|
|
47190
|
-
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 ride along with each doc's metadata).").action(
|
|
47908
|
+
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 ride along with each doc's metadata).").action(action23);
|
|
47191
47909
|
}
|
|
47192
47910
|
|
|
47193
47911
|
// src/cli/commands/search.ts
|
|
@@ -47212,7 +47930,7 @@ async function embedQuery(query) {
|
|
|
47212
47930
|
}
|
|
47213
47931
|
|
|
47214
47932
|
// src/cli/commands/search.ts
|
|
47215
|
-
async function
|
|
47933
|
+
async function action24(query, options) {
|
|
47216
47934
|
if (!query || query.trim() === "") {
|
|
47217
47935
|
throw userError("Empty query.");
|
|
47218
47936
|
}
|
|
@@ -47346,13 +48064,13 @@ async function action22(query, options) {
|
|
|
47346
48064
|
}
|
|
47347
48065
|
}
|
|
47348
48066
|
function registerSearch(program2) {
|
|
47349
|
-
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: 0.7).", "0.7").option("--min-score <float>", "Minimum cosine similarity threshold.", "0.5").option("--max-bytes <n>", "Response size budget in bytes.", "200000").option("-r, --requestor <name>", "Agent / user name (recorded in usage log).").option("--json", "Emit machine-readable JSON instead of the default text.").action(
|
|
48067
|
+
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: 0.7).", "0.7").option("--min-score <float>", "Minimum cosine similarity threshold.", "0.5").option("--max-bytes <n>", "Response size budget in bytes.", "200000").option("-r, --requestor <name>", "Agent / user name (recorded in usage log).").option("--json", "Emit machine-readable JSON instead of the default text.").action(action24);
|
|
47350
48068
|
}
|
|
47351
48069
|
|
|
47352
48070
|
// src/cli/commands/self-update.ts
|
|
47353
48071
|
init_cli_core();
|
|
47354
48072
|
init_meta();
|
|
47355
|
-
import { spawnSync as
|
|
48073
|
+
import { spawnSync as spawnSync5 } from "node:child_process";
|
|
47356
48074
|
function detectRuntime() {
|
|
47357
48075
|
const bin = (process.argv[1] ?? "").toLowerCase();
|
|
47358
48076
|
if (bin.includes(".bun") || bin.includes("/bun/")) {
|
|
@@ -47393,7 +48111,7 @@ async function fetchLatestVersion() {
|
|
|
47393
48111
|
}
|
|
47394
48112
|
return body.version;
|
|
47395
48113
|
}
|
|
47396
|
-
async function
|
|
48114
|
+
async function action25(options) {
|
|
47397
48115
|
let target;
|
|
47398
48116
|
try {
|
|
47399
48117
|
target = options.version ?? await fetchLatestVersion();
|
|
@@ -47425,7 +48143,7 @@ async function action23(options) {
|
|
|
47425
48143
|
return;
|
|
47426
48144
|
}
|
|
47427
48145
|
}
|
|
47428
|
-
const result =
|
|
48146
|
+
const result = spawnSync5(runtime.command, runtime.args(target), {
|
|
47429
48147
|
stdio: "inherit"
|
|
47430
48148
|
});
|
|
47431
48149
|
if (result.status !== 0) {
|
|
@@ -47445,7 +48163,7 @@ async function action23(options) {
|
|
|
47445
48163
|
}
|
|
47446
48164
|
function registerSelfUpdate(program2) {
|
|
47447
48165
|
const desc = "Upgrade Cerefox in place. Alias: `cerefox upgrade`.";
|
|
47448
|
-
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(
|
|
48166
|
+
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(action25);
|
|
47449
48167
|
declaration(program2.command("self-update"));
|
|
47450
48168
|
declaration(program2.command("upgrade"));
|
|
47451
48169
|
}
|
|
@@ -47464,7 +48182,7 @@ function symbol2(status) {
|
|
|
47464
48182
|
return cErr.dim("ℹ");
|
|
47465
48183
|
}
|
|
47466
48184
|
}
|
|
47467
|
-
async function
|
|
48185
|
+
async function action26(options) {
|
|
47468
48186
|
const useSpinner = !options.json && process.stderr.isTTY;
|
|
47469
48187
|
const spinner = useSpinner ? ora({ text: "Starting checks…", spinner: "dots", stream: process.stderr }).start() : null;
|
|
47470
48188
|
const results = await runFastChecks({
|
|
@@ -47485,7 +48203,7 @@ async function action24(options) {
|
|
|
47485
48203
|
}
|
|
47486
48204
|
}
|
|
47487
48205
|
function registerStatus(program2) {
|
|
47488
|
-
program2.command("status").description("Quick sanity check (fast subset of `cerefox doctor`).").option("--json", "Emit machine-readable JSON.").action(
|
|
48206
|
+
program2.command("status").description("Quick sanity check (fast subset of `cerefox doctor`).").option("--json", "Emit machine-readable JSON.").action(action26);
|
|
47489
48207
|
}
|
|
47490
48208
|
|
|
47491
48209
|
// src/cli/commands/sync-docs.ts
|
|
@@ -47494,19 +48212,19 @@ init_mcp_tools();
|
|
|
47494
48212
|
init_config();
|
|
47495
48213
|
init_client();
|
|
47496
48214
|
import {
|
|
47497
|
-
existsSync as
|
|
47498
|
-
readFileSync as
|
|
47499
|
-
readdirSync as
|
|
48215
|
+
existsSync as existsSync11,
|
|
48216
|
+
readFileSync as readFileSync12,
|
|
48217
|
+
readdirSync as readdirSync6,
|
|
47500
48218
|
statSync as statSync5
|
|
47501
48219
|
} from "node:fs";
|
|
47502
|
-
import { basename as basename5, extname as extname5, join as
|
|
48220
|
+
import { basename as basename5, extname as extname5, join as join11, relative } from "node:path";
|
|
47503
48221
|
var ROOT_LEVEL_DOCS = ["README.md", "AGENT_GUIDE.md", "AGENT_QUICK_REFERENCE.md"];
|
|
47504
48222
|
function walkMarkdown(dir) {
|
|
47505
48223
|
const out = [];
|
|
47506
|
-
if (!
|
|
48224
|
+
if (!existsSync11(dir))
|
|
47507
48225
|
return out;
|
|
47508
|
-
for (const name of
|
|
47509
|
-
const full =
|
|
48226
|
+
for (const name of readdirSync6(dir)) {
|
|
48227
|
+
const full = join11(dir, name);
|
|
47510
48228
|
let stat;
|
|
47511
48229
|
try {
|
|
47512
48230
|
stat = statSync5(full);
|
|
@@ -47521,16 +48239,16 @@ function walkMarkdown(dir) {
|
|
|
47521
48239
|
}
|
|
47522
48240
|
return out;
|
|
47523
48241
|
}
|
|
47524
|
-
async function
|
|
48242
|
+
async function action27(options) {
|
|
47525
48243
|
const cwd = process.cwd();
|
|
47526
48244
|
const project = options.project ?? "cerefox";
|
|
47527
48245
|
const targets = [];
|
|
47528
48246
|
for (const rel of ROOT_LEVEL_DOCS) {
|
|
47529
|
-
const abs =
|
|
47530
|
-
if (
|
|
48247
|
+
const abs = join11(cwd, rel);
|
|
48248
|
+
if (existsSync11(abs))
|
|
47531
48249
|
targets.push({ abs, rel });
|
|
47532
48250
|
}
|
|
47533
|
-
for (const abs of walkMarkdown(
|
|
48251
|
+
for (const abs of walkMarkdown(join11(cwd, "docs"))) {
|
|
47534
48252
|
targets.push({ abs, rel: relative(cwd, abs) });
|
|
47535
48253
|
}
|
|
47536
48254
|
if (targets.length === 0) {
|
|
@@ -47554,7 +48272,7 @@ async function action25(options) {
|
|
|
47554
48272
|
const authorType = resolveAuthorType("agent");
|
|
47555
48273
|
const outcomes = [];
|
|
47556
48274
|
for (const t of targets) {
|
|
47557
|
-
const content =
|
|
48275
|
+
const content = readFileSync12(t.abs, "utf8");
|
|
47558
48276
|
const title = basename5(t.abs, extname5(t.abs));
|
|
47559
48277
|
try {
|
|
47560
48278
|
const message = await ingestTool.handler(client.raw, {
|
|
@@ -47583,7 +48301,7 @@ async function action25(options) {
|
|
|
47583
48301
|
}
|
|
47584
48302
|
}
|
|
47585
48303
|
function registerSyncDocs(program2) {
|
|
47586
|
-
program2.command("sync-docs").description("Sync repo docs (README, AGENT_*, docs/) into a Cerefox project.").option("--dry-run", "Print what would be synced without writing.").option("-p, --project <name>", "Target project for the sync.", "cerefox").action(
|
|
48304
|
+
program2.command("sync-docs").description("Sync repo docs (README, AGENT_*, docs/) into a Cerefox project.").option("--dry-run", "Print what would be synced without writing.").option("-p, --project <name>", "Target project for the sync.", "cerefox").action(action27);
|
|
47587
48305
|
}
|
|
47588
48306
|
|
|
47589
48307
|
// src/cli/program.ts
|
|
@@ -48918,8 +49636,8 @@ var _baseMimes = {
|
|
|
48918
49636
|
var baseMimes = _baseMimes;
|
|
48919
49637
|
|
|
48920
49638
|
// ../../node_modules/.bun/@hono+node-server@2.0.4+1bbe96acb4c5ebf1/node_modules/@hono/node-server/dist/serve-static.mjs
|
|
48921
|
-
import { createReadStream, existsSync as
|
|
48922
|
-
import { join as
|
|
49639
|
+
import { createReadStream, existsSync as existsSync12, statSync as statSync6 } from "node:fs";
|
|
49640
|
+
import { join as join12 } from "node:path";
|
|
48923
49641
|
var COMPRESSIBLE_CONTENT_TYPE_REGEX = /^\s*(?:text\/[^;\s]+|application\/(?:javascript|json|xml|xml-dtd|ecmascript|dart|postscript|rtf|tar|toml|vnd\.dart|vnd\.ms-fontobject|vnd\.ms-opentype|wasm|x-httpd-php|x-javascript|x-ns-proxy-autoconfig|x-sh|x-tar|x-virtualbox-hdd|x-virtualbox-ova|x-virtualbox-ovf|x-virtualbox-vbox|x-virtualbox-vdi|x-virtualbox-vhd|x-virtualbox-vmdk|x-www-form-urlencoded)|font\/(?:otf|ttf)|image\/(?:bmp|vnd\.adobe\.photoshop|vnd\.microsoft\.icon|vnd\.ms-dds|x-icon|x-ms-bmp)|message\/rfc822|model\/gltf-binary|x-shader\/x-fragment|x-shader\/x-vertex|[^;\s]+?\+(?:json|text|xml|yaml))(?:[;\s]|$)/i;
|
|
48924
49642
|
var ENCODINGS = {
|
|
48925
49643
|
br: ".br",
|
|
@@ -48951,7 +49669,7 @@ var tryDecodeURI = (str) => tryDecode(str, decodeURI);
|
|
|
48951
49669
|
var serveStatic = (options = { root: "" }) => {
|
|
48952
49670
|
const root = options.root || "";
|
|
48953
49671
|
const optionPath = options.path;
|
|
48954
|
-
if (root !== "" && !
|
|
49672
|
+
if (root !== "" && !existsSync12(root))
|
|
48955
49673
|
console.error(`serveStatic: root path '${root}' is not found, are you sure it's correct?`);
|
|
48956
49674
|
return async (c2, next) => {
|
|
48957
49675
|
if (c2.finalized)
|
|
@@ -48968,11 +49686,11 @@ var serveStatic = (options = { root: "" }) => {
|
|
|
48968
49686
|
await options.onNotFound?.(c2.req.path, c2);
|
|
48969
49687
|
return next();
|
|
48970
49688
|
}
|
|
48971
|
-
let path =
|
|
49689
|
+
let path = join12(root, !optionPath && options.rewriteRequestPath ? options.rewriteRequestPath(filename, c2) : filename);
|
|
48972
49690
|
let stats = getStats(path);
|
|
48973
49691
|
if (stats && stats.isDirectory()) {
|
|
48974
49692
|
const indexFile = options.index ?? "index.html";
|
|
48975
|
-
path =
|
|
49693
|
+
path = join12(path, indexFile);
|
|
48976
49694
|
stats = getStats(path);
|
|
48977
49695
|
}
|
|
48978
49696
|
if (!stats) {
|
|
@@ -49029,9 +49747,9 @@ var serveStatic = (options = { root: "" }) => {
|
|
|
49029
49747
|
};
|
|
49030
49748
|
|
|
49031
49749
|
// src/web/server.ts
|
|
49032
|
-
import { existsSync as
|
|
49033
|
-
import { readFileSync as
|
|
49034
|
-
import { join as
|
|
49750
|
+
import { existsSync as existsSync15 } from "node:fs";
|
|
49751
|
+
import { readFileSync as readFileSync14 } from "node:fs";
|
|
49752
|
+
import { join as join15 } from "node:path";
|
|
49035
49753
|
|
|
49036
49754
|
// ../../node_modules/.bun/hono@4.12.23/node_modules/hono/dist/compose.js
|
|
49037
49755
|
var compose = (middleware, onError, onNotFound) => {
|
|
@@ -50838,7 +51556,7 @@ function registerConfigRoutes(app, ctx) {
|
|
|
50838
51556
|
}
|
|
50839
51557
|
|
|
50840
51558
|
// src/web/routes/discovery.ts
|
|
50841
|
-
var
|
|
51559
|
+
var UUID_RE2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
50842
51560
|
var DOC_COLS = "id, title, source, source_path, content_hash, metadata, chunk_count, total_chars, review_status, created_at, updated_at, deleted_at";
|
|
50843
51561
|
function jsonByteLength(value) {
|
|
50844
51562
|
return Buffer.byteLength(JSON.stringify(value), "utf8");
|
|
@@ -51284,7 +52002,7 @@ function registerDiscoveryRoutes(app, ctx) {
|
|
|
51284
52002
|
if (!path) {
|
|
51285
52003
|
return c2.json({ tried_path: "", anchor, matches: [] });
|
|
51286
52004
|
}
|
|
51287
|
-
if (
|
|
52005
|
+
if (UUID_RE2.test(path)) {
|
|
51288
52006
|
if (path === fromDocId) {
|
|
51289
52007
|
return c2.json({ tried_path: path, anchor, matches: [] });
|
|
51290
52008
|
}
|
|
@@ -51880,13 +52598,13 @@ import { execFileSync } from "node:child_process";
|
|
|
51880
52598
|
|
|
51881
52599
|
// src/web/docs.ts
|
|
51882
52600
|
import {
|
|
51883
|
-
existsSync as
|
|
51884
|
-
readFileSync as
|
|
51885
|
-
readdirSync as
|
|
52601
|
+
existsSync as existsSync13,
|
|
52602
|
+
readFileSync as readFileSync13,
|
|
52603
|
+
readdirSync as readdirSync7,
|
|
51886
52604
|
statSync as statSync7
|
|
51887
52605
|
} from "node:fs";
|
|
51888
|
-
import { basename as basename6, dirname as
|
|
51889
|
-
import { fileURLToPath as
|
|
52606
|
+
import { basename as basename6, dirname as dirname5, join as join13, resolve as resolve5 } from "node:path";
|
|
52607
|
+
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
51890
52608
|
var TOP_LEVEL_DOCS = [
|
|
51891
52609
|
{ filename: "README.md", path: "README.md", category: "readme" },
|
|
51892
52610
|
{
|
|
@@ -51900,38 +52618,38 @@ var TOP_LEVEL_DOCS = [
|
|
|
51900
52618
|
category: "agent-guide"
|
|
51901
52619
|
}
|
|
51902
52620
|
];
|
|
51903
|
-
function
|
|
51904
|
-
return
|
|
52621
|
+
function moduleDir2() {
|
|
52622
|
+
return dirname5(fileURLToPath3(import.meta.url));
|
|
51905
52623
|
}
|
|
51906
52624
|
function resolveDocsRoots() {
|
|
51907
|
-
const here =
|
|
52625
|
+
const here = moduleDir2();
|
|
51908
52626
|
const pkgRootCandidates = [
|
|
51909
|
-
|
|
51910
|
-
|
|
52627
|
+
join13(here, "..", ".."),
|
|
52628
|
+
join13(here, "..", "..", "..", "..")
|
|
51911
52629
|
];
|
|
51912
52630
|
let pkgGuides = null;
|
|
51913
52631
|
let pkgTopLevel = null;
|
|
51914
52632
|
for (const pkg of pkgRootCandidates) {
|
|
51915
|
-
const guides =
|
|
51916
|
-
if (
|
|
52633
|
+
const guides = join13(pkg, "docs", "guides");
|
|
52634
|
+
if (existsSync13(guides) && statSync7(guides).isDirectory()) {
|
|
51917
52635
|
pkgGuides = guides;
|
|
51918
52636
|
pkgTopLevel = pkg;
|
|
51919
52637
|
break;
|
|
51920
52638
|
}
|
|
51921
52639
|
}
|
|
51922
|
-
const repoCandidate =
|
|
51923
|
-
const repoGuides =
|
|
52640
|
+
const repoCandidate = join13(here, "..", "..", "..", "..");
|
|
52641
|
+
const repoGuides = join13(repoCandidate, "docs", "guides");
|
|
51924
52642
|
const repoTopLevel = repoCandidate;
|
|
51925
52643
|
return {
|
|
51926
52644
|
pkgGuides,
|
|
51927
52645
|
pkgTopLevel,
|
|
51928
|
-
repoGuides:
|
|
51929
|
-
repoTopLevel:
|
|
52646
|
+
repoGuides: existsSync13(repoGuides) ? repoGuides : null,
|
|
52647
|
+
repoTopLevel: existsSync13(join13(repoTopLevel, "README.md")) ? repoTopLevel : null
|
|
51930
52648
|
};
|
|
51931
52649
|
}
|
|
51932
52650
|
function readH1(filePath) {
|
|
51933
52651
|
try {
|
|
51934
|
-
const content =
|
|
52652
|
+
const content = readFileSync13(filePath, "utf8");
|
|
51935
52653
|
const match2 = content.match(/^#\s+(.+?)\s*$/m);
|
|
51936
52654
|
return match2 ? match2[1] : null;
|
|
51937
52655
|
} catch {
|
|
@@ -51951,17 +52669,17 @@ function listBundledDocs2() {
|
|
|
51951
52669
|
const topRoot = pkgTopLevel ?? repoTopLevel;
|
|
51952
52670
|
if (topRoot) {
|
|
51953
52671
|
for (const t of TOP_LEVEL_DOCS) {
|
|
51954
|
-
const abs =
|
|
51955
|
-
if (
|
|
52672
|
+
const abs = join13(topRoot, t.filename);
|
|
52673
|
+
if (existsSync13(abs)) {
|
|
51956
52674
|
entries.push(entryForFile(abs, t.path, t.category));
|
|
51957
52675
|
}
|
|
51958
52676
|
}
|
|
51959
52677
|
}
|
|
51960
52678
|
const guidesRoot = pkgGuides ?? repoGuides;
|
|
51961
52679
|
if (guidesRoot) {
|
|
51962
|
-
const names =
|
|
52680
|
+
const names = readdirSync7(guidesRoot).filter((n) => n.endsWith(".md")).sort();
|
|
51963
52681
|
for (const name of names) {
|
|
51964
|
-
const abs =
|
|
52682
|
+
const abs = join13(guidesRoot, name);
|
|
51965
52683
|
entries.push(entryForFile(abs, `guides/${name}`, "guide"));
|
|
51966
52684
|
}
|
|
51967
52685
|
}
|
|
@@ -51975,9 +52693,9 @@ function readDoc(docPath) {
|
|
|
51975
52693
|
if (!candidate.startsWith(resolve5(root) + "/") && candidate !== resolve5(root)) {
|
|
51976
52694
|
continue;
|
|
51977
52695
|
}
|
|
51978
|
-
if (
|
|
52696
|
+
if (existsSync13(candidate) && statSync7(candidate).isFile()) {
|
|
51979
52697
|
try {
|
|
51980
|
-
return
|
|
52698
|
+
return readFileSync13(candidate, "utf8");
|
|
51981
52699
|
} catch {
|
|
51982
52700
|
return null;
|
|
51983
52701
|
}
|
|
@@ -52006,7 +52724,7 @@ var VERSION_INFO = {
|
|
|
52006
52724
|
git_commit_short: resolveGitCommitShort(),
|
|
52007
52725
|
build_date: process.env.CEREFOX_BUILD_DATE ?? null
|
|
52008
52726
|
};
|
|
52009
|
-
var
|
|
52727
|
+
var SCHEMA_VERSION_RE2 = /^--\s*@version:\s*(\S+)/m;
|
|
52010
52728
|
function registerMetaRoutes(app, ctx) {
|
|
52011
52729
|
app.get("/api/v1/version", (c2) => c2.json(VERSION_INFO));
|
|
52012
52730
|
app.get("/api/v1/docs", (c2) => c2.json(listBundledDocs2()));
|
|
@@ -52023,18 +52741,18 @@ function registerMetaRoutes(app, ctx) {
|
|
|
52023
52741
|
app.get("/api/v1/schema-version", async (c2) => {
|
|
52024
52742
|
let bundled = null;
|
|
52025
52743
|
try {
|
|
52026
|
-
const { readFileSync:
|
|
52027
|
-
const { fileURLToPath:
|
|
52028
|
-
const { dirname:
|
|
52029
|
-
const here =
|
|
52744
|
+
const { readFileSync: readFileSync14, existsSync: existsSync14 } = await import("node:fs");
|
|
52745
|
+
const { fileURLToPath: fileURLToPath4 } = await import("node:url");
|
|
52746
|
+
const { dirname: dirname6, join: join14 } = await import("node:path");
|
|
52747
|
+
const here = dirname6(fileURLToPath4(import.meta.url));
|
|
52030
52748
|
const candidates = [
|
|
52031
|
-
|
|
52032
|
-
|
|
52749
|
+
join14(here, "..", "..", "..", "db", "schema.sql"),
|
|
52750
|
+
join14(here, "..", "..", "..", "..", "..", "src", "cerefox", "db", "schema.sql")
|
|
52033
52751
|
];
|
|
52034
52752
|
for (const path of candidates) {
|
|
52035
|
-
if (
|
|
52036
|
-
const sql =
|
|
52037
|
-
const match2 = sql.match(
|
|
52753
|
+
if (existsSync14(path)) {
|
|
52754
|
+
const sql = readFileSync14(path, "utf8");
|
|
52755
|
+
const match2 = sql.match(SCHEMA_VERSION_RE2);
|
|
52038
52756
|
bundled = match2 ? match2[1] : null;
|
|
52039
52757
|
break;
|
|
52040
52758
|
}
|
|
@@ -52071,7 +52789,14 @@ function registerMetaRoutes(app, ctx) {
|
|
|
52071
52789
|
} catch {}
|
|
52072
52790
|
}
|
|
52073
52791
|
const mismatch = Boolean(bundled && deployed && bundled !== deployed);
|
|
52074
|
-
|
|
52792
|
+
const level = classifyCompat(deployed, COMPATIBILITY.minSchema, bundled);
|
|
52793
|
+
return c2.json({
|
|
52794
|
+
bundled,
|
|
52795
|
+
deployed,
|
|
52796
|
+
mismatch,
|
|
52797
|
+
level,
|
|
52798
|
+
min: COMPATIBILITY.minSchema
|
|
52799
|
+
});
|
|
52075
52800
|
});
|
|
52076
52801
|
}
|
|
52077
52802
|
|
|
@@ -52136,21 +52861,21 @@ function registerProjectsRoutes(app, ctx) {
|
|
|
52136
52861
|
}
|
|
52137
52862
|
|
|
52138
52863
|
// src/web/static.ts
|
|
52139
|
-
import { existsSync as
|
|
52140
|
-
import { dirname as
|
|
52141
|
-
import { fileURLToPath as
|
|
52142
|
-
function
|
|
52143
|
-
return
|
|
52864
|
+
import { existsSync as existsSync14, statSync as statSync8 } from "node:fs";
|
|
52865
|
+
import { dirname as dirname6, join as join14 } from "node:path";
|
|
52866
|
+
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
52867
|
+
function moduleDir3() {
|
|
52868
|
+
return dirname6(fileURLToPath4(import.meta.url));
|
|
52144
52869
|
}
|
|
52145
52870
|
function isUsableSpaDir(dir) {
|
|
52146
|
-
return
|
|
52871
|
+
return existsSync14(dir) && statSync8(dir).isDirectory() && existsSync14(join14(dir, "index.html"));
|
|
52147
52872
|
}
|
|
52148
52873
|
function resolveSpaDist() {
|
|
52149
|
-
const here =
|
|
52874
|
+
const here = moduleDir3();
|
|
52150
52875
|
const candidates = [
|
|
52151
|
-
|
|
52152
|
-
|
|
52153
|
-
|
|
52876
|
+
join14(here, "..", "frontend"),
|
|
52877
|
+
join14(here, "..", "..", "..", "..", "frontend", "dist"),
|
|
52878
|
+
join14(here, "..", "..", "dist", "frontend")
|
|
52154
52879
|
];
|
|
52155
52880
|
for (const c2 of candidates) {
|
|
52156
52881
|
if (isUsableSpaDir(c2))
|
|
@@ -52159,13 +52884,13 @@ function resolveSpaDist() {
|
|
|
52159
52884
|
return null;
|
|
52160
52885
|
}
|
|
52161
52886
|
function resolveStaticDir() {
|
|
52162
|
-
const here =
|
|
52887
|
+
const here = moduleDir3();
|
|
52163
52888
|
const candidates = [
|
|
52164
|
-
|
|
52165
|
-
|
|
52889
|
+
join14(here, "..", "static"),
|
|
52890
|
+
join14(here, "..", "..", "..", "..", "web", "static")
|
|
52166
52891
|
];
|
|
52167
52892
|
for (const c2 of candidates) {
|
|
52168
|
-
if (
|
|
52893
|
+
if (existsSync14(c2) && statSync8(c2).isDirectory())
|
|
52169
52894
|
return c2;
|
|
52170
52895
|
}
|
|
52171
52896
|
return null;
|
|
@@ -52207,10 +52932,13 @@ var ROOT_REDIRECT_HTML = `<!DOCTYPE html>
|
|
|
52207
52932
|
</html>`;
|
|
52208
52933
|
|
|
52209
52934
|
// src/web/server.ts
|
|
52935
|
+
init_meta();
|
|
52936
|
+
init_cli_core();
|
|
52937
|
+
init_config();
|
|
52210
52938
|
function buildApp(ctx = buildWebContext()) {
|
|
52211
52939
|
const app = new Hono2;
|
|
52212
52940
|
if (true) {
|
|
52213
|
-
app.use(logger());
|
|
52941
|
+
app.use(logger((message, ...rest) => console.log(`${localTimestamp()} ${message}`, ...rest)));
|
|
52214
52942
|
}
|
|
52215
52943
|
registerMetaRoutes(app, ctx);
|
|
52216
52944
|
if (ctx) {
|
|
@@ -52246,18 +52974,52 @@ function buildApp(ctx = buildWebContext()) {
|
|
|
52246
52974
|
root: spaDist,
|
|
52247
52975
|
rewriteRequestPath: (path) => path.replace(/^\/app/, "") || "/"
|
|
52248
52976
|
}));
|
|
52249
|
-
const indexPath =
|
|
52250
|
-
if (
|
|
52251
|
-
const indexHtml =
|
|
52977
|
+
const indexPath = join15(spaDist, "index.html");
|
|
52978
|
+
if (existsSync15(indexPath)) {
|
|
52979
|
+
const indexHtml = readFileSync14(indexPath, "utf8");
|
|
52252
52980
|
app.get("/app/*", (c2) => c2.html(indexHtml));
|
|
52253
52981
|
}
|
|
52254
52982
|
}
|
|
52255
52983
|
app.get("/", (c2) => c2.html(ROOT_REDIRECT_HTML));
|
|
52256
52984
|
return app;
|
|
52257
52985
|
}
|
|
52986
|
+
|
|
52987
|
+
class CompatibilityError extends Error {
|
|
52988
|
+
}
|
|
52989
|
+
async function assertServerCompatible() {
|
|
52990
|
+
const settings = loadSettings();
|
|
52991
|
+
if (!settings.supabaseUrl || !settings.supabaseAnonKey)
|
|
52992
|
+
return;
|
|
52993
|
+
let compat2;
|
|
52994
|
+
try {
|
|
52995
|
+
compat2 = await checkServerCompatibility({
|
|
52996
|
+
aggregatorUrl: aggregatorUrlFor(settings.supabaseUrl),
|
|
52997
|
+
bearer: settings.supabaseAnonKey,
|
|
52998
|
+
bundledEf: PKG_VERSION
|
|
52999
|
+
});
|
|
53000
|
+
} catch {
|
|
53001
|
+
return;
|
|
53002
|
+
}
|
|
53003
|
+
if (!compat2.blocking)
|
|
53004
|
+
return;
|
|
53005
|
+
const parts = [];
|
|
53006
|
+
if (compat2.schema.level === "below-min") {
|
|
53007
|
+
parts.push(` • schema v${compat2.schema.deployed} is below the required v${compat2.schema.min}`);
|
|
53008
|
+
}
|
|
53009
|
+
if (compat2.edgeFunctions.level === "below-min") {
|
|
53010
|
+
parts.push(` • Edge Functions v${compat2.edgeFunctions.deployed} are below the required v${compat2.edgeFunctions.min}`);
|
|
53011
|
+
}
|
|
53012
|
+
throw new CompatibilityError(`Refusing to start: the deployed Cerefox server is incompatible with this client (v${PKG_VERSION}).
|
|
53013
|
+
` + parts.join(`
|
|
53014
|
+
`) + `
|
|
53015
|
+
|
|
53016
|
+
Redeploy your server: cerefox deploy-server
|
|
53017
|
+
` + `(or downgrade the client to match the deployed server).`);
|
|
53018
|
+
}
|
|
52258
53019
|
async function buildWebServer(options = {}) {
|
|
52259
53020
|
const host = options.host ?? "127.0.0.1";
|
|
52260
53021
|
const port = options.port ?? 8000;
|
|
53022
|
+
await assertServerCompatible();
|
|
52261
53023
|
const app = buildApp();
|
|
52262
53024
|
const server = serve({ fetch: app.fetch, hostname: host, port });
|
|
52263
53025
|
return {
|
|
@@ -52269,31 +53031,263 @@ async function buildWebServer(options = {}) {
|
|
|
52269
53031
|
};
|
|
52270
53032
|
}
|
|
52271
53033
|
|
|
53034
|
+
// src/web/daemon.ts
|
|
53035
|
+
import { spawn } from "node:child_process";
|
|
53036
|
+
import {
|
|
53037
|
+
existsSync as existsSync16,
|
|
53038
|
+
mkdirSync as mkdirSync4,
|
|
53039
|
+
openSync,
|
|
53040
|
+
readFileSync as readFileSync15,
|
|
53041
|
+
rmSync,
|
|
53042
|
+
writeFileSync as writeFileSync4
|
|
53043
|
+
} from "node:fs";
|
|
53044
|
+
import { homedir as homedir7 } from "node:os";
|
|
53045
|
+
import { join as join16 } from "node:path";
|
|
53046
|
+
var STATE_DIR = join16(homedir7(), ".cerefox");
|
|
53047
|
+
var PID_FILE = join16(STATE_DIR, "web.pid");
|
|
53048
|
+
var LOG_FILE = join16(STATE_DIR, "web.log");
|
|
53049
|
+
var daemonPaths = { stateDir: STATE_DIR, pidFile: PID_FILE, logFile: LOG_FILE };
|
|
53050
|
+
function ensureStateDir() {
|
|
53051
|
+
if (!existsSync16(STATE_DIR))
|
|
53052
|
+
mkdirSync4(STATE_DIR, { recursive: true });
|
|
53053
|
+
}
|
|
53054
|
+
function readPidFile() {
|
|
53055
|
+
if (!existsSync16(PID_FILE))
|
|
53056
|
+
return null;
|
|
53057
|
+
try {
|
|
53058
|
+
const parsed = JSON.parse(readFileSync15(PID_FILE, "utf8"));
|
|
53059
|
+
if (typeof parsed.pid !== "number")
|
|
53060
|
+
return null;
|
|
53061
|
+
return {
|
|
53062
|
+
pid: parsed.pid,
|
|
53063
|
+
port: typeof parsed.port === "number" ? parsed.port : 8000,
|
|
53064
|
+
host: typeof parsed.host === "string" ? parsed.host : "127.0.0.1",
|
|
53065
|
+
startedAt: typeof parsed.startedAt === "string" ? parsed.startedAt : "unknown"
|
|
53066
|
+
};
|
|
53067
|
+
} catch {
|
|
53068
|
+
return null;
|
|
53069
|
+
}
|
|
53070
|
+
}
|
|
53071
|
+
function writePidFile(info3) {
|
|
53072
|
+
ensureStateDir();
|
|
53073
|
+
writeFileSync4(PID_FILE, JSON.stringify(info3, null, 2) + `
|
|
53074
|
+
`, "utf8");
|
|
53075
|
+
}
|
|
53076
|
+
function removePidFile() {
|
|
53077
|
+
rmSync(PID_FILE, { force: true });
|
|
53078
|
+
}
|
|
53079
|
+
function isProcessAlive(pid) {
|
|
53080
|
+
try {
|
|
53081
|
+
process.kill(pid, 0);
|
|
53082
|
+
return true;
|
|
53083
|
+
} catch (err) {
|
|
53084
|
+
return err.code === "EPERM";
|
|
53085
|
+
}
|
|
53086
|
+
}
|
|
53087
|
+
async function isResponding(host, port, timeoutMs = 1500) {
|
|
53088
|
+
const probeHost = host === "0.0.0.0" ? "127.0.0.1" : host;
|
|
53089
|
+
try {
|
|
53090
|
+
const ctrl = new AbortController;
|
|
53091
|
+
const timer2 = setTimeout(() => ctrl.abort(), timeoutMs);
|
|
53092
|
+
try {
|
|
53093
|
+
const resp = await fetch(`http://${probeHost}:${port}/api/v1/version`, {
|
|
53094
|
+
signal: ctrl.signal
|
|
53095
|
+
});
|
|
53096
|
+
return resp.ok;
|
|
53097
|
+
} finally {
|
|
53098
|
+
clearTimeout(timer2);
|
|
53099
|
+
}
|
|
53100
|
+
} catch {
|
|
53101
|
+
return false;
|
|
53102
|
+
}
|
|
53103
|
+
}
|
|
53104
|
+
var sleep2 = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
53105
|
+
function assertUnix() {
|
|
53106
|
+
if (process.platform === "win32") {
|
|
53107
|
+
throw new Error("Daemon mode (`cerefox web start/stop/status`) is not supported on Windows yet. " + "Run `cerefox web` in the foreground, or set up a Windows service manually.");
|
|
53108
|
+
}
|
|
53109
|
+
}
|
|
53110
|
+
async function startDaemon(opts) {
|
|
53111
|
+
assertUnix();
|
|
53112
|
+
ensureStateDir();
|
|
53113
|
+
const existing = readPidFile();
|
|
53114
|
+
if (existing && isProcessAlive(existing.pid)) {
|
|
53115
|
+
return existing.port === opts.port ? { kind: "already-running", info: existing } : { kind: "port-conflict", info: existing };
|
|
53116
|
+
}
|
|
53117
|
+
if (existing)
|
|
53118
|
+
removePidFile();
|
|
53119
|
+
const logFd = openSync(LOG_FILE, "a");
|
|
53120
|
+
const child = spawn(opts.runtime, [opts.scriptPath, "web", "--host", opts.host, "--port", String(opts.port)], { detached: true, stdio: ["ignore", logFd, logFd] });
|
|
53121
|
+
child.unref();
|
|
53122
|
+
if (typeof child.pid !== "number") {
|
|
53123
|
+
throw new Error("Failed to spawn the web server process (no pid).");
|
|
53124
|
+
}
|
|
53125
|
+
writePidFile({
|
|
53126
|
+
pid: child.pid,
|
|
53127
|
+
port: opts.port,
|
|
53128
|
+
host: opts.host,
|
|
53129
|
+
startedAt: new Date().toISOString()
|
|
53130
|
+
});
|
|
53131
|
+
let responding = false;
|
|
53132
|
+
for (let i = 0;i < 20; i++) {
|
|
53133
|
+
if (!isProcessAlive(child.pid))
|
|
53134
|
+
break;
|
|
53135
|
+
if (await isResponding(opts.host, opts.port)) {
|
|
53136
|
+
responding = true;
|
|
53137
|
+
break;
|
|
53138
|
+
}
|
|
53139
|
+
await sleep2(250);
|
|
53140
|
+
}
|
|
53141
|
+
return { kind: "started", pid: child.pid, responding };
|
|
53142
|
+
}
|
|
53143
|
+
async function stopDaemon() {
|
|
53144
|
+
assertUnix();
|
|
53145
|
+
const info3 = readPidFile();
|
|
53146
|
+
if (!info3 || !isProcessAlive(info3.pid)) {
|
|
53147
|
+
removePidFile();
|
|
53148
|
+
return { kind: "not-running" };
|
|
53149
|
+
}
|
|
53150
|
+
try {
|
|
53151
|
+
process.kill(info3.pid, "SIGTERM");
|
|
53152
|
+
} catch {}
|
|
53153
|
+
let forced = false;
|
|
53154
|
+
let alive = true;
|
|
53155
|
+
for (let i = 0;i < 12; i++) {
|
|
53156
|
+
await sleep2(250);
|
|
53157
|
+
if (!isProcessAlive(info3.pid)) {
|
|
53158
|
+
alive = false;
|
|
53159
|
+
break;
|
|
53160
|
+
}
|
|
53161
|
+
}
|
|
53162
|
+
if (alive) {
|
|
53163
|
+
try {
|
|
53164
|
+
process.kill(info3.pid, "SIGKILL");
|
|
53165
|
+
forced = true;
|
|
53166
|
+
} catch {}
|
|
53167
|
+
}
|
|
53168
|
+
removePidFile();
|
|
53169
|
+
return { kind: "stopped", pid: info3.pid, forced };
|
|
53170
|
+
}
|
|
53171
|
+
async function statusDaemon() {
|
|
53172
|
+
const info3 = readPidFile();
|
|
53173
|
+
if (!info3)
|
|
53174
|
+
return { kind: "stopped" };
|
|
53175
|
+
if (!isProcessAlive(info3.pid))
|
|
53176
|
+
return { kind: "stale", info: info3 };
|
|
53177
|
+
const responding = await isResponding(info3.host, info3.port);
|
|
53178
|
+
return { kind: "running", info: info3, responding };
|
|
53179
|
+
}
|
|
53180
|
+
|
|
52272
53181
|
// src/cli/commands/web.ts
|
|
53182
|
+
function parsePort(raw2) {
|
|
53183
|
+
const port = Number.parseInt(raw2, 10);
|
|
53184
|
+
if (!Number.isFinite(port) || port < 1 || port > 65535) {
|
|
53185
|
+
eprintln(`Invalid --port: ${raw2}`);
|
|
53186
|
+
process.exit(2);
|
|
53187
|
+
}
|
|
53188
|
+
return port;
|
|
53189
|
+
}
|
|
53190
|
+
async function runForeground(host, port, watch) {
|
|
53191
|
+
if (watch) {
|
|
53192
|
+
info("--watch is reserved; not yet implemented.");
|
|
53193
|
+
}
|
|
53194
|
+
try {
|
|
53195
|
+
const handle = await buildWebServer({ host, port });
|
|
53196
|
+
println(`${localTimestamp()} Cerefox web listening on http://${handle.host}:${handle.port}/`);
|
|
53197
|
+
println(` Web UI: http://${handle.host}:${handle.port}/app/`);
|
|
53198
|
+
println(` API: http://${handle.host}:${handle.port}/api/v1/`);
|
|
53199
|
+
const shutdown = async (signal) => {
|
|
53200
|
+
println(`${localTimestamp()} Received ${signal}; shutting down.`);
|
|
53201
|
+
await handle.close().catch(() => {});
|
|
53202
|
+
process.exit(0);
|
|
53203
|
+
};
|
|
53204
|
+
process.on("SIGINT", () => void shutdown("SIGINT"));
|
|
53205
|
+
process.on("SIGTERM", () => void shutdown("SIGTERM"));
|
|
53206
|
+
} catch (err) {
|
|
53207
|
+
if (err instanceof CompatibilityError) {
|
|
53208
|
+
eprintln(err.message);
|
|
53209
|
+
} else {
|
|
53210
|
+
eprintln(`Failed to start web server: ${err instanceof Error ? err.message : String(err)}`);
|
|
53211
|
+
}
|
|
53212
|
+
process.exit(1);
|
|
53213
|
+
}
|
|
53214
|
+
}
|
|
52273
53215
|
function registerWeb(program2) {
|
|
52274
|
-
program2.command("web").description("Start the local web UI / API server.").option("--host <host>", "Bind host.", "127.0.0.1").option("--port <port>", "Bind port.", "8000").option("--watch", "Enable hot-reload (dev mode; reserved
|
|
52275
|
-
|
|
52276
|
-
|
|
52277
|
-
|
|
52278
|
-
|
|
53216
|
+
const web = program2.command("web").description("Start the local web UI / API server (foreground; see `web start` for daemon).").option("--host <host>", "Bind host.", "127.0.0.1").option("--port <port>", "Bind port.", "8000").option("--watch", "Enable hot-reload (dev mode; reserved).").action(async (rawOpts) => {
|
|
53217
|
+
await runForeground(rawOpts.host, parsePort(rawOpts.port), rawOpts.watch);
|
|
53218
|
+
});
|
|
53219
|
+
web.command("start").description("Start the web server in the background (detached daemon).").option("--host <host>", "Bind host.", "127.0.0.1").option("--port <port>", "Bind port.", "8000").action(async (rawOpts) => {
|
|
53220
|
+
const port = parsePort(rawOpts.port);
|
|
53221
|
+
try {
|
|
53222
|
+
const outcome = await startDaemon({
|
|
53223
|
+
host: rawOpts.host,
|
|
53224
|
+
port,
|
|
53225
|
+
scriptPath: process.argv[1],
|
|
53226
|
+
runtime: process.execPath
|
|
53227
|
+
});
|
|
53228
|
+
switch (outcome.kind) {
|
|
53229
|
+
case "already-running":
|
|
53230
|
+
info(`Cerefox web is already running on :${outcome.info.port} (pid ${outcome.info.pid}).`);
|
|
53231
|
+
process.exit(0);
|
|
53232
|
+
break;
|
|
53233
|
+
case "port-conflict":
|
|
53234
|
+
eprintln(`A Cerefox web daemon is already running on :${outcome.info.port} (pid ${outcome.info.pid}).
|
|
53235
|
+
` + `Stop it first (\`cerefox web stop\`) or start on its port.`);
|
|
53236
|
+
process.exit(1);
|
|
53237
|
+
break;
|
|
53238
|
+
case "started":
|
|
53239
|
+
if (outcome.responding) {
|
|
53240
|
+
info(`Cerefox web started (pid ${outcome.pid}) on http://${rawOpts.host}:${port}/`);
|
|
53241
|
+
println(` Web UI: http://${rawOpts.host}:${port}/app/`);
|
|
53242
|
+
println(c.dim(` Logs: ${daemonPaths.logFile}`));
|
|
53243
|
+
println(c.dim(` Stop: cerefox web stop`));
|
|
53244
|
+
} else {
|
|
53245
|
+
eprintln(`Started (pid ${outcome.pid}) but it is not responding on :${port} yet.
|
|
53246
|
+
` + `Check the log for errors: ${daemonPaths.logFile}`);
|
|
53247
|
+
process.exit(1);
|
|
53248
|
+
}
|
|
53249
|
+
break;
|
|
53250
|
+
}
|
|
53251
|
+
} catch (err) {
|
|
53252
|
+
eprintln(err instanceof Error ? err.message : String(err));
|
|
53253
|
+
process.exit(1);
|
|
52279
53254
|
}
|
|
52280
|
-
|
|
52281
|
-
|
|
53255
|
+
});
|
|
53256
|
+
web.command("stop").description("Stop the background web server daemon.").action(async () => {
|
|
53257
|
+
try {
|
|
53258
|
+
const outcome = await stopDaemon();
|
|
53259
|
+
if (outcome.kind === "not-running") {
|
|
53260
|
+
info("No Cerefox web daemon is running.");
|
|
53261
|
+
} else {
|
|
53262
|
+
info(`Stopped Cerefox web (pid ${outcome.pid})${outcome.forced ? " — forced (SIGKILL)" : ""}.`);
|
|
53263
|
+
}
|
|
53264
|
+
} catch (err) {
|
|
53265
|
+
eprintln(err instanceof Error ? err.message : String(err));
|
|
53266
|
+
process.exit(1);
|
|
52282
53267
|
}
|
|
53268
|
+
});
|
|
53269
|
+
web.command("status").description("Show the background web server daemon status.").action(async () => {
|
|
52283
53270
|
try {
|
|
52284
|
-
const
|
|
52285
|
-
|
|
52286
|
-
|
|
52287
|
-
|
|
52288
|
-
|
|
52289
|
-
|
|
52290
|
-
|
|
52291
|
-
|
|
52292
|
-
|
|
52293
|
-
|
|
52294
|
-
|
|
53271
|
+
const status = await statusDaemon();
|
|
53272
|
+
switch (status.kind) {
|
|
53273
|
+
case "stopped":
|
|
53274
|
+
println("Cerefox web: stopped (no daemon running).");
|
|
53275
|
+
break;
|
|
53276
|
+
case "stale":
|
|
53277
|
+
println(c.yellow(`Cerefox web: stale pidfile — process ${status.info.pid} is not running.`));
|
|
53278
|
+
println(c.dim(` Clean up: cerefox web stop (removes ${daemonPaths.pidFile})`));
|
|
53279
|
+
break;
|
|
53280
|
+
case "running":
|
|
53281
|
+
if (status.responding) {
|
|
53282
|
+
println(c.green(`Cerefox web: running on :${status.info.port} (pid ${status.info.pid}, since ${status.info.startedAt}).`));
|
|
53283
|
+
} else {
|
|
53284
|
+
println(c.yellow(`Cerefox web: process ${status.info.pid} alive but not responding on :${status.info.port}.`));
|
|
53285
|
+
println(c.dim(` Check the log: ${daemonPaths.logFile}`));
|
|
53286
|
+
}
|
|
53287
|
+
break;
|
|
53288
|
+
}
|
|
52295
53289
|
} catch (err) {
|
|
52296
|
-
eprintln(
|
|
53290
|
+
eprintln(err instanceof Error ? err.message : String(err));
|
|
52297
53291
|
process.exit(1);
|
|
52298
53292
|
}
|
|
52299
53293
|
});
|
|
@@ -52305,9 +53299,9 @@ function buildProgram() {
|
|
|
52305
53299
|
Command groups (each row in the list above falls into one):
|
|
52306
53300
|
` + ` READS search · get-doc · list-docs · list-versions · list-projects
|
|
52307
53301
|
` + ` · list-metadata-keys · metadata-search · get-audit-log
|
|
52308
|
-
` + ` WRITES ingest · ingest-dir · delete-doc
|
|
53302
|
+
` + ` WRITES ingest · ingest-dir · delete-doc · delete-project
|
|
52309
53303
|
` + ` SERVERS mcp · web
|
|
52310
|
-
` + ` LIFECYCLE init · doctor · status · configure-agent · self-update · upgrade · sync-self-docs
|
|
53304
|
+
` + ` LIFECYCLE init · doctor · status · configure-agent · self-update · upgrade · sync-self-docs · deploy-server
|
|
52311
53305
|
` + ` OPS backup · restore · sync-docs · docs · reindex · config-get · config-set · completion
|
|
52312
53306
|
` + `
|
|
52313
53307
|
Exit codes:
|
|
@@ -52330,6 +53324,7 @@ Learn more:
|
|
|
52330
53324
|
registerIngest(program2);
|
|
52331
53325
|
registerIngestDir(program2);
|
|
52332
53326
|
registerDeleteDoc(program2);
|
|
53327
|
+
registerDeleteProject(program2);
|
|
52333
53328
|
registerMcp(program2);
|
|
52334
53329
|
registerWeb(program2);
|
|
52335
53330
|
registerInit(program2);
|
|
@@ -52338,6 +53333,7 @@ Learn more:
|
|
|
52338
53333
|
registerConfigureAgent(program2);
|
|
52339
53334
|
registerSelfUpdate(program2);
|
|
52340
53335
|
registerSyncSelfDocs(program2);
|
|
53336
|
+
registerDeployServer(program2);
|
|
52341
53337
|
registerBackup(program2);
|
|
52342
53338
|
registerRestore(program2);
|
|
52343
53339
|
registerSyncDocs(program2);
|
|
@@ -52351,7 +53347,7 @@ Learn more:
|
|
|
52351
53347
|
|
|
52352
53348
|
// src/bin/cerefox.ts
|
|
52353
53349
|
async function bareEntryPoint() {
|
|
52354
|
-
const { existsSync:
|
|
53350
|
+
const { existsSync: existsSync17 } = await import("node:fs");
|
|
52355
53351
|
const { resolveEnvFile: resolveEnvFile2 } = await Promise.resolve().then(() => (init_config(), exports_config));
|
|
52356
53352
|
const { c: c2, println: println2 } = await Promise.resolve().then(() => (init_cli_core(), exports_cli_core));
|
|
52357
53353
|
const { PKG_VERSION: PKG_VERSION2 } = await Promise.resolve().then(() => (init_meta(), exports_meta));
|
|
@@ -52360,7 +53356,7 @@ async function bareEntryPoint() {
|
|
|
52360
53356
|
println2("");
|
|
52361
53357
|
let configExists = false;
|
|
52362
53358
|
try {
|
|
52363
|
-
configExists =
|
|
53359
|
+
configExists = existsSync17(resolveEnvFile2());
|
|
52364
53360
|
} catch {}
|
|
52365
53361
|
if (!configExists) {
|
|
52366
53362
|
println2(c2.yellow("⚠ No config detected."));
|