@aliyunrds/ctxdb 1.0.2 → 1.0.4
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 +174 -5
- package/dist/chunk-3PFMHU3C.js +442 -0
- package/dist/chunk-BQA7YSXT.js +462 -0
- package/dist/{chunk-2CSEFSLC.js → chunk-BVCDRUU4.js} +1 -1
- package/dist/{chunk-WTP4ZX22.js → chunk-CWGF5D52.js} +2 -2
- package/dist/{chunk-6FZL67GH.js → chunk-JFTKYEVN.js} +333 -45
- package/dist/{chunk-EUQ3OFCQ.js → chunk-Q4JYST7K.js} +3 -3
- package/dist/{chunk-IMYLU5C2.js → chunk-SAQT6VL6.js} +2 -2
- package/dist/{chunk-TGVURF54.js → chunk-USMJLDBD.js} +1 -1
- package/dist/cli/main.js +363 -166
- package/dist/hooks/hermes-post-llm-call.js +3 -3
- package/dist/hooks/hermes-pre-llm-call.js +6 -6
- package/dist/hooks/session-start.js +5 -5
- package/dist/hooks/stop.js +3 -3
- package/dist/hooks/user-prompt-submit.js +5 -5
- package/dist/setup/skills/contextdb-knowledge/SKILL.md +13 -3
- package/dist/workers/version-check.js +65 -0
- package/package.json +1 -1
- package/dist/chunk-UH7AJF6F.js +0 -204
package/dist/cli/main.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
DEFAULT_FILE_INGEST_TIMEOUT_MS,
|
|
4
|
+
DEFAULT_FILE_UPLOAD_TIMEOUT_MS,
|
|
4
5
|
DEFAULT_INGEST_TIMEOUT_MS,
|
|
5
6
|
compactKbQueryResponse,
|
|
6
7
|
createKb,
|
|
@@ -11,7 +12,7 @@ import {
|
|
|
11
12
|
pollIngest,
|
|
12
13
|
uploadFile,
|
|
13
14
|
uploadText
|
|
14
|
-
} from "../chunk-
|
|
15
|
+
} from "../chunk-3PFMHU3C.js";
|
|
15
16
|
import {
|
|
16
17
|
DEFAULT_BASE_URL,
|
|
17
18
|
DEFAULT_USER_ID,
|
|
@@ -21,7 +22,10 @@ import {
|
|
|
21
22
|
agentFromEnv,
|
|
22
23
|
agentHomeDir,
|
|
23
24
|
agentHomeDirs,
|
|
25
|
+
agentPlatformSupport,
|
|
24
26
|
configuredAgents,
|
|
27
|
+
detectInstalledAgents,
|
|
28
|
+
inspectAgentHomes,
|
|
25
29
|
isAgentSlug,
|
|
26
30
|
isBuiltinAgent,
|
|
27
31
|
isComplete,
|
|
@@ -29,7 +33,12 @@ import {
|
|
|
29
33
|
removeAgent,
|
|
30
34
|
save,
|
|
31
35
|
writeInstalledPkgVersion
|
|
32
|
-
} from "../chunk-
|
|
36
|
+
} from "../chunk-JFTKYEVN.js";
|
|
37
|
+
import {
|
|
38
|
+
beginUpdateNotification,
|
|
39
|
+
completeUpdateNotification,
|
|
40
|
+
runSelfUpdate
|
|
41
|
+
} from "../chunk-BQA7YSXT.js";
|
|
33
42
|
|
|
34
43
|
// src/cli/util.ts
|
|
35
44
|
var BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
|
|
@@ -55,6 +64,8 @@ var BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
|
|
|
55
64
|
"all",
|
|
56
65
|
// memory delete
|
|
57
66
|
// kb
|
|
67
|
+
"wait",
|
|
68
|
+
// kb upload-text / upload-file
|
|
58
69
|
"no-wait",
|
|
59
70
|
// kb upload-text / upload-file
|
|
60
71
|
"verbose",
|
|
@@ -116,8 +127,14 @@ var BOLD = "\x1B[1m";
|
|
|
116
127
|
var RESET = "\x1B[0m";
|
|
117
128
|
var CHECK = `${GREEN}\u2714${RESET}`;
|
|
118
129
|
var CROSS = `${RED}\u2718${RESET}`;
|
|
130
|
+
function highlightInlineCode(text, surroundingStyle = "") {
|
|
131
|
+
return text.replace(
|
|
132
|
+
/`([^`\n]+)`/g,
|
|
133
|
+
(_match, content) => `${RESET}${BOLD}${content}${RESET}${surroundingStyle}`
|
|
134
|
+
);
|
|
135
|
+
}
|
|
119
136
|
function dim(text) {
|
|
120
|
-
return `${DIM}${text}${RESET}`;
|
|
137
|
+
return `${DIM}${highlightInlineCode(text, DIM)}${RESET}`;
|
|
121
138
|
}
|
|
122
139
|
function isSetupResult(v) {
|
|
123
140
|
if (typeof v !== "object" || v === null) return false;
|
|
@@ -125,7 +142,12 @@ function isSetupResult(v) {
|
|
|
125
142
|
}
|
|
126
143
|
function isUpgradeResult(v) {
|
|
127
144
|
if (typeof v !== "object" || v === null) return false;
|
|
128
|
-
return "agents" in v && typeof v.agents === "object" && !("steps" in v);
|
|
145
|
+
return "agents" in v && typeof v.agents === "object" && !("steps" in v) && !("mode" in v);
|
|
146
|
+
}
|
|
147
|
+
function isMultiAgentResult(v) {
|
|
148
|
+
if (typeof v !== "object" || v === null) return false;
|
|
149
|
+
const value = v;
|
|
150
|
+
return value.mode === "all" && (value.operation === "setup" || value.operation === "status") && typeof value.agents === "object" && value.agents !== null && Array.isArray(value.skipped) && typeof value.summary === "object" && value.summary !== null;
|
|
129
151
|
}
|
|
130
152
|
function isStatusResult(v) {
|
|
131
153
|
if (typeof v !== "object" || v === null) return false;
|
|
@@ -137,7 +159,7 @@ function formatSetupResult(r, command = "setup") {
|
|
|
137
159
|
`);
|
|
138
160
|
for (const s of r.steps) {
|
|
139
161
|
const icon = s.ok ? CHECK : CROSS;
|
|
140
|
-
const detail = s.detail ? ` ${
|
|
162
|
+
const detail = s.detail ? ` ${dim(s.detail)}` : "";
|
|
141
163
|
lines.push(` ${icon} ${s.step}${detail}`);
|
|
142
164
|
}
|
|
143
165
|
return lines.join("\n");
|
|
@@ -152,12 +174,51 @@ function formatUpgradeResult(r) {
|
|
|
152
174
|
lines.push(` ${icon} ${BOLD}${name}${RESET}`);
|
|
153
175
|
for (const s of result.steps) {
|
|
154
176
|
const sIcon = s.ok ? CHECK : CROSS;
|
|
155
|
-
const detail = s.detail ? ` ${
|
|
177
|
+
const detail = s.detail ? ` ${dim(s.detail)}` : "";
|
|
156
178
|
lines.push(` ${sIcon} ${s.step}${detail}`);
|
|
157
179
|
}
|
|
158
180
|
}
|
|
159
181
|
return lines.join("\n");
|
|
160
182
|
}
|
|
183
|
+
function formatMultiAgentResult(r) {
|
|
184
|
+
const lines = [];
|
|
185
|
+
const { selected, succeeded, failed, skipped } = r.summary;
|
|
186
|
+
lines.push(
|
|
187
|
+
`${r.ok ? CHECK : CROSS} ${BOLD}ctxdb ${r.operation} --all${RESET} ${r.ok ? "completed" : "failed"} ${DIM}(${selected} selected, ${succeeded} succeeded, ${failed} failed, ${skipped} skipped)${RESET}
|
|
188
|
+
`
|
|
189
|
+
);
|
|
190
|
+
for (const [name, result] of Object.entries(r.agents)) {
|
|
191
|
+
const agentOk = r.operation === "setup" ? Boolean(result.ok) : Boolean(result.ok && result.connected);
|
|
192
|
+
lines.push(` ${agentOk ? CHECK : CROSS} ${BOLD}${name}${RESET}`);
|
|
193
|
+
if (r.operation === "setup") {
|
|
194
|
+
for (const step of result.steps ?? []) {
|
|
195
|
+
const detail = step.detail ? ` ${dim(step.detail)}` : "";
|
|
196
|
+
lines.push(` ${step.ok ? CHECK : CROSS} ${step.step}${detail}`);
|
|
197
|
+
}
|
|
198
|
+
for (const hint of result.hints ?? []) {
|
|
199
|
+
lines.push(` ${DIM}hint${RESET} ${highlightInlineCode(hint)}`);
|
|
200
|
+
}
|
|
201
|
+
continue;
|
|
202
|
+
}
|
|
203
|
+
lines.push(` ${DIM}config${RESET} ${result.ok ? "complete" : "incomplete"}`);
|
|
204
|
+
lines.push(` ${DIM}connected${RESET} ${result.connected ? "yes" : "no"}`);
|
|
205
|
+
if (result.hooks_node !== void 0) {
|
|
206
|
+
lines.push(` ${DIM}hooks${RESET} ${result.hooks_node}`);
|
|
207
|
+
}
|
|
208
|
+
if (result.ping_error) {
|
|
209
|
+
lines.push(` ${DIM}ping_error${RESET} ${result.ping_error}`);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
if (r.skipped.length > 0) {
|
|
213
|
+
lines.push("");
|
|
214
|
+
lines.push(` ${DIM}skipped${RESET}`);
|
|
215
|
+
for (const item of r.skipped) {
|
|
216
|
+
const detail = item.detail ? ` \u2014 ${item.detail}` : "";
|
|
217
|
+
lines.push(` ${item.agent}: ${item.reason}${detail}`);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
return lines.join("\n");
|
|
221
|
+
}
|
|
161
222
|
function formatStatusResult(r) {
|
|
162
223
|
const lines = [];
|
|
163
224
|
const ok = r.connected ? CHECK : CROSS;
|
|
@@ -190,6 +251,8 @@ function formatStatusResult(r) {
|
|
|
190
251
|
function printResult(value, json, command) {
|
|
191
252
|
if (json) {
|
|
192
253
|
process.stdout.write(JSON.stringify(value, null, 2) + "\n");
|
|
254
|
+
} else if (isMultiAgentResult(value)) {
|
|
255
|
+
process.stdout.write(formatMultiAgentResult(value) + "\n");
|
|
193
256
|
} else if (isUpgradeResult(value)) {
|
|
194
257
|
process.stdout.write(formatUpgradeResult(value) + "\n");
|
|
195
258
|
} else if (isSetupResult(value)) {
|
|
@@ -227,6 +290,9 @@ function fail(message, code = 1) {
|
|
|
227
290
|
process.exit(code);
|
|
228
291
|
}
|
|
229
292
|
|
|
293
|
+
// src/cli/main.ts
|
|
294
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
295
|
+
|
|
230
296
|
// src/setup/installer.ts
|
|
231
297
|
import {
|
|
232
298
|
readFileSync,
|
|
@@ -248,6 +314,10 @@ import { execFileSync } from "child_process";
|
|
|
248
314
|
import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
|
|
249
315
|
var UNINSTALL_NPM_HINT = "To also remove the npm binaries: `npm uninstall -g @aliyunrds/ctxdb @aliyunrds/ctxdb-shared`";
|
|
250
316
|
var UNINSTALL_ORDER_HINT = "When you eventually want to uninstall: run `ctxdb uninstall --purge-all` FIRST, then `npm uninstall -g @aliyunrds/ctxdb @aliyunrds/ctxdb-shared`. (npm 7+ removed uninstall lifecycle hooks, so the order matters \u2014 otherwise agent settings.json hooks + ~/.ctxdb/ residue stay behind.)";
|
|
317
|
+
var HERMES_RESTART_HINT = "Restart any running Hermes CLI or gateway process to load the registered hooks; Hermes registers shell hooks only at process startup.";
|
|
318
|
+
var HERMES_ALLOWLIST_ACTION_HINT = "Next action [hermes-hook-allowlist]: run `hermes --accept-hooks chat`; after Hermes starts, exit the chat and rerun `ctxdb setup --agent hermes`, then restart any running Hermes CLI or gateway process.";
|
|
319
|
+
var HERMES_WEBUI_GATEWAY_HINT = "Using hermes-webui? Its default legacy backend does not load Hermes shell hooks. Set `HERMES_WEBUI_CHAT_BACKEND=gateway` to route chat through Hermes Gateway; if the gateway requires authentication, also set `HERMES_WEBUI_GATEWAY_API_KEY`, then restart hermes-webui. Reference: https://github.com/nesquena/hermes-webui/blob/master/docs/advanced-chat-setup.md#gateway-backed-browser-chat";
|
|
320
|
+
var NO_AGENTS_DETECTED_HINT = "No setup-compatible Agent detected. Install or start a supported Agent once, then rerun `ctxdb setup --all`; use `ctxdb setup --agent <name>` to target one explicitly.";
|
|
251
321
|
function skillInstallRoot(agent) {
|
|
252
322
|
switch (agent) {
|
|
253
323
|
case "qoder":
|
|
@@ -579,8 +649,13 @@ async function runSetup(options) {
|
|
|
579
649
|
}
|
|
580
650
|
}
|
|
581
651
|
}
|
|
582
|
-
const
|
|
652
|
+
const failedSteps = steps.filter((s) => !s.ok);
|
|
653
|
+
const ok = failedSteps.length === 0;
|
|
654
|
+
const actionRequired = agent === "hermes" && failedSteps.length === 1 && failedSteps[0]?.step === "check-hermes-hook-allowlist" ? "hermes-hook-allowlist" : void 0;
|
|
583
655
|
const hints = ok ? [UNINSTALL_ORDER_HINT] : [];
|
|
656
|
+
if (actionRequired) {
|
|
657
|
+
hints.unshift(HERMES_ALLOWLIST_ACTION_HINT, HERMES_WEBUI_GATEWAY_HINT);
|
|
658
|
+
}
|
|
584
659
|
if (ok && agent === "opencode") {
|
|
585
660
|
hints.unshift(
|
|
586
661
|
`OpenCode plugin shim: ${opencodeShimPath()}`,
|
|
@@ -589,10 +664,98 @@ async function runSetup(options) {
|
|
|
589
664
|
}
|
|
590
665
|
if (ok && agent === "hermes") {
|
|
591
666
|
hints.unshift(
|
|
592
|
-
`Hermes shell hooks: ${hermesConfigPath()} \u2192 pre_llm_call + post_llm_call
|
|
667
|
+
`Hermes shell hooks: ${hermesConfigPath()} \u2192 pre_llm_call + post_llm_call`,
|
|
668
|
+
HERMES_RESTART_HINT,
|
|
669
|
+
HERMES_WEBUI_GATEWAY_HINT
|
|
593
670
|
);
|
|
594
671
|
}
|
|
595
|
-
return {
|
|
672
|
+
return {
|
|
673
|
+
ok,
|
|
674
|
+
steps,
|
|
675
|
+
actionRequired,
|
|
676
|
+
hints: hints.length > 0 ? hints : void 0
|
|
677
|
+
};
|
|
678
|
+
}
|
|
679
|
+
function skippedFromDetection(detection) {
|
|
680
|
+
return detection.observations.filter((item) => !item.selected).map((item) => ({
|
|
681
|
+
agent: item.agent,
|
|
682
|
+
reason: item.reason,
|
|
683
|
+
evidence: item.evidence,
|
|
684
|
+
...item.detail ? { detail: item.detail } : {}
|
|
685
|
+
}));
|
|
686
|
+
}
|
|
687
|
+
function withoutSharedUninstallHint(result) {
|
|
688
|
+
const hints = result.hints?.filter((hint) => hint !== UNINSTALL_ORDER_HINT);
|
|
689
|
+
return {
|
|
690
|
+
...result,
|
|
691
|
+
...hints && hints.length > 0 ? { hints } : { hints: void 0 }
|
|
692
|
+
};
|
|
693
|
+
}
|
|
694
|
+
function missingApiKeyResult(agent) {
|
|
695
|
+
return {
|
|
696
|
+
ok: false,
|
|
697
|
+
steps: [{
|
|
698
|
+
step: "write-config",
|
|
699
|
+
ok: false,
|
|
700
|
+
detail: `${agent}: --api-key is required (won't write config without a valid API key)`
|
|
701
|
+
}]
|
|
702
|
+
};
|
|
703
|
+
}
|
|
704
|
+
async function runSetupAll(options = {}, dependencies = {}) {
|
|
705
|
+
const detect = dependencies.detect ?? detectInstalledAgents;
|
|
706
|
+
const loadConfig = dependencies.loadConfig ?? ((agent) => load({ agent }));
|
|
707
|
+
const setup2 = dependencies.setup ?? runSetup;
|
|
708
|
+
const detection = detect(options.detection);
|
|
709
|
+
const agents = {};
|
|
710
|
+
if (detection.selected.length === 0) {
|
|
711
|
+
return {
|
|
712
|
+
ok: false,
|
|
713
|
+
operation: "setup",
|
|
714
|
+
mode: "all",
|
|
715
|
+
agents,
|
|
716
|
+
skipped: skippedFromDetection(detection),
|
|
717
|
+
summary: { selected: 0, succeeded: 0, failed: 0, skipped: detection.observations.length },
|
|
718
|
+
hints: [NO_AGENTS_DETECTED_HINT]
|
|
719
|
+
};
|
|
720
|
+
}
|
|
721
|
+
const configSnapshot = /* @__PURE__ */ new Map();
|
|
722
|
+
for (const agent of detection.selected) {
|
|
723
|
+
configSnapshot.set(agent, loadConfig(agent));
|
|
724
|
+
}
|
|
725
|
+
for (const agent of detection.selected) {
|
|
726
|
+
const existing = configSnapshot.get(agent);
|
|
727
|
+
const apiKey = options.apiKey ?? existing.apiKey;
|
|
728
|
+
if (!apiKey) {
|
|
729
|
+
agents[agent] = missingApiKeyResult(agent);
|
|
730
|
+
continue;
|
|
731
|
+
}
|
|
732
|
+
agents[agent] = withoutSharedUninstallHint(await setup2({
|
|
733
|
+
agent,
|
|
734
|
+
apiKey,
|
|
735
|
+
baseUrl: options.baseUrl ?? existing.baseUrl,
|
|
736
|
+
userId: options.userId ?? existing.userId,
|
|
737
|
+
installSkill: options.installSkill,
|
|
738
|
+
validate: options.validate
|
|
739
|
+
}));
|
|
740
|
+
}
|
|
741
|
+
const results = Object.values(agents);
|
|
742
|
+
const succeeded = results.filter((result) => result.ok).length;
|
|
743
|
+
const failed = results.length - succeeded;
|
|
744
|
+
const skipped = skippedFromDetection(detection);
|
|
745
|
+
return {
|
|
746
|
+
ok: failed === 0,
|
|
747
|
+
operation: "setup",
|
|
748
|
+
mode: "all",
|
|
749
|
+
agents,
|
|
750
|
+
skipped,
|
|
751
|
+
summary: {
|
|
752
|
+
selected: results.length,
|
|
753
|
+
succeeded,
|
|
754
|
+
failed,
|
|
755
|
+
skipped: skipped.length
|
|
756
|
+
},
|
|
757
|
+
hints: [UNINSTALL_ORDER_HINT]
|
|
758
|
+
};
|
|
596
759
|
}
|
|
597
760
|
function runRemove(agent, options = {}) {
|
|
598
761
|
const steps = [];
|
|
@@ -794,11 +957,12 @@ function runRemove(agent, options = {}) {
|
|
|
794
957
|
return { ok: steps.every((s) => s.ok), steps };
|
|
795
958
|
}
|
|
796
959
|
function checkAgentHome(agent) {
|
|
797
|
-
|
|
960
|
+
const platform = agentPlatformSupport(agent);
|
|
961
|
+
if (!platform.supported) {
|
|
798
962
|
return {
|
|
799
963
|
step: "check-agent-home",
|
|
800
964
|
ok: false,
|
|
801
|
-
detail:
|
|
965
|
+
detail: platform.detail
|
|
802
966
|
};
|
|
803
967
|
}
|
|
804
968
|
if (agent === "opencode" || agent === "hermes") {
|
|
@@ -814,7 +978,7 @@ function checkAgentHome(agent) {
|
|
|
814
978
|
};
|
|
815
979
|
}
|
|
816
980
|
}
|
|
817
|
-
const dirs =
|
|
981
|
+
const dirs = inspectAgentHomes(agent).existing;
|
|
818
982
|
if (dirs.length === 0) {
|
|
819
983
|
const primary = agentHomeDir(agent);
|
|
820
984
|
return {
|
|
@@ -845,23 +1009,27 @@ function runTeardown(options = {}) {
|
|
|
845
1009
|
}
|
|
846
1010
|
if (purgeConfig) {
|
|
847
1011
|
const cfgPath = join(homedir(), ".ctxdb", "ctxdb.json");
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
steps.push({ step: "purge-config", ok: true, detail: cfgPath });
|
|
852
|
-
} catch (err) {
|
|
853
|
-
steps.push({
|
|
854
|
-
step: "purge-config",
|
|
855
|
-
ok: false,
|
|
856
|
-
detail: `${cfgPath}: ${err?.message ?? String(err)}`
|
|
857
|
-
});
|
|
858
|
-
}
|
|
859
|
-
} else {
|
|
1012
|
+
const ownedConfigFiles = [cfgPath, `${cfgPath}.bak`];
|
|
1013
|
+
const existing = ownedConfigFiles.filter((path) => existsSync(path));
|
|
1014
|
+
if (existing.length === 0) {
|
|
860
1015
|
steps.push({
|
|
861
1016
|
step: "purge-config",
|
|
862
1017
|
ok: true,
|
|
863
1018
|
detail: `nothing to remove (${cfgPath})`
|
|
864
1019
|
});
|
|
1020
|
+
} else {
|
|
1021
|
+
for (const path of existing) {
|
|
1022
|
+
try {
|
|
1023
|
+
unlinkSync(path);
|
|
1024
|
+
steps.push({ step: "purge-config", ok: true, detail: path });
|
|
1025
|
+
} catch (err) {
|
|
1026
|
+
steps.push({
|
|
1027
|
+
step: "purge-config",
|
|
1028
|
+
ok: false,
|
|
1029
|
+
detail: `${path}: ${err?.message ?? String(err)}`
|
|
1030
|
+
});
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
865
1033
|
}
|
|
866
1034
|
}
|
|
867
1035
|
if (purgeLogs) {
|
|
@@ -1356,8 +1524,8 @@ function hermesAllowlistPath() {
|
|
|
1356
1524
|
return join(dirname(hermesConfigPath()), HERMES_ALLOWLIST_FILENAME);
|
|
1357
1525
|
}
|
|
1358
1526
|
function hermesHookApprovalHint(events = HERMES_HOOK_EVENTS) {
|
|
1359
|
-
const hookNames = events.
|
|
1360
|
-
return `Approve the Hermes ctxdb hooks ${hookNames}: run \`hermes --accept-hooks chat\` once. This command opens an interactive chat; after Hermes starts, exit the chat,
|
|
1527
|
+
const hookNames = events.join(" and ");
|
|
1528
|
+
return `Approve the Hermes ctxdb hooks ${hookNames}: run \`hermes --accept-hooks chat\` once. This command opens an interactive chat; after Hermes starts, exit the chat, rerun \`ctxdb setup --agent hermes\`, then restart any running Hermes CLI or gateway process.`;
|
|
1361
1529
|
}
|
|
1362
1530
|
function backupHermesConfig() {
|
|
1363
1531
|
backupSettingsFile(hermesConfigPath());
|
|
@@ -1806,8 +1974,17 @@ async function runUpgrade(options = {}) {
|
|
|
1806
1974
|
}
|
|
1807
1975
|
|
|
1808
1976
|
// src/cli/top.ts
|
|
1809
|
-
|
|
1810
|
-
|
|
1977
|
+
var STATUS_HELP = `ctxdb status \u2014 inspect configuration and connectivity
|
|
1978
|
+
|
|
1979
|
+
USAGE
|
|
1980
|
+
ctxdb status [--agent <qoder|qoderwork|codex|claude|opencode|hermes|default> | --all] [--json]
|
|
1981
|
+
|
|
1982
|
+
FLAGS
|
|
1983
|
+
--agent <name> Inspect exactly one Agent profile
|
|
1984
|
+
--all Inspect every setup-compatible detected built-in Agent
|
|
1985
|
+
--json Machine-readable output
|
|
1986
|
+
`;
|
|
1987
|
+
async function inspectStatus(agent) {
|
|
1811
1988
|
const cfg = load({ agent });
|
|
1812
1989
|
const complete = isComplete(cfg);
|
|
1813
1990
|
let connected = false;
|
|
@@ -1822,8 +1999,8 @@ async function status(args) {
|
|
|
1822
1999
|
}
|
|
1823
2000
|
}
|
|
1824
2001
|
const hookHealth = isBuiltinAgent(agent) ? checkHookNodePaths(agent) : { installed: false, nodePaths: [], nodeOk: true, detail: "no hooks (default agent)" };
|
|
1825
|
-
|
|
1826
|
-
{
|
|
2002
|
+
return {
|
|
2003
|
+
result: {
|
|
1827
2004
|
ok: complete,
|
|
1828
2005
|
agent,
|
|
1829
2006
|
base_url: cfg.baseUrl,
|
|
@@ -1840,9 +2017,69 @@ async function status(args) {
|
|
|
1840
2017
|
hooks_node_ok: hookHealth.nodeOk,
|
|
1841
2018
|
version: PACKAGE_VERSION
|
|
1842
2019
|
},
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
2020
|
+
success: complete && connected
|
|
2021
|
+
};
|
|
2022
|
+
}
|
|
2023
|
+
function statusSkips(detection) {
|
|
2024
|
+
return {
|
|
2025
|
+
selected: detection.selected,
|
|
2026
|
+
skipped: detection.observations.filter((item) => !item.selected).map((item) => ({
|
|
2027
|
+
agent: item.agent,
|
|
2028
|
+
reason: item.reason,
|
|
2029
|
+
evidence: item.evidence,
|
|
2030
|
+
...item.detail ? { detail: item.detail } : {}
|
|
2031
|
+
}))
|
|
2032
|
+
};
|
|
2033
|
+
}
|
|
2034
|
+
async function statusAll(dependencies = {}) {
|
|
2035
|
+
const detection = statusSkips((dependencies.detect ?? detectInstalledAgents)());
|
|
2036
|
+
const inspect = dependencies.inspect ?? inspectStatus;
|
|
2037
|
+
const agents = {};
|
|
2038
|
+
let succeeded = 0;
|
|
2039
|
+
for (const agent of detection.selected) {
|
|
2040
|
+
const inspection = await inspect(agent);
|
|
2041
|
+
agents[agent] = inspection.result;
|
|
2042
|
+
if (inspection.success) succeeded += 1;
|
|
2043
|
+
}
|
|
2044
|
+
const failed = detection.selected.length - succeeded;
|
|
2045
|
+
return {
|
|
2046
|
+
ok: detection.selected.length > 0 && failed === 0,
|
|
2047
|
+
operation: "status",
|
|
2048
|
+
mode: "all",
|
|
2049
|
+
agents,
|
|
2050
|
+
skipped: detection.skipped,
|
|
2051
|
+
summary: {
|
|
2052
|
+
selected: detection.selected.length,
|
|
2053
|
+
succeeded,
|
|
2054
|
+
failed,
|
|
2055
|
+
skipped: detection.skipped.length
|
|
2056
|
+
},
|
|
2057
|
+
...detection.selected.length === 0 ? { hints: ["No setup-compatible Agent detected. Install or start one, then rerun `ctxdb status --all`."] } : {}
|
|
2058
|
+
};
|
|
2059
|
+
}
|
|
2060
|
+
async function status(args) {
|
|
2061
|
+
if (args.flags.help || args.flags.h) {
|
|
2062
|
+
process.stdout.write(STATUS_HELP);
|
|
2063
|
+
return 0;
|
|
2064
|
+
}
|
|
2065
|
+
if (args.flags.all === true) {
|
|
2066
|
+
if (args.flags.agent !== void 0) {
|
|
2067
|
+
process.stderr.write("cannot use --all and --agent together\n");
|
|
2068
|
+
return 2;
|
|
2069
|
+
}
|
|
2070
|
+
const result = await statusAll();
|
|
2071
|
+
printResult(result, !!args.flags.json);
|
|
2072
|
+
if (!args.flags.json && result.hints) {
|
|
2073
|
+
for (const hint of result.hints) process.stderr.write(`
|
|
2074
|
+
${hint}
|
|
2075
|
+
`);
|
|
2076
|
+
}
|
|
2077
|
+
return result.ok ? 0 : 1;
|
|
2078
|
+
}
|
|
2079
|
+
const agent = agentFromFlags(args.flags);
|
|
2080
|
+
const inspection = await inspectStatus(agent);
|
|
2081
|
+
printResult(inspection.result, !!args.flags.json);
|
|
2082
|
+
return inspection.success ? 0 : 1;
|
|
1846
2083
|
}
|
|
1847
2084
|
async function ping(args) {
|
|
1848
2085
|
const agent = agentFromFlags(args.flags);
|
|
@@ -1862,7 +2099,7 @@ async function ping(args) {
|
|
|
1862
2099
|
var HELP = `ctxdb setup \u2014 configure an agent
|
|
1863
2100
|
|
|
1864
2101
|
USAGE
|
|
1865
|
-
ctxdb setup [--agent <qoder|qoderwork|codex|claude|opencode|hermes>]
|
|
2102
|
+
ctxdb setup [--agent <qoder|qoderwork|codex|claude|opencode|hermes> | --all]
|
|
1866
2103
|
[--api-key=K] [--base-url=URL] [--user-id=ID]
|
|
1867
2104
|
[--no-install-skill] [--no-validate] [--json]
|
|
1868
2105
|
|
|
@@ -1871,13 +2108,20 @@ BEHAVIOR
|
|
|
1871
2108
|
no hooks or skills installed).
|
|
1872
2109
|
With --agent Writes agent config + installs hooks + skills for the
|
|
1873
2110
|
specified agent harness.
|
|
2111
|
+
Rerun for a new Agent, to repair integration files, or
|
|
2112
|
+
with --api-key <new-key> to replace that Agent's key.
|
|
2113
|
+
With --all Detects setup-compatible Agents on this host and runs the
|
|
2114
|
+
same setup lifecycle sequentially for each one. Successful
|
|
2115
|
+
Agents are preserved when another Agent fails.
|
|
1874
2116
|
Hermes Also verifies ~/.hermes/shell-hooks-allowlist.json.
|
|
1875
2117
|
Approve pre_llm_call + post_llm_call with
|
|
1876
2118
|
\`hermes --accept-hooks chat\`. It opens interactive chat;
|
|
1877
|
-
exit after Hermes starts,
|
|
2119
|
+
exit after Hermes starts, rerun ctxdb setup, then restart
|
|
2120
|
+
any running Hermes CLI/gateway process to load the hooks.
|
|
1878
2121
|
|
|
1879
2122
|
FLAGS
|
|
1880
2123
|
--agent <name> Target agent (qoder|qoderwork|codex|claude|opencode|hermes)
|
|
2124
|
+
--all Target every setup-compatible detected Agent
|
|
1881
2125
|
--api-key <key> API key (required on first setup)
|
|
1882
2126
|
--base-url <url> Server URL (default: https://context-database.aliyuncs.com)
|
|
1883
2127
|
--user-id <id> User bucket (default: "default")
|
|
@@ -1885,6 +2129,10 @@ FLAGS
|
|
|
1885
2129
|
--no-validate Skip connectivity ping after setup
|
|
1886
2130
|
--json Machine-readable JSON output
|
|
1887
2131
|
`;
|
|
2132
|
+
var CODEX_HOOKS_TRUST_REMINDER = [
|
|
2133
|
+
"codex hooks \u914D\u7F6E\u540E\uFF0C\u9700\u8981\u91CD\u542F Codex \u5BF9\u8BDD\uFF0C\u5728\u5F39\u51FA\u7684 hooks \u786E\u8BA4\u754C\u9762\u9009\u62E9`\u63A5\u6536\u6240\u6709 hooks(\u94A9\u5B50)`\u9009\u9879\u3002",
|
|
2134
|
+
"\u5982\u679C\u4F7F\u7528\u7684\u662F Codex App \u684C\u9762\u7248\uFF0C\u64CD\u4F5C\u8DEF\u5F84\u662F\uFF1A\u5DE6\u4E0B\u89D2\u70B9\u51FB\u7528\u6237\u540D \u2192 \u70B9\u51FB\u8BBE\u7F6E \u2192 \u70B9\u51FB\u4FA7\u8FB9\u680F\u7684 `Hooks\uFF08\u94A9\u5B50\uFF09`\u2192 \u70B9\u51FB`\u7528\u6237\u914D\u7F6E`\uFF0C\u4FE1\u4EFB `UserPromptSubmit`\u3001`SessionStart` \u548C `Stop` \u91CC\u7684 `aliyunrds/ctxdb` \u94A9\u5B50\u3002"
|
|
2135
|
+
].join("\n");
|
|
1888
2136
|
function parseAgent(args) {
|
|
1889
2137
|
const raw = args.flags.agent;
|
|
1890
2138
|
if (raw === void 0) return "default";
|
|
@@ -1900,8 +2148,38 @@ async function setup(args) {
|
|
|
1900
2148
|
process.stdout.write(HELP);
|
|
1901
2149
|
return 0;
|
|
1902
2150
|
}
|
|
1903
|
-
const agent = parseAgent(args);
|
|
1904
2151
|
const json = !!args.flags.json;
|
|
2152
|
+
const all = args.flags.all === true;
|
|
2153
|
+
if (all && args.flags.agent !== void 0) {
|
|
2154
|
+
process.stderr.write("cannot use --all and --agent together\n");
|
|
2155
|
+
return 2;
|
|
2156
|
+
}
|
|
2157
|
+
if (all) {
|
|
2158
|
+
const result2 = await runSetupAll({
|
|
2159
|
+
apiKey: typeof args.flags["api-key"] === "string" ? args.flags["api-key"] : void 0,
|
|
2160
|
+
baseUrl: typeof args.flags["base-url"] === "string" ? args.flags["base-url"] : void 0,
|
|
2161
|
+
userId: typeof args.flags["user-id"] === "string" ? args.flags["user-id"] : void 0,
|
|
2162
|
+
installSkill: !args.flags["no-install-skill"],
|
|
2163
|
+
validate: !args.flags["no-validate"]
|
|
2164
|
+
});
|
|
2165
|
+
printResult(result2, json);
|
|
2166
|
+
if (!json && result2.hints) {
|
|
2167
|
+
for (const hint of result2.hints) {
|
|
2168
|
+
process.stderr.write(`
|
|
2169
|
+
${highlightInlineCode(hint)}
|
|
2170
|
+
`);
|
|
2171
|
+
}
|
|
2172
|
+
}
|
|
2173
|
+
if (!json && result2.agents.codex?.ok) {
|
|
2174
|
+
process.stderr.write(
|
|
2175
|
+
`
|
|
2176
|
+
${dim(CODEX_HOOKS_TRUST_REMINDER)}
|
|
2177
|
+
`
|
|
2178
|
+
);
|
|
2179
|
+
}
|
|
2180
|
+
return result2.ok ? 0 : 1;
|
|
2181
|
+
}
|
|
2182
|
+
const agent = parseAgent(args);
|
|
1905
2183
|
if (agent === "default" && !json && !configuredAgents().includes("default")) {
|
|
1906
2184
|
process.stderr.write(
|
|
1907
2185
|
`hint: creating CLI-only "default" agent (no hooks/skills). Use --agent <claude|qoder|qoderwork|codex|opencode|hermes> for full setup.
|
|
@@ -1918,14 +2196,16 @@ async function setup(args) {
|
|
|
1918
2196
|
});
|
|
1919
2197
|
printResult(result, json);
|
|
1920
2198
|
if (!json && result.hints) {
|
|
1921
|
-
for (const h of result.hints)
|
|
1922
|
-
|
|
2199
|
+
for (const h of result.hints) {
|
|
2200
|
+
process.stderr.write(`
|
|
2201
|
+
${highlightInlineCode(h)}
|
|
1923
2202
|
`);
|
|
2203
|
+
}
|
|
1924
2204
|
}
|
|
1925
2205
|
if (!json && agent === "codex" && result.ok) {
|
|
1926
2206
|
process.stderr.write(
|
|
1927
2207
|
`
|
|
1928
|
-
${dim(
|
|
2208
|
+
${dim(CODEX_HOOKS_TRUST_REMINDER)}
|
|
1929
2209
|
`
|
|
1930
2210
|
);
|
|
1931
2211
|
}
|
|
@@ -1996,118 +2276,6 @@ ${h}
|
|
|
1996
2276
|
return result.ok ? 0 : 1;
|
|
1997
2277
|
}
|
|
1998
2278
|
|
|
1999
|
-
// src/lib/self-update.ts
|
|
2000
|
-
import { spawnSync } from "child_process";
|
|
2001
|
-
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
2002
|
-
import { dirname as dirname2 } from "path";
|
|
2003
|
-
import semver from "semver";
|
|
2004
|
-
var PACKAGE_NAME = "@aliyunrds/ctxdb";
|
|
2005
|
-
var NPM_VIEW_TIMEOUT_MS = 1e4;
|
|
2006
|
-
function npmCommand(platform = process.platform) {
|
|
2007
|
-
return platform === "win32" ? "npm.cmd" : "npm";
|
|
2008
|
-
}
|
|
2009
|
-
function ctxdbCommand(platform = process.platform) {
|
|
2010
|
-
return platform === "win32" ? "ctxdb.cmd" : "ctxdb";
|
|
2011
|
-
}
|
|
2012
|
-
function detectInstallMethod() {
|
|
2013
|
-
const dir = dirname2(fileURLToPath2(import.meta.url));
|
|
2014
|
-
return dir.includes("/node_modules/") || dir.includes("\\node_modules\\") ? "npm" : "unknown";
|
|
2015
|
-
}
|
|
2016
|
-
function checkLatestVersion(currentVersion) {
|
|
2017
|
-
const result = spawnSync(npmCommand(), ["view", PACKAGE_NAME, "version"], {
|
|
2018
|
-
encoding: "utf-8",
|
|
2019
|
-
timeout: NPM_VIEW_TIMEOUT_MS,
|
|
2020
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
2021
|
-
shell: process.platform === "win32"
|
|
2022
|
-
});
|
|
2023
|
-
if (result.status !== 0 || !result.stdout?.trim()) {
|
|
2024
|
-
return {
|
|
2025
|
-
latest: null,
|
|
2026
|
-
current: currentVersion,
|
|
2027
|
-
isNewer: false,
|
|
2028
|
-
error: spawnFailureMessage(result, "npm view")
|
|
2029
|
-
};
|
|
2030
|
-
}
|
|
2031
|
-
const latest = result.stdout.trim();
|
|
2032
|
-
return {
|
|
2033
|
-
latest,
|
|
2034
|
-
current: currentVersion,
|
|
2035
|
-
isNewer: isNewerVersion(latest, currentVersion)
|
|
2036
|
-
};
|
|
2037
|
-
}
|
|
2038
|
-
function spawnFailureMessage(result, commandLabel) {
|
|
2039
|
-
const stderr = result.stderr?.toString().trim();
|
|
2040
|
-
if (stderr) return stderr;
|
|
2041
|
-
if (result.error) return `${commandLabel} failed: ${result.error.message}`;
|
|
2042
|
-
if (result.signal) return `${commandLabel} terminated by signal ${result.signal}`;
|
|
2043
|
-
return `${commandLabel} exited with code ${result.status}`;
|
|
2044
|
-
}
|
|
2045
|
-
function isNewerVersion(candidate, current) {
|
|
2046
|
-
const candidateVersion = semver.valid(candidate);
|
|
2047
|
-
const currentVersion = semver.valid(current);
|
|
2048
|
-
return Boolean(
|
|
2049
|
-
candidateVersion && currentVersion && semver.gt(candidateVersion, currentVersion)
|
|
2050
|
-
);
|
|
2051
|
-
}
|
|
2052
|
-
function runSelfUpdate(currentVersion, passthroughArgs = [], options = {}) {
|
|
2053
|
-
const method = options.installMethod ?? detectInstallMethod();
|
|
2054
|
-
if (method !== "npm") {
|
|
2055
|
-
return {
|
|
2056
|
-
ok: false,
|
|
2057
|
-
updated: false,
|
|
2058
|
-
fromVersion: currentVersion,
|
|
2059
|
-
error: "ctxdb was not installed via npm. Update manually with your package manager."
|
|
2060
|
-
};
|
|
2061
|
-
}
|
|
2062
|
-
const check = checkLatestVersion(currentVersion);
|
|
2063
|
-
if (check.error) {
|
|
2064
|
-
return {
|
|
2065
|
-
ok: false,
|
|
2066
|
-
updated: false,
|
|
2067
|
-
fromVersion: currentVersion,
|
|
2068
|
-
error: `npm view failed: ${check.error}`
|
|
2069
|
-
};
|
|
2070
|
-
}
|
|
2071
|
-
if (!check.isNewer) {
|
|
2072
|
-
process.stderr.write(
|
|
2073
|
-
`ctxdb: package already up to date (current v${currentVersion}, latest v${check.latest})
|
|
2074
|
-
`
|
|
2075
|
-
);
|
|
2076
|
-
return { ok: true, updated: false, fromVersion: currentVersion };
|
|
2077
|
-
}
|
|
2078
|
-
process.stderr.write(`ctxdb: updating ${PACKAGE_NAME} v${currentVersion} \u2192 v${check.latest}...
|
|
2079
|
-
`);
|
|
2080
|
-
const install = spawnSync(npmCommand(), ["install", "-g", `${PACKAGE_NAME}@${check.latest}`], {
|
|
2081
|
-
stdio: "inherit",
|
|
2082
|
-
encoding: "utf-8",
|
|
2083
|
-
shell: process.platform === "win32"
|
|
2084
|
-
});
|
|
2085
|
-
if (install.status !== 0) {
|
|
2086
|
-
return {
|
|
2087
|
-
ok: false,
|
|
2088
|
-
updated: false,
|
|
2089
|
-
fromVersion: currentVersion,
|
|
2090
|
-
error: spawnFailureMessage(install, "npm install -g")
|
|
2091
|
-
};
|
|
2092
|
-
}
|
|
2093
|
-
process.stderr.write(`ctxdb: package updated to v${check.latest}, running setup...
|
|
2094
|
-
`);
|
|
2095
|
-
const setupArgs = ["update", "--no-self-update", ...passthroughArgs];
|
|
2096
|
-
const refresh = spawnSync(ctxdbCommand(), setupArgs, {
|
|
2097
|
-
stdio: "inherit",
|
|
2098
|
-
encoding: "utf-8",
|
|
2099
|
-
shell: process.platform === "win32"
|
|
2100
|
-
});
|
|
2101
|
-
return {
|
|
2102
|
-
ok: refresh.status === 0,
|
|
2103
|
-
updated: true,
|
|
2104
|
-
fromVersion: currentVersion,
|
|
2105
|
-
toVersion: check.latest,
|
|
2106
|
-
error: refresh.status !== 0 ? spawnFailureMessage(refresh, "ctxdb setup") : void 0,
|
|
2107
|
-
failureHandled: refresh.status !== null && refresh.status !== 0
|
|
2108
|
-
};
|
|
2109
|
-
}
|
|
2110
|
-
|
|
2111
2279
|
// src/cli/upgrade.ts
|
|
2112
2280
|
var HELP3 = `ctxdb upgrade \u2014 refresh skills + hooks
|
|
2113
2281
|
|
|
@@ -2396,18 +2564,28 @@ function parseMetadataFlags(raw) {
|
|
|
2396
2564
|
}
|
|
2397
2565
|
|
|
2398
2566
|
// src/cli/kb-cli.ts
|
|
2567
|
+
var UPLOAD_TEXT_USAGE = "usage: ctxdb kb upload-text <kb-name> <doc-name> --text=<body> [--file-path=<server-logical-path>] [--wait|--no-wait]";
|
|
2568
|
+
var UPLOAD_FILE_USAGE = "usage: ctxdb kb upload-file <kb-name> <local-path> [--doc-name=...] [--file-path=<server-logical-path>] [--wait|--no-wait]";
|
|
2569
|
+
function shouldWaitForIngest(args, usage) {
|
|
2570
|
+
const waitRequested = args.flags.wait !== void 0;
|
|
2571
|
+
const noWaitRequested = args.flags["no-wait"] !== void 0;
|
|
2572
|
+
if (waitRequested && noWaitRequested) {
|
|
2573
|
+
fail(`cannot use --wait and --no-wait together
|
|
2574
|
+
${usage}`, 2);
|
|
2575
|
+
}
|
|
2576
|
+
return waitRequested;
|
|
2577
|
+
}
|
|
2399
2578
|
async function kbUploadText(args) {
|
|
2579
|
+
const shouldWait = shouldWaitForIngest(args, UPLOAD_TEXT_USAGE);
|
|
2400
2580
|
const [kbName, docName] = args.positional;
|
|
2401
2581
|
const text = args.flags["text"];
|
|
2402
2582
|
if (!kbName || !docName || typeof text !== "string") {
|
|
2403
|
-
fail(
|
|
2404
|
-
"usage: ctxdb kb upload-text <kb-name> <doc-name> --text=<body> [--file-path=<server-logical-path>] [--no-wait]"
|
|
2405
|
-
);
|
|
2583
|
+
fail(UPLOAD_TEXT_USAGE);
|
|
2406
2584
|
}
|
|
2407
2585
|
const ctx = buildContext(args);
|
|
2408
2586
|
const filePath = typeof args.flags["file-path"] === "string" ? args.flags["file-path"] : void 0;
|
|
2409
2587
|
const doc = await uploadText(ctx.client, kbName, docName, text, "text/plain", filePath);
|
|
2410
|
-
if (
|
|
2588
|
+
if (!shouldWait) {
|
|
2411
2589
|
printResult({ document: doc }, !!args.flags.json);
|
|
2412
2590
|
return 0;
|
|
2413
2591
|
}
|
|
@@ -2418,19 +2596,18 @@ async function kbUploadText(args) {
|
|
|
2418
2596
|
return 0;
|
|
2419
2597
|
}
|
|
2420
2598
|
async function kbUploadFile(args) {
|
|
2599
|
+
const shouldWait = shouldWaitForIngest(args, UPLOAD_FILE_USAGE);
|
|
2421
2600
|
const [kbName, localPath] = args.positional;
|
|
2422
2601
|
if (!kbName || !localPath) {
|
|
2423
|
-
fail(
|
|
2424
|
-
"usage: ctxdb kb upload-file <kb-name> <local-path> [--doc-name=...] [--file-path=<server-logical-path>] [--no-wait]"
|
|
2425
|
-
);
|
|
2602
|
+
fail(UPLOAD_FILE_USAGE);
|
|
2426
2603
|
}
|
|
2427
2604
|
const ctx = buildContext(args);
|
|
2428
2605
|
const doc = await uploadFile(ctx.client, kbName, localPath, {
|
|
2429
2606
|
docName: typeof args.flags["doc-name"] === "string" ? args.flags["doc-name"] : void 0,
|
|
2430
2607
|
filePath: typeof args.flags["file-path"] === "string" ? args.flags["file-path"] : void 0,
|
|
2431
|
-
timeoutMs:
|
|
2608
|
+
timeoutMs: DEFAULT_FILE_UPLOAD_TIMEOUT_MS
|
|
2432
2609
|
});
|
|
2433
|
-
if (
|
|
2610
|
+
if (!shouldWait) {
|
|
2434
2611
|
printResult({ document: doc }, !!args.flags.json);
|
|
2435
2612
|
return 0;
|
|
2436
2613
|
}
|
|
@@ -2510,7 +2687,7 @@ USAGE
|
|
|
2510
2687
|
ctxdb <command> [args] [--flags]
|
|
2511
2688
|
|
|
2512
2689
|
COMMANDS
|
|
2513
|
-
setup [--agent <qoder|qoderwork|codex|claude|opencode|hermes>]
|
|
2690
|
+
setup [--agent <qoder|qoderwork|codex|claude|opencode|hermes> | --all]
|
|
2514
2691
|
[--api-key=K] [--base-url=URL] [--user-id=ID]
|
|
2515
2692
|
[--no-install-skill] [--no-validate] [--json]
|
|
2516
2693
|
Without --agent \u2192 writes agents.default (CLI-only, no hooks/skills)
|
|
@@ -2521,8 +2698,12 @@ COMMANDS
|
|
|
2521
2698
|
OpenCode \u2192 writes agents.opencode config + ~/.config/opencode/plugins/ctxdb.ts shim + skill
|
|
2522
2699
|
Hermes \u2192 writes agents.hermes config + ~/.hermes/config.yaml pre/post_llm_call hooks + skill
|
|
2523
2700
|
Approve pre_llm_call + post_llm_call with \`hermes --accept-hooks chat\`
|
|
2524
|
-
(
|
|
2525
|
-
|
|
2701
|
+
(exit chat, rerun setup, then restart any running Hermes CLI/gateway)
|
|
2702
|
+
--all \u2192 detects and configures every setup-compatible built-in Agent
|
|
2703
|
+
status [--agent <name> | --all] [--json]
|
|
2704
|
+
Inspect configuration, connectivity, and integration health.
|
|
2705
|
+
--all inspects the same detected Agent set as setup --all.
|
|
2706
|
+
Rerun setup to add/repair an Agent or replace its API key.
|
|
2526
2707
|
ping [--agent <name>] [--json]
|
|
2527
2708
|
uninstall [--agent <name>] [--purge-config] [--purge-logs] [--purge-all] [--json]
|
|
2528
2709
|
teardown (alias for uninstall)
|
|
@@ -2551,9 +2732,12 @@ COMMANDS
|
|
|
2551
2732
|
|
|
2552
2733
|
kb create <kb-name> [--description=<desc>] [--agent=<name>]
|
|
2553
2734
|
kb upload-text <kb-name> <doc-name> --text=<body> [--agent=<name>]
|
|
2554
|
-
[--file-path=<server-logical-path>] [--no-wait]
|
|
2735
|
+
[--file-path=<server-logical-path>] [--wait|--no-wait]
|
|
2555
2736
|
kb upload-file <kb-name> <local-path> [--agent=<name>] [--doc-name=...]
|
|
2556
|
-
[--file-path=<server-logical-path>] [--no-wait]
|
|
2737
|
+
[--file-path=<server-logical-path>] [--wait|--no-wait]
|
|
2738
|
+
Uploads return immediately by default.
|
|
2739
|
+
--wait polls for terminal ingest status.
|
|
2740
|
+
--no-wait is a compatibility alias for the default.
|
|
2557
2741
|
kb list [--agent=<name>]
|
|
2558
2742
|
kb documents-list <kb-name> [--agent=<name>]
|
|
2559
2743
|
kb document-get <kb-name> <doc-id> [--agent=<name>]
|
|
@@ -2580,6 +2764,10 @@ ENV VARS (override selected ~/.ctxdb/ctxdb.json agent config):
|
|
|
2580
2764
|
CTXDB_AGENT CTXDB_API_KEY CTXDB_BASE_URL CTXDB_USER_ID
|
|
2581
2765
|
CTXDB_AGENT_ID CTXDB_APP_ID
|
|
2582
2766
|
|
|
2767
|
+
UPDATE CHECK ENV VARS:
|
|
2768
|
+
CTXDB_DISABLE_UPDATE_CHECK=1
|
|
2769
|
+
Disable background version checks and hints.
|
|
2770
|
+
|
|
2583
2771
|
HOOK ENV VARS:
|
|
2584
2772
|
CTXDB_SKIP_HOOKS=TRUE Hook/plugin entrypoints exit immediately.
|
|
2585
2773
|
Direct ctxdb CLI commands are unchanged.
|
|
@@ -2616,7 +2804,7 @@ var ROUTES = {
|
|
|
2616
2804
|
search: kbSearch
|
|
2617
2805
|
}
|
|
2618
2806
|
};
|
|
2619
|
-
async function
|
|
2807
|
+
async function dispatch(argv) {
|
|
2620
2808
|
if (argv.length === 0 || argv[0] === "-h" || argv[0] === "--help") {
|
|
2621
2809
|
process.stdout.write(HELP5);
|
|
2622
2810
|
return 0;
|
|
@@ -2660,6 +2848,15 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
2660
2848
|
}
|
|
2661
2849
|
return Promise.resolve(handler(parseArgs(subRest)));
|
|
2662
2850
|
}
|
|
2851
|
+
async function main(argv = process.argv.slice(2)) {
|
|
2852
|
+
const notification = beginUpdateNotification(argv, {
|
|
2853
|
+
currentVersion: PACKAGE_VERSION,
|
|
2854
|
+
workerPath: fileURLToPath2(new URL("../workers/version-check.js", import.meta.url))
|
|
2855
|
+
});
|
|
2856
|
+
const code = await dispatch(argv);
|
|
2857
|
+
completeUpdateNotification(notification, code);
|
|
2858
|
+
return code;
|
|
2859
|
+
}
|
|
2663
2860
|
main().then(
|
|
2664
2861
|
(code) => {
|
|
2665
2862
|
if (typeof code === "number") process.exitCode = code;
|