@aliyunrds/ctxdb 0.0.10 → 1.0.0-beta.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.
package/README.md CHANGED
@@ -55,7 +55,7 @@ For **qoder**, **qoderwork**, **codex**, and **claude**, hooks fire automaticall
55
55
 
56
56
  Implementation note: qoder/Claude consume the JSON `hookSpecificOutput.additionalContext` shape; Codex has been verified on this machine through `~/.codex/hooks.json`, `[features].hooks = true`, and hook audit logs, where non-empty stdout from `UserPromptSubmit`/`SessionStart` is treated as injected context. The same hook core is shared; setup passes `--agent=<name>` so each hook reads its own config section.
57
57
 
58
- For **opencode**, `ctxdb setup --agent opencode` writes a small re-export shim at `~/.config/opencode/plugins/ctxdb.ts`. The shim points into this package's bundled `dist/opencode/src/index.ts`, so `npm update -g @aliyunrds/ctxdb` updates the plugin implementation without copying source into the user config directory. `ctxdb upgrade --agent opencode` refreshes the absolute shim target after package moves.
58
+ For **opencode**, `ctxdb setup --agent opencode` writes a small re-export shim at `~/.config/opencode/plugins/ctxdb.ts`. The shim points into this package's bundled `dist/opencode/index.js`, so `npm update -g @aliyunrds/ctxdb` updates the plugin implementation without copying source into the user config directory. `ctxdb upgrade --agent opencode` refreshes the absolute shim target after package moves.
59
59
 
60
60
  ## CLI
61
61
 
@@ -95,7 +95,7 @@ Lives at `~/.ctxdb/ctxdb.json` (co-located with logs at `~/.ctxdb/logs/`). Schem
95
95
  "user_id": "default",
96
96
  "auto_capture": true,
97
97
  "auto_recall": true,
98
- "warmup_recall": true,
98
+ "warmup_recall": false,
99
99
  "recall_knowledge": false,
100
100
  "top_k": 5,
101
101
  "threshold": 0.4,
@@ -119,7 +119,7 @@ Field reference:
119
119
  | `user_id` | str | `"default"` | mem0-layer bucket key on every capture/recall call. The server's tenant isolation runs on `member_id` (injected from `X-API-Key`), so this is an optional per-user/agent slice. Override with `ctxdb setup --agent <a> --user-id <bucket>` or `CTXDB_USER_ID=<bucket>` when you need to isolate this install from another access layer or machine sharing the same workspace |
120
120
  | `auto_capture` | bool | `true` | Stop hook captures each turn into long-term memory for the selected agent |
121
121
  | `auto_recall` | bool | `true` | UserPromptSubmit hook recalls memory on each user prompt for the selected agent |
122
- | `warmup_recall` | bool | `true` | SessionStart hook recalls cwd/git-related memories for the selected agent |
122
+ | `warmup_recall` | bool | `false` | SessionStart hook recalls cwd/git-related memories for the selected agent. **Default is off** — open it per-agent when you want session-start warmup (adds one bounded, circuit-protected recall call on session start) |
123
123
  | `recall_knowledge` | bool | `false` | When `auto_recall` is on, also pull KB chunks alongside memory. Default is **off** — the recommended KB-recall path is the agent calling `kb search --agent <name>` explicitly when the user asks |
124
124
  | `top_k` / `threshold` | int / float | `5` / `0.4` | Memory recall pagination + similarity floor. `5` keeps the codex TUI `hook context: ...` line short enough to scan and bounds token spend on the modal recall path; raise it per-agent if you want more candidates |
125
125
  | `knowledge_top_k` | int | `6` | KB chunks pulled per recall (only effective when `recall_knowledge: true`) |
