@aliyunrds/ctxdb 0.0.5 → 0.0.8-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 +3 -3
- package/dist/{chunk-HAUTENYD.js → chunk-6S5RJYBC.js} +20 -77
- package/dist/{chunk-7NOXAU2X.js → chunk-C62I23HL.js} +41 -3
- package/dist/chunk-KEQMJ6IO.js +69 -0
- package/dist/{chunk-QSSNPN3M.js → chunk-U3T5O6NX.js} +57 -14
- package/dist/cli/main.js +428 -172
- package/dist/hooks/session-start.js +71 -32
- package/dist/hooks/stop.js +94 -21
- package/dist/hooks/user-prompt-submit.js +50 -45
- package/dist/setup/skills/contextdb-knowledge/SKILL.md +189 -0
- package/dist/setup/skills/contextdb-memory/SKILL.md +182 -0
- package/package.json +3 -4
- 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-U3T5O6NX.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)) {
|
|
@@ -649,11 +624,15 @@ function checkHookNodePaths(agent) {
|
|
|
649
624
|
if (!entryIsCtxdb(entry)) continue;
|
|
650
625
|
for (const h of entry.hooks ?? []) {
|
|
651
626
|
if (h?.type !== "command" || typeof h.command !== "string") continue;
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
627
|
+
if (Array.isArray(h.args) && h.args.length > 0) {
|
|
628
|
+
nodePaths.add(h.command);
|
|
629
|
+
} else {
|
|
630
|
+
const cmd = h.command;
|
|
631
|
+
if (cmd.includes("@aliyunrds/ctxdb")) {
|
|
632
|
+
const parts = cmd.split(" ");
|
|
633
|
+
if (parts.length >= 2 && !parts[0].endsWith(".js") && !parts[0].endsWith(".ts")) {
|
|
634
|
+
nodePaths.add(parts[0]);
|
|
635
|
+
}
|
|
657
636
|
}
|
|
658
637
|
}
|
|
659
638
|
}
|
|
@@ -827,6 +806,44 @@ function copySkillDir(src, dest, agent) {
|
|
|
827
806
|
}
|
|
828
807
|
}
|
|
829
808
|
}
|
|
809
|
+
var SKILL_INSTALL_TARGETS = {
|
|
810
|
+
qoder: join(homedir(), ".qoder", "skills"),
|
|
811
|
+
codex: join(homedir(), ".codex", "skills"),
|
|
812
|
+
claude: join(homedir(), ".claude", "skills"),
|
|
813
|
+
openclaw: join(homedir(), ".openclaw", "skills"),
|
|
814
|
+
hermes: join(homedir(), ".hermes", "skills")
|
|
815
|
+
};
|
|
816
|
+
function skillInstallTargetPath(target) {
|
|
817
|
+
return SKILL_INSTALL_TARGETS[target] ?? null;
|
|
818
|
+
}
|
|
819
|
+
function installSkillsTo(targetRoot, agent = "default") {
|
|
820
|
+
const steps = [];
|
|
821
|
+
for (const skillName of SKILL_DIRS) {
|
|
822
|
+
try {
|
|
823
|
+
const srcDir = locateSkillDir(skillName);
|
|
824
|
+
if (srcDir) {
|
|
825
|
+
const dest = join(targetRoot, skillName);
|
|
826
|
+
copySkillDir(srcDir, dest, agent);
|
|
827
|
+
steps.push({ step: "install-skill", ok: true, detail: dest });
|
|
828
|
+
} else {
|
|
829
|
+
steps.push({
|
|
830
|
+
step: "install-skill",
|
|
831
|
+
ok: false,
|
|
832
|
+
detail: `skill source directory not found (${skillName})`
|
|
833
|
+
});
|
|
834
|
+
return { ok: false, steps };
|
|
835
|
+
}
|
|
836
|
+
} catch (err) {
|
|
837
|
+
steps.push({
|
|
838
|
+
step: "install-skill",
|
|
839
|
+
ok: false,
|
|
840
|
+
detail: err?.message ?? String(err)
|
|
841
|
+
});
|
|
842
|
+
return { ok: false, steps };
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
return { ok: true, steps };
|
|
846
|
+
}
|
|
830
847
|
function appendHooks(agent, hookPaths) {
|
|
831
848
|
const path = hookConfigPath(agent);
|
|
832
849
|
if (!path) return;
|
|
@@ -852,16 +869,15 @@ var LEGACY_MARKER_KEYS = ["_ctxdbQoder", "_ctxdbPackage"];
|
|
|
852
869
|
var LEGACY_MARKER_VALUES = ["@aliyunrds/ctxdb-qoder"];
|
|
853
870
|
var TOOL_SCOPED_EVENTS = /* @__PURE__ */ new Set(["PreToolUse", "PostToolUse"]);
|
|
854
871
|
function appendOne(hooks, event, command, agent) {
|
|
855
|
-
const commandWithAgent = `${process.execPath} ${command} --agent=${agent}`;
|
|
856
872
|
if (!Array.isArray(hooks[event])) hooks[event] = [];
|
|
857
873
|
const dup = hooks[event].some(
|
|
858
874
|
(entry2) => Array.isArray(entry2?.hooks) && entry2.hooks.some(
|
|
859
|
-
(h) => h?.type === "command" &&
|
|
875
|
+
(h) => h?.type === "command" && Array.isArray(h.args) && h.args[0] === command
|
|
860
876
|
)
|
|
861
877
|
);
|
|
862
878
|
if (dup) return;
|
|
863
879
|
const entry = {
|
|
864
|
-
hooks: [{ type: "command", command:
|
|
880
|
+
hooks: [{ type: "command", command: process.execPath, args: [command, `--agent=${agent}`], timeout: 60 }],
|
|
865
881
|
[ENTRY_MARKER_KEY]: ENTRY_MARKER_VALUE,
|
|
866
882
|
[ENTRY_AGENT_KEY]: agent
|
|
867
883
|
};
|
|
@@ -1081,7 +1097,7 @@ function describeCodexFeatureMutation(status2, createdNew) {
|
|
|
1081
1097
|
}
|
|
1082
1098
|
}
|
|
1083
1099
|
function runUpgrade(options = {}) {
|
|
1084
|
-
const agents = options.agent ? [options.agent] : configuredAgents(options.configPath);
|
|
1100
|
+
const agents = options.agent ? [options.agent] : configuredAgents(options.configPath).filter(isBuiltinAgent);
|
|
1085
1101
|
if (agents.length === 0) {
|
|
1086
1102
|
return {
|
|
1087
1103
|
ok: false,
|
|
@@ -1113,24 +1129,19 @@ function upgradeOneAgent(agent) {
|
|
|
1113
1129
|
if (!homeCheck.ok) {
|
|
1114
1130
|
return { ok: true, steps, hints: [`${agent}: skipped \u2014 agent home not found`] };
|
|
1115
1131
|
}
|
|
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 };
|
|
1132
|
+
const root = skillInstallRoot(agent);
|
|
1133
|
+
for (const legacy of LEGACY_SKILL_DIRS) {
|
|
1134
|
+
const legacyDir = join(root, legacy);
|
|
1135
|
+
if (!existsSync(legacyDir)) continue;
|
|
1136
|
+
try {
|
|
1137
|
+
rmSync(legacyDir, { recursive: true, force: true });
|
|
1138
|
+
steps.push({ step: "remove-legacy-skill", ok: true, detail: legacyDir });
|
|
1139
|
+
} catch {
|
|
1129
1140
|
}
|
|
1130
|
-
} catch (err) {
|
|
1131
|
-
steps.push({ step: "install-skill", ok: false, detail: err?.message ?? String(err) });
|
|
1132
|
-
return { ok: false, steps };
|
|
1133
1141
|
}
|
|
1142
|
+
const skillResult = installSkillsTo(root, agent);
|
|
1143
|
+
steps.push(...skillResult.steps);
|
|
1144
|
+
if (!skillResult.ok) return { ok: false, steps };
|
|
1134
1145
|
if (agentSupportsHooks(agent)) {
|
|
1135
1146
|
const hookPaths = locateHookPaths();
|
|
1136
1147
|
if (!hookPaths) {
|
|
@@ -1188,7 +1199,7 @@ async function status(args) {
|
|
|
1188
1199
|
pingError = err?.message ?? String(err);
|
|
1189
1200
|
}
|
|
1190
1201
|
}
|
|
1191
|
-
const hookHealth = checkHookNodePaths(agent);
|
|
1202
|
+
const hookHealth = isBuiltinAgent(agent) ? checkHookNodePaths(agent) : { installed: false, nodePaths: [], nodeOk: true, detail: "no hooks (default agent)" };
|
|
1192
1203
|
printResult(
|
|
1193
1204
|
{
|
|
1194
1205
|
ok: complete,
|
|
@@ -1226,25 +1237,51 @@ async function ping(args) {
|
|
|
1226
1237
|
}
|
|
1227
1238
|
|
|
1228
1239
|
// src/cli/setup-cli.ts
|
|
1240
|
+
var HELP = `ctxdb setup \u2014 configure an agent
|
|
1241
|
+
|
|
1242
|
+
USAGE
|
|
1243
|
+
ctxdb setup [--agent <qoder|codex|claude>]
|
|
1244
|
+
[--api-key=K] [--base-url=URL] [--user-id=ID]
|
|
1245
|
+
[--no-install-skill] [--no-validate] [--json]
|
|
1246
|
+
|
|
1247
|
+
BEHAVIOR
|
|
1248
|
+
Without --agent Writes agents.default in ~/.ctxdb/ctxdb.json (CLI-only,
|
|
1249
|
+
no hooks or skills installed).
|
|
1250
|
+
With --agent Writes agent config + installs hooks + skills for the
|
|
1251
|
+
specified agent harness.
|
|
1252
|
+
|
|
1253
|
+
FLAGS
|
|
1254
|
+
--agent <name> Target agent (qoder|codex|claude)
|
|
1255
|
+
--api-key <key> API key (required on first setup)
|
|
1256
|
+
--base-url <url> Server URL (default: https://context-database.aliyuncs.com)
|
|
1257
|
+
--user-id <id> User bucket (default: "default")
|
|
1258
|
+
--no-install-skill Skip skill directory installation
|
|
1259
|
+
--no-validate Skip connectivity ping after setup
|
|
1260
|
+
--json Machine-readable JSON output
|
|
1261
|
+
`;
|
|
1229
1262
|
function parseAgent(args) {
|
|
1230
1263
|
const raw = args.flags.agent;
|
|
1231
|
-
if (
|
|
1232
|
-
|
|
1233
|
-
}
|
|
1234
|
-
function agentError() {
|
|
1264
|
+
if (raw === void 0) return "default";
|
|
1265
|
+
if (typeof raw === "string" && isAgentSlug(raw)) return raw;
|
|
1235
1266
|
process.stderr.write(
|
|
1236
|
-
`
|
|
1237
|
-
e.g. ctxdb setup --agent qoder --api-key=<key>
|
|
1267
|
+
`unknown --agent: ${String(raw)} (expected one of ${SUPPORTED_AGENTS.join(" / ")} / default)
|
|
1238
1268
|
`
|
|
1239
1269
|
);
|
|
1270
|
+
process.exit(2);
|
|
1240
1271
|
}
|
|
1241
1272
|
async function setup(args) {
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
return 2;
|
|
1273
|
+
if (args.flags.help || args.flags.h) {
|
|
1274
|
+
process.stdout.write(HELP);
|
|
1275
|
+
return 0;
|
|
1246
1276
|
}
|
|
1277
|
+
const agent = parseAgent(args);
|
|
1247
1278
|
const json = !!args.flags.json;
|
|
1279
|
+
if (agent === "default" && !json && !configuredAgents().includes("default")) {
|
|
1280
|
+
process.stderr.write(
|
|
1281
|
+
`hint: creating CLI-only "default" agent (no hooks/skills). Use --agent <claude|qoder|codex> for full setup.
|
|
1282
|
+
`
|
|
1283
|
+
);
|
|
1284
|
+
}
|
|
1248
1285
|
const result = await runSetup({
|
|
1249
1286
|
agent,
|
|
1250
1287
|
apiKey: typeof args.flags["api-key"] === "string" ? args.flags["api-key"] : void 0,
|
|
@@ -1263,7 +1300,7 @@ ${h}
|
|
|
1263
1300
|
}
|
|
1264
1301
|
|
|
1265
1302
|
// src/cli/teardown.ts
|
|
1266
|
-
var
|
|
1303
|
+
var HELP2 = `ctxdb uninstall \u2014 remove hooks + skills
|
|
1267
1304
|
|
|
1268
1305
|
USAGE
|
|
1269
1306
|
ctxdb uninstall [--agent <qoder|codex|claude>] [--purge-config] [--purge-logs] [--purge-all] [--json]
|
|
@@ -1290,15 +1327,15 @@ NOTE
|
|
|
1290
1327
|
`;
|
|
1291
1328
|
function uninstall(args) {
|
|
1292
1329
|
if (args.flags.help || args.flags.h) {
|
|
1293
|
-
process.stdout.write(
|
|
1330
|
+
process.stdout.write(HELP2);
|
|
1294
1331
|
return 0;
|
|
1295
1332
|
}
|
|
1296
1333
|
const json = !!args.flags.json;
|
|
1297
1334
|
const agentFlag = args.flags.agent;
|
|
1298
1335
|
if (agentFlag !== void 0) {
|
|
1299
|
-
if (!
|
|
1336
|
+
if (!isAgentSlug(agentFlag)) {
|
|
1300
1337
|
process.stderr.write(
|
|
1301
|
-
`unknown --agent: ${String(agentFlag)} (expected one of ${SUPPORTED_AGENTS.join(" / ")})
|
|
1338
|
+
`unknown --agent: ${String(agentFlag)} (expected one of ${SUPPORTED_AGENTS.join(" / ")} / default)
|
|
1302
1339
|
`
|
|
1303
1340
|
);
|
|
1304
1341
|
return 2;
|
|
@@ -1326,10 +1363,145 @@ ${h}
|
|
|
1326
1363
|
return result.ok ? 0 : 1;
|
|
1327
1364
|
}
|
|
1328
1365
|
|
|
1366
|
+
// src/lib/self-update.ts
|
|
1367
|
+
import { spawnSync } from "child_process";
|
|
1368
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
1369
|
+
import { dirname as dirname2 } from "path";
|
|
1370
|
+
var PACKAGE_NAME = "@aliyunrds/ctxdb";
|
|
1371
|
+
var NPM_VIEW_TIMEOUT_MS = 1e4;
|
|
1372
|
+
function detectInstallMethod() {
|
|
1373
|
+
const dir = dirname2(fileURLToPath2(import.meta.url));
|
|
1374
|
+
return dir.includes("/node_modules/") ? "npm" : "unknown";
|
|
1375
|
+
}
|
|
1376
|
+
function checkLatestVersion(currentVersion) {
|
|
1377
|
+
const result = spawnSync("npm", ["view", PACKAGE_NAME, "version"], {
|
|
1378
|
+
encoding: "utf-8",
|
|
1379
|
+
timeout: NPM_VIEW_TIMEOUT_MS,
|
|
1380
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
1381
|
+
});
|
|
1382
|
+
if (result.status !== 0 || !result.stdout?.trim()) {
|
|
1383
|
+
return {
|
|
1384
|
+
latest: null,
|
|
1385
|
+
current: currentVersion,
|
|
1386
|
+
isNewer: false,
|
|
1387
|
+
error: result.stderr?.trim() || `npm view exited with code ${result.status}`
|
|
1388
|
+
};
|
|
1389
|
+
}
|
|
1390
|
+
const latest = result.stdout.trim();
|
|
1391
|
+
return {
|
|
1392
|
+
latest,
|
|
1393
|
+
current: currentVersion,
|
|
1394
|
+
isNewer: isNewerVersion(latest, currentVersion)
|
|
1395
|
+
};
|
|
1396
|
+
}
|
|
1397
|
+
function isNewerVersion(candidate, current) {
|
|
1398
|
+
const parse = (v) => v.replace(/^v/, "").split(".").map(Number);
|
|
1399
|
+
const [cMaj = 0, cMin = 0, cPat = 0] = parse(candidate);
|
|
1400
|
+
const [uMaj = 0, uMin = 0, uPat = 0] = parse(current);
|
|
1401
|
+
if (cMaj !== uMaj) return cMaj > uMaj;
|
|
1402
|
+
if (cMin !== uMin) return cMin > uMin;
|
|
1403
|
+
return cPat > uPat;
|
|
1404
|
+
}
|
|
1405
|
+
function runSelfUpdate(currentVersion, passthroughArgs = []) {
|
|
1406
|
+
const method = detectInstallMethod();
|
|
1407
|
+
if (method !== "npm") {
|
|
1408
|
+
return {
|
|
1409
|
+
ok: false,
|
|
1410
|
+
updated: false,
|
|
1411
|
+
fromVersion: currentVersion,
|
|
1412
|
+
error: "ctxdb was not installed via npm. Update manually with your package manager."
|
|
1413
|
+
};
|
|
1414
|
+
}
|
|
1415
|
+
const check = checkLatestVersion(currentVersion);
|
|
1416
|
+
if (check.error) {
|
|
1417
|
+
process.stderr.write(`ctxdb: npm view failed (${check.error}), skipping self-update
|
|
1418
|
+
`);
|
|
1419
|
+
return { ok: true, updated: false, fromVersion: currentVersion };
|
|
1420
|
+
}
|
|
1421
|
+
if (!check.isNewer) {
|
|
1422
|
+
process.stderr.write(`ctxdb: package already up to date (v${currentVersion})
|
|
1423
|
+
`);
|
|
1424
|
+
return { ok: true, updated: false, fromVersion: currentVersion };
|
|
1425
|
+
}
|
|
1426
|
+
process.stderr.write(`ctxdb: updating ${PACKAGE_NAME} v${currentVersion} \u2192 v${check.latest}...
|
|
1427
|
+
`);
|
|
1428
|
+
const install = spawnSync("npm", ["install", "-g", `${PACKAGE_NAME}@${check.latest}`], {
|
|
1429
|
+
stdio: "inherit",
|
|
1430
|
+
encoding: "utf-8"
|
|
1431
|
+
});
|
|
1432
|
+
if (install.status !== 0) {
|
|
1433
|
+
return {
|
|
1434
|
+
ok: false,
|
|
1435
|
+
updated: false,
|
|
1436
|
+
fromVersion: currentVersion,
|
|
1437
|
+
error: `npm install -g failed with exit code ${install.status}`
|
|
1438
|
+
};
|
|
1439
|
+
}
|
|
1440
|
+
process.stderr.write(`ctxdb: package updated to v${check.latest}, refreshing skills/hooks...
|
|
1441
|
+
`);
|
|
1442
|
+
const upgradeArgs = ["upgrade", ...passthroughArgs];
|
|
1443
|
+
const refresh = spawnSync("ctxdb", upgradeArgs, {
|
|
1444
|
+
stdio: "inherit",
|
|
1445
|
+
encoding: "utf-8"
|
|
1446
|
+
});
|
|
1447
|
+
return {
|
|
1448
|
+
ok: refresh.status === 0,
|
|
1449
|
+
updated: true,
|
|
1450
|
+
fromVersion: currentVersion,
|
|
1451
|
+
toVersion: check.latest,
|
|
1452
|
+
error: refresh.status !== 0 ? `ctxdb upgrade exited with code ${refresh.status}` : void 0
|
|
1453
|
+
};
|
|
1454
|
+
}
|
|
1455
|
+
|
|
1329
1456
|
// src/cli/upgrade.ts
|
|
1457
|
+
var HELP3 = `ctxdb upgrade \u2014 refresh skills + hooks
|
|
1458
|
+
|
|
1459
|
+
USAGE
|
|
1460
|
+
ctxdb upgrade [--agent <qoder|codex|claude>] [--self-update] [--json]
|
|
1461
|
+
|
|
1462
|
+
BEHAVIOR
|
|
1463
|
+
Refreshes skill files and hook entries for configured agents without
|
|
1464
|
+
touching credentials. Designed for the post-npm-update path.
|
|
1465
|
+
|
|
1466
|
+
Without --agent: upgrades all configured built-in agents.
|
|
1467
|
+
With --agent: upgrades only the specified agent.
|
|
1468
|
+
|
|
1469
|
+
FLAGS
|
|
1470
|
+
--agent <name> Target a single agent (qoder|codex|claude)
|
|
1471
|
+
--self-update Also pull latest package from npm before upgrading
|
|
1472
|
+
--json Machine-readable JSON output
|
|
1473
|
+
`;
|
|
1330
1474
|
function upgrade(args) {
|
|
1475
|
+
if (args.flags.help || args.flags.h) {
|
|
1476
|
+
process.stdout.write(HELP3);
|
|
1477
|
+
return 0;
|
|
1478
|
+
}
|
|
1479
|
+
const selfUpdate = !!args.flags["self-update"];
|
|
1480
|
+
if (selfUpdate) {
|
|
1481
|
+
const passthrough = [];
|
|
1482
|
+
const agentFlag2 = args.flags.agent;
|
|
1483
|
+
if (agentFlag2) passthrough.push("--agent", agentFlag2);
|
|
1484
|
+
if (args.flags.json) passthrough.push("--json");
|
|
1485
|
+
const result2 = runSelfUpdate(PACKAGE_VERSION, passthrough);
|
|
1486
|
+
if (!result2.ok) {
|
|
1487
|
+
if (args.flags.json) {
|
|
1488
|
+
process.stdout.write(JSON.stringify({ ok: false, error: result2.error }) + "\n");
|
|
1489
|
+
} else {
|
|
1490
|
+
process.stderr.write(`ctxdb: self-update failed: ${result2.error}
|
|
1491
|
+
`);
|
|
1492
|
+
}
|
|
1493
|
+
return 1;
|
|
1494
|
+
}
|
|
1495
|
+
if (result2.updated) {
|
|
1496
|
+
return 0;
|
|
1497
|
+
}
|
|
1498
|
+
}
|
|
1331
1499
|
const agentFlag = args.flags.agent;
|
|
1332
|
-
if (agentFlag
|
|
1500
|
+
if (agentFlag === "default") {
|
|
1501
|
+
process.stderr.write("nothing to upgrade for default agent (no hooks or skills)\n");
|
|
1502
|
+
return 0;
|
|
1503
|
+
}
|
|
1504
|
+
if (agentFlag && !isBuiltinAgent(agentFlag)) {
|
|
1333
1505
|
process.stderr.write(
|
|
1334
1506
|
`unknown --agent: ${agentFlag} (expected one of ${SUPPORTED_AGENTS.join(" / ")})
|
|
1335
1507
|
`
|
|
@@ -1337,6 +1509,12 @@ function upgrade(args) {
|
|
|
1337
1509
|
return 2;
|
|
1338
1510
|
}
|
|
1339
1511
|
const result = runUpgrade({ agent: agentFlag });
|
|
1512
|
+
if (result.ok) {
|
|
1513
|
+
try {
|
|
1514
|
+
writeInstalledPkgVersion(PACKAGE_VERSION);
|
|
1515
|
+
} catch {
|
|
1516
|
+
}
|
|
1517
|
+
}
|
|
1340
1518
|
const json = !!args.flags.json;
|
|
1341
1519
|
printResult(result, json);
|
|
1342
1520
|
if (!json && result.hints) {
|
|
@@ -1347,6 +1525,71 @@ ${h}
|
|
|
1347
1525
|
return result.ok ? 0 : 1;
|
|
1348
1526
|
}
|
|
1349
1527
|
|
|
1528
|
+
// src/cli/skill-cli.ts
|
|
1529
|
+
var SUPPORTED_TARGETS = Object.keys(SKILL_INSTALL_TARGETS);
|
|
1530
|
+
var HELP4 = `ctxdb skill install \u2014 install skill files to an agent's skill directory
|
|
1531
|
+
|
|
1532
|
+
USAGE
|
|
1533
|
+
ctxdb skill install --target <name>
|
|
1534
|
+
ctxdb skill install --path <dir>
|
|
1535
|
+
|
|
1536
|
+
TARGETS
|
|
1537
|
+
${SUPPORTED_TARGETS.join(", ")}
|
|
1538
|
+
|
|
1539
|
+
FLAGS
|
|
1540
|
+
--target <name> Install to a built-in agent's skill directory
|
|
1541
|
+
--path <dir> Install to a custom directory
|
|
1542
|
+
--json Machine-readable JSON output
|
|
1543
|
+
|
|
1544
|
+
Note: This command only installs skill files (contextdb, contextdb-memory,
|
|
1545
|
+
contextdb-knowledge). It does not write config or install hooks.
|
|
1546
|
+
To configure server connection, run: ctxdb setup --api-key=<key> --base-url=<url>
|
|
1547
|
+
`;
|
|
1548
|
+
function skillInstall(args) {
|
|
1549
|
+
if (args.flags.help || args.flags.h) {
|
|
1550
|
+
process.stdout.write(HELP4);
|
|
1551
|
+
return 0;
|
|
1552
|
+
}
|
|
1553
|
+
const json = !!args.flags.json;
|
|
1554
|
+
const target = args.flags.target;
|
|
1555
|
+
const customPath = args.flags.path;
|
|
1556
|
+
if (target && customPath) {
|
|
1557
|
+
fail("--target and --path are mutually exclusive", 2);
|
|
1558
|
+
}
|
|
1559
|
+
if (!target && !customPath) {
|
|
1560
|
+
process.stderr.write(HELP4);
|
|
1561
|
+
return 2;
|
|
1562
|
+
}
|
|
1563
|
+
let targetRoot;
|
|
1564
|
+
if (customPath) {
|
|
1565
|
+
targetRoot = customPath;
|
|
1566
|
+
} else {
|
|
1567
|
+
const resolved = skillInstallTargetPath(target);
|
|
1568
|
+
if (!resolved) {
|
|
1569
|
+
fail(
|
|
1570
|
+
`unknown --target: ${target} (supported: ${SUPPORTED_TARGETS.join(", ")})`,
|
|
1571
|
+
2
|
|
1572
|
+
);
|
|
1573
|
+
}
|
|
1574
|
+
targetRoot = resolved;
|
|
1575
|
+
}
|
|
1576
|
+
const result = installSkillsTo(targetRoot);
|
|
1577
|
+
const ok = result.ok;
|
|
1578
|
+
const output = {
|
|
1579
|
+
ok,
|
|
1580
|
+
target: target ?? null,
|
|
1581
|
+
path: targetRoot,
|
|
1582
|
+
steps: result.steps
|
|
1583
|
+
};
|
|
1584
|
+
printResult(output, json);
|
|
1585
|
+
if (ok && !json) {
|
|
1586
|
+
process.stderr.write(
|
|
1587
|
+
"\nNote: This command only installs skill files.\nTo configure server connection, run:\n ctxdb setup --api-key=<key> --base-url=<url>\n"
|
|
1588
|
+
);
|
|
1589
|
+
}
|
|
1590
|
+
return ok ? 0 : 1;
|
|
1591
|
+
}
|
|
1592
|
+
|
|
1350
1593
|
// src/cli/memory.ts
|
|
1351
1594
|
async function memoryAdd(args) {
|
|
1352
1595
|
const text = args.positional[0];
|
|
@@ -1477,25 +1720,20 @@ async function kbUploadText(args) {
|
|
|
1477
1720
|
const text = args.flags["text"];
|
|
1478
1721
|
if (!kbName || !docName || typeof text !== "string") {
|
|
1479
1722
|
fail(
|
|
1480
|
-
"usage: ctxdb kb upload-text <kb-name> <doc-name> --text=<body> [--
|
|
1723
|
+
"usage: ctxdb kb upload-text <kb-name> <doc-name> --text=<body> [--file-path=<server-logical-path>] [--no-wait]"
|
|
1481
1724
|
);
|
|
1482
1725
|
}
|
|
1483
1726
|
const ctx = buildContext(args);
|
|
1484
|
-
const description = args.flags["kb-description"] ?? "";
|
|
1485
1727
|
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);
|
|
1728
|
+
const doc = await uploadText(ctx.client, kbName, docName, text, "text/plain", filePath);
|
|
1488
1729
|
if (args.flags["no-wait"]) {
|
|
1489
|
-
printResult({
|
|
1730
|
+
printResult({ document: doc }, !!args.flags.json);
|
|
1490
1731
|
return 0;
|
|
1491
1732
|
}
|
|
1492
|
-
const final = await pollIngest(ctx.client,
|
|
1733
|
+
const final = await pollIngest(ctx.client, kbName, doc.id, {
|
|
1493
1734
|
timeoutMs: DEFAULT_INGEST_TIMEOUT_MS
|
|
1494
1735
|
});
|
|
1495
|
-
printResult(
|
|
1496
|
-
{ kb, kb_created: created, document: final },
|
|
1497
|
-
!!args.flags.json
|
|
1498
|
-
);
|
|
1736
|
+
printResult({ document: final }, !!args.flags.json);
|
|
1499
1737
|
return 0;
|
|
1500
1738
|
}
|
|
1501
1739
|
async function kbUploadFile(args) {
|
|
@@ -1506,23 +1744,28 @@ async function kbUploadFile(args) {
|
|
|
1506
1744
|
);
|
|
1507
1745
|
}
|
|
1508
1746
|
const ctx = buildContext(args);
|
|
1509
|
-
const
|
|
1510
|
-
const doc = await uploadFile(ctx.client, kb.id, localPath, {
|
|
1747
|
+
const doc = await uploadFile(ctx.client, kbName, localPath, {
|
|
1511
1748
|
docName: typeof args.flags["doc-name"] === "string" ? args.flags["doc-name"] : void 0,
|
|
1512
1749
|
filePath: typeof args.flags["file-path"] === "string" ? args.flags["file-path"] : void 0,
|
|
1513
1750
|
timeoutMs: DEFAULT_FILE_INGEST_TIMEOUT_MS
|
|
1514
1751
|
});
|
|
1515
1752
|
if (args.flags["no-wait"]) {
|
|
1516
|
-
printResult({
|
|
1753
|
+
printResult({ document: doc }, !!args.flags.json);
|
|
1517
1754
|
return 0;
|
|
1518
1755
|
}
|
|
1519
|
-
const final = await pollIngest(ctx.client,
|
|
1756
|
+
const final = await pollIngest(ctx.client, kbName, doc.id, {
|
|
1520
1757
|
timeoutMs: DEFAULT_FILE_INGEST_TIMEOUT_MS
|
|
1521
1758
|
});
|
|
1522
|
-
printResult(
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1759
|
+
printResult({ document: final }, !!args.flags.json);
|
|
1760
|
+
return 0;
|
|
1761
|
+
}
|
|
1762
|
+
async function kbCreate(args) {
|
|
1763
|
+
const kbName = args.positional[0];
|
|
1764
|
+
if (!kbName) fail("usage: ctxdb kb create <kb-name> [--description=<desc>]");
|
|
1765
|
+
const ctx = buildContext(args);
|
|
1766
|
+
const description = typeof args.flags["description"] === "string" ? args.flags["description"] : "";
|
|
1767
|
+
const kb = await createKb(ctx.client, kbName, description);
|
|
1768
|
+
printResult(kb, !!args.flags.json);
|
|
1526
1769
|
return 0;
|
|
1527
1770
|
}
|
|
1528
1771
|
async function kbList(args) {
|
|
@@ -1532,28 +1775,24 @@ async function kbList(args) {
|
|
|
1532
1775
|
return 0;
|
|
1533
1776
|
}
|
|
1534
1777
|
async function kbDocumentsList(args) {
|
|
1535
|
-
const
|
|
1536
|
-
if (!
|
|
1778
|
+
const kbName = args.positional[0];
|
|
1779
|
+
if (!kbName) fail("usage: ctxdb kb documents-list <kb-name>");
|
|
1537
1780
|
const ctx = buildContext(args);
|
|
1538
|
-
const
|
|
1539
|
-
if (!kb) fail(`KB not found: ${kbNameOrId}`);
|
|
1540
|
-
const docs = await listDocuments(ctx.client, kb.id);
|
|
1781
|
+
const docs = await listDocuments(ctx.client, kbName);
|
|
1541
1782
|
printResult(
|
|
1542
|
-
{
|
|
1783
|
+
{ documents: docs, count: docs.length },
|
|
1543
1784
|
!!args.flags.json
|
|
1544
1785
|
);
|
|
1545
1786
|
return 0;
|
|
1546
1787
|
}
|
|
1547
1788
|
async function kbDocumentGet(args) {
|
|
1548
|
-
const [
|
|
1549
|
-
if (!
|
|
1550
|
-
fail("usage: ctxdb kb document-get <kb-name
|
|
1789
|
+
const [kbName, docId] = args.positional;
|
|
1790
|
+
if (!kbName || !docId) {
|
|
1791
|
+
fail("usage: ctxdb kb document-get <kb-name> <doc-id>");
|
|
1551
1792
|
}
|
|
1552
1793
|
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);
|
|
1794
|
+
const doc = await getDocument(ctx.client, kbName, docId);
|
|
1795
|
+
printResult({ document: doc }, !!args.flags.json);
|
|
1557
1796
|
return 0;
|
|
1558
1797
|
}
|
|
1559
1798
|
async function kbSearch(args) {
|
|
@@ -1564,16 +1803,10 @@ async function kbSearch(args) {
|
|
|
1564
1803
|
);
|
|
1565
1804
|
}
|
|
1566
1805
|
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
|
-
}
|
|
1806
|
+
const kbNames = (typeof args.flags.kb === "string" ? args.flags.kb : "").split(",").map((s) => s.trim()).filter(Boolean);
|
|
1574
1807
|
const body = {
|
|
1575
1808
|
question: query,
|
|
1576
|
-
|
|
1809
|
+
knowledge_base_names: kbNames
|
|
1577
1810
|
};
|
|
1578
1811
|
if (typeof args.flags["top-k"] === "string") {
|
|
1579
1812
|
const n = Number(args.flags["top-k"]);
|
|
@@ -1590,21 +1823,22 @@ async function kbSearch(args) {
|
|
|
1590
1823
|
}
|
|
1591
1824
|
|
|
1592
1825
|
// src/cli/main.ts
|
|
1593
|
-
var
|
|
1826
|
+
var HELP5 = `ctxdb v${PACKAGE_VERSION} \u2014 RDS ContextDatabase CLI (multi-agent)
|
|
1594
1827
|
|
|
1595
1828
|
USAGE
|
|
1596
1829
|
ctxdb <command> [args] [--flags]
|
|
1597
1830
|
|
|
1598
1831
|
COMMANDS
|
|
1599
|
-
setup --agent <qoder|codex|claude>
|
|
1832
|
+
setup [--agent <qoder|codex|claude>]
|
|
1600
1833
|
[--api-key=K] [--base-url=URL] [--user-id=ID]
|
|
1601
1834
|
[--no-install-skill] [--no-validate] [--json]
|
|
1835
|
+
Without --agent \u2192 writes agents.default (CLI-only, no hooks/skills)
|
|
1602
1836
|
Qoder \u2192 writes agents.qoder config + ~/.qoder/settings.json hooks + skill
|
|
1603
1837
|
Codex \u2192 writes agents.codex config + ~/.codex/hooks.json hooks + skill
|
|
1604
1838
|
Claude \u2192 writes agents.claude config + ~/.claude/settings.json hooks + skill
|
|
1605
|
-
status [--agent <
|
|
1606
|
-
ping [--agent <
|
|
1607
|
-
uninstall [--agent <
|
|
1839
|
+
status [--agent <name>] [--json]
|
|
1840
|
+
ping [--agent <name>] [--json]
|
|
1841
|
+
uninstall [--agent <name>] [--purge-config] [--purge-logs] [--purge-all] [--json]
|
|
1608
1842
|
teardown (alias for uninstall)
|
|
1609
1843
|
Without --agent: removes hooks + skills for every agent.
|
|
1610
1844
|
With --agent: removes only that agent's hooks + skill + config section.
|
|
@@ -1612,10 +1846,9 @@ COMMANDS
|
|
|
1612
1846
|
--purge-logs also deletes ~/.ctxdb/logs/.
|
|
1613
1847
|
--purge-all deletes everything under ~/.ctxdb/
|
|
1614
1848
|
(does not run npm uninstall).
|
|
1615
|
-
upgrade [--agent <name>] [--json]
|
|
1616
|
-
Refresh skills + hooks
|
|
1617
|
-
|
|
1618
|
-
Does not modify credentials.
|
|
1849
|
+
upgrade|update [--agent <name>] [--self-update] [--json]
|
|
1850
|
+
Refresh skills + hooks. --self-update also
|
|
1851
|
+
pulls latest package from npm.
|
|
1619
1852
|
|
|
1620
1853
|
memory add <text> [--agent=<name>] [--user-id=...] [--metadata=K1=V1,K2=V2] [--no-infer]
|
|
1621
1854
|
memory search <query> [--agent=<name>] [--top-k=10] [--threshold=0.4] [--knowledge]
|
|
@@ -1629,13 +1862,14 @@ COMMANDS
|
|
|
1629
1862
|
memory update <memory-id> --text=<new-text> [--agent=<name>]
|
|
1630
1863
|
memory delete <memory-id> | --all [--agent=<name>]
|
|
1631
1864
|
|
|
1865
|
+
kb create <kb-name> [--description=<desc>] [--agent=<name>]
|
|
1632
1866
|
kb upload-text <kb-name> <doc-name> --text=<body> [--agent=<name>]
|
|
1633
|
-
[--
|
|
1867
|
+
[--file-path=<server-logical-path>] [--no-wait]
|
|
1634
1868
|
kb upload-file <kb-name> <local-path> [--agent=<name>] [--doc-name=...]
|
|
1635
1869
|
[--file-path=<server-logical-path>] [--no-wait]
|
|
1636
1870
|
kb list [--agent=<name>]
|
|
1637
|
-
kb documents-list <kb-name
|
|
1638
|
-
kb document-get <kb-name
|
|
1871
|
+
kb documents-list <kb-name> [--agent=<name>]
|
|
1872
|
+
kb document-get <kb-name> <doc-id> [--agent=<name>]
|
|
1639
1873
|
kb search <query> [--agent=<name>] [--kb=name1,name2] [--top-k=N] [--threshold=F]
|
|
1640
1874
|
[--verbose] [--raw]
|
|
1641
1875
|
Standalone KB recall (independent of memory).
|
|
@@ -1644,10 +1878,20 @@ COMMANDS
|
|
|
1644
1878
|
doc_id?/tags? for citation.
|
|
1645
1879
|
--raw: server response verbatim (curl parity).
|
|
1646
1880
|
|
|
1881
|
+
skill install --target <qoder|codex|claude|openclaw|hermes> [--json]
|
|
1882
|
+
skill install --path <dir> [--json]
|
|
1883
|
+
Install skill files (contextdb-memory,
|
|
1884
|
+
contextdb-knowledge) to an agent's skill directory.
|
|
1885
|
+
Does not write config or install hooks.
|
|
1886
|
+
|
|
1887
|
+
AGENT RESOLUTION (when --agent is omitted):
|
|
1888
|
+
1. CTXDB_AGENT env var
|
|
1889
|
+
2. agents.default section in ~/.ctxdb/ctxdb.json
|
|
1890
|
+
|
|
1647
1891
|
ENV VARS (override selected ~/.ctxdb/ctxdb.json agent config):
|
|
1648
1892
|
CTXDB_AGENT CTXDB_API_KEY CTXDB_BASE_URL CTXDB_USER_ID
|
|
1649
1893
|
|
|
1650
|
-
CONFIG: ~/.ctxdb/ctxdb.json (agents.qoder / agents.codex / agents.claude)
|
|
1894
|
+
CONFIG: ~/.ctxdb/ctxdb.json (agents.default / agents.qoder / agents.codex / agents.claude)
|
|
1651
1895
|
LOGS: ~/.ctxdb/logs/ctxdb.log
|
|
1652
1896
|
`;
|
|
1653
1897
|
var ROUTES = {
|
|
@@ -1657,6 +1901,10 @@ var ROUTES = {
|
|
|
1657
1901
|
uninstall,
|
|
1658
1902
|
teardown: uninstall,
|
|
1659
1903
|
upgrade,
|
|
1904
|
+
update: upgrade,
|
|
1905
|
+
skill: {
|
|
1906
|
+
install: skillInstall
|
|
1907
|
+
},
|
|
1660
1908
|
memory: {
|
|
1661
1909
|
add: memoryAdd,
|
|
1662
1910
|
search: memorySearch,
|
|
@@ -1666,6 +1914,7 @@ var ROUTES = {
|
|
|
1666
1914
|
delete: memoryDelete
|
|
1667
1915
|
},
|
|
1668
1916
|
kb: {
|
|
1917
|
+
create: kbCreate,
|
|
1669
1918
|
"upload-text": kbUploadText,
|
|
1670
1919
|
"upload-file": kbUploadFile,
|
|
1671
1920
|
list: kbList,
|
|
@@ -1676,7 +1925,7 @@ var ROUTES = {
|
|
|
1676
1925
|
};
|
|
1677
1926
|
async function main(argv = process.argv.slice(2)) {
|
|
1678
1927
|
if (argv.length === 0 || argv[0] === "-h" || argv[0] === "--help") {
|
|
1679
|
-
process.stdout.write(
|
|
1928
|
+
process.stdout.write(HELP5);
|
|
1680
1929
|
return 0;
|
|
1681
1930
|
}
|
|
1682
1931
|
if (argv[0] === "-v" || argv[0] === "--version") {
|
|
@@ -1689,7 +1938,7 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
1689
1938
|
if (!route) {
|
|
1690
1939
|
process.stderr.write(`unknown command: ${first}
|
|
1691
1940
|
`);
|
|
1692
|
-
process.stderr.write(
|
|
1941
|
+
process.stderr.write(HELP5);
|
|
1693
1942
|
return 2;
|
|
1694
1943
|
}
|
|
1695
1944
|
if (typeof route === "function") {
|
|
@@ -1702,6 +1951,13 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
1702
1951
|
);
|
|
1703
1952
|
return 2;
|
|
1704
1953
|
}
|
|
1954
|
+
if (rest[0] === "-h" || rest[0] === "--help") {
|
|
1955
|
+
process.stdout.write(
|
|
1956
|
+
`usage: ctxdb ${first} <${Object.keys(route).join("|")}> ...
|
|
1957
|
+
`
|
|
1958
|
+
);
|
|
1959
|
+
return 0;
|
|
1960
|
+
}
|
|
1705
1961
|
const [sub, ...subRest] = rest;
|
|
1706
1962
|
const handler = route[sub];
|
|
1707
1963
|
if (!handler) {
|