@cerefox/memory 0.5.2 → 0.5.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/README.md +8 -0
- package/dist/bin/cerefox.js +231 -42
- package/docs/guides/connect-agents.md +10 -7
- package/docs/guides/migration-v0.4.md +20 -3
- package/docs/guides/migration-v0.5.md +77 -1
- package/docs/guides/upgrading.md +45 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -79,11 +79,19 @@ already provisioned (see "Before you install").
|
|
|
79
79
|
> the deploy logic is ported to the TS CLI. For now, the setup-supabase
|
|
80
80
|
> guide walks through it.
|
|
81
81
|
|
|
82
|
+
> **Upgrading from the Python `cerefox` CLI?** If you have a working
|
|
83
|
+
> `.env` in your repo clone, init detects it and offers to **copy** it to
|
|
84
|
+
> `~/.cerefox/.env` so the TS CLI uses the new home while Python keeps
|
|
85
|
+
> reading the repo file unchanged. See the migration-v0.5 guide for the
|
|
86
|
+
> three-choice prompt. Existing users with no `~/.cerefox/.env` see zero
|
|
87
|
+
> behavior change until they opt in.
|
|
88
|
+
|
|
82
89
|
---
|
|
83
90
|
|
|
84
91
|
## Connect an AI agent
|
|
85
92
|
|
|
86
93
|
```bash
|
|
94
|
+
# Run the configure-agent commands that apply to your setup:
|
|
87
95
|
cerefox configure-agent --tool claude-code # writes ~/.claude/mcp.json
|
|
88
96
|
cerefox configure-agent --tool claude-desktop # writes Claude Desktop config
|
|
89
97
|
```
|
package/dist/bin/cerefox.js
CHANGED
|
@@ -7179,7 +7179,7 @@ var exports_meta = {};
|
|
|
7179
7179
|
__export(exports_meta, {
|
|
7180
7180
|
PKG_VERSION: () => PKG_VERSION
|
|
7181
7181
|
});
|
|
7182
|
-
var PKG_VERSION = "0.5.
|
|
7182
|
+
var PKG_VERSION = "0.5.3";
|
|
7183
7183
|
var init_meta = () => {};
|
|
7184
7184
|
|
|
7185
7185
|
// ../../node_modules/.bun/tslib@2.8.1/node_modules/tslib/tslib.js
|
|
@@ -22494,26 +22494,35 @@ function expandTilde(p) {
|
|
|
22494
22494
|
}
|
|
22495
22495
|
return p;
|
|
22496
22496
|
}
|
|
22497
|
+
function userStateDirAbs(opts) {
|
|
22498
|
+
return resolvePath(join(opts.home ?? homedir(), USER_STATE_DIR_NAME));
|
|
22499
|
+
}
|
|
22497
22500
|
function resolveConfigDir(opts = {}) {
|
|
22498
22501
|
const override = (env.CEREFOX_CONFIG_DIR ?? "").trim();
|
|
22499
22502
|
if (override) {
|
|
22500
22503
|
return resolvePath(expandTilde(override));
|
|
22501
22504
|
}
|
|
22505
|
+
const userState = userStateDirAbs(opts);
|
|
22506
|
+
if (existsSync(join(userState, ".env"))) {
|
|
22507
|
+
return userState;
|
|
22508
|
+
}
|
|
22502
22509
|
const here = opts.cwd ?? processCwd();
|
|
22503
22510
|
if (existsSync(join(here, ".env"))) {
|
|
22504
22511
|
return resolvePath(here);
|
|
22505
22512
|
}
|
|
22506
|
-
return
|
|
22513
|
+
return userState;
|
|
22507
22514
|
}
|
|
22508
22515
|
function resolveEnvFile(opts = {}) {
|
|
22509
22516
|
return join(resolveConfigDir(opts), ".env");
|
|
22510
22517
|
}
|
|
22511
|
-
function userStateDir() {
|
|
22512
|
-
return
|
|
22518
|
+
function userStateDir(opts = {}) {
|
|
22519
|
+
return userStateDirAbs(opts);
|
|
22513
22520
|
}
|
|
22514
22521
|
function isDevMode(opts = {}) {
|
|
22515
22522
|
if ((env.CEREFOX_CONFIG_DIR ?? "").trim())
|
|
22516
22523
|
return false;
|
|
22524
|
+
if (existsSync(join(userStateDirAbs(opts), ".env")))
|
|
22525
|
+
return false;
|
|
22517
22526
|
const here = opts.cwd ?? processCwd();
|
|
22518
22527
|
return existsSync(join(here, ".env"));
|
|
22519
22528
|
}
|
|
@@ -38333,7 +38342,7 @@ init_cli_core();
|
|
|
38333
38342
|
init_meta();
|
|
38334
38343
|
init_config();
|
|
38335
38344
|
init_config();
|
|
38336
|
-
import { existsSync as existsSync5, statSync as statSync2 } from "node:fs";
|
|
38345
|
+
import { existsSync as existsSync5, realpathSync, statSync as statSync2 } from "node:fs";
|
|
38337
38346
|
import { homedir as homedir4 } from "node:os";
|
|
38338
38347
|
import { join as join5 } from "node:path";
|
|
38339
38348
|
function checkBinary() {
|
|
@@ -38577,6 +38586,23 @@ function checkMcpConfigs() {
|
|
|
38577
38586
|
detail: found.map((f) => f.label).join(", ")
|
|
38578
38587
|
};
|
|
38579
38588
|
}
|
|
38589
|
+
function checkLegacyShadowEnv() {
|
|
38590
|
+
const home = homedir4();
|
|
38591
|
+
const homeEnv = join5(home, USER_STATE_DIR_NAME, ".env");
|
|
38592
|
+
const cwdEnv = join5(process.cwd(), ".env");
|
|
38593
|
+
if (!existsSync5(homeEnv) || !existsSync5(cwdEnv))
|
|
38594
|
+
return null;
|
|
38595
|
+
try {
|
|
38596
|
+
if (realpathSync(homeEnv) === realpathSync(cwdEnv))
|
|
38597
|
+
return null;
|
|
38598
|
+
} catch {}
|
|
38599
|
+
return {
|
|
38600
|
+
name: "legacy env",
|
|
38601
|
+
status: "skipped",
|
|
38602
|
+
detail: `${cwdEnv} (shadowed by ~/.cerefox/.env)`,
|
|
38603
|
+
hint: "Python `uv run cerefox …` still reads this file during the v0.5–v0.7 migration window. " + "Safe to delete once Python support is removed (v0.9+)."
|
|
38604
|
+
};
|
|
38605
|
+
}
|
|
38580
38606
|
function checkPostgres() {
|
|
38581
38607
|
if (process.env.CEREFOX_DATABASE_URL) {
|
|
38582
38608
|
return {
|
|
@@ -38593,11 +38619,13 @@ function checkPostgres() {
|
|
|
38593
38619
|
};
|
|
38594
38620
|
}
|
|
38595
38621
|
async function runAllChecks() {
|
|
38622
|
+
const legacy = checkLegacyShadowEnv();
|
|
38596
38623
|
return [
|
|
38597
38624
|
checkBinary(),
|
|
38598
38625
|
checkRuntime(),
|
|
38599
38626
|
checkVersion(),
|
|
38600
38627
|
checkConfig(),
|
|
38628
|
+
...legacy ? [legacy] : [],
|
|
38601
38629
|
await checkSupabase(),
|
|
38602
38630
|
await checkOpenAI(),
|
|
38603
38631
|
await checkSchemaVersion(),
|
|
@@ -38938,12 +38966,14 @@ init_cli_core();
|
|
|
38938
38966
|
init_config();
|
|
38939
38967
|
import {
|
|
38940
38968
|
chmodSync,
|
|
38969
|
+
copyFileSync as copyFileSync2,
|
|
38941
38970
|
existsSync as existsSync6,
|
|
38942
38971
|
mkdirSync as mkdirSync3,
|
|
38943
38972
|
readFileSync as readFileSync7,
|
|
38944
38973
|
writeFileSync as writeFileSync3
|
|
38945
38974
|
} from "node:fs";
|
|
38946
|
-
import {
|
|
38975
|
+
import { homedir as homedir5 } from "node:os";
|
|
38976
|
+
import { dirname as dirname3, join as join7 } from "node:path";
|
|
38947
38977
|
async function readConfigFile(path) {
|
|
38948
38978
|
if (!existsSync6(path)) {
|
|
38949
38979
|
throw userError(`--config file not found: ${path}`);
|
|
@@ -38973,6 +39003,41 @@ async function readConfigFile(path) {
|
|
|
38973
39003
|
CEREFOX_AUTHOR_TYPE: typeof obj.CEREFOX_AUTHOR_TYPE === "string" ? obj.CEREFOX_AUTHOR_TYPE : undefined
|
|
38974
39004
|
};
|
|
38975
39005
|
}
|
|
39006
|
+
function parseDotEnvFile(content) {
|
|
39007
|
+
const map = {};
|
|
39008
|
+
for (const rawLine of content.split(/\r?\n/)) {
|
|
39009
|
+
const line = rawLine.trim();
|
|
39010
|
+
if (!line || line.startsWith("#"))
|
|
39011
|
+
continue;
|
|
39012
|
+
const eqIdx = line.indexOf("=");
|
|
39013
|
+
if (eqIdx === -1)
|
|
39014
|
+
continue;
|
|
39015
|
+
const key = line.slice(0, eqIdx).trim();
|
|
39016
|
+
let value = line.slice(eqIdx + 1).trim();
|
|
39017
|
+
if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
|
|
39018
|
+
value = value.slice(1, -1);
|
|
39019
|
+
}
|
|
39020
|
+
map[key] = value;
|
|
39021
|
+
}
|
|
39022
|
+
return map;
|
|
39023
|
+
}
|
|
39024
|
+
function answersFromEnvFile(path) {
|
|
39025
|
+
const parsed = parseDotEnvFile(readFileSync7(path, "utf8"));
|
|
39026
|
+
const required = ["CEREFOX_SUPABASE_URL", "CEREFOX_SUPABASE_KEY", "OPENAI_API_KEY"];
|
|
39027
|
+
for (const key of required) {
|
|
39028
|
+
if (!parsed[key] || parsed[key].trim() === "") {
|
|
39029
|
+
throw userError(`Existing .env at ${path} is missing required key "${key}".`, `Fix it manually or run \`cerefox init --force\` to start fresh.`);
|
|
39030
|
+
}
|
|
39031
|
+
}
|
|
39032
|
+
return {
|
|
39033
|
+
CEREFOX_SUPABASE_URL: parsed.CEREFOX_SUPABASE_URL,
|
|
39034
|
+
CEREFOX_SUPABASE_KEY: parsed.CEREFOX_SUPABASE_KEY,
|
|
39035
|
+
OPENAI_API_KEY: parsed.OPENAI_API_KEY,
|
|
39036
|
+
CEREFOX_DATABASE_URL: parsed.CEREFOX_DATABASE_URL,
|
|
39037
|
+
CEREFOX_AUTHOR_NAME: parsed.CEREFOX_AUTHOR_NAME,
|
|
39038
|
+
CEREFOX_AUTHOR_TYPE: parsed.CEREFOX_AUTHOR_TYPE
|
|
39039
|
+
};
|
|
39040
|
+
}
|
|
38976
39041
|
async function promptForAnswers() {
|
|
38977
39042
|
println(c.bold("Cerefox first-run setup."));
|
|
38978
39043
|
println(c.dim(`This will write configuration to ~/.cerefox/.env (or CEREFOX_CONFIG_DIR if set).
|
|
@@ -39087,35 +39152,38 @@ async function validateOpenAI(key) {
|
|
|
39087
39152
|
throw userError(`OpenAI key validation failed: ${resp.status} ${body.slice(0, 100)}`, "Verify the key on https://platform.openai.com/api-keys.");
|
|
39088
39153
|
}
|
|
39089
39154
|
}
|
|
39090
|
-
|
|
39091
|
-
const envPath = resolveEnvFile();
|
|
39092
|
-
if (existsSync6(envPath) && !options.force) {
|
|
39093
|
-
println(c.yellow(`⚠ Config already exists at ${envPath}.`));
|
|
39094
|
-
const ok2 = await confirm("Overwrite?", true);
|
|
39095
|
-
if (!ok2) {
|
|
39096
|
-
println(c.dim("Aborted. Use `--force` to skip this prompt next time."));
|
|
39097
|
-
return;
|
|
39098
|
-
}
|
|
39099
|
-
}
|
|
39100
|
-
const answers = options.config ? await readConfigFile(options.config) : await promptForAnswers();
|
|
39155
|
+
function printMigrationMenu(cwdEnv, homeEnv) {
|
|
39101
39156
|
println("");
|
|
39102
|
-
println(c.
|
|
39103
|
-
|
|
39104
|
-
println(
|
|
39105
|
-
|
|
39106
|
-
println(c.green(" ✓ OpenAI key valid (test embedding succeeded)"));
|
|
39107
|
-
mkdirSync3(dirname3(envPath), { recursive: true });
|
|
39108
|
-
writeFileSync3(envPath, buildEnvFile(answers), "utf8");
|
|
39109
|
-
if (process.platform !== "win32") {
|
|
39110
|
-
try {
|
|
39111
|
-
chmodSync(envPath, 384);
|
|
39112
|
-
} catch {
|
|
39113
|
-
warn(`Could not chmod 0600 ${envPath}.`);
|
|
39114
|
-
}
|
|
39115
|
-
}
|
|
39157
|
+
println(c.yellow(`⚠ Found existing config at ${cwdEnv}.`));
|
|
39158
|
+
println("");
|
|
39159
|
+
println("This may be from a previous Python install. The TS CLI can use the");
|
|
39160
|
+
println("same .env — env-var names are identical, no rewrite needed.");
|
|
39116
39161
|
println("");
|
|
39117
|
-
println(c.
|
|
39162
|
+
println(" " + c.bold("[c]") + " Copy to " + homeEnv + " " + c.green("(recommended)"));
|
|
39163
|
+
println(c.dim(" • TS reads the new home from now on"));
|
|
39164
|
+
println(c.dim(" • Python keeps reading " + cwdEnv + " (backward compat)"));
|
|
39165
|
+
println(c.dim(" • Edit ~/.cerefox/.env going forward; the repo .env is legacy"));
|
|
39118
39166
|
println("");
|
|
39167
|
+
println(" " + c.bold("[u]") + " Use " + cwdEnv + " as-is, skip writing anything");
|
|
39168
|
+
println(c.dim(" • Both TS and Python keep reading the existing file"));
|
|
39169
|
+
println(c.dim(" • Defer the migration"));
|
|
39170
|
+
println("");
|
|
39171
|
+
println(" " + c.bold("[f]") + " Fresh start — interactive prompts, write to " + homeEnv);
|
|
39172
|
+
println(c.dim(" • Use if the existing file is stale or wrong"));
|
|
39173
|
+
println("");
|
|
39174
|
+
}
|
|
39175
|
+
async function promptMigrationChoice() {
|
|
39176
|
+
const choice = await ask({
|
|
39177
|
+
type: "text",
|
|
39178
|
+
name: "choice",
|
|
39179
|
+
message: "Choice (c/u/f) [c]",
|
|
39180
|
+
initial: "c",
|
|
39181
|
+
validate: (v) => /^[cuf]?$/i.test(v.trim()) || "Expected c, u, or f."
|
|
39182
|
+
});
|
|
39183
|
+
const ch = choice.trim().toLowerCase() || "c";
|
|
39184
|
+
return ch;
|
|
39185
|
+
}
|
|
39186
|
+
async function postWriteLifecycle(envPath, options) {
|
|
39119
39187
|
if (!options.skipSchema) {
|
|
39120
39188
|
println(c.bold("Schema deploy"));
|
|
39121
39189
|
println(c.dim(` v0.5 doesn't yet bundle the schema-deploy path (it needs the direct
|
|
@@ -39159,6 +39227,127 @@ async function action14(options) {
|
|
|
39159
39227
|
println(c.dim(" cerefox doctor # verify everything"));
|
|
39160
39228
|
println(c.dim(' cerefox search "…" # search the KB'));
|
|
39161
39229
|
println(c.dim(" cerefox ingest <file> # add a doc"));
|
|
39230
|
+
println("");
|
|
39231
|
+
println(c.dim(` Config in effect: ${envPath}`));
|
|
39232
|
+
}
|
|
39233
|
+
function writeAnswersTo(target, answers) {
|
|
39234
|
+
mkdirSync3(dirname3(target), { recursive: true });
|
|
39235
|
+
writeFileSync3(target, buildEnvFile(answers), "utf8");
|
|
39236
|
+
if (process.platform !== "win32") {
|
|
39237
|
+
try {
|
|
39238
|
+
chmodSync(target, 384);
|
|
39239
|
+
} catch {
|
|
39240
|
+
warn(`Could not chmod 0600 ${target}.`);
|
|
39241
|
+
}
|
|
39242
|
+
}
|
|
39243
|
+
}
|
|
39244
|
+
async function action14(options) {
|
|
39245
|
+
const homeEnv = join7(homedir5(), USER_STATE_DIR_NAME, ".env");
|
|
39246
|
+
const cwdEnv = join7(process.cwd(), ".env");
|
|
39247
|
+
const explicitDir = (process.env.CEREFOX_CONFIG_DIR ?? "").trim();
|
|
39248
|
+
if (explicitDir) {
|
|
39249
|
+
const target2 = resolveEnvFile();
|
|
39250
|
+
if (existsSync6(target2) && !options.force) {
|
|
39251
|
+
println(c.yellow(`⚠ Config already exists at ${target2}.`));
|
|
39252
|
+
const ok2 = await confirm("Overwrite?", true);
|
|
39253
|
+
if (!ok2) {
|
|
39254
|
+
println(c.dim("Aborted. Use `--force` to skip this prompt next time."));
|
|
39255
|
+
return;
|
|
39256
|
+
}
|
|
39257
|
+
}
|
|
39258
|
+
const answers2 = options.config ? await readConfigFile(options.config) : await promptForAnswers();
|
|
39259
|
+
println("");
|
|
39260
|
+
println(c.bold("Validating credentials…"));
|
|
39261
|
+
await validateSupabase(answers2.CEREFOX_SUPABASE_URL, answers2.CEREFOX_SUPABASE_KEY);
|
|
39262
|
+
println(c.green(" ✓ Supabase reachable"));
|
|
39263
|
+
await validateOpenAI(answers2.OPENAI_API_KEY);
|
|
39264
|
+
println(c.green(" ✓ OpenAI key valid (test embedding succeeded)"));
|
|
39265
|
+
writeAnswersTo(target2, answers2);
|
|
39266
|
+
println("");
|
|
39267
|
+
println(c.green(`✓ Wrote ${target2}`));
|
|
39268
|
+
println("");
|
|
39269
|
+
await postWriteLifecycle(target2, options);
|
|
39270
|
+
return;
|
|
39271
|
+
}
|
|
39272
|
+
if (existsSync6(homeEnv) && !options.force) {
|
|
39273
|
+
println(c.yellow(`⚠ Config already exists at ${homeEnv}.`));
|
|
39274
|
+
const ok2 = await confirm("Overwrite?", true);
|
|
39275
|
+
if (!ok2) {
|
|
39276
|
+
println(c.dim("Aborted. Use `--force` to skip this prompt next time."));
|
|
39277
|
+
return;
|
|
39278
|
+
}
|
|
39279
|
+
const answers2 = options.config ? await readConfigFile(options.config) : await promptForAnswers();
|
|
39280
|
+
println("");
|
|
39281
|
+
println(c.bold("Validating credentials…"));
|
|
39282
|
+
await validateSupabase(answers2.CEREFOX_SUPABASE_URL, answers2.CEREFOX_SUPABASE_KEY);
|
|
39283
|
+
println(c.green(" ✓ Supabase reachable"));
|
|
39284
|
+
await validateOpenAI(answers2.OPENAI_API_KEY);
|
|
39285
|
+
println(c.green(" ✓ OpenAI key valid (test embedding succeeded)"));
|
|
39286
|
+
writeAnswersTo(homeEnv, answers2);
|
|
39287
|
+
println("");
|
|
39288
|
+
println(c.green(`✓ Wrote ${homeEnv}`));
|
|
39289
|
+
println("");
|
|
39290
|
+
await postWriteLifecycle(homeEnv, options);
|
|
39291
|
+
return;
|
|
39292
|
+
}
|
|
39293
|
+
if (existsSync6(cwdEnv) && !options.force && !options.config) {
|
|
39294
|
+
printMigrationMenu(cwdEnv, homeEnv);
|
|
39295
|
+
const ch = await promptMigrationChoice();
|
|
39296
|
+
println("");
|
|
39297
|
+
if (ch === "c") {
|
|
39298
|
+
mkdirSync3(dirname3(homeEnv), { recursive: true });
|
|
39299
|
+
copyFileSync2(cwdEnv, homeEnv);
|
|
39300
|
+
if (process.platform !== "win32") {
|
|
39301
|
+
try {
|
|
39302
|
+
chmodSync(homeEnv, 384);
|
|
39303
|
+
} catch {
|
|
39304
|
+
warn(`Could not chmod 0600 ${homeEnv}.`);
|
|
39305
|
+
}
|
|
39306
|
+
}
|
|
39307
|
+
println(c.green(`✓ Copied ${cwdEnv} → ${homeEnv}`));
|
|
39308
|
+
println(c.dim(` Repo file unchanged — Python still reads it during migration.`));
|
|
39309
|
+
println("");
|
|
39310
|
+
const answers2 = answersFromEnvFile(homeEnv);
|
|
39311
|
+
println(c.bold("Validating credentials…"));
|
|
39312
|
+
await validateSupabase(answers2.CEREFOX_SUPABASE_URL, answers2.CEREFOX_SUPABASE_KEY);
|
|
39313
|
+
println(c.green(" ✓ Supabase reachable"));
|
|
39314
|
+
await validateOpenAI(answers2.OPENAI_API_KEY);
|
|
39315
|
+
println(c.green(" ✓ OpenAI key valid (test embedding succeeded)"));
|
|
39316
|
+
println("");
|
|
39317
|
+
await postWriteLifecycle(homeEnv, options);
|
|
39318
|
+
return;
|
|
39319
|
+
}
|
|
39320
|
+
if (ch === "u") {
|
|
39321
|
+
const answers2 = answersFromEnvFile(cwdEnv);
|
|
39322
|
+
println(c.bold("Validating existing config…"));
|
|
39323
|
+
await validateSupabase(answers2.CEREFOX_SUPABASE_URL, answers2.CEREFOX_SUPABASE_KEY);
|
|
39324
|
+
println(c.green(" ✓ Supabase reachable"));
|
|
39325
|
+
await validateOpenAI(answers2.OPENAI_API_KEY);
|
|
39326
|
+
println(c.green(" ✓ OpenAI key valid (test embedding succeeded)"));
|
|
39327
|
+
println("");
|
|
39328
|
+
println(c.green(`✓ Using existing config at ${cwdEnv}`));
|
|
39329
|
+
println(c.dim(` TS reads it via the legacy dev-mode fallback (~/.cerefox/.env not present).`));
|
|
39330
|
+
println(c.dim(` Run \`cerefox init\` again later to migrate to the new home.`));
|
|
39331
|
+
println("");
|
|
39332
|
+
await postWriteLifecycle(cwdEnv, options);
|
|
39333
|
+
return;
|
|
39334
|
+
}
|
|
39335
|
+
println(c.dim(`Fresh start. Ignoring ${cwdEnv}; writing a new config to ${homeEnv}.`));
|
|
39336
|
+
println("");
|
|
39337
|
+
}
|
|
39338
|
+
const target = homeEnv;
|
|
39339
|
+
const answers = options.config ? await readConfigFile(options.config) : await promptForAnswers();
|
|
39340
|
+
println("");
|
|
39341
|
+
println(c.bold("Validating credentials…"));
|
|
39342
|
+
await validateSupabase(answers.CEREFOX_SUPABASE_URL, answers.CEREFOX_SUPABASE_KEY);
|
|
39343
|
+
println(c.green(" ✓ Supabase reachable"));
|
|
39344
|
+
await validateOpenAI(answers.OPENAI_API_KEY);
|
|
39345
|
+
println(c.green(" ✓ OpenAI key valid (test embedding succeeded)"));
|
|
39346
|
+
writeAnswersTo(target, answers);
|
|
39347
|
+
println("");
|
|
39348
|
+
println(c.green(`✓ Wrote ${target}`));
|
|
39349
|
+
println("");
|
|
39350
|
+
await postWriteLifecycle(target, options);
|
|
39162
39351
|
}
|
|
39163
39352
|
function registerInit(program2) {
|
|
39164
39353
|
program2.command("init").description("Interactive first-run setup (config, schema deploy stub, optional MCP wiring).").option("-c, --config <file>", "Non-interactive mode: read answers from a JSON file.").option("--force", "Overwrite existing configuration without prompting.").option("--skip-schema", "Skip the schema deploy step.").option("--skip-self-docs", "Skip the bundled self-doc ingest.").option("--skip-agent-config", "Skip the optional MCP agent wiring.").action(action14);
|
|
@@ -39436,13 +39625,13 @@ function registerReindex(program2) {
|
|
|
39436
39625
|
init_cli_core();
|
|
39437
39626
|
init_client();
|
|
39438
39627
|
import { existsSync as existsSync7, readFileSync as readFileSync8, readdirSync as readdirSync3, statSync as statSync4 } from "node:fs";
|
|
39439
|
-
import { homedir as
|
|
39440
|
-
import { join as
|
|
39628
|
+
import { homedir as homedir6 } from "node:os";
|
|
39629
|
+
import { join as join8, resolve as resolve3 } from "node:path";
|
|
39441
39630
|
function expandHome2(path) {
|
|
39442
39631
|
if (path === "~")
|
|
39443
|
-
return
|
|
39632
|
+
return homedir6();
|
|
39444
39633
|
if (path.startsWith("~/"))
|
|
39445
|
-
return
|
|
39634
|
+
return join8(homedir6(), path.slice(2));
|
|
39446
39635
|
return path;
|
|
39447
39636
|
}
|
|
39448
39637
|
function resolveBackupFile(target) {
|
|
@@ -39453,11 +39642,11 @@ function resolveBackupFile(target) {
|
|
|
39453
39642
|
const stat = statSync4(path);
|
|
39454
39643
|
if (stat.isFile())
|
|
39455
39644
|
return path;
|
|
39456
|
-
const candidates = readdirSync3(path).filter((n) => n.endsWith(".json") && n.startsWith("cerefox-")).map((n) => ({ name: n, mtime: statSync4(
|
|
39645
|
+
const candidates = readdirSync3(path).filter((n) => n.endsWith(".json") && n.startsWith("cerefox-")).map((n) => ({ name: n, mtime: statSync4(join8(path, n)).mtimeMs })).sort((a, b) => b.mtime - a.mtime);
|
|
39457
39646
|
if (candidates.length === 0) {
|
|
39458
39647
|
throw userError(`No cerefox-*.json files in ${path}`);
|
|
39459
39648
|
}
|
|
39460
|
-
return
|
|
39649
|
+
return join8(path, candidates[0].name);
|
|
39461
39650
|
}
|
|
39462
39651
|
async function action20(target, options) {
|
|
39463
39652
|
const file = resolveBackupFile(target);
|
|
@@ -39824,14 +40013,14 @@ import {
|
|
|
39824
40013
|
readdirSync as readdirSync4,
|
|
39825
40014
|
statSync as statSync5
|
|
39826
40015
|
} from "node:fs";
|
|
39827
|
-
import { basename as basename4, extname as extname4, join as
|
|
40016
|
+
import { basename as basename4, extname as extname4, join as join9, relative } from "node:path";
|
|
39828
40017
|
var ROOT_LEVEL_DOCS = ["README.md", "AGENT_GUIDE.md", "AGENT_QUICK_REFERENCE.md"];
|
|
39829
40018
|
function walkMarkdown(dir) {
|
|
39830
40019
|
const out = [];
|
|
39831
40020
|
if (!existsSync8(dir))
|
|
39832
40021
|
return out;
|
|
39833
40022
|
for (const name of readdirSync4(dir)) {
|
|
39834
|
-
const full =
|
|
40023
|
+
const full = join9(dir, name);
|
|
39835
40024
|
let stat;
|
|
39836
40025
|
try {
|
|
39837
40026
|
stat = statSync5(full);
|
|
@@ -39851,11 +40040,11 @@ async function action24(options) {
|
|
|
39851
40040
|
const project = options.project ?? "cerefox";
|
|
39852
40041
|
const targets = [];
|
|
39853
40042
|
for (const rel of ROOT_LEVEL_DOCS) {
|
|
39854
|
-
const abs =
|
|
40043
|
+
const abs = join9(cwd, rel);
|
|
39855
40044
|
if (existsSync8(abs))
|
|
39856
40045
|
targets.push({ abs, rel });
|
|
39857
40046
|
}
|
|
39858
|
-
for (const abs of walkMarkdown(
|
|
40047
|
+
for (const abs of walkMarkdown(join9(cwd, "docs"))) {
|
|
39859
40048
|
targets.push({ abs, rel: relative(cwd, abs) });
|
|
39860
40049
|
}
|
|
39861
40050
|
if (targets.length === 0) {
|
|
@@ -112,19 +112,22 @@ The local Cerefox MCP server runs on your machine and exposes the same 10 tools
|
|
|
112
112
|
Edge Function, communicating with clients over stdio.
|
|
113
113
|
|
|
114
114
|
As of **v0.4.0** the local server ships as an npm package — **[`@cerefox/memory`](https://www.npmjs.com/package/@cerefox/memory)** — built with the official `@modelcontextprotocol/sdk`.
|
|
115
|
-
The bin entry is `cerefox` (run as `cerefox mcp`). The recommended client config is `npx -y --package=@cerefox/memory cerefox mcp`.
|
|
115
|
+
The bin entry is `cerefox` (run as `cerefox mcp`). The recommended client config is `npx -y --package=@cerefox/memory cerefox mcp`, or if you've installed the package globally, just `cerefox mcp`.
|
|
116
116
|
|
|
117
|
-
The
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
117
|
+
The Python `uv run cerefox mcp` invocation **still works** and remains the right choice if
|
|
118
|
+
you've installed Cerefox from a source checkout. v0.4 through v0.5.1 advertised a
|
|
119
|
+
"soft wrapper" that tried to auto-delegate to the npm package, but the probe was unreliable
|
|
120
|
+
under MCP-client launch environments — v0.5.2 removed it. The two paths (Python via
|
|
121
|
+
`uv run`, TS via `cerefox mcp` on PATH or via `npx`) are now **fully independent**.
|
|
122
|
+
Pick one explicitly in your MCP client config.
|
|
121
123
|
|
|
122
124
|
- Embeddings are computed locally using your `.env` key (no extra credentials)
|
|
123
125
|
- Works offline except for the OpenAI embedding API call per query
|
|
124
126
|
- One setup, all compatible local clients (Claude Desktop, Cursor, Claude Code, Codex CLI, …)
|
|
125
127
|
|
|
126
|
-
See [`docs/guides/migration-v0.
|
|
127
|
-
|
|
128
|
+
See [`docs/guides/migration-v0.5.md`](migration-v0.5.md) for the per-client config
|
|
129
|
+
snippets, the v0.5.2 soft-wrapper removal explainer, and the v0.5.3 `.env` location
|
|
130
|
+
change.
|
|
128
131
|
|
|
129
132
|
> **Why not `mcp-server-fetch`?** The generic fetch MCP only supports GET requests and cannot
|
|
130
133
|
> make authenticated POST calls to the Edge Functions. The built-in local server is
|
|
@@ -1,6 +1,23 @@
|
|
|
1
|
-
# Migrating to Cerefox v0.4.0
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
# Migrating to Cerefox v0.4.0 (historical)
|
|
2
|
+
|
|
3
|
+
> ## ⚠ Historical document — do not use the snippets in this file
|
|
4
|
+
>
|
|
5
|
+
> This guide documents the **v0.4.0 → v0.4.3 migration window** (May 2026).
|
|
6
|
+
> The `cerefox-mcp` bin name referenced throughout was dropped in **v0.5.1**;
|
|
7
|
+
> the soft-wrapper described in some sections was removed in **v0.5.2**.
|
|
8
|
+
> The per-client config snippets below **will not work on @cerefox/memory v0.5+**.
|
|
9
|
+
>
|
|
10
|
+
> **If you're upgrading today, use the current guide instead:**
|
|
11
|
+
> → [`migration-v0.5.md`](migration-v0.5.md) — covers Python `cerefox` → v0.5.x
|
|
12
|
+
> AND v0.4.x → v0.5.x in a single document, with the v0.5.0/v0.5.1/v0.5.2/v0.5.3
|
|
13
|
+
> transitions all explained.
|
|
14
|
+
>
|
|
15
|
+
> This file is preserved so historical CHANGELOG entries that reference it
|
|
16
|
+
> still resolve. It's not maintained.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
**Original TL;DR (preserved verbatim)**: nothing urgent. Your existing `cerefox mcp` configs keep
|
|
4
21
|
working unchanged. The Python `cerefox mcp` command is now a soft
|
|
5
22
|
wrapper that transparently uses the new TypeScript MCP server if it's
|
|
6
23
|
installed, falling back to the legacy Python implementation otherwise.
|
|
@@ -1,4 +1,22 @@
|
|
|
1
|
-
# Migrating to Cerefox v0.5.
|
|
1
|
+
# Migrating to Cerefox v0.5.x
|
|
2
|
+
|
|
3
|
+
**This is the canonical upgrade guide for any user landing on Cerefox v0.5+.**
|
|
4
|
+
It covers the v0.4 → v0.5 transition, the v0.5.x patch trail (v0.5.1, v0.5.2,
|
|
5
|
+
v0.5.3), and the Python `cerefox` → TS `cerefox` migration path.
|
|
6
|
+
|
|
7
|
+
## Where to start
|
|
8
|
+
|
|
9
|
+
| Coming from | Read |
|
|
10
|
+
|---|---|
|
|
11
|
+
| Never used Cerefox before | [`quickstart.md`](quickstart.md) first, then come back here only if you hit a `.env` / config question |
|
|
12
|
+
| Python `cerefox` (any version through v0.5.x) | "What changed" → "Install paths" → "v0.5.3 migrated `.env`" sections below |
|
|
13
|
+
| `@cerefox/memory` v0.4.x (npm) | "Upgrading an existing MCP client config" → "v0.5.2 fixed the soft wrapper" → "v0.5.3 migrated `.env`" |
|
|
14
|
+
| `@cerefox/memory` v0.5.0 or v0.5.1 (npm) | "v0.5.2 fixed the soft wrapper" + "v0.5.3 migrated `.env`" |
|
|
15
|
+
| `@cerefox/memory` v0.5.2 (npm) | "v0.5.3 migrated `.env`" — the rest is unchanged |
|
|
16
|
+
|
|
17
|
+
> Looking for `migration-v0.4.md`? It's been demoted to a historical
|
|
18
|
+
> record (the bin names it documents no longer exist). Everything you
|
|
19
|
+
> need to know about the v0.4 → v0.5 transition lives in this file.
|
|
2
20
|
|
|
3
21
|
**TL;DR:** the Cerefox CLI is now a TypeScript binary published to npm.
|
|
4
22
|
You can keep using the Python CLI through v0.7.x (it just prints a
|
|
@@ -196,6 +214,64 @@ explicit instead of "magic delegation".
|
|
|
196
214
|
|
|
197
215
|
---
|
|
198
216
|
|
|
217
|
+
## v0.5.3 migrated `.env` from `<repo>/.env` to `~/.cerefox/.env`
|
|
218
|
+
|
|
219
|
+
If you've been using the Python `cerefox` CLI, your `.env` lives in your
|
|
220
|
+
repo root (`/path/to/cerefox/.env`). The TS CLI v0.5.2 also read that
|
|
221
|
+
file, via a "CWD `.env` wins" precedence inherited from Python. v0.5.3
|
|
222
|
+
flips that precedence: **once `~/.cerefox/.env` exists, the TS CLI reads
|
|
223
|
+
from there**; the repo file becomes a legacy fallback for Python's
|
|
224
|
+
`uv run cerefox …` workflows.
|
|
225
|
+
|
|
226
|
+
**You see zero behavior change until you run `cerefox init`.** If your
|
|
227
|
+
home dir doesn't have `~/.cerefox/.env`, the TS CLI keeps reading your
|
|
228
|
+
existing repo `.env` (legacy dev-mode precedence). No action required.
|
|
229
|
+
|
|
230
|
+
When you do run `cerefox init` with a repo `.env` already in place, the
|
|
231
|
+
TS CLI offers a three-choice menu:
|
|
232
|
+
|
|
233
|
+
```
|
|
234
|
+
⚠ Found existing config at /path/to/cerefox/.env.
|
|
235
|
+
|
|
236
|
+
[c] Copy to /Users/you/.cerefox/.env (recommended)
|
|
237
|
+
• TS reads the new home from now on
|
|
238
|
+
• Python keeps reading /path/to/cerefox/.env (backward compat)
|
|
239
|
+
• Edit ~/.cerefox/.env going forward; the repo .env is legacy
|
|
240
|
+
|
|
241
|
+
[u] Use /path/to/cerefox/.env as-is, skip writing anything
|
|
242
|
+
• Both TS and Python keep reading the existing file
|
|
243
|
+
• Defer the migration
|
|
244
|
+
|
|
245
|
+
[f] Fresh start — interactive prompts, write to /Users/you/.cerefox/.env
|
|
246
|
+
• Use if the existing file is stale or wrong
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
Pick **[c]** for the typical Python → TS upgrade. The TS CLI starts
|
|
250
|
+
reading `~/.cerefox/.env`; your remaining Python `uv run cerefox …`
|
|
251
|
+
commands keep reading the unchanged repo file. The two files diverge
|
|
252
|
+
only if you start editing one of them — keep them in sync (or just edit
|
|
253
|
+
`~/.cerefox/.env` and accept that Python uses a frozen snapshot until
|
|
254
|
+
v0.9).
|
|
255
|
+
|
|
256
|
+
After v0.9 (Python CLI removed), `cerefox doctor` will say "ok" if you
|
|
257
|
+
delete the repo file. Until then, `doctor` reports it as
|
|
258
|
+
`legacy env … (shadowed by ~/.cerefox/.env)` so you know it's harmless.
|
|
259
|
+
|
|
260
|
+
### Python paths.py precedence (unchanged)
|
|
261
|
+
|
|
262
|
+
`src/cerefox/paths.py` keeps the v0.5.2 precedence (CWD `.env` wins).
|
|
263
|
+
Your existing `uv run cerefox …` invocations from inside the repo
|
|
264
|
+
continue to read the repo file regardless of what's in `~/.cerefox/`.
|
|
265
|
+
When this module goes away in v0.9+, the divergence resolves naturally.
|
|
266
|
+
|
|
267
|
+
### `CEREFOX_CONFIG_DIR` is unchanged
|
|
268
|
+
|
|
269
|
+
If you have `CEREFOX_CONFIG_DIR` set (e.g. for a non-standard install),
|
|
270
|
+
it still wins over both home and repo `.env` files. Init writes there
|
|
271
|
+
and skips the migration prompt.
|
|
272
|
+
|
|
273
|
+
---
|
|
274
|
+
|
|
199
275
|
## Known gotchas
|
|
200
276
|
|
|
201
277
|
### `npx` from inside an npm workspace
|
package/docs/guides/upgrading.md
CHANGED
|
@@ -1,8 +1,27 @@
|
|
|
1
1
|
# Upgrading Cerefox
|
|
2
2
|
|
|
3
|
-
This guide covers upgrading an existing Cerefox installation
|
|
3
|
+
This guide covers upgrading an existing Cerefox installation. All steps are idempotent and safe to re-run.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Pick your path
|
|
6
|
+
|
|
7
|
+
Cerefox has two install paths since v0.4.0 (npm) and v0.5.0 (TS CLI). The right
|
|
8
|
+
upgrade procedure depends on how you installed Cerefox:
|
|
9
|
+
|
|
10
|
+
| You installed via | Upgrade with |
|
|
11
|
+
|---|---|
|
|
12
|
+
| **npm / Bun** (`@cerefox/memory` global) | `bun update -g @cerefox/memory` (or `npm update -g @cerefox/memory`), then read [`migration-v0.5.md`](migration-v0.5.md) for any breaking-change notes per version. **`cerefox doctor`** verifies the install. |
|
|
13
|
+
| **Source checkout** (`git clone` + `uv sync`) | The "Standard Upgrade Checklist" below — Python deps, schema migrations, Edge Functions, frontend build, the works. |
|
|
14
|
+
| **Both** (you contribute AND have the npm bin globally) | Both flows. The two paths share the same Supabase + `.env`; just keep them updated in lockstep. |
|
|
15
|
+
|
|
16
|
+
> If you're upgrading from Python `cerefox` to the npm-installed TS CLI for the first
|
|
17
|
+
> time, [`migration-v0.5.md`](migration-v0.5.md) is the canonical guide — it covers
|
|
18
|
+
> `cerefox init`'s coexistence flow (`[c]opy` your existing `.env` to `~/.cerefox/.env`),
|
|
19
|
+
> the v0.5.2 soft-wrapper removal, and the v0.5.3 paths precedence change.
|
|
20
|
+
|
|
21
|
+
The rest of this document covers the **source checkout** path (Python + frontend + Edge
|
|
22
|
+
Functions). If you're an npm-installed user, you've already got everything you need.
|
|
23
|
+
|
|
24
|
+
## Standard Upgrade Checklist (source-checkout users)
|
|
6
25
|
|
|
7
26
|
Run these steps every time you pull a new version:
|
|
8
27
|
|
|
@@ -61,6 +80,30 @@ open http://localhost:8000/app/
|
|
|
61
80
|
|
|
62
81
|
Most upgrades require no special steps beyond the standard checklist above. Notes below only apply when upgrading across specific version boundaries.
|
|
63
82
|
|
|
83
|
+
### Upgrading to v0.5.x (from any v0.4.x or earlier)
|
|
84
|
+
|
|
85
|
+
The v0.4 → v0.5 transition is a milestone — the CLI itself moved from Python
|
|
86
|
+
to TypeScript. The full migration guide is [`migration-v0.5.md`](migration-v0.5.md);
|
|
87
|
+
the short version for source-checkout users is:
|
|
88
|
+
|
|
89
|
+
- The Python `cerefox` CLI **still works** through v0.7.x — `uv sync` is enough
|
|
90
|
+
to pull it. It prints a one-line ⚠ deprecation banner on every invocation.
|
|
91
|
+
- The new npm CLI lives alongside: `bun install -g @cerefox/memory` (or
|
|
92
|
+
`npm install -g @cerefox/memory`). `cerefox doctor` from any directory will
|
|
93
|
+
verify it.
|
|
94
|
+
- **v0.5.2** stripped the Python `cerefox mcp` soft-wrapper. If your MCP
|
|
95
|
+
client config uses `uv run --directory /path/to/cerefox cerefox mcp`,
|
|
96
|
+
nothing changes — that path runs the Python MCP server directly. If you
|
|
97
|
+
want the TS server instead, point your client at `cerefox mcp`
|
|
98
|
+
(npm-installed) or `npx -y --package=@cerefox/memory cerefox mcp`.
|
|
99
|
+
- **v0.5.3** changed the TS CLI's `.env` precedence: `~/.cerefox/.env` now
|
|
100
|
+
wins over `<repo>/.env` when both exist. Your existing `<repo>/.env` keeps
|
|
101
|
+
working until you run `cerefox init` and pick the `[c]opy` migration
|
|
102
|
+
option. Python `paths.py` is unchanged.
|
|
103
|
+
|
|
104
|
+
No schema migration, no Edge Function redeploy, no chunk reindex required
|
|
105
|
+
for the v0.4 → v0.5.3 arc.
|
|
106
|
+
|
|
64
107
|
### Upgrading to v0.1.20 (from v0.1.19) -- Multi-Project Preservation Fix
|
|
65
108
|
|
|
66
109
|
**Edge Function redeploy is required.** v0.1.20 fixes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cerefox/memory",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.3",
|
|
4
4
|
"description": "Cerefox — user-owned shared memory for AI agents. The local TypeScript runtime: stdio MCP server in v0.4; CLI binary added in v0.5; in-process web server in v0.6; ingestion pipeline in v0.7.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://github.com/fstamatelopoulos/cerefox",
|