@aliyunrds/ctxdb 0.0.5 → 0.0.7
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 +3 -3
- package/dist/{chunk-HAUTENYD.js → chunk-6S5RJYBC.js} +20 -77
- package/dist/{chunk-7NOXAU2X.js → chunk-LIC44DR6.js} +9 -2
- package/dist/chunk-Q2EEP4CE.js +69 -0
- package/dist/{chunk-QSSNPN3M.js → chunk-S45GOYUU.js} +46 -12
- package/dist/cli/main.js +417 -164
- package/dist/hooks/session-start.js +10 -3
- package/dist/hooks/stop.js +100 -21
- package/dist/hooks/user-prompt-submit.js +14 -5
- package/dist/setup/skills/contextdb-knowledge/SKILL.md +161 -0
- package/dist/setup/skills/contextdb-memory/SKILL.md +142 -0
- package/package.json +2 -2
- package/dist/setup/skills/cli-only/SKILL.md +0 -116
- package/dist/setup/skills/hooks-driven/SKILL.md +0 -144
package/dist/cli/main.js
CHANGED
|
@@ -4,8 +4,7 @@ import {
|
|
|
4
4
|
DEFAULT_INGEST_TIMEOUT_MS,
|
|
5
5
|
compactChunk,
|
|
6
6
|
compactKbQueryResponse,
|
|
7
|
-
|
|
8
|
-
findOrCreateKb,
|
|
7
|
+
createKb,
|
|
9
8
|
getDocument,
|
|
10
9
|
listDocuments,
|
|
11
10
|
listKnowledgeBases,
|
|
@@ -14,7 +13,7 @@ import {
|
|
|
14
13
|
pollIngest,
|
|
15
14
|
uploadFile,
|
|
16
15
|
uploadText
|
|
17
|
-
} from "../chunk-
|
|
16
|
+
} from "../chunk-6S5RJYBC.js";
|
|
18
17
|
import {
|
|
19
18
|
DEFAULT_BASE_URL,
|
|
20
19
|
DEFAULT_USER_ID,
|
|
@@ -23,12 +22,14 @@ import {
|
|
|
23
22
|
agentFromEnv,
|
|
24
23
|
agentHomeDir,
|
|
25
24
|
configuredAgents,
|
|
26
|
-
|
|
25
|
+
isAgentSlug,
|
|
26
|
+
isBuiltinAgent,
|
|
27
27
|
isComplete,
|
|
28
28
|
load,
|
|
29
29
|
removeAgent,
|
|
30
|
-
save
|
|
31
|
-
|
|
30
|
+
save,
|
|
31
|
+
writeInstalledPkgVersion
|
|
32
|
+
} from "../chunk-S45GOYUU.js";
|
|
32
33
|
|
|
33
34
|
// src/cli/util.ts
|
|
34
35
|
var BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
|
|
@@ -192,17 +193,16 @@ function printResult(value, json, command) {
|
|
|
192
193
|
function agentFromFlags(flags) {
|
|
193
194
|
const raw = flags.agent;
|
|
194
195
|
if (raw === void 0) return agentFromEnv();
|
|
195
|
-
if (
|
|
196
|
-
fail(`unknown --agent: ${String(raw)} (expected one of ${SUPPORTED_AGENTS.join(" / ")})`, 2);
|
|
196
|
+
if (isAgentSlug(raw)) return raw;
|
|
197
|
+
fail(`unknown --agent: ${String(raw)} (expected one of ${SUPPORTED_AGENTS.join(" / ")} / default)`, 2);
|
|
197
198
|
}
|
|
198
199
|
function buildContext(args) {
|
|
199
200
|
const agent = agentFromFlags(args?.flags ?? {});
|
|
200
201
|
const cfg = load({ agent });
|
|
201
202
|
if (!isComplete(cfg)) {
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
`
|
|
205
|
-
);
|
|
203
|
+
const hint = agent === "default" ? "run `ctxdb setup --api-key=<key> --base-url=<url>` or set CTXDB_API_KEY / CTXDB_BASE_URL env vars" : `run \`ctxdb setup --agent ${agent}\` or set CTXDB_API_KEY / CTXDB_BASE_URL / CTXDB_USER_ID env vars`;
|
|
204
|
+
process.stderr.write(`config incomplete for agent ${agent}: ${hint}
|
|
205
|
+
`);
|
|
206
206
|
process.exit(2);
|
|
207
207
|
}
|
|
208
208
|
const client = new HttpClient({
|
|
@@ -216,7 +216,7 @@ function fail(message, code = 1) {
|
|
|
216
216
|
`);
|
|
217
217
|
process.exit(code);
|
|
218
218
|
}
|
|
219
|
-
var PACKAGE_VERSION = "0.0.
|
|
219
|
+
var PACKAGE_VERSION = "0.0.7";
|
|
220
220
|
|
|
221
221
|
// src/setup/installer.ts
|
|
222
222
|
import {
|
|
@@ -248,15 +248,10 @@ function skillInstallRoot(agent) {
|
|
|
248
248
|
return join(homedir(), ".claude", "skills");
|
|
249
249
|
}
|
|
250
250
|
}
|
|
251
|
-
var
|
|
252
|
-
|
|
253
|
-
return agentSupportsHooks(agent) ? "hooks-driven" : "cli-only";
|
|
254
|
-
}
|
|
255
|
-
function skillInstallDir(agent) {
|
|
256
|
-
return join(skillInstallRoot(agent), SKILL_DIR_NAME);
|
|
257
|
-
}
|
|
251
|
+
var SKILL_DIRS = ["contextdb-memory", "contextdb-knowledge"];
|
|
252
|
+
var LEGACY_SKILL_DIRS = ["ctxdb"];
|
|
258
253
|
function agentSupportsHooks(agent) {
|
|
259
|
-
return agent
|
|
254
|
+
return isBuiltinAgent(agent);
|
|
260
255
|
}
|
|
261
256
|
function hookConfigPath(agent) {
|
|
262
257
|
switch (agent) {
|
|
@@ -276,54 +271,48 @@ var LEGACY_QODER_SKILL_DIRS = [
|
|
|
276
271
|
var HOOK_EVENTS = ["UserPromptSubmit", "Stop", "SessionStart"];
|
|
277
272
|
async function runSetup(options) {
|
|
278
273
|
const steps = [];
|
|
279
|
-
if (!
|
|
274
|
+
if (!isAgentSlug(options.agent)) {
|
|
280
275
|
steps.push({
|
|
281
276
|
step: "validate-agent",
|
|
282
277
|
ok: false,
|
|
283
|
-
detail: `unknown --agent: ${String(options.agent)} (expected one of ${SUPPORTED_AGENTS.join(" / ")})`
|
|
278
|
+
detail: `unknown --agent: ${String(options.agent)} (expected one of ${SUPPORTED_AGENTS.join(" / ")} / default)`
|
|
284
279
|
});
|
|
285
280
|
return { ok: false, steps };
|
|
286
281
|
}
|
|
287
282
|
const agent = options.agent;
|
|
288
283
|
const installSkill = options.installSkill !== false;
|
|
289
284
|
const validate = options.validate !== false;
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
285
|
+
if (isBuiltinAgent(agent)) {
|
|
286
|
+
const homeCheck = checkAgentHome(agent);
|
|
287
|
+
steps.push(homeCheck);
|
|
288
|
+
if (!homeCheck.ok) return { ok: false, steps };
|
|
289
|
+
}
|
|
293
290
|
const cfg = load({ agent });
|
|
294
291
|
if (options.apiKey) cfg.apiKey = options.apiKey;
|
|
295
292
|
if (options.baseUrl) cfg.baseUrl = options.baseUrl.replace(/\/+$/, "");
|
|
296
293
|
else if (!cfg.baseUrl) cfg.baseUrl = DEFAULT_BASE_URL;
|
|
297
294
|
cfg.userId = options.userId ?? cfg.userId ?? DEFAULT_USER_ID;
|
|
295
|
+
if (!cfg.apiKey) {
|
|
296
|
+
steps.push({
|
|
297
|
+
step: "write-config",
|
|
298
|
+
ok: false,
|
|
299
|
+
detail: `${agent}: --api-key is required (won't write config without a valid API key)`
|
|
300
|
+
});
|
|
301
|
+
return { ok: false, steps };
|
|
302
|
+
}
|
|
298
303
|
save(cfg, void 0, { agent });
|
|
299
304
|
steps.push({
|
|
300
305
|
step: "write-config",
|
|
301
306
|
ok: true,
|
|
302
307
|
detail: `${agent}: ${cfg.baseUrl} (user_id=${cfg.userId})`
|
|
303
308
|
});
|
|
304
|
-
if (installSkill) {
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
copySkillDir(srcDir, dest, agent);
|
|
310
|
-
steps.push({ step: "install-skill", ok: true, detail: dest });
|
|
311
|
-
} else {
|
|
312
|
-
steps.push({
|
|
313
|
-
step: "install-skill",
|
|
314
|
-
ok: false,
|
|
315
|
-
detail: `skill source directory not found (${skillResourceDir(agent)})`
|
|
316
|
-
});
|
|
317
|
-
}
|
|
318
|
-
} catch (err) {
|
|
319
|
-
steps.push({
|
|
320
|
-
step: "install-skill",
|
|
321
|
-
ok: false,
|
|
322
|
-
detail: err?.message ?? String(err)
|
|
323
|
-
});
|
|
324
|
-
}
|
|
309
|
+
if (installSkill && isBuiltinAgent(agent)) {
|
|
310
|
+
const installRoot = skillInstallRoot(agent);
|
|
311
|
+
const skillResult = installSkillsTo(installRoot, agent);
|
|
312
|
+
steps.push(...skillResult.steps);
|
|
313
|
+
if (!skillResult.ok) return { ok: false, steps };
|
|
325
314
|
}
|
|
326
|
-
if (agentSupportsHooks(agent)) {
|
|
315
|
+
if (isBuiltinAgent(agent) && agentSupportsHooks(agent)) {
|
|
327
316
|
const hookPaths = locateHookPaths();
|
|
328
317
|
steps.push({
|
|
329
318
|
step: "locate-hooks",
|
|
@@ -406,15 +395,15 @@ async function runSetup(options) {
|
|
|
406
395
|
}
|
|
407
396
|
function runRemove(agent, options = {}) {
|
|
408
397
|
const steps = [];
|
|
409
|
-
if (!
|
|
398
|
+
if (!isAgentSlug(agent)) {
|
|
410
399
|
steps.push({
|
|
411
400
|
step: "validate-agent",
|
|
412
401
|
ok: false,
|
|
413
|
-
detail: `unknown --agent: ${String(agent)} (expected one of ${SUPPORTED_AGENTS.join(" / ")})`
|
|
402
|
+
detail: `unknown --agent: ${String(agent)} (expected one of ${SUPPORTED_AGENTS.join(" / ")} / default)`
|
|
414
403
|
});
|
|
415
404
|
return { ok: false, steps };
|
|
416
405
|
}
|
|
417
|
-
if (agentSupportsHooks(agent)) {
|
|
406
|
+
if (isBuiltinAgent(agent) && agentSupportsHooks(agent)) {
|
|
418
407
|
const path = hookConfigPath(agent);
|
|
419
408
|
if (!existsSync(path)) {
|
|
420
409
|
steps.push({
|
|
@@ -451,12 +440,12 @@ function runRemove(agent, options = {}) {
|
|
|
451
440
|
return { ok: false, steps };
|
|
452
441
|
}
|
|
453
442
|
}
|
|
454
|
-
const
|
|
455
|
-
|
|
456
|
-
...
|
|
457
|
-
|
|
458
|
-
)
|
|
459
|
-
]
|
|
443
|
+
const root = skillInstallRoot(agent);
|
|
444
|
+
const dirs = [
|
|
445
|
+
...SKILL_DIRS.map((d) => join(root, d)),
|
|
446
|
+
...LEGACY_SKILL_DIRS.map((d) => join(root, d)),
|
|
447
|
+
...agent === "qoder" ? LEGACY_QODER_SKILL_DIRS.map((d) => join(root, d)) : []
|
|
448
|
+
];
|
|
460
449
|
for (const p of dirs) {
|
|
461
450
|
if (!existsSync(p)) continue;
|
|
462
451
|
try {
|
|
@@ -470,26 +459,6 @@ function runRemove(agent, options = {}) {
|
|
|
470
459
|
});
|
|
471
460
|
}
|
|
472
461
|
}
|
|
473
|
-
} else {
|
|
474
|
-
const dir = skillInstallDir(agent);
|
|
475
|
-
if (!existsSync(dir)) {
|
|
476
|
-
steps.push({
|
|
477
|
-
step: "skill-missing",
|
|
478
|
-
ok: true,
|
|
479
|
-
detail: `nothing to remove (${dir})`
|
|
480
|
-
});
|
|
481
|
-
} else {
|
|
482
|
-
try {
|
|
483
|
-
rmSync(dir, { recursive: true, force: true });
|
|
484
|
-
steps.push({ step: "remove-skill-dir", ok: true, detail: dir });
|
|
485
|
-
} catch (err) {
|
|
486
|
-
steps.push({
|
|
487
|
-
step: "remove-skill-dir",
|
|
488
|
-
ok: false,
|
|
489
|
-
detail: `${dir}: ${err?.message ?? String(err)}`
|
|
490
|
-
});
|
|
491
|
-
}
|
|
492
|
-
}
|
|
493
462
|
}
|
|
494
463
|
try {
|
|
495
464
|
const r = removeAgent(agent, void 0, {
|
|
@@ -546,6 +515,12 @@ function runTeardown(options = {}) {
|
|
|
546
515
|
steps.push({ ...s, step: `${agent}:${s.step}` });
|
|
547
516
|
}
|
|
548
517
|
}
|
|
518
|
+
const defaultSub = runRemove("default", { keepConfigShell });
|
|
519
|
+
if (defaultSub.steps.some((s) => s.step === "remove-config-section" && s.detail && !s.detail.includes("nothing to remove"))) {
|
|
520
|
+
for (const s of defaultSub.steps) {
|
|
521
|
+
steps.push({ ...s, step: `default:${s.step}` });
|
|
522
|
+
}
|
|
523
|
+
}
|
|
549
524
|
if (purgeConfig) {
|
|
550
525
|
const cfgPath = join(homedir(), ".ctxdb", "ctxdb.json");
|
|
551
526
|
if (existsSync(cfgPath)) {
|
|
@@ -827,6 +802,44 @@ function copySkillDir(src, dest, agent) {
|
|
|
827
802
|
}
|
|
828
803
|
}
|
|
829
804
|
}
|
|
805
|
+
var SKILL_INSTALL_TARGETS = {
|
|
806
|
+
qoder: join(homedir(), ".qoder", "skills"),
|
|
807
|
+
codex: join(homedir(), ".codex", "skills"),
|
|
808
|
+
claude: join(homedir(), ".claude", "skills"),
|
|
809
|
+
openclaw: join(homedir(), ".openclaw", "skills"),
|
|
810
|
+
hermes: join(homedir(), ".hermes", "skills")
|
|
811
|
+
};
|
|
812
|
+
function skillInstallTargetPath(target) {
|
|
813
|
+
return SKILL_INSTALL_TARGETS[target] ?? null;
|
|
814
|
+
}
|
|
815
|
+
function installSkillsTo(targetRoot, agent = "default") {
|
|
816
|
+
const steps = [];
|
|
817
|
+
for (const skillName of SKILL_DIRS) {
|
|
818
|
+
try {
|
|
819
|
+
const srcDir = locateSkillDir(skillName);
|
|
820
|
+
if (srcDir) {
|
|
821
|
+
const dest = join(targetRoot, skillName);
|
|
822
|
+
copySkillDir(srcDir, dest, agent);
|
|
823
|
+
steps.push({ step: "install-skill", ok: true, detail: dest });
|
|
824
|
+
} else {
|
|
825
|
+
steps.push({
|
|
826
|
+
step: "install-skill",
|
|
827
|
+
ok: false,
|
|
828
|
+
detail: `skill source directory not found (${skillName})`
|
|
829
|
+
});
|
|
830
|
+
return { ok: false, steps };
|
|
831
|
+
}
|
|
832
|
+
} catch (err) {
|
|
833
|
+
steps.push({
|
|
834
|
+
step: "install-skill",
|
|
835
|
+
ok: false,
|
|
836
|
+
detail: err?.message ?? String(err)
|
|
837
|
+
});
|
|
838
|
+
return { ok: false, steps };
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
return { ok: true, steps };
|
|
842
|
+
}
|
|
830
843
|
function appendHooks(agent, hookPaths) {
|
|
831
844
|
const path = hookConfigPath(agent);
|
|
832
845
|
if (!path) return;
|
|
@@ -1081,7 +1094,7 @@ function describeCodexFeatureMutation(status2, createdNew) {
|
|
|
1081
1094
|
}
|
|
1082
1095
|
}
|
|
1083
1096
|
function runUpgrade(options = {}) {
|
|
1084
|
-
const agents = options.agent ? [options.agent] : configuredAgents(options.configPath);
|
|
1097
|
+
const agents = options.agent ? [options.agent] : configuredAgents(options.configPath).filter(isBuiltinAgent);
|
|
1085
1098
|
if (agents.length === 0) {
|
|
1086
1099
|
return {
|
|
1087
1100
|
ok: false,
|
|
@@ -1113,24 +1126,19 @@ function upgradeOneAgent(agent) {
|
|
|
1113
1126
|
if (!homeCheck.ok) {
|
|
1114
1127
|
return { ok: true, steps, hints: [`${agent}: skipped \u2014 agent home not found`] };
|
|
1115
1128
|
}
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
step: "install-skill",
|
|
1125
|
-
ok: false,
|
|
1126
|
-
detail: "skill source directory not found"
|
|
1127
|
-
});
|
|
1128
|
-
return { ok: false, steps };
|
|
1129
|
+
const root = skillInstallRoot(agent);
|
|
1130
|
+
for (const legacy of LEGACY_SKILL_DIRS) {
|
|
1131
|
+
const legacyDir = join(root, legacy);
|
|
1132
|
+
if (!existsSync(legacyDir)) continue;
|
|
1133
|
+
try {
|
|
1134
|
+
rmSync(legacyDir, { recursive: true, force: true });
|
|
1135
|
+
steps.push({ step: "remove-legacy-skill", ok: true, detail: legacyDir });
|
|
1136
|
+
} catch {
|
|
1129
1137
|
}
|
|
1130
|
-
} catch (err) {
|
|
1131
|
-
steps.push({ step: "install-skill", ok: false, detail: err?.message ?? String(err) });
|
|
1132
|
-
return { ok: false, steps };
|
|
1133
1138
|
}
|
|
1139
|
+
const skillResult = installSkillsTo(root, agent);
|
|
1140
|
+
steps.push(...skillResult.steps);
|
|
1141
|
+
if (!skillResult.ok) return { ok: false, steps };
|
|
1134
1142
|
if (agentSupportsHooks(agent)) {
|
|
1135
1143
|
const hookPaths = locateHookPaths();
|
|
1136
1144
|
if (!hookPaths) {
|
|
@@ -1188,7 +1196,7 @@ async function status(args) {
|
|
|
1188
1196
|
pingError = err?.message ?? String(err);
|
|
1189
1197
|
}
|
|
1190
1198
|
}
|
|
1191
|
-
const hookHealth = checkHookNodePaths(agent);
|
|
1199
|
+
const hookHealth = isBuiltinAgent(agent) ? checkHookNodePaths(agent) : { installed: false, nodePaths: [], nodeOk: true, detail: "no hooks (default agent)" };
|
|
1192
1200
|
printResult(
|
|
1193
1201
|
{
|
|
1194
1202
|
ok: complete,
|
|
@@ -1226,25 +1234,51 @@ async function ping(args) {
|
|
|
1226
1234
|
}
|
|
1227
1235
|
|
|
1228
1236
|
// src/cli/setup-cli.ts
|
|
1237
|
+
var HELP = `ctxdb setup \u2014 configure an agent
|
|
1238
|
+
|
|
1239
|
+
USAGE
|
|
1240
|
+
ctxdb setup [--agent <qoder|codex|claude>]
|
|
1241
|
+
[--api-key=K] [--base-url=URL] [--user-id=ID]
|
|
1242
|
+
[--no-install-skill] [--no-validate] [--json]
|
|
1243
|
+
|
|
1244
|
+
BEHAVIOR
|
|
1245
|
+
Without --agent Writes agents.default in ~/.ctxdb/ctxdb.json (CLI-only,
|
|
1246
|
+
no hooks or skills installed).
|
|
1247
|
+
With --agent Writes agent config + installs hooks + skills for the
|
|
1248
|
+
specified agent harness.
|
|
1249
|
+
|
|
1250
|
+
FLAGS
|
|
1251
|
+
--agent <name> Target agent (qoder|codex|claude)
|
|
1252
|
+
--api-key <key> API key (required on first setup)
|
|
1253
|
+
--base-url <url> Server URL (default: https://context-database.aliyuncs.com)
|
|
1254
|
+
--user-id <id> User bucket (default: "default")
|
|
1255
|
+
--no-install-skill Skip skill directory installation
|
|
1256
|
+
--no-validate Skip connectivity ping after setup
|
|
1257
|
+
--json Machine-readable JSON output
|
|
1258
|
+
`;
|
|
1229
1259
|
function parseAgent(args) {
|
|
1230
1260
|
const raw = args.flags.agent;
|
|
1231
|
-
if (
|
|
1232
|
-
|
|
1233
|
-
}
|
|
1234
|
-
function agentError() {
|
|
1261
|
+
if (raw === void 0) return "default";
|
|
1262
|
+
if (typeof raw === "string" && isAgentSlug(raw)) return raw;
|
|
1235
1263
|
process.stderr.write(
|
|
1236
|
-
`
|
|
1237
|
-
e.g. ctxdb setup --agent qoder --api-key=<key>
|
|
1264
|
+
`unknown --agent: ${String(raw)} (expected one of ${SUPPORTED_AGENTS.join(" / ")} / default)
|
|
1238
1265
|
`
|
|
1239
1266
|
);
|
|
1267
|
+
process.exit(2);
|
|
1240
1268
|
}
|
|
1241
1269
|
async function setup(args) {
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
return 2;
|
|
1270
|
+
if (args.flags.help || args.flags.h) {
|
|
1271
|
+
process.stdout.write(HELP);
|
|
1272
|
+
return 0;
|
|
1246
1273
|
}
|
|
1274
|
+
const agent = parseAgent(args);
|
|
1247
1275
|
const json = !!args.flags.json;
|
|
1276
|
+
if (agent === "default" && !json && !configuredAgents().includes("default")) {
|
|
1277
|
+
process.stderr.write(
|
|
1278
|
+
`hint: creating CLI-only "default" agent (no hooks/skills). Use --agent <claude|qoder|codex> for full setup.
|
|
1279
|
+
`
|
|
1280
|
+
);
|
|
1281
|
+
}
|
|
1248
1282
|
const result = await runSetup({
|
|
1249
1283
|
agent,
|
|
1250
1284
|
apiKey: typeof args.flags["api-key"] === "string" ? args.flags["api-key"] : void 0,
|
|
@@ -1263,7 +1297,7 @@ ${h}
|
|
|
1263
1297
|
}
|
|
1264
1298
|
|
|
1265
1299
|
// src/cli/teardown.ts
|
|
1266
|
-
var
|
|
1300
|
+
var HELP2 = `ctxdb uninstall \u2014 remove hooks + skills
|
|
1267
1301
|
|
|
1268
1302
|
USAGE
|
|
1269
1303
|
ctxdb uninstall [--agent <qoder|codex|claude>] [--purge-config] [--purge-logs] [--purge-all] [--json]
|
|
@@ -1290,15 +1324,15 @@ NOTE
|
|
|
1290
1324
|
`;
|
|
1291
1325
|
function uninstall(args) {
|
|
1292
1326
|
if (args.flags.help || args.flags.h) {
|
|
1293
|
-
process.stdout.write(
|
|
1327
|
+
process.stdout.write(HELP2);
|
|
1294
1328
|
return 0;
|
|
1295
1329
|
}
|
|
1296
1330
|
const json = !!args.flags.json;
|
|
1297
1331
|
const agentFlag = args.flags.agent;
|
|
1298
1332
|
if (agentFlag !== void 0) {
|
|
1299
|
-
if (!
|
|
1333
|
+
if (!isAgentSlug(agentFlag)) {
|
|
1300
1334
|
process.stderr.write(
|
|
1301
|
-
`unknown --agent: ${String(agentFlag)} (expected one of ${SUPPORTED_AGENTS.join(" / ")})
|
|
1335
|
+
`unknown --agent: ${String(agentFlag)} (expected one of ${SUPPORTED_AGENTS.join(" / ")} / default)
|
|
1302
1336
|
`
|
|
1303
1337
|
);
|
|
1304
1338
|
return 2;
|
|
@@ -1326,10 +1360,145 @@ ${h}
|
|
|
1326
1360
|
return result.ok ? 0 : 1;
|
|
1327
1361
|
}
|
|
1328
1362
|
|
|
1363
|
+
// src/lib/self-update.ts
|
|
1364
|
+
import { spawnSync } from "child_process";
|
|
1365
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
1366
|
+
import { dirname as dirname2 } from "path";
|
|
1367
|
+
var PACKAGE_NAME = "@aliyunrds/ctxdb";
|
|
1368
|
+
var NPM_VIEW_TIMEOUT_MS = 1e4;
|
|
1369
|
+
function detectInstallMethod() {
|
|
1370
|
+
const dir = dirname2(fileURLToPath2(import.meta.url));
|
|
1371
|
+
return dir.includes("/node_modules/") ? "npm" : "unknown";
|
|
1372
|
+
}
|
|
1373
|
+
function checkLatestVersion(currentVersion) {
|
|
1374
|
+
const result = spawnSync("npm", ["view", PACKAGE_NAME, "version"], {
|
|
1375
|
+
encoding: "utf-8",
|
|
1376
|
+
timeout: NPM_VIEW_TIMEOUT_MS,
|
|
1377
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
1378
|
+
});
|
|
1379
|
+
if (result.status !== 0 || !result.stdout?.trim()) {
|
|
1380
|
+
return {
|
|
1381
|
+
latest: null,
|
|
1382
|
+
current: currentVersion,
|
|
1383
|
+
isNewer: false,
|
|
1384
|
+
error: result.stderr?.trim() || `npm view exited with code ${result.status}`
|
|
1385
|
+
};
|
|
1386
|
+
}
|
|
1387
|
+
const latest = result.stdout.trim();
|
|
1388
|
+
return {
|
|
1389
|
+
latest,
|
|
1390
|
+
current: currentVersion,
|
|
1391
|
+
isNewer: isNewerVersion(latest, currentVersion)
|
|
1392
|
+
};
|
|
1393
|
+
}
|
|
1394
|
+
function isNewerVersion(candidate, current) {
|
|
1395
|
+
const parse = (v) => v.replace(/^v/, "").split(".").map(Number);
|
|
1396
|
+
const [cMaj = 0, cMin = 0, cPat = 0] = parse(candidate);
|
|
1397
|
+
const [uMaj = 0, uMin = 0, uPat = 0] = parse(current);
|
|
1398
|
+
if (cMaj !== uMaj) return cMaj > uMaj;
|
|
1399
|
+
if (cMin !== uMin) return cMin > uMin;
|
|
1400
|
+
return cPat > uPat;
|
|
1401
|
+
}
|
|
1402
|
+
function runSelfUpdate(currentVersion, passthroughArgs = []) {
|
|
1403
|
+
const method = detectInstallMethod();
|
|
1404
|
+
if (method !== "npm") {
|
|
1405
|
+
return {
|
|
1406
|
+
ok: false,
|
|
1407
|
+
updated: false,
|
|
1408
|
+
fromVersion: currentVersion,
|
|
1409
|
+
error: "ctxdb was not installed via npm. Update manually with your package manager."
|
|
1410
|
+
};
|
|
1411
|
+
}
|
|
1412
|
+
const check = checkLatestVersion(currentVersion);
|
|
1413
|
+
if (check.error) {
|
|
1414
|
+
process.stderr.write(`ctxdb: npm view failed (${check.error}), skipping self-update
|
|
1415
|
+
`);
|
|
1416
|
+
return { ok: true, updated: false, fromVersion: currentVersion };
|
|
1417
|
+
}
|
|
1418
|
+
if (!check.isNewer) {
|
|
1419
|
+
process.stderr.write(`ctxdb: package already up to date (v${currentVersion})
|
|
1420
|
+
`);
|
|
1421
|
+
return { ok: true, updated: false, fromVersion: currentVersion };
|
|
1422
|
+
}
|
|
1423
|
+
process.stderr.write(`ctxdb: updating ${PACKAGE_NAME} v${currentVersion} \u2192 v${check.latest}...
|
|
1424
|
+
`);
|
|
1425
|
+
const install = spawnSync("npm", ["install", "-g", `${PACKAGE_NAME}@${check.latest}`], {
|
|
1426
|
+
stdio: "inherit",
|
|
1427
|
+
encoding: "utf-8"
|
|
1428
|
+
});
|
|
1429
|
+
if (install.status !== 0) {
|
|
1430
|
+
return {
|
|
1431
|
+
ok: false,
|
|
1432
|
+
updated: false,
|
|
1433
|
+
fromVersion: currentVersion,
|
|
1434
|
+
error: `npm install -g failed with exit code ${install.status}`
|
|
1435
|
+
};
|
|
1436
|
+
}
|
|
1437
|
+
process.stderr.write(`ctxdb: package updated to v${check.latest}, refreshing skills/hooks...
|
|
1438
|
+
`);
|
|
1439
|
+
const upgradeArgs = ["upgrade", ...passthroughArgs];
|
|
1440
|
+
const refresh = spawnSync("ctxdb", upgradeArgs, {
|
|
1441
|
+
stdio: "inherit",
|
|
1442
|
+
encoding: "utf-8"
|
|
1443
|
+
});
|
|
1444
|
+
return {
|
|
1445
|
+
ok: refresh.status === 0,
|
|
1446
|
+
updated: true,
|
|
1447
|
+
fromVersion: currentVersion,
|
|
1448
|
+
toVersion: check.latest,
|
|
1449
|
+
error: refresh.status !== 0 ? `ctxdb upgrade exited with code ${refresh.status}` : void 0
|
|
1450
|
+
};
|
|
1451
|
+
}
|
|
1452
|
+
|
|
1329
1453
|
// src/cli/upgrade.ts
|
|
1454
|
+
var HELP3 = `ctxdb upgrade \u2014 refresh skills + hooks
|
|
1455
|
+
|
|
1456
|
+
USAGE
|
|
1457
|
+
ctxdb upgrade [--agent <qoder|codex|claude>] [--self-update] [--json]
|
|
1458
|
+
|
|
1459
|
+
BEHAVIOR
|
|
1460
|
+
Refreshes skill files and hook entries for configured agents without
|
|
1461
|
+
touching credentials. Designed for the post-npm-update path.
|
|
1462
|
+
|
|
1463
|
+
Without --agent: upgrades all configured built-in agents.
|
|
1464
|
+
With --agent: upgrades only the specified agent.
|
|
1465
|
+
|
|
1466
|
+
FLAGS
|
|
1467
|
+
--agent <name> Target a single agent (qoder|codex|claude)
|
|
1468
|
+
--self-update Also pull latest package from npm before upgrading
|
|
1469
|
+
--json Machine-readable JSON output
|
|
1470
|
+
`;
|
|
1330
1471
|
function upgrade(args) {
|
|
1472
|
+
if (args.flags.help || args.flags.h) {
|
|
1473
|
+
process.stdout.write(HELP3);
|
|
1474
|
+
return 0;
|
|
1475
|
+
}
|
|
1476
|
+
const selfUpdate = !!args.flags["self-update"];
|
|
1477
|
+
if (selfUpdate) {
|
|
1478
|
+
const passthrough = [];
|
|
1479
|
+
const agentFlag2 = args.flags.agent;
|
|
1480
|
+
if (agentFlag2) passthrough.push("--agent", agentFlag2);
|
|
1481
|
+
if (args.flags.json) passthrough.push("--json");
|
|
1482
|
+
const result2 = runSelfUpdate(PACKAGE_VERSION, passthrough);
|
|
1483
|
+
if (!result2.ok) {
|
|
1484
|
+
if (args.flags.json) {
|
|
1485
|
+
process.stdout.write(JSON.stringify({ ok: false, error: result2.error }) + "\n");
|
|
1486
|
+
} else {
|
|
1487
|
+
process.stderr.write(`ctxdb: self-update failed: ${result2.error}
|
|
1488
|
+
`);
|
|
1489
|
+
}
|
|
1490
|
+
return 1;
|
|
1491
|
+
}
|
|
1492
|
+
if (result2.updated) {
|
|
1493
|
+
return 0;
|
|
1494
|
+
}
|
|
1495
|
+
}
|
|
1331
1496
|
const agentFlag = args.flags.agent;
|
|
1332
|
-
if (agentFlag
|
|
1497
|
+
if (agentFlag === "default") {
|
|
1498
|
+
process.stderr.write("nothing to upgrade for default agent (no hooks or skills)\n");
|
|
1499
|
+
return 0;
|
|
1500
|
+
}
|
|
1501
|
+
if (agentFlag && !isBuiltinAgent(agentFlag)) {
|
|
1333
1502
|
process.stderr.write(
|
|
1334
1503
|
`unknown --agent: ${agentFlag} (expected one of ${SUPPORTED_AGENTS.join(" / ")})
|
|
1335
1504
|
`
|
|
@@ -1337,6 +1506,12 @@ function upgrade(args) {
|
|
|
1337
1506
|
return 2;
|
|
1338
1507
|
}
|
|
1339
1508
|
const result = runUpgrade({ agent: agentFlag });
|
|
1509
|
+
if (result.ok) {
|
|
1510
|
+
try {
|
|
1511
|
+
writeInstalledPkgVersion(PACKAGE_VERSION);
|
|
1512
|
+
} catch {
|
|
1513
|
+
}
|
|
1514
|
+
}
|
|
1340
1515
|
const json = !!args.flags.json;
|
|
1341
1516
|
printResult(result, json);
|
|
1342
1517
|
if (!json && result.hints) {
|
|
@@ -1347,6 +1522,71 @@ ${h}
|
|
|
1347
1522
|
return result.ok ? 0 : 1;
|
|
1348
1523
|
}
|
|
1349
1524
|
|
|
1525
|
+
// src/cli/skill-cli.ts
|
|
1526
|
+
var SUPPORTED_TARGETS = Object.keys(SKILL_INSTALL_TARGETS);
|
|
1527
|
+
var HELP4 = `ctxdb skill install \u2014 install skill files to an agent's skill directory
|
|
1528
|
+
|
|
1529
|
+
USAGE
|
|
1530
|
+
ctxdb skill install --target <name>
|
|
1531
|
+
ctxdb skill install --path <dir>
|
|
1532
|
+
|
|
1533
|
+
TARGETS
|
|
1534
|
+
${SUPPORTED_TARGETS.join(", ")}
|
|
1535
|
+
|
|
1536
|
+
FLAGS
|
|
1537
|
+
--target <name> Install to a built-in agent's skill directory
|
|
1538
|
+
--path <dir> Install to a custom directory
|
|
1539
|
+
--json Machine-readable JSON output
|
|
1540
|
+
|
|
1541
|
+
Note: This command only installs skill files (contextdb, contextdb-memory,
|
|
1542
|
+
contextdb-knowledge). It does not write config or install hooks.
|
|
1543
|
+
To configure server connection, run: ctxdb setup --api-key=<key> --base-url=<url>
|
|
1544
|
+
`;
|
|
1545
|
+
function skillInstall(args) {
|
|
1546
|
+
if (args.flags.help || args.flags.h) {
|
|
1547
|
+
process.stdout.write(HELP4);
|
|
1548
|
+
return 0;
|
|
1549
|
+
}
|
|
1550
|
+
const json = !!args.flags.json;
|
|
1551
|
+
const target = args.flags.target;
|
|
1552
|
+
const customPath = args.flags.path;
|
|
1553
|
+
if (target && customPath) {
|
|
1554
|
+
fail("--target and --path are mutually exclusive", 2);
|
|
1555
|
+
}
|
|
1556
|
+
if (!target && !customPath) {
|
|
1557
|
+
process.stderr.write(HELP4);
|
|
1558
|
+
return 2;
|
|
1559
|
+
}
|
|
1560
|
+
let targetRoot;
|
|
1561
|
+
if (customPath) {
|
|
1562
|
+
targetRoot = customPath;
|
|
1563
|
+
} else {
|
|
1564
|
+
const resolved = skillInstallTargetPath(target);
|
|
1565
|
+
if (!resolved) {
|
|
1566
|
+
fail(
|
|
1567
|
+
`unknown --target: ${target} (supported: ${SUPPORTED_TARGETS.join(", ")})`,
|
|
1568
|
+
2
|
|
1569
|
+
);
|
|
1570
|
+
}
|
|
1571
|
+
targetRoot = resolved;
|
|
1572
|
+
}
|
|
1573
|
+
const result = installSkillsTo(targetRoot);
|
|
1574
|
+
const ok = result.ok;
|
|
1575
|
+
const output = {
|
|
1576
|
+
ok,
|
|
1577
|
+
target: target ?? null,
|
|
1578
|
+
path: targetRoot,
|
|
1579
|
+
steps: result.steps
|
|
1580
|
+
};
|
|
1581
|
+
printResult(output, json);
|
|
1582
|
+
if (ok && !json) {
|
|
1583
|
+
process.stderr.write(
|
|
1584
|
+
"\nNote: This command only installs skill files.\nTo configure server connection, run:\n ctxdb setup --api-key=<key> --base-url=<url>\n"
|
|
1585
|
+
);
|
|
1586
|
+
}
|
|
1587
|
+
return ok ? 0 : 1;
|
|
1588
|
+
}
|
|
1589
|
+
|
|
1350
1590
|
// src/cli/memory.ts
|
|
1351
1591
|
async function memoryAdd(args) {
|
|
1352
1592
|
const text = args.positional[0];
|
|
@@ -1477,25 +1717,20 @@ async function kbUploadText(args) {
|
|
|
1477
1717
|
const text = args.flags["text"];
|
|
1478
1718
|
if (!kbName || !docName || typeof text !== "string") {
|
|
1479
1719
|
fail(
|
|
1480
|
-
"usage: ctxdb kb upload-text <kb-name> <doc-name> --text=<body> [--
|
|
1720
|
+
"usage: ctxdb kb upload-text <kb-name> <doc-name> --text=<body> [--file-path=<server-logical-path>] [--no-wait]"
|
|
1481
1721
|
);
|
|
1482
1722
|
}
|
|
1483
1723
|
const ctx = buildContext(args);
|
|
1484
|
-
const description = args.flags["kb-description"] ?? "";
|
|
1485
1724
|
const filePath = typeof args.flags["file-path"] === "string" ? args.flags["file-path"] : void 0;
|
|
1486
|
-
const
|
|
1487
|
-
const doc = await uploadText(ctx.client, kb.id, docName, text, "text/plain", filePath);
|
|
1725
|
+
const doc = await uploadText(ctx.client, kbName, docName, text, "text/plain", filePath);
|
|
1488
1726
|
if (args.flags["no-wait"]) {
|
|
1489
|
-
printResult({
|
|
1727
|
+
printResult({ document: doc }, !!args.flags.json);
|
|
1490
1728
|
return 0;
|
|
1491
1729
|
}
|
|
1492
|
-
const final = await pollIngest(ctx.client,
|
|
1730
|
+
const final = await pollIngest(ctx.client, kbName, doc.id, {
|
|
1493
1731
|
timeoutMs: DEFAULT_INGEST_TIMEOUT_MS
|
|
1494
1732
|
});
|
|
1495
|
-
printResult(
|
|
1496
|
-
{ kb, kb_created: created, document: final },
|
|
1497
|
-
!!args.flags.json
|
|
1498
|
-
);
|
|
1733
|
+
printResult({ document: final }, !!args.flags.json);
|
|
1499
1734
|
return 0;
|
|
1500
1735
|
}
|
|
1501
1736
|
async function kbUploadFile(args) {
|
|
@@ -1506,23 +1741,28 @@ async function kbUploadFile(args) {
|
|
|
1506
1741
|
);
|
|
1507
1742
|
}
|
|
1508
1743
|
const ctx = buildContext(args);
|
|
1509
|
-
const
|
|
1510
|
-
const doc = await uploadFile(ctx.client, kb.id, localPath, {
|
|
1744
|
+
const doc = await uploadFile(ctx.client, kbName, localPath, {
|
|
1511
1745
|
docName: typeof args.flags["doc-name"] === "string" ? args.flags["doc-name"] : void 0,
|
|
1512
1746
|
filePath: typeof args.flags["file-path"] === "string" ? args.flags["file-path"] : void 0,
|
|
1513
1747
|
timeoutMs: DEFAULT_FILE_INGEST_TIMEOUT_MS
|
|
1514
1748
|
});
|
|
1515
1749
|
if (args.flags["no-wait"]) {
|
|
1516
|
-
printResult({
|
|
1750
|
+
printResult({ document: doc }, !!args.flags.json);
|
|
1517
1751
|
return 0;
|
|
1518
1752
|
}
|
|
1519
|
-
const final = await pollIngest(ctx.client,
|
|
1753
|
+
const final = await pollIngest(ctx.client, kbName, doc.id, {
|
|
1520
1754
|
timeoutMs: DEFAULT_FILE_INGEST_TIMEOUT_MS
|
|
1521
1755
|
});
|
|
1522
|
-
printResult(
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1756
|
+
printResult({ document: final }, !!args.flags.json);
|
|
1757
|
+
return 0;
|
|
1758
|
+
}
|
|
1759
|
+
async function kbCreate(args) {
|
|
1760
|
+
const kbName = args.positional[0];
|
|
1761
|
+
if (!kbName) fail("usage: ctxdb kb create <kb-name> [--description=<desc>]");
|
|
1762
|
+
const ctx = buildContext(args);
|
|
1763
|
+
const description = typeof args.flags["description"] === "string" ? args.flags["description"] : "";
|
|
1764
|
+
const kb = await createKb(ctx.client, kbName, description);
|
|
1765
|
+
printResult(kb, !!args.flags.json);
|
|
1526
1766
|
return 0;
|
|
1527
1767
|
}
|
|
1528
1768
|
async function kbList(args) {
|
|
@@ -1532,28 +1772,24 @@ async function kbList(args) {
|
|
|
1532
1772
|
return 0;
|
|
1533
1773
|
}
|
|
1534
1774
|
async function kbDocumentsList(args) {
|
|
1535
|
-
const
|
|
1536
|
-
if (!
|
|
1775
|
+
const kbName = args.positional[0];
|
|
1776
|
+
if (!kbName) fail("usage: ctxdb kb documents-list <kb-name>");
|
|
1537
1777
|
const ctx = buildContext(args);
|
|
1538
|
-
const
|
|
1539
|
-
if (!kb) fail(`KB not found: ${kbNameOrId}`);
|
|
1540
|
-
const docs = await listDocuments(ctx.client, kb.id);
|
|
1778
|
+
const docs = await listDocuments(ctx.client, kbName);
|
|
1541
1779
|
printResult(
|
|
1542
|
-
{
|
|
1780
|
+
{ documents: docs, count: docs.length },
|
|
1543
1781
|
!!args.flags.json
|
|
1544
1782
|
);
|
|
1545
1783
|
return 0;
|
|
1546
1784
|
}
|
|
1547
1785
|
async function kbDocumentGet(args) {
|
|
1548
|
-
const [
|
|
1549
|
-
if (!
|
|
1550
|
-
fail("usage: ctxdb kb document-get <kb-name
|
|
1786
|
+
const [kbName, docId] = args.positional;
|
|
1787
|
+
if (!kbName || !docId) {
|
|
1788
|
+
fail("usage: ctxdb kb document-get <kb-name> <doc-id>");
|
|
1551
1789
|
}
|
|
1552
1790
|
const ctx = buildContext(args);
|
|
1553
|
-
const
|
|
1554
|
-
|
|
1555
|
-
const doc = await getDocument(ctx.client, kb.id, docId);
|
|
1556
|
-
printResult({ kb, document: doc }, !!args.flags.json);
|
|
1791
|
+
const doc = await getDocument(ctx.client, kbName, docId);
|
|
1792
|
+
printResult({ document: doc }, !!args.flags.json);
|
|
1557
1793
|
return 0;
|
|
1558
1794
|
}
|
|
1559
1795
|
async function kbSearch(args) {
|
|
@@ -1564,16 +1800,10 @@ async function kbSearch(args) {
|
|
|
1564
1800
|
);
|
|
1565
1801
|
}
|
|
1566
1802
|
const ctx = buildContext(args);
|
|
1567
|
-
const
|
|
1568
|
-
const datasetIds = [];
|
|
1569
|
-
for (const name of kbList2) {
|
|
1570
|
-
const kb = await findKb(ctx.client, name);
|
|
1571
|
-
if (!kb) fail(`KB not found: ${name}`);
|
|
1572
|
-
datasetIds.push(kb.id);
|
|
1573
|
-
}
|
|
1803
|
+
const kbNames = (typeof args.flags.kb === "string" ? args.flags.kb : "").split(",").map((s) => s.trim()).filter(Boolean);
|
|
1574
1804
|
const body = {
|
|
1575
1805
|
question: query,
|
|
1576
|
-
|
|
1806
|
+
knowledge_base_names: kbNames
|
|
1577
1807
|
};
|
|
1578
1808
|
if (typeof args.flags["top-k"] === "string") {
|
|
1579
1809
|
const n = Number(args.flags["top-k"]);
|
|
@@ -1590,21 +1820,22 @@ async function kbSearch(args) {
|
|
|
1590
1820
|
}
|
|
1591
1821
|
|
|
1592
1822
|
// src/cli/main.ts
|
|
1593
|
-
var
|
|
1823
|
+
var HELP5 = `ctxdb v${PACKAGE_VERSION} \u2014 RDS ContextDatabase CLI (multi-agent)
|
|
1594
1824
|
|
|
1595
1825
|
USAGE
|
|
1596
1826
|
ctxdb <command> [args] [--flags]
|
|
1597
1827
|
|
|
1598
1828
|
COMMANDS
|
|
1599
|
-
setup --agent <qoder|codex|claude>
|
|
1829
|
+
setup [--agent <qoder|codex|claude>]
|
|
1600
1830
|
[--api-key=K] [--base-url=URL] [--user-id=ID]
|
|
1601
1831
|
[--no-install-skill] [--no-validate] [--json]
|
|
1832
|
+
Without --agent \u2192 writes agents.default (CLI-only, no hooks/skills)
|
|
1602
1833
|
Qoder \u2192 writes agents.qoder config + ~/.qoder/settings.json hooks + skill
|
|
1603
1834
|
Codex \u2192 writes agents.codex config + ~/.codex/hooks.json hooks + skill
|
|
1604
1835
|
Claude \u2192 writes agents.claude config + ~/.claude/settings.json hooks + skill
|
|
1605
|
-
status [--agent <
|
|
1606
|
-
ping [--agent <
|
|
1607
|
-
uninstall [--agent <
|
|
1836
|
+
status [--agent <name>] [--json]
|
|
1837
|
+
ping [--agent <name>] [--json]
|
|
1838
|
+
uninstall [--agent <name>] [--purge-config] [--purge-logs] [--purge-all] [--json]
|
|
1608
1839
|
teardown (alias for uninstall)
|
|
1609
1840
|
Without --agent: removes hooks + skills for every agent.
|
|
1610
1841
|
With --agent: removes only that agent's hooks + skill + config section.
|
|
@@ -1612,10 +1843,9 @@ COMMANDS
|
|
|
1612
1843
|
--purge-logs also deletes ~/.ctxdb/logs/.
|
|
1613
1844
|
--purge-all deletes everything under ~/.ctxdb/
|
|
1614
1845
|
(does not run npm uninstall).
|
|
1615
|
-
upgrade [--agent <name>] [--json]
|
|
1616
|
-
Refresh skills + hooks
|
|
1617
|
-
|
|
1618
|
-
Does not modify credentials.
|
|
1846
|
+
upgrade|update [--agent <name>] [--self-update] [--json]
|
|
1847
|
+
Refresh skills + hooks. --self-update also
|
|
1848
|
+
pulls latest package from npm.
|
|
1619
1849
|
|
|
1620
1850
|
memory add <text> [--agent=<name>] [--user-id=...] [--metadata=K1=V1,K2=V2] [--no-infer]
|
|
1621
1851
|
memory search <query> [--agent=<name>] [--top-k=10] [--threshold=0.4] [--knowledge]
|
|
@@ -1629,13 +1859,14 @@ COMMANDS
|
|
|
1629
1859
|
memory update <memory-id> --text=<new-text> [--agent=<name>]
|
|
1630
1860
|
memory delete <memory-id> | --all [--agent=<name>]
|
|
1631
1861
|
|
|
1862
|
+
kb create <kb-name> [--description=<desc>] [--agent=<name>]
|
|
1632
1863
|
kb upload-text <kb-name> <doc-name> --text=<body> [--agent=<name>]
|
|
1633
|
-
[--
|
|
1864
|
+
[--file-path=<server-logical-path>] [--no-wait]
|
|
1634
1865
|
kb upload-file <kb-name> <local-path> [--agent=<name>] [--doc-name=...]
|
|
1635
1866
|
[--file-path=<server-logical-path>] [--no-wait]
|
|
1636
1867
|
kb list [--agent=<name>]
|
|
1637
|
-
kb documents-list <kb-name
|
|
1638
|
-
kb document-get <kb-name
|
|
1868
|
+
kb documents-list <kb-name> [--agent=<name>]
|
|
1869
|
+
kb document-get <kb-name> <doc-id> [--agent=<name>]
|
|
1639
1870
|
kb search <query> [--agent=<name>] [--kb=name1,name2] [--top-k=N] [--threshold=F]
|
|
1640
1871
|
[--verbose] [--raw]
|
|
1641
1872
|
Standalone KB recall (independent of memory).
|
|
@@ -1644,10 +1875,20 @@ COMMANDS
|
|
|
1644
1875
|
doc_id?/tags? for citation.
|
|
1645
1876
|
--raw: server response verbatim (curl parity).
|
|
1646
1877
|
|
|
1878
|
+
skill install --target <qoder|codex|claude|openclaw|hermes> [--json]
|
|
1879
|
+
skill install --path <dir> [--json]
|
|
1880
|
+
Install skill files (contextdb-memory,
|
|
1881
|
+
contextdb-knowledge) to an agent's skill directory.
|
|
1882
|
+
Does not write config or install hooks.
|
|
1883
|
+
|
|
1884
|
+
AGENT RESOLUTION (when --agent is omitted):
|
|
1885
|
+
1. CTXDB_AGENT env var
|
|
1886
|
+
2. agents.default section in ~/.ctxdb/ctxdb.json
|
|
1887
|
+
|
|
1647
1888
|
ENV VARS (override selected ~/.ctxdb/ctxdb.json agent config):
|
|
1648
1889
|
CTXDB_AGENT CTXDB_API_KEY CTXDB_BASE_URL CTXDB_USER_ID
|
|
1649
1890
|
|
|
1650
|
-
CONFIG: ~/.ctxdb/ctxdb.json (agents.qoder / agents.codex / agents.claude)
|
|
1891
|
+
CONFIG: ~/.ctxdb/ctxdb.json (agents.default / agents.qoder / agents.codex / agents.claude)
|
|
1651
1892
|
LOGS: ~/.ctxdb/logs/ctxdb.log
|
|
1652
1893
|
`;
|
|
1653
1894
|
var ROUTES = {
|
|
@@ -1657,6 +1898,10 @@ var ROUTES = {
|
|
|
1657
1898
|
uninstall,
|
|
1658
1899
|
teardown: uninstall,
|
|
1659
1900
|
upgrade,
|
|
1901
|
+
update: upgrade,
|
|
1902
|
+
skill: {
|
|
1903
|
+
install: skillInstall
|
|
1904
|
+
},
|
|
1660
1905
|
memory: {
|
|
1661
1906
|
add: memoryAdd,
|
|
1662
1907
|
search: memorySearch,
|
|
@@ -1666,6 +1911,7 @@ var ROUTES = {
|
|
|
1666
1911
|
delete: memoryDelete
|
|
1667
1912
|
},
|
|
1668
1913
|
kb: {
|
|
1914
|
+
create: kbCreate,
|
|
1669
1915
|
"upload-text": kbUploadText,
|
|
1670
1916
|
"upload-file": kbUploadFile,
|
|
1671
1917
|
list: kbList,
|
|
@@ -1676,7 +1922,7 @@ var ROUTES = {
|
|
|
1676
1922
|
};
|
|
1677
1923
|
async function main(argv = process.argv.slice(2)) {
|
|
1678
1924
|
if (argv.length === 0 || argv[0] === "-h" || argv[0] === "--help") {
|
|
1679
|
-
process.stdout.write(
|
|
1925
|
+
process.stdout.write(HELP5);
|
|
1680
1926
|
return 0;
|
|
1681
1927
|
}
|
|
1682
1928
|
if (argv[0] === "-v" || argv[0] === "--version") {
|
|
@@ -1689,7 +1935,7 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
1689
1935
|
if (!route) {
|
|
1690
1936
|
process.stderr.write(`unknown command: ${first}
|
|
1691
1937
|
`);
|
|
1692
|
-
process.stderr.write(
|
|
1938
|
+
process.stderr.write(HELP5);
|
|
1693
1939
|
return 2;
|
|
1694
1940
|
}
|
|
1695
1941
|
if (typeof route === "function") {
|
|
@@ -1702,6 +1948,13 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
1702
1948
|
);
|
|
1703
1949
|
return 2;
|
|
1704
1950
|
}
|
|
1951
|
+
if (rest[0] === "-h" || rest[0] === "--help") {
|
|
1952
|
+
process.stdout.write(
|
|
1953
|
+
`usage: ctxdb ${first} <${Object.keys(route).join("|")}> ...
|
|
1954
|
+
`
|
|
1955
|
+
);
|
|
1956
|
+
return 0;
|
|
1957
|
+
}
|
|
1705
1958
|
const [sub, ...subRest] = rest;
|
|
1706
1959
|
const handler = route[sub];
|
|
1707
1960
|
if (!handler) {
|