@cerefox/memory 0.9.0 → 0.9.1

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.
@@ -7184,7 +7184,7 @@ var exports_meta = {};
7184
7184
  __export(exports_meta, {
7185
7185
  PKG_VERSION: () => PKG_VERSION
7186
7186
  });
7187
- var PKG_VERSION = "0.9.0";
7187
+ var PKG_VERSION = "0.9.1";
7188
7188
  var init_meta = () => {};
7189
7189
 
7190
7190
  // ../../node_modules/.bun/tslib@2.8.1/node_modules/tslib/tslib.js
@@ -24628,16 +24628,16 @@ var init_src = __esm(() => {
24628
24628
  });
24629
24629
 
24630
24630
  // src/cli/util/bundled-docs.ts
24631
- import { existsSync as existsSync7, readdirSync as readdirSync3, readFileSync as readFileSync5, statSync } from "node:fs";
24632
- import { dirname as dirname3, join as join6, resolve as resolve2 } from "node:path";
24631
+ import { existsSync as existsSync8, readdirSync as readdirSync3, readFileSync as readFileSync6, statSync } from "node:fs";
24632
+ import { dirname as dirname3, join as join7, resolve as resolve2 } from "node:path";
24633
24633
  import { fileURLToPath as fileURLToPath2 } from "node:url";
