@aliyunrds/ctxdb 1.0.3 → 1.0.6-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.
package/dist/cli/main.js CHANGED
@@ -12,7 +12,7 @@ import {
12
12
  pollIngest,
13
13
  uploadFile,
14
14
  uploadText
15
- } from "../chunk-3PFMHU3C.js";
15
+ } from "../chunk-L4GVGVOP.js";
16
16
  import {
17
17
  DEFAULT_BASE_URL,
18
18
  DEFAULT_USER_ID,
@@ -25,6 +25,7 @@ import {
25
25
  agentPlatformSupport,
26
26
  configuredAgents,
27
27
  detectInstalledAgents,
28
+ hasConfiguredAgent,
28
29
  inspectAgentHomes,
29
30
  isAgentSlug,
30
31
  isBuiltinAgent,
@@ -32,13 +33,14 @@ import {
32
33
  load,
33
34
  removeAgent,
34
35
  save,
36
+ updateConfiguredDebug,
35
37
  writeInstalledPkgVersion
36
- } from "../chunk-JFTKYEVN.js";
38
+ } from "../chunk-ARZX2RLR.js";
37
39
  import {
38
40
  beginUpdateNotification,
39
41
  completeUpdateNotification,
40
42
  runSelfUpdate
41
- } from "../chunk-BQA7YSXT.js";
43
+ } from "../chunk-Z6OHSEF2.js";
42
44
 
43
45
  // src/cli/util.ts
44
46
  var BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
@@ -70,8 +72,10 @@ var BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
70
72
  // kb upload-text / upload-file
71
73
  "verbose",
72
74
  // memory search / kb search (three-tier projection)
73
- "raw"
75
+ "raw",
74
76
  // kb search / memory search --knowledge (W3 compaction bypass)
77
+ "full"
78
+ // debug recall full-content human output
75
79
  ]);
76
80
  function parseArgs(argv, booleanFlags = BOOLEAN_FLAGS) {
77
81
  const positional = [];
@@ -127,8 +131,14 @@ var BOLD = "\x1B[1m";
127
131
  var RESET = "\x1B[0m";
128
132
  var CHECK = `${GREEN}\u2714${RESET}`;
129
133
  var CROSS = `${RED}\u2718${RESET}`;
134
+ function highlightInlineCode(text, surroundingStyle = "") {
135
+ return text.replace(
136
+ /`([^`\n]+)`/g,
137
+ (_match, content) => `${RESET}${BOLD}${content}${RESET}${surroundingStyle}`
138
+ );
139
+ }
130
140
  function dim(text) {
131
- return `${DIM}${text}${RESET}`;
141
+ return `${DIM}${highlightInlineCode(text, DIM)}${RESET}`;
132
142
  }
133
143
  function isSetupResult(v) {
134
144
  if (typeof v !== "object" || v === null) return false;
@@ -153,7 +163,7 @@ function formatSetupResult(r, command = "setup") {
153
163
  `);
154
164
  for (const s of r.steps) {
155
165
  const icon = s.ok ? CHECK : CROSS;
156
- const detail = s.detail ? ` ${DIM}${s.detail}${RESET}` : "";
166
+ const detail = s.detail ? ` ${dim(s.detail)}` : "";
157
167
  lines.push(` ${icon} ${s.step}${detail}`);
158
168
  }
159
169
  return lines.join("\n");
@@ -168,7 +178,7 @@ function formatUpgradeResult(r) {
168
178
  lines.push(` ${icon} ${BOLD}${name}${RESET}`);
169
179
  for (const s of result.steps) {
170
180
  const sIcon = s.ok ? CHECK : CROSS;
171
- const detail = s.detail ? ` ${DIM}${s.detail}${RESET}` : "";
181
+ const detail = s.detail ? ` ${dim(s.detail)}` : "";
172
182
  lines.push(` ${sIcon} ${s.step}${detail}`);
173
183
  }
174
184
  }
