@cerefox/memory 0.5.3 → 0.5.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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.3";
7182
+ var PKG_VERSION = "0.5.4";
7183
7183
  var init_meta = () => {};
7184
7184
 
7185
7185
  // ../../node_modules/.bun/tslib@2.8.1/node_modules/tslib/tslib.js
@@ -24737,7 +24737,7 @@ __export(exports_sync_self_docs, {
24737
24737
  runSyncSelfDocs: () => runSyncSelfDocs,
24738
24738
  registerSyncSelfDocs: () => registerSyncSelfDocs
24739
24739
  });
24740
- import { readFileSync as readFileSync6 } from "node:fs";
24740
+ import { readFileSync as readFileSync7 } from "node:fs";
24741
24741
  import { basename as basename3, extname as extname3 } from "node:path";
24742
24742
  async function runSyncSelfDocs(options = {}) {
24743
24743
  const project = options.project ?? "_cerefox-self-docs";
@@ -24764,7 +24764,7 @@ async function runSyncSelfDocs(options = {}) {
24764
24764
  const authorType = resolveAuthorType("agent");
24765
24765
  const outcomes = [];
24766
24766
  for (const doc of docs) {
24767
- const content = readFileSync6(doc.path, "utf8");
24767
+ const content = readFileSync7(doc.path, "utf8");
24768
24768
  const m = content.match(/^#\s+(.+)$/m);
24769
24769
  const title = m ? m[1].trim() : basename3(doc.path, extname3(doc.path));
24770
24770
  try {
@@ -38144,17 +38144,24 @@ function registerConfigSet(program2) {
38144
38144
  init_cli_core();
38145
38145
 
38146
38146
  // src/cli/util/mcp-config-writers.ts
38147
- import { copyFileSync, existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "node:fs";
38147
+ import {
38148
+ copyFileSync,
38149
+ existsSync as existsSync3,
38150
+ mkdirSync as mkdirSync2,
38151
+ readFileSync as readFileSync2,
38152
+ writeFileSync as writeFileSync2
38153
+ } from "node:fs";
38148
38154
  import { homedir as homedir3, platform } from "node:os";
38149
38155
  import { dirname, join as join3 } from "node:path";
38156
+ import { spawnSync } from "node:child_process";
38150
38157
  function defaultCerefoxEntry() {
38151
38158
  return {
38152
38159
  command: "npx",
38153
38160
  args: ["-y", "--package=@cerefox/memory", "cerefox", "mcp"]
38154
38161
  };
38155
38162
  }
38156
- function claudeCodeConfigPath() {
38157
- return join3(homedir3(), ".claude", "mcp.json");
38163
+ function claudeCodeUserConfigPath() {
38164
+ return join3(homedir3(), ".claude.json");
38158
38165
  }
38159
38166
  function claudeDesktopConfigPath() {
38160
38167
  const home = homedir3();
@@ -38166,22 +38173,40 @@ function claudeDesktopConfigPath() {
38166
38173
  }
38167
38174
  return join3(home, ".config", "Claude", "claude_desktop_config.json");
38168
38175
  }
38176
+ function claudeCodeDelegated() {
38177
+ const entry = defaultCerefoxEntry();
38178
+ return {
38179
+ cmd: "claude",
38180
+ args: ["mcp", "add", "cerefox", "--scope", "user", "--", entry.command, ...entry.args]
38181
+ };
38182
+ }
38169
38183
  var WRITERS = {
38170
38184
  "claude-code": {
38171
38185
  id: "claude-code",
38172
38186
  label: "Claude Code",
38173
- configPath: claudeCodeConfigPath(),
38174
- buildServerEntry: defaultCerefoxEntry
38187
+ kind: "delegated",
38188
+ configPath: claudeCodeUserConfigPath(),
38189
+ buildServerEntry: defaultCerefoxEntry,
38190
+ delegated: claudeCodeDelegated
38175
38191
  },
38176
38192
  "claude-desktop": {
38177
38193
  id: "claude-desktop",
38178
38194
  label: "Claude Desktop",
38195
+ kind: "direct-write",
38179
38196
  configPath: claudeDesktopConfigPath(),
38180
38197
  buildServerEntry: defaultCerefoxEntry
38181
38198
  }
38182
38199
  };
38183
38200
  function writeMcpConfig(writer, opts = {}) {
38184
- const configPath = opts.customPath ?? writer.configPath;
38201
+ if (opts.customPath) {
38202
+ return directWrite({ ...writer, kind: "direct-write" }, opts.customPath, opts);
38203
+ }
38204
+ if (writer.kind === "delegated") {
38205
+ return delegatedWrite(writer, opts);
38206
+ }
38207
+ return directWrite(writer, writer.configPath, opts);
38208
+ }
38209
+ function directWrite(writer, configPath, opts) {
38185
38210
  const entry = writer.buildServerEntry();
38186
38211
  if (!opts.dryRun)
38187
38212
  mkdirSync2(dirname(configPath), { recursive: true });
@@ -38209,6 +38234,46 @@ function writeMcpConfig(writer, opts = {}) {
38209
38234
  }
38210
38235
  return { configPath, backupPath, action: action5, serverEntry: entry };
38211
38236
  }
38237
+ function delegatedWrite(writer, opts) {
38238
+ if (!writer.delegated) {
38239
+ throw new Error(`${writer.label}: kind=delegated but no delegated() factory`);
38240
+ }
38241
+ const { cmd, args } = writer.delegated();
38242
+ const entry = writer.buildServerEntry();
38243
+ const delegatedCommand = `${cmd} ${args.join(" ")}`;
38244
+ if (opts.dryRun) {
38245
+ return {
38246
+ configPath: writer.configPath,
38247
+ backupPath: null,
38248
+ action: "delegated",
38249
+ serverEntry: entry,
38250
+ delegatedCommand
38251
+ };
38252
+ }
38253
+ let backupPath = null;
38254
+ if (!opts.noBackup && existsSync3(writer.configPath)) {
38255
+ backupPath = writer.configPath + ".pre-cerefox.bak";
38256
+ copyFileSync(writer.configPath, backupPath);
38257
+ }
38258
+ const result = spawnSync(cmd, args, { stdio: "inherit" });
38259
+ if (result.error) {
38260
+ const err = result.error;
38261
+ if (err.code === "ENOENT") {
38262
+ throw new Error(`${writer.label}: \`${cmd}\` not found on PATH. ` + `Install ${writer.label} (https://docs.claude.com/en/docs/claude-code) ` + `and re-run \`cerefox configure-agent --tool ${writer.id}\`.`);
38263
+ }
38264
+ throw new Error(`${writer.label}: failed to spawn \`${cmd}\`: ${err.message}`);
38265
+ }
38266
+ if (result.status !== 0) {
38267
+ throw new Error(`${writer.label}: \`${delegatedCommand}\` exited with status ${result.status ?? "unknown"}. ` + `Check the output above; you may need to update or re-authenticate ${writer.label}.`);
38268
+ }
38269
+ return {
38270
+ configPath: writer.configPath,
38271
+ backupPath,
38272
+ action: "delegated",
38273
+ serverEntry: entry,
38274
+ delegatedCommand
38275
+ };
38276
+ }
38212
38277
 
38213
38278
  // src/cli/commands/configure-agent.ts
38214
38279
  function action5(options) {
@@ -38235,12 +38300,15 @@ function action5(options) {
38235
38300
  println(c.dim(` backup: ${result.backupPath}`));
38236
38301
  }
38237
38302
  println(c.dim(` action: ${result.action}`));
38303
+ if (result.delegatedCommand) {
38304
+ println(c.dim(` invoked: ${result.delegatedCommand}`));
38305
+ }
38238
38306
  println("");
38239
38307
  println(c.bold("Server entry written:"));
38240
38308
  println(JSON.stringify(result.serverEntry, null, 2));
38241
38309
  if (!options.dryRun) {
38242
38310
  println("");
38243
- println(c.dim(writer.id === "claude-desktop" ? "Restart Claude Desktop fully (Cmd+Q on macOS) to pick up the new server." : "Reload your Claude Code session to pick up the new server."));
38311
+ println(c.dim(writer.id === "claude-desktop" ? "Restart Claude Desktop fully (Cmd+Q on macOS) to pick up the new server." : "Start a new Claude Code session to pick up the new server " + "(running sessions cache MCP server lists at startup)."));
38244
38312
  }
38245
38313
  }
38246
38314
  function registerConfigureAgent(program2) {
@@ -38295,10 +38363,10 @@ function registerDeleteDoc(program2) {
38295
38363
  // src/cli/commands/docs.ts
38296
38364
  init_cli_core();
38297
38365
  init_bundled_docs();
38298
- import { spawnSync } from "node:child_process";
38366
+ import { spawnSync as spawnSync2 } from "node:child_process";
38299
38367
  function openInBrowser(path) {
38300
38368
  const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
38301
- const result = spawnSync(cmd, [path], { stdio: "ignore" });
38369
+ const result = spawnSync2(cmd, [path], { stdio: "ignore" });
38302
38370
  if (result.status !== 0) {
38303
38371
  println(c.dim(`(could not auto-open; the file is at: ${path})`));
38304
38372
  }
@@ -38342,7 +38410,7 @@ init_cli_core();
38342
38410
  init_meta();
38343
38411
  init_config();
38344
38412
  init_config();
38345
- import { existsSync as existsSync5, realpathSync, statSync as statSync2 } from "node:fs";
38413
+ import { existsSync as existsSync5, readFileSync as readFileSync4, realpathSync, statSync as statSync2 } from "node:fs";
38346
38414
  import { homedir as homedir4 } from "node:os";
38347
38415
  import { join as join5 } from "node:path";
38348
38416
  function checkBinary() {
@@ -38561,29 +38629,41 @@ async function checkSchemaVersion() {
38561
38629
  };
38562
38630
  }
38563
38631
  }
38632
+ function hasCerefoxInJsonFile(path) {
38633
+ if (!existsSync5(path))
38634
+ return false;
38635
+ try {
38636
+ const parsed = JSON.parse(readFileSync4(path, "utf8"));
38637
+ const mcpServers = parsed.mcpServers;
38638
+ return Boolean(mcpServers && typeof mcpServers === "object" && "cerefox" in mcpServers);
38639
+ } catch {
38640
+ return false;
38641
+ }
38642
+ }
38564
38643
  function checkMcpConfigs() {
38565
38644
  const home = homedir4();
38566
- const candidates = [
38567
- { label: "Claude Code (user)", path: join5(home, ".claude", "mcp.json") },
38568
- { label: "Claude Code (proj)", path: join5(process.cwd(), ".mcp.json") },
38569
- {
38570
- label: "Claude Desktop",
38571
- path: process.platform === "darwin" ? join5(home, "Library", "Application Support", "Claude", "claude_desktop_config.json") : process.platform === "win32" ? join5(process.env.APPDATA ?? "", "Claude", "claude_desktop_config.json") : join5(home, ".config", "Claude", "claude_desktop_config.json")
38572
- }
38573
- ];
38574
- const found = candidates.filter((c2) => existsSync5(c2.path));
38645
+ const claudeCodeUser = join5(home, ".claude.json");
38646
+ const claudeCodeProj = join5(process.cwd(), ".mcp.json");
38647
+ const claudeDesktop = process.platform === "darwin" ? join5(home, "Library", "Application Support", "Claude", "claude_desktop_config.json") : process.platform === "win32" ? join5(process.env.APPDATA ?? "", "Claude", "claude_desktop_config.json") : join5(home, ".config", "Claude", "claude_desktop_config.json");
38648
+ const found = [];
38649
+ if (hasCerefoxInJsonFile(claudeCodeUser))
38650
+ found.push("Claude Code (user)");
38651
+ if (hasCerefoxInJsonFile(claudeCodeProj))
38652
+ found.push("Claude Code (proj)");
38653
+ if (hasCerefoxInJsonFile(claudeDesktop))
38654
+ found.push("Claude Desktop");
38575
38655
  if (found.length === 0) {
38576
38656
  return {
38577
38657
  name: "mcp clients",
38578
38658
  status: "warn",
38579
- detail: "No MCP client configs detected.",
38580
- hint: "Run `cerefox configure-agent --tool claude-code` to wire up Claude Code."
38659
+ detail: "No MCP client configs reference Cerefox.",
38660
+ hint: "Run `cerefox configure-agent --tool claude-code` (or `--tool claude-desktop`) to wire up a client."
38581
38661
  };
38582
38662
  }
38583
38663
  return {
38584
38664
  name: "mcp clients",
38585
38665
  status: "ok",
38586
- detail: found.map((f) => f.label).join(", ")
38666
+ detail: found.join(", ")
38587
38667
  };
38588
38668
  }
38589
38669
  function checkLegacyShadowEnv() {
@@ -38766,7 +38846,7 @@ init_cli_core();
38766
38846
  init_mcp_tools();
38767
38847
  init_config();
38768
38848
  init_client();
38769
- import { readFileSync as readFileSync4 } from "node:fs";
38849
+ import { readFileSync as readFileSync5 } from "node:fs";
38770
38850
  import { basename, extname } from "node:path";
38771
38851
  async function readContent(path, paste) {
38772
38852
  if (paste) {
@@ -38788,7 +38868,7 @@ async function readContent(path, paste) {
38788
38868
  }
38789
38869
  let content;
38790
38870
  try {
38791
- content = readFileSync4(path, "utf8");
38871
+ content = readFileSync5(path, "utf8");
38792
38872
  } catch (err) {
38793
38873
  const msg = err instanceof Error ? err.message : String(err);
38794
38874
  throw userError(`Cannot read ${path}: ${msg}`);
@@ -38853,7 +38933,7 @@ init_mcp_tools();
38853
38933
  init_config();
38854
38934
  init_client();
38855
38935
  var import_cli_progress = __toESM(require_cli_progress(), 1);
38856
- import { readFileSync as readFileSync5, readdirSync as readdirSync2, statSync as statSync3 } from "node:fs";
38936
+ import { readFileSync as readFileSync6, readdirSync as readdirSync2, statSync as statSync3 } from "node:fs";
38857
38937
  import { basename as basename2, extname as extname2, join as join6 } from "node:path";
38858
38938
  function walk(dir, extensions) {
38859
38939
  let entries;
@@ -38909,7 +38989,7 @@ async function action12(dir, options) {
38909
38989
  bar?.update({ file: basename2(file) });
38910
38990
  let content;
38911
38991
  try {
38912
- content = readFileSync5(file, "utf8");
38992
+ content = readFileSync6(file, "utf8");
38913
38993
  } catch (err) {
38914
38994
  outcomes.push({ file, status: "error", detail: `read failed: ${err instanceof Error ? err.message : String(err)}` });
38915
38995
  bar?.increment();
@@ -38969,7 +39049,7 @@ import {
38969
39049
  copyFileSync as copyFileSync2,
38970
39050
  existsSync as existsSync6,
38971
39051
  mkdirSync as mkdirSync3,
38972
- readFileSync as readFileSync7,
39052
+ readFileSync as readFileSync8,
38973
39053
  writeFileSync as writeFileSync3
38974
39054
  } from "node:fs";
38975
39055
  import { homedir as homedir5 } from "node:os";
@@ -38980,7 +39060,7 @@ async function readConfigFile(path) {
38980
39060
  }
38981
39061
  let parsed;
38982
39062
  try {
38983
- parsed = JSON.parse(readFileSync7(path, "utf8"));
39063
+ parsed = JSON.parse(readFileSync8(path, "utf8"));
38984
39064
  } catch (err) {
38985
39065
  throw userError(`--config: invalid JSON in ${path}: ${err instanceof Error ? err.message : String(err)}`);
38986
39066
  }
@@ -39022,7 +39102,7 @@ function parseDotEnvFile(content) {
39022
39102
  return map;
39023
39103
  }
39024
39104
  function answersFromEnvFile(path) {
39025
- const parsed = parseDotEnvFile(readFileSync7(path, "utf8"));
39105
+ const parsed = parseDotEnvFile(readFileSync8(path, "utf8"));
39026
39106
  const required = ["CEREFOX_SUPABASE_URL", "CEREFOX_SUPABASE_KEY", "OPENAI_API_KEY"];
39027
39107
  for (const key of required) {
39028
39108
  if (!parsed[key] || parsed[key].trim() === "") {
@@ -39624,7 +39704,7 @@ function registerReindex(program2) {
39624
39704
  // src/cli/commands/restore.ts
39625
39705
  init_cli_core();
39626
39706
  init_client();
39627
- import { existsSync as existsSync7, readFileSync as readFileSync8, readdirSync as readdirSync3, statSync as statSync4 } from "node:fs";
39707
+ import { existsSync as existsSync7, readFileSync as readFileSync9, readdirSync as readdirSync3, statSync as statSync4 } from "node:fs";
39628
39708
  import { homedir as homedir6 } from "node:os";
39629
39709
  import { join as join8, resolve as resolve3 } from "node:path";
39630
39710
  function expandHome2(path) {
@@ -39652,7 +39732,7 @@ async function action20(target, options) {
39652
39732
  const file = resolveBackupFile(target);
39653
39733
  let payload;
39654
39734
  try {
39655
- payload = JSON.parse(readFileSync8(file, "utf8"));
39735
+ payload = JSON.parse(readFileSync9(file, "utf8"));
39656
39736
  } catch (err) {
39657
39737
  throw userError(`Could not parse backup file ${file}: ${err instanceof Error ? err.message : String(err)}`);
39658
39738
  }
@@ -39869,7 +39949,7 @@ function registerSearch(program2) {
39869
39949
  // src/cli/commands/self-update.ts
39870
39950
  init_cli_core();
39871
39951
  init_meta();
39872
- import { spawnSync as spawnSync2 } from "node:child_process";
39952
+ import { spawnSync as spawnSync3 } from "node:child_process";
39873
39953
  function detectRuntime() {
39874
39954
  const bin = (process.argv[1] ?? "").toLowerCase();
39875
39955
  if (bin.includes(".bun") || bin.includes("/bun/")) {
@@ -39942,7 +40022,7 @@ async function action22(options) {
39942
40022
  return;
39943
40023
  }
39944
40024
  }
39945
- const result = spawnSync2(runtime.command, runtime.args(target), {
40025
+ const result = spawnSync3(runtime.command, runtime.args(target), {
39946
40026
  stdio: "inherit"
39947
40027
  });
39948
40028
  if (result.status !== 0) {
@@ -40009,7 +40089,7 @@ init_config();
40009
40089
  init_client();
40010
40090
  import {
40011
40091
  existsSync as existsSync8,
40012
- readFileSync as readFileSync9,
40092
+ readFileSync as readFileSync10,
40013
40093
  readdirSync as readdirSync4,
40014
40094
  statSync as statSync5
40015
40095
  } from "node:fs";
@@ -40068,7 +40148,7 @@ async function action24(options) {
40068
40148
  const authorType = resolveAuthorType("agent");
40069
40149
  const outcomes = [];
40070
40150
  for (const t of targets) {
40071
- const content = readFileSync9(t.abs, "utf8");
40151
+ const content = readFileSync10(t.abs, "utf8");
40072
40152
  const title = basename4(t.abs, extname4(t.abs));
40073
40153
  try {
40074
40154
  const message = await ingestTool.handler(client.raw, {
@@ -11,8 +11,9 @@ v0.5.3), and the Python `cerefox` → TS `cerefox` migration path.
11
11
  | Never used Cerefox before | [`quickstart.md`](quickstart.md) first, then come back here only if you hit a `.env` / config question |
12
12
  | Python `cerefox` (any version through v0.5.x) | "What changed" → "Install paths" → "v0.5.3 migrated `.env`" sections below |
13
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 |
14
+ | `@cerefox/memory` v0.5.0 or v0.5.1 (npm) | "v0.5.2 fixed the soft wrapper" + "v0.5.3 migrated `.env`" + "v0.5.4 fixed configure-agent claude-code" |
15
+ | `@cerefox/memory` v0.5.2 (npm) | "v0.5.3 migrated `.env`" + "v0.5.4 fixed configure-agent claude-code" |
16
+ | `@cerefox/memory` v0.5.3 (npm) | **"v0.5.4 fixed configure-agent claude-code"** — re-run configure-agent |
16
17
 
17
18
  > Looking for `migration-v0.4.md`? It's been demoted to a historical
18
19
  > record (the bin names it documents no longer exist). Everything you
@@ -272,6 +273,64 @@ and skips the migration prompt.
272
273
 
273
274
  ---
274
275
 
276
+ ## v0.5.4 fixed `cerefox configure-agent --tool claude-code`
277
+
278
+ **If you ran `cerefox configure-agent --tool claude-code` on any version
279
+ from v0.5.0 through v0.5.3, Claude Code did not actually pick up the
280
+ config.** The writer wrote to `~/.claude/mcp.json` — a path Claude Code
281
+ doesn't read. Claude Code's user-scope MCP servers live in
282
+ **`~/.claude.json`** (a dot-file in `$HOME`) under the `.mcpServers` key.
283
+
284
+ The bug went unnoticed because `cerefox doctor` was scanning the same
285
+ wrong path — both surfaces were consistently lying.
286
+
287
+ ### What v0.5.4 changed
288
+
289
+ - **`configure-agent --tool claude-code`** now shells out to Claude Code's
290
+ own `claude mcp add --scope user` CLI. Claude Code manages its own
291
+ config schema; delegating is future-proof. Requires the `claude` CLI
292
+ on PATH (fair assumption — you're configuring it).
293
+ - Before invoking the delegated CLI, the writer takes a defensive backup
294
+ of `~/.claude.json` to `~/.claude.json.pre-cerefox.bak`.
295
+ - **`cerefox doctor`** now scans `~/.claude.json` for a `mcpServers.cerefox`
296
+ entry (not the orphaned `~/.claude/mcp.json` from the bug window).
297
+ - **`--tool claude-desktop` is unchanged** — Claude Desktop has no CLI
298
+ helper, so its writer remains direct-file-write.
299
+
300
+ ### What you need to do
301
+
302
+ Anyone who ran `configure-agent --tool claude-code` on v0.5.0–v0.5.3:
303
+
304
+ ```bash
305
+ # 1. Upgrade
306
+ bun update -g @cerefox/memory # or: npm update -g @cerefox/memory
307
+
308
+ # 2. (Optional) Remove the orphaned file the buggy versions wrote.
309
+ # It does nothing — Claude Code never read it. Safe to delete.
310
+ rm -f ~/.claude/mcp.json
311
+
312
+ # 3. Re-run configure-agent to write the config at the correct path.
313
+ cerefox configure-agent --tool claude-code
314
+
315
+ # 4. Verify
316
+ claude mcp list # should now show 'cerefox'
317
+ cerefox doctor # 'mcp clients' should list 'Claude Code (user)'
318
+
319
+ # 5. Start a fresh Claude Code session — the cerefox tools appear.
320
+ ```
321
+
322
+ Running sessions cache the MCP server list at startup, so an
323
+ **already-open Claude Code session won't pick up the new server**.
324
+ Open a new session.
325
+
326
+ ### `--config-path FILE` override (advanced)
327
+
328
+ If you pass `--config-path FILE` explicitly, configure-agent does a
329
+ direct-write to FILE instead of shelling out — preserves the v0.5.0–v0.5.3
330
+ test path and works for power users who want a specific file location.
331
+
332
+ ---
333
+
275
334
  ## Known gotchas
276
335
 
277
336
  ### `npx` from inside an npm workspace
@@ -4,9 +4,70 @@ Get Cerefox running locally and ingest your first document.
4
4
 
5
5
  > **Upgrading from a previous version?** See the [Upgrading Guide](upgrading.md) for migration steps instead.
6
6
 
7
+ ## Two install paths
8
+
9
+ | You want | Read this section | Why |
10
+ |---|---|---|
11
+ | **Use Cerefox as an MCP server / CLI** | "Path A — npm install" below (fastest) | One install, callable from any directory. No Python needed. Recommended for end users since v0.5. |
12
+ | **Contribute to Cerefox, run the web UI, deploy schema** | "Path B — source checkout" below | Full source: schema deploy, web UI, ingestion pipeline. Required for contributors and for the web UI (until v0.6). |
13
+
14
+ You'll need a Supabase project (free tier works) and an OpenAI API key for either
15
+ path — those go into `.env`. The npm install asks for them interactively via
16
+ `cerefox init`; the source checkout has you write them into a `.env` file
17
+ yourself.
18
+
19
+ ---
20
+
21
+ ## Path A — npm install (fastest, 5 min total)
22
+
23
+ For end users who just want the Cerefox CLI + MCP server on their machine.
24
+
25
+ ### A.1 Prerequisites
26
+ - Node.js 20+ (`node --version`) or Bun 1.0+ (`bun --version`)
27
+ - A Supabase account -- [supabase.com](https://supabase.com) (free tier works)
28
+ - An OpenAI API key -- [platform.openai.com/api-keys](https://platform.openai.com/api-keys)
29
+ - **Schema must be deployed** to your Supabase. Until v0.6 ports the schema
30
+ deploy to TypeScript, this still requires the source checkout (Path B) once,
31
+ or someone else who has the source checkout to deploy it for you.
32
+
33
+ ### A.2 Install
34
+ ```bash
35
+ # One-line install (detects Bun or installs it, falls back to npm):
36
+ curl -fsSL https://github.com/fstamatelopoulos/cerefox/releases/latest/download/install.sh | sh
37
+
38
+ # Or direct:
39
+ bun add -g @cerefox/memory # preferred
40
+ # npm install -g @cerefox/memory # alternative
41
+ ```
42
+
43
+ ### A.3 First-run setup
44
+ ```bash
45
+ cerefox init # 5-step interactive setup
46
+ cerefox doctor # verify the install
47
+ ```
48
+
49
+ ### A.4 Wire up your MCP client
50
+ ```bash
51
+ # Run the ones that apply:
52
+ cerefox configure-agent --tool claude-code
53
+ cerefox configure-agent --tool claude-desktop
54
+ ```
55
+
56
+ `--tool claude-code` shells out to Claude Code's own `claude mcp add --scope user`
57
+ to register the server (Claude Code knows where to store the config).
58
+ `--tool claude-desktop` writes the JSON config file directly.
59
+
60
+ Then restart your MCP client. **Path A users skip ahead to "[Connect an AI agent](#8-connect-an-ai-agent-optional-5-min)" (step 8) for the verification prompt.** Steps 3–7
61
+ below are Path B-only (setting up `.env` by hand, deploying the schema, the web UI).
62
+
7
63
  ---
8
64
 
9
- ## 1. Prerequisites (2 min)
65
+ ## Path B — source checkout (contributors, schema deploy, web UI)
66
+
67
+ For anyone hacking on Cerefox itself, deploying the schema for the first time,
68
+ or running the web UI.
69
+
70
+ ### B.1 Prerequisites
10
71
 
11
72
  - Python 3.11+ (`python3 --version`)
12
73
  - Node.js 18+ and npm (`node --version`)
@@ -14,9 +75,7 @@ Get Cerefox running locally and ingest your first document.
14
75
  - A Supabase account -- [supabase.com](https://supabase.com) (free tier works)
15
76
  - An OpenAI API key -- [platform.openai.com/api-keys](https://platform.openai.com/api-keys)
16
77
 
17
- ---
18
-
19
- ## 2. Install Cerefox (2 min)
78
+ ### B.2 Install Cerefox (2 min)
20
79
 
21
80
  ```bash
22
81
  git clone https://github.com/fstamatelopoulos/cerefox.git
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cerefox/memory",
3
- "version": "0.5.3",
3
+ "version": "0.5.4",
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",