24634
24634
  function findPackageRoot() {
24635
24635
  let dir = dirname3(fileURLToPath2(import.meta.url));
24636
24636
  for (let i = 0;i < 10; i++) {
24637
- const pkgJson = join6(dir, "package.json");
24638
- if (existsSync7(pkgJson)) {
24637
+ const pkgJson = join7(dir, "package.json");
24638
+ if (existsSync8(pkgJson)) {
24639
24639
  try {
24640
- const parsed = JSON.parse(readFileSync5(pkgJson, "utf8"));
24640
+ const parsed = JSON.parse(readFileSync6(pkgJson, "utf8"));
24641
24641
  if (parsed.name === "@cerefox/memory")
24642
24642
  return dir;
24643
24643
  } catch {}
@@ -24650,40 +24650,40 @@ function findPackageRoot() {
24650
24650
  return resolve2(dirname3(fileURLToPath2(import.meta.url)), "..", "..", "..");
24651
24651
  }
24652
24652
  function bundledDocsDir() {
24653
- const inPackage = join6(PACKAGE_ROOT, "docs");
24654
- if (existsSync7(inPackage))
24653
+ const inPackage = join7(PACKAGE_ROOT, "docs");
24654
+ if (existsSync8(inPackage))
24655
24655
  return inPackage;
24656
24656
  return resolve2(PACKAGE_ROOT, "..", "..", "docs");
24657
24657
  }
24658
24658
  function agentGuidePath() {
24659
24659
  const candidates = [
24660
- join6(PACKAGE_ROOT, "AGENT_GUIDE.md"),
24660
+ join7(PACKAGE_ROOT, "AGENT_GUIDE.md"),
24661
24661
  resolve2(PACKAGE_ROOT, "..", "..", "AGENT_GUIDE.md")
24662
24662
  ];
24663
24663
  for (const c2 of candidates)
24664
- if (existsSync7(c2))
24664
+ if (existsSync8(c2))
24665
24665
  return c2;
24666
24666
  return null;
24667
24667
  }
24668
24668
  function agentQuickReferencePath() {
24669
24669
  const candidates = [
24670
- join6(PACKAGE_ROOT, "AGENT_QUICK_REFERENCE.md"),
24670
+ join7(PACKAGE_ROOT, "AGENT_QUICK_REFERENCE.md"),
24671
24671
  resolve2(PACKAGE_ROOT, "..", "..", "AGENT_QUICK_REFERENCE.md")
24672
24672
  ];
24673
24673
  for (const c2 of candidates)
24674
- if (existsSync7(c2))
24674
+ if (existsSync8(c2))
24675
24675
  return c2;
24676
24676
  return null;
24677
24677
  }
24678
24678
  function listBundledDocs() {
24679
24679
  const entries = [];
24680
24680
  const docsDir = bundledDocsDir();
24681
- const guidesDir = join6(docsDir, "guides");
24682
- if (existsSync7(guidesDir) && statSync(guidesDir).isDirectory()) {
24681
+ const guidesDir = join7(docsDir, "guides");
24682
+ if (existsSync8(guidesDir) && statSync(guidesDir).isDirectory()) {
24683
24683
  for (const name of readdirSync3(guidesDir)) {
24684
24684
  if (!name.endsWith(".md"))
24685
24685
  continue;
24686
- const full = join6(guidesDir, name);
24686
+ const full = join7(guidesDir, name);
24687
24687
  entries.push({
24688
24688
  topic: name.replace(/\.md$/, ""),
24689
24689
  path: full,
@@ -24712,7 +24712,7 @@ function readBundledDoc(topic) {
24712
24712
  return {
24713
24713
  topic: entry.topic,
24714
24714
  path: entry.path,
24715
- content: readFileSync5(entry.path, "utf8")
24715
+ content: readFileSync6(entry.path, "utf8")
24716
24716
  };
24717
24717
  }
24718
24718
  var PACKAGE_ROOT;
@@ -25748,7 +25748,7 @@ var init_get_document = __esm(() => {
25748
25748
  });
25749
25749
 
25750
25750
  // ../../_shared/mcp-tools/get-help-content.ts
25751
- var HELP_FULL = '# Cerefox Knowledge Base -- Agent Quick Reference\n\nCerefox is a persistent, shared knowledge base. You have **10 MCP tools** (9 of them have CLI equivalents — `cerefox_get_help` is MCP-only). For the full guide, search Cerefox for "How AI Agents Use Cerefox" or call `cerefox_get_help` to retrieve this content over MCP.\n\n## Tools\n\n| Tool | Purpose | Key params |\n|------|---------|------------|\n| `cerefox_search` | Find documents (hybrid FTS + semantic) | `query` (required), `project_name`, `metadata_filter`, `requestor` |\n| `cerefox_ingest` | Save or update a document | `title`, `content` (required), `document_id` (update by ID), `update_if_exists`, `project_name` (single, non-destructive add on update), `project_names` (list, destructive replace on update), `metadata`, `author` |\n| `cerefox_get_document` | Get full document by ID | `document_id` (required) |\n| `cerefox_list_versions` | Version history of a document | `document_id` (required) |\n| `cerefox_metadata_search` | Find docs by metadata (no text query) | `metadata_filter` (required), `include_content`, `updated_since` |\n| `cerefox_list_metadata_keys` | Discover available metadata keys | (none required) |\n| `cerefox_list_projects` | List all projects | (none required) |\n| `cerefox_set_document_projects` | Set doc\'s project memberships to exactly the given list (destructive replace; metadata-only, no content change) | `document_id`, `project_names` (required) |\n| `cerefox_get_audit_log` | Query write operation history | `document_id`, `author`, `operation`, `since` |\n| `cerefox_get_help` | Retrieve Cerefox conventions (this reference) over MCP. **Call this whenever uncertain.** | `topic` (optional, case-insensitive H2 substring match) |\n\n## Essential Rules\n\n1. **Search before ingesting** -- check if the document exists first.\n2. **Prefer ID-based updates** -- pass `document_id` from search results for deterministic updates. Falls back to title-matching with `update_if_exists: true`.\n3. **Set `author`/`requestor`** to your name on every call (e.g., "Claude Code", "archiver"). On MCP, pass as parameters. On CLI, pass `--author`/`--author-type`/`--requestor` flags, or rely on `CEREFOX_AUTHOR_NAME`/`CEREFOX_AUTHOR_TYPE`/`CEREFOX_REQUESTOR_NAME` env vars set in the user\'s `.env`.\n4. **Use `document_id` from search results** `[id: uuid]` for get_document and list_versions.\n5. **Add metadata** -- at minimum `type` ("decision-log", "research", "design-doc") and `status` ("active", "draft").\n6. **Write structured Markdown** with H1/H2/H3 headings for good chunking and search.\n7. **Deletes are soft (recoverable); purge is web-UI-only.** If you decide to delete, surface it to the user (`I soft-deleted X — recoverable from the Cerefox web UI trash`). You cannot un-do your own delete from agent code by design.\n8. **Cross-doc links inside content**: **always use `[Text](document-uuid)`.** UUIDs are the only fully reliable link form — stable across title changes, never ambiguous, no encoding gotchas. Every `cerefox_search` result shows `[id: <uuid>]` after the title; grab it and use it. Title-based linking (`[Text](<Title With Spaces>)`) is fragile (breaks on colons, parens, ampersands, brackets — silently navigates to wrong page) — **don\'t write title-based links**; do an extra search to get the UUID instead. Repo-path forms (`[Text](docs/path.md)`) exist for repo-ingested files; don\'t construct manually. See `AGENT_GUIDE.md → Writing linkable content` for the full rule.\n9. **Project memberships — non-destructive by default**: on `cerefox_ingest` updates, **`project_name` (singular) is a non-destructive add** (ensures membership, preserves others). Use **`project_names` (list)** when you want to set the doc\'s full project set in one call (destructive replace). For metadata-only project changes without writing content, use **`cerefox_set_document_projects(document_id, project_names)`** — that tool is the destructive-replace contract made explicit. Never call `cerefox_set_document_projects` with a single name when you mean "add" — that would REMOVE the doc from all other projects. When in doubt, use `cerefox_ingest` with singular `project_name`.\n\n## Update Workflow (ID-based -- preferred)\n\n```\nsearch("topic") -> find doc [id: abc123] -> get_document(abc123) -> modify ->\ningest(title="Same Title", content="...", document_id="abc123", author="my-agent")\n```\n\n## Update Workflow (title-based -- fallback)\n\n```\nsearch("topic") -> find doc -> modify ->\ningest(title="Same Title", content="...", update_if_exists=true, author="my-agent")\n```\n\n## Catch-Up Workflow\n\n```\nmetadata_search(metadata_filter={"type": "decision-log"}, updated_since="2026-03-28T00:00:00Z")\n```\n\n## CLI fallback (when MCP is unavailable)\n\nIf `cerefox_search` is not in your tool list, your user has likely installed the Cerefox CLI. From v0.5+ the canonical invocation is plain **`cerefox <subcommand>`** (installed via `npm install -g @cerefox/memory`). The legacy `uv run cerefox <subcommand>` (Python CLI in a Cerefox checkout) still works through v0.7 but emits a deprecation banner.\n\nSame operations, same conventions. Full reference: [`docs/guides/cli.md`](docs/guides/cli.md). CLI flag names match MCP parameter names exactly (e.g. `metadata_filter` ↔ `--metadata-filter`); short forms (`--filter`, `--project`, `--count`, `--update`, `--version`) work as aliases.\n\n| MCP tool | CLI (v0.5+ canonical) |\n|---|---|\n| `cerefox_search` | `cerefox search "<q>" --requestor "<your-name>"` |\n| `cerefox_ingest` (paste) | `printf \'...\' \\| cerefox ingest --paste --title "<t>" --author "<your-name>" --author-type agent` |\n| `cerefox_ingest` (update by ID) | `printf \'...\' \\| cerefox ingest --paste --title "<t>" --document-id "<uuid>" --author "<your-name>" --author-type agent` |\n| `cerefox_get_document` | `cerefox get-doc <id> --version-id <vid> --requestor "<your-name>"` |\n| `cerefox_list_versions` | `cerefox list-versions <id> --requestor "<your-name>"` |\n| `cerefox_list_projects` | `cerefox list-projects --requestor "<your-name>"` |\n| `cerefox_list_metadata_keys` | `cerefox list-metadata-keys` |\n| `cerefox_metadata_search` | `cerefox metadata-search --metadata-filter \'<json>\' --requestor "<your-name>"` |\n| `cerefox_set_document_projects` | _MCP-only; a CLI command will be added in a future release. Until then, run via MCP if available._ |\n| `cerefox_get_audit_log` | `cerefox get-audit-log --requestor "<your-name>"` (add `--json` for scripted access) |\n| `cerefox_get_help` | `cerefox docs agent-quick-reference --print` (or `cerefox docs --list` for the full bundled-docs index) |\n\n**Set identity on every call**, exactly as you would on MCP:\n- Writes (`ingest`, `ingest-dir`): `--author "<your-name>" --author-type agent`\n- Reads: `--requestor "<your-name>"`\n\nOr have your user set `CEREFOX_AUTHOR_NAME` / `CEREFOX_AUTHOR_TYPE` / `CEREFOX_REQUESTOR_NAME` in their `.env` to apply defaults once.\n', HELP_SECTIONS, HELP_SECTION_HEADINGS;
25751
+ var HELP_FULL = '# Cerefox Knowledge Base -- Agent Quick Reference\n\nCerefox is a persistent, shared knowledge base. You have **10 MCP tools** (9 of them have CLI equivalents — `cerefox_get_help` is MCP-only). For the full guide, search Cerefox for "How AI Agents Use Cerefox" or call `cerefox_get_help` to retrieve this content over MCP.\n\n## Tools\n\n| Tool | Purpose | Key params |\n|------|---------|------------|\n| `cerefox_search` | Find documents (hybrid FTS + semantic) | `query` (required), `project_name`, `metadata_filter`, `requestor` |\n| `cerefox_ingest` | Save or update a document | `title`, `content` (required), `document_id` (update by ID), `update_if_exists`, `project_name` (single, non-destructive add on update), `project_names` (list, destructive replace on update), `metadata`, `author` |\n| `cerefox_get_document` | Get full document by ID | `document_id` (required) |\n| `cerefox_list_versions` | Version history of a document | `document_id` (required) |\n| `cerefox_metadata_search` | Find docs by metadata (no text query) | `metadata_filter` (required), `include_content`, `updated_since` |\n| `cerefox_list_metadata_keys` | Discover available metadata keys | (none required) |\n| `cerefox_list_projects` | List all projects | (none required) |\n| `cerefox_set_document_projects` | Set doc\'s project memberships to exactly the given list (destructive replace; metadata-only, no content change) | `document_id`, `project_names` (required) |\n| `cerefox_get_audit_log` | Query write operation history | `document_id`, `author`, `operation`, `since` |\n| `cerefox_get_help` | Retrieve Cerefox conventions (this reference) over MCP. **Call this whenever uncertain.** | `topic` (optional, case-insensitive H2 substring match) |\n\n## Essential Rules\n\n1. **Search before ingesting** -- check if the document exists first.\n2. **Prefer ID-based updates** -- pass `document_id` from search results for deterministic updates. Falls back to title-matching with `update_if_exists: true`.\n3. **Set `author`/`requestor`** to your name on every call (e.g., "Claude Code", "archiver"). On MCP, pass as parameters. On CLI, pass `--author`/`--author-type`/`--requestor` flags, or rely on `CEREFOX_AUTHOR_NAME`/`CEREFOX_AUTHOR_TYPE`/`CEREFOX_REQUESTOR_NAME` env vars set in the user\'s `.env`.\n4. **Use `document_id` from search results** `[id: uuid]` for get_document and list_versions.\n5. **Add metadata** -- at minimum `type` ("decision-log", "research", "design-doc") and `status` ("active", "draft").\n6. **Write structured Markdown** with H1/H2/H3 headings for good chunking and search.\n7. **Deletes are soft (recoverable); purge is web-UI-only.** If you decide to delete, surface it to the user (`I soft-deleted X — recoverable from the Cerefox web UI trash`). You cannot un-do your own delete from agent code by design.\n8. **Cross-doc links inside content**: **always use `[Text](document-uuid)`.** UUIDs are the only fully reliable link form — stable across title changes, never ambiguous, no encoding gotchas. Every `cerefox_search` result shows `[id: <uuid>]` after the title; grab it and use it. Title-based linking (`[Text](<Title With Spaces>)`) is fragile (breaks on colons, parens, ampersands, brackets — silently navigates to wrong page) — **don\'t write title-based links**; do an extra search to get the UUID instead. Repo-path forms (`[Text](docs/path.md)`) exist for repo-ingested files; don\'t construct manually. See `AGENT_GUIDE.md → Writing linkable content` for the full rule.\n9. **Project memberships — non-destructive by default**: on `cerefox_ingest` updates, **`project_name` (singular) is a non-destructive add** (ensures membership, preserves others). Use **`project_names` (list)** when you want to set the doc\'s full project set in one call (destructive replace). For metadata-only project changes without writing content, use **`cerefox_set_document_projects(document_id, project_names)`** — that tool is the destructive-replace contract made explicit. Never call `cerefox_set_document_projects` with a single name when you mean "add" — that would REMOVE the doc from all other projects. When in doubt, use `cerefox_ingest` with singular `project_name`.\n\n## Update Workflow (ID-based -- preferred)\n\n```\nsearch("topic") -> find doc [id: abc123] -> get_document(abc123) -> modify ->\ningest(title="Same Title", content="...", document_id="abc123", author="my-agent")\n```\n\n## Update Workflow (title-based -- fallback)\n\n```\nsearch("topic") -> find doc -> modify ->\ningest(title="Same Title", content="...", update_if_exists=true, author="my-agent")\n```\n\n## Catch-Up Workflow\n\n```\nmetadata_search(metadata_filter={"type": "decision-log"}, updated_since="2026-03-28T00:00:00Z")\n```\n\n## CLI fallback (when MCP is unavailable)\n\nIf `cerefox_search` is not in your tool list, your user has likely installed the Cerefox CLI. The canonical invocation is plain **`cerefox <subcommand>`** (the TypeScript CLI, installed via `npm install -g @cerefox/memory`). It uses a resource-verb shape (`cerefox document get`, `cerefox project list`, …). The legacy Python `uv run cerefox` is now a frozen husk as of v0.9 only `uv run cerefox mcp` still works.\n\nSame operations, same conventions. Full reference: [`docs/guides/cli.md`](docs/guides/cli.md). CLI flag names match MCP parameter names exactly (e.g. `metadata_filter` ↔ `--metadata-filter`); short forms (`--filter`, `--project`, `--count`, `--update`, `--version`) work as aliases.\n\n| MCP tool | CLI |\n|---|---|\n| `cerefox_search` | `cerefox search "<q>" --requestor "<your-name>"` |\n| `cerefox_ingest` (paste) | `printf \'...\' \\| cerefox document ingest --paste --title "<t>" --author "<your-name>" --author-type agent` |\n| `cerefox_ingest` (update by ID) | `printf \'...\' \\| cerefox document ingest --paste --title "<t>" --document-id "<uuid>" --author "<your-name>" --author-type agent` |\n| `cerefox_get_document` | `cerefox document get <id> --version-id <vid> --requestor "<your-name>"` |\n| `cerefox_list_versions` | `cerefox document version list <id> --requestor "<your-name>"` |\n| `cerefox_list_projects` | `cerefox project list --requestor "<your-name>"` |\n| `cerefox_list_metadata_keys` | `cerefox metadata keys` |\n| `cerefox_metadata_search` | `cerefox metadata search --metadata-filter \'<json>\' --requestor "<your-name>"` |\n| `cerefox_set_document_projects` | _MCP-only; a CLI command will be added in a future release. Until then, run via MCP if available._ |\n| `cerefox_get_audit_log` | `cerefox audit list --requestor "<your-name>"` (add `--json` for scripted access) |\n| `cerefox_get_help` | `cerefox guides show agent-quick-reference` (or `cerefox guides list` for the full bundled-docs index) |\n\n**Set identity on every call**, exactly as you would on MCP:\n- Writes (`document ingest`, `document ingest-dir`): `--author "<your-name>" --author-type agent`\n- Reads: `--requestor "<your-name>"`\n\nOr have your user set `CEREFOX_AUTHOR_NAME` / `CEREFOX_AUTHOR_TYPE` / `CEREFOX_REQUESTOR_NAME` in their `.env` to apply defaults once.\n', HELP_SECTIONS, HELP_SECTION_HEADINGS;
25752
25752
  var init_get_help_content = __esm(() => {
25753
25753
  HELP_SECTIONS = {
25754
25754
  Tools: "## Tools\n\n| Tool | Purpose | Key params |\n|------|---------|------------|\n| `cerefox_search` | Find documents (hybrid FTS + semantic) | `query` (required), `project_name`, `metadata_filter`, `requestor` |\n| `cerefox_ingest` | Save or update a document | `title`, `content` (required), `document_id` (update by ID), `update_if_exists`, `project_name` (single, non-destructive add on update), `project_names` (list, destructive replace on update), `metadata`, `author` |\n| `cerefox_get_document` | Get full document by ID | `document_id` (required) |\n| `cerefox_list_versions` | Version history of a document | `document_id` (required) |\n| `cerefox_metadata_search` | Find docs by metadata (no text query) | `metadata_filter` (required), `include_content`, `updated_since` |\n| `cerefox_list_metadata_keys` | Discover available metadata keys | (none required) |\n| `cerefox_list_projects` | List all projects | (none required) |\n| `cerefox_set_document_projects` | Set doc's project memberships to exactly the given list (destructive replace; metadata-only, no content change) | `document_id`, `project_names` (required) |\n| `cerefox_get_audit_log` | Query write operation history | `document_id`, `author`, `operation`, `since` |\n| `cerefox_get_help` | Retrieve Cerefox conventions (this reference) over MCP. **Call this whenever uncertain.** | `topic` (optional, case-insensitive H2 substring match) |",
@@ -25756,7 +25756,7 @@ var init_get_help_content = __esm(() => {
25756
25756
  "Update Workflow (ID-based -- preferred)": '## Update Workflow (ID-based -- preferred)\n\n```\nsearch("topic") -> find doc [id: abc123] -> get_document(abc123) -> modify ->\ningest(title="Same Title", content="...", document_id="abc123", author="my-agent")\n```',
25757
25757
  "Update Workflow (title-based -- fallback)": '## Update Workflow (title-based -- fallback)\n\n```\nsearch("topic") -> find doc -> modify ->\ningest(title="Same Title", content="...", update_if_exists=true, author="my-agent")\n```',
25758
25758
  "Catch-Up Workflow": '## Catch-Up Workflow\n\n```\nmetadata_search(metadata_filter={"type": "decision-log"}, updated_since="2026-03-28T00:00:00Z")\n```',
25759
- "CLI fallback (when MCP is unavailable)": '## CLI fallback (when MCP is unavailable)\n\nIf `cerefox_search` is not in your tool list, your user has likely installed the Cerefox CLI. From v0.5+ the canonical invocation is plain **`cerefox <subcommand>`** (installed via `npm install -g @cerefox/memory`). The legacy `uv run cerefox <subcommand>` (Python CLI in a Cerefox checkout) still works through v0.7 but emits a deprecation banner.\n\nSame operations, same conventions. Full reference: [`docs/guides/cli.md`](docs/guides/cli.md). CLI flag names match MCP parameter names exactly (e.g. `metadata_filter` ↔ `--metadata-filter`); short forms (`--filter`, `--project`, `--count`, `--update`, `--version`) work as aliases.\n\n| MCP tool | CLI (v0.5+ canonical) |\n|---|---|\n| `cerefox_search` | `cerefox search "<q>" --requestor "<your-name>"` |\n| `cerefox_ingest` (paste) | `printf \'...\' \\| cerefox ingest --paste --title "<t>" --author "<your-name>" --author-type agent` |\n| `cerefox_ingest` (update by ID) | `printf \'...\' \\| cerefox ingest --paste --title "<t>" --document-id "<uuid>" --author "<your-name>" --author-type agent` |\n| `cerefox_get_document` | `cerefox get-doc <id> --version-id <vid> --requestor "<your-name>"` |\n| `cerefox_list_versions` | `cerefox list-versions <id> --requestor "<your-name>"` |\n| `cerefox_list_projects` | `cerefox list-projects --requestor "<your-name>"` |\n| `cerefox_list_metadata_keys` | `cerefox list-metadata-keys` |\n| `cerefox_metadata_search` | `cerefox metadata-search --metadata-filter \'<json>\' --requestor "<your-name>"` |\n| `cerefox_set_document_projects` | _MCP-only; a CLI command will be added in a future release. Until then, run via MCP if available._ |\n| `cerefox_get_audit_log` | `cerefox get-audit-log --requestor "<your-name>"` (add `--json` for scripted access) |\n| `cerefox_get_help` | `cerefox docs agent-quick-reference --print` (or `cerefox docs --list` for the full bundled-docs index) |\n\n**Set identity on every call**, exactly as you would on MCP:\n- Writes (`ingest`, `ingest-dir`): `--author "<your-name>" --author-type agent`\n- Reads: `--requestor "<your-name>"`\n\nOr have your user set `CEREFOX_AUTHOR_NAME` / `CEREFOX_AUTHOR_TYPE` / `CEREFOX_REQUESTOR_NAME` in their `.env` to apply defaults once.'
25759
+ "CLI fallback (when MCP is unavailable)": '## CLI fallback (when MCP is unavailable)\n\nIf `cerefox_search` is not in your tool list, your user has likely installed the Cerefox CLI. The canonical invocation is plain **`cerefox <subcommand>`** (the TypeScript CLI, installed via `npm install -g @cerefox/memory`). It uses a resource-verb shape (`cerefox document get`, `cerefox project list`, …). The legacy Python `uv run cerefox` is now a frozen husk as of v0.9 only `uv run cerefox mcp` still works.\n\nSame operations, same conventions. Full reference: [`docs/guides/cli.md`](docs/guides/cli.md). CLI flag names match MCP parameter names exactly (e.g. `metadata_filter` ↔ `--metadata-filter`); short forms (`--filter`, `--project`, `--count`, `--update`, `--version`) work as aliases.\n\n| MCP tool | CLI |\n|---|---|\n| `cerefox_search` | `cerefox search "<q>" --requestor "<your-name>"` |\n| `cerefox_ingest` (paste) | `printf \'...\' \\| cerefox document ingest --paste --title "<t>" --author "<your-name>" --author-type agent` |\n| `cerefox_ingest` (update by ID) | `printf \'...\' \\| cerefox document ingest --paste --title "<t>" --document-id "<uuid>" --author "<your-name>" --author-type agent` |\n| `cerefox_get_document` | `cerefox document get <id> --version-id <vid> --requestor "<your-name>"` |\n| `cerefox_list_versions` | `cerefox document version list <id> --requestor "<your-name>"` |\n| `cerefox_list_projects` | `cerefox project list --requestor "<your-name>"` |\n| `cerefox_list_metadata_keys` | `cerefox metadata keys` |\n| `cerefox_metadata_search` | `cerefox metadata search --metadata-filter \'<json>\' --requestor "<your-name>"` |\n| `cerefox_set_document_projects` | _MCP-only; a CLI command will be added in a future release. Until then, run via MCP if available._ |\n| `cerefox_get_audit_log` | `cerefox audit list --requestor "<your-name>"` (add `--json` for scripted access) |\n| `cerefox_get_help` | `cerefox guides show agent-quick-reference` (or `cerefox guides list` for the full bundled-docs index) |\n\n**Set identity on every call**, exactly as you would on MCP:\n- Writes (`document ingest`, `document ingest-dir`): `--author "<your-name>" --author-type agent`\n- Reads: `--requestor "<your-name>"`\n\nOr have your user set `CEREFOX_AUTHOR_NAME` / `CEREFOX_AUTHOR_TYPE` / `CEREFOX_REQUESTOR_NAME` in their `.env` to apply defaults once.'
25760
25760
  };
25761
25761
  HELP_SECTION_HEADINGS = ["Tools", "Essential Rules", "Update Workflow (ID-based -- preferred)", "Update Workflow (title-based -- fallback)", "Catch-Up Workflow", "CLI fallback (when MCP is unavailable)"];
25762
25762
  });
@@ -26758,7 +26758,7 @@ __export(exports_sync_self_docs, {
26758
26758
  runSyncSelfDocs: () => runSyncSelfDocs,
26759
26759
  registerSyncSelfDocs: () => registerSyncSelfDocs
26760
26760
  });
26761
- import { readFileSync as readFileSync9 } from "node:fs";
26761
+ import { readFileSync as readFileSync10 } from "node:fs";
26762
26762
  import { basename as basename4, extname as extname4 } from "node:path";
26763
26763
  async function runSyncSelfDocs(options = {}) {
26764
26764
  const project = options.project ?? "_cerefox-self-docs";
@@ -26785,7 +26785,7 @@ async function runSyncSelfDocs(options = {}) {
26785
26785
  const authorType = resolveAuthorType("agent");
26786
26786
  const outcomes = [];
26787
26787
  for (const doc of docs) {
26788
- const content = readFileSync9(doc.path, "utf8");
26788
+ const content = readFileSync10(doc.path, "utf8");
26789
26789
  const m = content.match(/^#\s+(.+)$/m);
26790
26790
  const title = m ? m[1].trim() : basename4(doc.path, extname4(doc.path));
26791
26791
  try {
@@ -26819,11 +26819,11 @@ async function runSyncSelfDocs(options = {}) {
26819
26819
  printTable(outcomes.filter((o) => o.status === "error").map((o) => ({ topic: o.topic, error: o.detail.slice(0, 100) })));
26820
26820
  }
26821
26821
  }
26822
- async function action16(options) {
26822
+ async function action19(options) {
26823
26823
  await runSyncSelfDocs(options);
26824
26824
  }
26825
26825
  function registerSyncSelfDocs(program2) {
26826
- program2.command("sync-self-docs").description("Ingest bundled Cerefox docs under the _cerefox-self-docs project.").option("--dry-run", "List what would be ingested without writing.").option("--project <name>", "Override the target project name.", "_cerefox-self-docs").action(action16);
26826
+ program2.command("sync-self-docs").description("Ingest bundled Cerefox docs under the _cerefox-self-docs project.").option("--dry-run", "List what would be ingested without writing.").option("--project <name>", "Override the target project name.", "_cerefox-self-docs").action(action19);
26827
26827
  }
26828
26828
  var init_sync_self_docs = __esm(() => {
26829
26829
  init_cli_core();
@@ -40002,6 +40002,9 @@ function registerBackup(program2) {
40002
40002
 
40003
40003
  // src/cli/commands/completion.ts
40004
40004
  init_cli_core();
40005
+ import { existsSync as existsSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "node:fs";
40006
+ import { homedir as homedir3 } from "node:os";
40007
+ import { join as join3 } from "node:path";
40005
40008
  function collectCompletionInfo() {
40006
40009
  const program2 = buildProgram();
40007
40010
  const subcommands = [];
@@ -40093,26 +40096,84 @@ function fishScript(info2) {
40093
40096
  `) + `
40094
40097
  `;
40095
40098
  }
40096
- function action2(shell) {
40099
+ function scriptFor(shell) {
40097
40100
  const info2 = collectCompletionInfo();
40098
- let script;
40099
40101
  switch (shell) {
40100
40102
  case "bash":
40101
- script = bashScript(info2);
40102
- break;
40103
+ return bashScript(info2);
40103
40104
  case "zsh":
40104
- script = zshScript(info2);
40105
- break;
40105
+ return zshScript(info2);
40106
40106
  case "fish":
40107
- script = fishScript(info2);
40108
- break;
40109
- default:
40110
- throw userError(`Unknown shell "${shell}". Supported: bash, zsh, fish.`);
40107
+ return fishScript(info2);
40108
+ }
40109
+ }
40110
+ function detectShell() {
40111
+ const sh = (process.env.SHELL ?? "").split("/").pop() ?? "";
40112
+ if (sh === "bash" || sh === "zsh" || sh === "fish")
40113
+ return sh;
40114
+ return null;
40115
+ }
40116
+ var RC_BEGIN = "# >>> cerefox shell completion (managed by `cerefox completion install`) >>>";
40117
+ var RC_END = "# <<< cerefox shell completion <<<";
40118
+ async function installMode(options) {
40119
+ const shell = options.shell ?? detectShell();
40120
+ if (!shell) {
40121
+ throw userError("Could not detect your shell from $SHELL. Pass --shell bash|zsh|fish.");
40122
+ }
40123
+ if (shell !== "bash" && shell !== "zsh" && shell !== "fish") {
40124
+ throw userError(`Unsupported --shell "${shell}". Use bash, zsh, or fish.`);
40125
+ }
40126
+ const home = homedir3();
40127
+ const scriptPath = join3(home, `.cerefox-completion.${shell}`);
40128
+ writeFileSync2(scriptPath, scriptFor(shell), "utf8");
40129
+ println(c.green(`✓ Wrote completion script: ${scriptPath}`));
40130
+ if (shell === "fish") {
40131
+ println(c.dim(" For fish, also copy it into ~/.config/fish/completions/cerefox.fish (or `source` it)."));
40132
+ return;
40133
+ }
40134
+ const rcPath = join3(home, shell === "zsh" ? ".zshrc" : ".bashrc");
40135
+ const sourceLine = `[ -s "${scriptPath}" ] && source "${scriptPath}"`;
40136
+ const block = `${RC_BEGIN}
40137
+ ${sourceLine}
40138
+ ${RC_END}
40139
+ `;
40140
+ const existing = existsSync3(rcPath) ? readFileSync3(rcPath, "utf8") : "";
40141
+ if (existing.includes(RC_BEGIN)) {
40142
+ println(c.dim(` ${rcPath} already sources the completion (left as-is).`));
40143
+ } else {
40144
+ const interactive = process.stdout.isTTY && !options.yes;
40145
+ if (interactive) {
40146
+ const ok2 = await confirm(`Add a completion source line to ${rcPath}?`, false);
40147
+ if (!ok2) {
40148
+ println(c.dim(`Skipped the rc edit. Add this line to ${rcPath} yourself:`));
40149
+ println(` ${sourceLine}`);
40150
+ return;
40151
+ }
40152
+ }
40153
+ writeFileSync2(rcPath, (existing.endsWith(`
40154
+ `) || existing === "" ? existing : existing + `
40155
+ `) + `
40156
+ ` + block, "utf8");
40157
+ println(c.green(`✓ Added completion to ${rcPath}.`));
40158
+ }
40159
+ println(c.dim(` Activate now: exec ${shell} (or open a new terminal).`));
40160
+ }
40161
+ async function action2(target, options) {
40162
+ if (target === "install") {
40163
+ await installMode(options);
40164
+ return;
40165
+ }
40166
+ if (target !== "bash" && target !== "zsh" && target !== "fish") {
40167
+ throw userError(`Unknown shell "${target}". Supported: bash, zsh, fish (or 'install').`);
40168
+ }
40169
+ println(scriptFor(target));
40170
+ if (process.stdout.isTTY) {
40171
+ eprintln(c.dim(`
40172
+ # Tip: \`cerefox completion install\` writes this + wires your shell rc automatically.`));
40111
40173
  }
40112
- println(script);
40113
40174
  }
40114
40175
  function registerCompletion(program2) {
40115
- program2.command("completion").description("Emit a tab-completion script for your shell.").argument("<shell>", "Target shell: bash, zsh, or fish.").action(action2);
40176
+ program2.command("completion").description("Shell tab-completion. `install` to auto-wire your shell, or a shell name to print the script.").argument("<shell>", "bash | zsh | fish (print the script), or 'install' (auto-wire).").option("--shell <shell>", "For 'install': override the auto-detected shell.").option("--yes", "For 'install': skip the rc-edit confirmation (used by install.sh).").action(action2);
40116
40177
  }
40117
40178
 
40118
40179
  // src/cli/commands/config-get.ts
@@ -40145,10 +40206,41 @@ function registerConfigGet(program2) {
40145
40206
  program2.command("config-get").description("Read a runtime config value from the cerefox_config table.").argument("<key>", "Config key (e.g. usage_tracking_enabled).").option("--json", "Emit JSON.").action(action3);
40146
40207
  }
40147
40208
 
40209
+ // src/cli/commands/config-list.ts
40210
+ init_cli_core();
40211
+ var CONFIG_KEYS = [
40212
+ {
40213
+ key: "usage_tracking_enabled",
40214
+ description: "'true'/'false' — log reads + writes to cerefox_usage_log. Default off."
40215
+ },
40216
+ {
40217
+ key: "require_requestor_identity",
40218
+ description: "'true'/'false' — require requestor/author on MCP tool calls. Default off."
40219
+ },
40220
+ {
40221
+ key: "requestor_identity_format",
40222
+ description: "Regex the requestor/author must match (only enforced when the above is on)."
40223
+ }
40224
+ ];
40225
+ function action4(options) {
40226
+ if (options.json) {
40227
+ printJson({ keys: CONFIG_KEYS.map((k) => k.key) });
40228
+ return;
40229
+ }
40230
+ println(c.bold("Runtime config keys (stored in cerefox_config; read with `cerefox config get <key>`):"));
40231
+ for (const { key, description } of CONFIG_KEYS) {
40232
+ println(` ${c.bold(key)}`);
40233
+ println(c.dim(` ${description}`));
40234
+ }
40235
+ }
40236
+ function registerConfigList(parent) {
40237
+ parent.command("list").description("List the runtime config keys (the cerefox_config allow-list; not values).").option("--json", "Emit the key list as JSON.").action(action4);
40238
+ }
40239
+
40148
40240
  // src/cli/commands/config-set.ts
40149
40241
  init_cli_core();
40150
40242
  init_client();
40151
- async function action4(key, value) {
40243
+ async function action5(key, value) {
40152
40244
  const client = getClient();
40153
40245
  try {
40154
40246
  await client.rpc("cerefox_set_config", { p_key: key, p_value: value });
@@ -40159,7 +40251,7 @@ async function action4(key, value) {
40159
40251
  println(c.green("✓ ") + `${key} = ${value}`);
40160
40252
  }
40161
40253
  function registerConfigSet(program2) {
40162
- program2.command("config-set").description("Write a runtime config value into the cerefox_config table.").argument("<key>", "Config key.").argument("<value>", "Value to write.").action(action4);
40254
+ program2.command("config-set").description("Write a runtime config value into the cerefox_config table.").argument("<key>", "Config key.").argument("<value>", "Value to write.").action(action5);
40163
40255
  }
40164
40256
 
40165
40257
  // src/cli/commands/configure-agent.ts
@@ -40168,13 +40260,13 @@ init_cli_core();
40168
40260
  // src/cli/util/mcp-config-writers.ts
40169
40261
  import {
40170
40262
  copyFileSync,
40171
- existsSync as existsSync3,
40263
+ existsSync as existsSync4,
40172
40264
  mkdirSync as mkdirSync2,
40173
- readFileSync as readFileSync3,
40174
- writeFileSync as writeFileSync2
40265
+ readFileSync as readFileSync4,
40266
+ writeFileSync as writeFileSync3
40175
40267
  } from "node:fs";
40176
- import { homedir as homedir3, platform } from "node:os";
40177
- import { dirname, join as join3 } from "node:path";
40268
+ import { homedir as homedir4, platform } from "node:os";
40269
+ import { dirname, join as join4 } from "node:path";
40178
40270
  import { spawnSync } from "node:child_process";
40179
40271
 
40180
40272
  // ../../node_modules/.bun/smol-toml@1.6.1/node_modules/smol-toml/dist/error.js
@@ -41276,17 +41368,17 @@ function defaultCerefoxEntry() {
41276
41368
  };
41277
41369
  }
41278
41370
  function claudeCodeUserConfigPath() {
41279
- return join3(homedir3(), ".claude.json");
41371
+ return join4(homedir4(), ".claude.json");
41280
41372
  }
41281
41373
  function claudeDesktopConfigPath() {
41282
- const home = homedir3();
41374
+ const home = homedir4();
41283
41375
  if (platform() === "darwin") {
41284
- return join3(home, "Library", "Application Support", "Claude", "claude_desktop_config.json");
41376
+ return join4(home, "Library", "Application Support", "Claude", "claude_desktop_config.json");
41285
41377
  }
41286
41378
  if (platform() === "win32") {
41287
- return join3(process.env.APPDATA ?? home, "Claude", "claude_desktop_config.json");
41379
+ return join4(process.env.APPDATA ?? home, "Claude", "claude_desktop_config.json");
41288
41380
  }
41289
- return join3(home, ".config", "Claude", "claude_desktop_config.json");
41381
+ return join4(home, ".config", "Claude", "claude_desktop_config.json");
41290
41382
  }
41291
41383
  function claudeCodeDelegated() {
41292
41384
  const entry = defaultCerefoxEntry();
@@ -41296,13 +41388,13 @@ function claudeCodeDelegated() {
41296
41388
  };
41297
41389
  }
41298
41390
  function cursorConfigPath() {
41299
- return join3(homedir3(), ".cursor", "mcp.json");
41391
+ return join4(homedir4(), ".cursor", "mcp.json");
41300
41392
  }
41301
41393
  function codexConfigPath() {
41302
- return join3(homedir3(), ".codex", "config.toml");
41394
+ return join4(homedir4(), ".codex", "config.toml");
41303
41395
  }
41304
41396
  function geminiConfigPath() {
41305
- return join3(homedir3(), ".gemini", "settings.json");
41397
+ return join4(homedir4(), ".gemini", "settings.json");
41306
41398
  }
41307
41399
  var WRITERS = {
41308
41400
  "claude-code": {
@@ -41360,15 +41452,15 @@ function directWrite(writer, configPath, opts) {
41360
41452
  if (!opts.dryRun)
41361
41453
  mkdirSync2(dirname(configPath), { recursive: true });
41362
41454
  let existing = {};
41363
- let action5 = "created";
41455
+ let action6 = "created";
41364
41456
  let backupPath = null;
41365
- if (existsSync3(configPath)) {
41457
+ if (existsSync4(configPath)) {
41366
41458
  try {
41367
- const raw = readFileSync3(configPath, "utf8");
41459
+ const raw = readFileSync4(configPath, "utf8");
41368
41460
  existing = format === "toml" ? parse(raw) : JSON.parse(raw);
41369
- action5 = hasCerefoxEntry(existing, format) ? "replaced" : "merged";
41461
+ action6 = hasCerefoxEntry(existing, format) ? "replaced" : "merged";
41370
41462
  } catch {
41371
- action5 = "replaced";
41463
+ action6 = "replaced";
41372
41464
  }
41373
41465
  if (!opts.noBackup && !opts.dryRun) {
41374
41466
  backupPath = configPath + ".pre-cerefox.bak";
@@ -41383,9 +41475,9 @@ function directWrite(writer, configPath, opts) {
41383
41475
  const body = format === "toml" ? stringify(existing) + `
41384
41476
  ` : JSON.stringify(existing, null, 2) + `
41385
41477
  `;
41386
- writeFileSync2(configPath, body, "utf8");
41478
+ writeFileSync3(configPath, body, "utf8");
41387
41479
  }
41388
- return { configPath, backupPath, action: action5, serverEntry: entry };
41480
+ return { configPath, backupPath, action: action6, serverEntry: entry };
41389
41481
  }
41390
41482
  function hasCerefoxEntry(existing, format) {
41391
41483
  const key = format === "toml" ? "mcp_servers" : "mcpServers";
@@ -41409,7 +41501,7 @@ function delegatedWrite(writer, opts) {
41409
41501
  };
41410
41502
  }
41411
41503
  let backupPath = null;
41412
- if (!opts.noBackup && existsSync3(writer.configPath)) {
41504
+ if (!opts.noBackup && existsSync4(writer.configPath)) {
41413
41505
  backupPath = writer.configPath + ".pre-cerefox.bak";
41414
41506
  copyFileSync(writer.configPath, backupPath);
41415
41507
  }
@@ -41434,7 +41526,7 @@ function delegatedWrite(writer, opts) {
41434
41526
  }
41435
41527
 
41436
41528
  // src/cli/commands/configure-agent.ts
41437
- function action5(options) {
41529
+ function action6(options) {
41438
41530
  const writer = WRITERS[options.tool];
41439
41531
  if (!writer) {
41440
41532
  throw userError(`Unknown --tool "${options.tool}".`, `Supported clients: ${Object.keys(WRITERS).join(", ")}.`);
@@ -41486,13 +41578,13 @@ function restartHint(id) {
41486
41578
  }
41487
41579
  }
41488
41580
  function registerConfigureAgent(program2) {
41489
- program2.command("configure-agent").description("Write the MCP server config for a supported client.").requiredOption("-t, --tool <client>", "Target client: claude-code, claude-desktop, cursor, codex, gemini.").option("--config-path <path>", "Override the default config-file path.").option("--no-backup", "Skip the .pre-cerefox.bak backup of any existing config.").option("--dry-run", "Print the planned write without modifying any file.").option("--json", "Emit JSON describing the result.").action(action5);
41581
+ program2.command("configure-agent").description("Write the MCP server config for a supported client.").requiredOption("-t, --tool <client>", "Target client: claude-code, claude-desktop, cursor, codex, gemini.").option("--config-path <path>", "Override the default config-file path.").option("--no-backup", "Skip the .pre-cerefox.bak backup of any existing config.").option("--dry-run", "Print the planned write without modifying any file.").option("--json", "Emit JSON describing the result.").action(action6);
41490
41582
  }
41491
41583
 
41492
41584
  // src/cli/commands/delete-doc.ts
41493
41585
  init_cli_core();
41494
41586
  init_client();
41495
- async function action6(documentId, options) {
41587
+ async function action7(documentId, options) {
41496
41588
  const client = getClient();
41497
41589
  const { data: doc, error } = await client.raw.from("cerefox_documents").select("id, title, total_chars, chunk_count, deleted_at").eq("id", documentId).maybeSingle();
41498
41590
  if (error) {
@@ -41531,14 +41623,14 @@ async function action6(documentId, options) {
41531
41623
  }
41532
41624
  }
41533
41625
  function registerDeleteDoc(program2) {
41534
- program2.command("delete-doc").description("Soft-delete a document (recoverable via the web UI trash).").argument("<document-id>", "UUID of the document to delete.").option("--reason <text>", "Optional reason recorded in the audit log.").option("-a, --author <name>", "Caller identity (audit log).").option("--author-type <type>", "'user' or 'agent' (default: user).", "user").option("--yes", "Skip the confirmation prompt.").action(action6);
41626
+ program2.command("delete-doc").description("Soft-delete a document (recoverable via the web UI trash).").argument("<document-id>", "UUID of the document to delete.").option("--reason <text>", "Optional reason recorded in the audit log.").option("-a, --author <name>", "Caller identity (audit log).").option("--author-type <type>", "'user' or 'agent' (default: user).", "user").option("--yes", "Skip the confirmation prompt.").action(action7);
41535
41627
  }
41536
41628
 
41537
41629
  // src/cli/commands/delete-project.ts
41538
41630
  init_cli_core();
41539
41631
  init_client();
41540
41632
  var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
41541
- async function action7(target, options) {
41633
+ async function action8(target, options) {
41542
41634
  const client = getClient();
41543
41635
  const isUuid = UUID_RE.test(target);
41544
41636
  const lookup = isUuid ? client.raw.from("cerefox_projects").select("id, name, description").eq("id", target).maybeSingle() : client.raw.from("cerefox_projects").select("id, name, description").eq("name", target).maybeSingle();
@@ -41574,19 +41666,19 @@ async function action7(target, options) {
41574
41666
  println(c.green(`✓ Deleted project "${project.name}" (id: ${project.id}).`));
41575
41667
  }
41576
41668
  function registerDeleteProject(program2) {
41577
- program2.command("delete-project").description("Delete an empty project (use --force to remove a non-empty one).").argument("<name-or-id>", "Project name (exact match) or UUID.").option("--yes", "Skip the confirmation prompt.").option("--force", "Allow deletion when documents are still linked to the project.").action(action7);
41669
+ program2.command("delete-project").description("Delete an empty project (use --force to remove a non-empty one).").argument("<name-or-id>", "Project name (exact match) or UUID.").option("--yes", "Skip the confirmation prompt.").option("--force", "Allow deletion when documents are still linked to the project.").action(action8);
41578
41670
  }
41579
41671
 
41580
41672
  // src/cli/commands/deploy-server.ts
41581
41673
  init_cli_core();
41582
41674
  init_config();
41583
41675
  import { spawnSync as spawnSync2 } from "node:child_process";
41584
- import { existsSync as existsSync6 } from "node:fs";
41676
+ import { existsSync as existsSync7 } from "node:fs";
41585
41677
  import { readdirSync as readdirSync2 } from "node:fs";
41586
41678
 
41587
41679
  // ../../_shared/server-assets/index.ts
41588
- import { existsSync as existsSync4 } from "node:fs";
41589
- import { dirname as dirname2, join as join4 } from "node:path";
41680
+ import { existsSync as existsSync5 } from "node:fs";
41681
+ import { dirname as dirname2, join as join5 } from "node:path";
41590
41682
  import { fileURLToPath } from "node:url";
41591
41683
  import { cwd as processCwd2 } from "node:process";
41592
41684
  function moduleDir() {
@@ -41594,25 +41686,25 @@ function moduleDir() {
41594
41686
  }
41595
41687
  function bundledServerAssets(serverAssetsRoot) {
41596
41688
  return {
41597
- schemaFile: join4(serverAssetsRoot, "db", "schema.sql"),
41598
- rpcsFile: join4(serverAssetsRoot, "db", "rpcs.sql"),
41599
- migrationsDir: join4(serverAssetsRoot, "db", "migrations"),
41600
- functionsDir: join4(serverAssetsRoot, "supabase", "functions"),
41689
+ schemaFile: join5(serverAssetsRoot, "db", "schema.sql"),
41690
+ rpcsFile: join5(serverAssetsRoot, "db", "rpcs.sql"),
41691
+ migrationsDir: join5(serverAssetsRoot, "db", "migrations"),
41692
+ functionsDir: join5(serverAssetsRoot, "supabase", "functions"),
41601
41693
  layout: "bundled"
41602
41694
  };
41603
41695
  }
41604
41696
  function sourceServerAssets(repoRoot) {
41605
- const dbDir = join4(repoRoot, "src", "cerefox", "db");
41697
+ const dbDir = join5(repoRoot, "src", "cerefox", "db");
41606
41698
  return {
41607
- schemaFile: join4(dbDir, "schema.sql"),
41608
- rpcsFile: join4(dbDir, "rpcs.sql"),
41609
- migrationsDir: join4(dbDir, "migrations"),
41610
- functionsDir: join4(repoRoot, "supabase", "functions"),
41699
+ schemaFile: join5(dbDir, "schema.sql"),
41700
+ rpcsFile: join5(dbDir, "rpcs.sql"),
41701
+ migrationsDir: join5(dbDir, "migrations"),
41702
+ functionsDir: join5(repoRoot, "supabase", "functions"),
41611
41703
  layout: "source"
41612
41704
  };
41613
41705
  }
41614
41706
  function serverAssetsUsable(p) {
41615
- return existsSync4(p.schemaFile) && existsSync4(p.rpcsFile);
41707
+ return existsSync5(p.schemaFile) && existsSync5(p.rpcsFile);
41616
41708
  }
41617
41709
  function resolveServerAssets(opts = {}) {
41618
41710
  if (opts.assetsDir) {
@@ -41621,21 +41713,21 @@ function resolveServerAssets(opts = {}) {
41621
41713
  const here = opts.moduleDirOverride ?? moduleDir();
41622
41714
  const cwd = opts.cwd ?? processCwd2();
41623
41715
  const candidates = [
41624
- bundledServerAssets(join4(here, "..", "server-assets")),
41625
- sourceServerAssets(join4(here, "..", "..")),
41716
+ bundledServerAssets(join5(here, "..", "server-assets")),
41717
+ sourceServerAssets(join5(here, "..", "..")),
41626
41718
  sourceServerAssets(cwd)
41627
41719
  ];
41628
41720
  for (const candidate of candidates) {
41629
41721
  if (serverAssetsUsable(candidate))
41630
41722
  return candidate;
41631
41723
  }
41632
- return sourceServerAssets(join4(here, "..", ".."));
41724
+ return sourceServerAssets(join5(here, "..", ".."));
41633
41725
  }
41634
41726
 
41635
41727
  // ../../_shared/db-deploy/index.ts
41636
41728
  init_src();
41637
- import { existsSync as existsSync5, readFileSync as readFileSync4, readdirSync } from "node:fs";
41638
- import { join as join5 } from "node:path";
41729
+ import { existsSync as existsSync6, readFileSync as readFileSync5, readdirSync } from "node:fs";
41730
+ import { join as join6 } from "node:path";
41639
41731
  var RESET_SQL = `
41640
41732
  DROP TABLE IF EXISTS cerefox_chunks CASCADE;
41641
41733
  DROP TABLE IF EXISTS cerefox_documents CASCADE;
@@ -41652,13 +41744,13 @@ CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
41652
41744
  CREATE EXTENSION IF NOT EXISTS "vector";
41653
41745
  `;
41654
41746
  function listMigrationFiles(migrationsDir) {
41655
- if (!existsSync5(migrationsDir))
41747
+ if (!existsSync6(migrationsDir))
41656
41748
  return [];
41657
41749
  return readdirSync(migrationsDir).filter((n) => n.endsWith(".sql")).sort();
41658
41750
  }
41659
41751
  function buildDeploySteps(assets, opts = {}) {
41660
- const schemaSql = readFileSync4(assets.schemaFile, "utf8");
41661
- const rpcsSql = readFileSync4(assets.rpcsFile, "utf8");
41752
+ const schemaSql = readFileSync5(assets.schemaFile, "utf8");
41753
+ const rpcsSql = readFileSync5(assets.rpcsFile, "utf8");
41662
41754
  const steps = [];
41663
41755
  if (opts.reset) {
41664
41756
  steps.push({ label: "Reset: drop existing Cerefox objects", sql: RESET_SQL });
@@ -41751,7 +41843,7 @@ async function runDbMigrate(opts) {
41751
41843
  }
41752
41844
  const applied = [];
41753
41845
  for (const f of pending) {
41754
- const body = readFileSync4(join5(opts.assets.migrationsDir, f), "utf8");
41846
+ const body = readFileSync5(join6(opts.assets.migrationsDir, f), "utf8");
41755
41847
  log(`Applying ${f}…`);
41756
41848
  try {
41757
41849
  await sql.begin(async (tx) => {
@@ -41779,7 +41871,7 @@ async function applyRpcs(opts) {
41779
41871
  log("Refresh RPCs (rpcs.sql)…");
41780
41872
  if (opts.dryRun)
41781
41873
  return { ok: true };
41782
- const rpcsSql = readFileSync4(opts.assets.rpcsFile, "utf8");
41874
+ const rpcsSql = readFileSync5(opts.assets.rpcsFile, "utf8");
41783
41875
  const sql = src_default(opts.dbUrl, { prepare: false, onnotice: () => {} });
41784
41876
  try {
41785
41877
  await sql.unsafe(rpcsSql);
@@ -41812,11 +41904,11 @@ function parseProjectRef(supabaseUrl) {
41812
41904
  }
41813
41905
  }
41814
41906
  function listEdgeFunctions(functionsDir) {
41815
- if (!existsSync6(functionsDir))
41907
+ if (!existsSync7(functionsDir))
41816
41908
  return [];
41817
41909
  return readdirSync2(functionsDir, { withFileTypes: true }).filter((e) => e.isDirectory() && e.name.startsWith("cerefox-")).map((e) => e.name).sort();
41818
41910
  }
41819
- async function action8(options) {
41911
+ async function action9(options) {
41820
41912
  const settings = loadSettings();
41821
41913
  const assets = resolveServerAssets();
41822
41914
  const doSchema = !options.functionsOnly;
@@ -41831,7 +41923,7 @@ async function action8(options) {
41831
41923
  });
41832
41924
  checks.push({
41833
41925
  label: "Bundled schema assets present",
41834
- ok: existsSync6(assets.schemaFile) && existsSync6(assets.rpcsFile),
41926
+ ok: existsSync7(assets.schemaFile) && existsSync7(assets.rpcsFile),
41835
41927
  remediation: "Schema files not found. Reinstall the package, or run from a repo " + "clone (src/cerefox/db/)."
41836
41928
  });
41837
41929
  }
@@ -41999,13 +42091,89 @@ Proceed with deployment to Supabase?`, true);
41999
42091
  println(c.dim("Verify with: cerefox doctor"));
42000
42092
  }
42001
42093
  function registerDeployServer(program2) {
42002
- program2.command("deploy-server").description("Deploy/update the Cerefox server side (schema + RPCs + Edge Functions) on Supabase.").option("--dry-run", "Print the plan + pre-flight without deploying.").option("--schema-only", "Deploy/update only the schema + RPCs (skip Edge Functions).").option("--functions-only", "Deploy only the Edge Functions (skip the schema/RPCs).").option("--project-ref <ref>", "Supabase project ref for Edge Function deploys (default: derived from CEREFOX_SUPABASE_URL).").action(action8);
42094
+ program2.command("deploy-server").description("Deploy/update the Cerefox server side (schema + RPCs + Edge Functions) on Supabase.").option("--dry-run", "Print the plan + pre-flight without deploying.").option("--schema-only", "Deploy/update only the schema + RPCs (skip Edge Functions).").option("--functions-only", "Deploy only the Edge Functions (skip the schema/RPCs).").option("--project-ref <ref>", "Supabase project ref for Edge Function deploys (default: derived from CEREFOX_SUPABASE_URL).").action(action9);
42095
+ }
42096
+
42097
+ // src/cli/commands/document-edit.ts
42098
+ init_cli_core();
42099
+ init_client();
42100
+ function parseMetaPair(pair) {
42101
+ const eq = pair.indexOf("=");
42102
+ if (eq <= 0)
42103
+ throw userError(`--set-meta expects key=value, got "${pair}".`);
42104
+ const key = pair.slice(0, eq).trim();
42105
+ const raw = pair.slice(eq + 1);
42106
+ let value = raw;
42107
+ try {
42108
+ value = JSON.parse(raw);
42109
+ } catch {
42110
+ value = raw;
42111
+ }
42112
+ return [key, value];
42113
+ }
42114
+ async function action10(documentId, options) {
42115
+ const hasTitle = options.title !== undefined;
42116
+ const sets = options.setMeta ?? [];
42117
+ const unsets = options.unsetMeta ?? [];
42118
+ if (!hasTitle && sets.length === 0 && unsets.length === 0) {
42119
+ throw userError("Nothing to edit — pass --title and/or --set-meta / --unset-meta.");
42120
+ }
42121
+ if (hasTitle && !options.title.trim())
42122
+ throw userError("--title cannot be empty.");
42123
+ const client = getClient();
42124
+ const { data: doc, error } = await client.raw.from("cerefox_documents").select("id, title, metadata, deleted_at").eq("id", documentId).maybeSingle();
42125
+ if (error)
42126
+ throw systemError(`Lookup failed: ${error.message}`);
42127
+ if (!doc)
42128
+ throw notFound(`Document ${documentId} not found.`);
42129
+ if (doc.deleted_at) {
42130
+ throw userError(`Document ${documentId} is soft-deleted — restore it first (cerefox document restore).`);
42131
+ }
42132
+ const metadata = { ...doc.metadata ?? {} };
42133
+ for (const pair of sets) {
42134
+ const [k, v] = parseMetaPair(pair);
42135
+ metadata[k] = v;
42136
+ }
42137
+ for (const k of unsets)
42138
+ delete metadata[k.trim()];
42139
+ const newTitle = hasTitle ? options.title.trim() : doc.title;
42140
+ const titleChanged = newTitle !== doc.title;
42141
+ const { error: updErr } = await client.raw.from("cerefox_documents").update({ title: newTitle, metadata, updated_at: new Date().toISOString() }).eq("id", documentId);
42142
+ if (updErr)
42143
+ throw systemError(`Update failed: ${updErr.message}`);
42144
+ if (titleChanged) {
42145
+ const { error: ftsErr } = await client.raw.rpc("cerefox_update_chunk_fts", {
42146
+ p_document_id: documentId,
42147
+ p_new_title: newTitle
42148
+ });
42149
+ if (ftsErr)
42150
+ throw systemError(`Title updated but FTS refresh failed: ${ftsErr.message}`);
42151
+ }
42152
+ const author = resolveAuthor(options.author);
42153
+ const authorType = resolveAuthorType(options.authorType);
42154
+ await client.raw.rpc("cerefox_create_audit_entry", {
42155
+ p_document_id: documentId,
42156
+ p_operation: "update-metadata",
42157
+ p_author: author,
42158
+ p_author_type: authorType,
42159
+ p_description: `Edited${titleChanged ? " title" : ""}` + (sets.length ? ` · set ${sets.length} meta key(s)` : "") + (unsets.length ? ` · unset ${unsets.length} meta key(s)` : "")
42160
+ });
42161
+ println(c.green(`✓ Edited "${newTitle}" (id: ${documentId}).`));
42162
+ if (titleChanged) {
42163
+ println(c.dim(" Title changed: FTS refreshed; semantic embeddings update on next `cerefox server reindex`."));
42164
+ }
42165
+ }
42166
+ function collect(value, prev) {
42167
+ return [...prev, value];
42168
+ }
42169
+ function registerDocumentEdit(parent) {
42170
+ parent.command("edit").description("Edit a document's title and/or metadata (non-destructive patch). Content edits: `document ingest --document-id <id> --update`.").argument("<document-id>", "UUID of the document.").option("--title <title>", "New title (refreshes FTS; re-embed on next reindex).").option("--set-meta <key=value>", "Set/overwrite a metadata key (repeatable). Value is JSON-parsed when possible.", collect, []).option("--unset-meta <key>", "Remove a metadata key (repeatable).", collect, []).option("-a, --author <name>", "Caller identity (audit log).").option("--author-type <type>", "'user' or 'agent' (default: user).", "user").action(action10);
42003
42171
  }
42004
42172
 
42005
42173
  // src/cli/commands/document-restore.ts
42006
42174
  init_cli_core();
42007
42175
  init_client();
42008
- async function action9(documentId, options) {
42176
+ async function action11(documentId, options) {
42009
42177
  const client = getClient();
42010
42178
  const { data: doc, error } = await client.raw.from("cerefox_documents").select("id, title, deleted_at").eq("id", documentId).maybeSingle();
42011
42179
  if (error)
@@ -42029,7 +42197,103 @@ async function action9(documentId, options) {
42029
42197
  println(c.green(`✓ Restored "${doc.title}" (id: ${documentId}) from the trash.`));
42030
42198
  }
42031
42199
  function registerDocumentRestore(parent) {
42032
- parent.command("restore").description("Restore a soft-deleted document from the trash (inverse of `document delete`).").argument("<document-id>", "UUID of the soft-deleted document.").option("-a, --author <name>", "Caller identity (audit log).").option("--author-type <type>", "'user' or 'agent' (default: user).", "user").action(action9);
42200
+ parent.command("restore").description("Restore a soft-deleted document from the trash (inverse of `document delete`).").argument("<document-id>", "UUID of the soft-deleted document.").option("-a, --author <name>", "Caller identity (audit log).").option("--author-type <type>", "'user' or 'agent' (default: user).", "user").action(action11);
42201
+ }
42202
+
42203
+ // src/cli/commands/guides.ts
42204
+ init_cli_core();
42205
+ init_bundled_docs();
42206
+ import { spawnSync as spawnSync3 } from "node:child_process";
42207
+ function openInBrowser(path) {
42208
+ const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
42209
+ const result = spawnSync3(cmd, [path], { stdio: "ignore" });
42210
+ if (result.status !== 0) {
42211
+ println(c.dim(`(could not auto-open; the file is at: ${path})`));
42212
+ }
42213
+ }
42214
+ function resolveDoc(topic) {
42215
+ const doc = readBundledDoc(topic);
42216
+ if (!doc) {
42217
+ throw notFound(`No bundled guide named "${topic}".`, "Run `cerefox guides list` to see available topics.");
42218
+ }
42219
+ return doc;
42220
+ }
42221
+ function listAction() {
42222
+ const docs = listBundledDocs();
42223
+ if (docs.length === 0) {
42224
+ println("(no bundled guides found)");
42225
+ return;
42226
+ }
42227
+ println(c.bold("Available guides:"));
42228
+ println("");
42229
+ printTable(docs.map((d) => ({ topic: d.topic, size_kb: Math.round(d.size / 1024) + " KB" })));
42230
+ println("");
42231
+ println(c.dim("Open with `cerefox guides open <topic>` (browser) or `cerefox guides show <topic>` (stdout)."));
42232
+ }
42233
+ function openAction(topic) {
42234
+ const doc = resolveDoc(topic);
42235
+ println(c.dim(`Opening ${doc.path} …`));
42236
+ openInBrowser(doc.path);
42237
+ }
42238
+ function showAction(topic) {
42239
+ println(resolveDoc(topic).content);
42240
+ }
42241
+ function registerGuides(parent) {
42242
+ parent.command("list").description("List the bundled documentation topics.").action(listAction);
42243
+ parent.command("open").description("Open a bundled guide in your browser.").argument("<topic>", "Topic (e.g. quickstart, connect-agents).").action(openAction);
42244
+ parent.command("show").description("Print a bundled guide to stdout.").argument("<topic>", "Topic (e.g. quickstart, connect-agents).").action(showAction);
42245
+ }
42246
+
42247
+ // src/cli/commands/project-create.ts
42248
+ init_cli_core();
42249
+ init_client();
42250
+ async function action12(name, options) {
42251
+ const trimmed = name.trim();
42252
+ if (!trimmed)
42253
+ throw userError("Project name is required.");
42254
+ const client = getClient();
42255
+ const { data, error } = await client.raw.from("cerefox_projects").insert({ name: trimmed, description: (options.description ?? "").trim() }).select("id, name, description").maybeSingle();
42256
+ if (error || !data) {
42257
+ throw systemError(`Create failed: ${error?.message ?? "no row returned"}`);
42258
+ }
42259
+ println(c.green(`✓ Created project "${data.name}" (id: ${data.id}).`));
42260
+ }
42261
+ function registerProjectCreate(parent) {
42262
+ parent.command("create").description("Create a new (empty) project.").argument("<name>", "Project name (must be unique).").option("--description <text>", "Optional project description.").action(action12);
42263
+ }
42264
+
42265
+ // src/cli/commands/project-edit.ts
42266
+ init_cli_core();
42267
+ init_client();
42268
+ var UUID_RE2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
42269
+ async function action13(target, options) {
42270
+ const update = {};
42271
+ if (options.name !== undefined) {
42272
+ const n = options.name.trim();
42273
+ if (!n)
42274
+ throw userError("--name cannot be empty.");
42275
+ update.name = n;
42276
+ }
42277
+ if (options.description !== undefined)
42278
+ update.description = options.description.trim();
42279
+ if (Object.keys(update).length === 0) {
42280
+ throw userError("Nothing to update — pass --name and/or --description.");
42281
+ }
42282
+ const client = getClient();
42283
+ const isUuid = UUID_RE2.test(target);
42284
+ const { data: project, error: lookupErr } = await client.raw.from("cerefox_projects").select("id, name").eq(isUuid ? "id" : "name", target).maybeSingle();
42285
+ if (lookupErr)
42286
+ throw systemError(`Lookup failed: ${lookupErr.message}`);
42287
+ if (!project)
42288
+ throw notFound(`Project "${target}" not found.`);
42289
+ const { data, error } = await client.raw.from("cerefox_projects").update(update).eq("id", project.id).select("id, name, description").maybeSingle();
42290
+ if (error || !data) {
42291
+ throw systemError(`Update failed: ${error?.message ?? "no row returned"}`);
42292
+ }
42293
+ println(c.green(`✓ Updated project "${data.name}" (id: ${data.id}).`));
42294
+ }
42295
+ function registerProjectEdit(parent) {
42296
+ parent.command("edit").description("Rename a project and/or change its description.").argument("<name-or-id>", "Project name (exact match) or UUID.").option("--name <new-name>", "New project name.").option("--description <text>", "New project description.").action(action13);
42033
42297
  }
42034
42298
 
42035
42299
  // src/cli/commands/version-archive.ts
@@ -42060,49 +42324,6 @@ function registerVersionArchive(parent) {
42060
42324
  parent.command("unarchive").description("Unarchive a document version (allow version cleanup again).").argument("<version-id>", "UUID of the version (from `cerefox version list`).").option("-a, --author <name>", "Caller identity (audit log).").option("--author-type <type>", "'user' or 'agent' (default: user).", "user").action((versionId, options) => setArchived(versionId, false, options));
42061
42325
  }
42062
42326
 
42063
- // src/cli/commands/docs.ts
42064
- init_cli_core();
42065
- init_bundled_docs();
42066
- import { spawnSync as spawnSync3 } from "node:child_process";
42067
- function openInBrowser(path) {
42068
- const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
42069
- const result = spawnSync3(cmd, [path], { stdio: "ignore" });
42070
- if (result.status !== 0) {
42071
- println(c.dim(`(could not auto-open; the file is at: ${path})`));
42072
- }
42073
- }
42074
- function action10(topic, options) {
42075
- const docs = listBundledDocs();
42076
- if (options.list || !topic && !options.print) {
42077
- if (docs.length === 0) {
42078
- println("(no bundled docs found)");
42079
- return;
42080
- }
42081
- println(c.bold("Available docs:"));
42082
- println("");
42083
- printTable(docs.map((d) => ({
42084
- topic: d.topic,
42085
- size_kb: Math.round(d.size / 1024) + " KB"
42086
- })));
42087
- println("");
42088
- println(c.dim("Run `cerefox docs <topic>` to open in browser, or `--print` for stdout."));
42089
- return;
42090
- }
42091
- const doc = topic ? readBundledDoc(topic) : null;
42092
- if (!doc) {
42093
- throw notFound(`No bundled doc named "${topic}".`, `Run \`cerefox docs --list\` to see available topics.`);
42094
- }
42095
- if (options.print) {
42096
- println(doc.content);
42097
- return;
42098
- }
42099
- println(c.dim(`Opening ${doc.path} …`));
42100
- openInBrowser(doc.path);
42101
- }
42102
- function registerDocs(program2) {
42103
- program2.command("docs").description("Open bundled Cerefox docs in your browser (or print to stdout).").argument("[topic]", "Doc topic (e.g. quickstart, connect-agents). Omit for the index.").option("--print", "Print to stdout instead of opening a browser.").option("--list", "List available topics.").action(action10);
42104
- }
42105
-
42106
42327
  // ../../node_modules/.bun/ora@9.4.0/node_modules/ora/index.js
42107
42328
  import process8 from "node:process";
42108
42329
  import { stripVTControlCharacters } from "node:util";
@@ -45490,12 +45711,12 @@ init_cli_core();
45490
45711
 
45491
45712
  // src/cli/util/checks.ts
45492
45713
  init_meta();
45493
- import { existsSync as existsSync8, readFileSync as readFileSync6, realpathSync, statSync as statSync2 } from "node:fs";
45494
- import { homedir as homedir4 } from "node:os";
45495
- import { join as join7 } from "node:path";
45714
+ import { existsSync as existsSync9, readFileSync as readFileSync7, realpathSync, statSync as statSync2 } from "node:fs";
45715
+ import { homedir as homedir5 } from "node:os";
45716
+ import { join as join8 } from "node:path";
45496
45717
 
45497
45718
  // ../../_shared/ef-meta/index.ts
45498
- var EF_VERSION = "0.8.0";
45719
+ var EF_VERSION = "0.9.1";
45499
45720
 
45500
45721
  // src/cli/util/checks.ts
45501
45722
  init_config();
@@ -45646,7 +45867,7 @@ function checkConfig() {
45646
45867
  hint: "Run `cerefox init` to bootstrap."
45647
45868
  };
45648
45869
  }
45649
- if (!existsSync8(envPath)) {
45870
+ if (!existsSync9(envPath)) {
45650
45871
  return {
45651
45872
  name: "config",
45652
45873
  status: "error",
@@ -45774,9 +45995,9 @@ var SCHEMA_VERSION_RE = /^--\s*@version:\s*(\S+)/m;
45774
45995
  function readBundledSchemaVersion() {
45775
45996
  try {
45776
45997
  const assets = resolveServerAssets();
45777
- if (!existsSync8(assets.schemaFile))
45998
+ if (!existsSync9(assets.schemaFile))
45778
45999
  return null;
45779
- const m = readFileSync6(assets.schemaFile, "utf8").match(SCHEMA_VERSION_RE);
46000
+ const m = readFileSync7(assets.schemaFile, "utf8").match(SCHEMA_VERSION_RE);
45780
46001
  return m ? m[1] : null;
45781
46002
  } catch {
45782
46003
  return null;
@@ -45845,10 +46066,10 @@ async function checkSchemaVersion() {
45845
46066
  }
45846
46067
  }
45847
46068
  function hasCerefoxInJsonFile(path) {
45848
- if (!existsSync8(path))
46069
+ if (!existsSync9(path))
45849
46070
  return false;
45850
46071
  try {
45851
- const parsed = JSON.parse(readFileSync6(path, "utf8"));
46072
+ const parsed = JSON.parse(readFileSync7(path, "utf8"));
45852
46073
  const mcpServers = parsed.mcpServers;
45853
46074
  return Boolean(mcpServers && typeof mcpServers === "object" && "cerefox" in mcpServers);
45854
46075
  } catch {
@@ -45856,10 +46077,10 @@ function hasCerefoxInJsonFile(path) {
45856
46077
  }
45857
46078
  }
45858
46079
  function checkMcpConfigs() {
45859
- const home = homedir4();
45860
- const claudeCodeUser = join7(home, ".claude.json");
45861
- const claudeCodeProj = join7(process.cwd(), ".mcp.json");
45862
- const claudeDesktop = process.platform === "darwin" ? join7(home, "Library", "Application Support", "Claude", "claude_desktop_config.json") : process.platform === "win32" ? join7(process.env.APPDATA ?? "", "Claude", "claude_desktop_config.json") : join7(home, ".config", "Claude", "claude_desktop_config.json");
46080
+ const home = homedir5();
46081
+ const claudeCodeUser = join8(home, ".claude.json");
46082
+ const claudeCodeProj = join8(process.cwd(), ".mcp.json");
46083
+ const claudeDesktop = process.platform === "darwin" ? join8(home, "Library", "Application Support", "Claude", "claude_desktop_config.json") : process.platform === "win32" ? join8(process.env.APPDATA ?? "", "Claude", "claude_desktop_config.json") : join8(home, ".config", "Claude", "claude_desktop_config.json");
45863
46084
  const found = [];
45864
46085
  if (hasCerefoxInJsonFile(claudeCodeUser))
45865
46086
  found.push("Claude Code (user)");
@@ -45882,10 +46103,10 @@ function checkMcpConfigs() {
45882
46103
  };
45883
46104
  }
45884
46105
  function checkLegacyShadowEnv() {
45885
- const home = homedir4();
45886
- const homeEnv = join7(home, USER_STATE_DIR_NAME, ".env");
45887
- const cwdEnv = join7(process.cwd(), ".env");
45888
- if (!existsSync8(homeEnv) || !existsSync8(cwdEnv))
46106
+ const home = homedir5();
46107
+ const homeEnv = join8(home, USER_STATE_DIR_NAME, ".env");
46108
+ const cwdEnv = join8(process.cwd(), ".env");
46109
+ if (!existsSync9(homeEnv) || !existsSync9(cwdEnv))
45889
46110
  return null;
45890
46111
  try {
45891
46112
  if (realpathSync(homeEnv) === realpathSync(cwdEnv))
@@ -46060,7 +46281,7 @@ function symbol(status) {
46060
46281
  return cErr.dim("ℹ");
46061
46282
  }
46062
46283
  }
46063
- async function action11(options) {
46284
+ async function action14(options) {
46064
46285
  const useSpinner = !options.json && process.stderr.isTTY;
46065
46286
  const spinner = useSpinner ? ora({ text: "Starting checks…", spinner: "dots", stream: process.stderr }).start() : null;
46066
46287
  const results = await runAllChecks({
@@ -46117,13 +46338,13 @@ async function action11(options) {
46117
46338
  }
46118
46339
  }
46119
46340
  function registerDoctor(program2) {
46120
- program2.command("doctor").description("Run diagnostic checks against the installed Cerefox.").option("--json", "Emit machine-readable JSON (no colours, structured output).").action(action11);
46341
+ program2.command("doctor").description("Run diagnostic checks against the installed Cerefox.").option("--json", "Emit machine-readable JSON (no colours, structured output).").action(action14);
46121
46342
  }
46122
46343
 
46123
46344
  // src/cli/commands/get-audit-log.ts
46124
46345
  init_cli_core();
46125
46346
  init_client();
46126
- async function action12(options) {
46347
+ async function action15(options) {
46127
46348
  const limit = parsePositiveInt(options.limit, "--limit", 50);
46128
46349
  const client = getClient();
46129
46350
  const data = await client.rpc("cerefox_list_audit_entries", {
@@ -46161,14 +46382,14 @@ async function action12(options) {
46161
46382
  })));
46162
46383
  }
46163
46384
  function registerGetAuditLog(program2) {
46164
- program2.command("get-audit-log").description("Query the audit log with optional filters.").option("-d, --document-id <uuid>", "Filter by document.").option("-a, --author <name>", "Filter by author.").option("-o, --operation <type>", "Filter by operation: create, update-content, update-metadata, delete, restore.").option("--since <iso>", "Lower-bound ISO timestamp.").option("--until <iso>", "Upper-bound ISO timestamp.").option("-l, --limit <n>", "Maximum entries (max 200).", "50").option("-r, --requestor <name>", "Agent / user name (usage log).").option("--json", "Emit machine-readable JSON.").action(action12);
46385
+ program2.command("get-audit-log").description("Query the audit log with optional filters.").option("-d, --document-id <uuid>", "Filter by document.").option("-a, --author <name>", "Filter by author.").option("-o, --operation <type>", "Filter by operation: create, update-content, update-metadata, delete, restore.").option("--since <iso>", "Lower-bound ISO timestamp.").option("--until <iso>", "Upper-bound ISO timestamp.").option("-l, --limit <n>", "Maximum entries (max 200).", "50").option("-r, --requestor <name>", "Agent / user name (usage log).").option("--json", "Emit machine-readable JSON.").action(action15);
46165
46386
  }
46166
46387
 
46167
46388
  // src/cli/commands/get-doc.ts
46168
46389
  init_cli_core();
46169
46390
  init_cli_core();
46170
46391
  init_client();
46171
- async function action13(documentId, options) {
46392
+ async function action16(documentId, options) {
46172
46393
  const client = getClient();
46173
46394
  const rows = await client.rpc("cerefox_get_document", {
46174
46395
  p_document_id: documentId,
@@ -46198,18 +46419,18 @@ async function action13(documentId, options) {
46198
46419
  println(doc.full_content);
46199
46420
  }
46200
46421
  function registerGetDoc(program2) {
46201
- program2.command("get-doc").description("Retrieve the full content of a document by ID.").argument("<document-id>", "UUID of the document.").option("--version-id <uuid>", "Specific archived version (default: current).").option("-r, --requestor <name>", "Agent / user name (usage log).").option("--json", "Emit machine-readable JSON.").action(action13);
46422
+ program2.command("get-doc").description("Retrieve the full content of a document by ID.").argument("<document-id>", "UUID of the document.").option("--version-id <uuid>", "Specific archived version (default: current).").option("-r, --requestor <name>", "Agent / user name (usage log).").option("--json", "Emit machine-readable JSON.").action(action16);
46202
46423
  }
46203
46424
 
46204
46425
  // src/cli/commands/ingest.ts
46205
46426
  init_dist4();
46206
46427
  init_cli_core();
46207
46428
  init_config();
46208
- import { readFileSync as readFileSync8 } from "node:fs";
46429
+ import { readFileSync as readFileSync9 } from "node:fs";
46209
46430
  import { basename as basename2, extname as extname2 } from "node:path";
46210
46431
 
46211
46432
  // src/ingestion/pipeline.ts
46212
- import { readFileSync as readFileSync7 } from "node:fs";
46433
+ import { readFileSync as readFileSync8 } from "node:fs";
46213
46434
  import { basename, extname, resolve as resolve3 } from "node:path";
46214
46435
 
46215
46436
  // ../../_shared/ingest/chunker.ts
@@ -46893,7 +47114,7 @@ ${c2.content}`);
46893
47114
  };
46894
47115
  }
46895
47116
  async ingestFile(path, opts = {}) {
46896
- const text = readFileSync7(path, "utf8");
47117
+ const text = readFileSync8(path, "utf8");
46897
47118
  const absPath = resolve3(path);
46898
47119
  const stem = basename(absPath, extname(absPath));
46899
47120
  return this.ingestText({
@@ -46927,7 +47148,7 @@ async function readContent(path, paste) {
46927
47148
  }
46928
47149
  let content;
46929
47150
  try {
46930
- content = readFileSync8(path, "utf8");
47151
+ content = readFileSync9(path, "utf8");
46931
47152
  } catch (err) {
46932
47153
  const msg = err instanceof Error ? err.message : String(err);
46933
47154
  throw userError(`Cannot read ${path}: ${msg}`);
@@ -46935,7 +47156,7 @@ async function readContent(path, paste) {
46935
47156
  const titleFromPath = basename2(path, extname2(path));
46936
47157
  return { content, titleFromPath };
46937
47158
  }
46938
- async function action14(path, options) {
47159
+ async function action17(path, options) {
46939
47160
  const { content, titleFromPath } = await readContent(path, Boolean(options.paste));
46940
47161
  const title = options.title ?? titleFromPath;
46941
47162
  if (!title || title.trim() === "") {
@@ -47007,7 +47228,7 @@ async function action14(path, options) {
47007
47228
  }
47008
47229
  }
47009
47230
  function registerIngest(program2) {
47010
- program2.command("ingest").description("Ingest a file (or stdin paste) into the knowledge base.").argument("[path]", "Path to the file to ingest. Omit when using --paste.").option("--paste", "Read content from stdin instead of a file.").option("-t, --title <title>", "Document title (required with --paste; defaults to filename without extension).").option("-p, --project-name <name>", "Single project membership (non-destructive on update).").option("-P, --project-names <names>", "Comma-separated full project membership set (destructive replace on update).").option("-m, --metadata <json>", "JSON metadata object.").option("--source <label>", "Origin label (default: cli).", "cli").option("-u, --update-if-exists", "Update an existing doc with the same title.").option("-i, --document-id <uuid>", "Update a specific document by UUID (overrides --update-if-exists).").option("-a, --author <name>", "Caller identity (audit log).").option("--author-type <type>", "'user' or 'agent' (default: user).", "user").action(action14);
47231
+ program2.command("ingest").description("Ingest a file (or stdin paste) into the knowledge base.").argument("[path]", "Path to the file to ingest. Omit when using --paste.").option("--paste", "Read content from stdin instead of a file.").option("-t, --title <title>", "Document title (required with --paste; defaults to filename without extension).").option("-p, --project-name <name>", "Single project membership (non-destructive on update).").option("-P, --project-names <names>", "Comma-separated full project membership set (destructive replace on update).").option("-m, --metadata <json>", "JSON metadata object.").option("--source <label>", "Origin label (default: cli).", "cli").option("-u, --update-if-exists", "Update an existing doc with the same title.").option("-i, --document-id <uuid>", "Update a specific document by UUID (overrides --update-if-exists).").option("-a, --author <name>", "Caller identity (audit log).").option("--author-type <type>", "'user' or 'agent' (default: user).", "user").action(action17);
47011
47232
  }
47012
47233
 
47013
47234
  // src/cli/commands/ingest-dir.ts
@@ -47016,7 +47237,7 @@ init_cli_core();
47016
47237
  init_config();
47017
47238
  var import_cli_progress = __toESM(require_cli_progress(), 1);
47018
47239
  import { readdirSync as readdirSync4, statSync as statSync3 } from "node:fs";
47019
- import { basename as basename3, extname as extname3, join as join8 } from "node:path";
47240
+ import { basename as basename3, extname as extname3, join as join9 } from "node:path";
47020
47241
  function walk(dir, extensions) {
47021
47242
  let entries;
47022
47243
  try {
@@ -47026,7 +47247,7 @@ function walk(dir, extensions) {
47026
47247
  }
47027
47248
  const files = [];
47028
47249
  for (const name of entries) {
47029
- const full = join8(dir, name);
47250
+ const full = join9(dir, name);
47030
47251
  let stat;
47031
47252
  try {
47032
47253
  stat = statSync3(full);
@@ -47043,7 +47264,7 @@ function walk(dir, extensions) {
47043
47264
  }
47044
47265
  return files;
47045
47266
  }
47046
- async function action15(dir, options) {
47267
+ async function action18(dir, options) {
47047
47268
  const extensions = new Set((options.extensions ?? ".md,.txt").split(",").map((e) => e.trim().toLowerCase()).map((e) => e.startsWith(".") ? e : "." + e).filter((e) => e.length > 0));
47048
47269
  const files = walk(dir, extensions);
47049
47270
  if (files.length === 0) {
@@ -47116,7 +47337,7 @@ async function action15(dir, options) {
47116
47337
  }
47117
47338
  }
47118
47339
  function registerIngestDir(program2) {
47119
- program2.command("ingest-dir").description("Recursively ingest a directory of markdown / text files.").argument("<dir>", "Root directory to walk.").option("-p, --project-name <name>", "Project membership for all ingested docs.").option("-m, --metadata <json>", "JSON metadata applied to every doc.").option("--source <label>", "Origin label (default: cli).", "cli").option("-u, --update-if-exists", "Update an existing doc with the same title.").option("-a, --author <name>", "Caller identity (audit log).").option("--author-type <type>", "'user' or 'agent' (default: user).", "user").option("-e, --extensions <list>", "Comma-separated file extensions to ingest.", ".md,.txt").action(action15);
47340
+ program2.command("ingest-dir").description("Recursively ingest a directory of markdown / text files.").argument("<dir>", "Root directory to walk.").option("-p, --project-name <name>", "Project membership for all ingested docs.").option("-m, --metadata <json>", "JSON metadata applied to every doc.").option("--source <label>", "Origin label (default: cli).", "cli").option("-u, --update-if-exists", "Update an existing doc with the same title.").option("-a, --author <name>", "Caller identity (audit log).").option("--author-type <type>", "'user' or 'agent' (default: user).", "user").option("-e, --extensions <list>", "Comma-separated file extensions to ingest.", ".md,.txt").action(action18);
47120
47341
  }
47121
47342
 
47122
47343
  // src/cli/commands/init.ts
@@ -47126,20 +47347,20 @@ import { spawnSync as spawnSync4 } from "node:child_process";
47126
47347
  import {
47127
47348
  chmodSync,
47128
47349
  copyFileSync as copyFileSync2,
47129
- existsSync as existsSync9,
47350
+ existsSync as existsSync10,
47130
47351
  mkdirSync as mkdirSync3,
47131
- readFileSync as readFileSync10,
47132
- writeFileSync as writeFileSync3
47352
+ readFileSync as readFileSync11,
47353
+ writeFileSync as writeFileSync4
47133
47354
  } from "node:fs";
47134
- import { homedir as homedir5 } from "node:os";
47135
- import { dirname as dirname4, join as join9 } from "node:path";
47355
+ import { homedir as homedir6 } from "node:os";
47356
+ import { dirname as dirname4, join as join10 } from "node:path";
47136
47357
  async function readConfigFile(path) {
47137
- if (!existsSync9(path)) {
47358
+ if (!existsSync10(path)) {
47138
47359
  throw userError(`--config file not found: ${path}`);
47139
47360
  }
47140
47361
  let parsed;
47141
47362
  try {
47142
- parsed = JSON.parse(readFileSync10(path, "utf8"));
47363
+ parsed = JSON.parse(readFileSync11(path, "utf8"));
47143
47364
  } catch (err) {
47144
47365
  throw userError(`--config: invalid JSON in ${path}: ${err instanceof Error ? err.message : String(err)}`);
47145
47366
  }
@@ -47181,7 +47402,7 @@ function parseDotEnvFile(content) {
47181
47402
  return map;
47182
47403
  }
47183
47404
  function answersFromEnvFile(path) {
47184
- const parsed = parseDotEnvFile(readFileSync10(path, "utf8"));
47405
+ const parsed = parseDotEnvFile(readFileSync11(path, "utf8"));
47185
47406
  const required = ["CEREFOX_SUPABASE_URL", "CEREFOX_SUPABASE_KEY", "OPENAI_API_KEY"];
47186
47407
  for (const key of required) {
47187
47408
  if (!parsed[key] || parsed[key].trim() === "") {
@@ -47437,7 +47658,7 @@ async function postWriteLifecycle(envPath, options) {
47437
47658
  }
47438
47659
  function writeAnswersTo(target, answers) {
47439
47660
  mkdirSync3(dirname4(target), { recursive: true });
47440
- writeFileSync3(target, buildEnvFile(answers), "utf8");
47661
+ writeFileSync4(target, buildEnvFile(answers), "utf8");
47441
47662
  if (process.platform !== "win32") {
47442
47663
  try {
47443
47664
  chmodSync(target, 384);
@@ -47446,13 +47667,13 @@ function writeAnswersTo(target, answers) {
47446
47667
  }
47447
47668
  }
47448
47669
  }
47449
- async function action17(options) {
47450
- const homeEnv = join9(homedir5(), USER_STATE_DIR_NAME, ".env");
47451
- const cwdEnv = join9(process.cwd(), ".env");
47670
+ async function action20(options) {
47671
+ const homeEnv = join10(homedir6(), USER_STATE_DIR_NAME, ".env");
47672
+ const cwdEnv = join10(process.cwd(), ".env");
47452
47673
  const explicitDir = (process.env.CEREFOX_CONFIG_DIR ?? "").trim();
47453
47674
  if (explicitDir) {
47454
47675
  const target2 = resolveEnvFile();
47455
- if (existsSync9(target2) && !options.force) {
47676
+ if (existsSync10(target2) && !options.force) {
47456
47677
  println(c.yellow(`⚠ Config already exists at ${target2}.`));
47457
47678
  const ok2 = await confirm("Overwrite?", true);
47458
47679
  if (!ok2) {
@@ -47474,7 +47695,7 @@ async function action17(options) {
47474
47695
  await postWriteLifecycle(target2, options);
47475
47696
  return;
47476
47697
  }
47477
- if (existsSync9(homeEnv) && !options.force) {
47698
+ if (existsSync10(homeEnv) && !options.force) {
47478
47699
  println(c.yellow(`⚠ Config already exists at ${homeEnv}.`));
47479
47700
  const ok2 = await confirm("Overwrite?", true);
47480
47701
  if (!ok2) {
@@ -47495,7 +47716,7 @@ async function action17(options) {
47495
47716
  await postWriteLifecycle(homeEnv, options);
47496
47717
  return;
47497
47718
  }
47498
- if (existsSync9(cwdEnv) && !options.force && !options.config) {
47719
+ if (existsSync10(cwdEnv) && !options.force && !options.config) {
47499
47720
  printMigrationMenu(cwdEnv, homeEnv);
47500
47721
  const ch = await promptMigrationChoice();
47501
47722
  println("");
@@ -47555,13 +47776,13 @@ async function action17(options) {
47555
47776
  await postWriteLifecycle(target, options);
47556
47777
  }
47557
47778
  function registerInit(program2) {
47558
- 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(action17);
47779
+ 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(action20);
47559
47780
  }
47560
47781
 
47561
47782
  // src/cli/commands/list-docs.ts
47562
47783
  init_cli_core();
47563
47784
  init_client();
47564
- async function action18(options) {
47785
+ async function action21(options) {
47565
47786
  const limit = parsePositiveInt(options.limit, "--limit", 100);
47566
47787
  const client = getClient();
47567
47788
  let projectId;
@@ -47616,13 +47837,13 @@ async function action18(options) {
47616
47837
  })));
47617
47838
  }
47618
47839
  function registerListDocs(program2) {
47619
- program2.command("list-docs").description("List documents in the knowledge base.").option("-p, --project <name>", "Filter to a specific project.").option("-l, --limit <n>", "Maximum docs to return.", "100").option("--json", "Emit machine-readable JSON.").action(action18);
47840
+ program2.command("list-docs").description("List documents in the knowledge base.").option("-p, --project <name>", "Filter to a specific project.").option("-l, --limit <n>", "Maximum docs to return.", "100").option("--json", "Emit machine-readable JSON.").action(action21);
47620
47841
  }
47621
47842
 
47622
47843
  // src/cli/commands/list-metadata-keys.ts
47623
47844
  init_cli_core();
47624
47845
  init_client();
47625
- async function action19(options) {
47846
+ async function action22(options) {
47626
47847
  const client = getClient();
47627
47848
  const data = await client.rpc("cerefox_list_metadata_keys");
47628
47849
  if (data === null) {
@@ -47650,13 +47871,13 @@ async function action19(options) {
47650
47871
  })));
47651
47872
  }
47652
47873
  function registerListMetadataKeys(program2) {
47653
- program2.command("list-metadata-keys").description("List all metadata keys with document counts and example values.").option("-r, --requestor <name>", "Agent / user name (usage log).").option("--json", "Emit machine-readable JSON.").action(action19);
47874
+ program2.command("list-metadata-keys").description("List all metadata keys with document counts and example values.").option("-r, --requestor <name>", "Agent / user name (usage log).").option("--json", "Emit machine-readable JSON.").action(action22);
47654
47875
  }
47655
47876
 
47656
47877
  // src/cli/commands/list-projects.ts
47657
47878
  init_cli_core();
47658
47879
  init_client();
47659
- async function action20(options) {
47880
+ async function action23(options) {
47660
47881
  const client = getClient();
47661
47882
  const { data, error: error2 } = await client.raw.from("cerefox_projects").select("id, name, description, created_at").order("name", { ascending: true });
47662
47883
  if (error2) {
@@ -47685,13 +47906,13 @@ async function action20(options) {
47685
47906
  })), "(no projects)");
47686
47907
  }
47687
47908
  function registerListProjects(program2) {
47688
- program2.command("list-projects").description("List all projects in the knowledge base.").option("-r, --requestor <name>", "Agent / user name (usage log).").option("--json", "Emit machine-readable JSON.").action(action20);
47909
+ program2.command("list-projects").description("List all projects in the knowledge base.").option("-r, --requestor <name>", "Agent / user name (usage log).").option("--json", "Emit machine-readable JSON.").action(action23);
47689
47910
  }
47690
47911
 
47691
47912
  // src/cli/commands/list-versions.ts
47692
47913
  init_cli_core();
47693
47914
  init_client();
47694
- async function action21(documentId, options) {
47915
+ async function action24(documentId, options) {
47695
47916
  const client = getClient();
47696
47917
  const data = await client.rpc("cerefox_list_document_versions", {
47697
47918
  p_document_id: documentId
@@ -47732,7 +47953,7 @@ async function action21(documentId, options) {
47732
47953
  })));
47733
47954
  }
47734
47955
  function registerListVersions(program2) {
47735
- program2.command("list-versions").description("List archived versions of a document.").argument("<document-id>", "UUID of the document.").option("-r, --requestor <name>", "Agent / user name (usage log).").option("--json", "Emit machine-readable JSON.").action(action21);
47956
+ program2.command("list-versions").description("List archived versions of a document.").argument("<document-id>", "UUID of the document.").option("-r, --requestor <name>", "Agent / user name (usage log).").option("--json", "Emit machine-readable JSON.").action(action24);
47736
47957
  }
47737
47958
 
47738
47959
  // src/cli/commands/mcp.ts
@@ -47747,7 +47968,7 @@ function registerMcp(program2) {
47747
47968
  // src/cli/commands/metadata-search.ts
47748
47969
  init_cli_core();
47749
47970
  init_client();
47750
- async function action22(options) {
47971
+ async function action25(options) {
47751
47972
  const metadataFilter = parseJsonObjectArg(options.metadataFilter, "--metadata-filter");
47752
47973
  if (!metadataFilter || Object.keys(metadataFilter).length === 0) {
47753
47974
  throw userError("--metadata-filter is required and must be a non-empty JSON object.", `Example: --metadata-filter '{"type":"decision-log"}'.`);
@@ -47810,7 +48031,7 @@ async function action22(options) {
47810
48031
  }
47811
48032
  }
47812
48033
  function registerMetadataSearch(program2) {
47813
- program2.command("metadata-search").description("Find documents by metadata criteria (no text query).").requiredOption("-f, --metadata-filter <json>", "JSON object; only docs whose metadata contains ALL pairs are returned.").option("-p, --project-name <name>", "Filter to a specific project.").option("--updated-since <iso>", "Only docs updated on/after this ISO timestamp.").option("--created-since <iso>", "Only docs created on/after this ISO timestamp.").option("--include-content", "Include full document text in results.").option("-l, --limit <n>", "Maximum docs to return.", "10").option("--max-bytes <n>", "Response size budget in bytes (with --include-content).", "200000").option("-r, --requestor <name>", "Agent / user name (usage log).").option("--json", "Emit machine-readable JSON.").action(action22);
48034
+ program2.command("metadata-search").description("Find documents by metadata criteria (no text query).").requiredOption("-f, --metadata-filter <json>", "JSON object; only docs whose metadata contains ALL pairs are returned.").option("-p, --project-name <name>", "Filter to a specific project.").option("--updated-since <iso>", "Only docs updated on/after this ISO timestamp.").option("--created-since <iso>", "Only docs created on/after this ISO timestamp.").option("--include-content", "Include full document text in results.").option("-l, --limit <n>", "Maximum docs to return.", "10").option("--max-bytes <n>", "Response size budget in bytes (with --include-content).", "200000").option("-r, --requestor <name>", "Agent / user name (usage log).").option("--json", "Emit machine-readable JSON.").action(action25);
47814
48035
  }
47815
48036
 
47816
48037
  // src/cli/commands/reindex.ts
@@ -47818,7 +48039,7 @@ init_dist4();
47818
48039
  init_cli_core();
47819
48040
  init_config();
47820
48041
  var DEFAULT_MODEL = "text-embedding-3-small";
47821
- async function action23(options) {
48042
+ async function action26(options) {
47822
48043
  const settings = loadSettings();
47823
48044
  if (!settings.supabaseUrl || !settings.supabaseKey) {
47824
48045
  throw userError("Supabase credentials not configured — run `cerefox init` first.");
@@ -47897,41 +48118,41 @@ ${c2.content}`;
47897
48118
  }
47898
48119
  }
47899
48120
  function registerReindex(program2) {
47900
- 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(action23);
48121
+ 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(action26);
47901
48122
  }
47902
48123
 
47903
48124
  // src/cli/commands/restore.ts
47904
48125
  init_cli_core();
47905
48126
  init_client();
47906
- import { existsSync as existsSync10, readFileSync as readFileSync11, readdirSync as readdirSync5, statSync as statSync4 } from "node:fs";
47907
- import { homedir as homedir6 } from "node:os";
47908
- import { join as join10, resolve as resolve4 } from "node:path";
48127
+ import { existsSync as existsSync11, readFileSync as readFileSync12, readdirSync as readdirSync5, statSync as statSync4 } from "node:fs";
48128
+ import { homedir as homedir7 } from "node:os";
48129
+ import { join as join11, resolve as resolve4 } from "node:path";
47909
48130
  function expandHome2(path) {
47910
48131
  if (path === "~")
47911
- return homedir6();
48132
+ return homedir7();
47912
48133
  if (path.startsWith("~/"))
47913
- return join10(homedir6(), path.slice(2));
48134
+ return join11(homedir7(), path.slice(2));
47914
48135
  return path;
47915
48136
  }
47916
48137
  function resolveBackupFile(target) {
47917
48138
  const path = resolve4(expandHome2(target));
47918
- if (!existsSync10(path)) {
48139
+ if (!existsSync11(path)) {
47919
48140
  throw userError(`Backup path not found: ${target}`);
47920
48141
  }
47921
48142
  const stat = statSync4(path);
47922
48143
  if (stat.isFile())
47923
48144
  return path;
47924
- const candidates = readdirSync5(path).filter((n) => n.endsWith(".json") && n.startsWith("cerefox-")).map((n) => ({ name: n, mtime: statSync4(join10(path, n)).mtimeMs })).sort((a, b2) => b2.mtime - a.mtime);
48145
+ const candidates = readdirSync5(path).filter((n) => n.endsWith(".json") && n.startsWith("cerefox-")).map((n) => ({ name: n, mtime: statSync4(join11(path, n)).mtimeMs })).sort((a, b2) => b2.mtime - a.mtime);
47925
48146
  if (candidates.length === 0) {
47926
48147
  throw userError(`No cerefox-*.json files in ${path}`);
47927
48148
  }
47928
- return join10(path, candidates[0].name);
48149
+ return join11(path, candidates[0].name);
47929
48150
  }
47930
- async function action24(target, options) {
48151
+ async function action27(target, options) {
47931
48152
  const file = resolveBackupFile(target);
47932
48153
  let payload;
47933
48154
  try {
47934
- payload = JSON.parse(readFileSync11(file, "utf8"));
48155
+ payload = JSON.parse(readFileSync12(file, "utf8"));
47935
48156
  } catch (err) {
47936
48157
  throw userError(`Could not parse backup file ${file}: ${err instanceof Error ? err.message : String(err)}`);
47937
48158
  }
@@ -47983,7 +48204,7 @@ async function action24(target, options) {
47983
48204
  }
47984
48205
  }
47985
48206
  function registerRestore(program2) {
47986
- 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 ride along with each doc's metadata).").action(action24);
48207
+ 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 ride along with each doc's metadata).").action(action27);
47987
48208
  }
47988
48209
 
47989
48210
  // src/cli/commands/search.ts
@@ -48008,7 +48229,7 @@ async function embedQuery(query) {
48008
48229
  }
48009
48230
 
48010
48231
  // src/cli/commands/search.ts
48011
- async function action25(query, options) {
48232
+ async function action28(query, options) {
48012
48233
  if (!query || query.trim() === "") {
48013
48234
  throw userError("Empty query.");
48014
48235
  }
@@ -48097,8 +48318,14 @@ async function action25(query, options) {
48097
48318
  p_result_count: accepted.length
48098
48319
  }).then(() => {}, () => {});
48099
48320
  if (options.json) {
48321
+ const jsonResults = options.onlyMetadata ? accepted.map((r) => {
48322
+ const copy = { ...r };
48323
+ delete copy.full_content;
48324
+ delete copy.content;
48325
+ return copy;
48326
+ }) : accepted;
48100
48327
  printJson({
48101
- results: accepted,
48328
+ results: jsonResults,
48102
48329
  query,
48103
48330
  mode,
48104
48331
  match_count: matchCount,
@@ -48118,13 +48345,25 @@ async function action25(query, options) {
48118
48345
  const doc2 = row;
48119
48346
  const title = doc2.doc_title ?? "Untitled";
48120
48347
  const docId = doc2.document_id ? ` [id: ${doc2.document_id}]` : "";
48121
- const score = doc2.best_score != null ? ` (score: ${doc2.best_score.toFixed(3)})` : "";
48122
- const partial2 = doc2.is_partial ? ` -- partial (${doc2.chunk_count} of ${doc2.total_chars.toLocaleString()} chars)` : "";
48123
- println(c.bold(`## ${title}${docId}${score}${partial2}`));
48348
+ const score = doc2.best_score != null ? ` · score ${doc2.best_score.toFixed(3)}` : "";
48349
+ const counts = ` · ${doc2.chunk_count} chunk${doc2.chunk_count === 1 ? "" : "s"} · ${doc2.total_chars.toLocaleString()} chars`;
48350
+ const kind = doc2.is_partial ? " · partial" : " · full";
48351
+ println(c.bold(`## ${title}${docId}${score}${counts}${kind}`));
48352
+ const bestMatch = doc2.best_chunk_heading_path?.length ? doc2.best_chunk_heading_path.join(" › ") : null;
48353
+ const updated = doc2.doc_updated_at ? doc2.doc_updated_at.slice(0, 10) : null;
48354
+ if (bestMatch || updated) {
48355
+ const bits = [
48356
+ bestMatch ? `best match: ${bestMatch}` : null,
48357
+ updated ? `updated ${updated}` : null
48358
+ ].filter(Boolean);
48359
+ println(c.dim(` ${bits.join(" · ")}`));
48360
+ }
48361
+ if (options.onlyMetadata)
48362
+ continue;
48124
48363
  println("");
48125
48364
  println(doc2.full_content ?? "");
48126
48365
  println("");
48127
- println(c.dim("---"));
48366
+ println(c.dim("════════════════════════════════════════"));
48128
48367
  println("");
48129
48368
  } else {
48130
48369
  const chunk = row;
@@ -48142,7 +48381,7 @@ async function action25(query, options) {
48142
48381
  }
48143
48382
  }
48144
48383
  function registerSearch(program2) {
48145
- 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: 0.7).", "0.7").option("--min-score <float>", "Minimum cosine similarity threshold.", "0.5").option("--max-bytes <n>", "Response size budget in bytes.", "200000").option("-r, --requestor <name>", "Agent / user name (recorded in usage log).").option("--json", "Emit machine-readable JSON instead of the default text.").action(action25);
48384
+ 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: 0.7).", "0.7").option("--min-score <float>", "Minimum cosine similarity threshold.", "0.5").option("--max-bytes <n>", "Response size budget in bytes.", "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(action28);
48146
48385
  }
48147
48386
 
48148
48387
  // src/cli/commands/self-update.ts
@@ -48189,7 +48428,7 @@ async function fetchLatestVersion() {
48189
48428
  }
48190
48429
  return body.version;
48191
48430
  }
48192
- async function action26(options) {
48431
+ async function action29(options) {
48193
48432
  let target;
48194
48433
  try {
48195
48434
  target = options.version ?? await fetchLatestVersion();
@@ -48241,7 +48480,7 @@ async function action26(options) {
48241
48480
  }
48242
48481
  function registerSelfUpdate(program2) {
48243
48482
  const desc = "Upgrade Cerefox in place. Alias: `cerefox upgrade`.";
48244
- 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(action26);
48483
+ 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(action29);
48245
48484
  declaration(program2.command("self-update"));
48246
48485
  declaration(program2.command("upgrade"));
48247
48486
  }
@@ -48260,7 +48499,7 @@ function symbol2(status) {
48260
48499
  return cErr.dim("ℹ");
48261
48500
  }
48262
48501
  }
48263
- async function action27(options) {
48502
+ async function action30(options) {
48264
48503
  const useSpinner = !options.json && process.stderr.isTTY;
48265
48504
  const spinner = useSpinner ? ora({ text: "Starting checks…", spinner: "dots", stream: process.stderr }).start() : null;
48266
48505
  const results = await runFastChecks({
@@ -48281,105 +48520,7 @@ async function action27(options) {
48281
48520
  }
48282
48521
  }
48283
48522
  function registerStatus(program2) {
48284
- program2.command("status").description("Quick sanity check (fast subset of `cerefox doctor`).").option("--json", "Emit machine-readable JSON.").action(action27);
48285
- }
48286
-
48287
- // src/cli/commands/sync-docs.ts
48288
- init_cli_core();
48289
- init_mcp_tools();
48290
- init_config();
48291
- init_client();
48292
- import {
48293
- existsSync as existsSync11,
48294
- readFileSync as readFileSync12,
48295
- readdirSync as readdirSync6,
48296
- statSync as statSync5
48297
- } from "node:fs";
48298
- import { basename as basename5, extname as extname5, join as join11, relative } from "node:path";
48299
- var ROOT_LEVEL_DOCS = ["README.md", "AGENT_GUIDE.md", "AGENT_QUICK_REFERENCE.md"];
48300
- function walkMarkdown(dir) {
48301
- const out = [];
48302
- if (!existsSync11(dir))
48303
- return out;
48304
- for (const name of readdirSync6(dir)) {
48305
- const full = join11(dir, name);
48306
- let stat;
48307
- try {
48308
- stat = statSync5(full);
48309
- } catch {
48310
- continue;
48311
- }
48312
- if (stat.isDirectory()) {
48313
- out.push(...walkMarkdown(full));
48314
- } else if (stat.isFile() && name.toLowerCase().endsWith(".md")) {
48315
- out.push(full);
48316
- }
48317
- }
48318
- return out;
48319
- }
48320
- async function action28(options) {
48321
- const cwd = process.cwd();
48322
- const project = options.project ?? "cerefox";
48323
- const targets = [];
48324
- for (const rel of ROOT_LEVEL_DOCS) {
48325
- const abs = join11(cwd, rel);
48326
- if (existsSync11(abs))
48327
- targets.push({ abs, rel });
48328
- }
48329
- for (const abs of walkMarkdown(join11(cwd, "docs"))) {
48330
- targets.push({ abs, rel: relative(cwd, abs) });
48331
- }
48332
- if (targets.length === 0) {
48333
- println(c.dim(`(no markdown files found in ${cwd})`));
48334
- return;
48335
- }
48336
- println(c.bold(`Syncing ${targets.length} markdown file(s) to project "${project}"`));
48337
- if (options.dryRun)
48338
- println(c.yellow("(dry run — no writes)"));
48339
- println("");
48340
- if (options.dryRun) {
48341
- printTable(targets.map((t) => ({
48342
- file: t.rel,
48343
- title: basename5(t.abs, extname5(t.abs))
48344
- })));
48345
- return;
48346
- }
48347
- const client = getClient();
48348
- const settings = loadSettings();
48349
- const author = resolveAuthor(undefined);
48350
- const authorType = resolveAuthorType("agent");
48351
- const outcomes = [];
48352
- for (const t of targets) {
48353
- const content = readFileSync12(t.abs, "utf8");
48354
- const title = basename5(t.abs, extname5(t.abs));
48355
- try {
48356
- const message = await ingestTool.handler(client.raw, {
48357
- title,
48358
- content,
48359
- source: "sync-docs",
48360
- metadata: { source_path: t.rel },
48361
- update_if_exists: true,
48362
- project_name: project,
48363
- author,
48364
- author_type: authorType
48365
- }, { openaiApiKey: settings.openaiApiKey, accessPath: "cli" });
48366
- outcomes.push({ file: t.rel, status: "ok", detail: message });
48367
- } catch (err) {
48368
- const msg = err instanceof Error ? err.message : String(err);
48369
- outcomes.push({ file: t.rel, status: "error", detail: msg });
48370
- }
48371
- }
48372
- const ok2 = outcomes.filter((o) => o.status === "ok");
48373
- const errs = outcomes.filter((o) => o.status === "error");
48374
- println("");
48375
- println(c.bold(`Summary: ${ok2.length} ok · ${errs.length} error${errs.length === 1 ? "" : "s"}`));
48376
- if (errs.length > 0) {
48377
- println("");
48378
- printTable(errs.map((e) => ({ file: e.file, error: e.detail.slice(0, 100) })));
48379
- }
48380
- }
48381
- function registerSyncDocs(program2) {
48382
- program2.command("sync-docs").description("Sync repo docs (README, AGENT_*, docs/) into a Cerefox project.").option("--dry-run", "Print what would be synced without writing.").option("-p, --project <name>", "Target project for the sync.", "cerefox").action(action28);
48523
+ program2.command("status").description("Quick sanity check (fast subset of `cerefox doctor`).").option("--json", "Emit machine-readable JSON.").action(action30);
48383
48524
  }
48384
48525
 
48385
48526
  // src/cli/program.ts
@@ -49714,7 +49855,7 @@ var _baseMimes = {
49714
49855
  var baseMimes = _baseMimes;
49715
49856
 
49716
49857
  // ../../node_modules/.bun/@hono+node-server@2.0.4+1bbe96acb4c5ebf1/node_modules/@hono/node-server/dist/serve-static.mjs
49717
- import { createReadStream, existsSync as existsSync12, statSync as statSync6 } from "node:fs";
49858
+ import { createReadStream, existsSync as existsSync12, statSync as statSync5 } from "node:fs";
49718
49859
  import { join as join12 } from "node:path";
49719
49860
  var COMPRESSIBLE_CONTENT_TYPE_REGEX = /^\s*(?:text\/[^;\s]+|application\/(?:javascript|json|xml|xml-dtd|ecmascript|dart|postscript|rtf|tar|toml|vnd\.dart|vnd\.ms-fontobject|vnd\.ms-opentype|wasm|x-httpd-php|x-javascript|x-ns-proxy-autoconfig|x-sh|x-tar|x-virtualbox-hdd|x-virtualbox-ova|x-virtualbox-ovf|x-virtualbox-vbox|x-virtualbox-vdi|x-virtualbox-vhd|x-virtualbox-vmdk|x-www-form-urlencoded)|font\/(?:otf|ttf)|image\/(?:bmp|vnd\.adobe\.photoshop|vnd\.microsoft\.icon|vnd\.ms-dds|x-icon|x-ms-bmp)|message\/rfc822|model\/gltf-binary|x-shader\/x-fragment|x-shader\/x-vertex|[^;\s]+?\+(?:json|text|xml|yaml))(?:[;\s]|$)/i;
49720
49861
  var ENCODINGS = {
@@ -49726,7 +49867,7 @@ var ENCODINGS_ORDERED_KEYS = Object.keys(ENCODINGS);
49726
49867
  var getStats = (path) => {
49727
49868
  let stats;
49728
49869
  try {
49729
- stats = statSync6(path);
49870
+ stats = statSync5(path);
49730
49871
  } catch {}
49731
49872
  return stats;
49732
49873
  };
@@ -51634,7 +51775,7 @@ function registerConfigRoutes(app, ctx) {
51634
51775
  }
51635
51776
 
51636
51777
  // src/web/routes/discovery.ts
51637
- var UUID_RE2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
51778
+ var UUID_RE3 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
51638
51779
  var DOC_COLS = "id, title, source, source_path, content_hash, metadata, chunk_count, total_chars, review_status, created_at, updated_at, deleted_at";
51639
51780
  function jsonByteLength(value) {
51640
51781
  return Buffer.byteLength(JSON.stringify(value), "utf8");
@@ -52080,7 +52221,7 @@ function registerDiscoveryRoutes(app, ctx) {
52080
52221
  if (!path) {
52081
52222
  return c2.json({ tried_path: "", anchor, matches: [] });
52082
52223
  }
52083
- if (UUID_RE2.test(path)) {
52224
+ if (UUID_RE3.test(path)) {
52084
52225
  if (path === fromDocId) {
52085
52226
  return c2.json({ tried_path: path, anchor, matches: [] });
52086
52227
  }
@@ -52106,7 +52247,7 @@ function registerDiscoveryRoutes(app, ctx) {
52106
52247
  if (!normalised) {
52107
52248
  return c2.json({ tried_path: "", anchor, matches: [] });
52108
52249
  }
52109
- const basename6 = normalised.split("/").pop() ?? normalised;
52250
+ const basename5 = normalised.split("/").pop() ?? normalised;
52110
52251
  const project = (rows, method) => rows.filter((r) => r.id !== fromDocId).map((r) => ({
52111
52252
  document_id: r.id,
52112
52253
  title: r.title ?? "",
@@ -52121,8 +52262,8 @@ function registerDiscoveryRoutes(app, ctx) {
52121
52262
  return c2.json({ tried_path: normalised, anchor, matches });
52122
52263
  }
52123
52264
  }
52124
- if (basename6 !== normalised) {
52125
- const { data } = await ctx.supabase.from("cerefox_documents").select("id, title, source_path").is("deleted_at", null).like("source_path", `%/${basename6}`).order("updated_at", { ascending: false }).limit(limit);
52265
+ if (basename5 !== normalised) {
52266
+ const { data } = await ctx.supabase.from("cerefox_documents").select("id, title, source_path").is("deleted_at", null).like("source_path", `%/${basename5}`).order("updated_at", { ascending: false }).limit(limit);
52126
52267
  const rows = data ?? [];
52127
52268
  const matches = project(rows, "basename");
52128
52269
  if (matches.length > 0) {
@@ -52130,7 +52271,7 @@ function registerDiscoveryRoutes(app, ctx) {
52130
52271
  }
52131
52272
  }
52132
52273
  {
52133
- const stem = basename6.replace(/\.md$/i, "").replace(/[-_]+/g, " ").trim();
52274
+ const stem = basename5.replace(/\.md$/i, "").replace(/[-_]+/g, " ").trim();
52134
52275
  if (stem) {
52135
52276
  const { data } = await ctx.supabase.from("cerefox_documents").select("id, title, source_path").is("deleted_at", null).ilike("title", `%${stem}%`).order("updated_at", { ascending: false }).limit(limit);
52136
52277
  const rows = data ?? [];
@@ -52678,10 +52819,10 @@ import { execFileSync } from "node:child_process";
52678
52819
  import {
52679
52820
  existsSync as existsSync13,
52680
52821
  readFileSync as readFileSync13,
52681
- readdirSync as readdirSync7,
52682
- statSync as statSync7
52822
+ readdirSync as readdirSync6,
52823
+ statSync as statSync6
52683
52824
  } from "node:fs";
52684
- import { basename as basename6, dirname as dirname5, join as join13, resolve as resolve5 } from "node:path";
52825
+ import { basename as basename5, dirname as dirname5, join as join13, resolve as resolve5 } from "node:path";
52685
52826
  import { fileURLToPath as fileURLToPath3 } from "node:url";
52686
52827
  var TOP_LEVEL_DOCS = [
52687
52828
  { filename: "README.md", path: "README.md", category: "readme" },
@@ -52709,7 +52850,7 @@ function resolveDocsRoots() {
52709
52850
  let pkgTopLevel = null;
52710
52851
  for (const pkg of pkgRootCandidates) {
52711
52852
  const guides = join13(pkg, "docs", "guides");
52712
- if (existsSync13(guides) && statSync7(guides).isDirectory()) {
52853
+ if (existsSync13(guides) && statSync6(guides).isDirectory()) {
52713
52854
  pkgGuides = guides;
52714
52855
  pkgTopLevel = pkg;
52715
52856
  break;
@@ -52738,7 +52879,7 @@ function slugifiedTitle(filename) {
52738
52879
  return filename.replace(/\.md$/i, "").replace(/[-_]+/g, " ").replace(/\b\w/g, (m) => m.toUpperCase());
52739
52880
  }
52740
52881
  function entryForFile(absPath, relPath, category) {
52741
- const title = readH1(absPath) ?? slugifiedTitle(basename6(relPath));
52882
+ const title = readH1(absPath) ?? slugifiedTitle(basename5(relPath));
52742
52883
  return { path: relPath, title, category };
52743
52884
  }
52744
52885
  function listBundledDocs2() {
@@ -52755,7 +52896,7 @@ function listBundledDocs2() {
52755
52896
  }
52756
52897
  const guidesRoot = pkgGuides ?? repoGuides;
52757
52898
  if (guidesRoot) {
52758
- const names = readdirSync7(guidesRoot).filter((n) => n.endsWith(".md")).sort();
52899
+ const names = readdirSync6(guidesRoot).filter((n) => n.endsWith(".md")).sort();
52759
52900
  for (const name of names) {
52760
52901
  const abs = join13(guidesRoot, name);
52761
52902
  entries.push(entryForFile(abs, `guides/${name}`, "guide"));
@@ -52771,7 +52912,7 @@ function readDoc(docPath) {
52771
52912
  if (!candidate.startsWith(resolve5(root) + "/") && candidate !== resolve5(root)) {
52772
52913
  continue;
52773
52914
  }
52774
- if (existsSync13(candidate) && statSync7(candidate).isFile()) {
52915
+ if (existsSync13(candidate) && statSync6(candidate).isFile()) {
52775
52916
  try {
52776
52917
  return readFileSync13(candidate, "utf8");
52777
52918
  } catch {
@@ -52939,14 +53080,14 @@ function registerProjectsRoutes(app, ctx) {
52939
53080
  }
52940
53081
 
52941
53082
  // src/web/static.ts
52942
- import { existsSync as existsSync14, statSync as statSync8 } from "node:fs";
53083
+ import { existsSync as existsSync14, statSync as statSync7 } from "node:fs";
52943
53084
  import { dirname as dirname6, join as join14 } from "node:path";
52944
53085
  import { fileURLToPath as fileURLToPath4 } from "node:url";
52945
53086
  function moduleDir3() {
52946
53087
  return dirname6(fileURLToPath4(import.meta.url));
52947
53088
  }
52948
53089
  function isUsableSpaDir(dir) {
52949
- return existsSync14(dir) && statSync8(dir).isDirectory() && existsSync14(join14(dir, "index.html"));
53090
+ return existsSync14(dir) && statSync7(dir).isDirectory() && existsSync14(join14(dir, "index.html"));
52950
53091
  }
52951
53092
  function resolveSpaDist() {
52952
53093
  const here = moduleDir3();
@@ -52968,7 +53109,7 @@ function resolveStaticDir() {
52968
53109
  join14(here, "..", "..", "..", "..", "web", "static")
52969
53110
  ];
52970
53111
  for (const c2 of candidates) {
52971
- if (existsSync14(c2) && statSync8(c2).isDirectory())
53112
+ if (existsSync14(c2) && statSync7(c2).isDirectory())
52972
53113
  return c2;
52973
53114
  }
52974
53115
  return null;
@@ -53117,11 +53258,11 @@ import {
53117
53258
  openSync,
53118
53259
  readFileSync as readFileSync15,
53119
53260
  rmSync,
53120
- writeFileSync as writeFileSync4
53261
+ writeFileSync as writeFileSync5
53121
53262
  } from "node:fs";
53122
- import { homedir as homedir7 } from "node:os";
53263
+ import { homedir as homedir8 } from "node:os";
53123
53264
  import { join as join16 } from "node:path";
53124
- var STATE_DIR = join16(homedir7(), ".cerefox");
53265
+ var STATE_DIR = join16(homedir8(), ".cerefox");
53125
53266
  var PID_FILE = join16(STATE_DIR, "web.pid");
53126
53267
  var LOG_FILE = join16(STATE_DIR, "web.log");
53127
53268
  var daemonPaths = { stateDir: STATE_DIR, pidFile: PID_FILE, logFile: LOG_FILE };
@@ -53148,7 +53289,7 @@ function readPidFile() {
53148
53289
  }
53149
53290
  function writePidFile(info3) {
53150
53291
  ensureStateDir();
53151
- writeFileSync4(PID_FILE, JSON.stringify(info3, null, 2) + `
53292
+ writeFileSync5(PID_FILE, JSON.stringify(info3, null, 2) + `
53152
53293
  `, "utf8");
53153
53294
  }
53154
53295
  function removePidFile() {
@@ -53386,7 +53527,7 @@ var RENAMED_VERBS = [
53386
53527
  ["ingest-dir", "document ingest-dir"],
53387
53528
  ["list-projects", "project list"],
53388
53529
  ["delete-project", "project delete"],
53389
- ["list-versions", "version list"],
53530
+ ["list-versions", "document version list"],
53390
53531
  ["get-audit-log", "audit list"],
53391
53532
  ["list-metadata-keys", "metadata keys"],
53392
53533
  ["metadata-search", "metadata search"],
@@ -53394,30 +53535,32 @@ var RENAMED_VERBS = [
53394
53535
  ["config-set", "config set"],
53395
53536
  ["restore", "backup restore"],
53396
53537
  ["deploy-server", "server deploy"],
53397
- ["reindex", "server reindex"]
53538
+ ["reindex", "server reindex"],
53539
+ ["docs", "guides"],
53540
+ ["sync-self-docs", "guides ingest"]
53398
53541
  ];
53399
53542
  function registerRenameHusks(program2) {
53400
53543
  for (const [oldName, newForm] of RENAMED_VERBS) {
53401
53544
  program2.command(oldName, { hidden: true }).allowUnknownOption(true).allowExcessArguments(true).argument("[args...]", "(renamed)").action(() => {
53402
- eprintln(c.yellow(`✗ \`cerefox ${oldName}\` was renamed in v0.9.0.`));
53545
+ eprintln(c.yellow(`✗ \`cerefox ${oldName}\` was renamed.`));
53403
53546
  eprintln(` Use \`cerefox ${newForm}\` instead (run \`cerefox ${newForm.split(" ")[0]} --help\`).`);
53404
53547
  process.exit(1);
53405
53548
  });
53406
53549
  }
53407
53550
  }
53408
53551
  function buildProgram() {
53409
- const program2 = new Command("cerefox").description("Cerefox — user-owned shared memory for AI agents.").version(PKG_VERSION, "-v, --version", "Print the cerefox version and exit.").addOption(new Option("--json", "Emit machine-readable JSON on stdout instead of the default human text. " + "Available on read commands; ignored on commands without a JSON shape.").hideHelp()).showHelpAfterError("(run `cerefox --help` for usage)").enablePositionalOptions().addHelpText("after", "\nResource groups (run `cerefox <group> --help`):\n" + ` document get · list · delete · ingest · ingest-dir
53410
- ` + ` project list · delete
53411
- ` + ` version list
53552
+ const program2 = new Command("cerefox").description("Cerefox — user-owned shared memory for AI agents.").version(PKG_VERSION, "-v, --version", "Print the cerefox version and exit.").addOption(new Option("--json", "Emit machine-readable JSON on stdout instead of the default human text. " + "Available on read commands; ignored on commands without a JSON shape.").hideHelp()).showHelpAfterError("(run `cerefox --help` for usage)").enablePositionalOptions().addHelpText("after", "\nResource groups (run `cerefox <group> --help`):\n" + ` document get · list · edit · delete · restore · ingest · ingest-dir · version {list·archive·unarchive}
53553
+ ` + ` project list · create · edit · delete
53412
53554
  ` + ` metadata keys · search
53413
53555
  ` + ` audit list
53414
- ` + ` config get · set
53556
+ ` + ` config list · get · set
53415
53557
  ` + ` backup create · restore
53416
53558
  ` + ` server deploy · reindex
53559
+ ` + ` guides list · open · show · ingest (bundled documentation)
53417
53560
  ` + `
53418
53561
  Top-level commands:
53419
53562
  ` + ` search · init · doctor · status · configure-agent · self-update
53420
- ` + ` mcp · web · docs · completion · sync-docs · sync-self-docs
53563
+ ` + ` mcp · web · completion
53421
53564
  ` + `
53422
53565
  Renamed in v0.9.0: the old flat verbs (get-doc, list-docs, ingest, …)
53423
53566
  ` + ` now live under the groups above. The old names still run but exit with
@@ -53440,29 +53583,30 @@ Learn more:
53440
53583
  registerSelfUpdate(program2);
53441
53584
  registerMcp(program2);
53442
53585
  registerWeb(program2);
53443
- registerDocs(program2);
53444
53586
  registerCompletion(program2);
53445
- registerSyncDocs(program2);
53446
- registerSyncSelfDocs(program2);
53447
- const document2 = program2.command("document").description("Documents: get, list, delete, ingest.");
53587
+ const document2 = program2.command("document").description("Documents: get, list, edit, delete, restore, ingest, ingest-dir, version.");
53448
53588
  moveInto(document2, registerGetDoc, "get");
53449
53589
  moveInto(document2, registerListDocs, "list");
53450
53590
  moveInto(document2, registerDeleteDoc, "delete");
53451
53591
  registerDocumentRestore(document2);
53592
+ registerDocumentEdit(document2);
53452
53593
  moveInto(document2, registerIngest, "ingest");
53453
53594
  moveInto(document2, registerIngestDir, "ingest-dir");
53454
- const project = program2.command("project").description("Projects: list, delete.");
53595
+ const documentVersion = document2.command("version").description("Document versions: list, archive, unarchive.");
53596
+ moveInto(documentVersion, registerListVersions, "list");
53597
+ registerVersionArchive(documentVersion);
53598
+ const project = program2.command("project").description("Projects: list, create, edit, delete.");
53455
53599
  moveInto(project, registerListProjects, "list");
53600
+ registerProjectCreate(project);
53601
+ registerProjectEdit(project);
53456
53602
  moveInto(project, registerDeleteProject, "delete");
53457
- const version4 = program2.command("version").description("Document version history: list, archive, unarchive.");
53458
- moveInto(version4, registerListVersions, "list");
53459
- registerVersionArchive(version4);
53460
53603
  const metadata = program2.command("metadata").description("Metadata: keys, search.");
53461
53604
  moveInto(metadata, registerListMetadataKeys, "keys");
53462
53605
  moveInto(metadata, registerMetadataSearch, "search");
53463
53606
  const audit = program2.command("audit").description("Audit log: list.");
53464
53607
  moveInto(audit, registerGetAuditLog, "list");
53465
- const config2 = program2.command("config").description("Runtime config: get, set.");
53608
+ const config2 = program2.command("config").description("Runtime config: list, get, set.");
53609
+ registerConfigList(config2);
53466
53610
  moveInto(config2, registerConfigGet, "get");
53467
53611
  moveInto(config2, registerConfigSet, "set");
53468
53612
  const backup = program2.command("backup").description("Backup + restore the knowledge base: create, restore.").action(() => {
@@ -53475,7 +53619,15 @@ Learn more:
53475
53619
  const server = program2.command("server").description("Server side: deploy, reindex.");
53476
53620
  moveInto(server, registerDeployServer, "deploy");
53477
53621
  moveInto(server, registerReindex, "reindex");
53622
+ const guides = program2.command("guides").description("Bundled docs: list, open, show, ingest (into the KB).");
53623
+ registerGuides(guides);
53624
+ moveInto(guides, registerSyncSelfDocs, "ingest");
53478
53625
  registerRenameHusks(program2);
53626
+ program2.command("sync-docs", { hidden: true }).allowUnknownOption(true).allowExcessArguments(true).argument("[args...]", "(removed)").action(() => {
53627
+ eprintln(c.yellow("✗ `cerefox sync-docs` was removed from the CLI in v0.9.1."));
53628
+ eprintln(" It synced a local repo clone (contributor op). From a repo clone: `bun scripts/sync_docs.ts`.");
53629
+ process.exit(1);
53630
+ });
53479
53631
  return program2;
53480
53632
  }
53481
53633