@cerefox/memory 1.0.0-beta.2 → 1.0.0-beta.4
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/README.md +10 -9
- package/dist/bin/cerefox.js +695 -393
- package/dist/frontend/assets/index-6DS5ujj2.js +125 -0
- package/dist/frontend/assets/index-6DS5ujj2.js.map +1 -0
- package/dist/frontend/index.html +1 -1
- package/dist/server-assets/_shared/ef-meta/index.ts +1 -1
- package/dist/server-assets/_shared/embeddings/index.ts +51 -1
- package/dist/server-assets/_shared/embeddings/onnx-embedder.ts +229 -0
- package/dist/server-assets/_shared/mcp-tools/ingest.ts +16 -8
- package/dist/server-assets/_shared/mcp-tools/search.ts +3 -3
- package/dist/server-assets/db/rpcs.sql +5 -3
- package/dist/server-assets/db/schema.sql +1 -1
- package/dist/server-assets/supabase/functions/cerefox-ingest/index.ts +10 -0
- package/dist/server-assets/supabase/functions/cerefox-metadata-search/index.ts +3 -1
- package/dist/server-assets/supabase/functions/cerefox-search/index.ts +8 -1
- package/docs/guides/configuration.md +8 -3
- package/docs/guides/setup-local.md +34 -2
- package/package.json +6 -2
- package/dist/frontend/assets/index-D3FshoP3.js +0 -125
- package/dist/frontend/assets/index-D3FshoP3.js.map +0 -1
package/dist/bin/cerefox.js
CHANGED
|
@@ -7184,7 +7184,7 @@ var exports_meta = {};
|
|
|
7184
7184
|
__export(exports_meta, {
|
|
7185
7185
|
PKG_VERSION: () => PKG_VERSION
|
|
7186
7186
|
});
|
|
7187
|
-
var PKG_VERSION = "1.0.0-beta.
|
|
7187
|
+
var PKG_VERSION = "1.0.0-beta.4";
|
|
7188
7188
|
var init_meta = () => {};
|
|
7189
7189
|
|
|
7190
7190
|
// ../../node_modules/.bun/tslib@2.8.1/node_modules/tslib/tslib.js
|
|
@@ -22959,6 +22959,55 @@ var init_client = __esm(() => {
|
|
|
22959
22959
|
init_cli_core();
|
|
22960
22960
|
});
|
|
22961
22961
|
|
|
22962
|
+
// ../../_shared/server-assets/index.ts
|
|
22963
|
+
import { existsSync as existsSync5 } from "node:fs";
|
|
22964
|
+
import { dirname as dirname2, join as join5 } from "node:path";
|
|
22965
|
+
import { fileURLToPath } from "node:url";
|
|
22966
|
+
import { cwd as processCwd2 } from "node:process";
|
|
22967
|
+
function moduleDir() {
|
|
22968
|
+
return dirname2(fileURLToPath(import.meta.url));
|
|
22969
|
+
}
|
|
22970
|
+
function bundledServerAssets(serverAssetsRoot) {
|
|
22971
|
+
return {
|
|
22972
|
+
schemaFile: join5(serverAssetsRoot, "db", "schema.sql"),
|
|
22973
|
+
rpcsFile: join5(serverAssetsRoot, "db", "rpcs.sql"),
|
|
22974
|
+
migrationsDir: join5(serverAssetsRoot, "db", "migrations"),
|
|
22975
|
+
functionsDir: join5(serverAssetsRoot, "supabase", "functions"),
|
|
22976
|
+
layout: "bundled"
|
|
22977
|
+
};
|
|
22978
|
+
}
|
|
22979
|
+
function sourceServerAssets(repoRoot) {
|
|
22980
|
+
const dbDir = join5(repoRoot, "src", "cerefox", "db");
|
|
22981
|
+
return {
|
|
22982
|
+
schemaFile: join5(dbDir, "schema.sql"),
|
|
22983
|
+
rpcsFile: join5(dbDir, "rpcs.sql"),
|
|
22984
|
+
migrationsDir: join5(dbDir, "migrations"),
|
|
22985
|
+
functionsDir: join5(repoRoot, "supabase", "functions"),
|
|
22986
|
+
layout: "source"
|
|
22987
|
+
};
|
|
22988
|
+
}
|
|
22989
|
+
function serverAssetsUsable(p) {
|
|
22990
|
+
return existsSync5(p.schemaFile) && existsSync5(p.rpcsFile);
|
|
22991
|
+
}
|
|
22992
|
+
function resolveServerAssets(opts = {}) {
|
|
22993
|
+
if (opts.assetsDir) {
|
|
22994
|
+
return { ...bundledServerAssets(opts.assetsDir), layout: "explicit" };
|
|
22995
|
+
}
|
|
22996
|
+
const here = opts.moduleDirOverride ?? moduleDir();
|
|
22997
|
+
const cwd = opts.cwd ?? processCwd2();
|
|
22998
|
+
const candidates = [
|
|
22999
|
+
bundledServerAssets(join5(here, "..", "server-assets")),
|
|
23000
|
+
sourceServerAssets(join5(here, "..", "..")),
|
|
23001
|
+
sourceServerAssets(cwd)
|
|
23002
|
+
];
|
|
23003
|
+
for (const candidate of candidates) {
|
|
23004
|
+
if (serverAssetsUsable(candidate))
|
|
23005
|
+
return candidate;
|
|
23006
|
+
}
|
|
23007
|
+
return sourceServerAssets(join5(here, "..", ".."));
|
|
23008
|
+
}
|
|
23009
|
+
var init_server_assets = () => {};
|
|
23010
|
+
|
|
22962
23011
|
// ../../node_modules/.bun/postgres@3.4.9/node_modules/postgres/src/query.js
|
|
22963
23012
|
function cachedError(xs) {
|
|
22964
23013
|
if (originCache.has(xs))
|
|
@@ -25193,127 +25242,296 @@ var init_bundled_docs = __esm(() => {
|
|
|
25193
25242
|
PACKAGE_ROOT = findPackageRoot();
|
|
25194
25243
|
});
|
|
25195
25244
|
|
|
25196
|
-
// ../../_shared/
|
|
25197
|
-
function
|
|
25198
|
-
|
|
25199
|
-
|
|
25200
|
-
|
|
25201
|
-
|
|
25245
|
+
// ../../_shared/compatibility/index.ts
|
|
25246
|
+
function compareSemver(a, b2) {
|
|
25247
|
+
const norm = (v) => v.split(/[.-]/).slice(0, 3).map((p) => Number.parseInt(p, 10)).map((n) => Number.isFinite(n) ? n : 0);
|
|
25248
|
+
const pa = norm(a);
|
|
25249
|
+
const pb = norm(b2);
|
|
25250
|
+
for (let i = 0;i < 3; i++) {
|
|
25251
|
+
const x = pa[i] ?? 0;
|
|
25252
|
+
const y = pb[i] ?? 0;
|
|
25253
|
+
if (x !== y)
|
|
25254
|
+
return x < y ? -1 : 1;
|
|
25255
|
+
}
|
|
25256
|
+
return 0;
|
|
25202
25257
|
}
|
|
25203
|
-
function
|
|
25204
|
-
|
|
25205
|
-
|
|
25206
|
-
|
|
25207
|
-
|
|
25258
|
+
function classifyCompat(deployed, min, bundled) {
|
|
25259
|
+
if (!deployed)
|
|
25260
|
+
return "unknown";
|
|
25261
|
+
if (compareSemver(deployed, min) < 0)
|
|
25262
|
+
return "below-min";
|
|
25263
|
+
if (bundled && compareSemver(deployed, bundled) < 0)
|
|
25264
|
+
return "above-min-but-old";
|
|
25265
|
+
return "ok";
|
|
25208
25266
|
}
|
|
25209
|
-
function
|
|
25210
|
-
const
|
|
25211
|
-
|
|
25212
|
-
let m;
|
|
25213
|
-
while ((m = re.exec(doc)) !== null) {
|
|
25214
|
-
out.push({ offset: m.index, level: m[1].length, text: rstripHash(m[2]).trim() });
|
|
25215
|
-
}
|
|
25216
|
-
return out;
|
|
25267
|
+
function aggregatorUrlFor(supabaseUrl) {
|
|
25268
|
+
const base = supabaseUrl.replace(/\/$/, "");
|
|
25269
|
+
return `${base}/functions/v1/cerefox-mcp/version?peers=true`;
|
|
25217
25270
|
}
|
|
25218
|
-
function
|
|
25219
|
-
const
|
|
25220
|
-
|
|
25221
|
-
|
|
25222
|
-
|
|
25223
|
-
|
|
25224
|
-
|
|
25225
|
-
|
|
25271
|
+
async function checkServerCompatibility(opts) {
|
|
25272
|
+
const fetchImpl = opts.fetchImpl ?? fetch;
|
|
25273
|
+
const result = {
|
|
25274
|
+
schema: { deployed: null, min: COMPATIBILITY.minSchema, level: "unknown" },
|
|
25275
|
+
edgeFunctions: {
|
|
25276
|
+
deployed: null,
|
|
25277
|
+
min: COMPATIBILITY.minEdgeFunctions,
|
|
25278
|
+
level: "unknown",
|
|
25279
|
+
errors: []
|
|
25280
|
+
},
|
|
25281
|
+
blocking: false,
|
|
25282
|
+
efProbeSkipped: false
|
|
25283
|
+
};
|
|
25284
|
+
if (!opts.bearer) {
|
|
25285
|
+
result.efProbeSkipped = true;
|
|
25286
|
+
result.efSkipReason = "No CEREFOX_ACCESS_TOKEN configured; Edge Function version check skipped.";
|
|
25287
|
+
return result;
|
|
25226
25288
|
}
|
|
25227
|
-
|
|
25228
|
-
|
|
25229
|
-
|
|
25230
|
-
|
|
25231
|
-
|
|
25232
|
-
|
|
25233
|
-
|
|
25234
|
-
|
|
25235
|
-
|
|
25236
|
-
|
|
25237
|
-
|
|
25289
|
+
let agg = null;
|
|
25290
|
+
try {
|
|
25291
|
+
const ctrl = new AbortController;
|
|
25292
|
+
const timer2 = setTimeout(() => ctrl.abort(), opts.timeoutMs ?? 6000);
|
|
25293
|
+
try {
|
|
25294
|
+
const resp = await fetchImpl(opts.aggregatorUrl, {
|
|
25295
|
+
method: "GET",
|
|
25296
|
+
headers: { Authorization: `Bearer ${opts.bearer}`, apikey: opts.bearer },
|
|
25297
|
+
signal: ctrl.signal
|
|
25298
|
+
});
|
|
25299
|
+
if (resp.ok) {
|
|
25300
|
+
agg = await resp.json();
|
|
25301
|
+
} else {
|
|
25302
|
+
result.efProbeSkipped = true;
|
|
25303
|
+
result.efSkipReason = resp.status === 404 || resp.status === 405 ? "Edge Functions predate v0.8 (no /version route). Redeploy with `cerefox server deploy --functions-only` to enable version checks." : `Aggregator returned HTTP ${resp.status}; Edge Function version check skipped.`;
|
|
25304
|
+
}
|
|
25305
|
+
} finally {
|
|
25306
|
+
clearTimeout(timer2);
|
|
25238
25307
|
}
|
|
25239
|
-
|
|
25240
|
-
|
|
25308
|
+
} catch (err) {
|
|
25309
|
+
result.efProbeSkipped = true;
|
|
25310
|
+
result.efSkipReason = `Could not reach the version aggregator: ${err instanceof Error ? err.message : String(err)}`;
|
|
25241
25311
|
}
|
|
25242
|
-
if (
|
|
25243
|
-
|
|
25312
|
+
if (!agg)
|
|
25313
|
+
return result;
|
|
25314
|
+
result.schema.deployed = agg.schema ?? null;
|
|
25315
|
+
result.schema.level = classifyCompat(result.schema.deployed, COMPATIBILITY.minSchema, opts.bundledSchema);
|
|
25316
|
+
const versions = [];
|
|
25317
|
+
if (agg.version)
|
|
25318
|
+
versions.push(agg.version);
|
|
25319
|
+
for (const ef of agg.efs ?? [])
|
|
25320
|
+
versions.push(ef.version);
|
|
25321
|
+
result.edgeFunctions.errors = agg.errors ?? [];
|
|
25322
|
+
if (versions.length > 0) {
|
|
25323
|
+
const weakest = versions.reduce((lo, v) => compareSemver(v, lo) < 0 ? v : lo);
|
|
25324
|
+
result.edgeFunctions.deployed = weakest;
|
|
25325
|
+
result.edgeFunctions.level = classifyCompat(weakest, COMPATIBILITY.minEdgeFunctions, opts.bundledEf);
|
|
25326
|
+
} else {
|
|
25327
|
+
result.edgeFunctions.level = "unknown";
|
|
25328
|
+
result.efProbeSkipped = true;
|
|
25329
|
+
result.efSkipReason = "Aggregator reported no Edge Function versions; check skipped.";
|
|
25330
|
+
}
|
|
25331
|
+
result.blocking = result.schema.level === "below-min" || result.edgeFunctions.level === "below-min";
|
|
25332
|
+
return result;
|
|
25333
|
+
}
|
|
25334
|
+
var COMPATIBILITY;
|
|
25335
|
+
var init_compatibility = __esm(() => {
|
|
25336
|
+
COMPATIBILITY = {
|
|
25337
|
+
minSchema: "0.3.1",
|
|
25338
|
+
minEdgeFunctions: "0.6.0"
|
|
25339
|
+
};
|
|
25340
|
+
});
|
|
25341
|
+
|
|
25342
|
+
// ../../_shared/embeddings/onnx-embedder.ts
|
|
25343
|
+
var exports_onnx_embedder = {};
|
|
25344
|
+
__export(exports_onnx_embedder, {
|
|
25345
|
+
warmup: () => warmup,
|
|
25346
|
+
onnxEmbed: () => onnxEmbed,
|
|
25347
|
+
nomicPrefix: () => nomicPrefix,
|
|
25348
|
+
buildPrefixedInputs: () => buildPrefixedInputs,
|
|
25349
|
+
ONNX_MODEL_NAME: () => ONNX_MODEL_NAME,
|
|
25350
|
+
ONNX_MODEL_ID: () => ONNX_MODEL_ID,
|
|
25351
|
+
ONNX_MODEL_DTYPE: () => ONNX_MODEL_DTYPE,
|
|
25352
|
+
ONNX_MODEL_DIM: () => ONNX_MODEL_DIM,
|
|
25353
|
+
ONNX_MODEL_APPROX_MB: () => ONNX_MODEL_APPROX_MB
|
|
25354
|
+
});
|
|
25355
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync3 } from "node:fs";
|
|
25356
|
+
import { homedir as homedir5 } from "node:os";
|
|
25357
|
+
import { join as join8 } from "node:path";
|
|
25358
|
+
function nomicPrefix(role) {
|
|
25359
|
+
return role === "query" ? "search_query: " : "search_document: ";
|
|
25360
|
+
}
|
|
25361
|
+
function buildPrefixedInputs(texts, role) {
|
|
25362
|
+
const p = nomicPrefix(role);
|
|
25363
|
+
return texts.map((t) => p + t);
|
|
25364
|
+
}
|
|
25365
|
+
function getCacheDir() {
|
|
25366
|
+
const env4 = globalThis.process?.env ?? {};
|
|
25367
|
+
if (env4.CEREFOX_MODELS_DIR)
|
|
25368
|
+
return env4.CEREFOX_MODELS_DIR;
|
|
25369
|
+
return join8(homedir5(), ".cerefox", "models");
|
|
25370
|
+
}
|
|
25371
|
+
async function loadTransformers() {
|
|
25372
|
+
if (transformersModule)
|
|
25373
|
+
return transformersModule;
|
|
25374
|
+
const spec = "@huggingface/transformers";
|
|
25375
|
+
transformersModule = await import(spec);
|
|
25376
|
+
const dir = getCacheDir();
|
|
25377
|
+
if (!existsSync9(dir))
|
|
25378
|
+
mkdirSync3(dir, { recursive: true });
|
|
25379
|
+
transformersModule.env.cacheDir = dir;
|
|
25380
|
+
transformersModule.env.allowLocalModels = true;
|
|
25381
|
+
transformersModule.env.allowRemoteModels = true;
|
|
25382
|
+
return transformersModule;
|
|
25383
|
+
}
|
|
25384
|
+
function makeBar(pct, width = 20) {
|
|
25385
|
+
const clamped = Math.max(0, Math.min(100, pct));
|
|
25386
|
+
const filled = Math.round(clamped / 100 * width);
|
|
25387
|
+
return `[${"█".repeat(filled)}${"░".repeat(width - filled)}]`;
|
|
25388
|
+
}
|
|
25389
|
+
function l2Normalise(v) {
|
|
25390
|
+
let sum = 0;
|
|
25391
|
+
for (let i = 0;i < v.length; i++)
|
|
25392
|
+
sum += v[i] * v[i];
|
|
25393
|
+
const norm = Math.sqrt(sum);
|
|
25394
|
+
if (norm === 0)
|
|
25395
|
+
return v;
|
|
25396
|
+
const out = new Float32Array(v.length);
|
|
25397
|
+
for (let i = 0;i < v.length; i++)
|
|
25398
|
+
out[i] = v[i] / norm;
|
|
25244
25399
|
return out;
|
|
25245
25400
|
}
|
|
25246
|
-
function
|
|
25247
|
-
|
|
25248
|
-
|
|
25401
|
+
async function ensurePipeline() {
|
|
25402
|
+
if (pipelinePromise)
|
|
25403
|
+
return pipelinePromise;
|
|
25404
|
+
pipelinePromise = (async () => {
|
|
25405
|
+
const transformers = await loadTransformers();
|
|
25406
|
+
const mb = ONNX_MODEL_APPROX_MB;
|
|
25407
|
+
const fmt = (s) => s < 60 ? `${s}s` : `${Math.round(s / 60)}m`;
|
|
25408
|
+
process.stderr.write(`[cerefox-embed] loading "${ONNX_MODEL_NAME}" from HuggingFace (~${mb} MB; est. ${fmt(Math.round(mb * 8 / 50))}-${fmt(Math.round(mb * 8 / 10))} at 50-10 Mbps; first-run only)…
|
|
25409
|
+
`);
|
|
25410
|
+
const progressState = new Map;
|
|
25411
|
+
let activeFile = null;
|
|
25412
|
+
const isTty = !!process.stderr.isTTY;
|
|
25413
|
+
const RENDER_INTERVAL_MS = 250;
|
|
25414
|
+
const fmtMb = (n) => (n / 1024 / 1024).toFixed(1);
|
|
25415
|
+
const renderInPlace = (line) => {
|
|
25416
|
+
if (isTty)
|
|
25417
|
+
process.stderr.write(`\r\x1B[K${line}`);
|
|
25418
|
+
else
|
|
25419
|
+
process.stderr.write(`${line}
|
|
25420
|
+
`);
|
|
25421
|
+
};
|
|
25422
|
+
const finalizeLine = () => {
|
|
25423
|
+
if (isTty && activeFile !== null)
|
|
25424
|
+
process.stderr.write(`
|
|
25425
|
+
`);
|
|
25426
|
+
activeFile = null;
|
|
25427
|
+
};
|
|
25428
|
+
const progressCallback = (info3) => {
|
|
25429
|
+
const file = info3.file ?? info3.name ?? "(unknown)";
|
|
25430
|
+
const now = Date.now();
|
|
25431
|
+
if (info3.status === "progress") {
|
|
25432
|
+
const total = info3.total ?? 0;
|
|
25433
|
+
const loaded = info3.loaded ?? 0;
|
|
25434
|
+
if (total === 0 && loaded === 0)
|
|
25435
|
+
return;
|
|
25436
|
+
const prior = progressState.get(file) ?? {
|
|
25437
|
+
loaded: 0,
|
|
25438
|
+
total: 0,
|
|
25439
|
+
done: false,
|
|
25440
|
+
indeterminate: false,
|
|
25441
|
+
lastRenderAt: 0,
|
|
25442
|
+
lastRenderedPct: -1
|
|
25443
|
+
};
|
|
25444
|
+
const indeterminate = prior.indeterminate || prior.total > 0 && total > prior.total;
|
|
25445
|
+
const next = {
|
|
25446
|
+
loaded,
|
|
25447
|
+
total,
|
|
25448
|
+
done: false,
|
|
25449
|
+
indeterminate,
|
|
25450
|
+
lastRenderAt: prior.lastRenderAt,
|
|
25451
|
+
lastRenderedPct: prior.lastRenderedPct
|
|
25452
|
+
};
|
|
25453
|
+
if (activeFile !== file) {
|
|
25454
|
+
finalizeLine();
|
|
25455
|
+
activeFile = file;
|
|
25456
|
+
}
|
|
25457
|
+
if (indeterminate) {
|
|
25458
|
+
if (now - prior.lastRenderAt >= RENDER_INTERVAL_MS) {
|
|
25459
|
+
renderInPlace(`[cerefox-embed] [streaming...] ${fmtMb(loaded)} MB ${file}`);
|
|
25460
|
+
next.lastRenderAt = now;
|
|
25461
|
+
}
|
|
25462
|
+
} else if (total > 0) {
|
|
25463
|
+
const pct = Math.floor(loaded / total * 100);
|
|
25464
|
+
const stepBumped = pct >= prior.lastRenderedPct + 5;
|
|
25465
|
+
const timeBumped = isTty && now - prior.lastRenderAt >= RENDER_INTERVAL_MS && pct !== prior.lastRenderedPct;
|
|
25466
|
+
if (stepBumped || timeBumped) {
|
|
25467
|
+
renderInPlace(`[cerefox-embed] ${makeBar(pct)} ${pct.toString().padStart(3)}% ${fmtMb(loaded)}/${fmtMb(total)} MB ${file}`);
|
|
25468
|
+
next.lastRenderedPct = pct;
|
|
25469
|
+
next.lastRenderAt = now;
|
|
25470
|
+
}
|
|
25471
|
+
}
|
|
25472
|
+
progressState.set(file, next);
|
|
25473
|
+
} else if (info3.status === "done") {
|
|
25474
|
+
const prior = progressState.get(file);
|
|
25475
|
+
finalizeLine();
|
|
25476
|
+
const finalSize = prior && prior.loaded > 0 ? `${fmtMb(prior.loaded)} MB` : info3.total && info3.total > 0 ? `${fmtMb(info3.total)} MB` : "cached";
|
|
25477
|
+
process.stderr.write(`[cerefox-embed] ✓ ${file} (${finalSize})
|
|
25478
|
+
`);
|
|
25479
|
+
if (prior)
|
|
25480
|
+
progressState.set(file, { ...prior, done: true });
|
|
25481
|
+
}
|
|
25482
|
+
};
|
|
25483
|
+
const pipe = await transformers.pipeline("feature-extraction", ONNX_MODEL_ID, {
|
|
25484
|
+
dtype: ONNX_MODEL_DTYPE,
|
|
25485
|
+
progress_callback: progressCallback
|
|
25486
|
+
});
|
|
25487
|
+
process.stderr.write(`[cerefox-embed] embedder ready.
|
|
25488
|
+
`);
|
|
25489
|
+
return pipe;
|
|
25490
|
+
})();
|
|
25491
|
+
pipelinePromise.catch(() => {
|
|
25492
|
+
pipelinePromise = null;
|
|
25493
|
+
});
|
|
25494
|
+
return pipelinePromise;
|
|
25495
|
+
}
|
|
25496
|
+
async function warmup() {
|
|
25497
|
+
await ensurePipeline();
|
|
25498
|
+
}
|
|
25499
|
+
async function onnxEmbed(texts, role) {
|
|
25500
|
+
if (texts.length === 0)
|
|
25249
25501
|
return [];
|
|
25250
|
-
|
|
25251
|
-
|
|
25252
|
-
|
|
25253
|
-
|
|
25502
|
+
const pipeline = await ensurePipeline();
|
|
25503
|
+
const inputs = buildPrefixedInputs(texts, role);
|
|
25504
|
+
const out = await pipeline(inputs, { pooling: "mean", normalize: true });
|
|
25505
|
+
const dim2 = out.dims[out.dims.length - 1];
|
|
25506
|
+
if (dim2 !== ONNX_MODEL_DIM) {
|
|
25507
|
+
throw new Error(`OnnxEmbedder: expected dim=${ONNX_MODEL_DIM} (schema vector(768)), got ${dim2} from model`);
|
|
25254
25508
|
}
|
|
25255
|
-
const
|
|
25256
|
-
|
|
25257
|
-
|
|
25258
|
-
|
|
25259
|
-
const unit = (parts[i] ?? "") + (parts[i + 1] ?? "");
|
|
25260
|
-
if (unit === "")
|
|
25261
|
-
continue;
|
|
25262
|
-
if (cpLen(unit) > maxChunkChars)
|
|
25263
|
-
atoms.push(...hardSplitCp(unit, maxChunkChars));
|
|
25264
|
-
else
|
|
25265
|
-
atoms.push(unit);
|
|
25509
|
+
const vectors = [];
|
|
25510
|
+
for (let i = 0;i < inputs.length; i++) {
|
|
25511
|
+
const slice = out.data.slice(i * dim2, (i + 1) * dim2);
|
|
25512
|
+
vectors.push(Array.from(l2Normalise(slice)));
|
|
25266
25513
|
}
|
|
25267
|
-
|
|
25268
|
-
let buf = "";
|
|
25269
|
-
let bufCp = 0;
|
|
25270
|
-
let bufStart = 0;
|
|
25271
|
-
let offset = 0;
|
|
25272
|
-
const flush = () => {
|
|
25273
|
-
if (buf === "")
|
|
25274
|
-
return;
|
|
25275
|
-
const stack = activeHeadings(headings, bufStart);
|
|
25276
|
-
chunks.push({
|
|
25277
|
-
chunk_index: chunks.length,
|
|
25278
|
-
heading_path: stack.map((h) => h.text),
|
|
25279
|
-
heading_level: stack.length ? stack[stack.length - 1].level : 0,
|
|
25280
|
-
title: stack.length ? stack[stack.length - 1].text : "",
|
|
25281
|
-
content: buf,
|
|
25282
|
-
char_count: bufCp
|
|
25283
|
-
});
|
|
25284
|
-
buf = "";
|
|
25285
|
-
bufCp = 0;
|
|
25286
|
-
};
|
|
25287
|
-
for (const atom of atoms) {
|
|
25288
|
-
const cp = cpLen(atom);
|
|
25289
|
-
if (buf === "") {
|
|
25290
|
-
bufStart = offset;
|
|
25291
|
-
buf = atom;
|
|
25292
|
-
bufCp = cp;
|
|
25293
|
-
} else if (bufCp + cp <= maxChunkChars) {
|
|
25294
|
-
buf += atom;
|
|
25295
|
-
bufCp += cp;
|
|
25296
|
-
} else {
|
|
25297
|
-
flush();
|
|
25298
|
-
bufStart = offset;
|
|
25299
|
-
buf = atom;
|
|
25300
|
-
bufCp = cp;
|
|
25301
|
-
}
|
|
25302
|
-
offset += atom.length;
|
|
25303
|
-
}
|
|
25304
|
-
flush();
|
|
25305
|
-
return chunks;
|
|
25306
|
-
}
|
|
25307
|
-
function embeddingInputFor(docTitle, chunk) {
|
|
25308
|
-
const breadcrumb = chunk.heading_path.join(" > ");
|
|
25309
|
-
const head2 = breadcrumb ? `# ${docTitle}
|
|
25310
|
-
${breadcrumb}` : `# ${docTitle}`;
|
|
25311
|
-
return `${head2}
|
|
25312
|
-
${chunk.content}`;
|
|
25514
|
+
return vectors;
|
|
25313
25515
|
}
|
|
25314
|
-
var
|
|
25516
|
+
var ONNX_MODEL_ID = "nomic-ai/nomic-embed-text-v1.5", ONNX_MODEL_NAME = "nomic-embed-text-v1.5", ONNX_MODEL_DTYPE = "q8", ONNX_MODEL_DIM = 768, ONNX_MODEL_APPROX_MB = 130, transformersModule = null, pipelinePromise = null;
|
|
25517
|
+
var init_onnx_embedder = () => {};
|
|
25315
25518
|
|
|
25316
25519
|
// ../../_shared/embeddings/index.ts
|
|
25520
|
+
var exports_embeddings = {};
|
|
25521
|
+
__export(exports_embeddings, {
|
|
25522
|
+
resolveEmbedderKind: () => resolveEmbedderKind,
|
|
25523
|
+
openaiEmbeddingConfig: () => openaiEmbeddingConfig,
|
|
25524
|
+
getEmbedding: () => getEmbedding,
|
|
25525
|
+
embeddingMaxInputChars: () => embeddingMaxInputChars,
|
|
25526
|
+
embedBatch: () => embedBatch,
|
|
25527
|
+
capEmbeddingInput: () => capEmbeddingInput,
|
|
25528
|
+
activeEmbedderName: () => activeEmbedderName,
|
|
25529
|
+
OPENAI_MODEL: () => OPENAI_MODEL,
|
|
25530
|
+
OPENAI_EMBEDDING_URL: () => OPENAI_EMBEDDING_URL,
|
|
25531
|
+
EMBEDDING_DIMENSIONS: () => EMBEDDING_DIMENSIONS,
|
|
25532
|
+
EMBEDDING_BATCH_SIZE: () => EMBEDDING_BATCH_SIZE,
|
|
25533
|
+
DEFAULT_EMBED_MAX_INPUT_CHARS: () => DEFAULT_EMBED_MAX_INPUT_CHARS
|
|
25534
|
+
});
|
|
25317
25535
|
function openaiEmbeddingConfig() {
|
|
25318
25536
|
const env4 = globalThis.process?.env ?? {};
|
|
25319
25537
|
const base = env4.CEREFOX_OPENAI_BASE_URL?.replace(/\/+$/, "");
|
|
@@ -25340,7 +25558,22 @@ function capEmbeddingInput(text) {
|
|
|
25340
25558
|
console.warn(`[embeddings] truncated an embedding input: ${text.length} → ${cut.length} chars ` + `(cap CEREFOX_EMBED_MAX_INPUT_CHARS=${max}). The full content is stored and reconstructed ` + `untouched; only this chunk's embedding uses the prefix (degraded search for this chunk).`);
|
|
25341
25559
|
return cut;
|
|
25342
25560
|
}
|
|
25561
|
+
function resolveEmbedderKind() {
|
|
25562
|
+
const env4 = globalThis.process?.env ?? {};
|
|
25563
|
+
return env4.CEREFOX_EMBEDDER === "local" ? "local" : "openai";
|
|
25564
|
+
}
|
|
25565
|
+
function activeEmbedderName() {
|
|
25566
|
+
return resolveEmbedderKind() === "local" ? "nomic-embed-text-v1.5" : openaiEmbeddingConfig().model;
|
|
25567
|
+
}
|
|
25568
|
+
async function onnxModule() {
|
|
25569
|
+
return await Promise.resolve().then(() => (init_onnx_embedder(), exports_onnx_embedder));
|
|
25570
|
+
}
|
|
25343
25571
|
async function getEmbedding(text, apiKey) {
|
|
25572
|
+
if (resolveEmbedderKind() === "local") {
|
|
25573
|
+
const onnx = await onnxModule();
|
|
25574
|
+
const [vec] = await onnx.onnxEmbed([capEmbeddingInput(text)], "query");
|
|
25575
|
+
return vec;
|
|
25576
|
+
}
|
|
25344
25577
|
let lastError = null;
|
|
25345
25578
|
const cfg = openaiEmbeddingConfig();
|
|
25346
25579
|
const input = capEmbeddingInput(text);
|
|
@@ -25432,6 +25665,10 @@ async function embedBatchSingleCall(texts, apiKey) {
|
|
|
25432
25665
|
async function embedBatch(texts, apiKey, batchSize = EMBEDDING_BATCH_SIZE) {
|
|
25433
25666
|
if (texts.length === 0)
|
|
25434
25667
|
return [];
|
|
25668
|
+
if (resolveEmbedderKind() === "local") {
|
|
25669
|
+
const onnx = await onnxModule();
|
|
25670
|
+
return onnx.onnxEmbed(texts.map(capEmbeddingInput), "document");
|
|
25671
|
+
}
|
|
25435
25672
|
if (texts.length <= batchSize) {
|
|
25436
25673
|
return embedBatchSingleCall(texts, apiKey);
|
|
25437
25674
|
}
|
|
@@ -25446,6 +25683,126 @@ async function embedBatch(texts, apiKey, batchSize = EMBEDDING_BATCH_SIZE) {
|
|
|
25446
25683
|
}
|
|
25447
25684
|
var OPENAI_EMBEDDING_URL = "https://api.openai.com/v1/embeddings", OPENAI_MODEL = "text-embedding-3-small", EMBEDDING_DIMENSIONS = 768, DEFAULT_EMBED_MAX_INPUT_CHARS = 20000, EMBEDDING_MAX_RETRIES = 3, EMBEDDING_INITIAL_BACKOFF_MS = 500, EMBEDDING_BATCH_SIZE = 96;
|
|
25448
25685
|
|
|
25686
|
+
// ../../_shared/ingest/chunker.ts
|
|
25687
|
+
function cpLen(s) {
|
|
25688
|
+
let n = 0;
|
|
25689
|
+
for (const _ of s)
|
|
25690
|
+
n++;
|
|
25691
|
+
return n;
|
|
25692
|
+
}
|
|
25693
|
+
function rstripHash(s) {
|
|
25694
|
+
let i = s.length;
|
|
25695
|
+
while (i > 0 && s[i - 1] === "#")
|
|
25696
|
+
i--;
|
|
25697
|
+
return s.slice(0, i);
|
|
25698
|
+
}
|
|
25699
|
+
function findHeadings(doc) {
|
|
25700
|
+
const out = [];
|
|
25701
|
+
const re = /^(#{1,3})[ \t]+(.+)$/gm;
|
|
25702
|
+
let m;
|
|
25703
|
+
while ((m = re.exec(doc)) !== null) {
|
|
25704
|
+
out.push({ offset: m.index, level: m[1].length, text: rstripHash(m[2]).trim() });
|
|
25705
|
+
}
|
|
25706
|
+
return out;
|
|
25707
|
+
}
|
|
25708
|
+
function activeHeadings(headings, offset) {
|
|
25709
|
+
const stack = [];
|
|
25710
|
+
for (const h of headings) {
|
|
25711
|
+
if (h.offset > offset)
|
|
25712
|
+
break;
|
|
25713
|
+
while (stack.length && stack[stack.length - 1].level >= h.level)
|
|
25714
|
+
stack.pop();
|
|
25715
|
+
stack.push(h);
|
|
25716
|
+
}
|
|
25717
|
+
return stack;
|
|
25718
|
+
}
|
|
25719
|
+
function hardSplitCp(s, maxCp) {
|
|
25720
|
+
const out = [];
|
|
25721
|
+
let buf = "";
|
|
25722
|
+
let n = 0;
|
|
25723
|
+
for (const ch of s) {
|
|
25724
|
+
if (n >= maxCp) {
|
|
25725
|
+
out.push(buf);
|
|
25726
|
+
buf = "";
|
|
25727
|
+
n = 0;
|
|
25728
|
+
}
|
|
25729
|
+
buf += ch;
|
|
25730
|
+
n++;
|
|
25731
|
+
}
|
|
25732
|
+
if (buf)
|
|
25733
|
+
out.push(buf);
|
|
25734
|
+
return out;
|
|
25735
|
+
}
|
|
25736
|
+
function chunkMarkdown(text, maxChunkChars = 4000, _minChunkChars = 100) {
|
|
25737
|
+
const doc = text.trim();
|
|
25738
|
+
if (!doc)
|
|
25739
|
+
return [];
|
|
25740
|
+
if (cpLen(doc) <= maxChunkChars) {
|
|
25741
|
+
return [
|
|
25742
|
+
{ chunk_index: 0, heading_path: [], heading_level: 0, title: "", content: doc, char_count: cpLen(doc) }
|
|
25743
|
+
];
|
|
25744
|
+
}
|
|
25745
|
+
const headings = findHeadings(doc);
|
|
25746
|
+
const parts = doc.split(/(\n{2,})/);
|
|
25747
|
+
const atoms = [];
|
|
25748
|
+
for (let i = 0;i < parts.length; i += 2) {
|
|
25749
|
+
const unit = (parts[i] ?? "") + (parts[i + 1] ?? "");
|
|
25750
|
+
if (unit === "")
|
|
25751
|
+
continue;
|
|
25752
|
+
if (cpLen(unit) > maxChunkChars)
|
|
25753
|
+
atoms.push(...hardSplitCp(unit, maxChunkChars));
|
|
25754
|
+
else
|
|
25755
|
+
atoms.push(unit);
|
|
25756
|
+
}
|
|
25757
|
+
const chunks = [];
|
|
25758
|
+
let buf = "";
|
|
25759
|
+
let bufCp = 0;
|
|
25760
|
+
let bufStart = 0;
|
|
25761
|
+
let offset = 0;
|
|
25762
|
+
const flush = () => {
|
|
25763
|
+
if (buf === "")
|
|
25764
|
+
return;
|
|
25765
|
+
const stack = activeHeadings(headings, bufStart);
|
|
25766
|
+
chunks.push({
|
|
25767
|
+
chunk_index: chunks.length,
|
|
25768
|
+
heading_path: stack.map((h) => h.text),
|
|
25769
|
+
heading_level: stack.length ? stack[stack.length - 1].level : 0,
|
|
25770
|
+
title: stack.length ? stack[stack.length - 1].text : "",
|
|
25771
|
+
content: buf,
|
|
25772
|
+
char_count: bufCp
|
|
25773
|
+
});
|
|
25774
|
+
buf = "";
|
|
25775
|
+
bufCp = 0;
|
|
25776
|
+
};
|
|
25777
|
+
for (const atom of atoms) {
|
|
25778
|
+
const cp = cpLen(atom);
|
|
25779
|
+
if (buf === "") {
|
|
25780
|
+
bufStart = offset;
|
|
25781
|
+
buf = atom;
|
|
25782
|
+
bufCp = cp;
|
|
25783
|
+
} else if (bufCp + cp <= maxChunkChars) {
|
|
25784
|
+
buf += atom;
|
|
25785
|
+
bufCp += cp;
|
|
25786
|
+
} else {
|
|
25787
|
+
flush();
|
|
25788
|
+
bufStart = offset;
|
|
25789
|
+
buf = atom;
|
|
25790
|
+
bufCp = cp;
|
|
25791
|
+
}
|
|
25792
|
+
offset += atom.length;
|
|
25793
|
+
}
|
|
25794
|
+
flush();
|
|
25795
|
+
return chunks;
|
|
25796
|
+
}
|
|
25797
|
+
function embeddingInputFor(docTitle, chunk) {
|
|
25798
|
+
const breadcrumb = chunk.heading_path.join(" > ");
|
|
25799
|
+
const head2 = breadcrumb ? `# ${docTitle}
|
|
25800
|
+
${breadcrumb}` : `# ${docTitle}`;
|
|
25801
|
+
return `${head2}
|
|
25802
|
+
${chunk.content}`;
|
|
25803
|
+
}
|
|
25804
|
+
var CONTENT_FORMAT_BLIND_STITCH = 2;
|
|
25805
|
+
|
|
25449
25806
|
// ../../node_modules/.bun/underscore@1.13.8/node_modules/underscore/underscore-node-f.cjs
|
|
25450
25807
|
var require_underscore_node_f = __commonJS((exports) => {
|
|
25451
25808
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -32746,7 +33103,7 @@ var require_BufferList = __commonJS((exports, module) => {
|
|
|
32746
33103
|
this.head = this.tail = null;
|
|
32747
33104
|
this.length = 0;
|
|
32748
33105
|
};
|
|
32749
|
-
BufferList.prototype.join = function
|
|
33106
|
+
BufferList.prototype.join = function join10(s) {
|
|
32750
33107
|
if (this.length === 0)
|
|
32751
33108
|
return "";
|
|
32752
33109
|
var p = this.head;
|
|
@@ -54469,6 +54826,9 @@ async function handler4(supabase, args, ctx) {
|
|
|
54469
54826
|
const project_names_raw = args.project_names;
|
|
54470
54827
|
const source = args.source ?? "agent";
|
|
54471
54828
|
const metadata = args.metadata ?? null;
|
|
54829
|
+
if (metadata !== null && (typeof metadata !== "object" || Array.isArray(metadata))) {
|
|
54830
|
+
throw new McpInvalidParams('metadata must be a JSON object of key/value pairs, e.g. {"type":"note"} — not a string, number, or array');
|
|
54831
|
+
}
|
|
54472
54832
|
const update_if_exists = args.update_if_exists ?? false;
|
|
54473
54833
|
const author = args.author ?? "mcp-agent";
|
|
54474
54834
|
const author_type = "agent";
|
|
@@ -54481,7 +54841,7 @@ async function handler4(supabase, args, ctx) {
|
|
|
54481
54841
|
throw new McpInvalidParams("project_names must be a JSON array of strings; for a single project use project_name (string)");
|
|
54482
54842
|
}
|
|
54483
54843
|
const project_names = Array.isArray(project_names_raw) ? project_names_raw.filter((s) => typeof s === "string" && s.length > 0) : null;
|
|
54484
|
-
if (!ctx.openaiApiKey) {
|
|
54844
|
+
if (!ctx.openaiApiKey && resolveEmbedderKind() !== "local") {
|
|
54485
54845
|
throw new Error("OpenAI API key not configured. Set OPENAI_API_KEY (Edge Function) or CEREFOX_OPENAI_API_KEY (.env, local).");
|
|
54486
54846
|
}
|
|
54487
54847
|
const contentHash2 = await sha256hex(normalizeContent(content));
|
|
@@ -54503,7 +54863,7 @@ async function handler4(supabase, args, ctx) {
|
|
|
54503
54863
|
if (chunks2.length === 0)
|
|
54504
54864
|
throw new Error("Content produced no chunks");
|
|
54505
54865
|
const texts2 = chunks2.map((c2) => embeddingInputFor(title, c2));
|
|
54506
|
-
const embeddings2 = await embedBatch(texts2, ctx.openaiApiKey);
|
|
54866
|
+
const embeddings2 = await embedBatch(texts2, ctx.openaiApiKey ?? "");
|
|
54507
54867
|
const totalChars2 = chunks2.reduce((s, c2) => s + c2.char_count, 0);
|
|
54508
54868
|
const chunkData2 = chunks2.map((chunk, i) => ({
|
|
54509
54869
|
chunk_index: i,
|
|
@@ -54513,7 +54873,7 @@ async function handler4(supabase, args, ctx) {
|
|
|
54513
54873
|
content: chunk.content,
|
|
54514
54874
|
char_count: chunk.char_count,
|
|
54515
54875
|
embedding: embeddings2[i],
|
|
54516
|
-
embedder:
|
|
54876
|
+
embedder: activeEmbedderName()
|
|
54517
54877
|
}));
|
|
54518
54878
|
const { error: ingestErr2 } = await supabase.rpc("cerefox_ingest_document", {
|
|
54519
54879
|
p_document_id: existingDoc.id,
|
|
@@ -54561,7 +54921,7 @@ async function handler4(supabase, args, ctx) {
|
|
|
54561
54921
|
if (chunks2.length === 0)
|
|
54562
54922
|
throw new Error("Content produced no chunks");
|
|
54563
54923
|
const texts2 = chunks2.map((c2) => embeddingInputFor(title, c2));
|
|
54564
|
-
const embeddings2 = await embedBatch(texts2, ctx.openaiApiKey);
|
|
54924
|
+
const embeddings2 = await embedBatch(texts2, ctx.openaiApiKey ?? "");
|
|
54565
54925
|
const totalChars2 = chunks2.reduce((s, c2) => s + c2.char_count, 0);
|
|
54566
54926
|
const chunkData2 = chunks2.map((chunk, i) => ({
|
|
54567
54927
|
chunk_index: i,
|
|
@@ -54571,7 +54931,7 @@ async function handler4(supabase, args, ctx) {
|
|
|
54571
54931
|
content: chunk.content,
|
|
54572
54932
|
char_count: chunk.char_count,
|
|
54573
54933
|
embedding: embeddings2[i],
|
|
54574
|
-
embedder:
|
|
54934
|
+
embedder: activeEmbedderName()
|
|
54575
54935
|
}));
|
|
54576
54936
|
const { error: ingestErr2 } = await supabase.rpc("cerefox_ingest_document", {
|
|
54577
54937
|
p_document_id: existingDoc.id,
|
|
@@ -54613,7 +54973,7 @@ async function handler4(supabase, args, ctx) {
|
|
|
54613
54973
|
if (chunks.length === 0)
|
|
54614
54974
|
throw new Error("Content produced no chunks");
|
|
54615
54975
|
const texts = chunks.map((c2) => embeddingInputFor(title, c2));
|
|
54616
|
-
const embeddings = await embedBatch(texts, ctx.openaiApiKey);
|
|
54976
|
+
const embeddings = await embedBatch(texts, ctx.openaiApiKey ?? "");
|
|
54617
54977
|
const totalChars = chunks.reduce((s, c2) => s + c2.char_count, 0);
|
|
54618
54978
|
const chunkData = chunks.map((chunk, i) => ({
|
|
54619
54979
|
chunk_index: i,
|
|
@@ -54623,7 +54983,7 @@ async function handler4(supabase, args, ctx) {
|
|
|
54623
54983
|
content: chunk.content,
|
|
54624
54984
|
char_count: chunk.char_count,
|
|
54625
54985
|
embedding: embeddings[i],
|
|
54626
|
-
embedder:
|
|
54986
|
+
embedder: activeEmbedderName()
|
|
54627
54987
|
}));
|
|
54628
54988
|
const { data: ingestResult, error: ingestErr } = await supabase.rpc("cerefox_ingest_document", {
|
|
54629
54989
|
p_document_id: null,
|
|
@@ -54960,7 +55320,7 @@ async function handler9(supabase, args, ctx) {
|
|
|
54960
55320
|
}
|
|
54961
55321
|
if (!query?.trim())
|
|
54962
55322
|
throw new McpInvalidParams("query is required");
|
|
54963
|
-
if (mode !== "fts" && !ctx.openaiApiKey) {
|
|
55323
|
+
if (mode !== "fts" && !ctx.openaiApiKey && resolveEmbedderKind() !== "local") {
|
|
54964
55324
|
throw new Error("OpenAI API key not configured. Set OPENAI_API_KEY (Edge Function) or CEREFOX_OPENAI_API_KEY (.env, local).");
|
|
54965
55325
|
}
|
|
54966
55326
|
let projectId = null;
|
|
@@ -54971,7 +55331,7 @@ async function handler9(supabase, args, ctx) {
|
|
|
54971
55331
|
}
|
|
54972
55332
|
let embedding = null;
|
|
54973
55333
|
if (mode !== "fts") {
|
|
54974
|
-
embedding = await getEmbedding(query, ctx.openaiApiKey);
|
|
55334
|
+
embedding = await getEmbedding(query, ctx.openaiApiKey ?? "");
|
|
54975
55335
|
}
|
|
54976
55336
|
const metaFilterParam = metadata_filter && Object.keys(metadata_filter).length > 0 ? { p_metadata_filter: metadata_filter } : {};
|
|
54977
55337
|
let rpcName;
|
|
@@ -68266,6 +68626,7 @@ var exports_server = {};
|
|
|
68266
68626
|
__export(exports_server, {
|
|
68267
68627
|
buildServer: () => buildServer
|
|
68268
68628
|
});
|
|
68629
|
+
import { existsSync as existsSync12, readFileSync as readFileSync12 } from "node:fs";
|
|
68269
68630
|
function buildServer() {
|
|
68270
68631
|
const settings = loadSettings();
|
|
68271
68632
|
if (!settings.supabaseUrl || !settings.supabaseKey) {
|
|
@@ -68314,21 +68675,36 @@ async function warnIfSchemaVersionMismatch(supabase) {
|
|
|
68314
68675
|
try {
|
|
68315
68676
|
const { data } = await supabase.rpc("cerefox_schema_version");
|
|
68316
68677
|
const deployed = typeof data === "string" ? data : null;
|
|
68317
|
-
if (deployed
|
|
68318
|
-
|
|
68678
|
+
if (!deployed)
|
|
68679
|
+
return;
|
|
68680
|
+
let bundled = null;
|
|
68681
|
+
try {
|
|
68682
|
+
const assets = resolveServerAssets();
|
|
68683
|
+
if (existsSync12(assets.schemaFile)) {
|
|
68684
|
+
const m = readFileSync12(assets.schemaFile, "utf8").match(SCHEMA_VERSION_RE2);
|
|
68685
|
+
bundled = m ? m[1] : null;
|
|
68686
|
+
}
|
|
68687
|
+
} catch {}
|
|
68688
|
+
if (!bundled)
|
|
68689
|
+
return;
|
|
68690
|
+
if (compareSemver(deployed, bundled) < 0) {
|
|
68691
|
+
process.stderr.write(`[cerefox-mcp] ⚠ schema version mismatch: this client bundles v${bundled} ` + `but the deployed schema is v${deployed}. Run \`cerefox server deploy\` ` + `to update it. Tools may behave unexpectedly until then.
|
|
68319
68692
|
`);
|
|
68320
68693
|
}
|
|
68321
68694
|
} catch {}
|
|
68322
68695
|
}
|
|
68323
|
-
var SERVER_NAME = "cerefox";
|
|
68696
|
+
var SERVER_NAME = "cerefox", SCHEMA_VERSION_RE2;
|
|
68324
68697
|
var init_server3 = __esm(() => {
|
|
68325
68698
|
init_server2();
|
|
68326
68699
|
init_stdio2();
|
|
68327
68700
|
init_types4();
|
|
68328
68701
|
init_dist4();
|
|
68702
|
+
init_compatibility();
|
|
68329
68703
|
init_config();
|
|
68704
|
+
init_server_assets();
|
|
68330
68705
|
init_mcp_tools();
|
|
68331
68706
|
init_meta();
|
|
68707
|
+
SCHEMA_VERSION_RE2 = /^--\s*@version:\s*(\S+)/m;
|
|
68332
68708
|
});
|
|
68333
68709
|
|
|
68334
68710
|
// src/bin/cerefox.ts
|
|
@@ -68414,8 +68790,8 @@ async function action(options) {
|
|
|
68414
68790
|
println(c.green("✓ ") + `Backup written: ${dest}`);
|
|
68415
68791
|
println(c.dim(` documents: ${docs.length} · chunks: ${chunkTotal}`));
|
|
68416
68792
|
if (options.git) {
|
|
68417
|
-
println(c.yellow("⚠ ") + "--git commit
|
|
68418
|
-
println(c.dim("
|
|
68793
|
+
println(c.yellow("⚠ ") + "--git commit is not implemented; the snapshot was written without a git checkpoint.");
|
|
68794
|
+
println(c.dim(" Commit the backup directory yourself if you want it version-controlled."));
|
|
68419
68795
|
}
|
|
68420
68796
|
}
|
|
68421
68797
|
function registerBackup(program2) {
|
|
@@ -70166,58 +70542,11 @@ function registerDeleteProject(program2) {
|
|
|
70166
70542
|
// src/cli/commands/deploy-server.ts
|
|
70167
70543
|
init_cli_core();
|
|
70168
70544
|
init_config();
|
|
70545
|
+
init_server_assets();
|
|
70169
70546
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
70170
70547
|
import { existsSync as existsSync7 } from "node:fs";
|
|
70171
70548
|
import { readdirSync as readdirSync2 } from "node:fs";
|
|
70172
70549
|
|
|
70173
|
-
// ../../_shared/server-assets/index.ts
|
|
70174
|
-
import { existsSync as existsSync5 } from "node:fs";
|
|
70175
|
-
import { dirname as dirname2, join as join5 } from "node:path";
|
|
70176
|
-
import { fileURLToPath } from "node:url";
|
|
70177
|
-
import { cwd as processCwd2 } from "node:process";
|
|
70178
|
-
function moduleDir() {
|
|
70179
|
-
return dirname2(fileURLToPath(import.meta.url));
|
|
70180
|
-
}
|
|
70181
|
-
function bundledServerAssets(serverAssetsRoot) {
|
|
70182
|
-
return {
|
|
70183
|
-
schemaFile: join5(serverAssetsRoot, "db", "schema.sql"),
|
|
70184
|
-
rpcsFile: join5(serverAssetsRoot, "db", "rpcs.sql"),
|
|
70185
|
-
migrationsDir: join5(serverAssetsRoot, "db", "migrations"),
|
|
70186
|
-
functionsDir: join5(serverAssetsRoot, "supabase", "functions"),
|
|
70187
|
-
layout: "bundled"
|
|
70188
|
-
};
|
|
70189
|
-
}
|
|
70190
|
-
function sourceServerAssets(repoRoot) {
|
|
70191
|
-
const dbDir = join5(repoRoot, "src", "cerefox", "db");
|
|
70192
|
-
return {
|
|
70193
|
-
schemaFile: join5(dbDir, "schema.sql"),
|
|
70194
|
-
rpcsFile: join5(dbDir, "rpcs.sql"),
|
|
70195
|
-
migrationsDir: join5(dbDir, "migrations"),
|
|
70196
|
-
functionsDir: join5(repoRoot, "supabase", "functions"),
|
|
70197
|
-
layout: "source"
|
|
70198
|
-
};
|
|
70199
|
-
}
|
|
70200
|
-
function serverAssetsUsable(p) {
|
|
70201
|
-
return existsSync5(p.schemaFile) && existsSync5(p.rpcsFile);
|
|
70202
|
-
}
|
|
70203
|
-
function resolveServerAssets(opts = {}) {
|
|
70204
|
-
if (opts.assetsDir) {
|
|
70205
|
-
return { ...bundledServerAssets(opts.assetsDir), layout: "explicit" };
|
|
70206
|
-
}
|
|
70207
|
-
const here = opts.moduleDirOverride ?? moduleDir();
|
|
70208
|
-
const cwd = opts.cwd ?? processCwd2();
|
|
70209
|
-
const candidates = [
|
|
70210
|
-
bundledServerAssets(join5(here, "..", "server-assets")),
|
|
70211
|
-
sourceServerAssets(join5(here, "..", "..")),
|
|
70212
|
-
sourceServerAssets(cwd)
|
|
70213
|
-
];
|
|
70214
|
-
for (const candidate of candidates) {
|
|
70215
|
-
if (serverAssetsUsable(candidate))
|
|
70216
|
-
return candidate;
|
|
70217
|
-
}
|
|
70218
|
-
return sourceServerAssets(join5(here, "..", ".."));
|
|
70219
|
-
}
|
|
70220
|
-
|
|
70221
70550
|
// ../../_shared/db-deploy/index.ts
|
|
70222
70551
|
init_src();
|
|
70223
70552
|
import { existsSync as existsSync6, readFileSync as readFileSync5, readdirSync } from "node:fs";
|
|
@@ -74276,112 +74605,18 @@ init_cli_core();
|
|
|
74276
74605
|
|
|
74277
74606
|
// src/cli/util/checks.ts
|
|
74278
74607
|
init_meta();
|
|
74279
|
-
import { existsSync as
|
|
74280
|
-
import { homedir as
|
|
74281
|
-
import { join as
|
|
74608
|
+
import { existsSync as existsSync10, readFileSync as readFileSync7, realpathSync, statSync as statSync2 } from "node:fs";
|
|
74609
|
+
import { homedir as homedir6 } from "node:os";
|
|
74610
|
+
import { join as join9 } from "node:path";
|
|
74282
74611
|
|
|
74283
74612
|
// ../../_shared/ef-meta/index.ts
|
|
74284
|
-
var EF_VERSION = "1.0.0-beta.
|
|
74613
|
+
var EF_VERSION = "1.0.0-beta.4";
|
|
74285
74614
|
|
|
74286
74615
|
// src/cli/util/checks.ts
|
|
74287
74616
|
init_config();
|
|
74288
74617
|
init_config();
|
|
74289
|
-
|
|
74290
|
-
|
|
74291
|
-
var COMPATIBILITY = {
|
|
74292
|
-
minSchema: "0.3.1",
|
|
74293
|
-
minEdgeFunctions: "0.6.0"
|
|
74294
|
-
};
|
|
74295
|
-
function compareSemver(a, b2) {
|
|
74296
|
-
const norm = (v) => v.split(/[.-]/).slice(0, 3).map((p) => Number.parseInt(p, 10)).map((n) => Number.isFinite(n) ? n : 0);
|
|
74297
|
-
const pa = norm(a);
|
|
74298
|
-
const pb = norm(b2);
|
|
74299
|
-
for (let i = 0;i < 3; i++) {
|
|
74300
|
-
const x = pa[i] ?? 0;
|
|
74301
|
-
const y = pb[i] ?? 0;
|
|
74302
|
-
if (x !== y)
|
|
74303
|
-
return x < y ? -1 : 1;
|
|
74304
|
-
}
|
|
74305
|
-
return 0;
|
|
74306
|
-
}
|
|
74307
|
-
function classifyCompat(deployed, min, bundled) {
|
|
74308
|
-
if (!deployed)
|
|
74309
|
-
return "unknown";
|
|
74310
|
-
if (compareSemver(deployed, min) < 0)
|
|
74311
|
-
return "below-min";
|
|
74312
|
-
if (bundled && compareSemver(deployed, bundled) < 0)
|
|
74313
|
-
return "above-min-but-old";
|
|
74314
|
-
return "ok";
|
|
74315
|
-
}
|
|
74316
|
-
function aggregatorUrlFor(supabaseUrl) {
|
|
74317
|
-
const base = supabaseUrl.replace(/\/$/, "");
|
|
74318
|
-
return `${base}/functions/v1/cerefox-mcp/version?peers=true`;
|
|
74319
|
-
}
|
|
74320
|
-
async function checkServerCompatibility(opts) {
|
|
74321
|
-
const fetchImpl = opts.fetchImpl ?? fetch;
|
|
74322
|
-
const result = {
|
|
74323
|
-
schema: { deployed: null, min: COMPATIBILITY.minSchema, level: "unknown" },
|
|
74324
|
-
edgeFunctions: {
|
|
74325
|
-
deployed: null,
|
|
74326
|
-
min: COMPATIBILITY.minEdgeFunctions,
|
|
74327
|
-
level: "unknown",
|
|
74328
|
-
errors: []
|
|
74329
|
-
},
|
|
74330
|
-
blocking: false,
|
|
74331
|
-
efProbeSkipped: false
|
|
74332
|
-
};
|
|
74333
|
-
if (!opts.bearer) {
|
|
74334
|
-
result.efProbeSkipped = true;
|
|
74335
|
-
result.efSkipReason = "No CEREFOX_ACCESS_TOKEN configured; Edge Function version check skipped.";
|
|
74336
|
-
return result;
|
|
74337
|
-
}
|
|
74338
|
-
let agg = null;
|
|
74339
|
-
try {
|
|
74340
|
-
const ctrl = new AbortController;
|
|
74341
|
-
const timer2 = setTimeout(() => ctrl.abort(), opts.timeoutMs ?? 6000);
|
|
74342
|
-
try {
|
|
74343
|
-
const resp = await fetchImpl(opts.aggregatorUrl, {
|
|
74344
|
-
method: "GET",
|
|
74345
|
-
headers: { Authorization: `Bearer ${opts.bearer}`, apikey: opts.bearer },
|
|
74346
|
-
signal: ctrl.signal
|
|
74347
|
-
});
|
|
74348
|
-
if (resp.ok) {
|
|
74349
|
-
agg = await resp.json();
|
|
74350
|
-
} else {
|
|
74351
|
-
result.efProbeSkipped = true;
|
|
74352
|
-
result.efSkipReason = resp.status === 404 || resp.status === 405 ? "Edge Functions predate v0.8 (no /version route). Redeploy with `cerefox server deploy --functions-only` to enable version checks." : `Aggregator returned HTTP ${resp.status}; Edge Function version check skipped.`;
|
|
74353
|
-
}
|
|
74354
|
-
} finally {
|
|
74355
|
-
clearTimeout(timer2);
|
|
74356
|
-
}
|
|
74357
|
-
} catch (err) {
|
|
74358
|
-
result.efProbeSkipped = true;
|
|
74359
|
-
result.efSkipReason = `Could not reach the version aggregator: ${err instanceof Error ? err.message : String(err)}`;
|
|
74360
|
-
}
|
|
74361
|
-
if (!agg)
|
|
74362
|
-
return result;
|
|
74363
|
-
result.schema.deployed = agg.schema ?? null;
|
|
74364
|
-
result.schema.level = classifyCompat(result.schema.deployed, COMPATIBILITY.minSchema, opts.bundledSchema);
|
|
74365
|
-
const versions = [];
|
|
74366
|
-
if (agg.version)
|
|
74367
|
-
versions.push(agg.version);
|
|
74368
|
-
for (const ef of agg.efs ?? [])
|
|
74369
|
-
versions.push(ef.version);
|
|
74370
|
-
result.edgeFunctions.errors = agg.errors ?? [];
|
|
74371
|
-
if (versions.length > 0) {
|
|
74372
|
-
const weakest = versions.reduce((lo, v) => compareSemver(v, lo) < 0 ? v : lo);
|
|
74373
|
-
result.edgeFunctions.deployed = weakest;
|
|
74374
|
-
result.edgeFunctions.level = classifyCompat(weakest, COMPATIBILITY.minEdgeFunctions, opts.bundledEf);
|
|
74375
|
-
} else {
|
|
74376
|
-
result.edgeFunctions.level = "unknown";
|
|
74377
|
-
result.efProbeSkipped = true;
|
|
74378
|
-
result.efSkipReason = "Aggregator reported no Edge Function versions; check skipped.";
|
|
74379
|
-
}
|
|
74380
|
-
result.blocking = result.schema.level === "below-min" || result.edgeFunctions.level === "below-min";
|
|
74381
|
-
return result;
|
|
74382
|
-
}
|
|
74383
|
-
|
|
74384
|
-
// src/cli/util/checks.ts
|
|
74618
|
+
init_compatibility();
|
|
74619
|
+
init_server_assets();
|
|
74385
74620
|
function checkBinary() {
|
|
74386
74621
|
return {
|
|
74387
74622
|
name: "binary",
|
|
@@ -74432,7 +74667,7 @@ function checkConfig() {
|
|
|
74432
74667
|
hint: "Run `cerefox init` to bootstrap."
|
|
74433
74668
|
};
|
|
74434
74669
|
}
|
|
74435
|
-
if (!
|
|
74670
|
+
if (!existsSync10(envPath)) {
|
|
74436
74671
|
return {
|
|
74437
74672
|
name: "config",
|
|
74438
74673
|
status: "error",
|
|
@@ -74514,6 +74749,14 @@ async function checkSupabase() {
|
|
|
74514
74749
|
async function checkOpenAI() {
|
|
74515
74750
|
const settings = loadSettings();
|
|
74516
74751
|
if (!settings.openaiApiKey) {
|
|
74752
|
+
const { resolveEmbedderKind: resolveEmbedderKind2 } = await Promise.resolve().then(() => exports_embeddings);
|
|
74753
|
+
if (resolveEmbedderKind2() === "local") {
|
|
74754
|
+
return {
|
|
74755
|
+
name: "openai",
|
|
74756
|
+
status: "skipped",
|
|
74757
|
+
detail: "no key set — not needed (local embedder active; see the embedder check)."
|
|
74758
|
+
};
|
|
74759
|
+
}
|
|
74517
74760
|
return {
|
|
74518
74761
|
name: "openai",
|
|
74519
74762
|
status: "warn",
|
|
@@ -74560,7 +74803,7 @@ var SCHEMA_VERSION_RE = /^--\s*@version:\s*(\S+)/m;
|
|
|
74560
74803
|
function readBundledSchemaVersion() {
|
|
74561
74804
|
try {
|
|
74562
74805
|
const assets = resolveServerAssets();
|
|
74563
|
-
if (!
|
|
74806
|
+
if (!existsSync10(assets.schemaFile))
|
|
74564
74807
|
return null;
|
|
74565
74808
|
const m = readFileSync7(assets.schemaFile, "utf8").match(SCHEMA_VERSION_RE);
|
|
74566
74809
|
return m ? m[1] : null;
|
|
@@ -74630,6 +74873,46 @@ async function checkSchemaVersion() {
|
|
|
74630
74873
|
};
|
|
74631
74874
|
}
|
|
74632
74875
|
}
|
|
74876
|
+
var EMBEDDER_CHECK_NAME = "embedder";
|
|
74877
|
+
async function checkEmbedderMismatch() {
|
|
74878
|
+
const settings = loadSettings();
|
|
74879
|
+
if (!settings.supabaseUrl || !settings.supabaseKey) {
|
|
74880
|
+
return { name: EMBEDDER_CHECK_NAME, status: "skipped", detail: "Supabase config missing; skipped." };
|
|
74881
|
+
}
|
|
74882
|
+
const { activeEmbedderName: activeEmbedderName2 } = await Promise.resolve().then(() => exports_embeddings);
|
|
74883
|
+
const active = activeEmbedderName2();
|
|
74884
|
+
try {
|
|
74885
|
+
const url = `${settings.supabaseUrl.replace(/\/$/, "")}/rest/v1/cerefox_chunks?version_id=is.null&embedder_primary=not.is.null&select=embedder_primary&limit=1000`;
|
|
74886
|
+
const resp = await fetch(url, {
|
|
74887
|
+
headers: { apikey: settings.supabaseKey, Authorization: `Bearer ${settings.supabaseKey}` }
|
|
74888
|
+
});
|
|
74889
|
+
if (!resp.ok) {
|
|
74890
|
+
return { name: EMBEDDER_CHECK_NAME, status: "skipped", detail: `chunk probe returned ${resp.status}; skipped.` };
|
|
74891
|
+
}
|
|
74892
|
+
const rows = await resp.json();
|
|
74893
|
+
const recorded = [...new Set(rows.map((r) => r.embedder_primary))];
|
|
74894
|
+
const stale = recorded.filter((r) => r !== active);
|
|
74895
|
+
if (stale.length === 0) {
|
|
74896
|
+
return {
|
|
74897
|
+
name: EMBEDDER_CHECK_NAME,
|
|
74898
|
+
status: "ok",
|
|
74899
|
+
detail: `configured "${active}"${recorded.length ? " — matches all existing chunks" : " (no embedded chunks yet)"}`
|
|
74900
|
+
};
|
|
74901
|
+
}
|
|
74902
|
+
return {
|
|
74903
|
+
name: EMBEDDER_CHECK_NAME,
|
|
74904
|
+
status: "warn",
|
|
74905
|
+
detail: `configured "${active}" but existing chunks were embedded with ${stale.map((r) => `"${r}"`).join(", ")} — semantic search across them is broken.`,
|
|
74906
|
+
hint: "Run `cerefox server reindex` to re-embed everything with the configured embedder."
|
|
74907
|
+
};
|
|
74908
|
+
} catch (err) {
|
|
74909
|
+
return {
|
|
74910
|
+
name: EMBEDDER_CHECK_NAME,
|
|
74911
|
+
status: "skipped",
|
|
74912
|
+
detail: `probe failed: ${err instanceof Error ? err.message : String(err)}`
|
|
74913
|
+
};
|
|
74914
|
+
}
|
|
74915
|
+
}
|
|
74633
74916
|
var CONTENT_FORMAT_CHECK_NAME = "content format";
|
|
74634
74917
|
async function checkContentFormat() {
|
|
74635
74918
|
const settings = loadSettings();
|
|
@@ -74679,7 +74962,7 @@ async function checkContentFormat() {
|
|
|
74679
74962
|
}
|
|
74680
74963
|
}
|
|
74681
74964
|
function hasCerefoxInJsonFile(path) {
|
|
74682
|
-
if (!
|
|
74965
|
+
if (!existsSync10(path))
|
|
74683
74966
|
return false;
|
|
74684
74967
|
try {
|
|
74685
74968
|
const parsed = JSON.parse(readFileSync7(path, "utf8"));
|
|
@@ -74690,10 +74973,10 @@ function hasCerefoxInJsonFile(path) {
|
|
|
74690
74973
|
}
|
|
74691
74974
|
}
|
|
74692
74975
|
function checkMcpConfigs() {
|
|
74693
|
-
const home =
|
|
74694
|
-
const claudeCodeUser =
|
|
74695
|
-
const claudeCodeProj =
|
|
74696
|
-
const claudeDesktop = process.platform === "darwin" ?
|
|
74976
|
+
const home = homedir6();
|
|
74977
|
+
const claudeCodeUser = join9(home, ".claude.json");
|
|
74978
|
+
const claudeCodeProj = join9(process.cwd(), ".mcp.json");
|
|
74979
|
+
const claudeDesktop = process.platform === "darwin" ? join9(home, "Library", "Application Support", "Claude", "claude_desktop_config.json") : process.platform === "win32" ? join9(process.env.APPDATA ?? "", "Claude", "claude_desktop_config.json") : join9(home, ".config", "Claude", "claude_desktop_config.json");
|
|
74697
74980
|
const found = [];
|
|
74698
74981
|
if (hasCerefoxInJsonFile(claudeCodeUser))
|
|
74699
74982
|
found.push("Claude Code (user)");
|
|
@@ -74716,10 +74999,10 @@ function checkMcpConfigs() {
|
|
|
74716
74999
|
};
|
|
74717
75000
|
}
|
|
74718
75001
|
function checkLegacyShadowEnv() {
|
|
74719
|
-
const home =
|
|
74720
|
-
const homeEnv =
|
|
74721
|
-
const cwdEnv =
|
|
74722
|
-
if (!
|
|
75002
|
+
const home = homedir6();
|
|
75003
|
+
const homeEnv = join9(home, USER_STATE_DIR_NAME, ".env");
|
|
75004
|
+
const cwdEnv = join9(process.cwd(), ".env");
|
|
75005
|
+
if (!existsSync10(homeEnv) || !existsSync10(cwdEnv))
|
|
74723
75006
|
return null;
|
|
74724
75007
|
try {
|
|
74725
75008
|
if (realpathSync(homeEnv) === realpathSync(cwdEnv))
|
|
@@ -74729,7 +75012,7 @@ function checkLegacyShadowEnv() {
|
|
|
74729
75012
|
name: "legacy env",
|
|
74730
75013
|
status: "skipped",
|
|
74731
75014
|
detail: `${cwdEnv} (shadowed by ~/.cerefox/.env)`,
|
|
74732
|
-
hint: "
|
|
75015
|
+
hint: "Shadowed by ~/.cerefox/.env and no longer read by anything (Python was removed at v1.0.0). Safe to delete."
|
|
74733
75016
|
};
|
|
74734
75017
|
}
|
|
74735
75018
|
async function checkPostgres() {
|
|
@@ -74866,6 +75149,7 @@ async function runAllChecks(opts = {}) {
|
|
|
74866
75149
|
{ name: "supabase", phase: "Probing Supabase Data API", run: () => checkSupabase() },
|
|
74867
75150
|
{ name: "openai", phase: "Probing OpenAI embeddings", run: () => checkOpenAI() },
|
|
74868
75151
|
{ name: "schema + RPCs", phase: "Reading schema + RPC version", run: () => checkSchemaVersion() },
|
|
75152
|
+
{ name: "embedder", phase: "Checking embedder consistency", run: () => checkEmbedderMismatch() },
|
|
74869
75153
|
{ name: "content format", phase: "Checking chunk reconstruction format", run: () => checkContentFormat() },
|
|
74870
75154
|
{ name: "edge functions", phase: "Probing Edge Function versions", run: () => checkEdgeFunctionsCompat() },
|
|
74871
75155
|
{ name: "postgres", phase: "Probing Postgres DDL endpoint", run: () => checkPostgres() },
|
|
@@ -75316,7 +75600,7 @@ class IngestionPipeline {
|
|
|
75316
75600
|
constructor(deps) {
|
|
75317
75601
|
this.db = new IngestionDbBridge(deps.supabase);
|
|
75318
75602
|
this.apiKey = deps.openAiApiKey;
|
|
75319
|
-
this.embedderModel = deps.embedderModel ??
|
|
75603
|
+
this.embedderModel = deps.embedderModel ?? activeEmbedderName();
|
|
75320
75604
|
this.settings = { ...loadPipelineSettings(), ...deps.settings ?? {} };
|
|
75321
75605
|
}
|
|
75322
75606
|
async ingestText(opts) {
|
|
@@ -75681,7 +75965,7 @@ async function action18(path, options) {
|
|
|
75681
75965
|
if (!settings.supabaseUrl || !settings.supabaseKey) {
|
|
75682
75966
|
throw userError("Supabase credentials not configured — run `cerefox init` first.");
|
|
75683
75967
|
}
|
|
75684
|
-
if (!settings.openaiApiKey) {
|
|
75968
|
+
if (!settings.openaiApiKey && resolveEmbedderKind() !== "local") {
|
|
75685
75969
|
throw userError("OPENAI_API_KEY not set — required for embeddings during ingest.");
|
|
75686
75970
|
}
|
|
75687
75971
|
const supabase = createClient(settings.supabaseUrl, settings.supabaseKey, {
|
|
@@ -75744,7 +76028,7 @@ init_cli_core();
|
|
|
75744
76028
|
init_config();
|
|
75745
76029
|
var import_cli_progress = __toESM(require_cli_progress(), 1);
|
|
75746
76030
|
import { readdirSync as readdirSync4, statSync as statSync3 } from "node:fs";
|
|
75747
|
-
import { basename as basename3, extname as extname4, join as
|
|
76031
|
+
import { basename as basename3, extname as extname4, join as join10 } from "node:path";
|
|
75748
76032
|
function walk(dir, extensions) {
|
|
75749
76033
|
let entries;
|
|
75750
76034
|
try {
|
|
@@ -75754,7 +76038,7 @@ function walk(dir, extensions) {
|
|
|
75754
76038
|
}
|
|
75755
76039
|
const files = [];
|
|
75756
76040
|
for (const name of entries) {
|
|
75757
|
-
const full =
|
|
76041
|
+
const full = join10(dir, name);
|
|
75758
76042
|
let stat;
|
|
75759
76043
|
try {
|
|
75760
76044
|
stat = statSync3(full);
|
|
@@ -75788,7 +76072,7 @@ async function action19(dir, options) {
|
|
|
75788
76072
|
if (!settings.supabaseUrl || !settings.supabaseKey) {
|
|
75789
76073
|
throw userError("Supabase credentials not configured — run `cerefox init` first.");
|
|
75790
76074
|
}
|
|
75791
|
-
if (!settings.openaiApiKey) {
|
|
76075
|
+
if (!settings.openaiApiKey && resolveEmbedderKind() !== "local") {
|
|
75792
76076
|
throw userError("OPENAI_API_KEY not set — required for embeddings during ingest.");
|
|
75793
76077
|
}
|
|
75794
76078
|
const supabase = createClient(settings.supabaseUrl, settings.supabaseKey, {
|
|
@@ -75851,19 +76135,20 @@ function registerIngestDir(program2) {
|
|
|
75851
76135
|
// src/cli/commands/init.ts
|
|
75852
76136
|
init_cli_core();
|
|
75853
76137
|
init_config();
|
|
76138
|
+
init_compatibility();
|
|
75854
76139
|
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
75855
76140
|
import {
|
|
75856
76141
|
chmodSync,
|
|
75857
76142
|
copyFileSync as copyFileSync2,
|
|
75858
|
-
existsSync as
|
|
75859
|
-
mkdirSync as
|
|
76143
|
+
existsSync as existsSync11,
|
|
76144
|
+
mkdirSync as mkdirSync4,
|
|
75860
76145
|
readFileSync as readFileSync11,
|
|
75861
76146
|
writeFileSync as writeFileSync4
|
|
75862
76147
|
} from "node:fs";
|
|
75863
|
-
import { homedir as
|
|
75864
|
-
import { dirname as dirname4, join as
|
|
76148
|
+
import { homedir as homedir7 } from "node:os";
|
|
76149
|
+
import { dirname as dirname4, join as join11 } from "node:path";
|
|
75865
76150
|
async function readConfigFile(path) {
|
|
75866
|
-
if (!
|
|
76151
|
+
if (!existsSync11(path)) {
|
|
75867
76152
|
throw userError(`--config file not found: ${path}`);
|
|
75868
76153
|
}
|
|
75869
76154
|
let parsed;
|
|
@@ -75959,7 +76244,7 @@ async function promptForAnswers() {
|
|
|
75959
76244
|
});
|
|
75960
76245
|
println("");
|
|
75961
76246
|
println(c.cyan("▶ Step 4/5 — Direct Postgres connection (optional for npm-installed users)"));
|
|
75962
|
-
println(c.dim(" Only needed for `
|
|
76247
|
+
println(c.dim(" Only needed for `cerefox server deploy` (schema deploy + migrations).\n" + ` You can skip this and set CEREFOX_DATABASE_URL later — press Enter.
|
|
75963
76248
|
` + " Format: postgresql://postgres.<project-ref>:<pw>@…:5432/postgres?sslmode=require"));
|
|
75964
76249
|
const databaseUrl = await ask({
|
|
75965
76250
|
type: "text",
|
|
@@ -76045,16 +76330,15 @@ function printMigrationMenu(cwdEnv, homeEnv) {
|
|
|
76045
76330
|
println("");
|
|
76046
76331
|
println(c.yellow(`⚠ Found existing config at ${cwdEnv}.`));
|
|
76047
76332
|
println("");
|
|
76048
|
-
println("This may be from
|
|
76333
|
+
println("This may be from an earlier install. The CLI can use the");
|
|
76049
76334
|
println("same .env — env-var names are identical, no rewrite needed.");
|
|
76050
76335
|
println("");
|
|
76051
76336
|
println(" " + c.bold("[c]") + " Copy to " + homeEnv + " " + c.green("(recommended)"));
|
|
76052
|
-
println(c.dim(" •
|
|
76053
|
-
println(c.dim(" • Python keeps reading " + cwdEnv + " (backward compat)"));
|
|
76337
|
+
println(c.dim(" • The CLI reads the new home from now on"));
|
|
76054
76338
|
println(c.dim(" • Edit ~/.cerefox/.env going forward; the repo .env is legacy"));
|
|
76055
76339
|
println("");
|
|
76056
76340
|
println(" " + c.bold("[u]") + " Use " + cwdEnv + " as-is, skip writing anything");
|
|
76057
|
-
println(c.dim(" •
|
|
76341
|
+
println(c.dim(" • The CLI keeps reading the existing file"));
|
|
76058
76342
|
println(c.dim(" • Defer the migration"));
|
|
76059
76343
|
println("");
|
|
76060
76344
|
println(" " + c.bold("[f]") + " Fresh start — interactive prompts, write to " + homeEnv);
|
|
@@ -76166,7 +76450,7 @@ async function postWriteLifecycle(envPath, options) {
|
|
|
76166
76450
|
println(c.dim(` Config in effect: ${envPath}`));
|
|
76167
76451
|
}
|
|
76168
76452
|
function writeAnswersTo(target, answers) {
|
|
76169
|
-
|
|
76453
|
+
mkdirSync4(dirname4(target), { recursive: true });
|
|
76170
76454
|
writeFileSync4(target, buildEnvFile(answers), "utf8");
|
|
76171
76455
|
if (process.platform !== "win32") {
|
|
76172
76456
|
try {
|
|
@@ -76177,12 +76461,12 @@ function writeAnswersTo(target, answers) {
|
|
|
76177
76461
|
}
|
|
76178
76462
|
}
|
|
76179
76463
|
async function action21(options) {
|
|
76180
|
-
const homeEnv =
|
|
76181
|
-
const cwdEnv =
|
|
76464
|
+
const homeEnv = join11(homedir7(), USER_STATE_DIR_NAME, ".env");
|
|
76465
|
+
const cwdEnv = join11(process.cwd(), ".env");
|
|
76182
76466
|
const explicitDir = (process.env.CEREFOX_CONFIG_DIR ?? "").trim();
|
|
76183
76467
|
if (explicitDir) {
|
|
76184
76468
|
const target2 = resolveEnvFile();
|
|
76185
|
-
if (
|
|
76469
|
+
if (existsSync11(target2) && !options.force) {
|
|
76186
76470
|
println(c.yellow(`⚠ Config already exists at ${target2}.`));
|
|
76187
76471
|
const ok2 = await confirm("Overwrite?", true);
|
|
76188
76472
|
if (!ok2) {
|
|
@@ -76204,7 +76488,7 @@ async function action21(options) {
|
|
|
76204
76488
|
await postWriteLifecycle(target2, options);
|
|
76205
76489
|
return;
|
|
76206
76490
|
}
|
|
76207
|
-
if (
|
|
76491
|
+
if (existsSync11(homeEnv) && !options.force) {
|
|
76208
76492
|
println(c.yellow(`⚠ Config already exists at ${homeEnv}.`));
|
|
76209
76493
|
const ok2 = await confirm("Overwrite?", true);
|
|
76210
76494
|
if (!ok2) {
|
|
@@ -76225,12 +76509,12 @@ async function action21(options) {
|
|
|
76225
76509
|
await postWriteLifecycle(homeEnv, options);
|
|
76226
76510
|
return;
|
|
76227
76511
|
}
|
|
76228
|
-
if (
|
|
76512
|
+
if (existsSync11(cwdEnv) && !options.force && !options.config) {
|
|
76229
76513
|
printMigrationMenu(cwdEnv, homeEnv);
|
|
76230
76514
|
const ch = await promptMigrationChoice();
|
|
76231
76515
|
println("");
|
|
76232
76516
|
if (ch === "c") {
|
|
76233
|
-
|
|
76517
|
+
mkdirSync4(dirname4(homeEnv), { recursive: true });
|
|
76234
76518
|
copyFileSync2(cwdEnv, homeEnv);
|
|
76235
76519
|
if (process.platform !== "win32") {
|
|
76236
76520
|
try {
|
|
@@ -76240,7 +76524,7 @@ async function action21(options) {
|
|
|
76240
76524
|
}
|
|
76241
76525
|
}
|
|
76242
76526
|
println(c.green(`✓ Copied ${cwdEnv} → ${homeEnv}`));
|
|
76243
|
-
println(c.dim(` Repo file unchanged —
|
|
76527
|
+
println(c.dim(` Repo file left unchanged — safe to delete once the new location works.`));
|
|
76244
76528
|
println("");
|
|
76245
76529
|
const answers2 = answersFromEnvFile(homeEnv);
|
|
76246
76530
|
println(c.bold("Validating credentials…"));
|
|
@@ -76479,6 +76763,23 @@ function registerMcp(program2) {
|
|
|
76479
76763
|
});
|
|
76480
76764
|
}
|
|
76481
76765
|
|
|
76766
|
+
// src/cli/commands/embedder-warmup.ts
|
|
76767
|
+
function registerEmbedderWarmup(program2) {
|
|
76768
|
+
program2.command("embedder-warmup", { hidden: true }).description("Download + warm the local ONNX embedding model (Cerefox Local).").action(async () => {
|
|
76769
|
+
if (process.env.CEREFOX_EMBEDDER !== "local") {
|
|
76770
|
+
process.stderr.write(`embedder-warmup: CEREFOX_EMBEDDER is not 'local' — nothing to warm (the OpenAI embedder has no local model).
|
|
76771
|
+
`);
|
|
76772
|
+
process.exitCode = 1;
|
|
76773
|
+
return;
|
|
76774
|
+
}
|
|
76775
|
+
const onnx = await Promise.resolve().then(() => (init_onnx_embedder(), exports_onnx_embedder));
|
|
76776
|
+
await onnx.warmup();
|
|
76777
|
+
const [vec] = await onnx.onnxEmbed(["warmup"], "query");
|
|
76778
|
+
process.stderr.write(`[cerefox-embed] warm — ${vec.length}-dim vectors ready.
|
|
76779
|
+
`);
|
|
76780
|
+
});
|
|
76781
|
+
}
|
|
76782
|
+
|
|
76482
76783
|
// src/cli/commands/metadata-search.ts
|
|
76483
76784
|
init_cli_core();
|
|
76484
76785
|
init_client();
|
|
@@ -76638,35 +76939,35 @@ function registerReindex(program2) {
|
|
|
76638
76939
|
// src/cli/commands/restore.ts
|
|
76639
76940
|
init_cli_core();
|
|
76640
76941
|
init_client();
|
|
76641
|
-
import { existsSync as
|
|
76642
|
-
import { homedir as
|
|
76643
|
-
import { join as
|
|
76942
|
+
import { existsSync as existsSync13, readFileSync as readFileSync13, readdirSync as readdirSync5, statSync as statSync4 } from "node:fs";
|
|
76943
|
+
import { homedir as homedir8 } from "node:os";
|
|
76944
|
+
import { join as join12, resolve as resolve4 } from "node:path";
|
|
76644
76945
|
function expandHome2(path) {
|
|
76645
76946
|
if (path === "~")
|
|
76646
|
-
return
|
|
76947
|
+
return homedir8();
|
|
76647
76948
|
if (path.startsWith("~/"))
|
|
76648
|
-
return
|
|
76949
|
+
return join12(homedir8(), path.slice(2));
|
|
76649
76950
|
return path;
|
|
76650
76951
|
}
|
|
76651
76952
|
function resolveBackupFile(target) {
|
|
76652
76953
|
const path = resolve4(expandHome2(target));
|
|
76653
|
-
if (!
|
|
76954
|
+
if (!existsSync13(path)) {
|
|
76654
76955
|
throw userError(`Backup path not found: ${target}`);
|
|
76655
76956
|
}
|
|
76656
76957
|
const stat = statSync4(path);
|
|
76657
76958
|
if (stat.isFile())
|
|
76658
76959
|
return path;
|
|
76659
|
-
const candidates = readdirSync5(path).filter((n) => n.endsWith(".json") && n.startsWith("cerefox-")).map((n) => ({ name: n, mtime: statSync4(
|
|
76960
|
+
const candidates = readdirSync5(path).filter((n) => n.endsWith(".json") && n.startsWith("cerefox-")).map((n) => ({ name: n, mtime: statSync4(join12(path, n)).mtimeMs })).sort((a, b2) => b2.mtime - a.mtime);
|
|
76660
76961
|
if (candidates.length === 0) {
|
|
76661
76962
|
throw userError(`No cerefox-*.json files in ${path}`);
|
|
76662
76963
|
}
|
|
76663
|
-
return
|
|
76964
|
+
return join12(path, candidates[0].name);
|
|
76664
76965
|
}
|
|
76665
76966
|
async function action28(target, options) {
|
|
76666
76967
|
const file = resolveBackupFile(target);
|
|
76667
76968
|
let payload;
|
|
76668
76969
|
try {
|
|
76669
|
-
payload = JSON.parse(
|
|
76970
|
+
payload = JSON.parse(readFileSync13(file, "utf8"));
|
|
76670
76971
|
} catch (err) {
|
|
76671
76972
|
throw userError(`Could not parse backup file ${file}: ${err instanceof Error ? err.message : String(err)}`);
|
|
76672
76973
|
}
|
|
@@ -76731,7 +77032,7 @@ init_config();
|
|
|
76731
77032
|
async function embedQuery(query) {
|
|
76732
77033
|
const settings = loadSettings();
|
|
76733
77034
|
const apiKey = settings.openaiApiKey;
|
|
76734
|
-
if (!apiKey) {
|
|
77035
|
+
if (!apiKey && resolveEmbedderKind() !== "local") {
|
|
76735
77036
|
throw userError("OPENAI_API_KEY (or CEREFOX_OPENAI_API_KEY) is required for search.", "Set the key in your .env, or run `cerefox init` to bootstrap.");
|
|
76736
77037
|
}
|
|
76737
77038
|
try {
|
|
@@ -77046,7 +77347,7 @@ import { randomBytes } from "node:crypto";
|
|
|
77046
77347
|
import { spawnSync as spawnSync7 } from "node:child_process";
|
|
77047
77348
|
|
|
77048
77349
|
// src/cli/util/env-file.ts
|
|
77049
|
-
import { copyFileSync as copyFileSync3, existsSync as
|
|
77350
|
+
import { copyFileSync as copyFileSync3, existsSync as existsSync14, readFileSync as readFileSync14, writeFileSync as writeFileSync5 } from "node:fs";
|
|
77050
77351
|
import { dirname as dirname5 } from "node:path";
|
|
77051
77352
|
import { spawnSync as spawnSync6 } from "node:child_process";
|
|
77052
77353
|
function escapeRegExp(s) {
|
|
@@ -77056,12 +77357,12 @@ function upsertEnvVar(path, key, value, opts = {}) {
|
|
|
77056
77357
|
const line = `${key}=${value}`;
|
|
77057
77358
|
const header = opts.comment ? `# ${opts.comment}
|
|
77058
77359
|
` : "";
|
|
77059
|
-
if (!
|
|
77360
|
+
if (!existsSync14(path)) {
|
|
77060
77361
|
writeFileSync5(path, `${header}${line}
|
|
77061
77362
|
`, { mode: 384 });
|
|
77062
77363
|
return { path, action: "created" };
|
|
77063
77364
|
}
|
|
77064
|
-
const original =
|
|
77365
|
+
const original = readFileSync14(path, "utf8");
|
|
77065
77366
|
let backupPath;
|
|
77066
77367
|
if (!opts.noBackup) {
|
|
77067
77368
|
backupPath = `${path}.pre-cerefox.bak`;
|
|
@@ -77086,9 +77387,9 @@ ${header}${line}
|
|
|
77086
77387
|
return { path, action: action32, backupPath };
|
|
77087
77388
|
}
|
|
77088
77389
|
function readEnvVar(path, key) {
|
|
77089
|
-
if (!
|
|
77390
|
+
if (!existsSync14(path))
|
|
77090
77391
|
return null;
|
|
77091
|
-
const m =
|
|
77392
|
+
const m = readFileSync14(path, "utf8").match(new RegExp(`^\\s*${escapeRegExp(key)}=(.*)$`, "m"));
|
|
77092
77393
|
return m ? m[1].trim() : null;
|
|
77093
77394
|
}
|
|
77094
77395
|
function envGitignoreWarning(path) {
|
|
@@ -78556,8 +78857,8 @@ var _baseMimes = {
|
|
|
78556
78857
|
var baseMimes = _baseMimes;
|
|
78557
78858
|
|
|
78558
78859
|
// ../../node_modules/.bun/@hono+node-server@2.0.8+68404363cdc13251/node_modules/@hono/node-server/dist/serve-static.mjs
|
|
78559
|
-
import { createReadStream, existsSync as
|
|
78560
|
-
import { join as
|
|
78860
|
+
import { createReadStream, existsSync as existsSync15, statSync as statSync5 } from "node:fs";
|
|
78861
|
+
import { join as join13 } from "node:path";
|
|
78561
78862
|
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;
|
|
78562
78863
|
var ENCODINGS = {
|
|
78563
78864
|
br: ".br",
|
|
@@ -78589,7 +78890,7 @@ var tryDecodeURI = (str) => tryDecode(str, decodeURI);
|
|
|
78589
78890
|
var serveStatic = (options = { root: "" }) => {
|
|
78590
78891
|
const root = options.root || "";
|
|
78591
78892
|
const optionPath = options.path;
|
|
78592
|
-
if (root !== "" && !
|
|
78893
|
+
if (root !== "" && !existsSync15(root))
|
|
78593
78894
|
console.error(`serveStatic: root path '${root}' is not found, are you sure it's correct?`);
|
|
78594
78895
|
return async (c2, next) => {
|
|
78595
78896
|
if (c2.finalized)
|
|
@@ -78606,11 +78907,11 @@ var serveStatic = (options = { root: "" }) => {
|
|
|
78606
78907
|
await options.onNotFound?.(c2.req.path, c2);
|
|
78607
78908
|
return next();
|
|
78608
78909
|
}
|
|
78609
|
-
let path =
|
|
78910
|
+
let path = join13(root, !optionPath && options.rewriteRequestPath ? options.rewriteRequestPath(filename, c2) : filename);
|
|
78610
78911
|
let stats = getStats(path);
|
|
78611
78912
|
if (stats && stats.isDirectory()) {
|
|
78612
78913
|
const indexFile = options.index ?? "index.html";
|
|
78613
|
-
path =
|
|
78914
|
+
path = join13(path, indexFile);
|
|
78614
78915
|
stats = getStats(path);
|
|
78615
78916
|
}
|
|
78616
78917
|
if (!stats) {
|
|
@@ -78667,9 +78968,9 @@ var serveStatic = (options = { root: "" }) => {
|
|
|
78667
78968
|
};
|
|
78668
78969
|
|
|
78669
78970
|
// src/web/server.ts
|
|
78670
|
-
import { existsSync as
|
|
78671
|
-
import { readFileSync as
|
|
78672
|
-
import { join as
|
|
78971
|
+
import { existsSync as existsSync19 } from "node:fs";
|
|
78972
|
+
import { readFileSync as readFileSync17 } from "node:fs";
|
|
78973
|
+
import { join as join17 } from "node:path";
|
|
78673
78974
|
|
|
78674
78975
|
// ../../node_modules/.bun/hono@4.12.29/node_modules/hono/dist/compose.js
|
|
78675
78976
|
var compose = (middleware, onError, onNotFound) => {
|
|
@@ -80698,7 +80999,7 @@ async function runSearch(ctx, opts) {
|
|
|
80698
80999
|
throw error4;
|
|
80699
81000
|
return (data2 ?? []).map(projectChunkResult);
|
|
80700
81001
|
}
|
|
80701
|
-
if (!ctx.openAiApiKey) {
|
|
81002
|
+
if (!ctx.openAiApiKey && resolveEmbedderKind() !== "local") {
|
|
80702
81003
|
throw new HttpError(503, "Embedder not available");
|
|
80703
81004
|
}
|
|
80704
81005
|
const embedding = await getEmbedding(query, ctx.openAiApiKey);
|
|
@@ -81239,7 +81540,6 @@ function registerDocumentReadRoutes(app, ctx) {
|
|
|
81239
81540
|
return c2.json({ exists: false });
|
|
81240
81541
|
});
|
|
81241
81542
|
}
|
|
81242
|
-
|
|
81243
81543
|
// src/web/routes/documents-write.ts
|
|
81244
81544
|
async function createAuditEntry(ctx, args) {
|
|
81245
81545
|
try {
|
|
@@ -81290,7 +81590,7 @@ function registerDocumentWriteRoutes(app, ctx) {
|
|
|
81290
81590
|
const proposedHash = content.trim() ? contentHash(content) : null;
|
|
81291
81591
|
const contentChanged = proposedHash !== null && currentHash !== null && proposedHash !== currentHash;
|
|
81292
81592
|
if (contentChanged) {
|
|
81293
|
-
if (!ctx.openAiApiKey) {
|
|
81593
|
+
if (!ctx.openAiApiKey && resolveEmbedderKind() !== "local") {
|
|
81294
81594
|
return c2.json({
|
|
81295
81595
|
success: false,
|
|
81296
81596
|
error: "Embedder not available — set OPENAI_API_KEY in your config"
|
|
@@ -81446,14 +81746,13 @@ function registerDocumentWriteRoutes(app, ctx) {
|
|
|
81446
81746
|
return c2.json({ archived });
|
|
81447
81747
|
});
|
|
81448
81748
|
}
|
|
81449
|
-
|
|
81450
81749
|
// src/web/routes/ingest.ts
|
|
81451
81750
|
function notReady(error3) {
|
|
81452
81751
|
return { success: false, error: error3 };
|
|
81453
81752
|
}
|
|
81454
81753
|
function registerIngestRoutes(app, ctx) {
|
|
81455
81754
|
app.post("/api/v1/ingest", async (c2) => {
|
|
81456
|
-
if (!ctx.openAiApiKey) {
|
|
81755
|
+
if (!ctx.openAiApiKey && resolveEmbedderKind() !== "local") {
|
|
81457
81756
|
return c2.json(notReady("Embedder not available"), 503);
|
|
81458
81757
|
}
|
|
81459
81758
|
let body;
|
|
@@ -81501,7 +81800,7 @@ function registerIngestRoutes(app, ctx) {
|
|
|
81501
81800
|
}
|
|
81502
81801
|
});
|
|
81503
81802
|
app.post("/api/v1/ingest/file", async (c2) => {
|
|
81504
|
-
if (!ctx.openAiApiKey) {
|
|
81803
|
+
if (!ctx.openAiApiKey && resolveEmbedderKind() !== "local") {
|
|
81505
81804
|
return c2.json(notReady("Embedder not available"), 503);
|
|
81506
81805
|
}
|
|
81507
81806
|
let form;
|
|
@@ -81563,7 +81862,7 @@ function registerIngestRoutes(app, ctx) {
|
|
|
81563
81862
|
}
|
|
81564
81863
|
});
|
|
81565
81864
|
app.post("/api/v1/documents/:document_id/upload", async (c2) => {
|
|
81566
|
-
if (!ctx.openAiApiKey) {
|
|
81865
|
+
if (!ctx.openAiApiKey && resolveEmbedderKind() !== "local") {
|
|
81567
81866
|
return c2.json(notReady("Embedder not available"), 503);
|
|
81568
81867
|
}
|
|
81569
81868
|
const documentId = c2.req.param("document_id");
|
|
@@ -81618,12 +81917,12 @@ import { execFileSync } from "node:child_process";
|
|
|
81618
81917
|
|
|
81619
81918
|
// src/web/docs.ts
|
|
81620
81919
|
import {
|
|
81621
|
-
existsSync as
|
|
81622
|
-
readFileSync as
|
|
81920
|
+
existsSync as existsSync16,
|
|
81921
|
+
readFileSync as readFileSync15,
|
|
81623
81922
|
readdirSync as readdirSync6,
|
|
81624
81923
|
statSync as statSync6
|
|
81625
81924
|
} from "node:fs";
|
|
81626
|
-
import { basename as basename5, dirname as dirname6, join as
|
|
81925
|
+
import { basename as basename5, dirname as dirname6, join as join14, resolve as resolve5 } from "node:path";
|
|
81627
81926
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
81628
81927
|
var TOP_LEVEL_DOCS = [
|
|
81629
81928
|
{ filename: "README.md", path: "README.md", category: "readme" },
|
|
@@ -81644,32 +81943,32 @@ function moduleDir2() {
|
|
|
81644
81943
|
function resolveDocsRoots() {
|
|
81645
81944
|
const here = moduleDir2();
|
|
81646
81945
|
const pkgRootCandidates = [
|
|
81647
|
-
|
|
81648
|
-
|
|
81946
|
+
join14(here, "..", ".."),
|
|
81947
|
+
join14(here, "..", "..", "..", "..")
|
|
81649
81948
|
];
|
|
81650
81949
|
let pkgGuides = null;
|
|
81651
81950
|
let pkgTopLevel = null;
|
|
81652
81951
|
for (const pkg of pkgRootCandidates) {
|
|
81653
|
-
const guides =
|
|
81654
|
-
if (
|
|
81952
|
+
const guides = join14(pkg, "docs", "guides");
|
|
81953
|
+
if (existsSync16(guides) && statSync6(guides).isDirectory()) {
|
|
81655
81954
|
pkgGuides = guides;
|
|
81656
81955
|
pkgTopLevel = pkg;
|
|
81657
81956
|
break;
|
|
81658
81957
|
}
|
|
81659
81958
|
}
|
|
81660
|
-
const repoCandidate =
|
|
81661
|
-
const repoGuides =
|
|
81959
|
+
const repoCandidate = join14(here, "..", "..", "..", "..");
|
|
81960
|
+
const repoGuides = join14(repoCandidate, "docs", "guides");
|
|
81662
81961
|
const repoTopLevel = repoCandidate;
|
|
81663
81962
|
return {
|
|
81664
81963
|
pkgGuides,
|
|
81665
81964
|
pkgTopLevel,
|
|
81666
|
-
repoGuides:
|
|
81667
|
-
repoTopLevel:
|
|
81965
|
+
repoGuides: existsSync16(repoGuides) ? repoGuides : null,
|
|
81966
|
+
repoTopLevel: existsSync16(join14(repoTopLevel, "README.md")) ? repoTopLevel : null
|
|
81668
81967
|
};
|
|
81669
81968
|
}
|
|
81670
81969
|
function readH1(filePath) {
|
|
81671
81970
|
try {
|
|
81672
|
-
const content =
|
|
81971
|
+
const content = readFileSync15(filePath, "utf8");
|
|
81673
81972
|
const match2 = content.match(/^#\s+(.+?)\s*$/m);
|
|
81674
81973
|
return match2 ? match2[1] : null;
|
|
81675
81974
|
} catch {
|
|
@@ -81689,8 +81988,8 @@ function listBundledDocs2() {
|
|
|
81689
81988
|
const topRoot = pkgTopLevel ?? repoTopLevel;
|
|
81690
81989
|
if (topRoot) {
|
|
81691
81990
|
for (const t of TOP_LEVEL_DOCS) {
|
|
81692
|
-
const abs =
|
|
81693
|
-
if (
|
|
81991
|
+
const abs = join14(topRoot, t.filename);
|
|
81992
|
+
if (existsSync16(abs)) {
|
|
81694
81993
|
entries.push(entryForFile(abs, t.path, t.category));
|
|
81695
81994
|
}
|
|
81696
81995
|
}
|
|
@@ -81699,7 +81998,7 @@ function listBundledDocs2() {
|
|
|
81699
81998
|
if (guidesRoot) {
|
|
81700
81999
|
const names = readdirSync6(guidesRoot).filter((n) => n.endsWith(".md")).sort();
|
|
81701
82000
|
for (const name of names) {
|
|
81702
|
-
const abs =
|
|
82001
|
+
const abs = join14(guidesRoot, name);
|
|
81703
82002
|
entries.push(entryForFile(abs, `guides/${name}`, "guide"));
|
|
81704
82003
|
}
|
|
81705
82004
|
}
|
|
@@ -81717,9 +82016,9 @@ function readDoc(docPath) {
|
|
|
81717
82016
|
if (!candidate.startsWith(rootResolved + "/") && candidate !== rootResolved) {
|
|
81718
82017
|
return null;
|
|
81719
82018
|
}
|
|
81720
|
-
if (
|
|
82019
|
+
if (existsSync16(candidate) && statSync6(candidate).isFile()) {
|
|
81721
82020
|
try {
|
|
81722
|
-
return
|
|
82021
|
+
return readFileSync15(candidate, "utf8");
|
|
81723
82022
|
} catch {
|
|
81724
82023
|
return null;
|
|
81725
82024
|
}
|
|
@@ -81728,6 +82027,7 @@ function readDoc(docPath) {
|
|
|
81728
82027
|
}
|
|
81729
82028
|
|
|
81730
82029
|
// src/web/routes/meta.ts
|
|
82030
|
+
init_compatibility();
|
|
81731
82031
|
function resolveGitCommitShort() {
|
|
81732
82032
|
const env4 = process.env.CEREFOX_GIT_COMMIT;
|
|
81733
82033
|
if (env4)
|
|
@@ -81747,7 +82047,7 @@ var VERSION_INFO = {
|
|
|
81747
82047
|
git_commit_short: resolveGitCommitShort(),
|
|
81748
82048
|
build_date: process.env.CEREFOX_BUILD_DATE ?? null
|
|
81749
82049
|
};
|
|
81750
|
-
var
|
|
82050
|
+
var SCHEMA_VERSION_RE3 = /^--\s*@version:\s*(\S+)/m;
|
|
81751
82051
|
function registerMetaRoutes(app, ctx) {
|
|
81752
82052
|
app.get("/api/v1/version", (c2) => c2.json(VERSION_INFO));
|
|
81753
82053
|
app.get("/api/v1/docs", (c2) => c2.json(listBundledDocs2()));
|
|
@@ -81764,18 +82064,18 @@ function registerMetaRoutes(app, ctx) {
|
|
|
81764
82064
|
app.get("/api/v1/schema-version", async (c2) => {
|
|
81765
82065
|
let bundled = null;
|
|
81766
82066
|
try {
|
|
81767
|
-
const { readFileSync:
|
|
82067
|
+
const { readFileSync: readFileSync16, existsSync: existsSync17 } = await import("node:fs");
|
|
81768
82068
|
const { fileURLToPath: fileURLToPath4 } = await import("node:url");
|
|
81769
|
-
const { dirname: dirname7, join:
|
|
82069
|
+
const { dirname: dirname7, join: join15 } = await import("node:path");
|
|
81770
82070
|
const here = dirname7(fileURLToPath4(import.meta.url));
|
|
81771
82071
|
const candidates = [
|
|
81772
|
-
|
|
81773
|
-
|
|
82072
|
+
join15(here, "..", "..", "..", "db", "schema.sql"),
|
|
82073
|
+
join15(here, "..", "..", "..", "..", "..", "src", "cerefox", "db", "schema.sql")
|
|
81774
82074
|
];
|
|
81775
82075
|
for (const path of candidates) {
|
|
81776
|
-
if (
|
|
81777
|
-
const sql =
|
|
81778
|
-
const match2 = sql.match(
|
|
82076
|
+
if (existsSync17(path)) {
|
|
82077
|
+
const sql = readFileSync16(path, "utf8");
|
|
82078
|
+
const match2 = sql.match(SCHEMA_VERSION_RE3);
|
|
81779
82079
|
bundled = match2 ? match2[1] : null;
|
|
81780
82080
|
break;
|
|
81781
82081
|
}
|
|
@@ -81870,17 +82170,17 @@ function registerPostgrestProxy(app) {
|
|
|
81870
82170
|
|
|
81871
82171
|
// src/web/routes/preferences.ts
|
|
81872
82172
|
init_config();
|
|
81873
|
-
import { existsSync as
|
|
81874
|
-
import { join as
|
|
82173
|
+
import { existsSync as existsSync17, mkdirSync as mkdirSync5, readFileSync as readFileSync16, writeFileSync as writeFileSync6 } from "node:fs";
|
|
82174
|
+
import { join as join15 } from "node:path";
|
|
81875
82175
|
function isTheme(v) {
|
|
81876
82176
|
return v === "auto" || v === "light" || v === "dark";
|
|
81877
82177
|
}
|
|
81878
82178
|
function prefsFile() {
|
|
81879
|
-
return
|
|
82179
|
+
return join15(userStateDir(), "web-prefs.json");
|
|
81880
82180
|
}
|
|
81881
82181
|
function readPrefs() {
|
|
81882
82182
|
try {
|
|
81883
|
-
const raw2 = JSON.parse(
|
|
82183
|
+
const raw2 = JSON.parse(readFileSync16(prefsFile(), "utf8"));
|
|
81884
82184
|
if (isTheme(raw2.theme))
|
|
81885
82185
|
return { theme: raw2.theme };
|
|
81886
82186
|
} catch {}
|
|
@@ -81896,8 +82196,8 @@ function registerPreferencesRoutes(app) {
|
|
|
81896
82196
|
const next = { ...readPrefs(), theme: body.theme };
|
|
81897
82197
|
try {
|
|
81898
82198
|
const dir = userStateDir();
|
|
81899
|
-
if (!
|
|
81900
|
-
|
|
82199
|
+
if (!existsSync17(dir))
|
|
82200
|
+
mkdirSync5(dir, { recursive: true });
|
|
81901
82201
|
writeFileSync6(prefsFile(), `${JSON.stringify(next, null, 2)}
|
|
81902
82202
|
`);
|
|
81903
82203
|
} catch (err) {
|
|
@@ -81968,21 +82268,21 @@ function registerProjectsRoutes(app, ctx) {
|
|
|
81968
82268
|
}
|
|
81969
82269
|
|
|
81970
82270
|
// src/web/static.ts
|
|
81971
|
-
import { existsSync as
|
|
81972
|
-
import { dirname as dirname7, join as
|
|
82271
|
+
import { existsSync as existsSync18, statSync as statSync7 } from "node:fs";
|
|
82272
|
+
import { dirname as dirname7, join as join16 } from "node:path";
|
|
81973
82273
|
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
81974
82274
|
function moduleDir3() {
|
|
81975
82275
|
return dirname7(fileURLToPath4(import.meta.url));
|
|
81976
82276
|
}
|
|
81977
82277
|
function isUsableSpaDir(dir) {
|
|
81978
|
-
return
|
|
82278
|
+
return existsSync18(dir) && statSync7(dir).isDirectory() && existsSync18(join16(dir, "index.html"));
|
|
81979
82279
|
}
|
|
81980
82280
|
function resolveSpaDist() {
|
|
81981
82281
|
const here = moduleDir3();
|
|
81982
82282
|
const candidates = [
|
|
81983
|
-
|
|
81984
|
-
|
|
81985
|
-
|
|
82283
|
+
join16(here, "..", "frontend"),
|
|
82284
|
+
join16(here, "..", "..", "..", "..", "frontend", "dist"),
|
|
82285
|
+
join16(here, "..", "..", "dist", "frontend")
|
|
81986
82286
|
];
|
|
81987
82287
|
for (const c2 of candidates) {
|
|
81988
82288
|
if (isUsableSpaDir(c2))
|
|
@@ -81993,11 +82293,11 @@ function resolveSpaDist() {
|
|
|
81993
82293
|
function resolveStaticDir() {
|
|
81994
82294
|
const here = moduleDir3();
|
|
81995
82295
|
const candidates = [
|
|
81996
|
-
|
|
81997
|
-
|
|
82296
|
+
join16(here, "..", "static"),
|
|
82297
|
+
join16(here, "..", "..", "..", "..", "web", "static")
|
|
81998
82298
|
];
|
|
81999
82299
|
for (const c2 of candidates) {
|
|
82000
|
-
if (
|
|
82300
|
+
if (existsSync18(c2) && statSync7(c2).isDirectory())
|
|
82001
82301
|
return c2;
|
|
82002
82302
|
}
|
|
82003
82303
|
return null;
|
|
@@ -82042,6 +82342,7 @@ var ROOT_REDIRECT_HTML = `<!DOCTYPE html>
|
|
|
82042
82342
|
init_meta();
|
|
82043
82343
|
init_cli_core();
|
|
82044
82344
|
init_config();
|
|
82345
|
+
init_compatibility();
|
|
82045
82346
|
function buildApp(ctx = buildWebContext()) {
|
|
82046
82347
|
const app = new Hono2;
|
|
82047
82348
|
if (true) {
|
|
@@ -82083,9 +82384,9 @@ function buildApp(ctx = buildWebContext()) {
|
|
|
82083
82384
|
root: spaDist,
|
|
82084
82385
|
rewriteRequestPath: (path) => path.replace(/^\/app/, "") || "/"
|
|
82085
82386
|
}));
|
|
82086
|
-
const indexPath =
|
|
82087
|
-
if (
|
|
82088
|
-
const indexHtml =
|
|
82387
|
+
const indexPath = join17(spaDist, "index.html");
|
|
82388
|
+
if (existsSync19(indexPath)) {
|
|
82389
|
+
const indexHtml = readFileSync17(indexPath, "utf8");
|
|
82089
82390
|
app.get("/app/*", (c2) => c2.html(indexHtml));
|
|
82090
82391
|
}
|
|
82091
82392
|
}
|
|
@@ -82143,28 +82444,28 @@ async function buildWebServer(options = {}) {
|
|
|
82143
82444
|
// src/web/daemon.ts
|
|
82144
82445
|
import { spawn } from "node:child_process";
|
|
82145
82446
|
import {
|
|
82146
|
-
existsSync as
|
|
82147
|
-
mkdirSync as
|
|
82447
|
+
existsSync as existsSync20,
|
|
82448
|
+
mkdirSync as mkdirSync6,
|
|
82148
82449
|
openSync,
|
|
82149
|
-
readFileSync as
|
|
82450
|
+
readFileSync as readFileSync18,
|
|
82150
82451
|
rmSync,
|
|
82151
82452
|
writeFileSync as writeFileSync7
|
|
82152
82453
|
} from "node:fs";
|
|
82153
|
-
import { homedir as
|
|
82154
|
-
import { join as
|
|
82155
|
-
var STATE_DIR =
|
|
82156
|
-
var PID_FILE =
|
|
82157
|
-
var LOG_FILE =
|
|
82454
|
+
import { homedir as homedir9 } from "node:os";
|
|
82455
|
+
import { join as join18 } from "node:path";
|
|
82456
|
+
var STATE_DIR = join18(homedir9(), ".cerefox");
|
|
82457
|
+
var PID_FILE = join18(STATE_DIR, "web.pid");
|
|
82458
|
+
var LOG_FILE = join18(STATE_DIR, "web.log");
|
|
82158
82459
|
var daemonPaths = { stateDir: STATE_DIR, pidFile: PID_FILE, logFile: LOG_FILE };
|
|
82159
82460
|
function ensureStateDir() {
|
|
82160
|
-
if (!
|
|
82161
|
-
|
|
82461
|
+
if (!existsSync20(STATE_DIR))
|
|
82462
|
+
mkdirSync6(STATE_DIR, { recursive: true });
|
|
82162
82463
|
}
|
|
82163
82464
|
function readPidFile() {
|
|
82164
|
-
if (!
|
|
82465
|
+
if (!existsSync20(PID_FILE))
|
|
82165
82466
|
return null;
|
|
82166
82467
|
try {
|
|
82167
|
-
const parsed = JSON.parse(
|
|
82468
|
+
const parsed = JSON.parse(readFileSync18(PID_FILE, "utf8"));
|
|
82168
82469
|
if (typeof parsed.pid !== "number")
|
|
82169
82470
|
return null;
|
|
82170
82471
|
return {
|
|
@@ -82475,6 +82776,7 @@ Learn more:
|
|
|
82475
82776
|
registerConfigureAgent(program2);
|
|
82476
82777
|
registerSelfUpdate(program2);
|
|
82477
82778
|
registerMcp(program2);
|
|
82779
|
+
registerEmbedderWarmup(program2);
|
|
82478
82780
|
registerWeb(program2);
|
|
82479
82781
|
registerCompletion(program2);
|
|
82480
82782
|
registerToken(program2);
|
|
@@ -82528,7 +82830,7 @@ Learn more:
|
|
|
82528
82830
|
|
|
82529
82831
|
// src/bin/cerefox.ts
|
|
82530
82832
|
async function bareEntryPoint() {
|
|
82531
|
-
const { existsSync:
|
|
82833
|
+
const { existsSync: existsSync21 } = await import("node:fs");
|
|
82532
82834
|
const { resolveEnvFile: resolveEnvFile2 } = await Promise.resolve().then(() => (init_config(), exports_config));
|
|
82533
82835
|
const { c: c2, println: println2 } = await Promise.resolve().then(() => (init_cli_core(), exports_cli_core));
|
|
82534
82836
|
const { PKG_VERSION: PKG_VERSION2 } = await Promise.resolve().then(() => (init_meta(), exports_meta));
|
|
@@ -82537,7 +82839,7 @@ async function bareEntryPoint() {
|
|
|
82537
82839
|
println2("");
|
|
82538
82840
|
let configExists = false;
|
|
82539
82841
|
try {
|
|
82540
|
-
configExists =
|
|
82842
|
+
configExists = existsSync21(resolveEnvFile2());
|
|
82541
82843
|
} catch {}
|
|
82542
82844
|
if (!configExists) {
|
|
82543
82845
|
println2(c2.yellow("⚠ No config detected."));
|