@@ -186,16 +196,19 @@ function formatMultiAgentResult(r) {
186
196
  lines.push(` ${agentOk ? CHECK : CROSS} ${BOLD}${name}${RESET}`);
187
197
  if (r.operation === "setup") {
188
198
  for (const step of result.steps ?? []) {
189
- const detail = step.detail ? ` ${DIM}${step.detail}${RESET}` : "";
199
+ const detail = step.detail ? ` ${dim(step.detail)}` : "";
190
200
  lines.push(` ${step.ok ? CHECK : CROSS} ${step.step}${detail}`);
191
201
  }
192
202
  for (const hint of result.hints ?? []) {
193
- lines.push(` ${DIM}hint${RESET} ${hint}`);
203
+ lines.push(` ${DIM}hint${RESET} ${highlightInlineCode(hint)}`);
194
204
  }
195
205
  continue;
196
206
  }
197
207
  lines.push(` ${DIM}config${RESET} ${result.ok ? "complete" : "incomplete"}`);
198
208
  lines.push(` ${DIM}connected${RESET} ${result.connected ? "yes" : "no"}`);
209
+ lines.push(
210
+ ` ${DIM}debug${RESET} ${result.debug ? "enabled" : "disabled"} (configured=${result.debug_configured ? "enabled" : "disabled"}, forced=${result.debug_forced ? "yes" : "no"}, reason=${result.debug_reason ?? "-"})`
211
+ );
199
212
  if (result.hooks_node !== void 0) {
200
213
  lines.push(` ${DIM}hooks${RESET} ${result.hooks_node}`);
201
214
  }
@@ -227,6 +240,10 @@ function formatStatusResult(r) {
227
240
  ["top_k", r.top_k],
228
241
  ["threshold", r.threshold],
229
242
  ["knowledge_top_k", r.knowledge_top_k],
243
+ ["debug", r.debug],
244
+ ["debug_configured", r.debug_configured],
245
+ ["debug_forced", r.debug_forced],
246
+ ["debug_reason", r.debug_reason],
230
247
  ["connected", r.connected],
231
248
  ["version", r.version]
232
249
  ];
@@ -318,6 +335,8 @@ function skillInstallRoot(agent) {
318
335
  return join(homedir(), ".qoder", "skills");
319
336
  case "qoderwork":
320
337
  return join(homedir(), ".qoderwork", "skills");
338
+ case "qwenwork":
339
+ return join(homedir(), ".qwenwork", "skills");
321
340
  case "codex":
322
341
  return join(homedir(), ".codex", "skills");
323
342
  case "claude":
@@ -340,6 +359,8 @@ function hookConfigPath(agent) {
340
359
  return join(homedir(), ".qoder", "settings.json");
341
360
  case "qoderwork":
342
361
  return join(homedir(), ".qoderwork", "settings.json");
362
+ case "qwenwork":
363
+ return join(homedir(), ".qwenwork", "settings.json");
343
364
  case "codex":
344
365
  return join(homedir(), ".codex", "hooks.json");
345
366
  case "claude":
@@ -375,6 +396,7 @@ function checkCurrentNodeVersion() {
375
396
  }
376
397
  async function runSetup(options) {
377
398
  const steps = [];
399
+ let existingAgentHomes = [];
378
400
  if (!isAgentSlug(options.agent)) {
379
401
  steps.push({
380
402
  step: "validate-agent",
@@ -395,6 +417,7 @@ async function runSetup(options) {
395
417
  const homeCheck = checkAgentHome(agent);
396
418
  steps.push(homeCheck);
397
419
  if (!homeCheck.ok) return { ok: false, steps };
420
+ existingAgentHomes = inspectAgentHomes(agent).existing;
398
421
  }
399
422
  const cfg = load({ agent });
400
423
  if (options.apiKey) cfg.apiKey = options.apiKey;
@@ -423,7 +446,7 @@ async function runSetup(options) {
423
446
  detail: `default: copied from ${agent}`
424
447
  });
425
448
  }
426
- if (installSkill && isBuiltinAgent(agent)) {
449
+ if (installSkill && isBuiltinAgent(agent) && existingAgentHomes.includes(agentHomeDir(agent))) {
427
450
  const installRoot = skillInstallRoot(agent);
428
451
  for (const legacy of LEGACY_SKILL_DIRS) {
429
452
  const legacyDir = join(installRoot, legacy);
@@ -445,6 +468,8 @@ async function runSetup(options) {
445
468
  if (!skillResult.ok) return { ok: false, steps };
446
469
  }
447
470
  if (isBuiltinAgent(agent) && agentSupportsHooks(agent)) {
471
+ const primaryHome = agentHomeDir(agent);
472
+ const primaryHomeExists = existingAgentHomes.includes(primaryHome);
448
473
  const hookPaths = locateHookPaths();
449
474
  steps.push({
450
475
  step: "locate-hooks",
@@ -460,26 +485,28 @@ async function runSetup(options) {
460
485
  detail: nodeCheck.ok ? `${nodePath} (${nodeCheck.version})` : `node not executable: ${nodeCheck.error}`
461
486
  });
462
487
  if (!nodeCheck.ok) return { ok: false, steps };
463
- try {
464
- backupSettingsJson(agent);
465
- steps.push({ step: "backup-settings", ok: true });
466
- const removed = stripCtxdbHooks(agent);
467
- if (removed > 0) {
488
+ if (primaryHomeExists) {
489
+ try {
490
+ backupSettingsJson(agent);
491
+ steps.push({ step: "backup-settings", ok: true });
492
+ const removed = stripCtxdbHooks(agent);
493
+ if (removed > 0) {
494
+ steps.push({
495
+ step: "clean-legacy-hooks",
496
+ ok: true,
497
+ detail: `removed ${removed} existing entries`
498
+ });
499
+ }
500
+ appendHooks(agent, hookPaths);
501
+ steps.push({ step: "append-hooks", ok: true });
502
+ } catch (err) {
468
503
  steps.push({
469
- step: "clean-legacy-hooks",
470
- ok: true,
471
- detail: `removed ${removed} existing entries`
504
+ step: "settings-update",
505
+ ok: false,
506
+ detail: err?.message ?? String(err)
472
507
  });
508
+ return { ok: false, steps };
473
509
  }
474
- appendHooks(agent, hookPaths);
475
- steps.push({ step: "append-hooks", ok: true });
476
- } catch (err) {
477
- steps.push({
478
- step: "settings-update",
479
- ok: false,
480
- detail: err?.message ?? String(err)
481
- });
482
- return { ok: false, steps };
483
510
  }
484
511
  try {
485
512
  chmodSync(hookPaths.userPromptSubmit, 493);
@@ -499,8 +526,7 @@ async function runSetup(options) {
499
526
  if (agent === "codex") {
500
527
  steps.push(enableCodexHooksFeature());
501
528
  }
502
- const primaryHome = agentHomeDir(agent);
503
- const variantHomes = agentHomeDirs(agent).filter((d) => d !== primaryHome && existsSync(d));
529
+ const variantHomes = existingAgentHomes.filter((d) => d !== primaryHome);
504
530
  for (const vHome of variantHomes) {
505
531
  const tag = vHome.split("/").pop() ?? vHome;
506
532
  if (installSkill) {
@@ -1093,42 +1119,49 @@ function checkHookNodePaths(agent) {
1093
1119
  nodeOk: true,
1094
1120
  detail: "no hooks installed"
1095
1121
  };
1096
- const path = hookConfigPath(agent);
1097
- if (!path || !existsSync(path)) return empty;
1098
- let data;
1099
- try {
1100
- data = JSON.parse(readFileSync(path, "utf-8"));
1101
- } catch {
1102
- return empty;
1103
- }
1104
- if (!data?.hooks || typeof data.hooks !== "object") return empty;
1122
+ const primaryHome = agentHomeDir(agent);
1123
+ const primaryPath = hookConfigPath(agent);
1124
+ const configPaths = agentHomeDirs(agent).filter((home) => existsSync(home)).map((home) => home === primaryHome ? primaryPath : join(home, "settings.json")).filter((path) => path !== null && existsSync(path));
1125
+ if (configPaths.length === 0) return empty;
1126
+ let foundHooksObject = false;
1105
1127
  const nodePaths = /* @__PURE__ */ new Set();
1106
- for (const event of HOOK_EVENTS) {
1107
- const entries = data.hooks[event];
1108
- if (!Array.isArray(entries)) continue;
1109
- for (const entry of entries) {
1110
- if (!entryIsCtxdb(entry)) continue;
1111
- for (const h of entry.hooks ?? []) {
1112
- if (h?.type !== "command" || typeof h.command !== "string") continue;
1113
- if (Array.isArray(h.args) && h.args.length > 0) {
1114
- nodePaths.add(h.command);
1115
- } else {
1116
- const cmd = h.command;
1117
- let nodePath;
1118
- if (cmd.startsWith('"')) {
1119
- const closeQuote = cmd.indexOf('"', 1);
1120
- if (closeQuote > 1) nodePath = cmd.slice(1, closeQuote);
1128
+ for (const configPath of configPaths) {
1129
+ let data;
1130
+ try {
1131
+ data = JSON.parse(readFileSync(configPath, "utf-8"));
1132
+ } catch {
1133
+ continue;
1134
+ }
1135
+ if (!data?.hooks || typeof data.hooks !== "object") continue;
1136
+ foundHooksObject = true;
1137
+ for (const event of HOOK_EVENTS) {
1138
+ const entries = data.hooks[event];
1139
+ if (!Array.isArray(entries)) continue;
1140
+ for (const entry of entries) {
1141
+ if (!entryIsCtxdb(entry)) continue;
1142
+ for (const h of entry.hooks ?? []) {
1143
+ if (h?.type !== "command" || typeof h.command !== "string") continue;
1144
+ if (Array.isArray(h.args) && h.args.length > 0) {
1145
+ nodePaths.add(h.command);
1121
1146
  } else {
1122
- const parts = cmd.split(" ");
1123
- if (parts.length >= 2 && !parts[0].endsWith(".js") && !parts[0].endsWith(".ts") && (parts[0].includes("/") || parts[0].includes("\\"))) {
1124
- nodePath = parts[0];
1147
+ const cmd = h.command;
1148
+ let nodePath;
1149
+ if (cmd.startsWith('"')) {
1150
+ const closeQuote = cmd.indexOf('"', 1);
1151
+ if (closeQuote > 1) nodePath = cmd.slice(1, closeQuote);
1152
+ } else {
1153
+ const parts = cmd.split(" ");
1154
+ if (parts.length >= 2 && !parts[0].endsWith(".js") && !parts[0].endsWith(".ts") && (parts[0].includes("/") || parts[0].includes("\\"))) {
1155
+ nodePath = parts[0];
1156
+ }
1125
1157
  }
1158
+ if (nodePath) nodePaths.add(nodePath);
1126
1159
  }
1127
- if (nodePath) nodePaths.add(nodePath);
1128
1160
  }
1129
1161
  }
1130
1162
  }
1131
1163
  }
1164
+ if (!foundHooksObject) return empty;
1132
1165
  if (nodePaths.size === 0) {
1133
1166
  return { installed: true, nodePaths: [], nodeOk: true, detail: "hooks use shebang (no explicit node path)" };
1134
1167
  }
@@ -1360,6 +1393,8 @@ var SKILL_INSTALL_TARGETS = {
1360
1393
  qodercn: join(homedir(), ".qoder-cn", "skills"),
1361
1394
  qoderwork: join(homedir(), ".qoderwork", "skills"),
1362
1395
  qoderworkcn: join(homedir(), ".qoderworkcn", "skills"),
1396
+ qwenwork: join(homedir(), ".qwenwork", "skills"),
1397
+ qwenworkcn: join(homedir(), ".qwenworkcn", "skills"),
1363
1398
  codex: join(homedir(), ".codex", "skills"),
1364
1399
  claude: join(homedir(), ".claude", "skills"),
1365
1400
  opencode: join(homedir(), ".config", "opencode", "skills"),
@@ -1518,7 +1553,7 @@ function hermesAllowlistPath() {
1518
1553
  return join(dirname(hermesConfigPath()), HERMES_ALLOWLIST_FILENAME);
1519
1554
  }
1520
1555
  function hermesHookApprovalHint(events = HERMES_HOOK_EVENTS) {
1521
- const hookNames = events.map((event) => `\`${event}\``).join(" and ");
1556
+ const hookNames = events.join(" and ");
1522
1557
  return `Approve the Hermes ctxdb hooks ${hookNames}: run \`hermes --accept-hooks chat\` once. This command opens an interactive chat; after Hermes starts, exit the chat, rerun \`ctxdb setup --agent hermes\`, then restart any running Hermes CLI or gateway process.`;
1523
1558
  }
1524
1559
  function backupHermesConfig() {
@@ -1971,7 +2006,7 @@ async function runUpgrade(options = {}) {
1971
2006
  var STATUS_HELP = `ctxdb status \u2014 inspect configuration and connectivity
1972
2007
 
1973
2008
  USAGE
1974
- ctxdb status [--agent <qoder|qoderwork|codex|claude|opencode|hermes|default> | --all] [--json]
2009
+ ctxdb status [--agent <qoder|qoderwork|qwenwork|codex|claude|opencode|hermes|default> | --all] [--json]
1975
2010
 
1976
2011
  FLAGS
1977
2012
  --agent <name> Inspect exactly one Agent profile
@@ -2005,6 +2040,10 @@ async function inspectStatus(agent) {
2005
2040
  top_k: cfg.topK,
2006
2041
  threshold: cfg.threshold,
2007
2042
  knowledge_top_k: cfg.knowledgeTopK,
2043
+ debug: cfg.debug,
2044
+ debug_configured: cfg.debugConfigured,
2045
+ debug_forced: cfg.debugForced,
2046
+ debug_reason: cfg.debugReason,
2008
2047
  connected,
2009
2048
  ping_error: pingError,
2010
2049
  hooks_node: hookHealth.detail,
@@ -2093,7 +2132,7 @@ async function ping(args) {
2093
2132
  var HELP = `ctxdb setup \u2014 configure an agent
2094
2133
 
2095
2134
  USAGE
2096
- ctxdb setup [--agent <qoder|qoderwork|codex|claude|opencode|hermes> | --all]
2135
+ ctxdb setup [--agent <qoder|qoderwork|qwenwork|codex|claude|opencode|hermes> | --all]
2097
2136
  [--api-key=K] [--base-url=URL] [--user-id=ID]
2098
2137
  [--no-install-skill] [--no-validate] [--json]
2099
2138
 
@@ -2114,7 +2153,7 @@ BEHAVIOR
2114
2153
  any running Hermes CLI/gateway process to load the hooks.
2115
2154
 
2116
2155
  FLAGS
2117
- --agent <name> Target agent (qoder|qoderwork|codex|claude|opencode|hermes)
2156
+ --agent <name> Target agent (qoder|qoderwork|qwenwork|codex|claude|opencode|hermes)
2118
2157
  --all Target every setup-compatible detected Agent
2119
2158
  --api-key <key> API key (required on first setup)
2120
2159
  --base-url <url> Server URL (default: https://context-database.aliyuncs.com)
@@ -2124,9 +2163,27 @@ FLAGS
2124
2163
  --json Machine-readable JSON output
2125
2164
  `;
2126
2165
  var CODEX_HOOKS_TRUST_REMINDER = [
2127
- "codex hooks \u914D\u7F6E\u540E\uFF0C\u9700\u8981\u91CD\u542F Codex \u5BF9\u8BDD\uFF0C\u5728\u5F39\u51FA\u7684 hooks \u786E\u8BA4\u754C\u9762\u9009\u62E9\u63A5\u6536\u6240\u6709 hooks(\u94A9\u5B50)\u9009\u9879\u3002",
2128
- "\u5982\u679C\u4F7F\u7528\u7684\u662F Codex App \u684C\u9762\u7248\uFF0C\u64CD\u4F5C\u8DEF\u5F84\u662F\uFF1A\u5DE6\u4E0B\u89D2\u70B9\u51FB\u7528\u6237\u540D \u2192 \u70B9\u51FB\u8BBE\u7F6E \u2192 \u70B9\u51FB\u4FA7\u8FB9\u680F\u7684 Hooks\uFF08\u94A9\u5B50\uFF09\u2192 \u70B9\u51FB\u7528\u6237\u914D\u7F6E\uFF0C\u4FE1\u4EFB UserPromptSubmit \u548C SessionStart \u91CC\u7684 aliyunrds/ctxdb \u94A9\u5B50\u3002"
2166
+ "codex hooks \u914D\u7F6E\u540E\uFF0C\u9700\u8981\u91CD\u542F Codex \u5BF9\u8BDD\uFF0C\u5728\u5F39\u51FA\u7684 hooks \u786E\u8BA4\u754C\u9762\u9009\u62E9`\u63A5\u6536\u6240\u6709 hooks(\u94A9\u5B50)`\u9009\u9879\u3002",
2167
+ "\u5982\u679C\u4F7F\u7528\u7684\u662F Codex App \u684C\u9762\u7248\uFF0C\u64CD\u4F5C\u8DEF\u5F84\u662F\uFF1A\u5DE6\u4E0B\u89D2\u70B9\u51FB\u7528\u6237\u540D \u2192 \u70B9\u51FB\u8BBE\u7F6E \u2192 \u70B9\u51FB\u4FA7\u8FB9\u680F\u7684 `Hooks\uFF08\u94A9\u5B50\uFF09`\u2192 \u70B9\u51FB`\u7528\u6237\u914D\u7F6E`\uFF0C\u4FE1\u4EFB `UserPromptSubmit`\u3001`SessionStart` \u548C `Stop` \u91CC\u7684 `aliyunrds/ctxdb` \u94A9\u5B50\u3002"
2129
2168
  ].join("\n");
2169
+ var FULL_APP_RESTART_REMINDERS = {
2170
+ qoder: "Next action: \u8BF7\u5B8C\u5168\u9000\u51FA\u5E76\u91CD\u65B0\u542F\u52A8 Qoder\uFF08\u4E0D\u662F\u53EA\u5173\u95ED\u5F53\u524D\u5BF9\u8BDD\uFF09\uFF0C\u4F7F\u65B0\u7684 hooks \u548C skill \u751F\u6548\u3002",
2171
+ qoderwork: "Next action: \u8BF7\u5B8C\u5168\u9000\u51FA\u5E76\u91CD\u65B0\u542F\u52A8 QoderWork\uFF08\u4E0D\u662F\u53EA\u5173\u95ED\u5F53\u524D\u5BF9\u8BDD\uFF09\uFF0C\u4F7F\u65B0\u7684 hooks \u548C skill \u751F\u6548\u3002",
2172
+ qwenwork: "Next action: \u8BF7\u5B8C\u5168\u9000\u51FA\u5E76\u91CD\u65B0\u542F\u52A8 QwenWork\uFF08\u4E0D\u662F\u53EA\u5173\u95ED\u5F53\u524D\u5BF9\u8BDD\uFF09\uFF0C\u4F7F\u65B0\u7684 hooks \u548C skill \u751F\u6548\u3002"
2173
+ };
2174
+ function printPostSetupReminder(agent) {
2175
+ const restartReminder = FULL_APP_RESTART_REMINDERS[agent];
2176
+ if (restartReminder) {
2177
+ process.stderr.write(`
2178
+ ${dim(restartReminder)}
2179
+ `);
2180
+ }
2181
+ if (agent === "codex") {
2182
+ process.stderr.write(`
2183
+ ${dim(CODEX_HOOKS_TRUST_REMINDER)}
2184
+ `);
2185
+ }
2186
+ }
2130
2187
  function parseAgent(args) {
2131
2188
  const raw = args.flags.agent;
2132
2189
  if (raw === void 0) return "default";
@@ -2158,23 +2215,25 @@ async function setup(args) {
2158
2215
  });
2159
2216
  printResult(result2, json);
2160
2217
  if (!json && result2.hints) {
2161
- for (const hint of result2.hints) process.stderr.write(`
2162
- ${hint}
2218
+ for (const hint of result2.hints) {
2219
+ process.stderr.write(`
2220
+ ${highlightInlineCode(hint)}
2163
2221
  `);
2222
+ }
2164
2223
  }
2165
- if (!json && result2.agents.codex?.ok) {
2166
- process.stderr.write(
2167
- `
2168
- ${dim(CODEX_HOOKS_TRUST_REMINDER)}
2169
- `
2170
- );
2224
+ if (!json) {
2225
+ for (const agent2 of ["qoder", "qoderwork", "qwenwork", "codex"]) {
2226
+ if (result2.agents[agent2]?.ok) {
2227
+ printPostSetupReminder(agent2);
2228
+ }
2229
+ }
2171
2230
  }
2172
2231
  return result2.ok ? 0 : 1;
2173
2232
  }
2174
2233
  const agent = parseAgent(args);
2175
2234
  if (agent === "default" && !json && !configuredAgents().includes("default")) {
2176
2235
  process.stderr.write(
2177
- `hint: creating CLI-only "default" agent (no hooks/skills). Use --agent <claude|qoder|qoderwork|codex|opencode|hermes> for full setup.
2236
+ `hint: creating CLI-only "default" agent (no hooks/skills). Use --agent <claude|qoder|qoderwork|qwenwork|codex|opencode|hermes> for full setup.
2178
2237
  `
2179
2238
  );
2180
2239
  }
@@ -2188,16 +2247,14 @@ ${dim(CODEX_HOOKS_TRUST_REMINDER)}
2188
2247
  });
2189
2248
  printResult(result, json);
2190
2249
  if (!json && result.hints) {
2191
- for (const h of result.hints) process.stderr.write(`
2192
- ${h}
2250
+ for (const h of result.hints) {
2251
+ process.stderr.write(`
2252
+ ${highlightInlineCode(h)}
2193
2253
  `);
2254
+ }
2194
2255
  }
2195
- if (!json && agent === "codex" && result.ok) {
2196
- process.stderr.write(
2197
- `
2198
- ${dim(CODEX_HOOKS_TRUST_REMINDER)}
2199
- `
2200
- );
2256
+ if (!json && result.ok) {
2257
+ printPostSetupReminder(agent);
2201
2258
  }
2202
2259
  return result.ok ? 0 : 1;
2203
2260
  }
@@ -2206,11 +2263,11 @@ ${dim(CODEX_HOOKS_TRUST_REMINDER)}
2206
2263
  var HELP2 = `ctxdb uninstall \u2014 remove hooks + skills
2207
2264
 
2208
2265
  USAGE
2209
- ctxdb uninstall [--agent <qoder|qoderwork|codex|claude|opencode|hermes>] [--purge-config] [--purge-logs] [--purge-all] [--json]
2266
+ ctxdb uninstall [--agent <qoder|qoderwork|qwenwork|codex|claude|opencode|hermes>] [--purge-config] [--purge-logs] [--purge-all] [--json]
2210
2267
 
2211
2268
  DEFAULT BEHAVIOR (no --agent, no purge flags)
2212
2269
  Strips ctxdb hook entries and skill directories for ALL agents (qoder,
2213
- qoderwork, codex, claude, opencode, hermes). Keeps ~/.ctxdb/ctxdb.json (credentials) and ~/.ctxdb/logs/
2270
+ qoderwork, qwenwork, codex, claude, opencode, hermes). Keeps ~/.ctxdb/ctxdb.json (credentials) and ~/.ctxdb/logs/
2214
2271
  so you can re-run \`ctxdb setup\` later without losing configuration.
2215
2272
 
2216
2273
  WITH --agent <name>
@@ -2218,7 +2275,7 @@ WITH --agent <name>
2218
2275
  Other agents remain untouched.
2219
2276
 
2220
2277
  FLAGS
2221
- --agent <name> Target a single agent (qoder|qoderwork|codex|claude|opencode|hermes)
2278
+ --agent <name> Target a single agent (qoder|qoderwork|qwenwork|codex|claude|opencode|hermes)
2222
2279
  --purge-config Also delete ~/.ctxdb/ctxdb.json
2223
2280
  --purge-logs Also delete ~/.ctxdb/logs/
2224
2281
  --purge-all Delete everything under ~/.ctxdb/
@@ -2270,7 +2327,7 @@ ${h}
2270
2327
  var HELP3 = `ctxdb upgrade \u2014 refresh skills + hooks
2271
2328
 
2272
2329
  USAGE
2273
- ctxdb upgrade [--agent <qoder|qoderwork|codex|claude|opencode|hermes>] [--no-self-update] [--json]
2330
+ ctxdb upgrade [--agent <qoder|qoderwork|qwenwork|codex|claude|opencode|hermes>] [--no-self-update] [--json]
2274
2331
 
2275
2332
  BEHAVIOR
2276
2333
  Pulls the latest @aliyunrds/ctxdb package from npm, then re-runs setup
@@ -2280,7 +2337,7 @@ BEHAVIOR
2280
2337
  With --agent: sets up only the specified agent.
2281
2338
 
2282
2339
  FLAGS
2283
- --agent <name> Target a single agent (qoder|qoderwork|codex|claude|opencode|hermes)
2340
+ --agent <name> Target a single agent (qoder|qoderwork|qwenwork|codex|claude|opencode|hermes)
2284
2341
  --self-update Pull latest package from npm (enabled by default)
2285
2342
  --no-self-update Skip the npm package update and only re-run setup
2286
2343
  --json Machine-readable JSON output
@@ -2408,7 +2465,8 @@ function skillInstall(args) {
2408
2465
  }
2409
2466
  const TARGET_TEMPLATE_AGENT = {
2410
2467
  qodercn: "qoder",
2411
- qoderworkcn: "qoderwork"
2468
+ qoderworkcn: "qoderwork",
2469
+ qwenworkcn: "qwenwork"
2412
2470
  };
2413
2471
  const templateAgent = TARGET_TEMPLATE_AGENT[target] ?? (target && isBuiltinAgent(target) ? target : "default");
2414
2472
  const result = installSkillsTo(targetRoot, templateAgent);
@@ -2670,6 +2728,163 @@ async function kbSearch(args) {
2670
2728
  return 0;
2671
2729
  }
2672
2730
 
2731
+ // src/cli/debug-cli.ts
2732
+ import {
2733
+ readRecallTraces
2734
+ } from "@aliyunrds/ctxdb-shared";
2735
+ var CONTROL_HELP = `ctxdb debug enable|disable \u2014 control local recall tracing
2736
+
2737
+ USAGE
2738
+ ctxdb debug enable [--agent=<name>] [--json]
2739
+ ctxdb debug disable [--agent=<name>] [--json]
2740
+
2741
+ Debug is forced on when the final CTXDB base URL is not the official
2742
+ production URL. A forced profile cannot be disabled until its endpoint changes.
2743
+ `;
2744
+ var RECALL_HELP = `ctxdb debug recall \u2014 replay local recall traces
2745
+
2746
+ USAGE
2747
+ ctxdb debug recall (--session=<id> | --event=<id>) [--full] [--json]
2748
+
2749
+ Reads ~/.ctxdb/logs/recall-trace.jsonl and its rotated generations.
2750
+ An unmatched recall.start means the hook was interrupted or terminated before
2751
+ recall.finish; it is not a completed timeout outcome.
2752
+ `;
2753
+ function resultFor(agent, changed) {
2754
+ const cfg = load({ agent });
2755
+ return {
2756
+ ok: true,
2757
+ agent,
2758
+ debug: cfg.debug,
2759
+ debug_configured: cfg.debugConfigured,
2760
+ debug_forced: cfg.debugForced,
2761
+ debug_reason: cfg.debugReason,
2762
+ changed
2763
+ };
2764
+ }
2765
+ function printControlResult(result, json) {
2766
+ if (json) {
2767
+ process.stdout.write(`${JSON.stringify(result, null, 2)}
2768
+ `);
2769
+ return;
2770
+ }
2771
+ const configured = result.debug_configured ? "enabled" : "disabled";
2772
+ const effective = result.debug ? "enabled" : "disabled";
2773
+ const forced = result.debug_forced ? "yes" : "no";
2774
+ process.stdout.write(
2775
+ `ctxdb debug (${result.agent}): ${effective}
2776
+ configured: ${configured}
2777
+ forced: ${forced}
2778
+ reason: ${result.debug_reason ?? "-"}
2779
+ `
2780
+ );
2781
+ }
2782
+ async function controlDebug(args, configured) {
2783
+ if (args.flags.help || args.flags.h) {
2784
+ process.stdout.write(CONTROL_HELP);
2785
+ return 0;
2786
+ }
2787
+ const agent = agentFromFlags(args.flags);
2788
+ const current = load({ agent });
2789
+ if (!hasConfiguredAgent(agent)) {
2790
+ const hint = agent === "default" ? "run `ctxdb setup --api-key=<key>` or select a configured --agent" : `run \`ctxdb setup --agent ${agent}\` first`;
2791
+ process.stderr.write(`no configured profile for agent ${agent}; ${hint}
2792
+ `);
2793
+ return 1;
2794
+ }
2795
+ if (!configured && current.debugForced) {
2796
+ const result2 = {
2797
+ ok: false,
2798
+ agent,
2799
+ debug: current.debug,
2800
+ debug_configured: current.debugConfigured,
2801
+ debug_forced: current.debugForced,
2802
+ debug_reason: current.debugReason,
2803
+ changed: false
2804
+ };
2805
+ if (args.flags.json) {
2806
+ process.stdout.write(`${JSON.stringify(result2, null, 2)}
2807
+ `);
2808
+ } else {
2809
+ process.stderr.write(
2810
+ `cannot disable debug for ${agent}: debug is forced by non-production base_url (reason: ${current.debugReason})
2811
+ `
2812
+ );
2813
+ printControlResult(result2, false);
2814
+ }
2815
+ return 1;
2816
+ }
2817
+ const changed = current.debugConfigured !== configured;
2818
+ if (!updateConfiguredDebug(agent, configured)) {
2819
+ process.stderr.write(`failed to update debug for agent ${agent}
2820
+ `);
2821
+ return 1;
2822
+ }
2823
+ const result = resultFor(agent, changed);
2824
+ printControlResult(result, Boolean(args.flags.json));
2825
+ return 0;
2826
+ }
2827
+ function debugEnable(args) {
2828
+ return controlDebug(args, true);
2829
+ }
2830
+ function debugDisable(args) {
2831
+ return controlDebug(args, false);
2832
+ }
2833
+ function compactRecord(record) {
2834
+ const base = `${record.timestamp} ${record.agent}/${record.kind} ${record.type} event=${record.recall_event_id} session=${record.session_id ?? "-"}`;
2835
+ if (record.type === "recall.start") {
2836
+ return `${base} query_chars=${record.query.length}`;
2837
+ }
2838
+ return `${base} outcome=${record.outcome} duration_ms=${record.duration_ms} returned=${record.returned_memories.length} selected=${record.selection.selected.length} knowledge=${record.returned_knowledge.length}`;
2839
+ }
2840
+ async function debugRecall(args) {
2841
+ if (args.flags.help || args.flags.h) {
2842
+ process.stdout.write(RECALL_HELP);
2843
+ return 0;
2844
+ }
2845
+ const session = typeof args.flags.session === "string" && args.flags.session ? args.flags.session : null;
2846
+ const event = typeof args.flags.event === "string" && args.flags.event ? args.flags.event : null;
2847
+ if (session && event || !session && !event) {
2848
+ process.stderr.write(
2849
+ "exactly one of --session=<id> or --event=<id> is required\n"
2850
+ );
2851
+ return 2;
2852
+ }
2853
+ const result = readRecallTraces({
2854
+ ...session ? { sessionId: session } : { recallEventId: event }
2855
+ });
2856
+ const output = {
2857
+ ok: true,
2858
+ selector: session ? { session } : { event },
2859
+ count: result.records.length,
2860
+ malformed_lines: result.malformedLines,
2861
+ records: result.records
2862
+ };
2863
+ if (args.flags.json) {
2864
+ process.stdout.write(`${JSON.stringify(output, null, 2)}
2865
+ `);
2866
+ return 0;
2867
+ }
2868
+ if (result.records.length === 0) {
2869
+ process.stdout.write("No matching recall traces.\n");
2870
+ return 0;
2871
+ }
2872
+ if (args.flags.full) {
2873
+ process.stdout.write(`${JSON.stringify(result.records, null, 2)}
2874
+ `);
2875
+ } else {
2876
+ process.stdout.write(`${result.records.map(compactRecord).join("\n")}
2877
+ `);
2878
+ }
2879
+ if (result.malformedLines > 0) {
2880
+ process.stderr.write(
2881
+ `skipped ${result.malformedLines} malformed recall trace line(s)
2882
+ `
2883
+ );
2884
+ }
2885
+ return 0;
2886
+ }
2887
+
2673
2888
  // src/cli/main.ts
2674
2889
  var HELP5 = `ctxdb v${PACKAGE_VERSION} \u2014 RDS ContextDatabase CLI (multi-agent)
2675
2890
 
@@ -2677,7 +2892,7 @@ USAGE
2677
2892
  ctxdb <command> [args] [--flags]
2678
2893
 
2679
2894
  COMMANDS
2680
- setup [--agent <qoder|qoderwork|codex|claude|opencode|hermes> | --all]
2895
+ setup [--agent <qoder|qoderwork|qwenwork|codex|claude|opencode|hermes> | --all]
2681
2896
  [--api-key=K] [--base-url=URL] [--user-id=ID]
2682
2897
  [--no-install-skill] [--no-validate] [--json]
2683
2898
  Without --agent \u2192 writes agents.default (CLI-only, no hooks/skills)
@@ -2706,6 +2921,10 @@ COMMANDS
2706
2921
  upgrade|update [--agent <name>] [--no-self-update] [--json]
2707
2922
  Pull latest package from npm, then re-run
2708
2923
  setup. Self-update is enabled by default.
2924
+ debug enable|disable [--agent <name>] [--json]
2925
+ Control configured debug for an existing profile.
2926
+ debug recall (--session=<id> | --event=<id>) [--full] [--json]
2927
+ Replay local full-fidelity recall traces.
2709
2928
 
2710
2929
  memory add <text> [--agent=<name>] [--user-id=...] [--metadata=K1=V1,K2=V2] [--no-infer]
2711
2930
  memory search <query> [--agent=<name>] [--top-k=10] [--threshold=0.4] [--knowledge]
@@ -2740,7 +2959,7 @@ COMMANDS
2740
2959
  doc_id?/tags? for citation.
2741
2960
  --raw: server response verbatim (curl parity).
2742
2961
 
2743
- skill install --target <qoder|qoderwork|codex|claude|opencode|openclaw|hermes> [--json]
2962
+ skill install --target <qoder|qoderwork|qwenwork|codex|claude|opencode|openclaw|hermes> [--json]
2744
2963
  skill install --path <dir> [--json]
2745
2964
  Install skill files (contextdb-memory,
2746
2965
  contextdb-knowledge) to an agent's skill directory.
@@ -2763,7 +2982,7 @@ HOOK ENV VARS:
2763
2982
  Direct ctxdb CLI commands are unchanged.
2764
2983
 
2765
2984
  CONFIG: ~/.ctxdb/ctxdb.json (agents.default / agents.qoder / agents.qoderwork / agents.codex / agents.claude / agents.opencode / agents.hermes)
2766
- LOGS: ~/.ctxdb/logs/ctxdb.log
2985
+ LOGS: ~/.ctxdb/logs/ctxdb.log, ~/.ctxdb/logs/recall-trace.jsonl
2767
2986
  `;
2768
2987
  var ROUTES = {
2769
2988
  setup,
@@ -2773,6 +2992,11 @@ var ROUTES = {
2773
2992
  teardown: uninstall,
2774
2993
  upgrade,
2775
2994
  update: upgrade,
2995
+ debug: {
2996
+ enable: debugEnable,
2997
+ disable: debugDisable,
2998
+ recall: debugRecall
2999
+ },
2776
3000
  skill: {
2777
3001
  install: skillInstall
2778
3002
  },