@aliyunrds/ctxdb 1.0.10-beta.0 → 1.0.11-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  CtxdbError
4
- } from "./chunk-TZFDXKLJ.js";
4
+ } from "./chunk-HHKQPWYI.js";
5
5
 
6
6
  // src/lib/kb.ts
7
7
  import {
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/lib/memory-upload-agent.ts
4
+ function resolveMemoryUploadAgentId(configuredAgentId, agent = "default") {
5
+ return configuredAgentId || agent;
6
+ }
7
+
8
+ export {
9
+ resolveMemoryUploadAgentId
10
+ };
@@ -2,10 +2,10 @@
2
2
  import {
3
3
  fetchKbCatalogBlock,
4
4
  recallTurn
5
- } from "./chunk-VMBCSFGF.js";
5
+ } from "./chunk-XEX5344F.js";
6
6
  import {
7
7
  debug
8
- } from "./chunk-TZFDXKLJ.js";
8
+ } from "./chunk-HHKQPWYI.js";
9
9
 
10
10
  // src/lib/warmup-recall.ts
11
11
  import { execSync } from "node:child_process";
@@ -1,17 +1,17 @@
1
1
  #!/usr/bin/env node
2
- import {
3
- listKnowledgeBases
4
- } from "./chunk-SZ3AZDMU.js";
5
2
  import {
6
3
  isConnectionError,
7
4
  resetCircuit,
8
5
  tripCircuit
9
- } from "./chunk-XWJAZAMN.js";
6
+ } from "./chunk-7RMETV4M.js";
7
+ import {
8
+ listKnowledgeBases
9
+ } from "./chunk-JM7EOAQZ.js";
10
10
  import {
11
11
  CtxdbError,
12
12
  isDataApiReady,
13
13
  resolveDataApiCredential
14
- } from "./chunk-TZFDXKLJ.js";
14
+ } from "./chunk-HHKQPWYI.js";
15
15
 
16
16
  // src/lib/kb-catalog.ts
17
17
  function sanitizeKeyEntities(raw) {
package/dist/cli/main.js CHANGED
@@ -3,7 +3,10 @@ import {
3
3
  beginUpdateNotification,
4
4
  completeUpdateNotification,
5
5
  runSelfUpdate
6
- } from "../chunk-QUPLZ7KF.js";
6
+ } from "../chunk-G3MDJEX5.js";
7
+ import {
8
+ resolveMemoryUploadAgentId
9
+ } from "../chunk-SR3M7AL5.js";
7
10
  import {
8
11
  DEFAULT_FILE_INGEST_TIMEOUT_MS,
9
12
  DEFAULT_FILE_UPLOAD_TIMEOUT_MS,
@@ -36,7 +39,7 @@ import {
36
39
  uploadFile,
37
40
  uploadText,
38
41
  validateLocalFile
39
- } from "../chunk-SZ3AZDMU.js";
42
+ } from "../chunk-JM7EOAQZ.js";
40
43
  import {
41
44
  AGENT_CHOICES,
42
45
  CtxdbError,
@@ -97,7 +100,7 @@ import {
97
100
  withStateLock,
98
101
  writeInstalledPkgVersion,
99
102
  writeState
100
- } from "../chunk-TZFDXKLJ.js";
103
+ } from "../chunk-HHKQPWYI.js";
101
104
  import {
102
105
  DISTRIBUTION_MANIFEST
103
106
  } from "../chunk-5ITT5GSP.js";
@@ -441,10 +444,11 @@ import {
441
444
  rmSync,
442
445
  rmdirSync,
443
446
  unlinkSync,
444
- statSync
447
+ statSync,
448
+ lstatSync
445
449
  } from "node:fs";
446
450
  import { homedir } from "node:os";
447
- import { join, dirname, resolve } from "node:path";
451
+ import { join, dirname } from "node:path";
448
452
  import { fileURLToPath } from "node:url";
449
453
  import { execFileSync } from "node:child_process";
450
454
  import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
@@ -842,11 +846,11 @@ async function runSetup(options) {
842
846
  return { ok: false, steps };
843
847
  }