@@ -132,7 +132,7 @@ Env-var overrides apply to the selected agent config (env wins): `CTXDB_AGENT` /
132
132
  ```
133
133
  @aliyunrds/ctxdb ← this package (CLI + setup + hooks + skills)
134
134
 
135
- ├─ bundles OpenCode plugin source in dist/opencode/src
135
+ ├─ bundles OpenCode plugin in dist/opencode/index.js
136
136
 
137
137
  └─ depends on @aliyunrds/ctxdb-shared ← input sanitation,
138
138
  prompt-injection defenses,
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  configDir
4
- } from "./chunk-F25Q3WM4.js";
4
+ } from "./chunk-QHYJ7OXC.js";
5
5
 
6
6
  // src/lib/circuit.ts
7
7
  import { statSync, writeFileSync, unlinkSync, mkdirSync, readdirSync, readFileSync } from "fs";
@@ -285,6 +285,7 @@ function agentHomeDir(agent) {
285
285
  }
286
286
  }
287
287
  var AGENT_VARIANT_HOMES = {
288
+ qoder: [".qoder-cn"],
288
289
  qoderwork: [".qoderworkcn"]
289
290
  };
290
291
  function agentHomeDirs(agent) {
@@ -6,10 +6,10 @@ import {
6
6
  isConnectionError,
7
7
  resetCircuit,
8
8
  tripCircuit
9
- } from "./chunk-XWPTIFUK.js";
9
+ } from "./chunk-PLWEIEFH.js";
10
10
  import {
11
11
  CtxdbError
12
- } from "./chunk-F25Q3WM4.js";
12
+ } from "./chunk-QHYJ7OXC.js";
13
13
 
14
14
  // src/lib/recall-orchestrator.ts
15
15
  import {
package/dist/cli/main.js CHANGED
@@ -31,7 +31,7 @@ import {
31
31
  removeAgent,
32
32
  save,
33
33
  writeInstalledPkgVersion
34
- } from "../chunk-F25Q3WM4.js";
34
+ } from "../chunk-QHYJ7OXC.js";
35
35
 
36
36
  // src/cli/util.ts
37
37
  var BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
@@ -115,6 +115,9 @@ var BOLD = "\x1B[1m";
115
115
  var RESET = "\x1B[0m";
116
116
  var CHECK = `${GREEN}\u2714${RESET}`;
117
117
  var CROSS = `${RED}\u2718${RESET}`;
118
+ function dim(text) {
119
+ return `${DIM}${text}${RESET}`;
120
+ }
118
121
  function isSetupResult(v) {
119
122
  if (typeof v !== "object" || v === null) return false;
120
123
  return "steps" in v && Array.isArray(v.steps);
@@ -279,6 +282,24 @@ var LEGACY_QODER_SKILL_DIRS = [
279
282
  "qoder-ctxdb"
280
283
  ];
281
284
  var HOOK_EVENTS = ["UserPromptSubmit", "Stop", "SessionStart"];
285
+ var MIN_NODE_MAJOR = 20;
286
+ function parseNodeMajor(version) {
287
+ const match = /^v?(\d+)/.exec(version.trim());
288
+ if (!match) return null;
289
+ const major = Number.parseInt(match[1], 10);
290
+ return Number.isFinite(major) ? major : null;
291
+ }
292
+ function checkCurrentNodeVersion() {
293
+ const version = process.versions.node;
294
+ const major = parseNodeMajor(version);
295
+ if (major !== null && major >= MIN_NODE_MAJOR) return null;
296
+ const current = version.startsWith("v") ? version : `v${version}`;
297
+ return {
298
+ step: "check-node-version",
299
+ ok: false,
300
+ detail: `Node.js >=${MIN_NODE_MAJOR} is required by ctxdb; current ${current} at ${process.execPath}. Switch to Node 20+ (for example: \`nvm install 20 && nvm use 20\`), reinstall @aliyunrds/ctxdb, then rerun \`ctxdb setup\`.`
301
+ };
302
+ }
282
303
  async function runSetup(options) {
283
304
  const steps = [];
284
305
  if (!isAgentSlug(options.agent)) {
@@ -292,6 +313,11 @@ async function runSetup(options) {
292
313
  const agent = options.agent;
293
314
  const installSkill = options.installSkill !== false;
294
315
  const validate = options.validate !== false;
316
+ const nodeVersionCheck = checkCurrentNodeVersion();
317
+ if (nodeVersionCheck) {
318
+ steps.push(nodeVersionCheck);
319
+ return { ok: false, steps };
320
+ }
295
321
  if (isBuiltinAgent(agent)) {
296
322
  const homeCheck = checkAgentHome(agent);
297
323
  steps.push(homeCheck);
@@ -418,7 +444,7 @@ async function runSetup(options) {
418
444
  steps.push({
419
445
  step: "install-opencode-shim",
420
446
  ok: false,
421
- detail: "could not resolve plugin entry under @aliyunrds/ctxdb/dist/opencode/src"
447
+ detail: "could not resolve plugin entry under @aliyunrds/ctxdb/dist/opencode"
422
448
  });
423
449
  return { ok: false, steps };
424
450
  }
@@ -789,7 +815,7 @@ function checkHookNodePaths(agent) {
789
815
  if (closeQuote > 1) nodePath = cmd.slice(1, closeQuote);
790
816
  } else {
791
817
  const parts = cmd.split(" ");
792
- if (parts.length >= 2 && !parts[0].endsWith(".js") && !parts[0].endsWith(".ts")) {
818
+ if (parts.length >= 2 && !parts[0].endsWith(".js") && !parts[0].endsWith(".ts") && (parts[0].includes("/") || parts[0].includes("\\"))) {
793
819
  nodePath = parts[0];
794
820
  }
795
821
  }
@@ -1021,6 +1047,7 @@ function copySkillDir(src, dest, agent) {
1021
1047
  }
1022
1048
  var SKILL_INSTALL_TARGETS = {
1023
1049
  qoder: join(homedir(), ".qoder", "skills"),
1050
+ qodercn: join(homedir(), ".qoder-cn", "skills"),
1024
1051
  qoderwork: join(homedir(), ".qoderwork", "skills"),
1025
1052
  qoderworkcn: join(homedir(), ".qoderworkcn", "skills"),
1026
1053
  codex: join(homedir(), ".codex", "skills"),
@@ -1090,7 +1117,7 @@ function resolveOpencodePluginEntry() {
1090
1117
  const pkgRoot = walkUpToPackageJson(here, "@aliyunrds/ctxdb");
1091
1118
  if (!pkgRoot) return null;
1092
1119
  const candidates = [
1093
- join(pkgRoot, "dist", "opencode", "src", "index.ts"),
1120
+ join(pkgRoot, "dist", "opencode", "index.js"),
1094
1121
  join(pkgRoot, "..", "opencode", "src", "index.ts")
1095
1122
  ];
1096
1123
  return candidates.find((candidate) => existsSync(candidate)) ?? null;
@@ -1123,7 +1150,8 @@ var TOOL_SCOPED_EVENTS = /* @__PURE__ */ new Set(["PreToolUse", "PostToolUse"]);
1123
1150
  function appendOne(hooks, event, command, agent) {
1124
1151
  if (!Array.isArray(hooks[event])) hooks[event] = [];
1125
1152
  const useExecForm = agent === "claude";
1126
- const shellCmd = process.platform === "win32" ? `"${process.execPath.replace(/\\/g, "/")}" "${command.replace(/\\/g, "/")}" --agent=${agent}` : `${process.execPath} ${command} --agent=${agent}`;
1153
+ const cmdRunner = agent === "qoder";
1154
+ const shellCmd = process.platform === "win32" ? cmdRunner ? `node ${command.replace(/\\/g, "/")} --agent=${agent}` : `"${process.execPath.replace(/\\/g, "/")}" "${command.replace(/\\/g, "/")}" --agent=${agent}` : `${process.execPath} ${command} --agent=${agent}`;
1127
1155
  const dup = hooks[event].some(
1128
1156
  (entry2) => Array.isArray(entry2?.hooks) && entry2.hooks.some(
1129
1157
  (h) => h?.type === "command" && (Array.isArray(h.args) && h.args[0] === command || typeof h.command === "string" && h.command.includes(command))
@@ -1462,7 +1490,7 @@ function upgradeOneAgent(agent) {
1462
1490
  steps.push({
1463
1491
  step: "refresh-opencode-shim",
1464
1492
  ok: false,
1465
- detail: "could not resolve plugin entry under @aliyunrds/ctxdb/dist/opencode/src"
1493
+ detail: "could not resolve plugin entry under @aliyunrds/ctxdb/dist/opencode"
1466
1494
  });
1467
1495
  return { ok: false, steps };
1468
1496
  }
@@ -1594,6 +1622,13 @@ async function setup(args) {
1594
1622
  ${h}
1595
1623
  `);
1596
1624
  }
1625
+ if (!json && agent === "codex" && result.ok) {
1626
+ process.stderr.write(
1627
+ `
1628
+ ${dim("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")}
1629
+ `
1630
+ );
1631
+ }
1597
1632
  return result.ok ? 0 : 1;
1598
1633
  }
1599
1634
 
@@ -1887,7 +1922,11 @@ function skillInstall(args) {
1887
1922
  }
1888
1923
  targetRoot = resolved;
1889
1924
  }
1890
- const templateAgent = target && isBuiltinAgent(target) ? target : "default";
1925
+ const TARGET_TEMPLATE_AGENT = {
1926
+ qodercn: "qoder",
1927
+ qoderworkcn: "qoderwork"
1928
+ };
1929
+ const templateAgent = TARGET_TEMPLATE_AGENT[target] ?? (target && isBuiltinAgent(target) ? target : "default");
1891
1930
  const result = installSkillsTo(targetRoot, templateAgent);
1892
1931
  const ok = result.ok;
1893
1932
  const output = {
@@ -2,11 +2,11 @@
2
2
  import {
3
3
  fetchKbCatalogBlock,
4
4
  recallTurn
5
- } from "../chunk-I5HRGFZO.js";
5
+ } from "../chunk-QPFFMW52.js";
6
6
  import "../chunk-6S5RJYBC.js";
7
7
  import {
8
8
  isCircuitOpen
9
- } from "../chunk-XWPTIFUK.js";
9
+ } from "../chunk-PLWEIEFH.js";
10
10
  import {
11
11
  HttpClient,
12
12
  agentFromArgvWithFallback,
@@ -14,7 +14,7 @@ import {
14
14
  isComplete,
15
15
  load,
16
16
  setDebug
17
- } from "../chunk-F25Q3WM4.js";
17
+ } from "../chunk-QHYJ7OXC.js";
18
18
 
19
19
  // src/hooks/session-start.ts
20
20
  import { pathToFileURL } from "url";
@@ -4,7 +4,7 @@ import {
4
4
  isConnectionError,
5
5
  resetCircuit,
6
6
  tripCircuit
7
- } from "../chunk-XWPTIFUK.js";
7
+ } from "../chunk-PLWEIEFH.js";
8
8
  import {
9
9
  CtxdbError,
10
10
  HttpClient,
@@ -13,7 +13,7 @@ import {
13
13
  isDebug,
14
14
  load,
15
15
  setDebug
16
- } from "../chunk-F25Q3WM4.js";
16
+ } from "../chunk-QHYJ7OXC.js";
17
17
 
18
18
  // src/lib/capture-orchestrator.ts
19
19
  import {
@@ -2,11 +2,11 @@
2
2
  import {
3
3
  fetchKbCatalogBlock,
4
4
  recallTurn
5
- } from "../chunk-I5HRGFZO.js";
5
+ } from "../chunk-QPFFMW52.js";
6
6
  import "../chunk-6S5RJYBC.js";
7
7
  import {
8
8
  isCircuitOpen
9
- } from "../chunk-XWPTIFUK.js";
9
+ } from "../chunk-PLWEIEFH.js";
10
10
  import {
11
11
  HttpClient,
12
12
  agentFromArgvWithFallback,
@@ -14,7 +14,7 @@ import {
14
14
  isComplete,
15
15
  load,
16
16
  setDebug
17
- } from "../chunk-F25Q3WM4.js";
17
+ } from "../chunk-QHYJ7OXC.js";
18
18
 
19
19
  // src/hooks/user-prompt-submit.ts
20
20
  import { pathToFileURL } from "url";