@aliyunrds/ctxdb 0.0.7 → 0.0.8-beta.2
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/{chunk-Q2EEP4CE.js → chunk-52IAVJRK.js} +1 -1
- package/dist/{chunk-LIC44DR6.js → chunk-73OY44GY.js} +34 -3
- package/dist/{chunk-S45GOYUU.js → chunk-BWPFGTF7.js} +25 -8
- package/dist/cli/main.js +41 -22
- package/dist/hooks/session-start.js +64 -32
- package/dist/hooks/stop.js +167 -23
- package/dist/hooks/user-prompt-submit.js +41 -45
- package/dist/setup/skills/contextdb-knowledge/SKILL.md +135 -105
- package/dist/setup/skills/contextdb-memory/SKILL.md +137 -95
- package/package.json +2 -3
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
listKnowledgeBases
|
|
4
|
+
} from "./chunk-6S5RJYBC.js";
|
|
2
5
|
import {
|
|
3
6
|
isConnectionError,
|
|
4
7
|
resetCircuit,
|
|
5
8
|
tripCircuit
|
|
6
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-52IAVJRK.js";
|
|
7
10
|
import {
|
|
8
11
|
CtxdbError
|
|
9
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-BWPFGTF7.js";
|
|
10
13
|
|
|
11
14
|
// src/lib/recall-orchestrator.ts
|
|
12
15
|
import {
|
|
@@ -138,6 +141,34 @@ async function recallTurn(prompt, cfg, client, agent = "default") {
|
|
|
138
141
|
};
|
|
139
142
|
}
|
|
140
143
|
|
|
144
|
+
// src/lib/kb-catalog.ts
|
|
145
|
+
function sanitizeKeyEntities(raw) {
|
|
146
|
+
if (!Array.isArray(raw)) return [];
|
|
147
|
+
const out = [];
|
|
148
|
+
for (const e of raw) {
|
|
149
|
+
if (typeof e !== "string") continue;
|
|
150
|
+
const cleaned = e.replace(/\s+/g, " ").trim();
|
|
151
|
+
if (cleaned.length > 0) out.push(cleaned);
|
|
152
|
+
}
|
|
153
|
+
return out;
|
|
154
|
+
}
|
|
155
|
+
async function fetchKbCatalogBlock(client, agent) {
|
|
156
|
+
const kbs = await listKnowledgeBases(client);
|
|
157
|
+
const active = kbs.filter((kb) => kb.status === "active");
|
|
158
|
+
if (active.length === 0) return "";
|
|
159
|
+
const lines = active.map((kb) => {
|
|
160
|
+
const ents = sanitizeKeyEntities(kb.key_entities);
|
|
161
|
+
return ents.length > 0 ? `\xB7 ${kb.name}: ${ents.join(", ")}` : `\xB7 ${kb.name}`;
|
|
162
|
+
});
|
|
163
|
+
return [
|
|
164
|
+
"<available-knowledge-bases>",
|
|
165
|
+
`When you identify that relevant information may exist in the knowledge bases below, you MUST run \`ctxdb kb search "<query>" --kb=<name> --agent=${agent}\` with targeted keywords after initial analysis to supplement and correct your approach. Knowledge bases:`,
|
|
166
|
+
...lines,
|
|
167
|
+
"</available-knowledge-bases>"
|
|
168
|
+
].join("\n");
|
|
169
|
+
}
|
|
170
|
+
|
|
141
171
|
export {
|
|
142
|
-
recallTurn
|
|
172
|
+
recallTurn,
|
|
173
|
+
fetchKbCatalogBlock
|
|
143
174
|
};
|
|
@@ -39,23 +39,27 @@ ${s}`;
|
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
// src/lib/
|
|
42
|
+
// src/lib/package-version.ts
|
|
43
43
|
import { readFileSync } from "fs";
|
|
44
|
-
import { fileURLToPath } from "url";
|
|
45
44
|
import { dirname as dirname2, join as join2 } from "path";
|
|
45
|
+
import { fileURLToPath } from "url";
|
|
46
46
|
function findPackageVersion() {
|
|
47
47
|
let dir = dirname2(fileURLToPath(import.meta.url));
|
|
48
48
|
for (let i = 0; i < 5; i++) {
|
|
49
49
|
try {
|
|
50
50
|
const pkg = JSON.parse(readFileSync(join2(dir, "package.json"), "utf-8"));
|
|
51
|
-
if (pkg.name === "@aliyunrds/ctxdb"
|
|
51
|
+
if (pkg.name === "@aliyunrds/ctxdb" && typeof pkg.version === "string") {
|
|
52
|
+
return pkg.version;
|
|
53
|
+
}
|
|
52
54
|
} catch {
|
|
53
55
|
}
|
|
54
56
|
dir = dirname2(dir);
|
|
55
57
|
}
|
|
56
58
|
return "0.0.0";
|
|
57
59
|
}
|
|
58
|
-
var
|
|
60
|
+
var PACKAGE_VERSION = findPackageVersion();
|
|
61
|
+
|
|
62
|
+
// src/lib/http-client.ts
|
|
59
63
|
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
60
64
|
var CtxdbError = class extends Error {
|
|
61
65
|
constructor(message) {
|
|
@@ -108,7 +112,7 @@ var HttpClient = class {
|
|
|
108
112
|
this.baseUrl = opts.baseUrl.replace(/\/+$/, "");
|
|
109
113
|
this.apiKey = opts.apiKey;
|
|
110
114
|
this.timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
111
|
-
this.userAgent = opts.userAgent ?? `ctxdb-cli/${
|
|
115
|
+
this.userAgent = opts.userAgent ?? `ctxdb-cli/${PACKAGE_VERSION}`;
|
|
112
116
|
this.extraHeaders = { ...opts.extraHeaders ?? {} };
|
|
113
117
|
const f = opts.fetchImpl ?? globalThis.fetch.bind(globalThis);
|
|
114
118
|
this.fetchImpl = f;
|
|
@@ -257,7 +261,7 @@ function extractErrorDetail(text, fallback) {
|
|
|
257
261
|
// src/lib/agents.ts
|
|
258
262
|
import { homedir as homedir2 } from "os";
|
|
259
263
|
import { join as join3 } from "path";
|
|
260
|
-
var SUPPORTED_AGENTS = ["qoder", "codex", "claude"];
|
|
264
|
+
var SUPPORTED_AGENTS = ["qoder", "qoderwork", "codex", "claude"];
|
|
261
265
|
function isBuiltinAgent(v) {
|
|
262
266
|
return typeof v === "string" && SUPPORTED_AGENTS.includes(v);
|
|
263
267
|
}
|
|
@@ -269,6 +273,8 @@ function agentHomeDir(agent) {
|
|
|
269
273
|
switch (agent) {
|
|
270
274
|
case "qoder":
|
|
271
275
|
return join3(homedir2(), ".qoder");
|
|
276
|
+
case "qoderwork":
|
|
277
|
+
return join3(homedir2(), ".qoderwork");
|
|
272
278
|
case "codex":
|
|
273
279
|
return join3(homedir2(), ".codex");
|
|
274
280
|
case "claude":
|
|
@@ -308,6 +314,7 @@ var DEFAULT_USER_ID = "default";
|
|
|
308
314
|
var DEFAULT_TOP_K = 5;
|
|
309
315
|
var DEFAULT_THRESHOLD = 0.4;
|
|
310
316
|
var DEFAULT_KNOWLEDGE_TOP_K = 6;
|
|
317
|
+
var DEFAULT_KB_CATALOG_INJECTION = "session_start";
|
|
311
318
|
function isComplete(cfg) {
|
|
312
319
|
return Boolean(cfg.apiKey && cfg.baseUrl);
|
|
313
320
|
}
|
|
@@ -330,6 +337,12 @@ function coerceBool(v, fallback) {
|
|
|
330
337
|
if (v === void 0 || v === null) return fallback;
|
|
331
338
|
return Boolean(v);
|
|
332
339
|
}
|
|
340
|
+
function coerceKbCatalogInjection(v) {
|
|
341
|
+
if (v === "session_start" || v === "user_prompt_submit" || v === "off") {
|
|
342
|
+
return v;
|
|
343
|
+
}
|
|
344
|
+
return DEFAULT_KB_CATALOG_INJECTION;
|
|
345
|
+
}
|
|
333
346
|
function readRaw(path) {
|
|
334
347
|
if (!existsSync(path)) return {};
|
|
335
348
|
try {
|
|
@@ -367,7 +380,8 @@ function configFromDisk(raw) {
|
|
|
367
380
|
topK: coerceInt(raw.top_k, DEFAULT_TOP_K),
|
|
368
381
|
threshold: coerceFloat(raw.threshold, DEFAULT_THRESHOLD),
|
|
369
382
|
knowledgeTopK: coerceInt(raw.knowledge_top_k, DEFAULT_KNOWLEDGE_TOP_K),
|
|
370
|
-
debug: coerceBool(raw.debug, false)
|
|
383
|
+
debug: coerceBool(raw.debug, false),
|
|
384
|
+
kbCatalogInjection: coerceKbCatalogInjection(raw.kb_catalog_injection)
|
|
371
385
|
};
|
|
372
386
|
}
|
|
373
387
|
function applyEnv(cfg, env) {
|
|
@@ -416,7 +430,8 @@ function configToDisk(cfg) {
|
|
|
416
430
|
top_k: cfg.topK,
|
|
417
431
|
threshold: cfg.threshold,
|
|
418
432
|
knowledge_top_k: cfg.knowledgeTopK,
|
|
419
|
-
debug: cfg.debug
|
|
433
|
+
debug: cfg.debug,
|
|
434
|
+
kb_catalog_injection: cfg.kbCatalogInjection
|
|
420
435
|
};
|
|
421
436
|
}
|
|
422
437
|
function removeAgent(agent, path, options = {}) {
|
|
@@ -481,7 +496,9 @@ function writeInstalledPkgVersion(version, path) {
|
|
|
481
496
|
|
|
482
497
|
export {
|
|
483
498
|
setDebug,
|
|
499
|
+
isDebug,
|
|
484
500
|
debug,
|
|
501
|
+
PACKAGE_VERSION,
|
|
485
502
|
CtxdbError,
|
|
486
503
|
HttpClient,
|
|
487
504
|
SUPPORTED_AGENTS,
|
package/dist/cli/main.js
CHANGED
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
DEFAULT_BASE_URL,
|
|
19
19
|
DEFAULT_USER_ID,
|
|
20
20
|
HttpClient,
|
|
21
|
+
PACKAGE_VERSION,
|
|
21
22
|
SUPPORTED_AGENTS,
|
|
22
23
|
agentFromEnv,
|
|
23
24
|
agentHomeDir,
|
|
@@ -29,7 +30,7 @@ import {
|
|
|
29
30
|
removeAgent,
|
|
30
31
|
save,
|
|
31
32
|
writeInstalledPkgVersion
|
|
32
|
-
} from "../chunk-
|
|
33
|
+
} from "../chunk-BWPFGTF7.js";
|
|
33
34
|
|
|
34
35
|
// src/cli/util.ts
|
|
35
36
|
var BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
|
|
@@ -216,7 +217,6 @@ function fail(message, code = 1) {
|
|
|
216
217
|
`);
|
|
217
218
|
process.exit(code);
|
|
218
219
|
}
|
|
219
|
-
var PACKAGE_VERSION = "0.0.7";
|
|
220
220
|
|
|
221
221
|
// src/setup/installer.ts
|
|
222
222
|
import {
|
|
@@ -242,6 +242,8 @@ function skillInstallRoot(agent) {
|
|
|
242
242
|
switch (agent) {
|
|
243
243
|
case "qoder":
|
|
244
244
|
return join(homedir(), ".qoder", "skills");
|
|
245
|
+
case "qoderwork":
|
|
246
|
+
return join(homedir(), ".qoderwork", "skills");
|
|
245
247
|
case "codex":
|
|
246
248
|
return join(homedir(), ".codex", "skills");
|
|
247
249
|
case "claude":
|
|
@@ -257,6 +259,8 @@ function hookConfigPath(agent) {
|
|
|
257
259
|
switch (agent) {
|
|
258
260
|
case "qoder":
|
|
259
261
|
return join(homedir(), ".qoder", "settings.json");
|
|
262
|
+
case "qoderwork":
|
|
263
|
+
return join(homedir(), ".qoderwork", "settings.json");
|
|
260
264
|
case "codex":
|
|
261
265
|
return join(homedir(), ".codex", "hooks.json");
|
|
262
266
|
case "claude":
|
|
@@ -306,6 +310,14 @@ async function runSetup(options) {
|
|
|
306
310
|
ok: true,
|
|
307
311
|
detail: `${agent}: ${cfg.baseUrl} (user_id=${cfg.userId})`
|
|
308
312
|
});
|
|
313
|
+
if (isBuiltinAgent(agent) && !configuredAgents().includes("default")) {
|
|
314
|
+
save(cfg, void 0, { agent: "default" });
|
|
315
|
+
steps.push({
|
|
316
|
+
step: "write-default-config",
|
|
317
|
+
ok: true,
|
|
318
|
+
detail: `default: copied from ${agent}`
|
|
319
|
+
});
|
|
320
|
+
}
|
|
309
321
|
if (installSkill && isBuiltinAgent(agent)) {
|
|
310
322
|
const installRoot = skillInstallRoot(agent);
|
|
311
323
|
const skillResult = installSkillsTo(installRoot, agent);
|
|
@@ -624,8 +636,10 @@ function checkHookNodePaths(agent) {
|
|
|
624
636
|
if (!entryIsCtxdb(entry)) continue;
|
|
625
637
|
for (const h of entry.hooks ?? []) {
|
|
626
638
|
if (h?.type !== "command" || typeof h.command !== "string") continue;
|
|
627
|
-
|
|
628
|
-
|
|
639
|
+
if (Array.isArray(h.args) && h.args.length > 0) {
|
|
640
|
+
nodePaths.add(h.command);
|
|
641
|
+
} else {
|
|
642
|
+
const cmd = h.command;
|
|
629
643
|
const parts = cmd.split(" ");
|
|
630
644
|
if (parts.length >= 2 && !parts[0].endsWith(".js") && !parts[0].endsWith(".ts")) {
|
|
631
645
|
nodePaths.add(parts[0]);
|
|
@@ -804,6 +818,7 @@ function copySkillDir(src, dest, agent) {
|
|
|
804
818
|
}
|
|
805
819
|
var SKILL_INSTALL_TARGETS = {
|
|
806
820
|
qoder: join(homedir(), ".qoder", "skills"),
|
|
821
|
+
qoderwork: join(homedir(), ".qoderwork", "skills"),
|
|
807
822
|
codex: join(homedir(), ".codex", "skills"),
|
|
808
823
|
claude: join(homedir(), ".claude", "skills"),
|
|
809
824
|
openclaw: join(homedir(), ".openclaw", "skills"),
|
|
@@ -865,16 +880,18 @@ var LEGACY_MARKER_KEYS = ["_ctxdbQoder", "_ctxdbPackage"];
|
|
|
865
880
|
var LEGACY_MARKER_VALUES = ["@aliyunrds/ctxdb-qoder"];
|
|
866
881
|
var TOOL_SCOPED_EVENTS = /* @__PURE__ */ new Set(["PreToolUse", "PostToolUse"]);
|
|
867
882
|
function appendOne(hooks, event, command, agent) {
|
|
868
|
-
const commandWithAgent = `${process.execPath} ${command} --agent=${agent}`;
|
|
869
883
|
if (!Array.isArray(hooks[event])) hooks[event] = [];
|
|
884
|
+
const useExecForm = agent === "claude";
|
|
885
|
+
const shellCmd = `${process.execPath} ${command} --agent=${agent}`;
|
|
870
886
|
const dup = hooks[event].some(
|
|
871
887
|
(entry2) => Array.isArray(entry2?.hooks) && entry2.hooks.some(
|
|
872
|
-
(h) => h?.type === "command" && typeof h.command === "string" && h.command
|
|
888
|
+
(h) => h?.type === "command" && (Array.isArray(h.args) && h.args[0] === command || typeof h.command === "string" && h.command.includes(command))
|
|
873
889
|
)
|
|
874
890
|
);
|
|
875
891
|
if (dup) return;
|
|
892
|
+
const inner = useExecForm ? { type: "command", command: process.execPath, args: [command, `--agent=${agent}`], timeout: 60 } : { type: "command", command: shellCmd, timeout: 60 };
|
|
876
893
|
const entry = {
|
|
877
|
-
hooks: [
|
|
894
|
+
hooks: [inner],
|
|
878
895
|
[ENTRY_MARKER_KEY]: ENTRY_MARKER_VALUE,
|
|
879
896
|
[ENTRY_AGENT_KEY]: agent
|
|
880
897
|
};
|
|
@@ -1237,7 +1254,7 @@ async function ping(args) {
|
|
|
1237
1254
|
var HELP = `ctxdb setup \u2014 configure an agent
|
|
1238
1255
|
|
|
1239
1256
|
USAGE
|
|
1240
|
-
ctxdb setup [--agent <qoder|codex|claude>]
|
|
1257
|
+
ctxdb setup [--agent <qoder|qoderwork|codex|claude>]
|
|
1241
1258
|
[--api-key=K] [--base-url=URL] [--user-id=ID]
|
|
1242
1259
|
[--no-install-skill] [--no-validate] [--json]
|
|
1243
1260
|
|
|
@@ -1248,7 +1265,7 @@ BEHAVIOR
|
|
|
1248
1265
|
specified agent harness.
|
|
1249
1266
|
|
|
1250
1267
|
FLAGS
|
|
1251
|
-
--agent <name> Target agent (qoder|codex|claude)
|
|
1268
|
+
--agent <name> Target agent (qoder|qoderwork|codex|claude)
|
|
1252
1269
|
--api-key <key> API key (required on first setup)
|
|
1253
1270
|
--base-url <url> Server URL (default: https://context-database.aliyuncs.com)
|
|
1254
1271
|
--user-id <id> User bucket (default: "default")
|
|
@@ -1275,7 +1292,7 @@ async function setup(args) {
|
|
|
1275
1292
|
const json = !!args.flags.json;
|
|
1276
1293
|
if (agent === "default" && !json && !configuredAgents().includes("default")) {
|
|
1277
1294
|
process.stderr.write(
|
|
1278
|
-
`hint: creating CLI-only "default" agent (no hooks/skills). Use --agent <claude|qoder|codex> for full setup.
|
|
1295
|
+
`hint: creating CLI-only "default" agent (no hooks/skills). Use --agent <claude|qoder|qoderwork|codex> for full setup.
|
|
1279
1296
|
`
|
|
1280
1297
|
);
|
|
1281
1298
|
}
|
|
@@ -1300,11 +1317,11 @@ ${h}
|
|
|
1300
1317
|
var HELP2 = `ctxdb uninstall \u2014 remove hooks + skills
|
|
1301
1318
|
|
|
1302
1319
|
USAGE
|
|
1303
|
-
ctxdb uninstall [--agent <qoder|codex|claude>] [--purge-config] [--purge-logs] [--purge-all] [--json]
|
|
1320
|
+
ctxdb uninstall [--agent <qoder|qoderwork|codex|claude>] [--purge-config] [--purge-logs] [--purge-all] [--json]
|
|
1304
1321
|
|
|
1305
1322
|
DEFAULT BEHAVIOR (no --agent, no purge flags)
|
|
1306
1323
|
Strips ctxdb hook entries and skill directories for ALL agents (qoder,
|
|
1307
|
-
codex, claude). Keeps ~/.ctxdb/ctxdb.json (credentials) and ~/.ctxdb/logs/
|
|
1324
|
+
qoderwork, codex, claude). Keeps ~/.ctxdb/ctxdb.json (credentials) and ~/.ctxdb/logs/
|
|
1308
1325
|
so you can re-run \`ctxdb setup\` later without losing configuration.
|
|
1309
1326
|
|
|
1310
1327
|
WITH --agent <name>
|
|
@@ -1312,7 +1329,7 @@ WITH --agent <name>
|
|
|
1312
1329
|
Other agents remain untouched.
|
|
1313
1330
|
|
|
1314
1331
|
FLAGS
|
|
1315
|
-
--agent <name> Target a single agent (qoder|codex|claude)
|
|
1332
|
+
--agent <name> Target a single agent (qoder|qoderwork|codex|claude)
|
|
1316
1333
|
--purge-config Also delete ~/.ctxdb/ctxdb.json
|
|
1317
1334
|
--purge-logs Also delete ~/.ctxdb/logs/
|
|
1318
1335
|
--purge-all Delete everything under ~/.ctxdb/
|
|
@@ -1454,7 +1471,7 @@ function runSelfUpdate(currentVersion, passthroughArgs = []) {
|
|
|
1454
1471
|
var HELP3 = `ctxdb upgrade \u2014 refresh skills + hooks
|
|
1455
1472
|
|
|
1456
1473
|
USAGE
|
|
1457
|
-
ctxdb upgrade [--agent <qoder|codex|claude>] [--self-update] [--json]
|
|
1474
|
+
ctxdb upgrade [--agent <qoder|qoderwork|codex|claude>] [--self-update] [--json]
|
|
1458
1475
|
|
|
1459
1476
|
BEHAVIOR
|
|
1460
1477
|
Refreshes skill files and hook entries for configured agents without
|
|
@@ -1464,7 +1481,7 @@ BEHAVIOR
|
|
|
1464
1481
|
With --agent: upgrades only the specified agent.
|
|
1465
1482
|
|
|
1466
1483
|
FLAGS
|
|
1467
|
-
--agent <name> Target a single agent (qoder|codex|claude)
|
|
1484
|
+
--agent <name> Target a single agent (qoder|qoderwork|codex|claude)
|
|
1468
1485
|
--self-update Also pull latest package from npm before upgrading
|
|
1469
1486
|
--json Machine-readable JSON output
|
|
1470
1487
|
`;
|
|
@@ -1570,7 +1587,8 @@ function skillInstall(args) {
|
|
|
1570
1587
|
}
|
|
1571
1588
|
targetRoot = resolved;
|
|
1572
1589
|
}
|
|
1573
|
-
const
|
|
1590
|
+
const templateAgent = target && isBuiltinAgent(target) ? target : "default";
|
|
1591
|
+
const result = installSkillsTo(targetRoot, templateAgent);
|
|
1574
1592
|
const ok = result.ok;
|
|
1575
1593
|
const output = {
|
|
1576
1594
|
ok,
|
|
@@ -1826,13 +1844,14 @@ USAGE
|
|
|
1826
1844
|
ctxdb <command> [args] [--flags]
|
|
1827
1845
|
|
|
1828
1846
|
COMMANDS
|
|
1829
|
-
setup [--agent <qoder|codex|claude>]
|
|
1847
|
+
setup [--agent <qoder|qoderwork|codex|claude>]
|
|
1830
1848
|
[--api-key=K] [--base-url=URL] [--user-id=ID]
|
|
1831
1849
|
[--no-install-skill] [--no-validate] [--json]
|
|
1832
1850
|
Without --agent \u2192 writes agents.default (CLI-only, no hooks/skills)
|
|
1833
|
-
Qoder
|
|
1834
|
-
|
|
1835
|
-
|
|
1851
|
+
Qoder \u2192 writes agents.qoder config + ~/.qoder/settings.json hooks + skill
|
|
1852
|
+
QoderWork \u2192 writes agents.qoderwork config + ~/.qoderwork/settings.json hooks + skill
|
|
1853
|
+
Codex \u2192 writes agents.codex config + ~/.codex/hooks.json hooks + skill
|
|
1854
|
+
Claude \u2192 writes agents.claude config + ~/.claude/settings.json hooks + skill
|
|
1836
1855
|
status [--agent <name>] [--json]
|
|
1837
1856
|
ping [--agent <name>] [--json]
|
|
1838
1857
|
uninstall [--agent <name>] [--purge-config] [--purge-logs] [--purge-all] [--json]
|
|
@@ -1875,7 +1894,7 @@ COMMANDS
|
|
|
1875
1894
|
doc_id?/tags? for citation.
|
|
1876
1895
|
--raw: server response verbatim (curl parity).
|
|
1877
1896
|
|
|
1878
|
-
skill install --target <qoder|codex|claude|openclaw|hermes> [--json]
|
|
1897
|
+
skill install --target <qoder|qoderwork|codex|claude|openclaw|hermes> [--json]
|
|
1879
1898
|
skill install --path <dir> [--json]
|
|
1880
1899
|
Install skill files (contextdb-memory,
|
|
1881
1900
|
contextdb-knowledge) to an agent's skill directory.
|
|
@@ -1888,7 +1907,7 @@ AGENT RESOLUTION (when --agent is omitted):
|
|
|
1888
1907
|
ENV VARS (override selected ~/.ctxdb/ctxdb.json agent config):
|
|
1889
1908
|
CTXDB_AGENT CTXDB_API_KEY CTXDB_BASE_URL CTXDB_USER_ID
|
|
1890
1909
|
|
|
1891
|
-
CONFIG: ~/.ctxdb/ctxdb.json (agents.default / agents.qoder / agents.codex / agents.claude)
|
|
1910
|
+
CONFIG: ~/.ctxdb/ctxdb.json (agents.default / agents.qoder / agents.qoderwork / agents.codex / agents.claude)
|
|
1892
1911
|
LOGS: ~/.ctxdb/logs/ctxdb.log
|
|
1893
1912
|
`;
|
|
1894
1913
|
var ROUTES = {
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
+
fetchKbCatalogBlock,
|
|
3
4
|
recallTurn
|
|
4
|
-
} from "../chunk-
|
|
5
|
+
} from "../chunk-73OY44GY.js";
|
|
6
|
+
import "../chunk-6S5RJYBC.js";
|
|
5
7
|
import {
|
|
6
8
|
isCircuitOpen
|
|
7
|
-
} from "../chunk-
|
|
9
|
+
} from "../chunk-52IAVJRK.js";
|
|
8
10
|
import {
|
|
9
11
|
HttpClient,
|
|
10
12
|
agentFromArgvWithFallback,
|
|
@@ -12,7 +14,10 @@ import {
|
|
|
12
14
|
isComplete,
|
|
13
15
|
load,
|
|
14
16
|
setDebug
|
|
15
|
-
} from "../chunk-
|
|
17
|
+
} from "../chunk-BWPFGTF7.js";
|
|
18
|
+
|
|
19
|
+
// src/hooks/session-start.ts
|
|
20
|
+
import { pathToFileURL } from "url";
|
|
16
21
|
|
|
17
22
|
// src/lib/warmup-recall.ts
|
|
18
23
|
import { execSync } from "child_process";
|
|
@@ -67,6 +72,41 @@ async function warmupRecall(cwd, cfg, client) {
|
|
|
67
72
|
|
|
68
73
|
// src/hooks/session-start.ts
|
|
69
74
|
var HOOK_TIMEOUT_MS = 5e3;
|
|
75
|
+
function timeout(ms) {
|
|
76
|
+
return new Promise((resolve) => setTimeout(() => resolve(null), ms));
|
|
77
|
+
}
|
|
78
|
+
async function composeSessionStart(cfg, agent, client, cwd, timeoutMs = HOOK_TIMEOUT_MS) {
|
|
79
|
+
const kbInjectHere = cfg.kbCatalogInjection === "session_start";
|
|
80
|
+
const warmupPromise = cfg.warmupRecall ? Promise.race([warmupRecall(cwd, cfg, client), timeout(timeoutMs).then(() => null)]) : Promise.resolve(null);
|
|
81
|
+
const kbPromise = kbInjectHere ? Promise.race([fetchKbCatalogBlock(client, agent).catch(() => ""), timeout(timeoutMs).then(() => "")]) : Promise.resolve("");
|
|
82
|
+
const [result, kbBlock] = await Promise.all([warmupPromise, kbPromise]);
|
|
83
|
+
const warmupTimedOut = cfg.warmupRecall && result === null;
|
|
84
|
+
const warmupCtx = result && result.ok ? result.additionalContext || "" : "";
|
|
85
|
+
if (!warmupCtx && result && !result.ok) {
|
|
86
|
+
debug("warmup", `no result: ${result.reason}`);
|
|
87
|
+
}
|
|
88
|
+
let ctx = warmupCtx;
|
|
89
|
+
if (kbBlock) ctx = ctx ? `${ctx}
|
|
90
|
+
|
|
91
|
+
${kbBlock}` : kbBlock;
|
|
92
|
+
return {
|
|
93
|
+
ctx,
|
|
94
|
+
memoryCount: result?.ok ? result.memoryCount : 0,
|
|
95
|
+
kbChunkCount: result?.ok ? result.knowledgeChunkCount : 0,
|
|
96
|
+
kbCatalogLines: kbBlock ? kbBlock.split("\n").length : 0,
|
|
97
|
+
warmupTimedOut
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
function formatSessionStartStdout(agent, ctx) {
|
|
101
|
+
if (agent === "codex") return ctx + "\n";
|
|
102
|
+
const out = {
|
|
103
|
+
hookSpecificOutput: {
|
|
104
|
+
hookEventName: "SessionStart",
|
|
105
|
+
additionalContext: ctx
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
return JSON.stringify(out) + "\n";
|
|
109
|
+
}
|
|
70
110
|
async function readStdinJson() {
|
|
71
111
|
let raw = "";
|
|
72
112
|
for await (const chunk of process.stdin) raw += chunk;
|
|
@@ -78,9 +118,6 @@ async function readStdinJson() {
|
|
|
78
118
|
return {};
|
|
79
119
|
}
|
|
80
120
|
}
|
|
81
|
-
function timeout(ms) {
|
|
82
|
-
return new Promise((resolve) => setTimeout(() => resolve(null), ms));
|
|
83
|
-
}
|
|
84
121
|
async function main() {
|
|
85
122
|
try {
|
|
86
123
|
const event = await readStdinJson();
|
|
@@ -96,8 +133,9 @@ async function main() {
|
|
|
96
133
|
const cfg = load({ agent });
|
|
97
134
|
setDebug(cfg.debug);
|
|
98
135
|
debug("warmup", "start", { cwd, userId: cfg.userId });
|
|
99
|
-
|
|
100
|
-
|
|
136
|
+
const kbInjectHere = cfg.kbCatalogInjection === "session_start";
|
|
137
|
+
if (!isComplete(cfg) || !cfg.warmupRecall && !kbInjectHere) {
|
|
138
|
+
debug("warmup", "skip (config incomplete or both warmup+kb off)");
|
|
101
139
|
return 0;
|
|
102
140
|
}
|
|
103
141
|
if (isCircuitOpen(agent, cfg.baseUrl)) {
|
|
@@ -109,34 +147,21 @@ async function main() {
|
|
|
109
147
|
apiKey: cfg.apiKey,
|
|
110
148
|
timeoutMs: HOOK_TIMEOUT_MS
|
|
111
149
|
});
|
|
112
|
-
const
|
|
113
|
-
|
|
114
|
-
timeout(HOOK_TIMEOUT_MS).then(() => null)
|
|
115
|
-
]);
|
|
116
|
-
if (!result) {
|
|
150
|
+
const composed = await composeSessionStart(cfg, agent, client, cwd);
|
|
151
|
+
if (composed.warmupTimedOut) {
|
|
117
152
|
process.stderr.write("ctxdb warmup: timeout\n");
|
|
118
|
-
return 0;
|
|
119
153
|
}
|
|
120
|
-
if (!
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
154
|
+
if (!composed.ctx) return 0;
|
|
155
|
+
const { memoryCount, kbChunkCount, kbCatalogLines, ctx } = composed;
|
|
156
|
+
debug(
|
|
157
|
+
"warmup",
|
|
158
|
+
`ok, memories=${memoryCount} kb=${kbChunkCount} kb_catalog=${kbCatalogLines}`
|
|
159
|
+
);
|
|
125
160
|
process.stderr.write(
|
|
126
|
-
`ctxdb warmup: ok (${
|
|
161
|
+
`ctxdb warmup: ok (${memoryCount} memories, ${kbChunkCount} kb chunks, kb_catalog=${kbCatalogLines} lines)
|
|
127
162
|
`
|
|
128
163
|
);
|
|
129
|
-
|
|
130
|
-
process.stdout.write(result.additionalContext + "\n");
|
|
131
|
-
} else {
|
|
132
|
-
const out = {
|
|
133
|
-
hookSpecificOutput: {
|
|
134
|
-
hookEventName: "SessionStart",
|
|
135
|
-
additionalContext: result.additionalContext
|
|
136
|
-
}
|
|
137
|
-
};
|
|
138
|
-
process.stdout.write(JSON.stringify(out) + "\n");
|
|
139
|
-
}
|
|
164
|
+
process.stdout.write(formatSessionStartStdout(agent, ctx));
|
|
140
165
|
return 0;
|
|
141
166
|
} catch (err) {
|
|
142
167
|
process.stderr.write(`ctxdb warmup: unexpected error: ${err?.message ?? err}
|
|
@@ -144,4 +169,11 @@ async function main() {
|
|
|
144
169
|
return 0;
|
|
145
170
|
}
|
|
146
171
|
}
|
|
147
|
-
|
|
172
|
+
if (import.meta.url === pathToFileURL(process.argv[1] ?? "").href) {
|
|
173
|
+
main().then((code) => process.exit(code));
|
|
174
|
+
}
|
|
175
|
+
export {
|
|
176
|
+
HOOK_TIMEOUT_MS,
|
|
177
|
+
composeSessionStart,
|
|
178
|
+
formatSessionStartStdout
|
|
179
|
+
};
|