@cerefox/memory 1.1.0-beta.1 → 1.1.0-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/cerefox.js +511 -186
- package/dist/frontend/assets/{index-BMFGsK0D.js → index-BLqrpbNz.js} +30 -30
- package/dist/frontend/assets/index-BLqrpbNz.js.map +1 -0
- package/dist/frontend/index.html +1 -1
- package/dist/server-assets/_shared/ef-meta/index.ts +2 -2
- package/dist/server-assets/_shared/mcp-tools/feature-flags.ts +68 -0
- package/dist/server-assets/_shared/mcp-tools/index.ts +31 -1
- package/dist/server-assets/db/migrations/0014_document_relations.sql +5 -0
- package/dist/server-assets/db/rpcs.sql +4 -2
- package/dist/server-assets/db/schema.sql +6 -1
- package/dist/server-assets/supabase/functions/cerefox-mcp/index.ts +25 -8
- package/docs/guides/configuration.md +8 -1
- package/docs/guides/content-format.md +8 -1
- package/docs/guides/setup-supabase.md +35 -4
- package/package.json +1 -1
- package/dist/frontend/assets/index-BMFGsK0D.js.map +0 -1
package/dist/bin/cerefox.js
CHANGED
|
@@ -7438,9 +7438,143 @@ var exports_meta = {};
|
|
|
7438
7438
|
__export(exports_meta, {
|
|
7439
7439
|
PKG_VERSION: () => PKG_VERSION
|
|
7440
7440
|
});
|
|
7441
|
-
var PKG_VERSION = "1.1.0-beta.
|
|
7441
|
+
var PKG_VERSION = "1.1.0-beta.3";
|
|
7442
7442
|
var init_meta = () => {};
|
|
7443
7443
|
|
|
7444
|
+
// ../../_shared/config/paths.ts
|
|
7445
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
7446
|
+
import { homedir } from "node:os";
|
|
7447
|
+
import { join, resolve as resolvePath } from "node:path";
|
|
7448
|
+
import { cwd as processCwd, env } from "node:process";
|
|
7449
|
+
function expandTilde(p) {
|
|
7450
|
+
if (p === "~" || p.startsWith("~/")) {
|
|
7451
|
+
return join(homedir(), p.slice(2));
|
|
7452
|
+
}
|
|
7453
|
+
return p;
|
|
7454
|
+
}
|
|
7455
|
+
function userStateDirAbs(opts) {
|
|
7456
|
+
return resolvePath(join(opts.home ?? homedir(), USER_STATE_DIR_NAME));
|
|
7457
|
+
}
|
|
7458
|
+
function resolveConfigDir(opts = {}) {
|
|
7459
|
+
const override = (env.CEREFOX_CONFIG_DIR ?? "").trim();
|
|
7460
|
+
if (override) {
|
|
7461
|
+
return resolvePath(expandTilde(override));
|
|
7462
|
+
}
|
|
7463
|
+
const userState = userStateDirAbs(opts);
|
|
7464
|
+
if (existsSync(join(userState, ".env"))) {
|
|
7465
|
+
return userState;
|
|
7466
|
+
}
|
|
7467
|
+
const here = opts.cwd ?? processCwd();
|
|
7468
|
+
const cwdEnv = join(here, ".env");
|
|
7469
|
+
if (existsSync(cwdEnv) && cwdEnvHasCerefoxKey(cwdEnv)) {
|
|
7470
|
+
return resolvePath(here);
|
|
7471
|
+
}
|
|
7472
|
+
return userState;
|
|
7473
|
+
}
|
|
7474
|
+
function cwdEnvHasCerefoxKey(envPath) {
|
|
7475
|
+
try {
|
|
7476
|
+
const contents = readFileSync(envPath, "utf8");
|
|
7477
|
+
return /^\s*CEREFOX_[A-Z0-9_]+\s*=/m.test(contents);
|
|
7478
|
+
} catch {
|
|
7479
|
+
return false;
|
|
7480
|
+
}
|
|
7481
|
+
}
|
|
7482
|
+
function resolveEnvFile(opts = {}) {
|
|
7483
|
+
return join(resolveConfigDir(opts), ".env");
|
|
7484
|
+
}
|
|
7485
|
+
function userStateDir(opts = {}) {
|
|
7486
|
+
return userStateDirAbs(opts);
|
|
7487
|
+
}
|
|
7488
|
+
function isDevMode(opts = {}) {
|
|
7489
|
+
if ((env.CEREFOX_CONFIG_DIR ?? "").trim())
|
|
7490
|
+
return false;
|
|
7491
|
+
if (existsSync(join(userStateDirAbs(opts), ".env")))
|
|
7492
|
+
return false;
|
|
7493
|
+
const here = opts.cwd ?? processCwd();
|
|
7494
|
+
const cwdEnv = join(here, ".env");
|
|
7495
|
+
return existsSync(cwdEnv) && cwdEnvHasCerefoxKey(cwdEnv);
|
|
7496
|
+
}
|
|
7497
|
+
var USER_STATE_DIR_NAME = ".cerefox";
|
|
7498
|
+
var init_paths = () => {};
|
|
7499
|
+
|
|
7500
|
+
// ../../_shared/config/env.ts
|
|
7501
|
+
import { readFileSync as readFileSync2 } from "node:fs";
|
|
7502
|
+
import { env as env2 } from "node:process";
|
|
7503
|
+
function parseDotenv(content) {
|
|
7504
|
+
const result = {};
|
|
7505
|
+
for (const rawLine of content.split(/\r?\n/)) {
|
|
7506
|
+
const line = rawLine.trim();
|
|
7507
|
+
if (!line || line.startsWith("#"))
|
|
7508
|
+
continue;
|
|
7509
|
+
const match = line.match(KV_LINE);
|
|
7510
|
+
if (!match)
|
|
7511
|
+
continue;
|
|
7512
|
+
let value = match[2];
|
|
7513
|
+
if (value.length >= 2 && (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'"))) {
|
|
7514
|
+
value = value.slice(1, -1);
|
|
7515
|
+
}
|
|
7516
|
+
result[match[1]] = value;
|
|
7517
|
+
}
|
|
7518
|
+
return result;
|
|
7519
|
+
}
|
|
7520
|
+
function loadEnv(opts = {}) {
|
|
7521
|
+
if (_loaded) {
|
|
7522
|
+
return { path: "(already loaded)", vars: 0 };
|
|
7523
|
+
}
|
|
7524
|
+
_loaded = true;
|
|
7525
|
+
const envPath = resolveEnvFile(opts);
|
|
7526
|
+
let content;
|
|
7527
|
+
try {
|
|
7528
|
+
content = readFileSync2(envPath, "utf8");
|
|
7529
|
+
} catch {
|
|
7530
|
+
return { path: envPath, vars: 0 };
|
|
7531
|
+
}
|
|
7532
|
+
const configDirNamed = (env2.CEREFOX_CONFIG_DIR ?? "").trim() !== "";
|
|
7533
|
+
let count = 0;
|
|
7534
|
+
for (const [k, v] of Object.entries(parseDotenv(content))) {
|
|
7535
|
+
if (k === "CEREFOX_CONFIG_DIR")
|
|
7536
|
+
continue;
|
|
7537
|
+
if (env2[k] === undefined || configDirNamed) {
|
|
7538
|
+
env2[k] = v;
|
|
7539
|
+
count++;
|
|
7540
|
+
}
|
|
7541
|
+
}
|
|
7542
|
+
return { path: envPath, vars: count };
|
|
7543
|
+
}
|
|
7544
|
+
function loadSettings(opts = {}) {
|
|
7545
|
+
loadEnv(opts);
|
|
7546
|
+
return {
|
|
7547
|
+
supabaseUrl: env2.CEREFOX_SUPABASE_URL ?? "",
|
|
7548
|
+
supabaseKey: env2.CEREFOX_SUPABASE_KEY ?? "",
|
|
7549
|
+
supabaseAnonKey: env2.CEREFOX_SUPABASE_ANON_KEY ?? "",
|
|
7550
|
+
accessToken: env2.CEREFOX_ACCESS_TOKEN ?? "",
|
|
7551
|
+
databaseUrl: env2.CEREFOX_DATABASE_URL ?? "",
|
|
7552
|
+
openaiApiKey: env2.CEREFOX_OPENAI_API_KEY ?? env2.OPENAI_API_KEY ?? "",
|
|
7553
|
+
fireworksApiKey: env2.CEREFOX_FIREWORKS_API_KEY ?? ""
|
|
7554
|
+
};
|
|
7555
|
+
}
|
|
7556
|
+
var KV_LINE, _loaded = false;
|
|
7557
|
+
var init_env = __esm(() => {
|
|
7558
|
+
init_paths();
|
|
7559
|
+
KV_LINE = /^\s*([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*?)\s*$/;
|
|
7560
|
+
});
|
|
7561
|
+
|
|
7562
|
+
// ../../_shared/config/index.ts
|
|
7563
|
+
var exports_config = {};
|
|
7564
|
+
__export(exports_config, {
|
|
7565
|
+
userStateDir: () => userStateDir,
|
|
7566
|
+
resolveEnvFile: () => resolveEnvFile,
|
|
7567
|
+
resolveConfigDir: () => resolveConfigDir,
|
|
7568
|
+
loadSettings: () => loadSettings,
|
|
7569
|
+
loadEnv: () => loadEnv,
|
|
7570
|
+
isDevMode: () => isDevMode,
|
|
7571
|
+
USER_STATE_DIR_NAME: () => USER_STATE_DIR_NAME
|
|
7572
|
+
});
|
|
7573
|
+
var init_config = __esm(() => {
|
|
7574
|
+
init_paths();
|
|
7575
|
+
init_env();
|
|
7576
|
+
});
|
|
7577
|
+
|
|
7444
7578
|
// ../../node_modules/.bun/tslib@2.8.1/node_modules/tslib/tslib.js
|
|
7445
7579
|
var require_tslib = __commonJS((exports, module) => {
|
|
7446
7580
|
var __extends;
|
|
@@ -7935,7 +8069,7 @@ var require_tslib = __commonJS((exports, module) => {
|
|
|
7935
8069
|
throw new TypeError("Cannot use 'in' operator on non-object");
|
|
7936
8070
|
return typeof state === "function" ? receiver === state : state.has(receiver);
|
|
7937
8071
|
};
|
|
7938
|
-
__addDisposableResource = function(
|
|
8072
|
+
__addDisposableResource = function(env3, value, async) {
|
|
7939
8073
|
if (value !== null && value !== undefined) {
|
|
7940
8074
|
if (typeof value !== "object" && typeof value !== "function")
|
|
7941
8075
|
throw new TypeError("Object expected.");
|
|
@@ -7962,9 +8096,9 @@ var require_tslib = __commonJS((exports, module) => {
|
|
|
7962
8096
|
return Promise.reject(e);
|
|
7963
8097
|
}
|
|
7964
8098
|
};
|
|
7965
|
-
|
|
8099
|
+
env3.stack.push({ value, dispose, async });
|
|
7966
8100
|
} else if (async) {
|
|
7967
|
-
|
|
8101
|
+
env3.stack.push({ async: true });
|
|
7968
8102
|
}
|
|
7969
8103
|
return value;
|
|
7970
8104
|
};
|
|
@@ -7972,17 +8106,17 @@ var require_tslib = __commonJS((exports, module) => {
|
|
|
7972
8106
|
var e = new Error(message);
|
|
7973
8107
|
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
7974
8108
|
};
|
|
7975
|
-
__disposeResources = function(
|
|
8109
|
+
__disposeResources = function(env3) {
|
|
7976
8110
|
function fail(e) {
|
|
7977
|
-
|
|
7978
|
-
|
|
8111
|
+
env3.error = env3.hasError ? new _SuppressedError(e, env3.error, "An error was suppressed during disposal.") : e;
|
|
8112
|
+
env3.hasError = true;
|
|
7979
8113
|
}
|
|
7980
8114
|
var r, s = 0;
|
|
7981
8115
|
function next() {
|
|
7982
|
-
while (r =
|
|
8116
|
+
while (r = env3.stack.pop()) {
|
|
7983
8117
|
try {
|
|
7984
8118
|
if (!r.async && s === 1)
|
|
7985
|
-
return s = 0,
|
|
8119
|
+
return s = 0, env3.stack.push(r), Promise.resolve().then(next);
|
|
7986
8120
|
if (r.dispose) {
|
|
7987
8121
|
var result = r.dispose.call(r.value);
|
|
7988
8122
|
if (r.async)
|
|
@@ -7997,9 +8131,9 @@ var require_tslib = __commonJS((exports, module) => {
|
|
|
7997
8131
|
}
|
|
7998
8132
|
}
|
|
7999
8133
|
if (s === 1)
|
|
8000
|
-
return
|
|
8001
|
-
if (
|
|
8002
|
-
throw
|
|
8134
|
+
return env3.hasError ? Promise.reject(env3.error) : Promise.resolve();
|
|
8135
|
+
if (env3.hasError)
|
|
8136
|
+
throw env3.error;
|
|
8003
8137
|
}
|
|
8004
8138
|
return next();
|
|
8005
8139
|
};
|
|
@@ -9128,22 +9262,22 @@ var require_websocket_factory = __commonJS((exports) => {
|
|
|
9128
9262
|
};
|
|
9129
9263
|
}
|
|
9130
9264
|
static getWebSocketConstructor() {
|
|
9131
|
-
const
|
|
9132
|
-
if (
|
|
9133
|
-
return
|
|
9265
|
+
const env3 = this.detectEnvironment();
|
|
9266
|
+
if (env3.wsConstructor) {
|
|
9267
|
+
return env3.wsConstructor;
|
|
9134
9268
|
}
|
|
9135
|
-
let errorMessage =
|
|
9136
|
-
if (
|
|
9269
|
+
let errorMessage = env3.error || "WebSocket not supported in this environment.";
|
|
9270
|
+
if (env3.workaround) {
|
|
9137
9271
|
errorMessage += `
|
|
9138
9272
|
|
|
9139
|
-
Suggested solution: ${
|
|
9273
|
+
Suggested solution: ${env3.workaround}`;
|
|
9140
9274
|
}
|
|
9141
9275
|
throw new Error(errorMessage);
|
|
9142
9276
|
}
|
|
9143
9277
|
static isWebSocketSupported() {
|
|
9144
9278
|
try {
|
|
9145
|
-
const
|
|
9146
|
-
return
|
|
9279
|
+
const env3 = this.detectEnvironment();
|
|
9280
|
+
return env3.type === "native";
|
|
9147
9281
|
} catch (_a) {
|
|
9148
9282
|
return false;
|
|
9149
9283
|
}
|
|
@@ -11592,8 +11726,8 @@ var require_RealtimeChannel = __commonJS((exports) => {
|
|
|
11592
11726
|
});
|
|
11593
11727
|
}
|
|
11594
11728
|
_notThisChannelEvent(event, ref) {
|
|
11595
|
-
const { close, error, leave, join } = constants_1.CHANNEL_EVENTS;
|
|
11596
|
-
const events = [close, error, leave,
|
|
11729
|
+
const { close, error, leave, join: join2 } = constants_1.CHANNEL_EVENTS;
|
|
11730
|
+
const events = [close, error, leave, join2];
|
|
11597
11731
|
return ref && events.includes(event) && ref !== this.joinPush.ref;
|
|
11598
11732
|
}
|
|
11599
11733
|
_updateFilterTransform() {
|
|
@@ -23274,137 +23408,6 @@ var init_db_client = __esm(() => {
|
|
|
23274
23408
|
});
|
|
23275
23409
|
});
|
|
23276
23410
|
|
|
23277
|
-
// ../../_shared/config/paths.ts
|
|
23278
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
23279
|
-
import { homedir } from "node:os";
|
|
23280
|
-
import { join, resolve as resolvePath } from "node:path";
|
|
23281
|
-
import { cwd as processCwd, env } from "node:process";
|
|
23282
|
-
function expandTilde(p) {
|
|
23283
|
-
if (p === "~" || p.startsWith("~/")) {
|
|
23284
|
-
return join(homedir(), p.slice(2));
|
|
23285
|
-
}
|
|
23286
|
-
return p;
|
|
23287
|
-
}
|
|
23288
|
-
function userStateDirAbs(opts) {
|
|
23289
|
-
return resolvePath(join(opts.home ?? homedir(), USER_STATE_DIR_NAME));
|
|
23290
|
-
}
|
|
23291
|
-
function resolveConfigDir(opts = {}) {
|
|
23292
|
-
const override = (env.CEREFOX_CONFIG_DIR ?? "").trim();
|
|
23293
|
-
if (override) {
|
|
23294
|
-
return resolvePath(expandTilde(override));
|
|
23295
|
-
}
|
|
23296
|
-
const userState = userStateDirAbs(opts);
|
|
23297
|
-
if (existsSync(join(userState, ".env"))) {
|
|
23298
|
-
return userState;
|
|
23299
|
-
}
|
|
23300
|
-
const here = opts.cwd ?? processCwd();
|
|
23301
|
-
const cwdEnv = join(here, ".env");
|
|
23302
|
-
if (existsSync(cwdEnv) && cwdEnvHasCerefoxKey(cwdEnv)) {
|
|
23303
|
-
return resolvePath(here);
|
|
23304
|
-
}
|
|
23305
|
-
return userState;
|
|
23306
|
-
}
|
|
23307
|
-
function cwdEnvHasCerefoxKey(envPath) {
|
|
23308
|
-
try {
|
|
23309
|
-
const contents = readFileSync(envPath, "utf8");
|
|
23310
|
-
return /^\s*CEREFOX_[A-Z0-9_]+\s*=/m.test(contents);
|
|
23311
|
-
} catch {
|
|
23312
|
-
return false;
|
|
23313
|
-
}
|
|
23314
|
-
}
|
|
23315
|
-
function resolveEnvFile(opts = {}) {
|
|
23316
|
-
return join(resolveConfigDir(opts), ".env");
|
|
23317
|
-
}
|
|
23318
|
-
function userStateDir(opts = {}) {
|
|
23319
|
-
return userStateDirAbs(opts);
|
|
23320
|
-
}
|
|
23321
|
-
function isDevMode(opts = {}) {
|
|
23322
|
-
if ((env.CEREFOX_CONFIG_DIR ?? "").trim())
|
|
23323
|
-
return false;
|
|
23324
|
-
if (existsSync(join(userStateDirAbs(opts), ".env")))
|
|
23325
|
-
return false;
|
|
23326
|
-
const here = opts.cwd ?? processCwd();
|
|
23327
|
-
const cwdEnv = join(here, ".env");
|
|
23328
|
-
return existsSync(cwdEnv) && cwdEnvHasCerefoxKey(cwdEnv);
|
|
23329
|
-
}
|
|
23330
|
-
var USER_STATE_DIR_NAME = ".cerefox";
|
|
23331
|
-
var init_paths = () => {};
|
|
23332
|
-
|
|
23333
|
-
// ../../_shared/config/env.ts
|
|
23334
|
-
import { readFileSync as readFileSync2 } from "node:fs";
|
|
23335
|
-
import { env as env2 } from "node:process";
|
|
23336
|
-
function parseDotenv(content) {
|
|
23337
|
-
const result = {};
|
|
23338
|
-
for (const rawLine of content.split(/\r?\n/)) {
|
|
23339
|
-
const line = rawLine.trim();
|
|
23340
|
-
if (!line || line.startsWith("#"))
|
|
23341
|
-
continue;
|
|
23342
|
-
const match = line.match(KV_LINE);
|
|
23343
|
-
if (!match)
|
|
23344
|
-
continue;
|
|
23345
|
-
let value = match[2];
|
|
23346
|
-
if (value.length >= 2 && (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'"))) {
|
|
23347
|
-
value = value.slice(1, -1);
|
|
23348
|
-
}
|
|
23349
|
-
result[match[1]] = value;
|
|
23350
|
-
}
|
|
23351
|
-
return result;
|
|
23352
|
-
}
|
|
23353
|
-
function loadEnv(opts = {}) {
|
|
23354
|
-
if (_loaded) {
|
|
23355
|
-
return { path: "(already loaded)", vars: 0 };
|
|
23356
|
-
}
|
|
23357
|
-
_loaded = true;
|
|
23358
|
-
const envPath = resolveEnvFile(opts);
|
|
23359
|
-
let content;
|
|
23360
|
-
try {
|
|
23361
|
-
content = readFileSync2(envPath, "utf8");
|
|
23362
|
-
} catch {
|
|
23363
|
-
return { path: envPath, vars: 0 };
|
|
23364
|
-
}
|
|
23365
|
-
let count = 0;
|
|
23366
|
-
for (const [k, v] of Object.entries(parseDotenv(content))) {
|
|
23367
|
-
if (env2[k] === undefined) {
|
|
23368
|
-
env2[k] = v;
|
|
23369
|
-
count++;
|
|
23370
|
-
}
|
|
23371
|
-
}
|
|
23372
|
-
return { path: envPath, vars: count };
|
|
23373
|
-
}
|
|
23374
|
-
function loadSettings(opts = {}) {
|
|
23375
|
-
loadEnv(opts);
|
|
23376
|
-
return {
|
|
23377
|
-
supabaseUrl: env2.CEREFOX_SUPABASE_URL ?? "",
|
|
23378
|
-
supabaseKey: env2.CEREFOX_SUPABASE_KEY ?? "",
|
|
23379
|
-
supabaseAnonKey: env2.CEREFOX_SUPABASE_ANON_KEY ?? "",
|
|
23380
|
-
accessToken: env2.CEREFOX_ACCESS_TOKEN ?? "",
|
|
23381
|
-
databaseUrl: env2.CEREFOX_DATABASE_URL ?? "",
|
|
23382
|
-
openaiApiKey: env2.CEREFOX_OPENAI_API_KEY ?? env2.OPENAI_API_KEY ?? "",
|
|
23383
|
-
fireworksApiKey: env2.CEREFOX_FIREWORKS_API_KEY ?? ""
|
|
23384
|
-
};
|
|
23385
|
-
}
|
|
23386
|
-
var KV_LINE, _loaded = false;
|
|
23387
|
-
var init_env = __esm(() => {
|
|
23388
|
-
init_paths();
|
|
23389
|
-
KV_LINE = /^\s*([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*?)\s*$/;
|
|
23390
|
-
});
|
|
23391
|
-
|
|
23392
|
-
// ../../_shared/config/index.ts
|
|
23393
|
-
var exports_config = {};
|
|
23394
|
-
__export(exports_config, {
|
|
23395
|
-
userStateDir: () => userStateDir,
|
|
23396
|
-
resolveEnvFile: () => resolveEnvFile,
|
|
23397
|
-
resolveConfigDir: () => resolveConfigDir,
|
|
23398
|
-
loadSettings: () => loadSettings,
|
|
23399
|
-
loadEnv: () => loadEnv,
|
|
23400
|
-
isDevMode: () => isDevMode,
|
|
23401
|
-
USER_STATE_DIR_NAME: () => USER_STATE_DIR_NAME
|
|
23402
|
-
});
|
|
23403
|
-
var init_config = __esm(() => {
|
|
23404
|
-
init_paths();
|
|
23405
|
-
init_env();
|
|
23406
|
-
});
|
|
23407
|
-
|
|
23408
23411
|
// src/cli/util/client.ts
|
|
23409
23412
|
function getClient() {
|
|
23410
23413
|
const settings = loadSettings();
|
|
@@ -55186,6 +55189,36 @@ var init_audit_log = __esm(() => {
|
|
|
55186
55189
|
};
|
|
55187
55190
|
});
|
|
55188
55191
|
|
|
55192
|
+
// ../../_shared/mcp-tools/feature-flags.ts
|
|
55193
|
+
async function relationsEnabled(supabase) {
|
|
55194
|
+
if (cached && Date.now() - cached.at < CACHE_TTL_MS)
|
|
55195
|
+
return cached.value;
|
|
55196
|
+
try {
|
|
55197
|
+
const { data, error: error2 } = await supabase.rpc("cerefox_get_config", {
|
|
55198
|
+
p_key: "relations_enabled"
|
|
55199
|
+
});
|
|
55200
|
+
if (error2)
|
|
55201
|
+
throw new Error(error2.message);
|
|
55202
|
+
const value = String(data ?? "").trim().toLowerCase() === "true";
|
|
55203
|
+
cached = { value, at: Date.now() };
|
|
55204
|
+
return value;
|
|
55205
|
+
} catch {
|
|
55206
|
+
return false;
|
|
55207
|
+
}
|
|
55208
|
+
}
|
|
55209
|
+
function disabledToolMessage(name) {
|
|
55210
|
+
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).`;
|
|
55211
|
+
}
|
|
55212
|
+
var RELATION_TOOL_NAMES, CACHE_TTL_MS = 60000, cached = null;
|
|
55213
|
+
var init_feature_flags = __esm(() => {
|
|
55214
|
+
RELATION_TOOL_NAMES = new Set([
|
|
55215
|
+
"cerefox_set_relation",
|
|
55216
|
+
"cerefox_delete_relation",
|
|
55217
|
+
"cerefox_get_relations",
|
|
55218
|
+
"cerefox_get_neighbors"
|
|
55219
|
+
]);
|
|
55220
|
+
});
|
|
55221
|
+
|
|
55189
55222
|
// ../../_shared/mcp-tools/types.ts
|
|
55190
55223
|
var McpInvalidParams;
|
|
55191
55224
|
var init_types3 = __esm(() => {
|
|
@@ -56281,9 +56314,21 @@ var init_set_document_projects = __esm(() => {
|
|
|
56281
56314
|
});
|
|
56282
56315
|
|
|
56283
56316
|
// ../../_shared/mcp-tools/index.ts
|
|
56317
|
+
async function listEnabledTools(supabase) {
|
|
56318
|
+
const relations = await relationsEnabled(supabase);
|
|
56319
|
+
return ALL_TOOLS.filter((t) => relations || !RELATION_TOOL_NAMES.has(t.name));
|
|
56320
|
+
}
|
|
56321
|
+
async function assertToolEnabled(supabase, name) {
|
|
56322
|
+
if (!RELATION_TOOL_NAMES.has(name))
|
|
56323
|
+
return;
|
|
56324
|
+
if (await relationsEnabled(supabase))
|
|
56325
|
+
return;
|
|
56326
|
+
throw new McpInvalidParams(disabledToolMessage(name));
|
|
56327
|
+
}
|
|
56284
56328
|
var ALL_TOOLS, TOOLS_BY_NAME;
|
|
56285
56329
|
var init_mcp_tools = __esm(() => {
|
|
56286
56330
|
init_audit_log();
|
|
56331
|
+
init_feature_flags();
|
|
56287
56332
|
init_relations();
|
|
56288
56333
|
init_get_document();
|
|
56289
56334
|
init_get_help();
|
|
@@ -56295,6 +56340,7 @@ var init_mcp_tools = __esm(() => {
|
|
|
56295
56340
|
init_search();
|
|
56296
56341
|
init_set_document_projects();
|
|
56297
56342
|
init_types3();
|
|
56343
|
+
init_types3();
|
|
56298
56344
|
ALL_TOOLS = [
|
|
56299
56345
|
searchTool,
|
|
56300
56346
|
ingestTool,
|
|
@@ -56500,7 +56546,7 @@ __export(exports_util, {
|
|
|
56500
56546
|
cleanRegex: () => cleanRegex,
|
|
56501
56547
|
cleanEnum: () => cleanEnum,
|
|
56502
56548
|
captureStackTrace: () => captureStackTrace,
|
|
56503
|
-
cached: () =>
|
|
56549
|
+
cached: () => cached2,
|
|
56504
56550
|
assignProp: () => assignProp,
|
|
56505
56551
|
assertNotEqual: () => assertNotEqual,
|
|
56506
56552
|
assertNever: () => assertNever,
|
|
@@ -56537,7 +56583,7 @@ function jsonStringifyReplacer(_, value) {
|
|
|
56537
56583
|
return value.toString();
|
|
56538
56584
|
return value;
|
|
56539
56585
|
}
|
|
56540
|
-
function
|
|
56586
|
+
function cached2(getter) {
|
|
56541
56587
|
const set = false;
|
|
56542
56588
|
return {
|
|
56543
56589
|
get value() {
|
|
@@ -56949,7 +56995,7 @@ var captureStackTrace, allowsEval, getParsedType2 = (data) => {
|
|
|
56949
56995
|
}, propertyKeyTypes, primitiveTypes, NUMBER_FORMAT_RANGES, BIGINT_FORMAT_RANGES;
|
|
56950
56996
|
var init_util2 = __esm(() => {
|
|
56951
56997
|
captureStackTrace = Error.captureStackTrace ? Error.captureStackTrace : (..._args) => {};
|
|
56952
|
-
allowsEval =
|
|
56998
|
+
allowsEval = cached2(() => {
|
|
56953
56999
|
if (typeof navigator !== "undefined" && navigator?.userAgent?.includes("Cloudflare")) {
|
|
56954
57000
|
return false;
|
|
56955
57001
|
}
|
|
@@ -58254,7 +58300,7 @@ var init_schemas = __esm(() => {
|
|
|
58254
58300
|
});
|
|
58255
58301
|
$ZodObject = /* @__PURE__ */ $constructor("$ZodObject", (inst, def) => {
|
|
58256
58302
|
$ZodType.init(inst, def);
|
|
58257
|
-
const _normalized =
|
|
58303
|
+
const _normalized = cached2(() => {
|
|
58258
58304
|
const keys = Object.keys(def.shape);
|
|
58259
58305
|
for (const k of keys) {
|
|
58260
58306
|
if (!(def.shape[k] instanceof $ZodType)) {
|
|
@@ -58474,7 +58520,7 @@ var init_schemas = __esm(() => {
|
|
|
58474
58520
|
}
|
|
58475
58521
|
return propValues;
|
|
58476
58522
|
});
|
|
58477
|
-
const disc =
|
|
58523
|
+
const disc = cached2(() => {
|
|
58478
58524
|
const opts = def.options;
|
|
58479
58525
|
const map = new Map;
|
|
58480
58526
|
for (const o of opts) {
|
|
@@ -69455,7 +69501,7 @@ function buildServer() {
|
|
|
69455
69501
|
};
|
|
69456
69502
|
const server = new Server({ name: SERVER_NAME, version: PKG_VERSION }, { capabilities: { tools: {} } });
|
|
69457
69503
|
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
69458
|
-
tools:
|
|
69504
|
+
tools: (await listEnabledTools(supabase)).map((t) => ({
|
|
69459
69505
|
name: t.name,
|
|
69460
69506
|
description: t.description,
|
|
69461
69507
|
inputSchema: t.inputSchema
|
|
@@ -69468,6 +69514,7 @@ function buildServer() {
|
|
|
69468
69514
|
throw new McpInvalidParams(`Unknown tool: ${name}`);
|
|
69469
69515
|
}
|
|
69470
69516
|
try {
|
|
69517
|
+
await assertToolEnabled(supabase, name);
|
|
69471
69518
|
const text = await tool.handler(supabase, args, ctx);
|
|
69472
69519
|
return { content: [{ type: "text", text }] };
|
|
69473
69520
|
} catch (err) {
|
|
@@ -69545,6 +69592,7 @@ init_cli_core();
|
|
|
69545
69592
|
|
|
69546
69593
|
// src/cli/commands/backup.ts
|
|
69547
69594
|
init_cli_core();
|
|
69595
|
+
init_config();
|
|
69548
69596
|
import { existsSync as existsSync2, mkdirSync, writeFileSync } from "node:fs";
|
|
69549
69597
|
import { homedir as homedir2 } from "node:os";
|
|
69550
69598
|
import { join as join2, resolve } from "node:path";
|
|
@@ -69574,6 +69622,7 @@ async function fetchAllPages(makeQuery, batchSize = 200) {
|
|
|
69574
69622
|
|
|
69575
69623
|
// src/cli/commands/backup.ts
|
|
69576
69624
|
init_client();
|
|
69625
|
+
init_meta();
|
|
69577
69626
|
function expandHome(path) {
|
|
69578
69627
|
if (path === "~")
|
|
69579
69628
|
return homedir2();
|
|
@@ -69587,18 +69636,69 @@ function utcStamp() {
|
|
|
69587
69636
|
return d.getUTCFullYear().toString() + pad(d.getUTCMonth() + 1) + pad(d.getUTCDate()) + "T" + pad(d.getUTCHours()) + pad(d.getUTCMinutes()) + pad(d.getUTCSeconds()) + "Z";
|
|
69588
69637
|
}
|
|
69589
69638
|
async function action(options) {
|
|
69590
|
-
|
|
69639
|
+
loadEnv();
|
|
69640
|
+
const configuredDir = options.outputDir ?? process.env.CEREFOX_BACKUP_DIR;
|
|
69641
|
+
const outDir = resolve(expandHome(configuredDir ?? "~/.cerefox/backups"));
|
|
69642
|
+
if (configuredDir !== undefined && !configuredDir.startsWith("/") && !configuredDir.startsWith("~")) {
|
|
69643
|
+
println(c.yellow("⚠ ") + `Backup directory "${configuredDir}" is relative — it resolves against the ` + "current working directory, so backups land in different places depending " + "on where you run this from.");
|
|
69644
|
+
println(c.dim(` Writing to: ${outDir}`));
|
|
69645
|
+
println(c.dim(" Set an absolute path (e.g. ~/.cerefox/backups) to keep them together."));
|
|
69646
|
+
}
|
|
69591
69647
|
if (!existsSync2(outDir))
|
|
69592
69648
|
mkdirSync(outDir, { recursive: true });
|
|
69649
|
+
const envLabel = (process.env.CEREFOX_ENV_LABEL ?? "").trim().replace(/[^A-Za-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
69593
69650
|
const stamp = utcStamp();
|
|
69594
|
-
const filename = `cerefox-${
|
|
69651
|
+
const filename = `cerefox-${envLabel ? envLabel + "-" : ""}${stamp}` + `${options.label ? "-" + options.label : ""}.json`;
|
|
69595
69652
|
const dest = join2(outDir, filename);
|
|
69596
69653
|
const client = getClient();
|
|
69654
|
+
let schemaVersion = "unknown";
|
|
69655
|
+
try {
|
|
69656
|
+
schemaVersion = await client.rpc("cerefox_schema_version", {}) ?? "unknown";
|
|
69657
|
+
} catch {}
|
|
69658
|
+
const includeTrash = options.trash !== false;
|
|
69659
|
+
const BASE_COLUMNS = "id, title, content_hash, source, metadata, total_chars, chunk_count, " + "review_status, created_at, updated_at, deleted_at";
|
|
69660
|
+
const fetchDocs = (columns) => fetchAllPages((from, to) => {
|
|
69661
|
+
const q = client.raw.from("cerefox_documents").select(columns);
|
|
69662
|
+
return (includeTrash ? q : q.is("deleted_at", null)).order("created_at", { ascending: true }).order("id", { ascending: true }).range(from, to);
|
|
69663
|
+
});
|
|
69597
69664
|
let docs;
|
|
69665
|
+
let lifecycleCaptured = true;
|
|
69598
69666
|
try {
|
|
69599
|
-
docs = await
|
|
69667
|
+
docs = await fetchDocs(`${BASE_COLUMNS}, lifecycle_status`);
|
|
69600
69668
|
} catch (err) {
|
|
69601
|
-
|
|
69669
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
69670
|
+
if (!/lifecycle_status/.test(message)) {
|
|
69671
|
+
throw systemError(`Document fetch failed: ${message}`);
|
|
69672
|
+
}
|
|
69673
|
+
lifecycleCaptured = false;
|
|
69674
|
+
try {
|
|
69675
|
+
docs = await fetchDocs(BASE_COLUMNS);
|
|
69676
|
+
} catch (retryErr) {
|
|
69677
|
+
throw systemError(`Document fetch failed: ${retryErr instanceof Error ? retryErr.message : String(retryErr)}`);
|
|
69678
|
+
}
|
|
69679
|
+
println(c.dim(" (server predates lifecycle_status — captured without it)"));
|
|
69680
|
+
}
|
|
69681
|
+
const trashedCount = docs.filter((d) => d.deleted_at != null).length;
|
|
69682
|
+
let projects = [];
|
|
69683
|
+
let memberships = [];
|
|
69684
|
+
try {
|
|
69685
|
+
projects = await fetchAllPages((from, to) => client.raw.from("cerefox_projects").select("id, name, description, created_at, updated_at").order("id", { ascending: true }).range(from, to));
|
|
69686
|
+
memberships = await fetchAllPages((from, to) => client.raw.from("cerefox_document_projects").select("document_id, project_id").order("document_id", { ascending: true }).order("project_id", { ascending: true }).range(from, to));
|
|
69687
|
+
} catch (err) {
|
|
69688
|
+
throw systemError(`Project/membership fetch failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
69689
|
+
}
|
|
69690
|
+
let relations = [];
|
|
69691
|
+
try {
|
|
69692
|
+
relations = await fetchAllPages((from, to) => client.raw.from("cerefox_document_relations").select("source_id, target_id, rel_type, metadata, author, author_type, created_at").order("source_id", { ascending: true }).order("target_id", { ascending: true }).order("rel_type", { ascending: true }).range(from, to));
|
|
69693
|
+
} catch {}
|
|
69694
|
+
{
|
|
69695
|
+
const captured = new Set(docs.map((d) => d.id));
|
|
69696
|
+
const before = memberships.length;
|
|
69697
|
+
memberships = memberships.filter((m) => captured.has(m.document_id));
|
|
69698
|
+
const dropped = before - memberships.length;
|
|
69699
|
+
if (dropped > 0) {
|
|
69700
|
+
println(c.dim(` (skipped ${dropped} membership(s) belonging to trashed documents)`));
|
|
69701
|
+
}
|
|
69602
69702
|
}
|
|
69603
69703
|
let chunkTotal = 0;
|
|
69604
69704
|
const enriched = [];
|
|
@@ -69622,22 +69722,39 @@ async function action(options) {
|
|
|
69622
69722
|
`);
|
|
69623
69723
|
const payload = {
|
|
69624
69724
|
created_at: new Date().toISOString(),
|
|
69625
|
-
cerefox_version:
|
|
69725
|
+
cerefox_version: PKG_VERSION,
|
|
69726
|
+
backup_format: 4,
|
|
69727
|
+
schema_version: schemaVersion,
|
|
69626
69728
|
document_count: docs.length,
|
|
69729
|
+
trashed_count: trashedCount,
|
|
69730
|
+
includes_trash: includeTrash,
|
|
69731
|
+
env_label: envLabel || null,
|
|
69732
|
+
includes_lifecycle_status: lifecycleCaptured,
|
|
69627
69733
|
chunk_count: chunkTotal,
|
|
69734
|
+
project_count: projects.length,
|
|
69735
|
+
membership_count: memberships.length,
|
|
69736
|
+
relation_count: relations.length,
|
|
69737
|
+
projects,
|
|
69738
|
+
memberships,
|
|
69739
|
+
relations,
|
|
69628
69740
|
documents: enriched
|
|
69629
69741
|
};
|
|
69630
69742
|
writeFileSync(dest, JSON.stringify(payload, null, 2), "utf8");
|
|
69631
69743
|
println("");
|
|
69632
69744
|
println(c.green("✓ ") + `Backup written: ${dest}`);
|
|
69633
|
-
println(c.dim(` documents: ${docs.length} · chunks: ${chunkTotal}`));
|
|
69745
|
+
println(c.dim(` documents: ${docs.length} · chunks: ${chunkTotal} · ` + `projects: ${projects.length} · memberships: ${memberships.length}` + (relations.length > 0 ? ` · relations: ${relations.length}` : "")));
|
|
69746
|
+
if (!includeTrash) {
|
|
69747
|
+
println(c.dim(" trashed documents: excluded (--no-trash)"));
|
|
69748
|
+
} else if (trashedCount > 0) {
|
|
69749
|
+
println(c.dim(` of which trashed: ${trashedCount} (restored as trash, not resurrected)`));
|
|
69750
|
+
}
|
|
69634
69751
|
if (options.git) {
|
|
69635
69752
|
println(c.yellow("⚠ ") + "--git commit is not implemented; the snapshot was written without a git checkpoint.");
|
|
69636
69753
|
println(c.dim(" Commit the backup directory yourself if you want it version-controlled."));
|
|
69637
69754
|
}
|
|
69638
69755
|
}
|
|
69639
69756
|
function registerBackup(program2) {
|
|
69640
|
-
program2.command("backup").description("Write a JSON snapshot of the knowledge base.").option("-o, --output-dir <dir>", "Snapshot output directory (default: CEREFOX_BACKUP_DIR or ~/.cerefox/backups).").option("-l, --label <label>", "Optional suffix added to the filename.").option("--include-versions", "Include archived versions in the snapshot. (v0.5: ignored — current chunks only.)").option("--git", "Commit the snapshot to the output dir as a git checkpoint. (v0.5: ignored.)").action(action);
|
|
69757
|
+
program2.command("backup").description("Write a JSON snapshot of the knowledge base.").option("-o, --output-dir <dir>", "Snapshot output directory (default: CEREFOX_BACKUP_DIR or ~/.cerefox/backups).").option("-l, --label <label>", "Optional suffix added to the filename.").option("--include-versions", "Include archived versions in the snapshot. (v0.5: ignored — current chunks only.)").option("--git", "Commit the snapshot to the output dir as a git checkpoint. (v0.5: ignored.)").option("--no-trash", "Exclude soft-deleted documents. Default: they are captured and restored as trash.").action(action);
|
|
69641
69758
|
}
|
|
69642
69759
|
|
|
69643
69760
|
// src/cli/commands/completion.ts
|
|
@@ -69957,6 +70074,10 @@ var CONFIG_KEYS = [
|
|
|
69957
70074
|
key: "min_term_coverage",
|
|
69958
70075
|
description: "0–1 — fraction of a query's meaningful terms a keyword OR-fallback match must cover to count as confident. Default 0.5."
|
|
69959
70076
|
},
|
|
70077
|
+
{
|
|
70078
|
+
key: "relations_enabled",
|
|
70079
|
+
description: "'true'/'false' — expose the document-relation tools to agents. Off by default; the feature is dormant until enabled (iteration 29)."
|
|
70080
|
+
},
|
|
69960
70081
|
{
|
|
69961
70082
|
key: "search_alpha",
|
|
69962
70083
|
description: "0–1 — hybrid fusion weight: 1 = pure semantic, 0 = pure keyword. Default 0.7."
|
|
@@ -75502,8 +75623,8 @@ import { homedir as homedir6 } from "node:os";
|
|
|
75502
75623
|
import { join as join9 } from "node:path";
|
|
75503
75624
|
|
|
75504
75625
|
// ../../_shared/ef-meta/index.ts
|
|
75505
|
-
var EF_VERSION = "1.1.0-beta.
|
|
75506
|
-
var EF_LAST_CHANGED = "1.1.0-beta.
|
|
75626
|
+
var EF_VERSION = "1.1.0-beta.2";
|
|
75627
|
+
var EF_LAST_CHANGED = "1.1.0-beta.2";
|
|
75507
75628
|
|
|
75508
75629
|
// src/cli/util/checks.ts
|
|
75509
75630
|
init_config();
|
|
@@ -75591,10 +75712,11 @@ function checkConfig() {
|
|
|
75591
75712
|
modeDetail = ` (mode 0${mode.toString(8)})`;
|
|
75592
75713
|
} catch {}
|
|
75593
75714
|
}
|
|
75715
|
+
const envLabel = (process.env.CEREFOX_ENV_LABEL ?? "").trim();
|
|
75594
75716
|
return {
|
|
75595
75717
|
name: "config",
|
|
75596
75718
|
status: "ok",
|
|
75597
|
-
detail: `${envPath}${modeDetail}`
|
|
75719
|
+
detail: `${envPath}${modeDetail}${envLabel ? ` [${envLabel.toUpperCase()}]` : ""}`
|
|
75598
75720
|
};
|
|
75599
75721
|
}
|
|
75600
75722
|
async function checkSupabase() {
|
|
@@ -75852,7 +75974,7 @@ async function checkContentFormat() {
|
|
|
75852
75974
|
name: CONTENT_FORMAT_CHECK_NAME,
|
|
75853
75975
|
status: "skipped",
|
|
75854
75976
|
detail: `${legacy} of ${total} document(s) use the legacy reconstruction format (format 1).`,
|
|
75855
|
-
hint: "
|
|
75977
|
+
hint: "Harmless — they auto-convert on next edit. To convert them all now: `cerefox server migrate-format` (re-embeds, so try `--dry-run` first). To read what chunk formats are: `cerefox guides show content-format`."
|
|
75856
75978
|
};
|
|
75857
75979
|
} catch (err) {
|
|
75858
75980
|
return {
|
|
@@ -77997,6 +78119,114 @@ function registerReindex(program2) {
|
|
|
77997
78119
|
program2.command("reindex").description("Re-embed existing document chunks (v0.7+).").option("--all", "Reindex every chunk regardless of embedder.").option("--batch <n>", "Chunks per OpenAI batch call. Capped at 96 internally.", "32").option("--dry-run", "Show counts without re-embedding.").option("-i, --document-id <uuid>", "Limit reindex to a single document.").action(action27);
|
|
77998
78120
|
}
|
|
77999
78121
|
|
|
78122
|
+
// src/cli/commands/migrate-format.ts
|
|
78123
|
+
init_cli_core();
|
|
78124
|
+
init_config();
|
|
78125
|
+
init_client();
|
|
78126
|
+
var CURRENT_FORMAT = 2;
|
|
78127
|
+
async function action28(options) {
|
|
78128
|
+
const settings = loadSettings();
|
|
78129
|
+
const client = getClient();
|
|
78130
|
+
const supabase = client.raw;
|
|
78131
|
+
let legacyChunkRows;
|
|
78132
|
+
try {
|
|
78133
|
+
legacyChunkRows = await fetchAllPages((from, to) => {
|
|
78134
|
+
let q = supabase.from("cerefox_chunks").select("document_id").is("version_id", null).lt("content_format", CURRENT_FORMAT);
|
|
78135
|
+
if (options.documentId)
|
|
78136
|
+
q = q.eq("document_id", options.documentId);
|
|
78137
|
+
return q.order("document_id", { ascending: true }).range(from, to);
|
|
78138
|
+
}, 1000);
|
|
78139
|
+
} catch (err) {
|
|
78140
|
+
throw systemError(`Could not list legacy chunks: ${err instanceof Error ? err.message : String(err)}`);
|
|
78141
|
+
}
|
|
78142
|
+
const docIds = [...new Set(legacyChunkRows.map((r) => r.document_id))];
|
|
78143
|
+
const limit = options.limit ? parsePositiveInt(options.limit, "--limit", docIds.length) : docIds.length;
|
|
78144
|
+
const targets = docIds.slice(0, limit);
|
|
78145
|
+
if (targets.length === 0) {
|
|
78146
|
+
println(c.green("✓ Nothing to migrate — every document already uses the current format."));
|
|
78147
|
+
return;
|
|
78148
|
+
}
|
|
78149
|
+
println(c.bold(`${docIds.length} document(s) on the legacy format` + (targets.length < docIds.length ? `; converting ${targets.length} (--limit)` : "")));
|
|
78150
|
+
if (options.dryRun) {
|
|
78151
|
+
println(c.yellow("⚠ --dry-run: nothing was written."));
|
|
78152
|
+
println(c.dim(" Each document would be re-chunked and RE-EMBEDDED (embedding spend)."));
|
|
78153
|
+
return;
|
|
78154
|
+
}
|
|
78155
|
+
println(c.dim("Each document is re-chunked and re-embedded — this costs embedding spend."));
|
|
78156
|
+
println("");
|
|
78157
|
+
const author = resolveAuthor(options.author);
|
|
78158
|
+
const authorType = resolveAuthorType(undefined);
|
|
78159
|
+
const pipeline2 = new IngestionPipeline({
|
|
78160
|
+
supabase,
|
|
78161
|
+
openAiApiKey: settings.openaiApiKey
|
|
78162
|
+
});
|
|
78163
|
+
let converted = 0;
|
|
78164
|
+
let skipped = 0;
|
|
78165
|
+
const duplicates = [];
|
|
78166
|
+
const failures = [];
|
|
78167
|
+
for (let i = 0;i < targets.length; i++) {
|
|
78168
|
+
const id = targets[i];
|
|
78169
|
+
if (process.stdout.isTTY) {
|
|
78170
|
+
process.stderr.write(`\r Converting ${i + 1}/${targets.length}…`);
|
|
78171
|
+
}
|
|
78172
|
+
let doc2 = null;
|
|
78173
|
+
try {
|
|
78174
|
+
const rows = await client.rpc("cerefox_get_document", { p_document_id: id, p_version_id: null });
|
|
78175
|
+
doc2 = rows?.[0] ?? null;
|
|
78176
|
+
} catch (err) {
|
|
78177
|
+
failures.push({ document: id, reason: `read: ${err instanceof Error ? err.message : String(err)}` });
|
|
78178
|
+
continue;
|
|
78179
|
+
}
|
|
78180
|
+
if (!doc2) {
|
|
78181
|
+
failures.push({ document: id, reason: "read: document not found" });
|
|
78182
|
+
continue;
|
|
78183
|
+
}
|
|
78184
|
+
try {
|
|
78185
|
+
await pipeline2.ingestText({
|
|
78186
|
+
text: doc2.full_content,
|
|
78187
|
+
title: doc2.doc_title,
|
|
78188
|
+
documentId: id,
|
|
78189
|
+
source: "migrate-format",
|
|
78190
|
+
author,
|
|
78191
|
+
authorType,
|
|
78192
|
+
expectedContentHash: doc2.content_hash
|
|
78193
|
+
});
|
|
78194
|
+
converted++;
|
|
78195
|
+
} catch (err) {
|
|
78196
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
78197
|
+
if (/conflict/i.test(message)) {
|
|
78198
|
+
skipped++;
|
|
78199
|
+
} else if (/identical content already exists/i.test(message)) {
|
|
78200
|
+
duplicates.push({ document: `${doc2.doc_title} (${id})`, reason: message });
|
|
78201
|
+
} else {
|
|
78202
|
+
failures.push({ document: `${doc2.doc_title} (${id})`, reason: message });
|
|
78203
|
+
}
|
|
78204
|
+
}
|
|
78205
|
+
}
|
|
78206
|
+
if (process.stdout.isTTY)
|
|
78207
|
+
process.stderr.write(`
|
|
78208
|
+
`);
|
|
78209
|
+
println("");
|
|
78210
|
+
println(c.bold(`Converted ${converted} · skipped ${skipped} (changed mid-run) · failed ${failures.length}`));
|
|
78211
|
+
if (targets.length < docIds.length) {
|
|
78212
|
+
println(c.dim(` ${docIds.length - targets.length} document(s) still pending — re-run to continue.`));
|
|
78213
|
+
}
|
|
78214
|
+
if (duplicates.length > 0) {
|
|
78215
|
+
println("");
|
|
78216
|
+
println(c.yellow(`⚠ ${duplicates.length} document(s) could not be converted because their content is ` + "byte-identical to another document."));
|
|
78217
|
+
println(c.dim(" Re-ingesting them would collide with the content-hash dedup check. They keep working " + "on the legacy format; de-duplicate them if you want them converted."));
|
|
78218
|
+
printTable(duplicates.map((d) => ({ document: d.document })));
|
|
78219
|
+
}
|
|
78220
|
+
if (failures.length > 0) {
|
|
78221
|
+
println("");
|
|
78222
|
+
printTable(failures);
|
|
78223
|
+
throw systemError(`${failures.length} document(s) failed to convert.`);
|
|
78224
|
+
}
|
|
78225
|
+
}
|
|
78226
|
+
function registerMigrateFormat(program2) {
|
|
78227
|
+
program2.command("migrate-format").description("Convert legacy-format documents to the current chunk format (re-chunks + re-embeds).").option("--dry-run", "Report how many documents would be converted; write nothing.").option("-l, --limit <n>", "Convert at most N documents (re-run to continue).").option("--document-id <uuid>", "Convert a single document.").option("--author <name>", "Recorded in the audit log for each conversion.").action(action28);
|
|
78228
|
+
}
|
|
78229
|
+
|
|
78000
78230
|
// src/cli/commands/restore.ts
|
|
78001
78231
|
init_cli_core();
|
|
78002
78232
|
init_client();
|
|
@@ -78024,7 +78254,7 @@ function resolveBackupFile(target) {
|
|
|
78024
78254
|
}
|
|
78025
78255
|
return join12(path, candidates[0].name);
|
|
78026
78256
|
}
|
|
78027
|
-
async function
|
|
78257
|
+
async function action29(target, options) {
|
|
78028
78258
|
const file = resolveBackupFile(target);
|
|
78029
78259
|
let payload;
|
|
78030
78260
|
try {
|
|
@@ -78036,7 +78266,24 @@ async function action28(target, options) {
|
|
|
78036
78266
|
throw userError(`Backup file is missing "documents" array: ${file}`);
|
|
78037
78267
|
}
|
|
78038
78268
|
println(c.bold(`Restoring from ${file}`));
|
|
78039
|
-
|
|
78269
|
+
const hasMemberships = Array.isArray(payload.memberships);
|
|
78270
|
+
println(c.dim(` cerefox_version: ${payload.cerefox_version ?? "?"} · ` + `schema: ${payload.schema_version ?? "?"} · ` + `documents in file: ${payload.documents.length} · chunks in file: ${payload.chunk_count ?? "?"}`));
|
|
78271
|
+
if (hasMemberships) {
|
|
78272
|
+
println(c.dim(` projects: ${payload.projects?.length ?? 0} · memberships: ${payload.memberships?.length ?? 0}`));
|
|
78273
|
+
} else {
|
|
78274
|
+
warn("This backup predates project-membership capture (format 1) — documents " + "will be restored WITHOUT their project assignments.");
|
|
78275
|
+
}
|
|
78276
|
+
{
|
|
78277
|
+
const fileEnv = (payload.env_label ?? "").trim();
|
|
78278
|
+
const targetEnv = (process.env.CEREFOX_ENV_LABEL ?? "").trim();
|
|
78279
|
+
if (fileEnv !== targetEnv) {
|
|
78280
|
+
warn(`This snapshot came from ${fileEnv ? `the "${fileEnv}" environment` : "an unlabelled (production) environment"}, ` + `but you are restoring into ${targetEnv ? `"${targetEnv}"` : "an unlabelled (production) environment"}.`);
|
|
78281
|
+
}
|
|
78282
|
+
}
|
|
78283
|
+
const trashedInFile = payload.documents.filter((d) => d.deleted_at != null).length;
|
|
78284
|
+
if (trashedInFile > 0) {
|
|
78285
|
+
println(c.dim(` trashed documents in file: ${trashedInFile} — restored as trash ` + "(still deleted; recover with `cerefox document restore`)"));
|
|
78286
|
+
}
|
|
78040
78287
|
println("");
|
|
78041
78288
|
const client = getClient();
|
|
78042
78289
|
let restored = 0;
|
|
@@ -78044,7 +78291,7 @@ async function action28(target, options) {
|
|
|
78044
78291
|
let errors4 = 0;
|
|
78045
78292
|
const errorDetails = [];
|
|
78046
78293
|
for (const doc2 of payload.documents) {
|
|
78047
|
-
const { data: existing } = await client.raw.from("cerefox_documents").select("id").eq
|
|
78294
|
+
const { data: existing } = await client.raw.from("cerefox_documents").select("id").or(`id.eq.${doc2.id},content_hash.eq.${doc2.content_hash}`).limit(1).maybeSingle();
|
|
78048
78295
|
if (existing) {
|
|
78049
78296
|
skipped++;
|
|
78050
78297
|
continue;
|
|
@@ -78071,8 +78318,70 @@ async function action28(target, options) {
|
|
|
78071
78318
|
}
|
|
78072
78319
|
restored++;
|
|
78073
78320
|
}
|
|
78321
|
+
let projectsRestored = 0;
|
|
78322
|
+
let membershipsRestored = 0;
|
|
78323
|
+
let relationsRestored = 0;
|
|
78324
|
+
if (!options.dryRun && hasMemberships) {
|
|
78325
|
+
const projects = payload.projects ?? [];
|
|
78326
|
+
if (projects.length > 0) {
|
|
78327
|
+
const { error: projErr } = await client.raw.from("cerefox_projects").upsert(projects, { onConflict: "id", ignoreDuplicates: true });
|
|
78328
|
+
if (projErr) {
|
|
78329
|
+
errors4++;
|
|
78330
|
+
errorDetails.push({ title: "(projects)", error: projErr.message });
|
|
78331
|
+
} else {
|
|
78332
|
+
projectsRestored = projects.length;
|
|
78333
|
+
}
|
|
78334
|
+
}
|
|
78335
|
+
const presentDocIds = new Set;
|
|
78336
|
+
{
|
|
78337
|
+
const ids = (payload.documents ?? []).map((d) => d.id);
|
|
78338
|
+
for (let i = 0;i < ids.length; i += 200) {
|
|
78339
|
+
const { data } = await client.raw.from("cerefox_documents").select("id").in("id", ids.slice(i, i + 200));
|
|
78340
|
+
for (const row of data ?? [])
|
|
78341
|
+
presentDocIds.add(row.id);
|
|
78342
|
+
}
|
|
78343
|
+
}
|
|
78344
|
+
const links = (payload.memberships ?? []).filter((m) => presentDocIds.has(m.document_id));
|
|
78345
|
+
for (let i = 0;i < links.length; i += 500) {
|
|
78346
|
+
const { error: linkErr } = await client.raw.from("cerefox_document_projects").upsert(links.slice(i, i + 500), {
|
|
78347
|
+
onConflict: "document_id,project_id",
|
|
78348
|
+
ignoreDuplicates: true
|
|
78349
|
+
});
|
|
78350
|
+
if (linkErr) {
|
|
78351
|
+
errors4++;
|
|
78352
|
+
errorDetails.push({ title: "(memberships)", error: linkErr.message });
|
|
78353
|
+
break;
|
|
78354
|
+
}
|
|
78355
|
+
membershipsRestored += links.slice(i, i + 500).length;
|
|
78356
|
+
}
|
|
78357
|
+
const relations = (payload.relations ?? []).filter((r) => presentDocIds.has(r.source_id) && presentDocIds.has(r.target_id));
|
|
78358
|
+
if (relations.length > 0) {
|
|
78359
|
+
for (let i = 0;i < relations.length; i += 500) {
|
|
78360
|
+
const { error: relErr } = await client.raw.from("cerefox_document_relations").upsert(relations.slice(i, i + 500), {
|
|
78361
|
+
onConflict: "source_id,target_id,rel_type",
|
|
78362
|
+
ignoreDuplicates: true
|
|
78363
|
+
});
|
|
78364
|
+
if (relErr) {
|
|
78365
|
+
errorDetails.push({ title: "(relations)", error: relErr.message });
|
|
78366
|
+
errors4++;
|
|
78367
|
+
break;
|
|
78368
|
+
}
|
|
78369
|
+
relationsRestored += relations.slice(i, i + 500).length;
|
|
78370
|
+
}
|
|
78371
|
+
const dropped = (payload.relations?.length ?? 0) - relations.length;
|
|
78372
|
+
if (dropped > 0) {
|
|
78373
|
+
warn(`${dropped} relation(s) skipped — one or both documents were not restored.`);
|
|
78374
|
+
}
|
|
78375
|
+
}
|
|
78376
|
+
}
|
|
78074
78377
|
println("");
|
|
78075
78378
|
println((options.dryRun ? c.yellow("(dry-run) ") : "") + c.bold(`Summary: ${restored} restored · ${skipped} skipped · ${errors4} errors`));
|
|
78379
|
+
if (hasMemberships && !options.dryRun) {
|
|
78380
|
+
println(c.dim(` projects: ${projectsRestored} · memberships: ${membershipsRestored}` + (relationsRestored > 0 ? ` · relations: ${relationsRestored}` : "")));
|
|
78381
|
+
}
|
|
78382
|
+
if (trashedInFile > 0) {
|
|
78383
|
+
println(c.dim(` ${trashedInFile} of those are trashed and stay trashed.`));
|
|
78384
|
+
}
|
|
78076
78385
|
if (errors4 > 0) {
|
|
78077
78386
|
println("");
|
|
78078
78387
|
printTable(errorDetails);
|
|
@@ -78080,7 +78389,7 @@ async function action28(target, options) {
|
|
|
78080
78389
|
}
|
|
78081
78390
|
}
|
|
78082
78391
|
function registerRestore(program2) {
|
|
78083
|
-
program2.command("restore").description("Restore a JSON-snapshot backup into the knowledge base.").argument("<snapshot>", "Backup file (or directory; most recent is picked) produced by `cerefox backup`.").option("--dry-run", "Print what would be restored without writing.").option("-p, --project-name <name>", "Reserved for future use; currently ignored
|
|
78392
|
+
program2.command("restore").description("Restore a JSON-snapshot backup into the knowledge base.").argument("<snapshot>", "Backup file (or directory; most recent is picked) produced by `cerefox backup`.").option("--dry-run", "Print what would be restored without writing.").option("-p, --project-name <name>", "Reserved for future use; currently ignored. Project memberships are restored from the backup itself (format 2+).").action(action29);
|
|
78084
78393
|
}
|
|
78085
78394
|
|
|
78086
78395
|
// src/cli/commands/search.ts
|
|
@@ -78105,7 +78414,7 @@ async function embedQuery(query) {
|
|
|
78105
78414
|
}
|
|
78106
78415
|
|
|
78107
78416
|
// src/cli/commands/search.ts
|
|
78108
|
-
async function
|
|
78417
|
+
async function action30(query, options) {
|
|
78109
78418
|
if (!query || query.trim() === "") {
|
|
78110
78419
|
throw userError("Empty query.");
|
|
78111
78420
|
}
|
|
@@ -78271,7 +78580,7 @@ async function action29(query, options) {
|
|
|
78271
78580
|
}
|
|
78272
78581
|
}
|
|
78273
78582
|
function registerSearch(program2) {
|
|
78274
|
-
program2.command("search").description("Search the knowledge base (hybrid FTS + semantic).").argument("<query>", "Natural-language search query.").option("-c, --match-count <n>", "Maximum number of documents to return.", "5").option("-p, --project-name <name>", "Filter results to a specific project.").option("-f, --metadata-filter <json>", "JSON containment filter; only docs whose metadata contains ALL pairs are returned.").option("--mode <mode>", "Search mode: docs (default), hybrid, fts.", "docs").option("--alpha <float>", "Semantic weight 0..1 (default: CEREFOX_SEARCH_ALPHA; else 0.7).").option("--min-score <float>", "Minimum cosine similarity threshold (default: CEREFOX_MIN_SEARCH_SCORE; else 0.5, or 0.6 with the local embedder).").option("--min-term-coverage <float>", "OR-fallback keyword matches must cover at least this fraction of the query's meaningful terms to count as confident hits (default: CEREFOX_MIN_TERM_COVERAGE; else the server default 0.5; needs schema ≥ 0.9.1).").option("--max-bytes <n>", "Response size budget in bytes (default: CEREFOX_MAX_RESPONSE_BYTES or 200000).").option("-r, --requestor <name>", "Agent / user name (recorded in usage log).").option("--json", "Emit machine-readable JSON instead of the default text.").option("--only-metadata", "List matching docs (id, score, chunks, chars, partial/full) WITHOUT their content — like the web UI's collapsed result list. Grab a [id:…] then `cerefox document get <id>`.").action(
|
|
78583
|
+
program2.command("search").description("Search the knowledge base (hybrid FTS + semantic).").argument("<query>", "Natural-language search query.").option("-c, --match-count <n>", "Maximum number of documents to return.", "5").option("-p, --project-name <name>", "Filter results to a specific project.").option("-f, --metadata-filter <json>", "JSON containment filter; only docs whose metadata contains ALL pairs are returned.").option("--mode <mode>", "Search mode: docs (default), hybrid, fts.", "docs").option("--alpha <float>", "Semantic weight 0..1 (default: CEREFOX_SEARCH_ALPHA; else 0.7).").option("--min-score <float>", "Minimum cosine similarity threshold (default: CEREFOX_MIN_SEARCH_SCORE; else 0.5, or 0.6 with the local embedder).").option("--min-term-coverage <float>", "OR-fallback keyword matches must cover at least this fraction of the query's meaningful terms to count as confident hits (default: CEREFOX_MIN_TERM_COVERAGE; else the server default 0.5; needs schema ≥ 0.9.1).").option("--max-bytes <n>", "Response size budget in bytes (default: CEREFOX_MAX_RESPONSE_BYTES or 200000).").option("-r, --requestor <name>", "Agent / user name (recorded in usage log).").option("--json", "Emit machine-readable JSON instead of the default text.").option("--only-metadata", "List matching docs (id, score, chunks, chars, partial/full) WITHOUT their content — like the web UI's collapsed result list. Grab a [id:…] then `cerefox document get <id>`.").action(action30);
|
|
78275
78584
|
}
|
|
78276
78585
|
|
|
78277
78586
|
// src/cli/commands/self-update.ts
|
|
@@ -78318,7 +78627,7 @@ async function fetchLatestVersion() {
|
|
|
78318
78627
|
}
|
|
78319
78628
|
return body.version;
|
|
78320
78629
|
}
|
|
78321
|
-
async function
|
|
78630
|
+
async function action31(options) {
|
|
78322
78631
|
let target;
|
|
78323
78632
|
try {
|
|
78324
78633
|
target = options.version ?? await fetchLatestVersion();
|
|
@@ -78371,7 +78680,7 @@ async function action30(options) {
|
|
|
78371
78680
|
}
|
|
78372
78681
|
function registerSelfUpdate(program2) {
|
|
78373
78682
|
const desc = "Upgrade Cerefox in place. Alias: `cerefox upgrade`.";
|
|
78374
|
-
const declaration = (cmd) => cmd.description(desc).option("--check", "Print current vs latest; do nothing.").option("--yes", "Non-interactive (skip confirmation).").option("--version <version>", "Pin a specific version (e.g. 0.5.1 or 0.6.0-rc.1).").action(
|
|
78683
|
+
const declaration = (cmd) => cmd.description(desc).option("--check", "Print current vs latest; do nothing.").option("--yes", "Non-interactive (skip confirmation).").option("--version <version>", "Pin a specific version (e.g. 0.5.1 or 0.6.0-rc.1).").action(action31);
|
|
78375
78684
|
declaration(program2.command("self-update"));
|
|
78376
78685
|
declaration(program2.command("upgrade"));
|
|
78377
78686
|
}
|
|
@@ -78390,7 +78699,7 @@ function symbol2(status) {
|
|
|
78390
78699
|
return cErr.dim("ℹ");
|
|
78391
78700
|
}
|
|
78392
78701
|
}
|
|
78393
|
-
async function
|
|
78702
|
+
async function action32(options) {
|
|
78394
78703
|
const useSpinner = !options.json && process.stderr.isTTY;
|
|
78395
78704
|
const spinner = useSpinner ? ora({ text: "Starting checks…", spinner: "dots", stream: process.stderr }).start() : null;
|
|
78396
78705
|
const results = await runFastChecks({
|
|
@@ -78411,7 +78720,7 @@ async function action31(options) {
|
|
|
78411
78720
|
}
|
|
78412
78721
|
}
|
|
78413
78722
|
function registerStatus(program2) {
|
|
78414
|
-
program2.command("status").description("Quick sanity check (fast subset of `cerefox doctor`).").option("--json", "Emit machine-readable JSON.").action(
|
|
78723
|
+
program2.command("status").description("Quick sanity check (fast subset of `cerefox doctor`).").option("--json", "Emit machine-readable JSON.").action(action32);
|
|
78415
78724
|
}
|
|
78416
78725
|
|
|
78417
78726
|
// src/cli/commands/token.ts
|
|
@@ -78444,10 +78753,10 @@ function upsertEnvVar(path, key, value, opts = {}) {
|
|
|
78444
78753
|
}
|
|
78445
78754
|
const re = new RegExp(`^(\\s*)${escapeRegExp(key)}=.*$`, "m");
|
|
78446
78755
|
let next;
|
|
78447
|
-
let
|
|
78756
|
+
let action33;
|
|
78448
78757
|
if (re.test(original)) {
|
|
78449
78758
|
next = original.replace(re, `$1${line}`);
|
|
78450
|
-
|
|
78759
|
+
action33 = "updated";
|
|
78451
78760
|
} else {
|
|
78452
78761
|
const base = original.endsWith(`
|
|
78453
78762
|
`) ? original : `${original}
|
|
@@ -78455,10 +78764,10 @@ function upsertEnvVar(path, key, value, opts = {}) {
|
|
|
78455
78764
|
next = `${base}
|
|
78456
78765
|
${header}${line}
|
|
78457
78766
|
`;
|
|
78458
|
-
|
|
78767
|
+
action33 = "added";
|
|
78459
78768
|
}
|
|
78460
78769
|
writeFileSync5(path, next);
|
|
78461
|
-
return { path, action:
|
|
78770
|
+
return { path, action: action33, backupPath };
|
|
78462
78771
|
}
|
|
78463
78772
|
function readEnvVar(path, key) {
|
|
78464
78773
|
if (!existsSync14(path))
|
|
@@ -83303,7 +83612,10 @@ var VERSION_INFO = {
|
|
|
83303
83612
|
};
|
|
83304
83613
|
var SCHEMA_VERSION_RE3 = /^--\s*@version:\s*(\S+)/m;
|
|
83305
83614
|
function registerMetaRoutes(app, ctx) {
|
|
83306
|
-
app.get("/api/v1/version", (c2) =>
|
|
83615
|
+
app.get("/api/v1/version", (c2) => {
|
|
83616
|
+
const label = (process.env.CEREFOX_ENV_LABEL ?? "").trim();
|
|
83617
|
+
return c2.json({ ...VERSION_INFO, env_label: label.length > 0 ? label : null });
|
|
83618
|
+
});
|
|
83307
83619
|
app.get("/api/v1/docs", (c2) => c2.json(listBundledDocs2()));
|
|
83308
83620
|
app.get("/api/v1/docs/:path{.+}", (c2) => {
|
|
83309
83621
|
const docPath = c2.req.param("path");
|
|
@@ -83707,7 +84019,13 @@ import {
|
|
|
83707
84019
|
} from "node:fs";
|
|
83708
84020
|
import { homedir as homedir9 } from "node:os";
|
|
83709
84021
|
import { join as join18 } from "node:path";
|
|
83710
|
-
|
|
84022
|
+
function resolveStateDir(override = process.env.CEREFOX_CONFIG_DIR, home = homedir9()) {
|
|
84023
|
+
override = (override ?? "").trim();
|
|
84024
|
+
if (!override)
|
|
84025
|
+
return join18(home, ".cerefox");
|
|
84026
|
+
return override === "~" || override.startsWith("~/") ? join18(home, override.slice(2)) : override;
|
|
84027
|
+
}
|
|
84028
|
+
var STATE_DIR = resolveStateDir();
|
|
83711
84029
|
var PID_FILE = join18(STATE_DIR, "web.pid");
|
|
83712
84030
|
var LOG_FILE = join18(STATE_DIR, "web.log");
|
|
83713
84031
|
var daemonPaths = { stateDir: STATE_DIR, pidFile: PID_FILE, logFile: LOG_FILE };
|
|
@@ -84075,6 +84393,7 @@ Learn more:
|
|
|
84075
84393
|
const server = program2.command("server").description("Server side: deploy, reindex.");
|
|
84076
84394
|
moveInto(server, registerDeployServer, "deploy");
|
|
84077
84395
|
moveInto(server, registerReindex, "reindex");
|
|
84396
|
+
registerMigrateFormat(server);
|
|
84078
84397
|
const guides = program2.command("guides").description("Bundled docs: list, open, show, ingest (into the KB).");
|
|
84079
84398
|
registerGuides(guides);
|
|
84080
84399
|
moveInto(guides, registerSyncSelfDocs, "ingest");
|
|
@@ -84122,6 +84441,12 @@ async function bareEntryPoint() {
|
|
|
84122
84441
|
}
|
|
84123
84442
|
}
|
|
84124
84443
|
async function main() {
|
|
84444
|
+
{
|
|
84445
|
+
const { loadEnv: loadEnv2 } = await Promise.resolve().then(() => (init_config(), exports_config));
|
|
84446
|
+
try {
|
|
84447
|
+
loadEnv2();
|
|
84448
|
+
} catch {}
|
|
84449
|
+
}
|
|
84125
84450
|
if (process.argv.length === 2) {
|
|
84126
84451
|
await bareEntryPoint();
|
|
84127
84452
|
return;
|