@cerefox/memory 1.17.3 → 1.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/bin/cerefox.js +699 -469
- package/dist/frontend/assets/{index-D7YyXio_.js → index-CxMT7hjH.js} +10 -10
- package/dist/frontend/assets/{index-D7YyXio_.js.map → index-CxMT7hjH.js.map} +1 -1
- package/dist/frontend/index.html +1 -1
- package/dist/server-assets/_shared/ef-meta/index.ts +2 -2
- package/dist/server-assets/db/migrations/0012_content_format.sql +1 -1
- package/dist/server-assets/db/migrations/0014_document_relations.sql +1 -1
- package/dist/server-assets/db/migrations/0020_ingest_preserves_source.sql +1 -1
- package/dist/server-assets/db/migrations/0022_rls_on_document_relations.sql +1 -1
- package/dist/server-assets/db/migrations/0032_derive_grants.sql +1 -1
- package/dist/server-assets/db/migrations/0034_drop_vector_indexes.sql +22 -0
- package/dist/server-assets/db/rpcs.sql +9 -6
- package/dist/server-assets/db/schema.sql +9 -15
- package/docs/api/openapi.json +16 -2
- package/docs/guides/access-paths.md +7 -3
- package/docs/guides/api.md +1 -1
- package/docs/guides/cli.md +2 -2
- package/docs/guides/configuration.md +22 -1
- package/docs/guides/connect-agents.md +42 -18
- package/docs/guides/quickstart.md +7 -3
- package/docs/guides/setup-supabase.md +5 -0
- package/docs/guides/upgrading.md +2 -1
- package/package.json +2 -2
package/dist/bin/cerefox.js
CHANGED
|
@@ -5318,7 +5318,7 @@ var init_cli_core = __esm(() => {
|
|
|
5318
5318
|
});
|
|
5319
5319
|
|
|
5320
5320
|
// src/meta.ts
|
|
5321
|
-
var PKG_VERSION = "1.
|
|
5321
|
+
var PKG_VERSION = "1.18.0";
|
|
5322
5322
|
var init_meta = () => {};
|
|
5323
5323
|
|
|
5324
5324
|
// ../../_shared/config/paths.ts
|
|
@@ -26229,10 +26229,6 @@ var init_bundled_docs = __esm(() => {
|
|
|
26229
26229
|
PACKAGE_ROOT = findPackageRoot();
|
|
26230
26230
|
});
|
|
26231
26231
|
|
|
26232
|
-
// ../../_shared/ef-meta/index.ts
|
|
26233
|
-
var EF_VERSION = "1.17.3", CEREFOX_VERSION = "1.17.3", EF_LAST_CHANGED = "1.17.3";
|
|
26234
|
-
var init_ef_meta = () => {};
|
|
26235
|
-
|
|
26236
26232
|
// ../../_shared/compatibility/index.ts
|
|
26237
26233
|
function compareSemver(a, b) {
|
|
26238
26234
|
const split = (v) => {
|
|
@@ -26366,6 +26362,425 @@ var init_compatibility = __esm(() => {
|
|
|
26366
26362
|
};
|
|
26367
26363
|
});
|
|
26368
26364
|
|
|
26365
|
+
// ../../node_modules/.bun/@hono+node-server@2.1.1+2ac783cc5e75a70c/node_modules/@hono/node-server/dist/conninfo.mjs
|
|
26366
|
+
var getConnInfo = (c) => {
|
|
26367
|
+
const bindings = c.env.server ? c.env.server : c.env;
|
|
26368
|
+
const address = bindings.incoming.socket.remoteAddress;
|
|
26369
|
+
const port = bindings.incoming.socket.remotePort;
|
|
26370
|
+
const family = bindings.incoming.socket.remoteFamily;
|
|
26371
|
+
return { remote: {
|
|
26372
|
+
address,
|
|
26373
|
+
port,
|
|
26374
|
+
addressType: family === "IPv4" ? "IPv4" : family === "IPv6" ? "IPv6" : undefined
|
|
26375
|
+
} };
|
|
26376
|
+
};
|
|
26377
|
+
var init_conninfo = () => {};
|
|
26378
|
+
|
|
26379
|
+
// ../../_shared/mcp-auth/index.ts
|
|
26380
|
+
function constantTimeEqual(a, b) {
|
|
26381
|
+
const ab = new TextEncoder().encode(a);
|
|
26382
|
+
const bb = new TextEncoder().encode(b);
|
|
26383
|
+
const len = Math.max(ab.length, bb.length);
|
|
26384
|
+
let diff = ab.length ^ bb.length;
|
|
26385
|
+
for (let i = 0;i < len; i++) {
|
|
26386
|
+
diff |= (ab[i] ?? 0) ^ (bb[i] ?? 0);
|
|
26387
|
+
}
|
|
26388
|
+
return diff === 0;
|
|
26389
|
+
}
|
|
26390
|
+
|
|
26391
|
+
// ../../_shared/ef-auth/index.ts
|
|
26392
|
+
function parseAccessTokens(raw) {
|
|
26393
|
+
if (!raw)
|
|
26394
|
+
return [];
|
|
26395
|
+
return raw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
26396
|
+
}
|
|
26397
|
+
function checkAccessToken(authorizationHeader, config) {
|
|
26398
|
+
if (!authorizationHeader || !authorizationHeader.startsWith(BEARER_PREFIX)) {
|
|
26399
|
+
return { ok: false, reason: "no_token" };
|
|
26400
|
+
}
|
|
26401
|
+
const token = authorizationHeader.slice(BEARER_PREFIX.length).trim();
|
|
26402
|
+
if (!token)
|
|
26403
|
+
return { ok: false, reason: "no_token" };
|
|
26404
|
+
if (config.tokens.length === 0) {
|
|
26405
|
+
return {
|
|
26406
|
+
ok: false,
|
|
26407
|
+
reason: "no_tokens_configured",
|
|
26408
|
+
detail: "CEREFOX_ACCESS_TOKENS is unset/empty; refusing to accept-all"
|
|
26409
|
+
};
|
|
26410
|
+
}
|
|
26411
|
+
let matched = false;
|
|
26412
|
+
for (const accepted of config.tokens) {
|
|
26413
|
+
if (constantTimeEqual(token, accepted))
|
|
26414
|
+
matched = true;
|
|
26415
|
+
}
|
|
26416
|
+
return matched ? { ok: true } : { ok: false, reason: "bad_token" };
|
|
26417
|
+
}
|
|
26418
|
+
var BEARER_PREFIX = "Bearer ";
|
|
26419
|
+
var init_ef_auth = () => {};
|
|
26420
|
+
|
|
26421
|
+
// src/web/auth.ts
|
|
26422
|
+
import { existsSync as existsSync9 } from "node:fs";
|
|
26423
|
+
function isContainerised() {
|
|
26424
|
+
try {
|
|
26425
|
+
return existsSync9("/.dockerenv");
|
|
26426
|
+
} catch {
|
|
26427
|
+
return false;
|
|
26428
|
+
}
|
|
26429
|
+
}
|
|
26430
|
+
function containerGateWarning(env = process.env) {
|
|
26431
|
+
const hasKey = (env.CEREFOX_API_KEY ?? "").trim() !== "";
|
|
26432
|
+
const requireAll = (env.CEREFOX_API_REQUIRE_KEY ?? "") === "1";
|
|
26433
|
+
if (!hasKey || requireAll || !isContainerised())
|
|
26434
|
+
return null;
|
|
26435
|
+
return `
|
|
26436
|
+
⚠ CEREFOX_API_KEY is set inside a container without CEREFOX_API_REQUIRE_KEY=1.
|
|
26437
|
+
` + ` Docker rewrites the source address of every published-port request, so the
|
|
26438
|
+
` + ` loopback exemption cannot match and EVERY caller will get a 401 — including
|
|
26439
|
+
` + ` the web UI. In a container the gate must be all-or-nothing:
|
|
26440
|
+
` + ` • publishing on 127.0.0.1 → leave CEREFOX_API_KEY unset (the bind is the boundary)
|
|
26441
|
+
` + ` • publishing wider → also set CEREFOX_API_REQUIRE_KEY=1
|
|
26442
|
+
`;
|
|
26443
|
+
}
|
|
26444
|
+
function isLoopbackAddress(address) {
|
|
26445
|
+
if (!address)
|
|
26446
|
+
return false;
|
|
26447
|
+
return LOOPBACK_ADDRESSES.has(address.trim().toLowerCase());
|
|
26448
|
+
}
|
|
26449
|
+
function decideAuth(input) {
|
|
26450
|
+
const keys = input.configuredKeys.trim();
|
|
26451
|
+
if (!keys)
|
|
26452
|
+
return { allow: true, reason: "disabled" };
|
|
26453
|
+
const local = isLoopbackAddress(input.remoteAddress);
|
|
26454
|
+
if (local && !input.requireKeyEverywhere) {
|
|
26455
|
+
return { allow: true, reason: "loopback" };
|
|
26456
|
+
}
|
|
26457
|
+
const result = checkAccessToken(input.authorization, {
|
|
26458
|
+
tokens: parseAccessTokens(keys)
|
|
26459
|
+
});
|
|
26460
|
+
if (result.ok)
|
|
26461
|
+
return { allow: true, reason: "valid_key" };
|
|
26462
|
+
if (result.reason === "no_token") {
|
|
26463
|
+
return {
|
|
26464
|
+
allow: false,
|
|
26465
|
+
reason: "no_key",
|
|
26466
|
+
message: local ? "This server requires an API key on every request (CEREFOX_API_REQUIRE_KEY is set). " + "Send it as `Authorization: Bearer <key>`." : "This request did not come from the local machine, so it needs the server's API key " + "as `Authorization: Bearer <key>`. Print it with `cerefox api-key show` " + "(or `cerefox-local api-key` for a container install)."
|
|
26467
|
+
};
|
|
26468
|
+
}
|
|
26469
|
+
return {
|
|
26470
|
+
allow: false,
|
|
26471
|
+
reason: "bad_key",
|
|
26472
|
+
message: "The API key presented is not valid for this server."
|
|
26473
|
+
};
|
|
26474
|
+
}
|
|
26475
|
+
function apiAuth() {
|
|
26476
|
+
return async (c, next) => {
|
|
26477
|
+
const decision = decideAuth({
|
|
26478
|
+
remoteAddress: remoteAddressOf(c),
|
|
26479
|
+
authorization: c.req.header("Authorization") ?? null,
|
|
26480
|
+
configuredKeys: process.env.CEREFOX_API_KEY ?? "",
|
|
26481
|
+
requireKeyEverywhere: (process.env.CEREFOX_API_REQUIRE_KEY ?? "") === "1"
|
|
26482
|
+
});
|
|
26483
|
+
if (decision.allow)
|
|
26484
|
+
return next();
|
|
26485
|
+
return c.json({ detail: decision.message }, 401, {
|
|
26486
|
+
"WWW-Authenticate": 'Bearer realm="cerefox"'
|
|
26487
|
+
});
|
|
26488
|
+
};
|
|
26489
|
+
}
|
|
26490
|
+
function remoteAddressOf(c) {
|
|
26491
|
+
try {
|
|
26492
|
+
return getConnInfo(c).remote.address;
|
|
26493
|
+
} catch {
|
|
26494
|
+
return;
|
|
26495
|
+
}
|
|
26496
|
+
}
|
|
26497
|
+
var API_KEY_PREFIX = "cfx_lak_", LOOPBACK_ADDRESSES;
|
|
26498
|
+
var init_auth = __esm(() => {
|
|
26499
|
+
init_conninfo();
|
|
26500
|
+
init_ef_auth();
|
|
26501
|
+
LOOPBACK_ADDRESSES = new Set([
|
|
26502
|
+
"127.0.0.1",
|
|
26503
|
+
"::1",
|
|
26504
|
+
"::ffff:127.0.0.1"
|
|
26505
|
+
]);
|
|
26506
|
+
});
|
|
26507
|
+
|
|
26508
|
+
// src/web/daemon.ts
|
|
26509
|
+
import { spawn } from "node:child_process";
|
|
26510
|
+
import {
|
|
26511
|
+
existsSync as existsSync10,
|
|
26512
|
+
mkdirSync as mkdirSync3,
|
|
26513
|
+
openSync,
|
|
26514
|
+
readFileSync as readFileSync8,
|
|
26515
|
+
rmSync,
|
|
26516
|
+
writeFileSync as writeFileSync4
|
|
26517
|
+
} from "node:fs";
|
|
26518
|
+
import { homedir as homedir5 } from "node:os";
|
|
26519
|
+
import { join as join8 } from "node:path";
|
|
26520
|
+
function resolveStateDir(override = process.env.CEREFOX_CONFIG_DIR, home = homedir5()) {
|
|
26521
|
+
override = (override ?? "").trim();
|
|
26522
|
+
if (!override)
|
|
26523
|
+
return join8(home, ".cerefox");
|
|
26524
|
+
return override === "~" || override.startsWith("~/") ? join8(home, override.slice(2)) : override;
|
|
26525
|
+
}
|
|
26526
|
+
function ensureStateDir() {
|
|
26527
|
+
if (!existsSync10(STATE_DIR))
|
|
26528
|
+
mkdirSync3(STATE_DIR, { recursive: true });
|
|
26529
|
+
}
|
|
26530
|
+
function readPidFile() {
|
|
26531
|
+
if (!existsSync10(PID_FILE))
|
|
26532
|
+
return null;
|
|
26533
|
+
try {
|
|
26534
|
+
const parsed = JSON.parse(readFileSync8(PID_FILE, "utf8"));
|
|
26535
|
+
if (typeof parsed.pid !== "number")
|
|
26536
|
+
return null;
|
|
26537
|
+
return {
|
|
26538
|
+
pid: parsed.pid,
|
|
26539
|
+
port: typeof parsed.port === "number" ? parsed.port : 8000,
|
|
26540
|
+
host: typeof parsed.host === "string" ? parsed.host : "127.0.0.1",
|
|
26541
|
+
startedAt: typeof parsed.startedAt === "string" ? parsed.startedAt : "unknown"
|
|
26542
|
+
};
|
|
26543
|
+
} catch {
|
|
26544
|
+
return null;
|
|
26545
|
+
}
|
|
26546
|
+
}
|
|
26547
|
+
function writePidFile(info) {
|
|
26548
|
+
ensureStateDir();
|
|
26549
|
+
writeFileSync4(PID_FILE, JSON.stringify(info, null, 2) + `
|
|
26550
|
+
`, "utf8");
|
|
26551
|
+
}
|
|
26552
|
+
function removePidFile() {
|
|
26553
|
+
rmSync(PID_FILE, { force: true });
|
|
26554
|
+
}
|
|
26555
|
+
function isProcessAlive(pid) {
|
|
26556
|
+
try {
|
|
26557
|
+
process.kill(pid, 0);
|
|
26558
|
+
return true;
|
|
26559
|
+
} catch (err) {
|
|
26560
|
+
return err.code === "EPERM";
|
|
26561
|
+
}
|
|
26562
|
+
}
|
|
26563
|
+
async function probeVersion(host, port, timeoutMs = 1500) {
|
|
26564
|
+
const probeHost = host === "0.0.0.0" ? "127.0.0.1" : host;
|
|
26565
|
+
try {
|
|
26566
|
+
const ctrl = new AbortController;
|
|
26567
|
+
const timer = setTimeout(() => ctrl.abort(), timeoutMs);
|
|
26568
|
+
try {
|
|
26569
|
+
const resp = await fetch(`http://${probeHost}:${port}/api/v1/version`, {
|
|
26570
|
+
signal: ctrl.signal
|
|
26571
|
+
});
|
|
26572
|
+
if (!resp.ok)
|
|
26573
|
+
return { responding: false, version: null };
|
|
26574
|
+
const body = await resp.json().catch(() => null);
|
|
26575
|
+
return {
|
|
26576
|
+
responding: true,
|
|
26577
|
+
version: typeof body?.version === "string" ? body.version : null
|
|
26578
|
+
};
|
|
26579
|
+
} finally {
|
|
26580
|
+
clearTimeout(timer);
|
|
26581
|
+
}
|
|
26582
|
+
} catch {
|
|
26583
|
+
return { responding: false, version: null };
|
|
26584
|
+
}
|
|
26585
|
+
}
|
|
26586
|
+
async function isResponding(host, port, timeoutMs = 1500) {
|
|
26587
|
+
return (await probeVersion(host, port, timeoutMs)).responding;
|
|
26588
|
+
}
|
|
26589
|
+
function assertUnix() {
|
|
26590
|
+
if (process.platform === "win32") {
|
|
26591
|
+
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.");
|
|
26592
|
+
}
|
|
26593
|
+
}
|
|
26594
|
+
async function startDaemon(opts) {
|
|
26595
|
+
assertUnix();
|
|
26596
|
+
ensureStateDir();
|
|
26597
|
+
const existing = readPidFile();
|
|
26598
|
+
if (existing && isProcessAlive(existing.pid)) {
|
|
26599
|
+
return existing.port === opts.port ? { kind: "already-running", info: existing } : { kind: "port-conflict", info: existing };
|
|
26600
|
+
}
|
|
26601
|
+
if (existing)
|
|
26602
|
+
removePidFile();
|
|
26603
|
+
const logFd = openSync(LOG_FILE, "a");
|
|
26604
|
+
const child = spawn(opts.runtime, [opts.scriptPath, "web", "--host", opts.host, "--port", String(opts.port)], { detached: true, stdio: ["ignore", logFd, logFd] });
|
|
26605
|
+
child.unref();
|
|
26606
|
+
if (typeof child.pid !== "number") {
|
|
26607
|
+
throw new Error("Failed to spawn the web server process (no pid).");
|
|
26608
|
+
}
|
|
26609
|
+
writePidFile({
|
|
26610
|
+
pid: child.pid,
|
|
26611
|
+
port: opts.port,
|
|
26612
|
+
host: opts.host,
|
|
26613
|
+
startedAt: new Date().toISOString()
|
|
26614
|
+
});
|
|
26615
|
+
let responding = false;
|
|
26616
|
+
for (let i = 0;i < 20; i++) {
|
|
26617
|
+
if (!isProcessAlive(child.pid))
|
|
26618
|
+
break;
|
|
26619
|
+
if (await isResponding(opts.host, opts.port)) {
|
|
26620
|
+
responding = true;
|
|
26621
|
+
break;
|
|
26622
|
+
}
|
|
26623
|
+
await sleep2(250);
|
|
26624
|
+
}
|
|
26625
|
+
return { kind: "started", pid: child.pid, responding };
|
|
26626
|
+
}
|
|
26627
|
+
async function stopDaemon() {
|
|
26628
|
+
assertUnix();
|
|
26629
|
+
const info = readPidFile();
|
|
26630
|
+
if (!info || !isProcessAlive(info.pid)) {
|
|
26631
|
+
removePidFile();
|
|
26632
|
+
return { kind: "not-running" };
|
|
26633
|
+
}
|
|
26634
|
+
try {
|
|
26635
|
+
process.kill(info.pid, "SIGTERM");
|
|
26636
|
+
} catch {}
|
|
26637
|
+
let forced = false;
|
|
26638
|
+
let alive = true;
|
|
26639
|
+
for (let i = 0;i < 12; i++) {
|
|
26640
|
+
await sleep2(250);
|
|
26641
|
+
if (!isProcessAlive(info.pid)) {
|
|
26642
|
+
alive = false;
|
|
26643
|
+
break;
|
|
26644
|
+
}
|
|
26645
|
+
}
|
|
26646
|
+
if (alive) {
|
|
26647
|
+
try {
|
|
26648
|
+
process.kill(info.pid, "SIGKILL");
|
|
26649
|
+
forced = true;
|
|
26650
|
+
} catch {}
|
|
26651
|
+
}
|
|
26652
|
+
removePidFile();
|
|
26653
|
+
return { kind: "stopped", pid: info.pid, forced };
|
|
26654
|
+
}
|
|
26655
|
+
function restartCommand(host, port) {
|
|
26656
|
+
const flags = `${host === "127.0.0.1" ? "" : ` --host ${host}`}${port === 8000 ? "" : ` --port ${port}`}`;
|
|
26657
|
+
return `cerefox web stop && cerefox web start${flags}`;
|
|
26658
|
+
}
|
|
26659
|
+
async function statusDaemon() {
|
|
26660
|
+
const info = readPidFile();
|
|
26661
|
+
if (!info)
|
|
26662
|
+
return { kind: "stopped" };
|
|
26663
|
+
if (!isProcessAlive(info.pid))
|
|
26664
|
+
return { kind: "stale", info };
|
|
26665
|
+
const { responding, version } = await probeVersion(info.host, info.port);
|
|
26666
|
+
return { kind: "running", info, responding, version };
|
|
26667
|
+
}
|
|
26668
|
+
var STATE_DIR, PID_FILE, LOG_FILE, daemonPaths, sleep2 = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
26669
|
+
var init_daemon = __esm(() => {
|
|
26670
|
+
STATE_DIR = resolveStateDir();
|
|
26671
|
+
PID_FILE = join8(STATE_DIR, "web.pid");
|
|
26672
|
+
LOG_FILE = join8(STATE_DIR, "web.log");
|
|
26673
|
+
daemonPaths = { stateDir: STATE_DIR, pidFile: PID_FILE, logFile: LOG_FILE };
|
|
26674
|
+
});
|
|
26675
|
+
|
|
26676
|
+
// src/update-check.ts
|
|
26677
|
+
import { mkdirSync as mkdirSync4, readFileSync as readFileSync9, writeFileSync as writeFileSync5 } from "node:fs";
|
|
26678
|
+
import { dirname as dirname4, join as join9 } from "node:path";
|
|
26679
|
+
function updateCheckDisabled(env = process.env) {
|
|
26680
|
+
const on = (v) => {
|
|
26681
|
+
const t = (v ?? "").trim().toLowerCase();
|
|
26682
|
+
return t !== "" && t !== "0" && t !== "false";
|
|
26683
|
+
};
|
|
26684
|
+
return on(env.CEREFOX_NO_UPDATE_CHECK) || on(env.NO_UPDATE_NOTIFIER) || on(env.CI);
|
|
26685
|
+
}
|
|
26686
|
+
function cachePath() {
|
|
26687
|
+
return join9(resolveStateDir(), "update-check.json");
|
|
26688
|
+
}
|
|
26689
|
+
function readCache(path = cachePath()) {
|
|
26690
|
+
try {
|
|
26691
|
+
const parsed = JSON.parse(readFileSync9(path, "utf8"));
|
|
26692
|
+
if (typeof parsed.latest !== "string" || typeof parsed.checkedAt !== "string")
|
|
26693
|
+
return null;
|
|
26694
|
+
return parsed;
|
|
26695
|
+
} catch {
|
|
26696
|
+
return null;
|
|
26697
|
+
}
|
|
26698
|
+
}
|
|
26699
|
+
function writeCache(cache, path = cachePath()) {
|
|
26700
|
+
try {
|
|
26701
|
+
mkdirSync4(dirname4(path), { recursive: true });
|
|
26702
|
+
writeFileSync5(path, JSON.stringify(cache, null, 2) + `
|
|
26703
|
+
`);
|
|
26704
|
+
} catch {}
|
|
26705
|
+
}
|
|
26706
|
+
async function fetchLatestVersion({ timeoutMs = 3000, fetchImpl = fetch } = {}) {
|
|
26707
|
+
const resp = await fetchImpl(LATEST_URL, { signal: AbortSignal.timeout(timeoutMs) });
|
|
26708
|
+
if (!resp.ok)
|
|
26709
|
+
throw new Error(`npm registry answered ${resp.status} ${resp.statusText}`);
|
|
26710
|
+
const body = await resp.json();
|
|
26711
|
+
if (typeof body.version !== "string" || body.version === "") {
|
|
26712
|
+
throw new Error("npm registry response has no version field");
|
|
26713
|
+
}
|
|
26714
|
+
return body.version;
|
|
26715
|
+
}
|
|
26716
|
+
function recordLatest(latest, path = cachePath(), now = new Date) {
|
|
26717
|
+
const prev = readCache(path);
|
|
26718
|
+
writeCache({ ...prev, latest, checkedAt: now.toISOString() }, path);
|
|
26719
|
+
}
|
|
26720
|
+
async function refreshLatest(opts = {}) {
|
|
26721
|
+
if (updateCheckDisabled(opts.env))
|
|
26722
|
+
return null;
|
|
26723
|
+
const path = opts.path ?? cachePath();
|
|
26724
|
+
const now = opts.now ?? new Date;
|
|
26725
|
+
const cached = readCache(path);
|
|
26726
|
+
const age = cached ? now.getTime() - Date.parse(cached.checkedAt) : Infinity;
|
|
26727
|
+
if (cached && !opts.force && age >= 0 && age < CACHE_TTL_MS)
|
|
26728
|
+
return cached.latest;
|
|
26729
|
+
try {
|
|
26730
|
+
const latest = await fetchLatestVersion({ fetchImpl: opts.fetchImpl });
|
|
26731
|
+
recordLatest(latest, path, now);
|
|
26732
|
+
return latest;
|
|
26733
|
+
} catch {
|
|
26734
|
+
return cached?.latest ?? null;
|
|
26735
|
+
}
|
|
26736
|
+
}
|
|
26737
|
+
function startPeriodicRefresh() {
|
|
26738
|
+
if (updateCheckDisabled())
|
|
26739
|
+
return;
|
|
26740
|
+
refreshLatest();
|
|
26741
|
+
const timer = setInterval(() => void refreshLatest(), CACHE_TTL_MS);
|
|
26742
|
+
timer.unref?.();
|
|
26743
|
+
}
|
|
26744
|
+
function newerRelease(latest, installed = PKG_VERSION) {
|
|
26745
|
+
if (!latest)
|
|
26746
|
+
return null;
|
|
26747
|
+
return compareSemver(latest, installed) > 0 ? latest : null;
|
|
26748
|
+
}
|
|
26749
|
+
function upgradeCommand() {
|
|
26750
|
+
return isContainerised() ? "cerefox-local upgrade" : "cerefox self-update";
|
|
26751
|
+
}
|
|
26752
|
+
function takeCliNotice(opts = {}) {
|
|
26753
|
+
if (updateCheckDisabled(opts.env))
|
|
26754
|
+
return null;
|
|
26755
|
+
const path = opts.path ?? cachePath();
|
|
26756
|
+
const now = opts.now ?? new Date;
|
|
26757
|
+
const cached = readCache(path);
|
|
26758
|
+
const newer = newerRelease(cached?.latest, opts.installed);
|
|
26759
|
+
if (!cached || !newer)
|
|
26760
|
+
return null;
|
|
26761
|
+
if (cached.notifiedAt) {
|
|
26762
|
+
const since = now.getTime() - Date.parse(cached.notifiedAt);
|
|
26763
|
+
if (since >= 0 && since < NOTIFY_INTERVAL_MS)
|
|
26764
|
+
return null;
|
|
26765
|
+
}
|
|
26766
|
+
writeCache({ ...cached, notifiedAt: now.toISOString() }, path);
|
|
26767
|
+
return `Cerefox ${newer} is available (you have ${opts.installed ?? PKG_VERSION}). Run \`${upgradeCommand()}\`.`;
|
|
26768
|
+
}
|
|
26769
|
+
var LATEST_URL = "https://registry.npmjs.org/@cerefox%2Fmemory/latest", DAY_MS, CACHE_TTL_MS, NOTIFY_INTERVAL_MS, releaseNotesUrl = (version) => `https://github.com/fstamatelopoulos/cerefox/releases/tag/v${version}`;
|
|
26770
|
+
var init_update_check = __esm(() => {
|
|
26771
|
+
init_compatibility();
|
|
26772
|
+
init_meta();
|
|
26773
|
+
init_auth();
|
|
26774
|
+
init_daemon();
|
|
26775
|
+
DAY_MS = 24 * 60 * 60 * 1000;
|
|
26776
|
+
CACHE_TTL_MS = DAY_MS;
|
|
26777
|
+
NOTIFY_INTERVAL_MS = DAY_MS;
|
|
26778
|
+
});
|
|
26779
|
+
|
|
26780
|
+
// ../../_shared/ef-meta/index.ts
|
|
26781
|
+
var EF_VERSION = "1.18.0", CEREFOX_VERSION = "1.18.0", EF_LAST_CHANGED = "1.17.3";
|
|
26782
|
+
var init_ef_meta = () => {};
|
|
26783
|
+
|
|
26369
26784
|
// ../../_shared/embeddings/onnx-embedder.ts
|
|
26370
26785
|
var exports_onnx_embedder = {};
|
|
26371
26786
|
__export(exports_onnx_embedder, {
|
|
@@ -26382,9 +26797,9 @@ __export(exports_onnx_embedder, {
|
|
|
26382
26797
|
onnxEmbed: () => onnxEmbed,
|
|
26383
26798
|
warmup: () => warmup
|
|
26384
26799
|
});
|
|
26385
|
-
import { existsSync as
|
|
26800
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync5, renameSync, statSync as statSync2, writeFileSync as writeFileSync6, appendFileSync } from "node:fs";
|
|
26386
26801
|
import { homedir as homedir6 } from "node:os";
|
|
26387
|
-
import { dirname as
|
|
26802
|
+
import { dirname as dirname5, join as join10 } from "node:path";
|
|
26388
26803
|
function nomicPrefix(role) {
|
|
26389
26804
|
return role === "query" ? "search_query: " : "search_document: ";
|
|
26390
26805
|
}
|
|
@@ -26421,17 +26836,17 @@ async function downloadModelFiles(remoteHost, onProgress, onDone, opts = {}) {
|
|
|
26421
26836
|
const dir = getCacheDir();
|
|
26422
26837
|
const base = remoteHost.endsWith("/") ? remoteHost : `${remoteHost}/`;
|
|
26423
26838
|
for (const rel of MODEL_REPO_FILES) {
|
|
26424
|
-
const dest =
|
|
26425
|
-
if (
|
|
26839
|
+
const dest = join10(dir, ONNX_MODEL_ID, rel);
|
|
26840
|
+
if (existsSync11(dest))
|
|
26426
26841
|
continue;
|
|
26427
|
-
|
|
26842
|
+
mkdirSync5(dirname5(dest), { recursive: true });
|
|
26428
26843
|
const part = `${dest}.part`;
|
|
26429
26844
|
const url = `${base}${ONNX_MODEL_ID}/resolve/main/${rel}`;
|
|
26430
26845
|
let failures = 0;
|
|
26431
26846
|
let lastError = "";
|
|
26432
26847
|
let total = 0;
|
|
26433
26848
|
for (;; ) {
|
|
26434
|
-
const have =
|
|
26849
|
+
const have = existsSync11(part) ? statSync2(part).size : 0;
|
|
26435
26850
|
if (total > 0 && have >= total)
|
|
26436
26851
|
break;
|
|
26437
26852
|
try {
|
|
@@ -26445,12 +26860,12 @@ async function downloadModelFiles(remoteHost, onProgress, onDone, opts = {}) {
|
|
|
26445
26860
|
if (declared > 0 && bytes.byteLength !== declared) {
|
|
26446
26861
|
throw new Error(`got ${bytes.byteLength} bytes, expected ${declared}`);
|
|
26447
26862
|
}
|
|
26448
|
-
|
|
26863
|
+
writeFileSync6(part, bytes);
|
|
26449
26864
|
total = bytes.byteLength;
|
|
26450
26865
|
} else {
|
|
26451
26866
|
total = got.total;
|
|
26452
26867
|
if (have > total) {
|
|
26453
|
-
|
|
26868
|
+
writeFileSync6(part, new Uint8Array(0));
|
|
26454
26869
|
continue;
|
|
26455
26870
|
}
|
|
26456
26871
|
appendFileSync(part, got.bytes);
|
|
@@ -26473,13 +26888,13 @@ async function downloadModelFiles(remoteHost, onProgress, onDone, opts = {}) {
|
|
|
26473
26888
|
}
|
|
26474
26889
|
}
|
|
26475
26890
|
function isModelCached(dir = getCacheDir()) {
|
|
26476
|
-
return MODEL_FILES.every((f) =>
|
|
26891
|
+
return MODEL_FILES.every((f) => existsSync11(join10(dir, f)));
|
|
26477
26892
|
}
|
|
26478
26893
|
function getCacheDir() {
|
|
26479
26894
|
const env = globalThis.process?.env ?? {};
|
|
26480
26895
|
if (env.CEREFOX_MODELS_DIR)
|
|
26481
26896
|
return env.CEREFOX_MODELS_DIR;
|
|
26482
|
-
return
|
|
26897
|
+
return join10(homedir6(), ".cerefox", "models");
|
|
26483
26898
|
}
|
|
26484
26899
|
async function loadTransformers() {
|
|
26485
26900
|
if (transformersModule)
|
|
@@ -26488,8 +26903,8 @@ async function loadTransformers() {
|
|
|
26488
26903
|
process.env.ORT_DISABLE_TELEMETRY ??= "1";
|
|
26489
26904
|
transformersModule = await import(spec);
|
|
26490
26905
|
const dir = getCacheDir();
|
|
26491
|
-
if (!
|
|
26492
|
-
|
|
26906
|
+
if (!existsSync11(dir))
|
|
26907
|
+
mkdirSync5(dir, { recursive: true });
|
|
26493
26908
|
transformersModule.env.cacheDir = dir;
|
|
26494
26909
|
transformersModule.env.allowLocalModels = true;
|
|
26495
26910
|
transformersModule.env.allowRemoteModels = true;
|
|
@@ -26654,7 +27069,7 @@ var init_onnx_embedder = __esm(() => {
|
|
|
26654
27069
|
"tokenizer_config.json",
|
|
26655
27070
|
`onnx/model_quantized.onnx`
|
|
26656
27071
|
];
|
|
26657
|
-
MODEL_FILES = MODEL_REPO_FILES.map((f) =>
|
|
27072
|
+
MODEL_FILES = MODEL_REPO_FILES.map((f) => join10(ONNX_MODEL_ID, f));
|
|
26658
27073
|
EmbedderDownloadError = class EmbedderDownloadError extends Error {
|
|
26659
27074
|
status = 503;
|
|
26660
27075
|
constructor(detail) {
|
|
@@ -50797,7 +51212,7 @@ function resetFeatureFlagCache() {
|
|
|
50797
51212
|
}
|
|
50798
51213
|
async function readBoolFlag(supabase, key) {
|
|
50799
51214
|
const hit = cache.get(key);
|
|
50800
|
-
if (hit && Date.now() - hit.at <
|
|
51215
|
+
if (hit && Date.now() - hit.at < CACHE_TTL_MS2)
|
|
50801
51216
|
return hit.value;
|
|
50802
51217
|
try {
|
|
50803
51218
|
const { data, error } = await supabase.rpc("cerefox_get_config", { p_key: key });
|
|
@@ -50819,7 +51234,7 @@ async function reviewWorkflowEnabled(supabase) {
|
|
|
50819
51234
|
function disabledToolMessage(name) {
|
|
50820
51235
|
return `${name} is part of the document-relations feature, which is off by default. ` + `Enable it with: cerefox config set relations_enabled true ` + `(deployment-wide; every access path picks it up).`;
|
|
50821
51236
|
}
|
|
50822
|
-
var RELATION_TOOL_NAMES,
|
|
51237
|
+
var RELATION_TOOL_NAMES, CACHE_TTL_MS2 = 15000, cache;
|
|
50823
51238
|
var init_feature_flags = __esm(() => {
|
|
50824
51239
|
RELATION_TOOL_NAMES = new Set([
|
|
50825
51240
|
"cerefox_set_relation",
|
|
@@ -53584,7 +53999,7 @@ var require_cli_progress = __commonJS(function(exports, module) {
|
|
|
53584
53999
|
});
|
|
53585
54000
|
|
|
53586
54001
|
// src/cli/commands/sync-self-docs.ts
|
|
53587
|
-
import { readFileSync as
|
|
54002
|
+
import { readFileSync as readFileSync14 } from "node:fs";
|
|
53588
54003
|
import { basename as basename4, extname as extname5 } from "node:path";
|
|
53589
54004
|
async function runSyncSelfDocs(options = {}) {
|
|
53590
54005
|
const project = options.project ?? "_cerefox-self-docs";
|
|
@@ -53611,7 +54026,7 @@ async function runSyncSelfDocs(options = {}) {
|
|
|
53611
54026
|
const authorType = resolveAuthorType("agent");
|
|
53612
54027
|
const outcomes = [];
|
|
53613
54028
|
for (const doc of docs) {
|
|
53614
|
-
const content =
|
|
54029
|
+
const content = readFileSync14(doc.path, "utf8");
|
|
53615
54030
|
const m = content.match(/^#\s+(.+)$/m);
|
|
53616
54031
|
const title = m ? m[1].trim() : basename4(doc.path, extname5(doc.path));
|
|
53617
54032
|
try {
|
|
@@ -53694,7 +54109,7 @@ var init_v4_mini = __esm(() => {
|
|
|
53694
54109
|
init_external2();
|
|
53695
54110
|
});
|
|
53696
54111
|
|
|
53697
|
-
// ../../node_modules/.bun/@modelcontextprotocol+sdk@1.
|
|
54112
|
+
// ../../node_modules/.bun/@modelcontextprotocol+sdk@1.32.1/node_modules/@modelcontextprotocol/sdk/dist/esm/server/zod-compat.js
|
|
53698
54113
|
function isZ4Schema(s) {
|
|
53699
54114
|
const schema = s;
|
|
53700
54115
|
return !!schema._zod;
|
|
@@ -53770,7 +54185,7 @@ var init_v4 = __esm(() => {
|
|
|
53770
54185
|
init_classic();
|
|
53771
54186
|
});
|
|
53772
54187
|
|
|
53773
|
-
// ../../node_modules/.bun/@modelcontextprotocol+sdk@1.
|
|
54188
|
+
// ../../node_modules/.bun/@modelcontextprotocol+sdk@1.32.1/node_modules/@modelcontextprotocol/sdk/dist/esm/types.js
|
|
53774
54189
|
var LATEST_PROTOCOL_VERSION = "2025-11-25", SUPPORTED_PROTOCOL_VERSIONS, RELATED_TASK_META_KEY = "io.modelcontextprotocol/related-task", JSONRPC_VERSION = "2.0", AssertObjectSchema, ProgressTokenSchema, CursorSchema, TaskCreationParamsSchema, TaskMetadataSchema, RelatedTaskMetadataSchema, RequestMetaSchema, BaseRequestParamsSchema, TaskAugmentedRequestParamsSchema, isTaskAugmentedRequestParams = (value) => TaskAugmentedRequestParamsSchema.safeParse(value).success, RequestSchema, NotificationsParamsSchema, NotificationSchema, ResultSchema, RequestIdSchema, JSONRPCRequestSchema, isJSONRPCRequest = (value) => JSONRPCRequestSchema.safeParse(value).success, JSONRPCNotificationSchema, isJSONRPCNotification = (value) => JSONRPCNotificationSchema.safeParse(value).success, JSONRPCResultResponseSchema, isJSONRPCResultResponse = (value) => JSONRPCResultResponseSchema.safeParse(value).success, ErrorCode, JSONRPCErrorResponseSchema, isJSONRPCErrorResponse = (value) => JSONRPCErrorResponseSchema.safeParse(value).success, JSONRPCMessageSchema, JSONRPCResponseSchema, EmptyResultSchema, CancelledNotificationParamsSchema, CancelledNotificationSchema, IconSchema, IconsSchema, BaseMetadataSchema, ImplementationSchema, FormElicitationCapabilitySchema, ElicitationCapabilitySchema, ClientTasksCapabilitySchema, ServerTasksCapabilitySchema, ClientCapabilitiesSchema, InitializeRequestParamsSchema, InitializeRequestSchema, ServerCapabilitiesSchema, InitializeResultSchema, InitializedNotificationSchema, PingRequestSchema, ProgressSchema, ProgressNotificationParamsSchema, ProgressNotificationSchema, PaginatedRequestParamsSchema, PaginatedRequestSchema, PaginatedResultSchema, TaskStatusSchema, TaskSchema, CreateTaskResultSchema, TaskStatusNotificationParamsSchema, TaskStatusNotificationSchema, GetTaskRequestSchema, GetTaskResultSchema, GetTaskPayloadRequestSchema, GetTaskPayloadResultSchema, ListTasksRequestSchema, ListTasksResultSchema, CancelTaskRequestSchema, CancelTaskResultSchema, ResourceContentsSchema, TextResourceContentsSchema, Base64Schema, BlobResourceContentsSchema, RoleSchema, AnnotationsSchema, ResourceSchema, ResourceTemplateSchema, ListResourcesRequestSchema, ListResourcesResultSchema, ListResourceTemplatesRequestSchema, ListResourceTemplatesResultSchema, ResourceRequestParamsSchema, ReadResourceRequestParamsSchema, ReadResourceRequestSchema, ReadResourceResultSchema, ResourceListChangedNotificationSchema, SubscribeRequestParamsSchema, SubscribeRequestSchema, UnsubscribeRequestParamsSchema, UnsubscribeRequestSchema, ResourceUpdatedNotificationParamsSchema, ResourceUpdatedNotificationSchema, PromptArgumentSchema, PromptSchema, ListPromptsRequestSchema, ListPromptsResultSchema, GetPromptRequestParamsSchema, GetPromptRequestSchema, TextContentSchema, ImageContentSchema, AudioContentSchema, ToolUseContentSchema, EmbeddedResourceSchema, ResourceLinkSchema, ContentBlockSchema, PromptMessageSchema, GetPromptResultSchema, PromptListChangedNotificationSchema, ToolAnnotationsSchema, ToolExecutionSchema, ToolSchema, ListToolsRequestSchema, ListToolsResultSchema, CallToolResultSchema, CompatibilityCallToolResultSchema, CallToolRequestParamsSchema, CallToolRequestSchema, ToolListChangedNotificationSchema, ListChangedOptionsBaseSchema, LoggingLevelSchema, SetLevelRequestParamsSchema, SetLevelRequestSchema, LoggingMessageNotificationParamsSchema, LoggingMessageNotificationSchema, ModelHintSchema, ModelPreferencesSchema, ToolChoiceSchema, ToolResultContentSchema, SamplingContentSchema, SamplingMessageContentBlockSchema, SamplingMessageSchema, CreateMessageRequestParamsSchema, CreateMessageRequestSchema, CreateMessageResultSchema, CreateMessageResultWithToolsSchema, BooleanSchemaSchema, StringSchemaSchema, NumberSchemaSchema, UntitledSingleSelectEnumSchemaSchema, TitledSingleSelectEnumSchemaSchema, LegacyTitledEnumSchemaSchema, SingleSelectEnumSchemaSchema, UntitledMultiSelectEnumSchemaSchema, TitledMultiSelectEnumSchemaSchema, MultiSelectEnumSchemaSchema, EnumSchemaSchema, PrimitiveSchemaDefinitionSchema, ElicitRequestFormParamsSchema, ElicitRequestURLParamsSchema, ElicitRequestParamsSchema, ElicitRequestSchema, ElicitationCompleteNotificationParamsSchema, ElicitationCompleteNotificationSchema, ElicitResultSchema, ResourceTemplateReferenceSchema, PromptReferenceSchema, CompleteRequestParamsSchema, CompleteRequestSchema, CompleteResultSchema, RootSchema, ListRootsRequestSchema, ListRootsResultSchema, RootsListChangedNotificationSchema, ClientRequestSchema, ClientNotificationSchema, ClientResultSchema, ServerRequestSchema, ServerNotificationSchema, ServerResultSchema, McpError, UrlElicitationRequiredError;
|
|
53775
54190
|
var init_types3 = __esm(() => {
|
|
53776
54191
|
init_v4();
|
|
@@ -54598,7 +55013,7 @@ var init_types3 = __esm(() => {
|
|
|
54598
55013
|
};
|
|
54599
55014
|
});
|
|
54600
55015
|
|
|
54601
|
-
// ../../node_modules/.bun/@modelcontextprotocol+sdk@1.
|
|
55016
|
+
// ../../node_modules/.bun/@modelcontextprotocol+sdk@1.32.1/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/interfaces.js
|
|
54602
55017
|
function isTerminal(status) {
|
|
54603
55018
|
return status === "completed" || status === "failed" || status === "cancelled";
|
|
54604
55019
|
}
|
|
@@ -54816,7 +55231,7 @@ var init_esm = __esm(() => {
|
|
|
54816
55231
|
init_zodToJsonSchema();
|
|
54817
55232
|
});
|
|
54818
55233
|
|
|
54819
|
-
// ../../node_modules/.bun/@modelcontextprotocol+sdk@1.
|
|
55234
|
+
// ../../node_modules/.bun/@modelcontextprotocol+sdk@1.32.1/node_modules/@modelcontextprotocol/sdk/dist/esm/server/zod-json-schema-compat.js
|
|
54820
55235
|
function getMethodLiteral(schema) {
|
|
54821
55236
|
const shape = getObjectShape(schema);
|
|
54822
55237
|
const methodSchema = shape?.method;
|
|
@@ -54841,7 +55256,7 @@ var init_zod_json_schema_compat = __esm(() => {
|
|
|
54841
55256
|
init_esm();
|
|
54842
55257
|
});
|
|
54843
55258
|
|
|
54844
|
-
// ../../node_modules/.bun/@modelcontextprotocol+sdk@1.
|
|
55259
|
+
// ../../node_modules/.bun/@modelcontextprotocol+sdk@1.32.1/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/protocol.js
|
|
54845
55260
|
class Protocol {
|
|
54846
55261
|
constructor(_options) {
|
|
54847
55262
|
this._options = _options;
|
|
@@ -54877,6 +55292,9 @@ class Protocol {
|
|
|
54877
55292
|
this.setRequestHandler(GetTaskPayloadRequestSchema, async (request, extra) => {
|
|
54878
55293
|
const handleTaskResult = async () => {
|
|
54879
55294
|
const taskId = request.params.taskId;
|
|
55295
|
+
if (!await this._taskStore.getTask(taskId, extra.sessionId)) {
|
|
55296
|
+
throw new McpError(ErrorCode.InvalidParams, `Task not found: ${taskId}`);
|
|
55297
|
+
}
|
|
54880
55298
|
if (this._taskMessageQueue) {
|
|
54881
55299
|
let queuedMessage;
|
|
54882
55300
|
while (queuedMessage = await this._taskMessageQueue.dequeue(taskId, extra.sessionId)) {
|
|
@@ -54907,12 +55325,12 @@ class Protocol {
|
|
|
54907
55325
|
throw new McpError(ErrorCode.InvalidParams, `Task not found: ${taskId}`);
|
|
54908
55326
|
}
|
|
54909
55327
|
if (!isTerminal(task.status)) {
|
|
54910
|
-
await this._waitForTaskUpdate(taskId, extra.signal);
|
|
55328
|
+
await this._waitForTaskUpdate(taskId, extra.signal, extra.sessionId);
|
|
54911
55329
|
return await handleTaskResult();
|
|
54912
55330
|
}
|
|
54913
55331
|
if (isTerminal(task.status)) {
|
|
54914
55332
|
const result = await this._taskStore.getTaskResult(taskId, extra.sessionId);
|
|
54915
|
-
this._clearTaskQueue(taskId);
|
|
55333
|
+
this._clearTaskQueue(taskId, extra.sessionId);
|
|
54916
55334
|
return {
|
|
54917
55335
|
...result,
|
|
54918
55336
|
_meta: {
|
|
@@ -54949,7 +55367,7 @@ class Protocol {
|
|
|
54949
55367
|
throw new McpError(ErrorCode.InvalidParams, `Cannot cancel task in terminal status: ${task.status}`);
|
|
54950
55368
|
}
|
|
54951
55369
|
await this._taskStore.updateTaskStatus(request.params.taskId, "cancelled", "Client cancelled task execution.", extra.sessionId);
|
|
54952
|
-
this._clearTaskQueue(request.params.taskId);
|
|
55370
|
+
this._clearTaskQueue(request.params.taskId, extra.sessionId);
|
|
54953
55371
|
const cancelledTask = await this._taskStore.getTask(request.params.taskId, extra.sessionId);
|
|
54954
55372
|
if (!cancelledTask) {
|
|
54955
55373
|
throw new McpError(ErrorCode.InvalidParams, `Task not found after cancellation: ${request.params.taskId}`);
|
|
@@ -55072,6 +55490,19 @@ class Protocol {
|
|
|
55072
55490
|
const handler = this._requestHandlers.get(request.method) ?? this.fallbackRequestHandler;
|
|
55073
55491
|
const capturedTransport = this._transport;
|
|
55074
55492
|
const relatedTaskId = request.params?._meta?.[RELATED_TASK_META_KEY]?.taskId;
|
|
55493
|
+
const sessionId = capturedTransport?.sessionId;
|
|
55494
|
+
const store = this._taskStore;
|
|
55495
|
+
let relatedTaskFound = true;
|
|
55496
|
+
let relatedTaskLookup;
|
|
55497
|
+
if (relatedTaskId && store && this._taskMessageQueue && sessionId !== undefined) {
|
|
55498
|
+
relatedTaskFound = false;
|
|
55499
|
+
relatedTaskLookup = (async () => {
|
|
55500
|
+
if (!await store.getTask(relatedTaskId, sessionId)) {
|
|
55501
|
+
throw new McpError(ErrorCode.InvalidParams, `Task not found: ${relatedTaskId}`);
|
|
55502
|
+
}
|
|
55503
|
+
relatedTaskFound = true;
|
|
55504
|
+
})();
|
|
55505
|
+
}
|
|
55075
55506
|
if (handler === undefined) {
|
|
55076
55507
|
const errorResponse = {
|
|
55077
55508
|
jsonrpc: "2.0",
|
|
@@ -55081,7 +55512,10 @@ class Protocol {
|
|
|
55081
55512
|
message: "Method not found"
|
|
55082
55513
|
}
|
|
55083
55514
|
};
|
|
55084
|
-
if (relatedTaskId &&
|
|
55515
|
+
if (relatedTaskId && relatedTaskLookup) {
|
|
55516
|
+
const queuedError = { type: "error", message: errorResponse, timestamp: Date.now() };
|
|
55517
|
+
relatedTaskLookup.then(() => this._enqueueTaskMessage(relatedTaskId, queuedError, sessionId), () => capturedTransport?.send(errorResponse)).catch((error) => this._onerror(new Error(`Failed to send an error response: ${error}`)));
|
|
55518
|
+
} else if (relatedTaskId && this._taskMessageQueue) {
|
|
55085
55519
|
this._enqueueTaskMessage(relatedTaskId, {
|
|
55086
55520
|
type: "error",
|
|
55087
55521
|
message: errorResponse,
|
|
@@ -55132,7 +55566,10 @@ class Protocol {
|
|
|
55132
55566
|
closeSSEStream: extra?.closeSSEStream,
|
|
55133
55567
|
closeStandaloneSSEStream: extra?.closeStandaloneSSEStream
|
|
55134
55568
|
};
|
|
55135
|
-
Promise.resolve().then(() => {
|
|
55569
|
+
(relatedTaskLookup ?? Promise.resolve()).then(() => {
|
|
55570
|
+
if (relatedTaskLookup && abortController.signal.aborted) {
|
|
55571
|
+
throw new McpError(ErrorCode.ConnectionClosed, "Request was cancelled");
|
|
55572
|
+
}
|
|
55136
55573
|
if (taskCreationParams) {
|
|
55137
55574
|
this.assertTaskHandlerCapability(request.method);
|
|
55138
55575
|
}
|
|
@@ -55167,7 +55604,7 @@ class Protocol {
|
|
|
55167
55604
|
...error["data"] !== undefined && { data: error["data"] }
|
|
55168
55605
|
}
|
|
55169
55606
|
};
|
|
55170
|
-
if (relatedTaskId && this._taskMessageQueue) {
|
|
55607
|
+
if (relatedTaskId && this._taskMessageQueue && relatedTaskFound) {
|
|
55171
55608
|
await this._enqueueTaskMessage(relatedTaskId, {
|
|
55172
55609
|
type: "error",
|
|
55173
55610
|
message: errorResponse,
|
|
@@ -55555,7 +55992,7 @@ class Protocol {
|
|
|
55555
55992
|
throw new Error("Cannot enqueue task message: taskStore and taskMessageQueue are not configured");
|
|
55556
55993
|
}
|
|
55557
55994
|
const maxQueueSize = this._options?.maxTaskQueueSize;
|
|
55558
|
-
await this._taskMessageQueue.enqueue(taskId, message, sessionId, maxQueueSize);
|
|
55995
|
+
await this._taskMessageQueue.enqueue(taskId, message, sessionId ?? this._transport?.sessionId, maxQueueSize);
|
|
55559
55996
|
}
|
|
55560
55997
|
async _clearTaskQueue(taskId, sessionId) {
|
|
55561
55998
|
if (this._taskMessageQueue) {
|
|
@@ -55574,10 +56011,10 @@ class Protocol {
|
|
|
55574
56011
|
}
|
|
55575
56012
|
}
|
|
55576
56013
|
}
|
|
55577
|
-
async _waitForTaskUpdate(taskId, signal) {
|
|
56014
|
+
async _waitForTaskUpdate(taskId, signal, sessionId) {
|
|
55578
56015
|
let interval = this._options?.defaultTaskPollInterval ?? 1000;
|
|
55579
56016
|
try {
|
|
55580
|
-
const task = await this._taskStore?.getTask(taskId);
|
|
56017
|
+
const task = await this._taskStore?.getTask(taskId, sessionId);
|
|
55581
56018
|
if (task?.pollInterval) {
|
|
55582
56019
|
interval = task.pollInterval;
|
|
55583
56020
|
}
|
|
@@ -62573,7 +63010,7 @@ var require_dist3 = __commonJS(function(exports, module) {
|
|
|
62573
63010
|
exports.default = formatsPlugin;
|
|
62574
63011
|
});
|
|
62575
63012
|
|
|
62576
|
-
// ../../node_modules/.bun/@modelcontextprotocol+sdk@1.
|
|
63013
|
+
// ../../node_modules/.bun/@modelcontextprotocol+sdk@1.32.1/node_modules/@modelcontextprotocol/sdk/dist/esm/validation/ajv-provider.js
|
|
62577
63014
|
function createDefaultAjvInstance() {
|
|
62578
63015
|
const ajv = new import_ajv.default({
|
|
62579
63016
|
strict: false,
|
|
@@ -62616,7 +63053,7 @@ var init_ajv_provider = __esm(() => {
|
|
|
62616
63053
|
import_ajv_formats = __toESM(require_dist3(), 1);
|
|
62617
63054
|
});
|
|
62618
63055
|
|
|
62619
|
-
// ../../node_modules/.bun/@modelcontextprotocol+sdk@1.
|
|
63056
|
+
// ../../node_modules/.bun/@modelcontextprotocol+sdk@1.32.1/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/server.js
|
|
62620
63057
|
class ExperimentalServerTasks {
|
|
62621
63058
|
constructor(_server) {
|
|
62622
63059
|
this._server = _server;
|
|
@@ -62697,7 +63134,7 @@ var init_server = __esm(() => {
|
|
|
62697
63134
|
init_types3();
|
|
62698
63135
|
});
|
|
62699
63136
|
|
|
62700
|
-
// ../../node_modules/.bun/@modelcontextprotocol+sdk@1.
|
|
63137
|
+
// ../../node_modules/.bun/@modelcontextprotocol+sdk@1.32.1/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/helpers.js
|
|
62701
63138
|
function assertToolsCallTaskCapability(requests, method, entityName) {
|
|
62702
63139
|
if (!requests) {
|
|
62703
63140
|
throw new Error(`${entityName} does not support task creation (required for ${method})`);
|
|
@@ -62732,7 +63169,7 @@ function assertClientRequestTaskCapability(requests, method, entityName) {
|
|
|
62732
63169
|
}
|
|
62733
63170
|
}
|
|
62734
63171
|
|
|
62735
|
-
// ../../node_modules/.bun/@modelcontextprotocol+sdk@1.
|
|
63172
|
+
// ../../node_modules/.bun/@modelcontextprotocol+sdk@1.32.1/node_modules/@modelcontextprotocol/sdk/dist/esm/server/index.js
|
|
62736
63173
|
var Server;
|
|
62737
63174
|
var init_server2 = __esm(() => {
|
|
62738
63175
|
init_protocol();
|
|
@@ -63064,7 +63501,7 @@ var init_server2 = __esm(() => {
|
|
|
63064
63501
|
};
|
|
63065
63502
|
});
|
|
63066
63503
|
|
|
63067
|
-
// ../../node_modules/.bun/@modelcontextprotocol+sdk@1.
|
|
63504
|
+
// ../../node_modules/.bun/@modelcontextprotocol+sdk@1.32.1/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/stdio.js
|
|
63068
63505
|
class ReadBuffer {
|
|
63069
63506
|
constructor(options) {
|
|
63070
63507
|
this._maxBufferSize = options?.maxBufferSize ?? STDIO_DEFAULT_MAX_BUFFER_SIZE;
|
|
@@ -63107,7 +63544,7 @@ var init_stdio = __esm(() => {
|
|
|
63107
63544
|
STDIO_DEFAULT_MAX_BUFFER_SIZE = 10 * 1024 * 1024;
|
|
63108
63545
|
});
|
|
63109
63546
|
|
|
63110
|
-
// ../../node_modules/.bun/@modelcontextprotocol+sdk@1.
|
|
63547
|
+
// ../../node_modules/.bun/@modelcontextprotocol+sdk@1.32.1/node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
|
|
63111
63548
|
import process10 from "node:process";
|
|
63112
63549
|
|
|
63113
63550
|
class StdioServerTransport {
|
|
@@ -63185,6 +63622,7 @@ function buildServer() {
|
|
|
63185
63622
|
auth: { persistSession: false, autoRefreshToken: false }
|
|
63186
63623
|
});
|
|
63187
63624
|
warnIfSchemaVersionMismatch(supabase);
|
|
63625
|
+
Promise.resolve().then(() => (init_update_check(), {})).then((m) => refreshLatest()).catch(() => {});
|
|
63188
63626
|
const ctx = {
|
|
63189
63627
|
accessPath: "local-mcp",
|
|
63190
63628
|
openaiApiKey: settings.openaiApiKey || undefined
|
|
@@ -63230,7 +63668,7 @@ async function warnIfSchemaVersionMismatch(supabase) {
|
|
|
63230
63668
|
if (!bundled)
|
|
63231
63669
|
return;
|
|
63232
63670
|
if (compareSemver(deployed, bundled) < 0) {
|
|
63233
|
-
process.stderr.write(`[cerefox-mcp] ⚠ schema version mismatch: this client bundles v${bundled}
|
|
63671
|
+
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.
|
|
63234
63672
|
`);
|
|
63235
63673
|
}
|
|
63236
63674
|
} catch {}
|
|
@@ -71859,182 +72297,16 @@ init_cli_core();
|
|
|
71859
72297
|
|
|
71860
72298
|
// src/cli/util/checks.ts
|
|
71861
72299
|
init_meta();
|
|
72300
|
+
init_update_check();
|
|
71862
72301
|
init_ef_meta();
|
|
71863
72302
|
init_config();
|
|
71864
72303
|
init_config();
|
|
71865
72304
|
init_compatibility();
|
|
71866
72305
|
init_server_assets();
|
|
71867
|
-
|
|
72306
|
+
init_daemon();
|
|
72307
|
+
import { existsSync as existsSync12, readFileSync as readFileSync10, realpathSync, statSync as statSync3 } from "node:fs";
|
|
71868
72308
|
import { homedir as homedir7 } from "node:os";
|
|
71869
|
-
import { join as
|
|
71870
|
-
|
|
71871
|
-
// src/web/daemon.ts
|
|
71872
|
-
import { spawn } from "node:child_process";
|
|
71873
|
-
import {
|
|
71874
|
-
existsSync as existsSync9,
|
|
71875
|
-
mkdirSync as mkdirSync3,
|
|
71876
|
-
openSync,
|
|
71877
|
-
readFileSync as readFileSync8,
|
|
71878
|
-
rmSync,
|
|
71879
|
-
writeFileSync as writeFileSync4
|
|
71880
|
-
} from "node:fs";
|
|
71881
|
-
import { homedir as homedir5 } from "node:os";
|
|
71882
|
-
import { join as join8 } from "node:path";
|
|
71883
|
-
function resolveStateDir(override = process.env.CEREFOX_CONFIG_DIR, home = homedir5()) {
|
|
71884
|
-
override = (override ?? "").trim();
|
|
71885
|
-
if (!override)
|
|
71886
|
-
return join8(home, ".cerefox");
|
|
71887
|
-
return override === "~" || override.startsWith("~/") ? join8(home, override.slice(2)) : override;
|
|
71888
|
-
}
|
|
71889
|
-
var STATE_DIR = resolveStateDir();
|
|
71890
|
-
var PID_FILE = join8(STATE_DIR, "web.pid");
|
|
71891
|
-
var LOG_FILE = join8(STATE_DIR, "web.log");
|
|
71892
|
-
var daemonPaths = { stateDir: STATE_DIR, pidFile: PID_FILE, logFile: LOG_FILE };
|
|
71893
|
-
function ensureStateDir() {
|
|
71894
|
-
if (!existsSync9(STATE_DIR))
|
|
71895
|
-
mkdirSync3(STATE_DIR, { recursive: true });
|
|
71896
|
-
}
|
|
71897
|
-
function readPidFile() {
|
|
71898
|
-
if (!existsSync9(PID_FILE))
|
|
71899
|
-
return null;
|
|
71900
|
-
try {
|
|
71901
|
-
const parsed = JSON.parse(readFileSync8(PID_FILE, "utf8"));
|
|
71902
|
-
if (typeof parsed.pid !== "number")
|
|
71903
|
-
return null;
|
|
71904
|
-
return {
|
|
71905
|
-
pid: parsed.pid,
|
|
71906
|
-
port: typeof parsed.port === "number" ? parsed.port : 8000,
|
|
71907
|
-
host: typeof parsed.host === "string" ? parsed.host : "127.0.0.1",
|
|
71908
|
-
startedAt: typeof parsed.startedAt === "string" ? parsed.startedAt : "unknown"
|
|
71909
|
-
};
|
|
71910
|
-
} catch {
|
|
71911
|
-
return null;
|
|
71912
|
-
}
|
|
71913
|
-
}
|
|
71914
|
-
function writePidFile(info) {
|
|
71915
|
-
ensureStateDir();
|
|
71916
|
-
writeFileSync4(PID_FILE, JSON.stringify(info, null, 2) + `
|
|
71917
|
-
`, "utf8");
|
|
71918
|
-
}
|
|
71919
|
-
function removePidFile() {
|
|
71920
|
-
rmSync(PID_FILE, { force: true });
|
|
71921
|
-
}
|
|
71922
|
-
function isProcessAlive(pid) {
|
|
71923
|
-
try {
|
|
71924
|
-
process.kill(pid, 0);
|
|
71925
|
-
return true;
|
|
71926
|
-
} catch (err) {
|
|
71927
|
-
return err.code === "EPERM";
|
|
71928
|
-
}
|
|
71929
|
-
}
|
|
71930
|
-
async function probeVersion(host, port, timeoutMs = 1500) {
|
|
71931
|
-
const probeHost = host === "0.0.0.0" ? "127.0.0.1" : host;
|
|
71932
|
-
try {
|
|
71933
|
-
const ctrl = new AbortController;
|
|
71934
|
-
const timer = setTimeout(() => ctrl.abort(), timeoutMs);
|
|
71935
|
-
try {
|
|
71936
|
-
const resp = await fetch(`http://${probeHost}:${port}/api/v1/version`, {
|
|
71937
|
-
signal: ctrl.signal
|
|
71938
|
-
});
|
|
71939
|
-
if (!resp.ok)
|
|
71940
|
-
return { responding: false, version: null };
|
|
71941
|
-
const body = await resp.json().catch(() => null);
|
|
71942
|
-
return {
|
|
71943
|
-
responding: true,
|
|
71944
|
-
version: typeof body?.version === "string" ? body.version : null
|
|
71945
|
-
};
|
|
71946
|
-
} finally {
|
|
71947
|
-
clearTimeout(timer);
|
|
71948
|
-
}
|
|
71949
|
-
} catch {
|
|
71950
|
-
return { responding: false, version: null };
|
|
71951
|
-
}
|
|
71952
|
-
}
|
|
71953
|
-
async function isResponding(host, port, timeoutMs = 1500) {
|
|
71954
|
-
return (await probeVersion(host, port, timeoutMs)).responding;
|
|
71955
|
-
}
|
|
71956
|
-
var sleep2 = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
71957
|
-
function assertUnix() {
|
|
71958
|
-
if (process.platform === "win32") {
|
|
71959
|
-
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.");
|
|
71960
|
-
}
|
|
71961
|
-
}
|
|
71962
|
-
async function startDaemon(opts) {
|
|
71963
|
-
assertUnix();
|
|
71964
|
-
ensureStateDir();
|
|
71965
|
-
const existing = readPidFile();
|
|
71966
|
-
if (existing && isProcessAlive(existing.pid)) {
|
|
71967
|
-
return existing.port === opts.port ? { kind: "already-running", info: existing } : { kind: "port-conflict", info: existing };
|
|
71968
|
-
}
|
|
71969
|
-
if (existing)
|
|
71970
|
-
removePidFile();
|
|
71971
|
-
const logFd = openSync(LOG_FILE, "a");
|
|
71972
|
-
const child = spawn(opts.runtime, [opts.scriptPath, "web", "--host", opts.host, "--port", String(opts.port)], { detached: true, stdio: ["ignore", logFd, logFd] });
|
|
71973
|
-
child.unref();
|
|
71974
|
-
if (typeof child.pid !== "number") {
|
|
71975
|
-
throw new Error("Failed to spawn the web server process (no pid).");
|
|
71976
|
-
}
|
|
71977
|
-
writePidFile({
|
|
71978
|
-
pid: child.pid,
|
|
71979
|
-
port: opts.port,
|
|
71980
|
-
host: opts.host,
|
|
71981
|
-
startedAt: new Date().toISOString()
|
|
71982
|
-
});
|
|
71983
|
-
let responding = false;
|
|
71984
|
-
for (let i = 0;i < 20; i++) {
|
|
71985
|
-
if (!isProcessAlive(child.pid))
|
|
71986
|
-
break;
|
|
71987
|
-
if (await isResponding(opts.host, opts.port)) {
|
|
71988
|
-
responding = true;
|
|
71989
|
-
break;
|
|
71990
|
-
}
|
|
71991
|
-
await sleep2(250);
|
|
71992
|
-
}
|
|
71993
|
-
return { kind: "started", pid: child.pid, responding };
|
|
71994
|
-
}
|
|
71995
|
-
async function stopDaemon() {
|
|
71996
|
-
assertUnix();
|
|
71997
|
-
const info = readPidFile();
|
|
71998
|
-
if (!info || !isProcessAlive(info.pid)) {
|
|
71999
|
-
removePidFile();
|
|
72000
|
-
return { kind: "not-running" };
|
|
72001
|
-
}
|
|
72002
|
-
try {
|
|
72003
|
-
process.kill(info.pid, "SIGTERM");
|
|
72004
|
-
} catch {}
|
|
72005
|
-
let forced = false;
|
|
72006
|
-
let alive = true;
|
|
72007
|
-
for (let i = 0;i < 12; i++) {
|
|
72008
|
-
await sleep2(250);
|
|
72009
|
-
if (!isProcessAlive(info.pid)) {
|
|
72010
|
-
alive = false;
|
|
72011
|
-
break;
|
|
72012
|
-
}
|
|
72013
|
-
}
|
|
72014
|
-
if (alive) {
|
|
72015
|
-
try {
|
|
72016
|
-
process.kill(info.pid, "SIGKILL");
|
|
72017
|
-
forced = true;
|
|
72018
|
-
} catch {}
|
|
72019
|
-
}
|
|
72020
|
-
removePidFile();
|
|
72021
|
-
return { kind: "stopped", pid: info.pid, forced };
|
|
72022
|
-
}
|
|
72023
|
-
function restartCommand(host, port) {
|
|
72024
|
-
const flags = `${host === "127.0.0.1" ? "" : ` --host ${host}`}${port === 8000 ? "" : ` --port ${port}`}`;
|
|
72025
|
-
return `cerefox web stop && cerefox web start${flags}`;
|
|
72026
|
-
}
|
|
72027
|
-
async function statusDaemon() {
|
|
72028
|
-
const info = readPidFile();
|
|
72029
|
-
if (!info)
|
|
72030
|
-
return { kind: "stopped" };
|
|
72031
|
-
if (!isProcessAlive(info.pid))
|
|
72032
|
-
return { kind: "stale", info };
|
|
72033
|
-
const { responding, version } = await probeVersion(info.host, info.port);
|
|
72034
|
-
return { kind: "running", info, responding, version };
|
|
72035
|
-
}
|
|
72036
|
-
|
|
72037
|
-
// src/cli/util/checks.ts
|
|
72309
|
+
import { join as join11 } from "node:path";
|
|
72038
72310
|
function checkBinary() {
|
|
72039
72311
|
return {
|
|
72040
72312
|
name: "binary",
|
|
@@ -72074,6 +72346,28 @@ function checkVersion() {
|
|
|
72074
72346
|
detail: `cerefox v${PKG_VERSION}`
|
|
72075
72347
|
};
|
|
72076
72348
|
}
|
|
72349
|
+
async function checkUpdates() {
|
|
72350
|
+
const name = "updates";
|
|
72351
|
+
if (updateCheckDisabled()) {
|
|
72352
|
+
return { name, status: "skipped", detail: "update check is off (CEREFOX_NO_UPDATE_CHECK, NO_UPDATE_NOTIFIER or CI)" };
|
|
72353
|
+
}
|
|
72354
|
+
let latest;
|
|
72355
|
+
try {
|
|
72356
|
+
latest = await fetchLatestVersion();
|
|
72357
|
+
recordLatest(latest);
|
|
72358
|
+
} catch {
|
|
72359
|
+
return { name, status: "skipped", detail: "could not reach the npm registry to check for a newer release" };
|
|
72360
|
+
}
|
|
72361
|
+
const newer = newerRelease(latest);
|
|
72362
|
+
if (!newer)
|
|
72363
|
+
return { name, status: "ok", detail: `up to date (latest release: v${latest})` };
|
|
72364
|
+
return {
|
|
72365
|
+
name,
|
|
72366
|
+
status: "skipped",
|
|
72367
|
+
detail: `v${newer} is available (installed: v${PKG_VERSION})`,
|
|
72368
|
+
hint: `Run \`${upgradeCommand()}\`. Release notes: ${releaseNotesUrl(newer)}`
|
|
72369
|
+
};
|
|
72370
|
+
}
|
|
72077
72371
|
function checkConfig() {
|
|
72078
72372
|
let envPath;
|
|
72079
72373
|
try {
|
|
@@ -72086,7 +72380,7 @@ function checkConfig() {
|
|
|
72086
72380
|
hint: "Run `cerefox init` to bootstrap."
|
|
72087
72381
|
};
|
|
72088
72382
|
}
|
|
72089
|
-
if (!
|
|
72383
|
+
if (!existsSync12(envPath)) {
|
|
72090
72384
|
const settings = loadSettings();
|
|
72091
72385
|
if (settings.supabaseUrl && settings.supabaseKey) {
|
|
72092
72386
|
return {
|
|
@@ -72514,6 +72808,47 @@ async function probeRpcJson(settings, fn) {
|
|
|
72514
72808
|
return { kind: "error", detail: err instanceof Error ? err.message : String(err) };
|
|
72515
72809
|
}
|
|
72516
72810
|
}
|
|
72811
|
+
var CHUNK_COUNT_WARN_AT = 1e5;
|
|
72812
|
+
function classifyChunkCount(count) {
|
|
72813
|
+
const n = count.toLocaleString("en-US");
|
|
72814
|
+
if (count <= CHUNK_COUNT_WARN_AT) {
|
|
72815
|
+
return { name: "chunks", status: "ok", detail: `${n} current chunk(s)` };
|
|
72816
|
+
}
|
|
72817
|
+
return {
|
|
72818
|
+
name: "chunks",
|
|
72819
|
+
status: "warn",
|
|
72820
|
+
detail: `${n} current chunks: past ${CHUNK_COUNT_WARN_AT.toLocaleString("en-US")}, search's exact vector scan may slow down`,
|
|
72821
|
+
hint: "Search still returns correct results; it may just take longer. Large-store support (a tuned vector index) is tracked in https://github.com/fstamatelopoulos/cerefox/issues/328; comment there with your chunk count."
|
|
72822
|
+
};
|
|
72823
|
+
}
|
|
72824
|
+
async function checkChunkCount() {
|
|
72825
|
+
const settings = loadSettings();
|
|
72826
|
+
if (!settings.supabaseUrl || !settings.supabaseKey) {
|
|
72827
|
+
return { name: "chunks", status: "skipped", detail: "Supabase config missing; skipped." };
|
|
72828
|
+
}
|
|
72829
|
+
try {
|
|
72830
|
+
const url = `${settings.supabaseUrl.replace(/\/$/, "")}/rest/v1/cerefox_chunks?select=id&version_id=is.null`;
|
|
72831
|
+
const resp = await fetch(url, {
|
|
72832
|
+
method: "HEAD",
|
|
72833
|
+
headers: {
|
|
72834
|
+
apikey: settings.supabaseKey,
|
|
72835
|
+
Authorization: `Bearer ${settings.supabaseKey}`,
|
|
72836
|
+
Prefer: "count=exact"
|
|
72837
|
+
}
|
|
72838
|
+
});
|
|
72839
|
+
const total = Number((resp.headers.get("content-range") ?? "").split("/")[1]);
|
|
72840
|
+
if (!resp.ok || !Number.isFinite(total)) {
|
|
72841
|
+
return { name: "chunks", status: "skipped", detail: `chunk count unavailable (HTTP ${resp.status})` };
|
|
72842
|
+
}
|
|
72843
|
+
return classifyChunkCount(total);
|
|
72844
|
+
} catch (err) {
|
|
72845
|
+
return {
|
|
72846
|
+
name: "chunks",
|
|
72847
|
+
status: "skipped",
|
|
72848
|
+
detail: `chunk count unavailable (${err instanceof Error ? err.message : String(err)})`
|
|
72849
|
+
};
|
|
72850
|
+
}
|
|
72851
|
+
}
|
|
72517
72852
|
var CONTENT_FORMAT_CHECK_NAME = "content format";
|
|
72518
72853
|
async function checkContentFormat() {
|
|
72519
72854
|
const settings = loadSettings();
|
|
@@ -72587,10 +72922,10 @@ async function checkMetadataHealth() {
|
|
|
72587
72922
|
};
|
|
72588
72923
|
}
|
|
72589
72924
|
function hasCerefoxInJsonFile(path) {
|
|
72590
|
-
if (!
|
|
72925
|
+
if (!existsSync12(path))
|
|
72591
72926
|
return false;
|
|
72592
72927
|
try {
|
|
72593
|
-
const parsed = JSON.parse(
|
|
72928
|
+
const parsed = JSON.parse(readFileSync10(path, "utf8"));
|
|
72594
72929
|
const mcpServers = parsed.mcpServers;
|
|
72595
72930
|
return Boolean(mcpServers && typeof mcpServers === "object" && "cerefox" in mcpServers);
|
|
72596
72931
|
} catch {
|
|
@@ -72647,9 +72982,9 @@ async function checkWebDaemon() {
|
|
|
72647
72982
|
}
|
|
72648
72983
|
function checkMcpConfigs() {
|
|
72649
72984
|
const home = homedir7();
|
|
72650
|
-
const claudeCodeUser =
|
|
72651
|
-
const claudeCodeProj =
|
|
72652
|
-
const claudeDesktop = process.platform === "darwin" ?
|
|
72985
|
+
const claudeCodeUser = join11(home, ".claude.json");
|
|
72986
|
+
const claudeCodeProj = join11(process.cwd(), ".mcp.json");
|
|
72987
|
+
const claudeDesktop = process.platform === "darwin" ? join11(home, "Library", "Application Support", "Claude", "claude_desktop_config.json") : process.platform === "win32" ? join11(process.env.APPDATA ?? "", "Claude", "claude_desktop_config.json") : join11(home, ".config", "Claude", "claude_desktop_config.json");
|
|
72653
72988
|
const found = [];
|
|
72654
72989
|
if (hasCerefoxInJsonFile(claudeCodeUser))
|
|
72655
72990
|
found.push("Claude Code (user)");
|
|
@@ -72673,8 +73008,8 @@ function checkMcpConfigs() {
|
|
|
72673
73008
|
}
|
|
72674
73009
|
function checkLegacyShadowEnv(opts = {}) {
|
|
72675
73010
|
const activeEnv = resolveEnvFile(opts);
|
|
72676
|
-
const cwdEnv =
|
|
72677
|
-
if (!
|
|
73011
|
+
const cwdEnv = join11(opts.cwd ?? process.cwd(), ".env");
|
|
73012
|
+
if (!existsSync12(activeEnv) || !existsSync12(cwdEnv))
|
|
72678
73013
|
return null;
|
|
72679
73014
|
try {
|
|
72680
73015
|
if (realpathSync(activeEnv) === realpathSync(cwdEnv))
|
|
@@ -72836,6 +73171,7 @@ async function runAllChecks(opts = {}) {
|
|
|
72836
73171
|
{ name: "binary", phase: "Locating binary", run: () => checkBinary() },
|
|
72837
73172
|
{ name: "runtime", phase: "Inspecting runtime", run: () => checkRuntime() },
|
|
72838
73173
|
{ name: "version", phase: "Reading package version", run: () => checkVersion() },
|
|
73174
|
+
{ name: "updates", phase: "Checking npm for a newer release", run: () => checkUpdates() },
|
|
72839
73175
|
{ name: "config", phase: "Resolving config", run: () => checkConfig() },
|
|
72840
73176
|
{ name: "legacy env", phase: "Checking legacy env shadowing", run: () => checkLegacyShadowEnv() },
|
|
72841
73177
|
{ name: "retired env", phase: "Checking retired env vars", run: () => checkRetiredEnvVars() },
|
|
@@ -72845,6 +73181,7 @@ async function runAllChecks(opts = {}) {
|
|
|
72845
73181
|
{ name: "review workflow", phase: "Reading review workflow flag", run: () => checkReviewWorkflow() },
|
|
72846
73182
|
{ name: "trash auto-purge", phase: "Reading trash auto-purge settings", run: () => checkTrashAutoPurge() },
|
|
72847
73183
|
{ name: "embedder", phase: "Checking embedder consistency", run: () => checkEmbedderMismatch() },
|
|
73184
|
+
{ name: "chunks", phase: "Counting current chunks", run: () => checkChunkCount() },
|
|
72848
73185
|
{ name: "content format", phase: "Checking chunk reconstruction format", run: () => checkContentFormat() },
|
|
72849
73186
|
{ name: "metadata health", phase: "Checking metadata well-formedness", run: () => checkMetadataHealth() },
|
|
72850
73187
|
{ name: "edge functions", phase: "Probing Edge Function versions", run: () => checkEdgeFunctionsCompat() },
|
|
@@ -73246,11 +73583,11 @@ init_dist4();
|
|
|
73246
73583
|
init_escape_heuristic();
|
|
73247
73584
|
init_cli_core();
|
|
73248
73585
|
init_config();
|
|
73249
|
-
import { readFileSync as
|
|
73586
|
+
import { readFileSync as readFileSync12 } from "node:fs";
|
|
73250
73587
|
import { basename as basename2, extname as extname3 } from "node:path";
|
|
73251
73588
|
|
|
73252
73589
|
// src/ingestion/pipeline.ts
|
|
73253
|
-
import { readFileSync as
|
|
73590
|
+
import { readFileSync as readFileSync11 } from "node:fs";
|
|
73254
73591
|
import { basename, extname as extname2, resolve as resolve3 } from "node:path";
|
|
73255
73592
|
// ../../_shared/ingest/pipeline-helpers.ts
|
|
73256
73593
|
import { createHash } from "node:crypto";
|
|
@@ -73920,7 +74257,7 @@ class IngestionPipeline {
|
|
|
73920
74257
|
};
|
|
73921
74258
|
}
|
|
73922
74259
|
async ingestFile(path, opts = {}) {
|
|
73923
|
-
const text = await fileToMarkdown(path,
|
|
74260
|
+
const text = await fileToMarkdown(path, readFileSync11(path));
|
|
73924
74261
|
const absPath = resolve3(path);
|
|
73925
74262
|
const stem = basename(absPath, extname2(absPath));
|
|
73926
74263
|
return this.ingestText({
|
|
@@ -73951,11 +74288,11 @@ async function readContent(path, paste) {
|
|
|
73951
74288
|
return { content, titleFromPath: undefined };
|
|
73952
74289
|
}
|
|
73953
74290
|
if (!path) {
|
|
73954
|
-
throw userError("Provide a file path or use --paste.", "Example: cerefox ingest notes.md --title 'My Note'");
|
|
74291
|
+
throw userError("Provide a file path or use --paste.", "Example: cerefox document ingest notes.md --title 'My Note'");
|
|
73955
74292
|
}
|
|
73956
74293
|
let content;
|
|
73957
74294
|
try {
|
|
73958
|
-
content =
|
|
74295
|
+
content = readFileSync12(path, "utf8");
|
|
73959
74296
|
} catch (err) {
|
|
73960
74297
|
const msg = err instanceof Error ? err.message : String(err);
|
|
73961
74298
|
throw userError(`Cannot read ${path}: ${msg}`);
|
|
@@ -74065,14 +74402,14 @@ init_cli_core();
|
|
|
74065
74402
|
init_mcp_tools();
|
|
74066
74403
|
init_config();
|
|
74067
74404
|
init_client();
|
|
74068
|
-
import { readFileSync as
|
|
74405
|
+
import { readFileSync as readFileSync13 } from "node:fs";
|
|
74069
74406
|
function resolveText(value, what) {
|
|
74070
74407
|
if (value === undefined)
|
|
74071
74408
|
throw userError(`${what} is required.`);
|
|
74072
74409
|
if (value === "-")
|
|
74073
|
-
return
|
|
74410
|
+
return readFileSync13(0, "utf8");
|
|
74074
74411
|
if (value.startsWith("@"))
|
|
74075
|
-
return
|
|
74412
|
+
return readFileSync13(value.slice(1), "utf8");
|
|
74076
74413
|
return value;
|
|
74077
74414
|
}
|
|
74078
74415
|
function context() {
|
|
@@ -74133,7 +74470,7 @@ init_cli_core();
|
|
|
74133
74470
|
init_config();
|
|
74134
74471
|
var import_cli_progress = __toESM(require_cli_progress(), 1);
|
|
74135
74472
|
import { readdirSync as readdirSync4, statSync as statSync4 } from "node:fs";
|
|
74136
|
-
import { basename as basename3, extname as extname4, join as
|
|
74473
|
+
import { basename as basename3, extname as extname4, join as join12 } from "node:path";
|
|
74137
74474
|
function walk(dir, extensions) {
|
|
74138
74475
|
let entries;
|
|
74139
74476
|
try {
|
|
@@ -74143,7 +74480,7 @@ function walk(dir, extensions) {
|
|
|
74143
74480
|
}
|
|
74144
74481
|
const files = [];
|
|
74145
74482
|
for (const name of entries) {
|
|
74146
|
-
const full =
|
|
74483
|
+
const full = join12(dir, name);
|
|
74147
74484
|
let stat;
|
|
74148
74485
|
try {
|
|
74149
74486
|
stat = statSync4(full);
|
|
@@ -74246,20 +74583,20 @@ import { spawnSync as spawnSync4 } from "node:child_process";
|
|
|
74246
74583
|
import {
|
|
74247
74584
|
chmodSync,
|
|
74248
74585
|
copyFileSync as copyFileSync2,
|
|
74249
|
-
existsSync as
|
|
74250
|
-
mkdirSync as
|
|
74251
|
-
readFileSync as
|
|
74252
|
-
writeFileSync as
|
|
74586
|
+
existsSync as existsSync13,
|
|
74587
|
+
mkdirSync as mkdirSync6,
|
|
74588
|
+
readFileSync as readFileSync15,
|
|
74589
|
+
writeFileSync as writeFileSync7
|
|
74253
74590
|
} from "node:fs";
|
|
74254
74591
|
import { homedir as homedir8 } from "node:os";
|
|
74255
|
-
import { dirname as
|
|
74592
|
+
import { dirname as dirname6, join as join13 } from "node:path";
|
|
74256
74593
|
async function readConfigFile(path) {
|
|
74257
|
-
if (!
|
|
74594
|
+
if (!existsSync13(path)) {
|
|
74258
74595
|
throw userError(`--config file not found: ${path}`);
|
|
74259
74596
|
}
|
|
74260
74597
|
let parsed;
|
|
74261
74598
|
try {
|
|
74262
|
-
parsed = JSON.parse(
|
|
74599
|
+
parsed = JSON.parse(readFileSync15(path, "utf8"));
|
|
74263
74600
|
} catch (err) {
|
|
74264
74601
|
throw userError(`--config: invalid JSON in ${path}: ${err instanceof Error ? err.message : String(err)}`);
|
|
74265
74602
|
}
|
|
@@ -74301,7 +74638,7 @@ function parseDotEnvFile(content) {
|
|
|
74301
74638
|
return map;
|
|
74302
74639
|
}
|
|
74303
74640
|
function answersFromEnvFile(path) {
|
|
74304
|
-
const parsed = parseDotEnvFile(
|
|
74641
|
+
const parsed = parseDotEnvFile(readFileSync15(path, "utf8"));
|
|
74305
74642
|
const required = ["CEREFOX_SUPABASE_URL", "CEREFOX_SUPABASE_KEY", "OPENAI_API_KEY"];
|
|
74306
74643
|
for (const key of required) {
|
|
74307
74644
|
if (!parsed[key] || parsed[key].trim() === "") {
|
|
@@ -74525,7 +74862,7 @@ async function postWriteLifecycle(envPath, options) {
|
|
|
74525
74862
|
await Promise.resolve().then(() => init_sync_self_docs());
|
|
74526
74863
|
await runSyncSelfDocs({});
|
|
74527
74864
|
} catch (err) {
|
|
74528
|
-
warn(`Self-doc ingest failed: ${err instanceof Error ? err.message : String(err)}. Run \`cerefox
|
|
74865
|
+
warn(`Self-doc ingest failed: ${err instanceof Error ? err.message : String(err)}. Run \`cerefox guides ingest\` manually after init.`);
|
|
74529
74866
|
}
|
|
74530
74867
|
println("");
|
|
74531
74868
|
}
|
|
@@ -74549,15 +74886,15 @@ async function postWriteLifecycle(envPath, options) {
|
|
|
74549
74886
|
}
|
|
74550
74887
|
println("");
|
|
74551
74888
|
println(c.green("Done. Try:"));
|
|
74552
|
-
println(c.dim(" cerefox doctor
|
|
74553
|
-
println(c.dim(' cerefox search "…"
|
|
74554
|
-
println(c.dim(" cerefox ingest <file>
|
|
74889
|
+
println(c.dim(" cerefox doctor # verify everything"));
|
|
74890
|
+
println(c.dim(' cerefox search "…" # search the KB'));
|
|
74891
|
+
println(c.dim(" cerefox document ingest <file> # add a doc"));
|
|
74555
74892
|
println("");
|
|
74556
74893
|
println(c.dim(` Config in effect: ${envPath}`));
|
|
74557
74894
|
}
|
|
74558
74895
|
function writeAnswersTo(target, answers) {
|
|
74559
|
-
|
|
74560
|
-
|
|
74896
|
+
mkdirSync6(dirname6(target), { recursive: true });
|
|
74897
|
+
writeFileSync7(target, buildEnvFile(answers), "utf8");
|
|
74561
74898
|
if (process.platform !== "win32") {
|
|
74562
74899
|
try {
|
|
74563
74900
|
chmodSync(target, 384);
|
|
@@ -74567,12 +74904,12 @@ function writeAnswersTo(target, answers) {
|
|
|
74567
74904
|
}
|
|
74568
74905
|
}
|
|
74569
74906
|
async function action23(options) {
|
|
74570
|
-
const homeEnv =
|
|
74571
|
-
const cwdEnv =
|
|
74907
|
+
const homeEnv = join13(homedir8(), USER_STATE_DIR_NAME, ".env");
|
|
74908
|
+
const cwdEnv = join13(process.cwd(), ".env");
|
|
74572
74909
|
const explicitDir = (process.env.CEREFOX_CONFIG_DIR ?? "").trim();
|
|
74573
74910
|
if (explicitDir) {
|
|
74574
74911
|
const target = resolveEnvFile();
|
|
74575
|
-
if (
|
|
74912
|
+
if (existsSync13(target) && !options.force) {
|
|
74576
74913
|
println(c.yellow(`⚠ Config already exists at ${target}.`));
|
|
74577
74914
|
const ok = await confirm("Overwrite?", true);
|
|
74578
74915
|
if (!ok) {
|
|
@@ -74594,7 +74931,7 @@ async function action23(options) {
|
|
|
74594
74931
|
await postWriteLifecycle(target, options);
|
|
74595
74932
|
return;
|
|
74596
74933
|
}
|
|
74597
|
-
if (
|
|
74934
|
+
if (existsSync13(homeEnv) && !options.force) {
|
|
74598
74935
|
println(c.yellow(`⚠ Config already exists at ${homeEnv}.`));
|
|
74599
74936
|
const ok = await confirm("Overwrite?", true);
|
|
74600
74937
|
if (!ok) {
|
|
@@ -74615,12 +74952,12 @@ async function action23(options) {
|
|
|
74615
74952
|
await postWriteLifecycle(homeEnv, options);
|
|
74616
74953
|
return;
|
|
74617
74954
|
}
|
|
74618
|
-
if (
|
|
74955
|
+
if (existsSync13(cwdEnv) && !options.force && !options.config) {
|
|
74619
74956
|
printMigrationMenu(cwdEnv, homeEnv);
|
|
74620
74957
|
const ch = await promptMigrationChoice();
|
|
74621
74958
|
println("");
|
|
74622
74959
|
if (ch === "c") {
|
|
74623
|
-
|
|
74960
|
+
mkdirSync6(dirname6(homeEnv), { recursive: true });
|
|
74624
74961
|
copyFileSync2(cwdEnv, homeEnv);
|
|
74625
74962
|
if (process.platform !== "win32") {
|
|
74626
74963
|
try {
|
|
@@ -74693,7 +75030,7 @@ async function action24(options) {
|
|
|
74693
75030
|
throw systemError(`Project lookup failed: ${projectError.message}`);
|
|
74694
75031
|
}
|
|
74695
75032
|
if (!project) {
|
|
74696
|
-
throw userError(`Project "${options.project}" not found.`, "Run `cerefox list
|
|
75033
|
+
throw userError(`Project "${options.project}" not found.`, "Run `cerefox project list` to see available names.");
|
|
74697
75034
|
}
|
|
74698
75035
|
projectId = project.id;
|
|
74699
75036
|
}
|
|
@@ -75237,35 +75574,35 @@ function registerMigrateFormat(program) {
|
|
|
75237
75574
|
// src/cli/commands/restore.ts
|
|
75238
75575
|
init_cli_core();
|
|
75239
75576
|
init_client();
|
|
75240
|
-
import { existsSync as
|
|
75577
|
+
import { existsSync as existsSync14, readFileSync as readFileSync16, readdirSync as readdirSync5, statSync as statSync5 } from "node:fs";
|
|
75241
75578
|
import { homedir as homedir9 } from "node:os";
|
|
75242
|
-
import { join as
|
|
75579
|
+
import { join as join14, resolve as resolve4 } from "node:path";
|
|
75243
75580
|
function expandHome2(path) {
|
|
75244
75581
|
if (path === "~")
|
|
75245
75582
|
return homedir9();
|
|
75246
75583
|
if (path.startsWith("~/"))
|
|
75247
|
-
return
|
|
75584
|
+
return join14(homedir9(), path.slice(2));
|
|
75248
75585
|
return path;
|
|
75249
75586
|
}
|
|
75250
75587
|
function resolveBackupFile(target) {
|
|
75251
75588
|
const path = resolve4(expandHome2(target));
|
|
75252
|
-
if (!
|
|
75589
|
+
if (!existsSync14(path)) {
|
|
75253
75590
|
throw userError(`Backup path not found: ${target}`);
|
|
75254
75591
|
}
|
|
75255
75592
|
const stat = statSync5(path);
|
|
75256
75593
|
if (stat.isFile())
|
|
75257
75594
|
return path;
|
|
75258
|
-
const candidates = readdirSync5(path).filter((n) => n.endsWith(".json") && n.startsWith("cerefox-")).map((n) => ({ name: n, mtime: statSync5(
|
|
75595
|
+
const candidates = readdirSync5(path).filter((n) => n.endsWith(".json") && n.startsWith("cerefox-")).map((n) => ({ name: n, mtime: statSync5(join14(path, n)).mtimeMs })).sort((a, b) => b.mtime - a.mtime);
|
|
75259
75596
|
if (candidates.length === 0) {
|
|
75260
75597
|
throw userError(`No cerefox-*.json files in ${path}`);
|
|
75261
75598
|
}
|
|
75262
|
-
return
|
|
75599
|
+
return join14(path, candidates[0].name);
|
|
75263
75600
|
}
|
|
75264
75601
|
async function action31(target, options) {
|
|
75265
75602
|
const file = resolveBackupFile(target);
|
|
75266
75603
|
let payload;
|
|
75267
75604
|
try {
|
|
75268
|
-
payload = JSON.parse(
|
|
75605
|
+
payload = JSON.parse(readFileSync16(file, "utf8"));
|
|
75269
75606
|
} catch (err) {
|
|
75270
75607
|
throw userError(`Could not parse backup file ${file}: ${err instanceof Error ? err.message : String(err)}`);
|
|
75271
75608
|
}
|
|
@@ -75595,6 +75932,8 @@ function registerSearch(program) {
|
|
|
75595
75932
|
// src/cli/commands/self-update.ts
|
|
75596
75933
|
init_cli_core();
|
|
75597
75934
|
init_meta();
|
|
75935
|
+
init_update_check();
|
|
75936
|
+
init_daemon();
|
|
75598
75937
|
import { spawnSync as spawnSync5 } from "node:child_process";
|
|
75599
75938
|
function detectRuntime() {
|
|
75600
75939
|
const bin = (process.argv[1] ?? "").toLowerCase();
|
|
@@ -75625,21 +75964,19 @@ function detectRuntime() {
|
|
|
75625
75964
|
description: "npm"
|
|
75626
75965
|
};
|
|
75627
75966
|
}
|
|
75628
|
-
async function
|
|
75629
|
-
|
|
75630
|
-
|
|
75631
|
-
|
|
75632
|
-
|
|
75633
|
-
|
|
75634
|
-
|
|
75635
|
-
throw systemError("npm registry response missing version field.");
|
|
75967
|
+
async function fetchLatest() {
|
|
75968
|
+
try {
|
|
75969
|
+
const latest = await fetchLatestVersion({ timeoutMs: 15000 });
|
|
75970
|
+
recordLatest(latest);
|
|
75971
|
+
return latest;
|
|
75972
|
+
} catch (err) {
|
|
75973
|
+
throw systemError(`Could not query the npm registry: ${err instanceof Error ? err.message : String(err)}`);
|
|
75636
75974
|
}
|
|
75637
|
-
return body.version;
|
|
75638
75975
|
}
|
|
75639
75976
|
async function action33(options) {
|
|
75640
75977
|
let target;
|
|
75641
75978
|
try {
|
|
75642
|
-
target = options.version ?? await
|
|
75979
|
+
target = options.version ?? await fetchLatest();
|
|
75643
75980
|
} catch (err) {
|
|
75644
75981
|
if (err instanceof Error)
|
|
75645
75982
|
throw err;
|
|
@@ -75647,12 +75984,12 @@ async function action33(options) {
|
|
|
75647
75984
|
}
|
|
75648
75985
|
println(c.dim(`Installed: ${PKG_VERSION}`));
|
|
75649
75986
|
println(c.dim(`Target: ${target}`));
|
|
75650
|
-
if (
|
|
75987
|
+
if (!options.version && !newerRelease(target)) {
|
|
75651
75988
|
println(c.green("✓ Already up to date."));
|
|
75652
75989
|
return;
|
|
75653
75990
|
}
|
|
75654
75991
|
if (options.check) {
|
|
75655
|
-
if (target
|
|
75992
|
+
if (newerRelease(target)) {
|
|
75656
75993
|
println(c.yellow(`Update available: ${PKG_VERSION} → ${target}`));
|
|
75657
75994
|
println(c.dim("Run `cerefox self-update` to upgrade."));
|
|
75658
75995
|
}
|
|
@@ -75740,8 +76077,8 @@ init_config();
|
|
|
75740
76077
|
import { randomBytes } from "node:crypto";
|
|
75741
76078
|
|
|
75742
76079
|
// src/cli/util/env-file.ts
|
|
75743
|
-
import { copyFileSync as copyFileSync3, existsSync as
|
|
75744
|
-
import { dirname as
|
|
76080
|
+
import { copyFileSync as copyFileSync3, existsSync as existsSync15, readFileSync as readFileSync17, writeFileSync as writeFileSync8 } from "node:fs";
|
|
76081
|
+
import { dirname as dirname7 } from "node:path";
|
|
75745
76082
|
import { spawnSync as spawnSync6 } from "node:child_process";
|
|
75746
76083
|
function escapeRegExp(s) {
|
|
75747
76084
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
@@ -75750,12 +76087,12 @@ function upsertEnvVar(path, key, value, opts = {}) {
|
|
|
75750
76087
|
const line = `${key}=${value}`;
|
|
75751
76088
|
const header = opts.comment ? `# ${opts.comment}
|
|
75752
76089
|
` : "";
|
|
75753
|
-
if (!
|
|
75754
|
-
|
|
76090
|
+
if (!existsSync15(path)) {
|
|
76091
|
+
writeFileSync8(path, `${header}${line}
|
|
75755
76092
|
`, { mode: 384 });
|
|
75756
76093
|
return { path, action: "created" };
|
|
75757
76094
|
}
|
|
75758
|
-
const original =
|
|
76095
|
+
const original = readFileSync17(path, "utf8");
|
|
75759
76096
|
let backupPath;
|
|
75760
76097
|
if (!opts.noBackup) {
|
|
75761
76098
|
backupPath = `${path}.pre-cerefox.bak`;
|
|
@@ -75776,18 +76113,18 @@ ${header}${line}
|
|
|
75776
76113
|
`;
|
|
75777
76114
|
action = "added";
|
|
75778
76115
|
}
|
|
75779
|
-
|
|
76116
|
+
writeFileSync8(path, next);
|
|
75780
76117
|
return { path, action, backupPath };
|
|
75781
76118
|
}
|
|
75782
76119
|
function readEnvVar(path, key) {
|
|
75783
|
-
if (!
|
|
76120
|
+
if (!existsSync15(path))
|
|
75784
76121
|
return null;
|
|
75785
|
-
const m =
|
|
76122
|
+
const m = readFileSync17(path, "utf8").match(new RegExp(`^\\s*${escapeRegExp(key)}=(.*)$`, "m"));
|
|
75786
76123
|
return m ? m[1].trim() : null;
|
|
75787
76124
|
}
|
|
75788
76125
|
function envGitignoreWarning(path) {
|
|
75789
76126
|
try {
|
|
75790
|
-
const dir =
|
|
76127
|
+
const dir = dirname7(path);
|
|
75791
76128
|
const inTree = spawnSync6("git", ["-C", dir, "rev-parse", "--is-inside-work-tree"], {
|
|
75792
76129
|
encoding: "utf8"
|
|
75793
76130
|
});
|
|
@@ -75802,146 +76139,8 @@ function envGitignoreWarning(path) {
|
|
|
75802
76139
|
}
|
|
75803
76140
|
}
|
|
75804
76141
|
|
|
75805
|
-
// src/web/auth.ts
|
|
75806
|
-
import { existsSync as existsSync15 } from "node:fs";
|
|
75807
|
-
|
|
75808
|
-
// ../../node_modules/.bun/@hono+node-server@2.1.1+2ac783cc5e75a70c/node_modules/@hono/node-server/dist/conninfo.mjs
|
|
75809
|
-
var getConnInfo = (c) => {
|
|
75810
|
-
const bindings = c.env.server ? c.env.server : c.env;
|
|
75811
|
-
const address = bindings.incoming.socket.remoteAddress;
|
|
75812
|
-
const port = bindings.incoming.socket.remotePort;
|
|
75813
|
-
const family = bindings.incoming.socket.remoteFamily;
|
|
75814
|
-
return { remote: {
|
|
75815
|
-
address,
|
|
75816
|
-
port,
|
|
75817
|
-
addressType: family === "IPv4" ? "IPv4" : family === "IPv6" ? "IPv6" : undefined
|
|
75818
|
-
} };
|
|
75819
|
-
};
|
|
75820
|
-
|
|
75821
|
-
// ../../_shared/mcp-auth/index.ts
|
|
75822
|
-
function constantTimeEqual(a, b) {
|
|
75823
|
-
const ab = new TextEncoder().encode(a);
|
|
75824
|
-
const bb = new TextEncoder().encode(b);
|
|
75825
|
-
const len = Math.max(ab.length, bb.length);
|
|
75826
|
-
let diff = ab.length ^ bb.length;
|
|
75827
|
-
for (let i = 0;i < len; i++) {
|
|
75828
|
-
diff |= (ab[i] ?? 0) ^ (bb[i] ?? 0);
|
|
75829
|
-
}
|
|
75830
|
-
return diff === 0;
|
|
75831
|
-
}
|
|
75832
|
-
|
|
75833
|
-
// ../../_shared/ef-auth/index.ts
|
|
75834
|
-
function parseAccessTokens(raw) {
|
|
75835
|
-
if (!raw)
|
|
75836
|
-
return [];
|
|
75837
|
-
return raw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
75838
|
-
}
|
|
75839
|
-
var BEARER_PREFIX = "Bearer ";
|
|
75840
|
-
function checkAccessToken(authorizationHeader, config) {
|
|
75841
|
-
if (!authorizationHeader || !authorizationHeader.startsWith(BEARER_PREFIX)) {
|
|
75842
|
-
return { ok: false, reason: "no_token" };
|
|
75843
|
-
}
|
|
75844
|
-
const token = authorizationHeader.slice(BEARER_PREFIX.length).trim();
|
|
75845
|
-
if (!token)
|
|
75846
|
-
return { ok: false, reason: "no_token" };
|
|
75847
|
-
if (config.tokens.length === 0) {
|
|
75848
|
-
return {
|
|
75849
|
-
ok: false,
|
|
75850
|
-
reason: "no_tokens_configured",
|
|
75851
|
-
detail: "CEREFOX_ACCESS_TOKENS is unset/empty; refusing to accept-all"
|
|
75852
|
-
};
|
|
75853
|
-
}
|
|
75854
|
-
let matched = false;
|
|
75855
|
-
for (const accepted of config.tokens) {
|
|
75856
|
-
if (constantTimeEqual(token, accepted))
|
|
75857
|
-
matched = true;
|
|
75858
|
-
}
|
|
75859
|
-
return matched ? { ok: true } : { ok: false, reason: "bad_token" };
|
|
75860
|
-
}
|
|
75861
|
-
|
|
75862
|
-
// src/web/auth.ts
|
|
75863
|
-
var API_KEY_PREFIX = "cfx_lak_";
|
|
75864
|
-
var LOOPBACK_ADDRESSES = new Set([
|
|
75865
|
-
"127.0.0.1",
|
|
75866
|
-
"::1",
|
|
75867
|
-
"::ffff:127.0.0.1"
|
|
75868
|
-
]);
|
|
75869
|
-
function isContainerised() {
|
|
75870
|
-
try {
|
|
75871
|
-
return existsSync15("/.dockerenv");
|
|
75872
|
-
} catch {
|
|
75873
|
-
return false;
|
|
75874
|
-
}
|
|
75875
|
-
}
|
|
75876
|
-
function containerGateWarning(env = process.env) {
|
|
75877
|
-
const hasKey = (env.CEREFOX_API_KEY ?? "").trim() !== "";
|
|
75878
|
-
const requireAll = (env.CEREFOX_API_REQUIRE_KEY ?? "") === "1";
|
|
75879
|
-
if (!hasKey || requireAll || !isContainerised())
|
|
75880
|
-
return null;
|
|
75881
|
-
return `
|
|
75882
|
-
⚠ CEREFOX_API_KEY is set inside a container without CEREFOX_API_REQUIRE_KEY=1.
|
|
75883
|
-
` + ` Docker rewrites the source address of every published-port request, so the
|
|
75884
|
-
` + ` loopback exemption cannot match and EVERY caller will get a 401 — including
|
|
75885
|
-
` + ` the web UI. In a container the gate must be all-or-nothing:
|
|
75886
|
-
` + ` • publishing on 127.0.0.1 → leave CEREFOX_API_KEY unset (the bind is the boundary)
|
|
75887
|
-
` + ` • publishing wider → also set CEREFOX_API_REQUIRE_KEY=1
|
|
75888
|
-
`;
|
|
75889
|
-
}
|
|
75890
|
-
function isLoopbackAddress(address) {
|
|
75891
|
-
if (!address)
|
|
75892
|
-
return false;
|
|
75893
|
-
return LOOPBACK_ADDRESSES.has(address.trim().toLowerCase());
|
|
75894
|
-
}
|
|
75895
|
-
function decideAuth(input) {
|
|
75896
|
-
const keys = input.configuredKeys.trim();
|
|
75897
|
-
if (!keys)
|
|
75898
|
-
return { allow: true, reason: "disabled" };
|
|
75899
|
-
const local = isLoopbackAddress(input.remoteAddress);
|
|
75900
|
-
if (local && !input.requireKeyEverywhere) {
|
|
75901
|
-
return { allow: true, reason: "loopback" };
|
|
75902
|
-
}
|
|
75903
|
-
const result = checkAccessToken(input.authorization, {
|
|
75904
|
-
tokens: parseAccessTokens(keys)
|
|
75905
|
-
});
|
|
75906
|
-
if (result.ok)
|
|
75907
|
-
return { allow: true, reason: "valid_key" };
|
|
75908
|
-
if (result.reason === "no_token") {
|
|
75909
|
-
return {
|
|
75910
|
-
allow: false,
|
|
75911
|
-
reason: "no_key",
|
|
75912
|
-
message: local ? "This server requires an API key on every request (CEREFOX_API_REQUIRE_KEY is set). " + "Send it as `Authorization: Bearer <key>`." : "This request did not come from the local machine, so it needs the server's API key " + "as `Authorization: Bearer <key>`. Print it with `cerefox api-key show` " + "(or `cerefox-local api-key` for a container install)."
|
|
75913
|
-
};
|
|
75914
|
-
}
|
|
75915
|
-
return {
|
|
75916
|
-
allow: false,
|
|
75917
|
-
reason: "bad_key",
|
|
75918
|
-
message: "The API key presented is not valid for this server."
|
|
75919
|
-
};
|
|
75920
|
-
}
|
|
75921
|
-
function apiAuth() {
|
|
75922
|
-
return async (c, next) => {
|
|
75923
|
-
const decision = decideAuth({
|
|
75924
|
-
remoteAddress: remoteAddressOf(c),
|
|
75925
|
-
authorization: c.req.header("Authorization") ?? null,
|
|
75926
|
-
configuredKeys: process.env.CEREFOX_API_KEY ?? "",
|
|
75927
|
-
requireKeyEverywhere: (process.env.CEREFOX_API_REQUIRE_KEY ?? "") === "1"
|
|
75928
|
-
});
|
|
75929
|
-
if (decision.allow)
|
|
75930
|
-
return next();
|
|
75931
|
-
return c.json({ detail: decision.message }, 401, {
|
|
75932
|
-
"WWW-Authenticate": 'Bearer realm="cerefox"'
|
|
75933
|
-
});
|
|
75934
|
-
};
|
|
75935
|
-
}
|
|
75936
|
-
function remoteAddressOf(c) {
|
|
75937
|
-
try {
|
|
75938
|
-
return getConnInfo(c).remote.address;
|
|
75939
|
-
} catch {
|
|
75940
|
-
return;
|
|
75941
|
-
}
|
|
75942
|
-
}
|
|
75943
|
-
|
|
75944
76142
|
// src/cli/commands/api-key.ts
|
|
76143
|
+
init_auth();
|
|
75945
76144
|
var ENV_NAME = "CEREFOX_API_KEY";
|
|
75946
76145
|
function mint() {
|
|
75947
76146
|
return API_KEY_PREFIX + randomBytes(32).toString("base64url");
|
|
@@ -76146,7 +76345,7 @@ init_sync_self_docs();
|
|
|
76146
76345
|
|
|
76147
76346
|
// src/cli/commands/web.ts
|
|
76148
76347
|
init_cli_core();
|
|
76149
|
-
import { readFileSync as
|
|
76348
|
+
import { readFileSync as readFileSync21 } from "node:fs";
|
|
76150
76349
|
|
|
76151
76350
|
// ../../node_modules/.bun/@hono+node-server@2.1.1+2ac783cc5e75a70c/node_modules/@hono/node-server/dist/constants-BLSFu_RU.mjs
|
|
76152
76351
|
var X_ALREADY_SENT = "x-hono-already-sent";
|
|
@@ -77748,7 +77947,7 @@ var baseMimes = _baseMimes;
|
|
|
77748
77947
|
|
|
77749
77948
|
// ../../node_modules/.bun/@hono+node-server@2.1.1+2ac783cc5e75a70c/node_modules/@hono/node-server/dist/serve-static.mjs
|
|
77750
77949
|
import { createReadStream, existsSync as existsSync16, statSync as statSync6 } from "node:fs";
|
|
77751
|
-
import { join as
|
|
77950
|
+
import { join as join15 } from "node:path";
|
|
77752
77951
|
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;
|
|
77753
77952
|
var ENCODINGS = {
|
|
77754
77953
|
br: ".br",
|
|
@@ -77838,11 +78037,11 @@ var serveStatic = (options = { root: "" }) => {
|
|
|
77838
78037
|
await options.onNotFound?.(c.req.path, c);
|
|
77839
78038
|
return next();
|
|
77840
78039
|
}
|
|
77841
|
-
let path =
|
|
78040
|
+
let path = join15(root, !optionPath && options.rewriteRequestPath ? options.rewriteRequestPath(filename, c) : filename);
|
|
77842
78041
|
let stats = getStats(path);
|
|
77843
78042
|
if (stats && stats.isDirectory()) {
|
|
77844
78043
|
const indexFile = options.index ?? "index.html";
|
|
77845
|
-
path =
|
|
78044
|
+
path = join15(path, indexFile);
|
|
77846
78045
|
stats = getStats(path);
|
|
77847
78046
|
}
|
|
77848
78047
|
if (!stats) {
|
|
@@ -77904,9 +78103,10 @@ var serveStatic = (options = { root: "" }) => {
|
|
|
77904
78103
|
};
|
|
77905
78104
|
|
|
77906
78105
|
// src/web/server.ts
|
|
78106
|
+
init_auth();
|
|
77907
78107
|
import { existsSync as existsSync20 } from "node:fs";
|
|
77908
|
-
import { readFileSync as
|
|
77909
|
-
import { join as
|
|
78108
|
+
import { readFileSync as readFileSync20, statSync as statSync9 } from "node:fs";
|
|
78109
|
+
import { join as join19 } from "node:path";
|
|
77910
78110
|
|
|
77911
78111
|
// ../../node_modules/.bun/hono@4.13.7/node_modules/hono/dist/compose.js
|
|
77912
78112
|
var compose = (middleware, onError, onNotFound) => {
|
|
@@ -81165,18 +81365,19 @@ function registerIngestRoutes(app, ctx) {
|
|
|
81165
81365
|
// src/web/routes/meta.ts
|
|
81166
81366
|
init_server_assets();
|
|
81167
81367
|
init_meta();
|
|
81368
|
+
init_update_check();
|
|
81168
81369
|
import { execFileSync } from "node:child_process";
|
|
81169
|
-
import { dirname as
|
|
81370
|
+
import { dirname as dirname9 } from "node:path";
|
|
81170
81371
|
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
81171
81372
|
|
|
81172
81373
|
// src/web/docs.ts
|
|
81173
81374
|
import {
|
|
81174
81375
|
existsSync as existsSync17,
|
|
81175
|
-
readFileSync as
|
|
81376
|
+
readFileSync as readFileSync18,
|
|
81176
81377
|
readdirSync as readdirSync6,
|
|
81177
81378
|
statSync as statSync7
|
|
81178
81379
|
} from "node:fs";
|
|
81179
|
-
import { basename as basename5, dirname as
|
|
81380
|
+
import { basename as basename5, dirname as dirname8, join as join16, resolve as resolve5 } from "node:path";
|
|
81180
81381
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
81181
81382
|
var TOP_LEVEL_DOCS = [
|
|
81182
81383
|
{ filename: "README.md", path: "README.md", category: "readme" },
|
|
@@ -81192,37 +81393,37 @@ var TOP_LEVEL_DOCS = [
|
|
|
81192
81393
|
}
|
|
81193
81394
|
];
|
|
81194
81395
|
function moduleDir2() {
|
|
81195
|
-
return
|
|
81396
|
+
return dirname8(fileURLToPath3(import.meta.url));
|
|
81196
81397
|
}
|
|
81197
81398
|
function resolveDocsRoots() {
|
|
81198
81399
|
const here = moduleDir2();
|
|
81199
81400
|
const pkgRootCandidates = [
|
|
81200
|
-
|
|
81201
|
-
|
|
81401
|
+
join16(here, "..", ".."),
|
|
81402
|
+
join16(here, "..", "..", "..", "..")
|
|
81202
81403
|
];
|
|
81203
81404
|
let pkgGuides = null;
|
|
81204
81405
|
let pkgTopLevel = null;
|
|
81205
81406
|
for (const pkg of pkgRootCandidates) {
|
|
81206
|
-
const guides =
|
|
81407
|
+
const guides = join16(pkg, "docs", "guides");
|
|
81207
81408
|
if (existsSync17(guides) && statSync7(guides).isDirectory()) {
|
|
81208
81409
|
pkgGuides = guides;
|
|
81209
81410
|
pkgTopLevel = pkg;
|
|
81210
81411
|
break;
|
|
81211
81412
|
}
|
|
81212
81413
|
}
|
|
81213
|
-
const repoCandidate =
|
|
81214
|
-
const repoGuides =
|
|
81414
|
+
const repoCandidate = join16(here, "..", "..", "..", "..");
|
|
81415
|
+
const repoGuides = join16(repoCandidate, "docs", "guides");
|
|
81215
81416
|
const repoTopLevel = repoCandidate;
|
|
81216
81417
|
return {
|
|
81217
81418
|
pkgGuides,
|
|
81218
81419
|
pkgTopLevel,
|
|
81219
81420
|
repoGuides: existsSync17(repoGuides) ? repoGuides : null,
|
|
81220
|
-
repoTopLevel: existsSync17(
|
|
81421
|
+
repoTopLevel: existsSync17(join16(repoTopLevel, "README.md")) ? repoTopLevel : null
|
|
81221
81422
|
};
|
|
81222
81423
|
}
|
|
81223
81424
|
function readH1(filePath) {
|
|
81224
81425
|
try {
|
|
81225
|
-
const content =
|
|
81426
|
+
const content = readFileSync18(filePath, "utf8");
|
|
81226
81427
|
const match = content.match(/^#\s+(.+?)\s*$/m);
|
|
81227
81428
|
return match ? match[1] : null;
|
|
81228
81429
|
} catch {
|
|
@@ -81242,7 +81443,7 @@ function listBundledDocs2() {
|
|
|
81242
81443
|
const topRoot = pkgTopLevel ?? repoTopLevel;
|
|
81243
81444
|
if (topRoot) {
|
|
81244
81445
|
for (const t of TOP_LEVEL_DOCS) {
|
|
81245
|
-
const abs =
|
|
81446
|
+
const abs = join16(topRoot, t.filename);
|
|
81246
81447
|
if (existsSync17(abs)) {
|
|
81247
81448
|
entries.push(entryForFile(abs, t.path, t.category));
|
|
81248
81449
|
}
|
|
@@ -81252,7 +81453,7 @@ function listBundledDocs2() {
|
|
|
81252
81453
|
if (guidesRoot) {
|
|
81253
81454
|
const names = readdirSync6(guidesRoot).filter((n) => n.endsWith(".md")).sort();
|
|
81254
81455
|
for (const name of names) {
|
|
81255
|
-
const abs =
|
|
81456
|
+
const abs = join16(guidesRoot, name);
|
|
81256
81457
|
entries.push(entryForFile(abs, `guides/${name}`, "guide"));
|
|
81257
81458
|
}
|
|
81258
81459
|
}
|
|
@@ -81272,7 +81473,7 @@ function readDoc(docPath) {
|
|
|
81272
81473
|
}
|
|
81273
81474
|
if (existsSync17(candidate) && statSync7(candidate).isFile()) {
|
|
81274
81475
|
try {
|
|
81275
|
-
return
|
|
81476
|
+
return readFileSync18(candidate, "utf8");
|
|
81276
81477
|
} catch {
|
|
81277
81478
|
return null;
|
|
81278
81479
|
}
|
|
@@ -81281,22 +81482,22 @@ function readDoc(docPath) {
|
|
|
81281
81482
|
}
|
|
81282
81483
|
function readOpenApiDocument() {
|
|
81283
81484
|
const here = moduleDir2();
|
|
81284
|
-
const fromSource = here.endsWith(
|
|
81285
|
-
const repoCopy =
|
|
81485
|
+
const fromSource = here.endsWith(join16("src", "web"));
|
|
81486
|
+
const repoCopy = join16(here, "..", "..", "..", "..", "docs", "api", "openapi.json");
|
|
81286
81487
|
const candidates = fromSource ? [repoCopy] : [
|
|
81287
|
-
|
|
81488
|
+
join16(here, "..", "..", "docs", "api", "openapi.json"),
|
|
81288
81489
|
repoCopy
|
|
81289
81490
|
];
|
|
81290
81491
|
for (const p of candidates) {
|
|
81291
81492
|
if (existsSync17(p))
|
|
81292
|
-
return
|
|
81493
|
+
return readFileSync18(p, "utf8");
|
|
81293
81494
|
}
|
|
81294
81495
|
return null;
|
|
81295
81496
|
}
|
|
81296
81497
|
|
|
81297
81498
|
// src/web/routes/meta.ts
|
|
81298
81499
|
init_compatibility();
|
|
81299
|
-
function resolveGitCommitShort(dir =
|
|
81500
|
+
function resolveGitCommitShort(dir = dirname9(fileURLToPath4(import.meta.url))) {
|
|
81300
81501
|
const env = process.env.CEREFOX_GIT_COMMIT;
|
|
81301
81502
|
if (env)
|
|
81302
81503
|
return env.slice(0, 7);
|
|
@@ -81319,7 +81520,13 @@ var VERSION_INFO = {
|
|
|
81319
81520
|
function registerMetaRoutes(app, ctx) {
|
|
81320
81521
|
app.get("/api/v1/version", (c) => {
|
|
81321
81522
|
const label = (process.env.CEREFOX_ENV_LABEL ?? "").trim();
|
|
81322
|
-
|
|
81523
|
+
const latest = updateCheckDisabled() ? null : readCache()?.latest ?? null;
|
|
81524
|
+
return c.json({
|
|
81525
|
+
...VERSION_INFO,
|
|
81526
|
+
env_label: label.length > 0 ? label : null,
|
|
81527
|
+
latest,
|
|
81528
|
+
update_command: newerRelease(latest) ? upgradeCommand() : null
|
|
81529
|
+
});
|
|
81323
81530
|
});
|
|
81324
81531
|
app.get("/api/v1/docs", (c) => c.json(listBundledDocs2()));
|
|
81325
81532
|
app.get("/api/v1/docs/:path{.+}", (c) => {
|
|
@@ -81428,17 +81635,17 @@ function registerPostgrestProxy(app) {
|
|
|
81428
81635
|
|
|
81429
81636
|
// src/web/routes/preferences.ts
|
|
81430
81637
|
init_config();
|
|
81431
|
-
import { existsSync as existsSync18, mkdirSync as
|
|
81432
|
-
import { join as
|
|
81638
|
+
import { existsSync as existsSync18, mkdirSync as mkdirSync7, readFileSync as readFileSync19, writeFileSync as writeFileSync9 } from "node:fs";
|
|
81639
|
+
import { join as join17 } from "node:path";
|
|
81433
81640
|
function isTheme(v) {
|
|
81434
81641
|
return v === "auto" || v === "light" || v === "dark";
|
|
81435
81642
|
}
|
|
81436
81643
|
function prefsFile() {
|
|
81437
|
-
return
|
|
81644
|
+
return join17(userStateDir(), "web-prefs.json");
|
|
81438
81645
|
}
|
|
81439
81646
|
function readPrefs() {
|
|
81440
81647
|
try {
|
|
81441
|
-
const raw = JSON.parse(
|
|
81648
|
+
const raw = JSON.parse(readFileSync19(prefsFile(), "utf8"));
|
|
81442
81649
|
if (isTheme(raw.theme))
|
|
81443
81650
|
return { theme: raw.theme };
|
|
81444
81651
|
} catch {}
|
|
@@ -81455,8 +81662,8 @@ function registerPreferencesRoutes(app) {
|
|
|
81455
81662
|
try {
|
|
81456
81663
|
const dir = userStateDir();
|
|
81457
81664
|
if (!existsSync18(dir))
|
|
81458
|
-
|
|
81459
|
-
|
|
81665
|
+
mkdirSync7(dir, { recursive: true });
|
|
81666
|
+
writeFileSync9(prefsFile(), `${JSON.stringify(next, null, 2)}
|
|
81460
81667
|
`);
|
|
81461
81668
|
} catch (err) {
|
|
81462
81669
|
return c.json({ detail: err instanceof Error ? err.message : String(err) }, 500);
|
|
@@ -81592,20 +81799,20 @@ function registerProjectsRoutes(app, ctx) {
|
|
|
81592
81799
|
|
|
81593
81800
|
// src/web/static.ts
|
|
81594
81801
|
import { existsSync as existsSync19, statSync as statSync8 } from "node:fs";
|
|
81595
|
-
import { dirname as
|
|
81802
|
+
import { dirname as dirname10, join as join18 } from "node:path";
|
|
81596
81803
|
import { fileURLToPath as fileURLToPath5 } from "node:url";
|
|
81597
81804
|
function moduleDir3() {
|
|
81598
|
-
return
|
|
81805
|
+
return dirname10(fileURLToPath5(import.meta.url));
|
|
81599
81806
|
}
|
|
81600
81807
|
function isUsableSpaDir(dir) {
|
|
81601
|
-
return existsSync19(dir) && statSync8(dir).isDirectory() && existsSync19(
|
|
81808
|
+
return existsSync19(dir) && statSync8(dir).isDirectory() && existsSync19(join18(dir, "index.html"));
|
|
81602
81809
|
}
|
|
81603
81810
|
function resolveSpaDist() {
|
|
81604
81811
|
const here = moduleDir3();
|
|
81605
81812
|
const candidates = [
|
|
81606
|
-
|
|
81607
|
-
|
|
81608
|
-
|
|
81813
|
+
join18(here, "..", "frontend"),
|
|
81814
|
+
join18(here, "..", "..", "..", "..", "frontend", "dist"),
|
|
81815
|
+
join18(here, "..", "..", "dist", "frontend")
|
|
81609
81816
|
];
|
|
81610
81817
|
for (const c of candidates) {
|
|
81611
81818
|
if (isUsableSpaDir(c))
|
|
@@ -81616,8 +81823,8 @@ function resolveSpaDist() {
|
|
|
81616
81823
|
function resolveStaticDir() {
|
|
81617
81824
|
const here = moduleDir3();
|
|
81618
81825
|
const candidates = [
|
|
81619
|
-
|
|
81620
|
-
|
|
81826
|
+
join18(here, "..", "static"),
|
|
81827
|
+
join18(here, "..", "..", "..", "..", "web", "static")
|
|
81621
81828
|
];
|
|
81622
81829
|
for (const c of candidates) {
|
|
81623
81830
|
if (existsSync19(c) && statSync8(c).isDirectory())
|
|
@@ -81663,6 +81870,7 @@ var ROOT_REDIRECT_HTML = `<!DOCTYPE html>
|
|
|
81663
81870
|
|
|
81664
81871
|
// src/web/server.ts
|
|
81665
81872
|
init_meta();
|
|
81873
|
+
init_update_check();
|
|
81666
81874
|
init_ef_meta();
|
|
81667
81875
|
init_cli_core();
|
|
81668
81876
|
init_config();
|
|
@@ -81716,14 +81924,14 @@ function buildApp(ctx = buildWebContext()) {
|
|
|
81716
81924
|
rewriteRequestPath: (path) => path.replace(/^\/app/, "") || "/"
|
|
81717
81925
|
}));
|
|
81718
81926
|
app.get("/app/assets/*", (c) => c.text("Not found", 404));
|
|
81719
|
-
const indexPath =
|
|
81927
|
+
const indexPath = join19(spaDist, "index.html");
|
|
81720
81928
|
if (existsSync20(indexPath)) {
|
|
81721
81929
|
let cached = null;
|
|
81722
81930
|
const readIndex = () => {
|
|
81723
81931
|
try {
|
|
81724
81932
|
const { mtimeMs, size } = statSync9(indexPath);
|
|
81725
81933
|
if (!cached || cached.mtimeMs !== mtimeMs || cached.size !== size) {
|
|
81726
|
-
cached = { mtimeMs, size, html:
|
|
81934
|
+
cached = { mtimeMs, size, html: readFileSync20(indexPath, "utf8") };
|
|
81727
81935
|
}
|
|
81728
81936
|
} catch {}
|
|
81729
81937
|
return cached?.html ?? null;
|
|
@@ -81791,6 +81999,7 @@ async function buildWebServer(options = {}) {
|
|
|
81791
81999
|
}
|
|
81792
82000
|
const app = buildApp();
|
|
81793
82001
|
const server = serve({ fetch: app.fetch, hostname: host, port, overrideGlobalObjects: false });
|
|
82002
|
+
startPeriodicRefresh();
|
|
81794
82003
|
return {
|
|
81795
82004
|
host,
|
|
81796
82005
|
port,
|
|
@@ -81801,6 +82010,7 @@ async function buildWebServer(options = {}) {
|
|
|
81801
82010
|
}
|
|
81802
82011
|
|
|
81803
82012
|
// src/cli/commands/web.ts
|
|
82013
|
+
init_daemon();
|
|
81804
82014
|
init_meta();
|
|
81805
82015
|
function parsePort(raw) {
|
|
81806
82016
|
const port = Number.parseInt(raw, 10);
|
|
@@ -81837,7 +82047,7 @@ async function runForeground(host, port, watch) {
|
|
|
81837
82047
|
}
|
|
81838
82048
|
function readStartupRefusal() {
|
|
81839
82049
|
try {
|
|
81840
|
-
const tail =
|
|
82050
|
+
const tail = readFileSync21(daemonPaths.logFile, "utf8").slice(-4000);
|
|
81841
82051
|
const idx = tail.lastIndexOf("Refusing to start:");
|
|
81842
82052
|
if (idx === -1)
|
|
81843
82053
|
return null;
|
|
@@ -82093,17 +82303,17 @@ async function bareEntryPoint() {
|
|
|
82093
82303
|
println(" " + c.bold("cerefox init") + " # interactive first-run setup (~2 min)");
|
|
82094
82304
|
println("");
|
|
82095
82305
|
println(c.dim("Once configured, try:"));
|
|
82096
|
-
println(c.dim(" cerefox doctor
|
|
82097
|
-
println(c.dim(' cerefox search "…"
|
|
82098
|
-
println(c.dim(" cerefox ingest <file>
|
|
82306
|
+
println(c.dim(" cerefox doctor # verify your install"));
|
|
82307
|
+
println(c.dim(' cerefox search "…" # search the KB'));
|
|
82308
|
+
println(c.dim(" cerefox document ingest <file> # add a doc"));
|
|
82099
82309
|
} else {
|
|
82100
82310
|
println(c.green("✓ Config detected. You're good to go."));
|
|
82101
82311
|
println("");
|
|
82102
82312
|
println("Common commands:");
|
|
82103
|
-
println(c.dim(" cerefox doctor
|
|
82104
|
-
println(c.dim(' cerefox search "…"
|
|
82105
|
-
println(c.dim(" cerefox ingest <file>
|
|
82106
|
-
println(c.dim(" cerefox configure-agent
|
|
82313
|
+
println(c.dim(" cerefox doctor # diagnose your install"));
|
|
82314
|
+
println(c.dim(' cerefox search "…" # search the KB'));
|
|
82315
|
+
println(c.dim(" cerefox document ingest <file> # add a doc"));
|
|
82316
|
+
println(c.dim(" cerefox configure-agent # wire up an MCP client"));
|
|
82107
82317
|
println("");
|
|
82108
82318
|
println(c.dim("Run `cerefox --help` for the full command list."));
|
|
82109
82319
|
}
|
|
@@ -82117,6 +82327,7 @@ async function main() {
|
|
|
82117
82327
|
}
|
|
82118
82328
|
if (process.argv.length === 2) {
|
|
82119
82329
|
await bareEntryPoint();
|
|
82330
|
+
await printUpdateNotice();
|
|
82120
82331
|
return;
|
|
82121
82332
|
}
|
|
82122
82333
|
const program = buildProgram();
|
|
@@ -82127,6 +82338,25 @@ async function main() {
|
|
|
82127
82338
|
process.exit(1);
|
|
82128
82339
|
});
|
|
82129
82340
|
await program.parseAsync(process.argv);
|
|
82341
|
+
await printUpdateNotice();
|
|
82342
|
+
}
|
|
82343
|
+
var NO_UPDATE_NOTICE = new Set(["mcp", "completion", "self-update", "upgrade", "doctor"]);
|
|
82344
|
+
async function printUpdateNotice() {
|
|
82345
|
+
const args = process.argv.slice(2);
|
|
82346
|
+
if (!process.stderr.isTTY || args.includes("--json"))
|
|
82347
|
+
return;
|
|
82348
|
+
if (args[0] && NO_UPDATE_NOTICE.has(args[0]))
|
|
82349
|
+
return;
|
|
82350
|
+
try {
|
|
82351
|
+
await Promise.resolve().then(() => init_update_check());
|
|
82352
|
+
const line = takeCliNotice();
|
|
82353
|
+
if (line) {
|
|
82354
|
+
await Promise.resolve().then(() => init_cli_core());
|
|
82355
|
+
process.stderr.write(`
|
|
82356
|
+
` + cErr.yellow(line) + `
|
|
82357
|
+
`);
|
|
82358
|
+
}
|
|
82359
|
+
} catch {}
|
|
82130
82360
|
}
|
|
82131
82361
|
main().catch((err) => {
|
|
82132
82362
|
if (err instanceof CliError) {
|