844
848
  try {
845
- writeOpencodeShim(absEntry);
849
+ writeOpencodePlugin(absEntry);
846
850
  steps.push({
847
851
  step: "install-opencode-shim",
848
852
  ok: true,
849
- detail: `${opencodeShimPath()} \u2192 ${absEntry}`
853
+ detail: `${opencodeBundlePath()} \u2190 ${absEntry}`
850
854
  });
851
855
  } catch (err) {
852
856
  steps.push({
@@ -893,8 +897,8 @@ async function runSetup(options) {
893
897
  }
894
898
  if (ok && agent === "opencode") {
895
899
  hints.unshift(
896
- `OpenCode plugin shim: ${opencodeShimPath()}`,
897
- "Restart OpenCode to load the plugin. `ctxdb upgrade` auto-refreshes the shim after npm updates; only re-run setup if you move ctxdb's install dir."
900
+ `OpenCode plugin: ${opencodeBundlePath()}`,
901
+ "Restart OpenCode to load the plugin. Run `ctxdb upgrade --agent opencode` after npm updates to refresh the bundle and migrate older installations."
898
902
  );
899
903
  }
900
904
  if (ok && agent === "hermes") {
@@ -1119,12 +1123,7 @@ function runRemove(agent, options = {}) {
1119
1123
  }
1120
1124
  }
1121
1125
  if (agent === "opencode") {
1122
- const removed = removeOpencodeShim();
1123
- steps.push({
1124
- step: "remove-opencode-shim",
1125
- ok: true,
1126
- detail: removed ? opencodeShimPath() : "nothing to remove"
1127
- });
1126
+ steps.push(...removeOpencodeShim());
1128
1127
  const root = skillInstallRoot(agent);
1129
1128
  const dirs = [
1130
1129
  ...SKILL_DIRS.map((d) => join(root, d)),
@@ -1146,6 +1145,8 @@ function runRemove(agent, options = {}) {
1146
1145
  }
1147
1146
  if (agent === "hermes") {
1148
1147
  try {
1148
+ const removedApprovals = removeHermesHookApprovals();
1149
+ steps.push({ step: "remove-hermes-approvals", ok: true, detail: `removed ${removedApprovals} entries` });
1149
1150
  backupHermesConfig();
1150
1151
  const removed = removeHermesHooksConfig();
1151
1152
  steps.push({
@@ -1250,6 +1251,23 @@ function runTeardown(options = {}) {
1250
1251
  const purgeConfig = Boolean(options.purgeConfig || options.purgeAll);
1251
1252
  const purgeLogs = Boolean(options.purgeLogs || options.purgeAll);
1252
1253
  const purgeRoot = Boolean(options.purgeAll);
1254
+ if (purgeConfig || purgeLogs) {
1255
+ const root = join(homedir(), ".ctxdb");
1256
+ try {
1257
+ const stat = lstatSync(root);
1258
+ if (stat.isSymbolicLink() || !stat.isDirectory()) {
1259
+ throw new Error(`refusing to purge non-directory or symlinked state root: ${root}`);
1260
+ }
1261
+ if (purgeRoot) {
1262
+ const locks = readdirSync(root).filter((name) => name === "ctxdb.json.oauth-config.lock" || /^credentials\.json(?:\.[a-f0-9]{64})?\.lock$/.test(name) || name === ".skill-evolution-budget.lock");
1263
+ if (locks.length) throw new Error(`state is locked; stop related processes before retrying: ${locks.join(", ")}`);
1264
+ }
1265
+ } catch (error) {
1266
+ if (error.code !== "ENOENT") {
1267
+ return { ok: false, steps: [{ step: "purge-preflight", ok: false, detail: error.message }] };
1268
+ }
1269
+ }
1270
+ }
1253
1271
  const keepConfigShell = !purgeConfig;
1254
1272
  for (const agent of SUPPORTED_AGENTS) {
1255
1273
  const sub = runRemove(agent, { keepConfigShell });
@@ -1266,46 +1284,35 @@ function runTeardown(options = {}) {
1266
1284
  if (purgeConfig) {
1267
1285
  const cfgPath = join(homedir(), ".ctxdb", "ctxdb.json");
1268
1286
  const ownedConfigFiles = [cfgPath, `${cfgPath}.bak`];
1269
- const existing = ownedConfigFiles.filter((path) => existsSync(path));
1270
- if (existing.length === 0) {
1287
+ const start = steps.length;
1288
+ for (const path of ownedConfigFiles) {
1289
+ try {
1290
+ unlinkSync(path);
1291
+ steps.push({ step: "purge-config", ok: true, detail: path });
1292
+ } catch (err) {
1293
+ if (err.code !== "ENOENT") {
1294
+ steps.push({ step: "purge-config", ok: false, detail: `${path}: ${err.message}` });
1295
+ }
1296
+ }
1297
+ }
1298
+ if (steps.length === start) {
1271
1299
  steps.push({
1272
1300
  step: "purge-config",
1273
1301
  ok: true,
1274
1302
  detail: `nothing to remove (${cfgPath})`
1275
1303
  });
1276
- } else {
1277
- for (const path of existing) {
1278
- try {
1279
- unlinkSync(path);
1280
- steps.push({ step: "purge-config", ok: true, detail: path });
1281
- } catch (err) {
1282
- steps.push({
1283
- step: "purge-config",
1284
- ok: false,
1285
- detail: `${path}: ${err?.message ?? String(err)}`
1286
- });
1287
- }
1288
- }
1289
1304
  }
1290
1305
  }
1291
1306
  if (purgeLogs) {
1292
1307
  const logsDir = join(homedir(), ".ctxdb", "logs");
1293
- if (existsSync(logsDir)) {
1294
- try {
1295
- rmSync(logsDir, { recursive: true, force: true });
1296
- steps.push({ step: "purge-logs", ok: true, detail: logsDir });
1297
- } catch (err) {
1298
- steps.push({
1299
- step: "purge-logs",
1300
- ok: false,
1301
- detail: `${logsDir}: ${err?.message ?? String(err)}`
1302
- });
1303
- }
1304
- } else {
1308
+ try {
1309
+ rmSync(logsDir, { recursive: true, force: true });
1310
+ steps.push({ step: "purge-logs", ok: true, detail: logsDir });
1311
+ } catch (err) {
1305
1312
  steps.push({
1306
1313
  step: "purge-logs",
1307
- ok: true,
1308
- detail: `nothing to remove (${logsDir})`
1314
+ ok: false,
1315
+ detail: `${logsDir}: ${err?.message ?? String(err)}`
1309
1316
  });
1310
1317
  }
1311
1318
  }
@@ -1313,6 +1320,25 @@ function runTeardown(options = {}) {
1313
1320
  const root = join(homedir(), ".ctxdb");
1314
1321
  if (existsSync(root)) {
1315
1322
  try {
1323
+ const ownedState = /* @__PURE__ */ new Set([
1324
+ "credentials.json",
1325
+ "cache",
1326
+ "circuit",
1327
+ "sessions",
1328
+ "skills",
1329
+ "skill-evolution"
1330
+ ]);
1331
+ for (const name of readdirSync(root)) {
1332
+ const interruptedWrite = /^(?:ctxdb|credentials)\.json\.[a-f0-9]{24}\.tmp$/.test(name);
1333
+ if (!ownedState.has(name) && !interruptedWrite) continue;
1334
+ const path = join(root, name);
1335
+ try {
1336
+ rmSync(path, { recursive: true, force: true });
1337
+ steps.push({ step: "purge-state", ok: true, detail: path });
1338
+ } catch (error) {
1339
+ steps.push({ step: "purge-state", ok: false, detail: `${path}: ${error.message}` });
1340
+ }
1341
+ }
1316
1342
  const remaining = readdirSync(root);
1317
1343
  if (remaining.length === 0) {
1318
1344
  rmdirSync(root);
@@ -1321,7 +1347,7 @@ function runTeardown(options = {}) {
1321
1347
  steps.push({
1322
1348
  step: "purge-root",
1323
1349
  ok: true,
1324
- detail: `kept (not empty): ${remaining.join(", ")}`
1350
+ detail: `kept (not empty); preserved paths: ${remaining.join(", ")}`
1325
1351
  });
1326
1352
  }
1327
1353
  } catch (err) {
@@ -1347,7 +1373,7 @@ function verifyNodeBinary(nodePath) {
1347
1373
  }
1348
1374
  }
1349
1375
  function checkHookNodePaths(agent) {
1350
- if (agent === "opencode") return checkOpencodeShimHealth();
1376
+ if (agent === "opencode") return checkOpencodePluginHealth();
1351
1377
  if (agent === "hermes") return checkHermesHookHealth();
1352
1378
  const empty = {
1353
1379
  installed: false,
@@ -1419,51 +1445,35 @@ function checkHookNodePaths(agent) {
1419
1445
  }
1420
1446
  return { installed: true, nodePaths: paths, nodeOk: true, detail: `${paths[0]} (${goodVersion})` };
1421
1447
  }
1422
- function checkOpencodeShimHealth() {
1423
- const path = opencodeShimPath();
1424
- if (!existsSync(path)) {
1425
- return {
1426
- installed: false,
1427
- nodePaths: [],
1428
- nodeOk: false,
1429
- detail: `opencode shim not installed \u2014 run \`ctxdb setup --agent opencode\``
1430
- };
1431
- }
1432
- let text = "";
1433
- try {
1434
- text = readFileSync(path, "utf-8");
1435
- } catch (err) {
1448
+ function checkOpencodePluginHealth() {
1449
+ const path = opencodeBundlePath();
1450
+ if (existsSync(opencodeShimPath())) {
1436
1451
  return {
1437
1452
  installed: true,
1438
- nodePaths: [],
1453
+ nodePaths: [path],
1439
1454
  nodeOk: false,
1440
- detail: `opencode shim unreadable: ${err?.message ?? String(err)}`
1455
+ detail: "opencode legacy shim requires migration \u2014 run `ctxdb upgrade --agent opencode` and restart OpenCode"
1441
1456
  };
1442
1457
  }
1443
- const target = text.match(/export\s+\{\s*default\s*\}\s+from\s+["']([^"']+)["'];/)?.[1];
1444
- if (!target) {
1458
+ if (!existsSync(path)) {
1445
1459
  return {
1446
- installed: true,
1460
+ installed: false,
1447
1461
  nodePaths: [],
1448
1462
  nodeOk: false,
1449
- detail: `opencode shim malformed: ${path} \u2014 re-run \`ctxdb setup --agent opencode\``
1463
+ detail: "opencode plugin not installed \u2014 run `ctxdb setup --agent opencode`"
1450
1464
  };
1451
1465
  }
1452
- const targetPath = target.startsWith("file:") ? fileURLToPath(target) : resolve(dirname(path), target);
1453
- if (!existsSync(targetPath)) {
1466
+ try {
1467
+ if (!readFileSync(path, "utf-8").trim()) throw new Error("empty bundle");
1468
+ } catch (err) {
1454
1469
  return {
1455
1470
  installed: true,
1456
- nodePaths: [targetPath],
1471
+ nodePaths: [path],
1457
1472
  nodeOk: false,
1458
- detail: `opencode shim target missing: ${targetPath} \u2014 re-run \`ctxdb setup --agent opencode\``
1473
+ detail: `opencode plugin unreadable: ${err?.message ?? String(err)} \u2014 re-run \`ctxdb setup --agent opencode\``
1459
1474
  };
1460
1475
  }
1461
- return {
1462
- installed: true,
1463
- nodePaths: [targetPath],
1464
- nodeOk: true,
1465
- detail: `opencode shim: ${path} \u2192 ${targetPath}`
1466
- };
1476
+ return { installed: true, nodePaths: [path], nodeOk: true, detail: `opencode plugin: ${path}` };
1467
1477
  }
1468
1478
  var SETTINGS_BACKUP_KEEP = 5;
1469
1479
  function backupSettingsFile(path) {
@@ -1709,36 +1719,35 @@ function resolveOpencodePluginEntry() {
1709
1719
  const here = dirname(fileURLToPath(import.meta.url));
1710
1720
  const pkgRoot = walkUpToPackageJson(here, CTXDB_PACKAGE_NAMES);
1711
1721
  if (!pkgRoot) return null;
1712
- const candidates = [
1713
- join(pkgRoot, "dist", "opencode", "index.js"),
1714
- join(pkgRoot, "..", "opencode", "src", "index.ts")
1715
- ];
1716
- return candidates.find((candidate) => existsSync(candidate)) ?? null;
1722
+ const candidate = join(pkgRoot, "dist", "opencode", "index.js");
1723
+ return existsSync(candidate) ? candidate : null;
1717
1724
  }
1718
- var OPENCODE_SHIM_HEADER = "// Generated by ctxdb setup --agent opencode. Do not edit by hand.\n// To refresh after moving ctxdb's install directory, run ctxdb upgrade --agent opencode or re-run setup.\n// To remove, run: ctxdb setup --remove --agent opencode\n";
1719
- function writeOpencodeShim(absEntry) {
1725
+ var OPENCODE_GENERATED_HEADER = "// Generated by ctxdb setup --agent opencode.";
1726
+ function writeOpencodePlugin(absEntry) {
1720
1727
  const shimPath = opencodeShimPath();
1721
1728
  const bundlePath = opencodeBundlePath();
1722
- mkdirSync(dirname(shimPath), { recursive: true });
1729
+ mkdirSync(dirname(bundlePath), { recursive: true });
1730
+ if (existsSync(shimPath) && !readFileSync(shimPath, "utf-8").startsWith(OPENCODE_GENERATED_HEADER)) {
1731
+ throw new Error(`Cannot migrate unrecognized OpenCode entry ${shimPath}; move it out of plugins/ before running setup again.`);
1732
+ }
1723
1733
  copyFileSync(absEntry, bundlePath);
1724
- const importSpec = "./" + OPENCODE_BUNDLE_FILENAME;
1725
- const body = `${OPENCODE_SHIM_HEADER}export { default } from ${JSON.stringify(importSpec)};
1726
- `;
1727
- writeFileSync(shimPath, body, "utf-8");
1734
+ if (existsSync(shimPath)) unlinkSync(shimPath);
1728
1735
  }
1729
1736
  function removeOpencodeShim() {
1730
1737
  const shimPath = opencodeShimPath();
1731
1738
  const bundlePath = opencodeBundlePath();
1732
- let removed = false;
1739
+ const steps = [];
1733
1740
  for (const p of [shimPath, bundlePath]) {
1734
- if (!existsSync(p)) continue;
1735
1741
  try {
1736
1742
  unlinkSync(p);
1737
- removed = true;
1738
- } catch {
1743
+ steps.push({ step: "remove-opencode-shim", ok: true, detail: p });
1744
+ } catch (error) {
1745
+ if (error.code !== "ENOENT") {
1746
+ steps.push({ step: "remove-opencode-shim", ok: false, detail: `${p}: ${error.message}` });
1747
+ }
1739
1748
  }
1740
1749
  }
1741
- return removed;
1750
+ return steps.length ? steps : [{ step: "remove-opencode-shim", ok: true, detail: "nothing to remove" }];
1742
1751
  }
1743
1752
  var ENTRY_MARKER_KEY = "_ctxdb";
1744
1753
  var ENTRY_MARKER_VALUE = "@aliyunrds/ctxdb";
@@ -1926,6 +1935,23 @@ function removeHermesHooksConfig() {
1926
1935
  if (removed > 0) writeHermesConfig(data);
1927
1936
  return removed;
1928
1937
  }
1938
+ function removeHermesHookApprovals() {
1939
+ const path = hermesAllowlistPath();
1940
+ if (!existsSync(path)) return 0;
1941
+ const data = JSON.parse(readFileSync(path, "utf8"));
1942
+ if (!Array.isArray(data?.approvals)) throw new Error(`${path}: expected an approvals array`);
1943
+ const entries = hermesCtxdbEntriesByEvent(readHermesConfig());
1944
+ const approvals = data.approvals.filter((approval) => {
1945
+ if (!approval || !HERMES_HOOK_EVENTS.includes(approval.event) || typeof approval.command !== "string") return true;
1946
+ const configured = entries.get(approval.event)?.some((entry) => entry.command === approval.command);
1947
+ const hook = approval.event === HERMES_PRE_LLM_CALL_EVENT ? "pre" : "post";
1948
+ const generated = new RegExp(`^'[^']+' '[^']*[/\\\\]hermes-${hook}-llm-call\\.(?:js|ts)' --agent=hermes$`).test(approval.command);
1949
+ return !configured && !generated;
1950
+ });
1951
+ const removed = data.approvals.length - approvals.length;
1952
+ if (removed) writeFileSync(path, JSON.stringify({ ...data, approvals }, null, 2) + "\n", "utf8");
1953
+ return removed;
1954
+ }
1929
1955
  function firstCommandToken(command) {
1930
1956
  const s = command.trim();
1931
1957
  if (!s) return null;
@@ -2574,10 +2600,12 @@ FLAGS
2574
2600
  --agent <name> Target a single agent (${SUPPORTED_AGENT_CHOICES})
2575
2601
  --purge-config Also delete ~/.ctxdb/ctxdb.json
2576
2602
  --purge-logs Also delete ~/.ctxdb/logs/
2577
- --purge-all Delete everything under ~/.ctxdb/
2603
+ --purge-all Delete ctxdb-owned state under ~/.ctxdb/; preserve unknown files
2578
2604
  --json Machine-readable JSON output
2579
2605
 
2580
2606
  NOTE
2607
+ Purge flags cannot be combined with --agent. Local removal does not revoke
2608
+ server sessions; log out of each login before uninstalling to revoke them.
2581
2609
  Does not run \`npm uninstall\`. After uninstall completes, remove the
2582
2610
  npm package separately: npm uninstall -g ${PACKAGE_UNINSTALL_TARGETS2}
2583
2611
  `;
@@ -2589,6 +2617,10 @@ function uninstall(args) {
2589
2617
  const json = !!args.flags.json;
2590
2618
  const agentFlag = args.flags.agent;
2591
2619
  if (agentFlag !== void 0) {
2620
+ if (["purge-config", "purge-logs", "purge-all"].some((flag) => args.flags[flag])) {
2621
+ printResult({ ok: false, error: "--agent cannot be combined with --purge-config, --purge-logs, or --purge-all" }, json, "uninstall");
2622
+ return 2;
2623
+ }
2592
2624
  if (!isAgentSlug(agentFlag)) {
2593
2625
  process.stderr.write(
2594
2626
  `unknown --agent: ${String(agentFlag)} (expected one of ${SUPPORTED_AGENTS.join(" / ")} / default)
@@ -2796,7 +2828,7 @@ import { join as join3, win32 } from "node:path";
2796
2828
  import { existsSync as existsSync3 } from "node:fs";
2797
2829
 
2798
2830
  // src/skills/status.ts
2799
- import { existsSync as existsSync2, readdirSync as readdirSync2, lstatSync } from "node:fs";
2831
+ import { existsSync as existsSync2, readdirSync as readdirSync2, lstatSync as lstatSync2 } from "node:fs";
2800
2832
  import "node:path";
2801
2833
  function statusBindings(root, agent) {
2802
2834
  const dir = privatePath(root, "sessions", "bindings");
@@ -2867,7 +2899,7 @@ function localSkillStatus(bound, root) {
2867
2899
  const manifestPath = path(skills, "manifest.json");
2868
2900
  const snapshot = existsSync2(manifestPath) ? readState(root, manifestPath) : void 0;
2869
2901
  const drafts = list(path(skills, "drafts")).flatMap((name) => {
2870
- if (!lstatSync(path(skills, "drafts", name)).isDirectory()) return [];
2902
+ if (!lstatSync2(path(skills, "drafts", name)).isDirectory()) return [];
2871
2903
  const direct = path(skills, "drafts", name, "SKILL.md"), bundle = path(skills, "drafts", name, "bundle", "SKILL.md");
2872
2904
  return [direct, bundle].filter((file) => existsSync2(file));
2873
2905
  });
@@ -3845,6 +3877,7 @@ ${usage2}`, 2);
3845
3877
  const images = imageFlags.length > 0 ? await Promise.all(imageFlags.map((value2) => loadImagePart(value2, usage2))) : [];
3846
3878
  const ctx = buildContext(args);
3847
3879
  const userId = args.flags["user-id"] ?? ctx.cfg.userId;
3880
+ const agentId = resolveMemoryUploadAgentId(ctx.cfg.agentId, ctx.agent);
3848
3881
  const metadata = parseMetadataFlags(args.flags["metadata"]);
3849
3882
  if (images.length > 0) {
3850
3883
  const message = {
@@ -3855,6 +3888,7 @@ ${usage2}`, 2);
3855
3888
  const request = {
3856
3889
  messages: [message],
3857
3890
  user_id: userId,
3891
+ agent_id: agentId,
3858
3892
  infer: true
3859
3893
  };
3860
3894
  if (Object.keys(metadata).length > 0) request.metadata = metadata;
@@ -3879,6 +3913,7 @@ ${usage2}`, 2);
3879
3913
  const body = {
3880
3914
  messages: [{ role: "user", content: text }],
3881
3915
  user_id: userId,
3916
+ agent_id: agentId,
3882
3917
  async_mode: false
3883
3918
  };
3884
3919
  if (Object.keys(metadata).length > 0) body.metadata = metadata;
@@ -6115,12 +6150,14 @@ function topLevelCommands(managedCredentials) {
6115
6150
  }),
6116
6151
  option("--purge-config", "Also delete ~/.ctxdb/ctxdb.json.", { type: "boolean" }),
6117
6152
  option("--purge-logs", "Also delete ~/.ctxdb/logs/.", { type: "boolean" }),
6118
- option("--purge-all", "Delete everything under ~/.ctxdb/.", { type: "boolean" }),
6153
+ option("--purge-all", "Delete ctxdb-owned local state under ~/.ctxdb/; preserve unknown files.", { type: "boolean" }),
6119
6154
  JSON_OPTION
6120
6155
  ],
6121
6156
  warnings: [
6122
6157
  "Without --agent, ctxdb-owned hooks and Skills are removed for every supported Agent.",
6123
- "--purge-all deletes all ctxdb configuration, credentials, logs, and cache under ~/.ctxdb/.",
6158
+ "--purge-all deletes ctxdb configuration, shared credentials, logs, cache, sessions, and Skill state (including drafts) under ~/.ctxdb/; unknown files are preserved and reported.",
6159
+ "Purge flags cannot be combined with --agent. Stop running Agent sessions and transfers before purging.",
6160
+ "Local removal does not revoke server sessions; log out of each login before uninstalling to revoke them.",
6124
6161
  "This command does not remove the npm package."
6125
6162
  ],
6126
6163
  examples: [
@@ -6616,7 +6653,10 @@ var memoryGroup = group("memory", "Store, retrieve, update, and promote memories
6616
6653
  AGENT_OPTION,
6617
6654
  JSON_OPTION
6618
6655
  ],
6619
- constraints: ["At least text or one --image is required."],
6656
+ constraints: [
6657
+ "At least text or one --image is required.",
6658
+ "Uploads include agent_id: CTXDB_AGENT_ID overrides configured agent_id; otherwise the selected --agent / CTXDB_AGENT / default is used. This does not add a default search filter."
6659
+ ],
6620
6660
  examples: [
6621
6661
  { command: "ctxdb memory add <text> --no-infer --json" },
6622
6662
  { command: "ctxdb memory add --image=<image-path> --agent=codex" }
@@ -1,8 +1,12 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  captureParsedMessages
4
- } from "../chunk-LASAMQQY.js";
5
- import "../chunk-XWJAZAMN.js";
4
+ } from "../chunk-EWCB3UQS.js";
5
+ import "../chunk-7RMETV4M.js";
6
+ import {
7
+ shouldSkipHooks
8
+ } from "../chunk-5ML4VSXN.js";
9
+ import "../chunk-SR3M7AL5.js";
6
10
  import {
7
11
  HttpClient,
8
12
  agentFromArgvWithFallback,
@@ -12,11 +16,8 @@ import {
12
16
  sessionBinding,
13
17
  setDebug,
14
18
  skillStopRows
15
- } from "../chunk-TZFDXKLJ.js";
19
+ } from "../chunk-HHKQPWYI.js";
16
20
  import "../chunk-5ITT5GSP.js";
17
- import {
18
- shouldSkipHooks
19
- } from "../chunk-5ML4VSXN.js";
20
21
  import "../chunk-PI2SUS3M.js";
21
22
 
22
23
  // src/hooks/hermes-post-llm-call.ts
@@ -1,18 +1,21 @@
1
1
  #!/usr/bin/env node
2
- import {
3
- composeUserPromptSubmit
4
- } from "../chunk-5HPYYOPH.js";
5
2
  import {
6
3
  HOOK_TIMEOUT_MS,
7
4
  composeSessionStart
8
- } from "../chunk-SG4LQTOF.js";
5
+ } from "../chunk-WCVCSOFL.js";
6
+ import {
7
+ composeUserPromptSubmit
8
+ } from "../chunk-6XK3RDZ6.js";
9
9
  import {
10
10
  fetchKbCatalogBlock
11
- } from "../chunk-VMBCSFGF.js";
12
- import "../chunk-SZ3AZDMU.js";
11
+ } from "../chunk-XEX5344F.js";
13
12
  import {
14
13
  isCircuitOpen
15
- } from "../chunk-XWJAZAMN.js";
14
+ } from "../chunk-7RMETV4M.js";
15
+ import {
16
+ shouldSkipHooks
17
+ } from "../chunk-5ML4VSXN.js";
18
+ import "../chunk-JM7EOAQZ.js";
16
19
  import {
17
20
  HttpClient,
18
21
  agentFromArgvWithFallback,
@@ -25,11 +28,8 @@ import {
25
28
  skillDeferredFeedback,
26
29
  skillPromptContext,
27
30
  skillSessionStart
28
- } from "../chunk-TZFDXKLJ.js";
31
+ } from "../chunk-HHKQPWYI.js";
29
32
  import "../chunk-5ITT5GSP.js";
30
- import {
31
- shouldSkipHooks
32
- } from "../chunk-5ML4VSXN.js";
33
33
  import "../chunk-PI2SUS3M.js";
34
34
 
35
35
  // src/hooks/hermes-pre-llm-call.ts
@@ -1,13 +1,13 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ shouldSkipHooks
4
+ } from "../chunk-5ML4VSXN.js";
2
5
  import {
3
6
  agentFromArgvWithFallback,
4
7
  receiveEnd,
5
8
  sessionBinding
6
- } from "../chunk-TZFDXKLJ.js";
9
+ } from "../chunk-HHKQPWYI.js";
7
10
  import "../chunk-5ITT5GSP.js";
8
- import {
9
- shouldSkipHooks
10
- } from "../chunk-5ML4VSXN.js";
11
11
  import "../chunk-PI2SUS3M.js";
12
12
 
13
13
  // src/hooks/session-end.ts
@@ -3,12 +3,15 @@ import {
3
3
  HOOK_TIMEOUT_MS,
4
4
  composeSessionStart,
5
5
  formatSessionStartStdout
6
- } from "../chunk-SG4LQTOF.js";
7
- import "../chunk-VMBCSFGF.js";
8
- import "../chunk-SZ3AZDMU.js";
6
+ } from "../chunk-WCVCSOFL.js";
7
+ import "../chunk-XEX5344F.js";
9
8
  import {
10
9
  isCircuitOpen
11
- } from "../chunk-XWJAZAMN.js";
10
+ } from "../chunk-7RMETV4M.js";
11
+ import {
12
+ shouldSkipHooks
13
+ } from "../chunk-5ML4VSXN.js";
14
+ import "../chunk-JM7EOAQZ.js";
12
15
  import {
13
16
  HttpClient,
14
17
  agentFromArgvWithFallback,
@@ -17,11 +20,8 @@ import {
17
20
  resolveDataApiCredential,
18
21
  setDebug,
19
22
  skillSessionStart
20
- } from "../chunk-TZFDXKLJ.js";
23
+ } from "../chunk-HHKQPWYI.js";
21
24
  import "../chunk-5ITT5GSP.js";
22
- import {
23
- shouldSkipHooks
24
- } from "../chunk-5ML4VSXN.js";
25
25
  import "../chunk-PI2SUS3M.js";
26
26
 
27
27
  // src/hooks/session-start.ts
@@ -1,8 +1,12 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  captureTurn
4
- } from "../chunk-LASAMQQY.js";
5
- import "../chunk-XWJAZAMN.js";
4
+ } from "../chunk-EWCB3UQS.js";
5
+ import "../chunk-7RMETV4M.js";
6
+ import {
7
+ shouldSkipHooks
8
+ } from "../chunk-5ML4VSXN.js";
9
+ import "../chunk-SR3M7AL5.js";
6
10
  import {
7
11
  HttpClient,
8
12
  agentFromArgvWithFallback,
@@ -12,11 +16,8 @@ import {
12
16
  sessionBinding,
13
17
  setDebug,
14
18
  skillStop
15
- } from "../chunk-TZFDXKLJ.js";
19
+ } from "../chunk-HHKQPWYI.js";
16
20
  import "../chunk-5ITT5GSP.js";
17
- import {
18
- shouldSkipHooks
19
- } from "../chunk-5ML4VSXN.js";
20
21
  import "../chunk-PI2SUS3M.js";
21
22
 
22
23
  // src/hooks/stop.ts