@aliyunrds/ctxdb 1.0.9 → 1.0.10-beta.0
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 +36 -2
- package/dist/{chunk-U4DRH4NZ.js → chunk-5HPYYOPH.js} +2 -3
- package/dist/chunk-LASAMQQY.js +259 -0
- package/dist/{chunk-3MEBQDGU.js → chunk-QUPLZ7KF.js} +8 -8
- package/dist/{chunk-FD3IPF6R.js → chunk-SG4LQTOF.js} +4 -4
- package/dist/{chunk-T5ZJEPR4.js → chunk-SZ3AZDMU.js} +5 -5
- package/dist/chunk-TZFDXKLJ.js +3278 -0
- package/dist/{chunk-V7IZ2UYJ.js → chunk-VMBCSFGF.js} +4 -4
- package/dist/{chunk-7TPYIT63.js → chunk-XWJAZAMN.js} +3 -3
- package/dist/cli/main.js +984 -205
- package/dist/hooks/hermes-post-llm-call.js +25 -6
- package/dist/hooks/hermes-pre-llm-call.js +46 -13
- package/dist/hooks/session-end.js +35 -0
- package/dist/hooks/session-start.js +20 -10
- package/dist/hooks/stop.js +15 -5
- package/dist/hooks/user-prompt-submit.js +20 -9
- package/dist/opencode/index.js +22792 -1663
- package/dist/setup/skills/contextdb-skills/SKILL.md +100 -0
- package/dist/workers/version-check.js +3 -3
- package/package.json +10 -1
- package/dist/chunk-2ROMQSPA.js +0 -569
- package/dist/chunk-2U7G6UXE.js +0 -1205
package/dist/cli/main.js
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
beginUpdateNotification,
|
|
4
|
+
completeUpdateNotification,
|
|
5
|
+
runSelfUpdate
|
|
6
|
+
} from "../chunk-QUPLZ7KF.js";
|
|
2
7
|
import {
|
|
3
8
|
DEFAULT_FILE_INGEST_TIMEOUT_MS,
|
|
4
9
|
DEFAULT_FILE_UPLOAD_TIMEOUT_MS,
|
|
@@ -31,13 +36,14 @@ import {
|
|
|
31
36
|
uploadFile,
|
|
32
37
|
uploadText,
|
|
33
38
|
validateLocalFile
|
|
34
|
-
} from "../chunk-
|
|
39
|
+
} from "../chunk-SZ3AZDMU.js";
|
|
35
40
|
import {
|
|
36
41
|
AGENT_CHOICES,
|
|
37
42
|
CtxdbError,
|
|
38
43
|
DEFAULT_BASE_URL,
|
|
39
44
|
DEFAULT_USER_ID,
|
|
40
45
|
HttpClient,
|
|
46
|
+
MAX_ZIP,
|
|
41
47
|
PACKAGE_NAME,
|
|
42
48
|
PACKAGE_VERSION,
|
|
43
49
|
SUPPORTED_AGENTS,
|
|
@@ -46,36 +52,61 @@ import {
|
|
|
46
52
|
agentHomeDir,
|
|
47
53
|
agentHomeDirs,
|
|
48
54
|
agentPlatformSupport,
|
|
55
|
+
autoCollectAllowed,
|
|
56
|
+
bindSession,
|
|
57
|
+
bindingPath,
|
|
58
|
+
businessEvents,
|
|
59
|
+
catalogContext,
|
|
60
|
+
configFileName,
|
|
49
61
|
configuredAgents,
|
|
50
62
|
defaultConfigPath,
|
|
51
63
|
detectInstalledAgents,
|
|
64
|
+
expireSessionEvidence,
|
|
65
|
+
getBinding,
|
|
52
66
|
hasConfiguredAgent,
|
|
53
67
|
inspectAgentHomes,
|
|
54
68
|
inspectConfig,
|
|
69
|
+
inspectZip,
|
|
55
70
|
isAgentSlug,
|
|
56
71
|
isBuiltinAgent,
|
|
57
72
|
isDataApiReady,
|
|
58
73
|
load,
|
|
74
|
+
loadSkill,
|
|
75
|
+
privatePath,
|
|
76
|
+
publishPackage,
|
|
77
|
+
readPackage,
|
|
78
|
+
readPrivate,
|
|
79
|
+
readSpool,
|
|
80
|
+
readState,
|
|
81
|
+
refreshManifest,
|
|
59
82
|
removeAgent,
|
|
83
|
+
requireUuid,
|
|
60
84
|
resolveDataApiCredential,
|
|
85
|
+
resumeSubmission,
|
|
86
|
+
retryFeedback,
|
|
61
87
|
save,
|
|
88
|
+
sha256,
|
|
89
|
+
skillRoot,
|
|
90
|
+
spoolDirectory,
|
|
91
|
+
threshold,
|
|
92
|
+
unbox,
|
|
93
|
+
updateAutoSkillEvolution,
|
|
62
94
|
updateConfiguredDebug,
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
} from "../chunk-3MEBQDGU.js";
|
|
95
|
+
validateEvidence,
|
|
96
|
+
verifiedClient,
|
|
97
|
+
withStateLock,
|
|
98
|
+
writeInstalledPkgVersion,
|
|
99
|
+
writeState
|
|
100
|
+
} from "../chunk-TZFDXKLJ.js";
|
|
70
101
|
import {
|
|
71
102
|
DISTRIBUTION_MANIFEST
|
|
72
103
|
} from "../chunk-5ITT5GSP.js";
|
|
73
104
|
import "../chunk-PI2SUS3M.js";
|
|
74
105
|
|
|
75
106
|
// src/cli/main.ts
|
|
76
|
-
import { realpathSync } from "fs";
|
|
77
|
-
import { basename as basename3, resolve as
|
|
78
|
-
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
107
|
+
import { realpathSync } from "node:fs";
|
|
108
|
+
import { basename as basename3, resolve as resolve4 } from "node:path";
|
|
109
|
+
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
79
110
|
|
|
80
111
|
// src/cli/util.ts
|
|
81
112
|
var REPEATABLE_FLAGS = /* @__PURE__ */ new Set([
|
|
@@ -100,6 +131,13 @@ var BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
|
|
|
100
131
|
"purge-config",
|
|
101
132
|
"purge-logs",
|
|
102
133
|
"purge-all",
|
|
134
|
+
// skills
|
|
135
|
+
"local",
|
|
136
|
+
"editable",
|
|
137
|
+
"remote",
|
|
138
|
+
"resume",
|
|
139
|
+
"apply",
|
|
140
|
+
"cache",
|
|
103
141
|
// memory
|
|
104
142
|
"no-infer",
|
|
105
143
|
// memory add
|
|
@@ -155,10 +193,10 @@ function parseArgs(argv, booleanFlags = BOOLEAN_FLAGS) {
|
|
|
155
193
|
const positional2 = [];
|
|
156
194
|
const flags = {};
|
|
157
195
|
const repeatedFlags = {};
|
|
158
|
-
const setFlag = (name,
|
|
159
|
-
flags[name] =
|
|
196
|
+
const setFlag = (name, value2) => {
|
|
197
|
+
flags[name] = value2;
|
|
160
198
|
if (REPEATABLE_FLAGS.has(name)) {
|
|
161
|
-
(repeatedFlags[name] ??= []).push(
|
|
199
|
+
(repeatedFlags[name] ??= []).push(value2);
|
|
162
200
|
}
|
|
163
201
|
};
|
|
164
202
|
let separatorSeen = false;
|
|
@@ -231,8 +269,8 @@ function isUpgradeResult(v) {
|
|
|
231
269
|
}
|
|
232
270
|
function isMultiAgentResult(v) {
|
|
233
271
|
if (typeof v !== "object" || v === null) return false;
|
|
234
|
-
const
|
|
235
|
-
return
|
|
272
|
+
const value2 = v;
|
|
273
|
+
return value2.mode === "all" && (value2.operation === "setup" || value2.operation === "status") && typeof value2.agents === "object" && value2.agents !== null && Array.isArray(value2.skipped) && typeof value2.summary === "object" && value2.summary !== null;
|
|
236
274
|
}
|
|
237
275
|
function isStatusResult(v) {
|
|
238
276
|
if (typeof v !== "object" || v === null) return false;
|
|
@@ -257,6 +295,7 @@ function formatUpgradeResult(r) {
|
|
|
257
295
|
for (const [name, result] of Object.entries(r.agents)) {
|
|
258
296
|
const icon = result.ok ? CHECK : CROSS;
|
|
259
297
|
lines.push(` ${icon} ${BOLD}${name}${RESET}`);
|
|
298
|
+
if (result.hook_activation) lines.push(` ${highlightInlineCode(result.hook_activation.next_action)}`);
|
|
260
299
|
for (const s of result.steps) {
|
|
261
300
|
const sIcon = s.ok ? CHECK : CROSS;
|
|
262
301
|
const detail = s.detail ? ` ${dim(s.detail)}` : "";
|
|
@@ -293,6 +332,7 @@ function formatMultiAgentResult(r) {
|
|
|
293
332
|
if (result.hooks_node !== void 0) {
|
|
294
333
|
lines.push(` ${DIM}hooks${RESET} ${result.hooks_node}`);
|
|
295
334
|
}
|
|
335
|
+
if (result.hook_activation) lines.push(` ${highlightInlineCode(result.hook_activation.next_action)}`);
|
|
296
336
|
if (result.ping_error) {
|
|
297
337
|
lines.push(` ${DIM}ping_error${RESET} ${result.ping_error}`);
|
|
298
338
|
}
|
|
@@ -316,6 +356,7 @@ function formatStatusResult(r) {
|
|
|
316
356
|
["base_url", r.base_url],
|
|
317
357
|
["user_id", r.user_id],
|
|
318
358
|
["api_key", r.api_key_set ? "set" : "not set"],
|
|
359
|
+
["auto_skill_evolution", r.auto_skill_evolution],
|
|
319
360
|
["access_token", r.access_token_set ? "set" : "not set"],
|
|
320
361
|
["credential_type", r.credential_type ?? "none"],
|
|
321
362
|
["auto_capture", r.auto_capture],
|
|
@@ -334,6 +375,12 @@ function formatStatusResult(r) {
|
|
|
334
375
|
display.push(["hooks_node", r.hooks_node]);
|
|
335
376
|
display.push(["hooks_node_ok", r.hooks_node_ok]);
|
|
336
377
|
}
|
|
378
|
+
if (r.hook_activation) {
|
|
379
|
+
const activation = r.hook_activation;
|
|
380
|
+
display.push(["hook_trust", activation.trust], ["runtime_ready", "\u5F85\u786E\u8BA4"], ["hook_config", activation.config_path]);
|
|
381
|
+
lines.push(`${BOLD}${highlightInlineCode(String(activation.next_action))}${RESET}
|
|
382
|
+
`);
|
|
383
|
+
}
|
|
337
384
|
if (r.ping_error) display.push(["ping_error", r.ping_error]);
|
|
338
385
|
const maxKey = Math.max(...display.map(([k]) => k.length));
|
|
339
386
|
for (const [k, v] of display) {
|
|
@@ -342,19 +389,19 @@ function formatStatusResult(r) {
|
|
|
342
389
|
}
|
|
343
390
|
return lines.join("\n");
|
|
344
391
|
}
|
|
345
|
-
function printResult(
|
|
392
|
+
function printResult(value2, json, command) {
|
|
346
393
|
if (json) {
|
|
347
|
-
process.stdout.write(JSON.stringify(
|
|
348
|
-
} else if (isMultiAgentResult(
|
|
349
|
-
process.stdout.write(formatMultiAgentResult(
|
|
350
|
-
} else if (isUpgradeResult(
|
|
351
|
-
process.stdout.write(formatUpgradeResult(
|
|
352
|
-
} else if (isSetupResult(
|
|
353
|
-
process.stdout.write(formatSetupResult(
|
|
354
|
-
} else if (isStatusResult(
|
|
355
|
-
process.stdout.write(formatStatusResult(
|
|
394
|
+
process.stdout.write(JSON.stringify(value2, null, 2) + "\n");
|
|
395
|
+
} else if (isMultiAgentResult(value2)) {
|
|
396
|
+
process.stdout.write(formatMultiAgentResult(value2) + "\n");
|
|
397
|
+
} else if (isUpgradeResult(value2)) {
|
|
398
|
+
process.stdout.write(formatUpgradeResult(value2) + "\n");
|
|
399
|
+
} else if (isSetupResult(value2)) {
|
|
400
|
+
process.stdout.write(formatSetupResult(value2, command ?? "setup") + "\n");
|
|
401
|
+
} else if (isStatusResult(value2)) {
|
|
402
|
+
process.stdout.write(formatStatusResult(value2) + "\n");
|
|
356
403
|
} else {
|
|
357
|
-
process.stdout.write(summarize(
|
|
404
|
+
process.stdout.write(summarize(value2) + "\n");
|
|
358
405
|
}
|
|
359
406
|
}
|
|
360
407
|
function agentFromFlags(flags) {
|
|
@@ -395,11 +442,11 @@ import {
|
|
|
395
442
|
rmdirSync,
|
|
396
443
|
unlinkSync,
|
|
397
444
|
statSync
|
|
398
|
-
} from "fs";
|
|
399
|
-
import { homedir } from "os";
|
|
400
|
-
import { join, dirname, resolve } from "path";
|
|
401
|
-
import { fileURLToPath } from "url";
|
|
402
|
-
import { execFileSync } from "child_process";
|
|
445
|
+
} from "node:fs";
|
|
446
|
+
import { homedir } from "node:os";
|
|
447
|
+
import { join, dirname, resolve } from "node:path";
|
|
448
|
+
import { fileURLToPath } from "node:url";
|
|
449
|
+
import { execFileSync } from "node:child_process";
|
|
403
450
|
import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
|
|
404
451
|
import { setupAuthentication, oauthProfileStatus, validateDataBaseUrl } from "@aliyunrds/ctxdb-shared";
|
|
405
452
|
|
|
@@ -440,7 +487,7 @@ function skillInstallRoot(agent) {
|
|
|
440
487
|
return join(homedir(), ".workbuddy-ai", "skills");
|
|
441
488
|
}
|
|
442
489
|
}
|
|
443
|
-
var SKILL_DIRS = ["contextdb-memory", "contextdb-knowledge"];
|
|
490
|
+
var SKILL_DIRS = ["contextdb-memory", "contextdb-knowledge", "contextdb-skills"];
|
|
444
491
|
var LEGACY_SKILL_DIRS = ["ctxdb"];
|
|
445
492
|
function agentSupportsHooks(agent) {
|
|
446
493
|
if (agent === "opencode" || agent === "hermes") return false;
|
|
@@ -470,7 +517,23 @@ var LEGACY_QODER_SKILL_DIRS = [
|
|
|
470
517
|
"rds-ctxdb-qoder",
|
|
471
518
|
"qoder-ctxdb"
|
|
472
519
|
];
|
|
473
|
-
var HOOK_EVENTS = ["UserPromptSubmit", "Stop", "SessionStart"];
|
|
520
|
+
var HOOK_EVENTS = ["UserPromptSubmit", "Stop", "SessionStart", "SessionEnd"];
|
|
521
|
+
var CODEX_HOOKS_TRUST_HINT = "\u5F85\u786E\u8BA4\uFF1ACodex Hook \u4FE1\u4EFB\u5C1A\u672A\u6838\u5B9E\uFF0C\u5B89\u88C5\u6210\u529F\u548C\u8FDE\u63A5\u6210\u529F\u4E0D\u4EE3\u8868\u81EA\u52A8\u63D0\u70BC\u5DF2\u5C31\u7EEA\u3002CLI \u8F93\u5165 `/hooks`\uFF1B\u684C\u9762\u7248\u8FDB\u5165 \u8BBE\u7F6E \u2192 `Hooks\uFF08\u94A9\u5B50\uFF09` \u2192 `\u7528\u6237\u914D\u7F6E`\uFF0C\u4EC5\u68C0\u67E5\u5E76\u4FE1\u4EFB `@aliyunrds/ctxdb` \u7684 `SessionStart`\u3001`UserPromptSubmit`\u3001`Stop`\u3001`SessionEnd`\u3002\u91CD\u542F\u5BA2\u6237\u7AEF\u540E\u65B0\u5EFA\u4F1A\u8BDD\u5E76\u53D1\u9001\u666E\u901A\u6D88\u606F\uFF0C\u518D\u8FD0\u884C `ctxdb skill status --agent codex --json` \u6838\u5BF9\u8BE5\u4F1A\u8BDD\u7684\u91C7\u96C6\u8BB0\u5F55\u3002";
|
|
522
|
+
function codexHookActivation() {
|
|
523
|
+
return {
|
|
524
|
+
trust: "unverified",
|
|
525
|
+
runtime_ready: null,
|
|
526
|
+
config_path: hookConfigPath("codex"),
|
|
527
|
+
required_events: [...HOOK_EVENTS],
|
|
528
|
+
next_action: CODEX_HOOKS_TRUST_HINT
|
|
529
|
+
};
|
|
530
|
+
}
|
|
531
|
+
function codexHookDefinitions() {
|
|
532
|
+
const file = hookConfigPath("codex");
|
|
533
|
+
if (!existsSync(file)) return "[]";
|
|
534
|
+
const data = JSON.parse(readFileSync(file, "utf8"));
|
|
535
|
+
return JSON.stringify(Object.entries(data.hooks ?? {}).sort(([a], [b]) => a.localeCompare(b)).flatMap(([event, entries]) => Array.isArray(entries) ? entries.filter(entryIsCtxdb).map((entry) => [event, entry]) : []));
|
|
536
|
+
}
|
|
474
537
|
var MIN_NODE_MAJOR = 20;
|
|
475
538
|
function parseNodeMajor(version) {
|
|
476
539
|
const match = /^v?(\d+)/.exec(version.trim());
|
|
@@ -501,6 +564,7 @@ async function runSetup(options) {
|
|
|
501
564
|
return { ok: false, steps };
|
|
502
565
|
}
|
|
503
566
|
const agent = options.agent;
|
|
567
|
+
let codexDefinitionsChanged;
|
|
504
568
|
const installSkill = options.installSkill !== false;
|
|
505
569
|
const validate = options.validate !== false;
|
|
506
570
|
const nodeVersionCheck = checkCurrentNodeVersion();
|
|
@@ -629,6 +693,7 @@ async function runSetup(options) {
|
|
|
629
693
|
if (!nodeCheck.ok) return { ok: false, steps };
|
|
630
694
|
if (primaryHomeExists) {
|
|
631
695
|
try {
|
|
696
|
+
const before = agent === "codex" ? codexHookDefinitions() : void 0;
|
|
632
697
|
backupSettingsJson(agent);
|
|
633
698
|
steps.push({ step: "backup-settings", ok: true });
|
|
634
699
|
const removed = stripCtxdbHooks(agent);
|
|
@@ -640,6 +705,7 @@ async function runSetup(options) {
|
|
|
640
705
|
});
|
|
641
706
|
}
|
|
642
707
|
appendHooks(agent, hookPaths);
|
|
708
|
+
if (agent === "codex") codexDefinitionsChanged = before !== codexHookDefinitions();
|
|
643
709
|
steps.push({ step: "append-hooks", ok: true });
|
|
644
710
|
} catch (err) {
|
|
645
711
|
steps.push({
|
|
@@ -654,6 +720,7 @@ async function runSetup(options) {
|
|
|
654
720
|
chmodSync(hookPaths.userPromptSubmit, 493);
|
|
655
721
|
chmodSync(hookPaths.stop, 493);
|
|
656
722
|
chmodSync(hookPaths.sessionStart, 493);
|
|
723
|
+
if (hookPaths.sessionEnd) chmodSync(hookPaths.sessionEnd, 493);
|
|
657
724
|
if (hookPaths.preToolUse && existsSync(hookPaths.preToolUse)) {
|
|
658
725
|
chmodSync(hookPaths.preToolUse, 493);
|
|
659
726
|
}
|
|
@@ -816,11 +883,14 @@ async function runSetup(options) {
|
|
|
816
883
|
}
|
|
817
884
|
const failedSteps = steps.filter((s) => !s.ok);
|
|
818
885
|
const ok = failedSteps.length === 0;
|
|
819
|
-
const actionRequired = agent === "hermes" && failedSteps.length === 1 && failedSteps[0]?.step === "check-hermes-hook-allowlist" ? "hermes-hook-allowlist" : void 0;
|
|
886
|
+
const actionRequired = agent === "hermes" && failedSteps.length === 1 && failedSteps[0]?.step === "check-hermes-hook-allowlist" ? "hermes-hook-allowlist" : agent === "codex" && failedSteps.length === 0 && codexDefinitionsChanged !== void 0 ? "review-codex-hook-trust" : void 0;
|
|
820
887
|
const hints = ok ? [UNINSTALL_ORDER_HINT] : [];
|
|
821
|
-
if (actionRequired) {
|
|
888
|
+
if (actionRequired === "hermes-hook-allowlist") {
|
|
822
889
|
hints.unshift(HERMES_ALLOWLIST_ACTION_HINT, HERMES_WEBUI_GATEWAY_HINT);
|
|
823
890
|
}
|
|
891
|
+
if (actionRequired === "review-codex-hook-trust") {
|
|
892
|
+
hints.unshift(CODEX_HOOKS_TRUST_HINT, codexDefinitionsChanged ? "ContextDB Hook \u5B9A\u4E49\u5DF2\u65B0\u589E\u6216\u53D8\u66F4\uFF1BCodex \u6309\u5B9A\u4E49\u54C8\u5E0C\u8BB0\u5F55\u4FE1\u4EFB\uFF0C\u8BF7\u91CD\u65B0\u68C0\u67E5\u6388\u6743\u3002" : "ContextDB Hook \u5B9A\u4E49\u672A\u53D8\u5316\uFF1B\u8FD9\u4E0D\u8BC1\u660E\u5DF2\u6388\u6743\uFF0C\u4E5F\u4E0D\u4F1A\u4FEE\u6539\u5BBF\u4E3B\u7684\u4FE1\u4EFB\u8BB0\u5F55\u3002");
|
|
893
|
+
}
|
|
824
894
|
if (ok && agent === "opencode") {
|
|
825
895
|
hints.unshift(
|
|
826
896
|
`OpenCode plugin shim: ${opencodeShimPath()}`,
|
|
@@ -838,6 +908,7 @@ async function runSetup(options) {
|
|
|
838
908
|
ok,
|
|
839
909
|
steps,
|
|
840
910
|
actionRequired,
|
|
911
|
+
...actionRequired === "review-codex-hook-trust" ? { hook_activation: { ...codexHookActivation(), definitions_changed: codexDefinitionsChanged } } : {},
|
|
841
912
|
hints: hints.length > 0 ? hints : void 0
|
|
842
913
|
};
|
|
843
914
|
}
|
|
@@ -1500,6 +1571,7 @@ function hookPathsFromDir(dir, ext) {
|
|
|
1500
1571
|
userPromptSubmit: ups,
|
|
1501
1572
|
stop: stp,
|
|
1502
1573
|
sessionStart: ss,
|
|
1574
|
+
sessionEnd: existsSync(join(dir, `session-end.${ext}`)) ? join(dir, `session-end.${ext}`) : void 0,
|
|
1503
1575
|
preToolUse: existsSync(ptu) ? ptu : void 0,
|
|
1504
1576
|
hermesPreLlmCall: existsSync(hpl) ? hpl : void 0,
|
|
1505
1577
|
hermesPostLlmCall: existsSync(hpost) ? hpost : void 0
|
|
@@ -1616,6 +1688,7 @@ function appendHooksToFile(path, agent, hookPaths) {
|
|
|
1616
1688
|
appendOne(data.hooks, "UserPromptSubmit", hookPaths.userPromptSubmit, agent);
|
|
1617
1689
|
appendOne(data.hooks, "Stop", hookPaths.stop, agent);
|
|
1618
1690
|
appendOne(data.hooks, "SessionStart", hookPaths.sessionStart, agent);
|
|
1691
|
+
if ((agent === "codex" || agent === "claude" || agent === "workbuddy") && hookPaths.sessionEnd) appendOne(data.hooks, "SessionEnd", hookPaths.sessionEnd, agent);
|
|
1619
1692
|
mkdirSync(dirname(path), { recursive: true });
|
|
1620
1693
|
writeFileSync(path, JSON.stringify(data, null, 2) + "\n", "utf-8");
|
|
1621
1694
|
}
|
|
@@ -1684,7 +1757,7 @@ function appendOne(hooks, event, command, agent) {
|
|
|
1684
1757
|
)
|
|
1685
1758
|
);
|
|
1686
1759
|
if (dup) return;
|
|
1687
|
-
const inner = useExecForm ? { type: "command", command: process.execPath, args: [command, `--agent=${agent}`], timeout: 60 } : { type: "command", command: shellCmd, timeout: 60 };
|
|
1760
|
+
const inner = useExecForm ? { type: "command", command: process.execPath, args: [command, `--agent=${agent}`], timeout: 60 } : { type: "command", command: shellCmd, timeout: event === "SessionEnd" ? 3 : 60 };
|
|
1688
1761
|
const entry = {
|
|
1689
1762
|
hooks: [inner],
|
|
1690
1763
|
[ENTRY_MARKER_KEY]: ENTRY_MARKER_VALUE,
|
|
@@ -1753,8 +1826,8 @@ function hermesHooksMap(data) {
|
|
|
1753
1826
|
}
|
|
1754
1827
|
return data.hooks;
|
|
1755
1828
|
}
|
|
1756
|
-
function quoteHermesCommandPart(
|
|
1757
|
-
return `'${
|
|
1829
|
+
function quoteHermesCommandPart(value2) {
|
|
1830
|
+
return `'${value2.replace(/'/g, `'\\''`)}'`;
|
|
1758
1831
|
}
|
|
1759
1832
|
function hermesHookCommand(scriptPath, nodePath) {
|
|
1760
1833
|
return `${quoteHermesCommandPart(nodePath)} ${quoteHermesCommandPart(scriptPath)} --agent=hermes`;
|
|
@@ -1960,11 +2033,11 @@ function inspectCodexHooksFeature(rawContent) {
|
|
|
1960
2033
|
};
|
|
1961
2034
|
}
|
|
1962
2035
|
if (/^features\.hooks\s*=/.test(stripped)) {
|
|
1963
|
-
const
|
|
1964
|
-
if (
|
|
2036
|
+
const value2 = stripped.split("=", 2)[1]?.trim();
|
|
2037
|
+
if (value2 === "true") return { kind: "already-enabled" };
|
|
1965
2038
|
return {
|
|
1966
2039
|
kind: "ambiguous",
|
|
1967
|
-
reason: `features.hooks already set to '${
|
|
2040
|
+
reason: `features.hooks already set to '${value2}' via dotted-key \u2014 please set it to true manually`
|
|
1968
2041
|
};
|
|
1969
2042
|
}
|
|
1970
2043
|
}
|
|
@@ -1989,12 +2062,12 @@ function inspectCodexHooksFeature(rawContent) {
|
|
|
1989
2062
|
if (!inFeatures) continue;
|
|
1990
2063
|
const kv = stripped.match(/^hooks\s*=\s*(.+)$/);
|
|
1991
2064
|
if (kv) {
|
|
1992
|
-
const
|
|
1993
|
-
if (
|
|
1994
|
-
if (
|
|
2065
|
+
const value2 = kv[1].trim();
|
|
2066
|
+
if (value2 === "true") return { kind: "already-enabled" };
|
|
2067
|
+
if (value2 === "false") return { kind: "features-with-hooks-false" };
|
|
1995
2068
|
return {
|
|
1996
2069
|
kind: "ambiguous",
|
|
1997
|
-
reason: `[features].hooks already set to '${
|
|
2070
|
+
reason: `[features].hooks already set to '${value2}' \u2014 please set it to true manually`
|
|
1998
2071
|
};
|
|
1999
2072
|
}
|
|
2000
2073
|
}
|
|
@@ -2210,10 +2283,6 @@ FLAGS
|
|
|
2210
2283
|
--no-validate Skip connectivity ping after setup
|
|
2211
2284
|
--json Machine-readable JSON output
|
|
2212
2285
|
`;
|
|
2213
|
-
var CODEX_HOOKS_TRUST_REMINDER = [
|
|
2214
|
-
"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",
|
|
2215
|
-
"\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"
|
|
2216
|
-
].join("\n");
|
|
2217
2286
|
var FULL_APP_RESTART_REMINDERS = {
|
|
2218
2287
|
qoder: "Next action: \u8BF7\u5B8C\u5168\u9000\u51FA\u5E76\u91CD\u65B0\u542F\u52A8 Qoder\uFF08\u4E0D\u662F\u53EA\u5173\u95ED\u5F53\u524D\u5BF9\u8BDD\uFF09\uFF0C\u4F7F\u65B0\u7684 hooks \u548C skill \u751F\u6548\u3002",
|
|
2219
2288
|
qoderwork: "Next action: \u8BF7\u5B8C\u5168\u9000\u51FA\u5E76\u91CD\u65B0\u542F\u52A8 QoderWork\uFF08\u4E0D\u662F\u53EA\u5173\u95ED\u5F53\u524D\u5BF9\u8BDD\uFF09\uFF0C\u4F7F\u65B0\u7684 hooks \u548C skill \u751F\u6548\u3002",
|
|
@@ -2221,7 +2290,7 @@ var FULL_APP_RESTART_REMINDERS = {
|
|
|
2221
2290
|
};
|
|
2222
2291
|
function postSetupReminders(agent) {
|
|
2223
2292
|
const reminder = FULL_APP_RESTART_REMINDERS[agent];
|
|
2224
|
-
return [...reminder ? [reminder] : [], ...agent === "codex" ? [
|
|
2293
|
+
return [...reminder ? [reminder] : [], ...agent === "codex" ? [CODEX_HOOKS_TRUST_HINT] : []];
|
|
2225
2294
|
}
|
|
2226
2295
|
function printPostSetupReminder(agent) {
|
|
2227
2296
|
for (const reminder of postSetupReminders(agent)) process.stderr.write(`
|
|
@@ -2387,6 +2456,8 @@ async function inspectStatus(agent) {
|
|
|
2387
2456
|
base_url: cfg.baseUrl,
|
|
2388
2457
|
user_id: cfg.userId,
|
|
2389
2458
|
api_key_set: Boolean(cfg.apiKey),
|
|
2459
|
+
auto_skill_evolution: cfg.autoSkillEvolution,
|
|
2460
|
+
...agent === "codex" ? { hook_activation: codexHookActivation() } : {},
|
|
2390
2461
|
access_token_set: credential?.type === "access-token",
|
|
2391
2462
|
credential_type: credential?.type ?? null,
|
|
2392
2463
|
auto_capture: cfg.autoCapture,
|
|
@@ -2665,7 +2736,7 @@ FLAGS
|
|
|
2665
2736
|
--json Machine-readable JSON output
|
|
2666
2737
|
|
|
2667
2738
|
Note: This command only installs skill files (contextdb, contextdb-memory,
|
|
2668
|
-
contextdb-knowledge). It does not write config or install hooks.
|
|
2739
|
+
contextdb-knowledge, contextdb-skills). It does not write config or install hooks.
|
|
2669
2740
|
To configure server connection, run: ctxdb setup --api-key=<key> --base-url=<url>
|
|
2670
2741
|
`;
|
|
2671
2742
|
function skillInstall(args) {
|
|
@@ -2719,6 +2790,603 @@ function skillInstall(args) {
|
|
|
2719
2790
|
return ok ? 0 : 1;
|
|
2720
2791
|
}
|
|
2721
2792
|
|
|
2793
|
+
// src/skills/session-selector.ts
|
|
2794
|
+
import { homedir as homedir2 } from "node:os";
|
|
2795
|
+
import { join as join3, win32 } from "node:path";
|
|
2796
|
+
import { existsSync as existsSync3 } from "node:fs";
|
|
2797
|
+
|
|
2798
|
+
// src/skills/status.ts
|
|
2799
|
+
import { existsSync as existsSync2, readdirSync as readdirSync2, lstatSync } from "node:fs";
|
|
2800
|
+
import "node:path";
|
|
2801
|
+
function statusBindings(root, agent) {
|
|
2802
|
+
const dir = privatePath(root, "sessions", "bindings");
|
|
2803
|
+
if (!existsSync2(dir)) return [];
|
|
2804
|
+
return readdirSync2(dir).filter((name) => /^[a-f0-9-]{36}\.json$/.test(name)).map((name) => getBinding(name.slice(0, -5), root)).filter((bound) => !agent || bound.agent === agent).sort((a, b) => Number(b.active === true) - Number(a.active === true));
|
|
2805
|
+
}
|
|
2806
|
+
function localSkillStatus(bound, root) {
|
|
2807
|
+
const spool = readSpool(bound, root), business = businessEvents(spool);
|
|
2808
|
+
const calls = new Set(business.filter((e) => e.type === "tool_call").map((e) => e.tool_call_id));
|
|
2809
|
+
const results = new Set(spool.events.filter((e) => e.type === "tool_result").map((e) => e.tool_call_id));
|
|
2810
|
+
const unpaired = spool.events.filter((e) => e.type === "tool_call" && !results.has(e.tool_call_id)).map((e) => e.tool_call_id);
|
|
2811
|
+
const path = (...parts) => privatePath(root, ...parts);
|
|
2812
|
+
const skills = path("skills", bound.scope_key), evolution = path("skill-evolution", bound.scope_key);
|
|
2813
|
+
const directory = path(spoolDirectory(bound));
|
|
2814
|
+
const list = (dir) => existsSync2(dir) ? readdirSync2(dir) : [];
|
|
2815
|
+
const dispositions = list(path(directory, "dispositions")).filter((n) => /^\d+-\d+\.json$/.test(n)).map((name) => {
|
|
2816
|
+
const file = path(directory, "dispositions", name);
|
|
2817
|
+
const d = readState(root, file);
|
|
2818
|
+
return {
|
|
2819
|
+
path: file,
|
|
2820
|
+
status: d.status,
|
|
2821
|
+
reason: d.reason,
|
|
2822
|
+
from_sequence: d.from_sequence,
|
|
2823
|
+
through_sequence: d.through_sequence,
|
|
2824
|
+
event_count: d.event_count,
|
|
2825
|
+
buffer_bytes: d.buffer_bytes,
|
|
2826
|
+
created_at: d.created_at
|
|
2827
|
+
};
|
|
2828
|
+
});
|
|
2829
|
+
const publications = [], evaluations = [];
|
|
2830
|
+
for (const name of list(path(evolution, "artifacts"))) {
|
|
2831
|
+
if (/^upload-[a-f0-9-]{36}$/.test(name)) {
|
|
2832
|
+
const file = path(evolution, "artifacts", name, "publication.json");
|
|
2833
|
+
const p = readState(root, file);
|
|
2834
|
+
if (p.binding_id !== bound.id) continue;
|
|
2835
|
+
publications.push({
|
|
2836
|
+
evaluation_id: p.evaluation_id,
|
|
2837
|
+
request_id: p.input.client_request_id,
|
|
2838
|
+
source: p.input.source,
|
|
2839
|
+
result: p.result,
|
|
2840
|
+
verified: p.verified ?? false,
|
|
2841
|
+
manifest_refreshed: p.manifest_refreshed,
|
|
2842
|
+
active_advanced: p.active_advanced,
|
|
2843
|
+
receipt_path: file,
|
|
2844
|
+
bundle_path: path(evolution, "artifacts", name, "bundle.zip")
|
|
2845
|
+
});
|
|
2846
|
+
} else if (/^evaluation-[a-f0-9-]{36}\.json$/.test(name)) {
|
|
2847
|
+
const file = path(evolution, "artifacts", name), e = readState(root, file);
|
|
2848
|
+
if (e.binding_id === bound.id) evaluations.push({ request_id: e.evidence.client_request_id, result: e.result, path: file });
|
|
2849
|
+
}
|
|
2850
|
+
}
|
|
2851
|
+
const handoffs = list(path(directory, "handoffs")).filter((n) => /^[a-zA-Z0-9_-]{1,128}\.json$/.test(n)).map((name) => {
|
|
2852
|
+
const file = path(directory, "handoffs", name), h = readState(root, file);
|
|
2853
|
+
const related = publications.filter((p) => p.evaluation_id === h.event_id);
|
|
2854
|
+
return {
|
|
2855
|
+
event_id: h.event_id,
|
|
2856
|
+
delivery: h.delivery,
|
|
2857
|
+
recorded_at: h.recorded_at,
|
|
2858
|
+
completion: related.some((p) => p.verified) ? "published" : related.length ? "publication_unconfirmed" : "unconfirmed",
|
|
2859
|
+
automatic_redelivery: false,
|
|
2860
|
+
path: file
|
|
2861
|
+
};
|
|
2862
|
+
});
|
|
2863
|
+
const loaded = (bound.loaded_versions ?? []).map((ref) => ({
|
|
2864
|
+
...ref,
|
|
2865
|
+
path: path(skills, "cache", ref.skill_id, ref.version_id, "bundle", "SKILL.md")
|
|
2866
|
+
}));
|
|
2867
|
+
const manifestPath = path(skills, "manifest.json");
|
|
2868
|
+
const snapshot = existsSync2(manifestPath) ? readState(root, manifestPath) : void 0;
|
|
2869
|
+
const drafts = list(path(skills, "drafts")).flatMap((name) => {
|
|
2870
|
+
if (!lstatSync(path(skills, "drafts", name)).isDirectory()) return [];
|
|
2871
|
+
const direct = path(skills, "drafts", name, "SKILL.md"), bundle = path(skills, "drafts", name, "bundle", "SKILL.md");
|
|
2872
|
+
return [direct, bundle].filter((file) => existsSync2(file));
|
|
2873
|
+
});
|
|
2874
|
+
const submissions = list(path(directory, "submissions")).filter((n) => /^[a-f0-9-]{36}\.json$/.test(n)).map((name) => {
|
|
2875
|
+
const file = path(directory, "submissions", name);
|
|
2876
|
+
const bytes = readPrivate(root, file, 65536), e = JSON.parse(bytes.toString("utf8"));
|
|
2877
|
+
return {
|
|
2878
|
+
path: file,
|
|
2879
|
+
request_id: e.client_request_id,
|
|
2880
|
+
trigger: e.trigger,
|
|
2881
|
+
request_bytes: bytes.length,
|
|
2882
|
+
distinct_tool_calls: new Set(e.events.filter((event) => event.type === "tool_call").map((event) => event.tool_call_id)).size,
|
|
2883
|
+
event_count: e.events.length,
|
|
2884
|
+
goal_characters: Array.from(e.goal ?? "").length,
|
|
2885
|
+
max_summary_characters: Math.max(0, ...e.events.map((event) => Array.from(event.summary ?? "").length))
|
|
2886
|
+
};
|
|
2887
|
+
});
|
|
2888
|
+
const trigger = threshold(spool);
|
|
2889
|
+
const waiting = bound.active === false ? "inactive_session" : spool.maintenance?.active ? "agent_maintenance" : spool.current ? "evaluation_in_progress_or_awaiting_delivery" : !autoCollectAllowed(bound, root) ? "automatic_capture_disabled" : !trigger ? "below_threshold" : "awaiting_complete_host_checkpoint";
|
|
2890
|
+
return {
|
|
2891
|
+
binding_id: bound.id,
|
|
2892
|
+
session_id: bound.session_id,
|
|
2893
|
+
agent: bound.agent,
|
|
2894
|
+
endpoint: bound.endpoint,
|
|
2895
|
+
auth_scope: bound.auth_scope,
|
|
2896
|
+
scope_key: bound.scope_key,
|
|
2897
|
+
active: bound.active,
|
|
2898
|
+
verified: bound.verified,
|
|
2899
|
+
auto_evolution_allowed: bound.auto_evolution_allowed,
|
|
2900
|
+
current: spool.current,
|
|
2901
|
+
error: spool.error,
|
|
2902
|
+
maintenance: spool.maintenance,
|
|
2903
|
+
buffered_events: spool.events.length,
|
|
2904
|
+
buffer_bytes: spool.buffer_bytes,
|
|
2905
|
+
buffer: {
|
|
2906
|
+
business_events: business.length,
|
|
2907
|
+
distinct_tool_calls: calls.size,
|
|
2908
|
+
bytes: spool.buffer_bytes,
|
|
2909
|
+
threshold_reached: !!trigger,
|
|
2910
|
+
trigger,
|
|
2911
|
+
tool_call_threshold: 10,
|
|
2912
|
+
bytes_threshold: 40960,
|
|
2913
|
+
max_request_bytes: 65536,
|
|
2914
|
+
max_events: 200,
|
|
2915
|
+
max_summary_characters: 2e3,
|
|
2916
|
+
unpaired_call_ids: unpaired,
|
|
2917
|
+
has_final_answer_hash: !!spool.last_answer_hash,
|
|
2918
|
+
waiting_reason: waiting
|
|
2919
|
+
},
|
|
2920
|
+
...bound.agent === "codex" ? { hook_activation: {
|
|
2921
|
+
trust: "unverified",
|
|
2922
|
+
runtime_ready: null,
|
|
2923
|
+
binding_record: "present",
|
|
2924
|
+
transcript_checkpoint: spool.cursor > 0 ? "present" : "not_observed",
|
|
2925
|
+
evidence_capture: spool.events.length > 0 || submissions.some((s) => s.event_count > 0) || dispositions.some((d) => Number(d.event_count) > 0) ? "present" : "not_observed",
|
|
2926
|
+
evaluation_submission: spool.current?.event_id ? "accepted" : submissions.length ? "prepared" : "not_observed",
|
|
2927
|
+
last_checkpoint_at: spool.updated_at ?? null,
|
|
2928
|
+
note: "Local records are not Codex trust receipts. A binding can be created by CLI; historical capture or submission does not prove current hooks are trusted. Match this session to your new conversation. Missing records can mean no event yet, an unloaded hook, missing trust, or execution failure."
|
|
2929
|
+
} } : {},
|
|
2930
|
+
state_exists: existsSync2(path(directory, "state.json")),
|
|
2931
|
+
cursor: spool.cursor,
|
|
2932
|
+
submitted_through_sequence: spool.submitted_through_sequence,
|
|
2933
|
+
processed_through_sequence: spool.processed_through_sequence,
|
|
2934
|
+
updated_at: spool.updated_at,
|
|
2935
|
+
dispositions,
|
|
2936
|
+
submissions,
|
|
2937
|
+
publications,
|
|
2938
|
+
evaluations,
|
|
2939
|
+
handoffs,
|
|
2940
|
+
scope_drafts: drafts,
|
|
2941
|
+
loaded_versions: loaded,
|
|
2942
|
+
manifest: {
|
|
2943
|
+
path: manifestPath,
|
|
2944
|
+
exists: !!snapshot,
|
|
2945
|
+
status: bound.manifest_status,
|
|
2946
|
+
fetched_at: snapshot?.fetched_at,
|
|
2947
|
+
skills: snapshot?.manifest.skills ?? []
|
|
2948
|
+
},
|
|
2949
|
+
paths: {
|
|
2950
|
+
binding: path(bindingPath(bound)),
|
|
2951
|
+
state: path(directory, "state.json"),
|
|
2952
|
+
skills,
|
|
2953
|
+
drafts: path(skills, "drafts"),
|
|
2954
|
+
cache: path(skills, "cache"),
|
|
2955
|
+
evolution,
|
|
2956
|
+
submissions: path(directory, "submissions"),
|
|
2957
|
+
dispositions: path(directory, "dispositions"),
|
|
2958
|
+
current_submission: spool.current ? path(directory, "submissions", `${spool.current.request_id}.json`) : null
|
|
2959
|
+
},
|
|
2960
|
+
notes: [
|
|
2961
|
+
"Buffer counts only unsubmitted evidence and clears after accepted submission; submissions retain the submitted call/event/byte counts.",
|
|
2962
|
+
"Inactive sessions may be host initialization sessions; match session_id to the actual conversation before interpreting counters.",
|
|
2963
|
+
"A delivered handoff is not completion. Unconfirmed includes ignored, interrupted or permission-blocked work; absence of a receipt cannot identify the reason. No automatic redelivery.",
|
|
2964
|
+
"Drafts and manifest are scope-wide; draft ownership is not inferred from directory existence.",
|
|
2965
|
+
"Loaded versions may come from publication verification or manual Load; they do not prove business reuse.",
|
|
2966
|
+
"Local current is a checkpoint snapshot; use --remote for server status. A final-answer hash alone does not certify a complete boundary."
|
|
2967
|
+
]
|
|
2968
|
+
};
|
|
2969
|
+
}
|
|
2970
|
+
|
|
2971
|
+
// src/skills/session-selector.ts
|
|
2972
|
+
function qoderWorkDatabase(platform2 = process.platform, home = homedir2(), appData = process.env.APPDATA) {
|
|
2973
|
+
if (platform2 === "darwin") return join3(home, "Library", "Application Support", "QoderWork", "data", "agents.db");
|
|
2974
|
+
if (platform2 === "win32") return win32.join(appData || win32.join(home, "AppData", "Roaming"), "QoderWork", "data", "agents.db");
|
|
2975
|
+
throw new Error("qoderwork_chat_lookup_platform_unsupported_use_binding_id");
|
|
2976
|
+
}
|
|
2977
|
+
async function selectSkillSessions(id, agent, root) {
|
|
2978
|
+
if (!id.trim() || id.length > 256) throw new Error("invalid_session_id");
|
|
2979
|
+
const bindings = statusBindings(root, agent);
|
|
2980
|
+
const direct = bindings.filter((b) => b.session_id === id);
|
|
2981
|
+
if (direct.length) return { bindings: direct, host_chat_id: void 0, unbound_session_ids: [] };
|
|
2982
|
+
if (agent !== "qoderwork") throw new Error("session_binding_not_found");
|
|
2983
|
+
const database = qoderWorkDatabase();
|
|
2984
|
+
if (!existsSync3(database)) throw new Error("qoderwork_database_not_found");
|
|
2985
|
+
const [major, minor] = process.versions.node.split(".").map(Number);
|
|
2986
|
+
if (major < 22 || major === 22 && minor < 13 || major === 23 && minor < 4) {
|
|
2987
|
+
throw new Error("qoderwork_chat_lookup_requires_node_22_13_or_newer_use_binding_id");
|
|
2988
|
+
}
|
|
2989
|
+
let sqlite;
|
|
2990
|
+
try {
|
|
2991
|
+
sqlite = await import("node:sqlite");
|
|
2992
|
+
} catch {
|
|
2993
|
+
throw new Error("qoderwork_chat_lookup_requires_node_22_13_or_newer_use_binding_id");
|
|
2994
|
+
}
|
|
2995
|
+
let rows;
|
|
2996
|
+
try {
|
|
2997
|
+
const db = new sqlite.DatabaseSync(database, { readOnly: true });
|
|
2998
|
+
try {
|
|
2999
|
+
rows = db.prepare("SELECT s.session_id FROM chats c LEFT JOIN sub_chats s ON s.chat_id=c.id WHERE c.id=? ORDER BY s.session_id").all(id);
|
|
3000
|
+
if (rows.some((r) => !(r.session_id === null || typeof r.session_id === "string"))) throw new Error();
|
|
3001
|
+
} finally {
|
|
3002
|
+
db.close();
|
|
3003
|
+
}
|
|
3004
|
+
} catch {
|
|
3005
|
+
throw new Error("qoderwork_database_unreadable_or_schema_unsupported_use_binding_id");
|
|
3006
|
+
}
|
|
3007
|
+
if (!rows.length) throw new Error("qoderwork_chat_not_found");
|
|
3008
|
+
const ids = [...new Set(rows.map((r) => r.session_id).filter((s) => !!s))];
|
|
3009
|
+
if (!ids.length) throw new Error("qoderwork_session_not_started");
|
|
3010
|
+
const matched = bindings.filter((b) => ids.includes(b.session_id));
|
|
3011
|
+
const unbound = ids.filter((id2) => !matched.some((b) => b.session_id === id2));
|
|
3012
|
+
return { bindings: matched, host_chat_id: id, unbound_session_ids: unbound };
|
|
3013
|
+
}
|
|
3014
|
+
|
|
3015
|
+
// src/skills/evaluation.ts
|
|
3016
|
+
import { randomUUID } from "node:crypto";
|
|
3017
|
+
import { existsSync as existsSync4 } from "node:fs";
|
|
3018
|
+
import { join as join4 } from "node:path";
|
|
3019
|
+
async function submitManualEvaluation(binding2, client, input, source, requestId, root = skillRoot()) {
|
|
3020
|
+
const { client_request_id: ignored, ...rest } = input;
|
|
3021
|
+
const body = { ...rest, submission_mode: "manual", trigger: "manual" };
|
|
3022
|
+
const artifacts = join4("skill-evolution", binding2.scope_key, "artifacts");
|
|
3023
|
+
const index = join4(artifacts, `manual-${sha256(JSON.stringify([source, body]))}.json`);
|
|
3024
|
+
const id = requestId ? requireUuid(requestId) : await withStateLock(root, index, async () => {
|
|
3025
|
+
if (existsSync4(privatePath(root, index))) return requireUuid(readState(root, index).request_id);
|
|
3026
|
+
const request_id = randomUUID();
|
|
3027
|
+
writeState(root, index, { request_id });
|
|
3028
|
+
return request_id;
|
|
3029
|
+
});
|
|
3030
|
+
const evidence = { ...body, client_request_id: id };
|
|
3031
|
+
validateEvidence(evidence);
|
|
3032
|
+
const path = join4(artifacts, `evaluation-${id}.json`);
|
|
3033
|
+
return withStateLock(root, path, async () => {
|
|
3034
|
+
let state;
|
|
3035
|
+
if (existsSync4(privatePath(root, path))) {
|
|
3036
|
+
state = readState(root, path);
|
|
3037
|
+
if (JSON.stringify(state.evidence) !== JSON.stringify(evidence)) throw new Error("idempotency_payload_mismatch");
|
|
3038
|
+
} else {
|
|
3039
|
+
state = { binding_id: binding2.id, evidence };
|
|
3040
|
+
writeState(root, path, state);
|
|
3041
|
+
}
|
|
3042
|
+
if (!state.result) {
|
|
3043
|
+
const result = unbox(await client.postJson("/v1/skill-evolution/evaluations", evidence));
|
|
3044
|
+
if (!result || !/^[a-zA-Z0-9_-]{1,128}$/.test(result.event_id) || typeof result.status !== "string") throw new Error("invalid_evaluation_response");
|
|
3045
|
+
state.result = result;
|
|
3046
|
+
writeState(root, path, state);
|
|
3047
|
+
}
|
|
3048
|
+
return state.result;
|
|
3049
|
+
});
|
|
3050
|
+
}
|
|
3051
|
+
|
|
3052
|
+
// src/cli/skill-storage-cli.ts
|
|
3053
|
+
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
3054
|
+
import { join as join5, resolve as resolve2 } from "node:path";
|
|
3055
|
+
import { existsSync as existsSync5, readdirSync as readdirSync3, rmSync as rmSync2 } from "node:fs";
|
|
3056
|
+
function value(args, name) {
|
|
3057
|
+
const item = args.flags[name];
|
|
3058
|
+
if (item === true) throw new Error(`--${name} requires a value`);
|
|
3059
|
+
return item;
|
|
3060
|
+
}
|
|
3061
|
+
async function binding(args) {
|
|
3062
|
+
const id = value(args, "session");
|
|
3063
|
+
if (id) return getBinding(id);
|
|
3064
|
+
if (process.env.CODEX_THREAD_ID || process.env.CODEX_SESSION_ID || process.env.CLAUDE_CODE_ENTRYPOINT || process.env.CTXDB_SKILL_REQUIRE_SESSION === "1") throw new Error("session_binding_required");
|
|
3065
|
+
return bindSession(agentFromFlags(args.flags), `terminal-${randomUUID2()}`, skillRoot(), 3e4);
|
|
3066
|
+
}
|
|
3067
|
+
var skillBind = async (args) => {
|
|
3068
|
+
const session = value(args, "session-id");
|
|
3069
|
+
if (!session) throw new Error("--session-id is required");
|
|
3070
|
+
const result = await bindSession(agentFromFlags(args.flags), session, skillRoot(), 3e4);
|
|
3071
|
+
const client = await verifiedClient(result);
|
|
3072
|
+
await refreshManifest(result, client);
|
|
3073
|
+
printResult({ binding_id: result.id, auth_scope: result.auth_scope }, !!args.flags.json);
|
|
3074
|
+
return 0;
|
|
3075
|
+
};
|
|
3076
|
+
var skillManifest = async (args) => {
|
|
3077
|
+
const bound = await binding(args), client = await verifiedClient(bound);
|
|
3078
|
+
const snapshot = await refreshManifest(bound, client);
|
|
3079
|
+
printResult({ ...snapshot, catalog_context: catalogContext(bound) }, !!args.flags.json);
|
|
3080
|
+
return 0;
|
|
3081
|
+
};
|
|
3082
|
+
var skillList = async (args) => {
|
|
3083
|
+
const bound = await binding(args), client = await verifiedClient(bound);
|
|
3084
|
+
const snapshot = await refreshManifest(bound, client);
|
|
3085
|
+
const result = {
|
|
3086
|
+
fetched_at: snapshot.fetched_at,
|
|
3087
|
+
auth_scope: snapshot.manifest.auth_scope,
|
|
3088
|
+
skills: [...snapshot.manifest.skills].sort((left, right) => left.display_name.localeCompare(right.display_name) || left.skill_id.localeCompare(right.skill_id))
|
|
3089
|
+
};
|
|
3090
|
+
if (args.flags.json) printResult(result, true);
|
|
3091
|
+
else if (result.skills.length === 0) process.stdout.write("No active Skills.\n");
|
|
3092
|
+
else process.stdout.write(`${result.skills.length} active Skill${result.skills.length === 1 ? "" : "s"}:
|
|
3093
|
+
${result.skills.map((entry) => `- ${entry.display_name} (${entry.category})
|
|
3094
|
+
skill_id: ${entry.skill_id}
|
|
3095
|
+
active_version_id: ${entry.active_version_id}
|
|
3096
|
+
updated_at: ${entry.updated_at}`).join("\n")}
|
|
3097
|
+
`);
|
|
3098
|
+
return 0;
|
|
3099
|
+
};
|
|
3100
|
+
async function effectiveSkillConfig(args) {
|
|
3101
|
+
const bound = await binding(args), client = await verifiedClient(bound);
|
|
3102
|
+
const remote = unbox(await client.get("/v1/skill-evolution/config"));
|
|
3103
|
+
const localEnabled = load({ agent: bound.agent, path: join5(skillRoot(), configFileName()) }).autoSkillEvolution !== false;
|
|
3104
|
+
return {
|
|
3105
|
+
...remote,
|
|
3106
|
+
local_auto_evolution_enabled: localEnabled,
|
|
3107
|
+
effective_auto_evolution_enabled: localEnabled && remote.auto_evolution_enabled === true
|
|
3108
|
+
};
|
|
3109
|
+
}
|
|
3110
|
+
function localConfigAgent(args, requireExplicit = false) {
|
|
3111
|
+
const session = value(args, "session");
|
|
3112
|
+
if (session) {
|
|
3113
|
+
if (requireExplicit) throw new Error("--session cannot be used for local config changes");
|
|
3114
|
+
const bound = getBinding(session);
|
|
3115
|
+
const requested = args.flags.agent === void 0 ? void 0 : agentFromFlags(args.flags);
|
|
3116
|
+
if (requested && requested !== bound.agent) throw new Error("session_agent_mismatch");
|
|
3117
|
+
return bound.agent;
|
|
3118
|
+
}
|
|
3119
|
+
if (requireExplicit && typeof args.flags.agent !== "string") throw new Error("--agent is required for local config changes");
|
|
3120
|
+
return agentFromFlags(args.flags);
|
|
3121
|
+
}
|
|
3122
|
+
function localAutoEvolution(agent) {
|
|
3123
|
+
return load({ agent, path: join5(skillRoot(), configFileName()) }).autoSkillEvolution !== false;
|
|
3124
|
+
}
|
|
3125
|
+
var skillConfig = async (args) => {
|
|
3126
|
+
const [action, key, rawValue, ...extra] = args.positional;
|
|
3127
|
+
if (!action || action === "get" && !key) {
|
|
3128
|
+
if (rawValue || extra.length) throw new Error("invalid_skill_config_command");
|
|
3129
|
+
printResult(await effectiveSkillConfig(args), !!args.flags.json);
|
|
3130
|
+
return 0;
|
|
3131
|
+
}
|
|
3132
|
+
if (!["get", "set", "unset"].includes(action) || key !== "auto-skill-evolution" || extra.length) {
|
|
3133
|
+
throw new Error("invalid_skill_config_command");
|
|
3134
|
+
}
|
|
3135
|
+
if (action === "get") {
|
|
3136
|
+
if (rawValue) throw new Error("invalid_skill_config_command");
|
|
3137
|
+
const agent2 = localConfigAgent(args);
|
|
3138
|
+
printResult({ key, agent: agent2, value: localAutoEvolution(agent2), source: "local" }, !!args.flags.json);
|
|
3139
|
+
return 0;
|
|
3140
|
+
}
|
|
3141
|
+
const agent = localConfigAgent(args, true);
|
|
3142
|
+
let enabled;
|
|
3143
|
+
if (action === "set") {
|
|
3144
|
+
if (rawValue !== "on" && rawValue !== "off") throw new Error("auto-skill-evolution value must be on or off");
|
|
3145
|
+
enabled = rawValue === "on";
|
|
3146
|
+
} else if (rawValue) throw new Error("invalid_skill_config_command");
|
|
3147
|
+
if (!updateAutoSkillEvolution(agent, enabled, join5(skillRoot(), configFileName()))) throw new Error("agent_config_not_found");
|
|
3148
|
+
printResult({ key, agent, value: localAutoEvolution(agent), source: enabled === void 0 ? "default" : "local" }, !!args.flags.json);
|
|
3149
|
+
return 0;
|
|
3150
|
+
};
|
|
3151
|
+
var skillSearch = async (args) => {
|
|
3152
|
+
const query = args.positional.join(" ");
|
|
3153
|
+
const topK = Number(value(args, "top-k") ?? 5);
|
|
3154
|
+
if (!query || Array.from(query).length > 512 || !Number.isInteger(topK) || topK < 1 || topK > 10) throw new Error("invalid_search");
|
|
3155
|
+
if (args.flags.local) throw new Error("local_search_removed_use_manifest_or_remote_search");
|
|
3156
|
+
const bound = await binding(args);
|
|
3157
|
+
const result = unbox(await (await verifiedClient(bound)).get("/v1/skills/search", { query, top_k: topK }));
|
|
3158
|
+
printResult(result, !!args.flags.json);
|
|
3159
|
+
return 0;
|
|
3160
|
+
};
|
|
3161
|
+
var skillLoad = async (args) => {
|
|
3162
|
+
const id = value(args, "skill-id");
|
|
3163
|
+
if (!id) throw new Error("--skill-id is required");
|
|
3164
|
+
const bound = await binding(args), client = await verifiedClient(bound);
|
|
3165
|
+
printResult(await loadSkill(bound, client, id, value(args, "version-id"), !!args.flags.editable), !!args.flags.json);
|
|
3166
|
+
return 0;
|
|
3167
|
+
};
|
|
3168
|
+
var skillDelete = (args) => skillDisable(args, true);
|
|
3169
|
+
var skillDisable = async (args, deleteHistory = false) => {
|
|
3170
|
+
const id = value(args, "skill-id");
|
|
3171
|
+
if (!id) throw new Error("--skill-id is required");
|
|
3172
|
+
requireUuid(id);
|
|
3173
|
+
const bound = await binding(args);
|
|
3174
|
+
if (readSpool(bound).maintenance?.active) throw new Error("management_requires_user_instruction");
|
|
3175
|
+
const client = await verifiedClient(bound);
|
|
3176
|
+
const result = unbox(await client.delete("/v1/skills", {
|
|
3177
|
+
skill_id: id,
|
|
3178
|
+
...deleteHistory ? { delete_history: true } : {}
|
|
3179
|
+
}));
|
|
3180
|
+
if (result.skill_id !== id || result.deleted !== true) throw new Error("invalid_disable_response");
|
|
3181
|
+
await refreshManifest(bound, client);
|
|
3182
|
+
printResult(result, !!args.flags.json);
|
|
3183
|
+
return 0;
|
|
3184
|
+
};
|
|
3185
|
+
var skillRollback = async (args) => {
|
|
3186
|
+
const id = value(args, "skill-id"), version = value(args, "version-id"), base = value(args, "base-version-id");
|
|
3187
|
+
if (!id || !version || !base) throw new Error("rollback_requires_skill_version_and_base");
|
|
3188
|
+
[id, version, base].forEach(requireUuid);
|
|
3189
|
+
const reason = value(args, "revoke-reason");
|
|
3190
|
+
if (reason !== void 0 && (!reason.trim() || reason.length > 1e3)) throw new Error("invalid_revoke_reason");
|
|
3191
|
+
const bound = await binding(args);
|
|
3192
|
+
if (readSpool(bound).maintenance?.active) throw new Error("management_requires_user_instruction");
|
|
3193
|
+
const client = await verifiedClient(bound);
|
|
3194
|
+
const result = unbox(await client.postJson("/v1/skills/rollback", {
|
|
3195
|
+
skill_id: id,
|
|
3196
|
+
version_id: version,
|
|
3197
|
+
base_version_id: base,
|
|
3198
|
+
...reason ? { revoke_reason: reason } : {}
|
|
3199
|
+
}));
|
|
3200
|
+
if (result.skill_id !== id || result.version_id !== version || result.action !== "rollback") throw new Error("invalid_rollback_response");
|
|
3201
|
+
await refreshManifest(bound, client);
|
|
3202
|
+
printResult(result, !!args.flags.json);
|
|
3203
|
+
return 0;
|
|
3204
|
+
};
|
|
3205
|
+
var skillValidate = async (args) => {
|
|
3206
|
+
const path = args.positional[0];
|
|
3207
|
+
if (!path) throw new Error("package path is required");
|
|
3208
|
+
const pkg = await readPackage(resolve2(path));
|
|
3209
|
+
printResult({
|
|
3210
|
+
valid: true,
|
|
3211
|
+
validation_scope: "static_package",
|
|
3212
|
+
scripts_executed: false,
|
|
3213
|
+
bundle_hash: pkg.hash,
|
|
3214
|
+
bundle_size_bytes: pkg.zip.length,
|
|
3215
|
+
file_count: pkg.files.size,
|
|
3216
|
+
name: pkg.metadata.name,
|
|
3217
|
+
version: pkg.metadata.version
|
|
3218
|
+
}, !!args.flags.json);
|
|
3219
|
+
return 0;
|
|
3220
|
+
};
|
|
3221
|
+
var skillUpload = async (args) => {
|
|
3222
|
+
const path = args.positional[0];
|
|
3223
|
+
if (!path) throw new Error("package path is required");
|
|
3224
|
+
const skillId = value(args, "skill-id"), base = value(args, "base-version-id");
|
|
3225
|
+
if (!!skillId !== !!base) throw new Error("update_requires_skill_and_base_version");
|
|
3226
|
+
if (skillId) {
|
|
3227
|
+
requireUuid(skillId);
|
|
3228
|
+
requireUuid(base);
|
|
3229
|
+
}
|
|
3230
|
+
const pkg = await readPackage(resolve2(path));
|
|
3231
|
+
const bound = await binding(args), client = await verifiedClient(bound), root = skillRoot();
|
|
3232
|
+
const source = value(args, "source") ?? "import";
|
|
3233
|
+
if (source !== "import" && source !== "evolution") throw new Error("invalid_upload_source");
|
|
3234
|
+
if (readSpool(bound, root).maintenance?.active && source !== "evolution") throw new Error("maintenance_upload_requires_evolution_source");
|
|
3235
|
+
const body = {
|
|
3236
|
+
operation: skillId ? "update" : "create",
|
|
3237
|
+
bundle_hash: pkg.hash,
|
|
3238
|
+
bundle_size_bytes: pkg.zip.length,
|
|
3239
|
+
source,
|
|
3240
|
+
...skillId ? { skill_id: skillId, base_version_id: base } : {}
|
|
3241
|
+
};
|
|
3242
|
+
const index = join5("skill-evolution", bound.scope_key, "artifacts", `draft-${sha256(resolve2(path))}.json`);
|
|
3243
|
+
const result = await withStateLock(root, index, async () => {
|
|
3244
|
+
const previous = existsSync5(privatePath(root, index)) ? readState(root, index) : void 0;
|
|
3245
|
+
const same = previous && JSON.stringify(previous.body) === JSON.stringify(body);
|
|
3246
|
+
if (previous && !same) {
|
|
3247
|
+
const publicationPath = join5("skill-evolution", bound.scope_key, "artifacts", `upload-${previous.request_id}`, "publication.json");
|
|
3248
|
+
if (existsSync5(privatePath(root, publicationPath)) && !readState(root, publicationPath).result)
|
|
3249
|
+
throw new Error("previous_upload_unresolved_run_status_resume_before_changing_draft");
|
|
3250
|
+
}
|
|
3251
|
+
const requested = value(args, "request-id");
|
|
3252
|
+
if (same && requested && requested !== previous.request_id) throw new Error("retry_requires_original_request_id");
|
|
3253
|
+
const requestId = same ? previous.request_id : requested ?? randomUUID2();
|
|
3254
|
+
requireUuid(requestId);
|
|
3255
|
+
const receipt = join5("skill-evolution", bound.scope_key, "artifacts", `upload-${requestId}`, "publication.json");
|
|
3256
|
+
if (existsSync5(privatePath(root, receipt))) {
|
|
3257
|
+
const original = readState(root, receipt).input;
|
|
3258
|
+
if (JSON.stringify(original) !== JSON.stringify({ ...body, client_request_id: requestId })) throw new Error("idempotency_payload_mismatch");
|
|
3259
|
+
}
|
|
3260
|
+
writeState(root, index, { request_id: requestId, body });
|
|
3261
|
+
return publishPackage(bound, client, pkg, { ...body, client_request_id: requestId }, root);
|
|
3262
|
+
});
|
|
3263
|
+
printResult(result, !!args.flags.json);
|
|
3264
|
+
return 0;
|
|
3265
|
+
};
|
|
3266
|
+
var skillEvaluate = async (args) => {
|
|
3267
|
+
const file = args.positional[0];
|
|
3268
|
+
if (!file) throw new Error("evidence JSON path is required");
|
|
3269
|
+
const root = skillRoot(), bytes = readPrivate(resolve2(file, ".."), resolve2(file), 65536);
|
|
3270
|
+
const evidence = JSON.parse(bytes.toString("utf8"));
|
|
3271
|
+
if (!evidence || typeof evidence !== "object" || Array.isArray(evidence)) throw new Error("invalid_evidence");
|
|
3272
|
+
const bound = await binding(args), client = await verifiedClient(bound);
|
|
3273
|
+
const result = await submitManualEvaluation(bound, client, evidence, resolve2(file), value(args, "request-id"), root);
|
|
3274
|
+
printResult(result, !!args.flags.json);
|
|
3275
|
+
return 0;
|
|
3276
|
+
};
|
|
3277
|
+
var skillStatus = async (args) => {
|
|
3278
|
+
const root = skillRoot();
|
|
3279
|
+
let selected = value(args, "session");
|
|
3280
|
+
const sessionId = value(args, "session-id");
|
|
3281
|
+
if (sessionId !== void 0 && selected) throw new Error("session_and_session_id_are_mutually_exclusive");
|
|
3282
|
+
if (sessionId !== void 0 && !value(args, "agent")) throw new Error("--session-id requires --agent");
|
|
3283
|
+
const selection = sessionId !== void 0 ? await selectSkillSessions(sessionId, agentFromFlags(args.flags), root) : void 0;
|
|
3284
|
+
if (selection && (args.flags.remote || args.flags.resume || args.flags["event-id"])) {
|
|
3285
|
+
if (selection.bindings.length !== 1 || selection.unbound_session_ids.length) throw new Error("session_id_requires_unique_binding_use_session");
|
|
3286
|
+
selected = selection.bindings[0].id;
|
|
3287
|
+
args = { ...args, flags: { ...args.flags, session: selected } };
|
|
3288
|
+
}
|
|
3289
|
+
const event = value(args, "event-id");
|
|
3290
|
+
if (args.flags.remote && args.flags.resume) throw new Error("remote_and_resume_are_mutually_exclusive");
|
|
3291
|
+
if (!args.flags.resume && !event) {
|
|
3292
|
+
if (args.flags.remote && !selected) throw new Error("--remote requires --session");
|
|
3293
|
+
const bounds = selection?.bindings ?? (selected ? [getBinding(selected, root)] : statusBindings(root, value(args, "agent")));
|
|
3294
|
+
const sessions = bounds.map((bound2) => ({ ...localSkillStatus(bound2, root), ...selection?.host_chat_id ? { host_chat_id: selection.host_chat_id } : {} }));
|
|
3295
|
+
if (args.flags.remote) {
|
|
3296
|
+
const id = sessions[0]?.current?.event_id;
|
|
3297
|
+
if (id) Object.assign(sessions[0], { evaluation: unbox(await (await verifiedClient(bounds[0])).get("/v1/skill-evolution/evaluations", { event_id: id })) });
|
|
3298
|
+
else if (sessions[0]) Object.assign(sessions[0], { remote_status: "no_event_id" });
|
|
3299
|
+
}
|
|
3300
|
+
const result = { auth_scope: selected ? bounds[0].auth_scope : void 0, sessions, ...selection ? { requested_session_id: sessionId, unbound_session_ids: selection.unbound_session_ids } : {} };
|
|
3301
|
+
if (args.flags.json) printResult(result, true);
|
|
3302
|
+
else {
|
|
3303
|
+
if (!sessions.length) console.log("No Skill sessions found. Start a bound Agent conversation first.");
|
|
3304
|
+
if (selection?.host_chat_id) console.log(`QoderWork chat: ${selection.host_chat_id}`);
|
|
3305
|
+
for (const id of selection?.unbound_session_ids ?? []) console.log(`No ContextDB binding observed for session: ${id}`);
|
|
3306
|
+
for (const s of sessions) {
|
|
3307
|
+
console.log(`${s.binding_id} ${s.agent} session=${s.session_id}`);
|
|
3308
|
+
console.log(` Session: ${s.active === false ? "inactive" : s.active === true ? "active" : "unknown"}`);
|
|
3309
|
+
console.log(` Workspace: ${s.auth_scope.workspace_id} Member: ${s.auth_scope.member_id}`);
|
|
3310
|
+
console.log(` Pending buffer (clears after submission): ${s.buffer.distinct_tool_calls}/10 calls, ${s.buffer.bytes}/40960 bytes, ${s.buffered_events} events; ${s.buffer.waiting_reason}`);
|
|
3311
|
+
console.log(` Evaluate: ${s.current?.event_id ?? "no_event_id"}; request=${s.current?.request_id ?? "none"}; delivery=${s.current?.delivery ?? "none"}`);
|
|
3312
|
+
if ("evaluation" in s) console.log(` Server: ${JSON.stringify(s.evaluation)}`);
|
|
3313
|
+
for (const h of s.handoffs) console.log(` Handoff: ${h.event_id}; delivery=${h.delivery}; completion=${h.completion}; automatic_redelivery=false`);
|
|
3314
|
+
if (s.error) console.log(` Error: ${s.error}`);
|
|
3315
|
+
for (const d of s.dispositions) console.log(` Not evaluated: ${d.reason}; events=${d.event_count}, bytes=${d.buffer_bytes}; ${d.path}`);
|
|
3316
|
+
for (const p of s.publications) console.log(` Publication: ${p.request_id}; verified=${p.verified}; ${JSON.stringify(p.result ?? null)}; ${p.receipt_path}`);
|
|
3317
|
+
console.log(` Drafts (scope-wide): ${s.paths.drafts}`);
|
|
3318
|
+
for (const file of s.scope_drafts) console.log(` Scope draft: ${file}`);
|
|
3319
|
+
for (const e of s.submissions) console.log(` Frozen request: ${e.request_id}; ${e.distinct_tool_calls} calls, ${e.request_bytes} bytes, ${e.event_count} events; ${e.path}`);
|
|
3320
|
+
console.log(` Manifest: ${s.manifest.path} (${s.manifest.status})`);
|
|
3321
|
+
for (const v of s.loaded_versions) console.log(` Loaded: ${v.skill_id}@${v.version_id}; ${v.path}`);
|
|
3322
|
+
console.log(` State: ${s.paths.state}`);
|
|
3323
|
+
}
|
|
3324
|
+
}
|
|
3325
|
+
return 0;
|
|
3326
|
+
}
|
|
3327
|
+
if (args.flags.resume && !selected && !event) throw new Error("--resume requires --session");
|
|
3328
|
+
const bound = await binding(args);
|
|
3329
|
+
if (event) {
|
|
3330
|
+
if (!/^[a-zA-Z0-9_-]{1,128}$/.test(event)) throw new Error("invalid_event_id");
|
|
3331
|
+
printResult(unbox(await (await verifiedClient(bound)).get("/v1/skill-evolution/evaluations", { event_id: event })), !!args.flags.json);
|
|
3332
|
+
return 0;
|
|
3333
|
+
}
|
|
3334
|
+
const artifacts = join5("skill-evolution", bound.scope_key, "artifacts");
|
|
3335
|
+
if (existsSync5(privatePath(root, artifacts))) for (const name of readdirSync3(privatePath(root, artifacts))) {
|
|
3336
|
+
if (/^evaluation-[a-f0-9-]{36}\.json$/.test(name)) {
|
|
3337
|
+
const state = readState(root, join5(artifacts, name));
|
|
3338
|
+
if (state.binding_id === bound.id && !state.result) await submitManualEvaluation(
|
|
3339
|
+
bound,
|
|
3340
|
+
await verifiedClient(bound),
|
|
3341
|
+
state.evidence,
|
|
3342
|
+
"",
|
|
3343
|
+
state.evidence.client_request_id,
|
|
3344
|
+
root
|
|
3345
|
+
);
|
|
3346
|
+
} else if (/^upload-[a-f0-9-]{36}$/.test(name)) {
|
|
3347
|
+
const dir = join5(artifacts, name), state = readState(root, join5(dir, "publication.json"));
|
|
3348
|
+
if (state.binding_id !== bound.id || state.verified) continue;
|
|
3349
|
+
const client = await verifiedClient(bound);
|
|
3350
|
+
const pkg = await inspectZip(readPrivate(root, join5(dir, "bundle.zip"), MAX_ZIP), state.input.bundle_hash, state.input.bundle_size_bytes);
|
|
3351
|
+
await publishPackage(bound, client, pkg, state.input, root);
|
|
3352
|
+
}
|
|
3353
|
+
}
|
|
3354
|
+
await expireSessionEvidence(bound, root);
|
|
3355
|
+
await resumeSubmission(bound, root);
|
|
3356
|
+
return skillStatus({ positional: [], flags: { session: bound.id, ...args.flags.json ? { json: true } : {} } });
|
|
3357
|
+
};
|
|
3358
|
+
var skillPurge = async (args) => {
|
|
3359
|
+
const bound = await binding(args), root = skillRoot();
|
|
3360
|
+
if (args.flags.cache) {
|
|
3361
|
+
const cache = join5("skills", bound.scope_key, "cache");
|
|
3362
|
+
const eligible2 = existsSync5(privatePath(root, cache)) ? [cache] : [];
|
|
3363
|
+
if (args.flags.apply) await withStateLock(root, cache, async () => {
|
|
3364
|
+
rmSync2(privatePath(root, cache), { recursive: true, force: true });
|
|
3365
|
+
});
|
|
3366
|
+
printResult({ applied: !!args.flags.apply, eligible: eligible2, prerequisite: "Stop related sessions and transfers before --apply; drafts are preserved." }, !!args.flags.json);
|
|
3367
|
+
return 0;
|
|
3368
|
+
}
|
|
3369
|
+
const artifacts = join5("skill-evolution", bound.scope_key, "artifacts"), eligible = [];
|
|
3370
|
+
if (existsSync5(privatePath(root, artifacts))) for (const name of readdirSync3(privatePath(root, artifacts))) {
|
|
3371
|
+
if (!/^upload-[a-f0-9-]{36}$/.test(name)) continue;
|
|
3372
|
+
const dir = join5(artifacts, name), state = readState(root, join5(dir, "publication.json"));
|
|
3373
|
+
if (state.verified && existsSync5(privatePath(root, dir, "bundle.zip"))) eligible.push(name);
|
|
3374
|
+
}
|
|
3375
|
+
if (args.flags.apply) for (const name of eligible) await withStateLock(root, join5(artifacts, name), async () => {
|
|
3376
|
+
if (readState(root, join5(artifacts, name, "publication.json")).verified)
|
|
3377
|
+
rmSync2(privatePath(root, artifacts, name, "bundle.zip"), { force: true });
|
|
3378
|
+
});
|
|
3379
|
+
printResult({ applied: !!args.flags.apply, scope_key: bound.scope_key, eligible }, !!args.flags.json);
|
|
3380
|
+
return 0;
|
|
3381
|
+
};
|
|
3382
|
+
var skillRetryFeedback = async (args) => {
|
|
3383
|
+
const id = value(args, "session"), event = value(args, "event-id");
|
|
3384
|
+
if (!id || !event) throw new Error("retry-feedback requires --session and --event-id");
|
|
3385
|
+
await retryFeedback(getBinding(id), event);
|
|
3386
|
+
printResult({ event_id: event, queued_for_next_user_prompt: true, published: false }, !!args.flags.json);
|
|
3387
|
+
return 0;
|
|
3388
|
+
};
|
|
3389
|
+
|
|
2722
3390
|
// src/cli/debug-cli.ts
|
|
2723
3391
|
import {
|
|
2724
3392
|
readRecallTraces
|
|
@@ -2880,12 +3548,12 @@ async function debugRecall(args) {
|
|
|
2880
3548
|
import {
|
|
2881
3549
|
accessSync,
|
|
2882
3550
|
constants as fsConstants,
|
|
2883
|
-
existsSync as
|
|
3551
|
+
existsSync as existsSync6,
|
|
2884
3552
|
openAsBlob,
|
|
2885
3553
|
statSync as statSync2
|
|
2886
|
-
} from "fs";
|
|
2887
|
-
import { homedir as
|
|
2888
|
-
import { basename, extname, resolve as
|
|
3554
|
+
} from "node:fs";
|
|
3555
|
+
import { homedir as homedir3 } from "node:os";
|
|
3556
|
+
import { basename, extname, resolve as resolve3 } from "node:path";
|
|
2889
3557
|
|
|
2890
3558
|
// src/lib/review.ts
|
|
2891
3559
|
function unwrapReviewData(response, operation) {
|
|
@@ -2901,31 +3569,31 @@ function unwrapReviewData(response, operation) {
|
|
|
2901
3569
|
}
|
|
2902
3570
|
return box.data ?? null;
|
|
2903
3571
|
}
|
|
2904
|
-
function asRecord(
|
|
2905
|
-
return
|
|
3572
|
+
function asRecord(value2) {
|
|
3573
|
+
return value2 && typeof value2 === "object" && !Array.isArray(value2) ? value2 : void 0;
|
|
2906
3574
|
}
|
|
2907
3575
|
function pickString(record, field) {
|
|
2908
|
-
const
|
|
2909
|
-
return typeof
|
|
3576
|
+
const value2 = record[field];
|
|
3577
|
+
return typeof value2 === "string" ? value2 : "";
|
|
2910
3578
|
}
|
|
2911
3579
|
function pickNumber(record, field) {
|
|
2912
|
-
const
|
|
2913
|
-
return typeof
|
|
3580
|
+
const value2 = record[field];
|
|
3581
|
+
return typeof value2 === "number" && Number.isFinite(value2) ? value2 : void 0;
|
|
2914
3582
|
}
|
|
2915
3583
|
function pickBoolean(record, field) {
|
|
2916
|
-
const
|
|
2917
|
-
return typeof
|
|
3584
|
+
const value2 = record[field];
|
|
3585
|
+
return typeof value2 === "boolean" ? value2 : void 0;
|
|
2918
3586
|
}
|
|
2919
|
-
function parseEmbeddedJson(
|
|
2920
|
-
if (typeof
|
|
3587
|
+
function parseEmbeddedJson(value2) {
|
|
3588
|
+
if (typeof value2 !== "string" || value2.trim() === "") return void 0;
|
|
2921
3589
|
try {
|
|
2922
|
-
return JSON.parse(
|
|
3590
|
+
return JSON.parse(value2);
|
|
2923
3591
|
} catch {
|
|
2924
3592
|
return void 0;
|
|
2925
3593
|
}
|
|
2926
3594
|
}
|
|
2927
|
-
function countArrayEntries(
|
|
2928
|
-
return Array.isArray(
|
|
3595
|
+
function countArrayEntries(value2) {
|
|
3596
|
+
return Array.isArray(value2) ? value2.length : void 0;
|
|
2929
3597
|
}
|
|
2930
3598
|
function readReviewListData(data) {
|
|
2931
3599
|
const record = asRecord(data);
|
|
@@ -3000,8 +3668,8 @@ function minimalReviewDetail(raw) {
|
|
|
3000
3668
|
"human_action",
|
|
3001
3669
|
"created_at"
|
|
3002
3670
|
]) {
|
|
3003
|
-
const
|
|
3004
|
-
if (
|
|
3671
|
+
const value2 = pickString(r, field);
|
|
3672
|
+
if (value2) out[field] = value2;
|
|
3005
3673
|
}
|
|
3006
3674
|
for (const field of [
|
|
3007
3675
|
"confidence_score",
|
|
@@ -3009,12 +3677,12 @@ function minimalReviewDetail(raw) {
|
|
|
3009
3677
|
"noise_score",
|
|
3010
3678
|
"contradiction_score"
|
|
3011
3679
|
]) {
|
|
3012
|
-
const
|
|
3013
|
-
if (
|
|
3680
|
+
const value2 = pickNumber(r, field);
|
|
3681
|
+
if (value2 !== void 0) out[field] = value2;
|
|
3014
3682
|
}
|
|
3015
3683
|
for (const field of ["has_contradictions", "rewrite_needed"]) {
|
|
3016
|
-
const
|
|
3017
|
-
if (
|
|
3684
|
+
const value2 = pickBoolean(r, field);
|
|
3685
|
+
if (value2 !== void 0) out[field] = value2;
|
|
3018
3686
|
}
|
|
3019
3687
|
const conflictCount = countArrayEntries(parseEmbeddedJson(r.conflicts));
|
|
3020
3688
|
if (conflictCount !== void 0) out.conflict_count = conflictCount;
|
|
@@ -3174,7 +3842,7 @@ async function memoryAdd(args) {
|
|
|
3174
3842
|
fail(`memory add cannot use --image with --no-infer; image memory requires inference
|
|
3175
3843
|
${usage2}`, 2);
|
|
3176
3844
|
}
|
|
3177
|
-
const images = imageFlags.length > 0 ? await Promise.all(imageFlags.map((
|
|
3845
|
+
const images = imageFlags.length > 0 ? await Promise.all(imageFlags.map((value2) => loadImagePart(value2, usage2))) : [];
|
|
3178
3846
|
const ctx = buildContext(args);
|
|
3179
3847
|
const userId = args.flags["user-id"] ?? ctx.cfg.userId;
|
|
3180
3848
|
const metadata = parseMetadataFlags(args.flags["metadata"]);
|
|
@@ -3225,12 +3893,12 @@ async function memorySearch(args) {
|
|
|
3225
3893
|
const ctx = buildContext(args);
|
|
3226
3894
|
const userId = args.flags["user-id"] ?? ctx.cfg.userId;
|
|
3227
3895
|
const topK = numFlag(args.flags["top-k"], ctx.cfg.topK);
|
|
3228
|
-
const
|
|
3896
|
+
const threshold2 = numFlag(args.flags["threshold"], ctx.cfg.threshold);
|
|
3229
3897
|
const body = {
|
|
3230
3898
|
query,
|
|
3231
3899
|
user_id: userId,
|
|
3232
3900
|
top_k: topK,
|
|
3233
|
-
threshold
|
|
3901
|
+
threshold: threshold2
|
|
3234
3902
|
};
|
|
3235
3903
|
if (args.flags.knowledge) {
|
|
3236
3904
|
body.knowledge = { enable: true, top_k: ctx.cfg.knowledgeTopK };
|
|
@@ -3352,7 +4020,7 @@ async function memoryEntityCreate(args) {
|
|
|
3352
4020
|
};
|
|
3353
4021
|
addOptionalEntityFields(body, args);
|
|
3354
4022
|
const ctx = buildContext(args);
|
|
3355
|
-
if (![body.user_id, body.agent_id, body.app_id, body.run_id].some((
|
|
4023
|
+
if (![body.user_id, body.agent_id, body.app_id, body.run_id].some((value2) => typeof value2 === "string" && value2.trim() !== "")) {
|
|
3356
4024
|
body.user_id = ctx.cfg.userId;
|
|
3357
4025
|
}
|
|
3358
4026
|
const resp = await ctx.client.postJson("/v1/memories/entities", body);
|
|
@@ -3417,18 +4085,18 @@ function parseMetadataFlags(raw) {
|
|
|
3417
4085
|
}
|
|
3418
4086
|
return out;
|
|
3419
4087
|
}
|
|
3420
|
-
function stringFlag(
|
|
3421
|
-
return typeof
|
|
4088
|
+
function stringFlag(value2) {
|
|
4089
|
+
return typeof value2 === "string" ? value2 : void 0;
|
|
3422
4090
|
}
|
|
3423
|
-
function csvFlag(
|
|
3424
|
-
return typeof
|
|
4091
|
+
function csvFlag(value2) {
|
|
4092
|
+
return typeof value2 === "string" ? value2.split(",").map((item) => item.trim()).filter(Boolean) : [];
|
|
3425
4093
|
}
|
|
3426
|
-
function jsonStringArray(
|
|
3427
|
-
if (
|
|
3428
|
-
if (typeof
|
|
4094
|
+
function jsonStringArray(value2, name) {
|
|
4095
|
+
if (value2 === void 0) return [];
|
|
4096
|
+
if (typeof value2 !== "string") fail(`--${name} must be a JSON array of strings`, 2);
|
|
3429
4097
|
let parsed;
|
|
3430
4098
|
try {
|
|
3431
|
-
parsed = JSON.parse(
|
|
4099
|
+
parsed = JSON.parse(value2);
|
|
3432
4100
|
} catch {
|
|
3433
4101
|
fail(`--${name} must be a JSON array of strings`, 2);
|
|
3434
4102
|
}
|
|
@@ -3439,8 +4107,8 @@ function jsonStringArray(value, name) {
|
|
|
3439
4107
|
}
|
|
3440
4108
|
function addOptionalScopeFields(body, args) {
|
|
3441
4109
|
for (const [flag, field] of [["user-id", "user_id"], ["agent-id", "agent_id"], ["app-id", "app_id"], ["run-id", "run_id"]]) {
|
|
3442
|
-
const
|
|
3443
|
-
if (
|
|
4110
|
+
const value2 = stringFlag(args.flags[flag]);
|
|
4111
|
+
if (value2 !== void 0) body[field] = value2;
|
|
3444
4112
|
}
|
|
3445
4113
|
}
|
|
3446
4114
|
function addOptionalEntityFields(body, args) {
|
|
@@ -3452,8 +4120,8 @@ function addOptionalEntityFields(body, args) {
|
|
|
3452
4120
|
function repeatedFlagValues(args, name) {
|
|
3453
4121
|
const repeated = args.repeatedFlags?.[name];
|
|
3454
4122
|
if (repeated) return repeated;
|
|
3455
|
-
const
|
|
3456
|
-
return
|
|
4123
|
+
const value2 = args.flags[name];
|
|
4124
|
+
return value2 === void 0 ? [] : [value2];
|
|
3457
4125
|
}
|
|
3458
4126
|
async function loadImagePart(rawPath, usage2) {
|
|
3459
4127
|
if (typeof rawPath !== "string" || rawPath.trim() === "") {
|
|
@@ -3461,7 +4129,7 @@ async function loadImagePart(rawPath, usage2) {
|
|
|
3461
4129
|
${usage2}`, 2);
|
|
3462
4130
|
}
|
|
3463
4131
|
const path = expandLocalPath(rawPath);
|
|
3464
|
-
if (!
|
|
4132
|
+
if (!existsSync6(path)) fail(`image file not found: ${path}`, 2);
|
|
3465
4133
|
const stat = statSync2(path);
|
|
3466
4134
|
if (!stat.isFile()) fail(`image path is not a file: ${path}`, 2);
|
|
3467
4135
|
try {
|
|
@@ -3482,9 +4150,9 @@ ${usage2}`, 2);
|
|
|
3482
4150
|
}
|
|
3483
4151
|
function expandLocalPath(path) {
|
|
3484
4152
|
if (path === "~" || path.startsWith("~/")) {
|
|
3485
|
-
return
|
|
4153
|
+
return resolve3(homedir3(), path === "~" ? "" : path.slice(2));
|
|
3486
4154
|
}
|
|
3487
|
-
return
|
|
4155
|
+
return resolve3(path);
|
|
3488
4156
|
}
|
|
3489
4157
|
function imageMimeType(path) {
|
|
3490
4158
|
switch (extname(path).toLowerCase()) {
|
|
@@ -3501,7 +4169,7 @@ function imageMimeType(path) {
|
|
|
3501
4169
|
}
|
|
3502
4170
|
|
|
3503
4171
|
// src/cli/kb-cli.ts
|
|
3504
|
-
import { basename as basename2 } from "path";
|
|
4172
|
+
import { basename as basename2 } from "node:path";
|
|
3505
4173
|
var UPLOAD_TEXT_USAGE = "usage: ctxdb kb upload-text <kb-name> <doc-name> --text=<body> [--file-path=<server-logical-path>] [--review-enabled|--no-review-enabled] [--wait|--no-wait]";
|
|
3506
4174
|
var UPLOAD_FILE_USAGE = "usage: ctxdb kb upload-file <kb-name> <local-path> [--doc-name=...] [--file-path=<server-logical-path>] [--review-enabled|--no-review-enabled] [--wait|--no-wait]";
|
|
3507
4175
|
var UPDATE_TEXT_USAGE = "usage: ctxdb kb update-text <document-id> --text=<body> [--wait|--no-wait]\n or: ctxdb kb update-text --kb-name=<kb-name> --doc-name=<logical-name> --text=<body> [--file-path=<server-logical-path>] [--wait|--no-wait]";
|
|
@@ -3521,17 +4189,17 @@ var ENTITY_CHUNKS_USAGE = "usage: ctxdb kb entity-chunks --kb=<kb-id> --entity-i
|
|
|
3521
4189
|
var RELATIONS_USAGE = "usage: ctxdb kb relations [--kb=<kb-id>] [--entity-id=<id> | --entity-ids=<a,b>]\n [--relation-type=<t>] [--page=N] [--page-size=N]\n [--max-nodes=N] [--max-edges=N] [--verbose] [--raw] [--json]";
|
|
3522
4190
|
var UPDATE_LOCATOR_FLAGS = ["kb-name", "doc-name", "file-path"];
|
|
3523
4191
|
function nonEmptyFlag(args, name) {
|
|
3524
|
-
const
|
|
3525
|
-
return typeof
|
|
4192
|
+
const value2 = args.flags[name];
|
|
4193
|
+
return typeof value2 === "string" && value2.trim() !== "" ? value2 : void 0;
|
|
3526
4194
|
}
|
|
3527
4195
|
function optionalNonEmptyFlag(args, name, usage2) {
|
|
3528
4196
|
if (!Object.hasOwn(args.flags, name)) return void 0;
|
|
3529
|
-
const
|
|
3530
|
-
if (
|
|
4197
|
+
const value2 = nonEmptyFlag(args, name);
|
|
4198
|
+
if (value2 === void 0) {
|
|
3531
4199
|
fail(`--${name} must have a non-empty value
|
|
3532
4200
|
${usage2}`, 2);
|
|
3533
4201
|
}
|
|
3534
|
-
return
|
|
4202
|
+
return value2;
|
|
3535
4203
|
}
|
|
3536
4204
|
function hasAnyLocatorFlag(args) {
|
|
3537
4205
|
return UPDATE_LOCATOR_FLAGS.some((name) => Object.hasOwn(args.flags, name));
|
|
@@ -3603,10 +4271,10 @@ function parseKbLocator(args, usage2) {
|
|
|
3603
4271
|
function optionalNonNegativeInteger(args, name, usage2) {
|
|
3604
4272
|
const raw = args.flags[name];
|
|
3605
4273
|
if (raw === void 0) return void 0;
|
|
3606
|
-
const
|
|
3607
|
-
if (!Number.isInteger(
|
|
4274
|
+
const value2 = typeof raw === "string" ? Number(raw) : Number.NaN;
|
|
4275
|
+
if (!Number.isInteger(value2) || value2 < 0) fail(`--${name} must be a non-negative integer
|
|
3608
4276
|
${usage2}`, 2);
|
|
3609
|
-
return
|
|
4277
|
+
return value2;
|
|
3610
4278
|
}
|
|
3611
4279
|
function requiredIds(args, usage2) {
|
|
3612
4280
|
const raw = args.flags.ids;
|
|
@@ -3916,10 +4584,10 @@ function limitGraphRelations(result, maxNodes, maxEdges) {
|
|
|
3916
4584
|
if (!Array.isArray(graph.relations)) return result;
|
|
3917
4585
|
const nodeIds = /* @__PURE__ */ new Set();
|
|
3918
4586
|
const relations = [];
|
|
3919
|
-
for (const
|
|
4587
|
+
for (const value2 of graph.relations) {
|
|
3920
4588
|
if (maxEdges !== void 0 && relations.length >= maxEdges) break;
|
|
3921
|
-
if (!
|
|
3922
|
-
const relation =
|
|
4589
|
+
if (!value2 || typeof value2 !== "object") continue;
|
|
4590
|
+
const relation = value2;
|
|
3923
4591
|
const source = relation.source_entity_id;
|
|
3924
4592
|
const target = relation.target_entity_id;
|
|
3925
4593
|
if (typeof source !== "string" || typeof target !== "string") continue;
|
|
@@ -3927,7 +4595,7 @@ function limitGraphRelations(result, maxNodes, maxEdges) {
|
|
|
3927
4595
|
nextNodes.add(source);
|
|
3928
4596
|
nextNodes.add(target);
|
|
3929
4597
|
if (maxNodes !== void 0 && nextNodes.size > maxNodes) continue;
|
|
3930
|
-
relations.push(
|
|
4598
|
+
relations.push(value2);
|
|
3931
4599
|
nodeIds.add(source);
|
|
3932
4600
|
nodeIds.add(target);
|
|
3933
4601
|
}
|
|
@@ -3987,10 +4655,10 @@ async function kbSearch(args) {
|
|
|
3987
4655
|
return 0;
|
|
3988
4656
|
}
|
|
3989
4657
|
function positiveIntFlag(args, flagName, usage2) {
|
|
3990
|
-
const
|
|
3991
|
-
if (
|
|
3992
|
-
if (typeof
|
|
3993
|
-
const parsed = Number(
|
|
4658
|
+
const value2 = args.flags[flagName];
|
|
4659
|
+
if (value2 === void 0) return void 0;
|
|
4660
|
+
if (typeof value2 !== "string") fail(usage2, 2);
|
|
4661
|
+
const parsed = Number(value2);
|
|
3994
4662
|
if (!Number.isInteger(parsed) || parsed < 1) {
|
|
3995
4663
|
fail(`${flagName} must be a positive integer
|
|
3996
4664
|
${usage2}`, 2);
|
|
@@ -4109,11 +4777,11 @@ async function kbAcl(operation, args) {
|
|
|
4109
4777
|
throw new Error(`exactly one ${operation === "delete" ? "ACL" : "KB"} ID is required`);
|
|
4110
4778
|
}
|
|
4111
4779
|
const allowed = /* @__PURE__ */ new Set([...FLAGS[operation], "agent", "json", "raw"]);
|
|
4112
|
-
for (const [flag,
|
|
4780
|
+
for (const [flag, value2] of Object.entries(args.flags)) {
|
|
4113
4781
|
if (!allowed.has(flag)) throw new Error(`unknown --${flag}`);
|
|
4114
4782
|
if (flag === "agent" || flag === "json" || flag === "raw") continue;
|
|
4115
|
-
if (typeof
|
|
4116
|
-
values[flag.replaceAll("-", "_")] =
|
|
4783
|
+
if (typeof value2 !== "string" || !value2.trim()) throw new Error(`--${flag} requires a value`);
|
|
4784
|
+
values[flag.replaceAll("-", "_")] = value2.trim();
|
|
4117
4785
|
}
|
|
4118
4786
|
for (const [field, choices] of Object.entries({
|
|
4119
4787
|
principal_type: ["member", "group"],
|
|
@@ -4176,24 +4844,24 @@ var GRAPH_MUTATION_USAGE = {
|
|
|
4176
4844
|
var ENTITY_FIELDS = ["name", "type", "description", "aliases-json"];
|
|
4177
4845
|
var RELATION_FIELDS = ["relation-type", "description", "keywords-json", "weight"];
|
|
4178
4846
|
function stringFlag2(args, name, allowEmpty = false) {
|
|
4179
|
-
const
|
|
4180
|
-
if (typeof
|
|
4847
|
+
const value2 = args.flags[name];
|
|
4848
|
+
if (typeof value2 !== "string" || !allowEmpty && !value2.trim()) {
|
|
4181
4849
|
throw new Error(`--${name} requires ${allowEmpty ? "a string value (use --description='' to clear)" : "a non-empty value"}`);
|
|
4182
4850
|
}
|
|
4183
|
-
return
|
|
4851
|
+
return value2;
|
|
4184
4852
|
}
|
|
4185
4853
|
function stringArrayFlag(args, name) {
|
|
4186
4854
|
const text = stringFlag2(args, name);
|
|
4187
|
-
let
|
|
4855
|
+
let value2;
|
|
4188
4856
|
try {
|
|
4189
|
-
|
|
4857
|
+
value2 = JSON.parse(text);
|
|
4190
4858
|
} catch {
|
|
4191
4859
|
throw new Error(`--${name} must be a JSON array of strings (use '[]' to clear)`);
|
|
4192
4860
|
}
|
|
4193
|
-
if (!Array.isArray(
|
|
4861
|
+
if (!Array.isArray(value2) || !value2.every((item) => typeof item === "string")) {
|
|
4194
4862
|
throw new Error(`--${name} must be a JSON array of strings (use '[]' to clear)`);
|
|
4195
4863
|
}
|
|
4196
|
-
return
|
|
4864
|
+
return value2;
|
|
4197
4865
|
}
|
|
4198
4866
|
function parseMutation(args, resource, action) {
|
|
4199
4867
|
const idFlag = `${resource}-id`;
|
|
@@ -4208,9 +4876,9 @@ function parseMutation(args, resource, action) {
|
|
|
4208
4876
|
]
|
|
4209
4877
|
]);
|
|
4210
4878
|
if (args.positional.length) throw new Error("use explicit ID flags; positional locators are not supported");
|
|
4211
|
-
for (const [flag,
|
|
4879
|
+
for (const [flag, value2] of Object.entries(args.flags)) {
|
|
4212
4880
|
if (!allowed.has(flag)) throw new Error(`unknown --${flag}`);
|
|
4213
|
-
if (["yes", "json", "raw"].includes(flag) &&
|
|
4881
|
+
if (["yes", "json", "raw"].includes(flag) && value2 !== true) {
|
|
4214
4882
|
throw new Error(`--${flag} is a boolean switch; do not supply a value`);
|
|
4215
4883
|
}
|
|
4216
4884
|
}
|
|
@@ -4393,7 +5061,7 @@ ${GENERATE_USAGE}`, 2);
|
|
|
4393
5061
|
}) + "\n");
|
|
4394
5062
|
const deadline = Date.now() + 3e5;
|
|
4395
5063
|
while (data.status === "generating" && Date.now() < deadline) {
|
|
4396
|
-
await new Promise((
|
|
5064
|
+
await new Promise((resolve5) => setTimeout(resolve5, 1500));
|
|
4397
5065
|
data = unwrapBox(
|
|
4398
5066
|
await ctx.client.get("/v1/memory_promotions/detail", { promotion_id: promotionId }),
|
|
4399
5067
|
"memory promotion get"
|
|
@@ -4619,11 +5287,11 @@ ${SETTINGS_UPDATE_USAGE}`, 2);
|
|
|
4619
5287
|
}
|
|
4620
5288
|
body.auto_ingest_enabled = enabled === "true";
|
|
4621
5289
|
}
|
|
4622
|
-
const
|
|
4623
|
-
if (
|
|
4624
|
-
const n = Number(
|
|
5290
|
+
const threshold2 = stringFlag3(args, "auto-ingest-threshold");
|
|
5291
|
+
if (threshold2 !== void 0) {
|
|
5292
|
+
const n = Number(threshold2);
|
|
4625
5293
|
if (!Number.isFinite(n) || n < 0 || n > 1) {
|
|
4626
|
-
fail(`invalid --auto-ingest-threshold: ${
|
|
5294
|
+
fail(`invalid --auto-ingest-threshold: ${threshold2} (expected a number in [0,1])
|
|
4627
5295
|
${SETTINGS_UPDATE_USAGE}`, 2);
|
|
4628
5296
|
}
|
|
4629
5297
|
body.auto_ingest_threshold = n;
|
|
@@ -4646,14 +5314,14 @@ ${SETTINGS_UPDATE_USAGE}`, 2);
|
|
|
4646
5314
|
return 0;
|
|
4647
5315
|
}
|
|
4648
5316
|
function stringFlag3(args, name) {
|
|
4649
|
-
const
|
|
4650
|
-
return typeof
|
|
5317
|
+
const value2 = args.flags[name];
|
|
5318
|
+
return typeof value2 === "string" && value2.trim() !== "" ? value2 : void 0;
|
|
4651
5319
|
}
|
|
4652
5320
|
function requireIdFlag(args, name, usage2) {
|
|
4653
|
-
const
|
|
4654
|
-
if (
|
|
5321
|
+
const value2 = stringFlag3(args, name);
|
|
5322
|
+
if (value2 === void 0) fail(`--${name} is required
|
|
4655
5323
|
${usage2}`, 2);
|
|
4656
|
-
return
|
|
5324
|
+
return value2;
|
|
4657
5325
|
}
|
|
4658
5326
|
function requireTemplateIdPositional(args, usage2) {
|
|
4659
5327
|
const templateId = args.positional[0];
|
|
@@ -4806,8 +5474,8 @@ function batchExitCode(data) {
|
|
|
4806
5474
|
function pickFields(source, fields) {
|
|
4807
5475
|
const out = {};
|
|
4808
5476
|
for (const key of fields) {
|
|
4809
|
-
const
|
|
4810
|
-
if (
|
|
5477
|
+
const value2 = source[key];
|
|
5478
|
+
if (value2 !== void 0 && value2 !== null) out[key] = value2;
|
|
4811
5479
|
}
|
|
4812
5480
|
return out;
|
|
4813
5481
|
}
|
|
@@ -4847,7 +5515,7 @@ function compactTemplateList(data) {
|
|
|
4847
5515
|
}
|
|
4848
5516
|
|
|
4849
5517
|
// src/cli/review-cli.ts
|
|
4850
|
-
import { readFileSync as readFileSync2 } from "fs";
|
|
5518
|
+
import { readFileSync as readFileSync2 } from "node:fs";
|
|
4851
5519
|
var REVIEW_LIST_USAGE = "usage: ctxdb kb review list [--knowledge-base-id=<id>] [--decision=<d>]\n [--review-status=<pending|reviewed|rejected>]\n [--page=N] [--page-size=N] [--sort-by=confidence_score]\n [--sort-order=asc|desc] [--verbose] [--raw] [--json]";
|
|
4852
5520
|
var REVIEW_GET_USAGE = "usage: ctxdb kb review get <review-id> [--content-page=N] [--verbose] [--raw] [--json]";
|
|
4853
5521
|
var REVIEW_ACTION_USAGE = `usage: ctxdb kb review action <review-id> --action=<${REVIEW_ACTIONS.join("|")}>
|
|
@@ -4867,29 +5535,29 @@ var TEMPLATE_CLEAR_DEFAULT_USAGE2 = "usage: ctxdb kb review template clear-defau
|
|
|
4867
5535
|
var SETTINGS_GET_USAGE2 = "usage: ctxdb kb review settings get <knowledge-base-id> [--json]";
|
|
4868
5536
|
var SETTINGS_UPDATE_USAGE2 = "usage: ctxdb kb review settings update <knowledge-base-id>\n [--review-enabled | --no-review-enabled]\n [--high-threshold=F] [--logic-rewrite-threshold=F]\n [--noise-rewrite-threshold=F] [--max-rewrite-iterations=N]\n [--rewrite-enabled | --no-rewrite-enabled]\n [--conflict-detection-enabled | --no-conflict-detection-enabled]\n [--rewrite-auto-ingest-enabled | --no-rewrite-auto-ingest-enabled] [--json]";
|
|
4869
5537
|
function stringValue(args, name) {
|
|
4870
|
-
const
|
|
4871
|
-
return typeof
|
|
5538
|
+
const value2 = args.flags[name];
|
|
5539
|
+
return typeof value2 === "string" && value2.trim() !== "" ? value2 : void 0;
|
|
4872
5540
|
}
|
|
4873
5541
|
function requireId(args, flagName, positionalIndex, usage2) {
|
|
4874
5542
|
const positional2 = args.positional[positionalIndex]?.trim();
|
|
4875
|
-
const
|
|
4876
|
-
if (
|
|
4877
|
-
return
|
|
5543
|
+
const value2 = positional2 !== void 0 && positional2 !== "" ? positional2 : stringValue(args, flagName);
|
|
5544
|
+
if (value2 === void 0) fail(usage2, 2);
|
|
5545
|
+
return value2.trim();
|
|
4878
5546
|
}
|
|
4879
5547
|
function requireEnumFlag(args, flagName, allowed, usage2) {
|
|
4880
|
-
const
|
|
4881
|
-
if (
|
|
4882
|
-
if (!allowed.includes(
|
|
5548
|
+
const value2 = stringValue(args, flagName);
|
|
5549
|
+
if (value2 === void 0) fail(usage2, 2);
|
|
5550
|
+
if (!allowed.includes(value2)) {
|
|
4883
5551
|
fail(`${flagName} must be one of ${allowed.join("|")}
|
|
4884
5552
|
${usage2}`, 2);
|
|
4885
5553
|
}
|
|
4886
|
-
return
|
|
5554
|
+
return value2;
|
|
4887
5555
|
}
|
|
4888
5556
|
function positiveIntFlag2(args, flagName, usage2) {
|
|
4889
|
-
const
|
|
4890
|
-
if (
|
|
4891
|
-
if (typeof
|
|
4892
|
-
const parsed = Number(
|
|
5557
|
+
const value2 = args.flags[flagName];
|
|
5558
|
+
if (value2 === void 0) return void 0;
|
|
5559
|
+
if (typeof value2 !== "string") fail(usage2, 2);
|
|
5560
|
+
const parsed = Number(value2);
|
|
4893
5561
|
if (!Number.isInteger(parsed) || parsed < 1) {
|
|
4894
5562
|
fail(`${flagName} must be a positive integer
|
|
4895
5563
|
${usage2}`, 2);
|
|
@@ -5244,10 +5912,10 @@ ${SETTINGS_UPDATE_USAGE2}`, 2);
|
|
|
5244
5912
|
else if (off) body[field] = false;
|
|
5245
5913
|
}
|
|
5246
5914
|
for (const [flag, field, integer] of SETTINGS_NUMBER_FLAG_FIELDS) {
|
|
5247
|
-
const
|
|
5248
|
-
if (
|
|
5249
|
-
if (typeof
|
|
5250
|
-
const parsed = Number(
|
|
5915
|
+
const value2 = args.flags[flag];
|
|
5916
|
+
if (value2 === void 0) continue;
|
|
5917
|
+
if (typeof value2 !== "string") fail(SETTINGS_UPDATE_USAGE2, 2);
|
|
5918
|
+
const parsed = Number(value2);
|
|
5251
5919
|
if (!Number.isFinite(parsed) || integer && !Number.isInteger(parsed)) {
|
|
5252
5920
|
fail(`--${flag} must be ${integer ? "an integer" : "a number"}
|
|
5253
5921
|
${SETTINGS_UPDATE_USAGE2}`, 2);
|
|
@@ -5302,20 +5970,20 @@ function outputs(...extra) {
|
|
|
5302
5970
|
...extra
|
|
5303
5971
|
];
|
|
5304
5972
|
}
|
|
5305
|
-
function details(
|
|
5973
|
+
function details(value2) {
|
|
5306
5974
|
return {
|
|
5307
|
-
usage:
|
|
5308
|
-
positionals:
|
|
5309
|
-
options:
|
|
5310
|
-
constraints:
|
|
5311
|
-
outputModes:
|
|
5312
|
-
warnings:
|
|
5313
|
-
examples:
|
|
5314
|
-
notes:
|
|
5975
|
+
usage: value2.usage,
|
|
5976
|
+
positionals: value2.positionals ?? [],
|
|
5977
|
+
options: value2.options ?? [],
|
|
5978
|
+
constraints: value2.constraints ?? [],
|
|
5979
|
+
outputModes: value2.outputModes ?? outputs(),
|
|
5980
|
+
warnings: value2.warnings ?? [],
|
|
5981
|
+
examples: value2.examples,
|
|
5982
|
+
notes: value2.notes ?? []
|
|
5315
5983
|
};
|
|
5316
5984
|
}
|
|
5317
|
-
function leaf(name, summary, handler,
|
|
5318
|
-
return { kind: "command", name, aliases, summary, handler, ...
|
|
5985
|
+
function leaf(name, summary, handler, value2, aliases = []) {
|
|
5986
|
+
return { kind: "command", name, aliases, summary, handler, ...value2 };
|
|
5319
5987
|
}
|
|
5320
5988
|
function group(name, summary, children, aliases = []) {
|
|
5321
5989
|
return { kind: "group", name, aliases, summary, children };
|
|
@@ -5372,12 +6040,14 @@ function publicSetupSpec(managedCredentials) {
|
|
|
5372
6040
|
notes: managedCredentials ? [
|
|
5373
6041
|
"Without --agent, setup writes the CLI-only default profile and installs no Hooks or Skills.",
|
|
5374
6042
|
"Run ctxdb login before setup to create managed credentials.",
|
|
6043
|
+
"Codex setup does not grant hook trust: review only ContextDB hooks with /hooks or App Settings > Hooks. JSON includes the pending review action.",
|
|
5375
6044
|
"Hermes requires approval of pre_llm_call and post_llm_call with: hermes --accept-hooks chat"
|
|
5376
6045
|
] : [
|
|
5377
6046
|
"Without --agent, setup writes the CLI-only default profile and installs no Hooks or Skills.",
|
|
5378
6047
|
"Ordinary setup preserves existing authentication; a profile with no authentication may bind the default login.",
|
|
5379
6048
|
"Explicitly unbound, invalid, or conflicting authentication is not automatically replaced; use --login or --api-key to switch.",
|
|
5380
6049
|
"A shared login keeps its Core origin; --base-url cannot redirect its tokens to another origin.",
|
|
6050
|
+
"Codex setup does not grant hook trust: review only ContextDB hooks with /hooks or App Settings > Hooks. JSON includes the pending review action.",
|
|
5381
6051
|
"Hermes requires approval of pre_llm_call and post_llm_call with: hermes --accept-hooks chat"
|
|
5382
6052
|
],
|
|
5383
6053
|
examples: managedCredentials ? [
|
|
@@ -5536,7 +6206,116 @@ var debugGroup = group("debug", "Control and inspect local recall traces.", [
|
|
|
5536
6206
|
})
|
|
5537
6207
|
)
|
|
5538
6208
|
]);
|
|
5539
|
-
var
|
|
6209
|
+
var SKILL_SCOPE_OPTIONS = [
|
|
6210
|
+
option("--session", "Use an existing Skill session binding.", { valueName: "binding-id" }),
|
|
6211
|
+
AGENT_OPTION,
|
|
6212
|
+
JSON_OPTION
|
|
6213
|
+
];
|
|
6214
|
+
var SKILL_ID_OPTION = option("--skill-id", "Skill UUID.", { valueName: "id", required: true });
|
|
6215
|
+
var skillGroup = group("skill", "Install, discover, publish, and manage ContextDB Skills.", [
|
|
6216
|
+
leaf("bind", "Bind a session to the current member and refresh its Skill manifest.", skillBind, details({
|
|
6217
|
+
usage: ["ctxdb skill bind --session-id=<id> [--agent=<name>] [--json]"],
|
|
6218
|
+
options: [option("--session-id", "Agent session identifier.", { valueName: "id", required: true }), AGENT_OPTION, JSON_OPTION],
|
|
6219
|
+
examples: [{ command: "ctxdb skill bind --session-id=<session-id> --agent=codex --json" }]
|
|
6220
|
+
})),
|
|
6221
|
+
leaf("manifest", "Refresh the visible Skill manifest for this subject.", skillManifest, details({
|
|
6222
|
+
usage: ["ctxdb skill manifest [--session=<binding-id>] [--agent=<name>] [--json]"],
|
|
6223
|
+
options: SKILL_SCOPE_OPTIONS,
|
|
6224
|
+
examples: [{ command: "ctxdb skill manifest --session=<binding-id> --json" }]
|
|
6225
|
+
}), ["sync"]),
|
|
6226
|
+
leaf("list", "List active Skills visible to the current subject.", skillList, details({
|
|
6227
|
+
usage: ["ctxdb skill list [--session=<binding-id>] [--agent=<name>] [--json]"],
|
|
6228
|
+
options: SKILL_SCOPE_OPTIONS,
|
|
6229
|
+
notes: ["Refreshes the authoritative remote manifest; it does not fall back to stale cached permissions."],
|
|
6230
|
+
examples: [{ command: "ctxdb skill list --agent=qwenwork --json" }]
|
|
6231
|
+
})),
|
|
6232
|
+
leaf("config", "Read effective Skill configuration or change an Agent-local setting.", skillConfig, details({
|
|
6233
|
+
usage: [
|
|
6234
|
+
"ctxdb skill config [get [auto-skill-evolution]] [--session=<binding-id>] [--agent=<name>] [--json]",
|
|
6235
|
+
"ctxdb skill config set auto-skill-evolution <on|off> --agent=<name> [--json]",
|
|
6236
|
+
"ctxdb skill config unset auto-skill-evolution --agent=<name> [--json]"
|
|
6237
|
+
],
|
|
6238
|
+
positionals: [
|
|
6239
|
+
positional("action", "Optional operation: get, set, or unset.", false),
|
|
6240
|
+
positional("key", "Agent-local configuration key.", false),
|
|
6241
|
+
positional("value", "Configuration value; auto-skill-evolution accepts on or off.", false)
|
|
6242
|
+
],
|
|
6243
|
+
options: SKILL_SCOPE_OPTIONS,
|
|
6244
|
+
constraints: ["set and unset require --agent and cannot be combined with --session."],
|
|
6245
|
+
notes: ["Only auto-skill-evolution is locally writable. Service policy and thresholds remain read-only."],
|
|
6246
|
+
examples: [
|
|
6247
|
+
{ command: "ctxdb skill config --session=<binding-id> --json" },
|
|
6248
|
+
{ command: "ctxdb skill config set auto-skill-evolution off --agent=qwenwork --json" }
|
|
6249
|
+
]
|
|
6250
|
+
})),
|
|
6251
|
+
leaf("search", "Search remote Skills visible to the current subject.", skillSearch, details({
|
|
6252
|
+
usage: ["ctxdb skill search <query> [--top-k=<n>] [--session=<binding-id>] [--agent=<name>] [--json]"],
|
|
6253
|
+
positionals: [positional("query", "Search text, at most 512 Unicode code points.")],
|
|
6254
|
+
options: [option("--top-k", "Number of results, from 1 to 10.", { valueName: "n", type: "integer", default: 5 }), ...SKILL_SCOPE_OPTIONS],
|
|
6255
|
+
examples: [{ command: "ctxdb skill search 'validate JSONL' --top-k=5 --json" }]
|
|
6256
|
+
})),
|
|
6257
|
+
leaf("load", "Download and verify a Skill version, optionally creating an editable copy.", skillLoad, details({
|
|
6258
|
+
usage: ["ctxdb skill load --skill-id=<id> [--version-id=<id>] [--editable] [--session=<binding-id>] [--agent=<name>] [--json]"],
|
|
6259
|
+
options: [SKILL_ID_OPTION, option("--version-id", "Exact version UUID; omit to select the active version.", { valueName: "id" }), option("--editable", "Create an editable draft from the verified package.", { type: "boolean" }), ...SKILL_SCOPE_OPTIONS],
|
|
6260
|
+
examples: [{ command: "ctxdb skill load --skill-id=<skill-id> --version-id=<version-id> --json" }]
|
|
6261
|
+
})),
|
|
6262
|
+
leaf("disable", "Disable a private Skill while retaining its history.", skillDisable, details({
|
|
6263
|
+
usage: ["ctxdb skill disable --skill-id=<id> [--session=<binding-id>] [--agent=<name>] [--json]"],
|
|
6264
|
+
options: [SKILL_ID_OPTION, ...SKILL_SCOPE_OPTIONS],
|
|
6265
|
+
warnings: ["Requires an explicit user instruction; unavailable during automatic maintenance."],
|
|
6266
|
+
examples: [{ command: "ctxdb skill disable --skill-id=<skill-id> --json" }]
|
|
6267
|
+
})),
|
|
6268
|
+
leaf("delete", "Delete a private Skill and clean up its history and packages.", skillDelete, details({
|
|
6269
|
+
usage: ["ctxdb skill delete --skill-id=<id> [--session=<binding-id>] [--agent=<name>] [--json]"],
|
|
6270
|
+
options: [SKILL_ID_OPTION, ...SKILL_SCOPE_OPTIONS],
|
|
6271
|
+
warnings: ["Deletes historical packages. Requires an explicit user instruction; unavailable during automatic maintenance."],
|
|
6272
|
+
examples: [{ command: "ctxdb skill delete --skill-id=<skill-id> --json" }]
|
|
6273
|
+
})),
|
|
6274
|
+
leaf("rollback", "Activate a retained version using the expected current version.", skillRollback, details({
|
|
6275
|
+
usage: ["ctxdb skill rollback --skill-id=<id> --version-id=<target> --base-version-id=<current> [--revoke-reason=<reason>] [--session=<binding-id>] [--agent=<name>] [--json]"],
|
|
6276
|
+
options: [SKILL_ID_OPTION, option("--version-id", "Target version UUID.", { valueName: "target", required: true }), option("--base-version-id", "Expected active version UUID.", { valueName: "current", required: true }), option("--revoke-reason", "Optional nonblank reason, at most 1000 UTF-16 code units.", { valueName: "reason" }), ...SKILL_SCOPE_OPTIONS],
|
|
6277
|
+
warnings: ["Requires an explicit user instruction; unavailable during automatic maintenance."],
|
|
6278
|
+
examples: [{ command: "ctxdb skill rollback --skill-id=<skill-id> --version-id=<target> --base-version-id=<current> --json" }]
|
|
6279
|
+
})),
|
|
6280
|
+
leaf("validate", "Check local Skill package structure without executing scripts.", skillValidate, details({
|
|
6281
|
+
usage: ["ctxdb skill validate <path> [--json]"],
|
|
6282
|
+
positionals: [positional("path", "Skill package directory or ZIP path.", true, "path")],
|
|
6283
|
+
options: [JSON_OPTION],
|
|
6284
|
+
notes: ["Reports validation_scope=static_package and scripts_executed=false; does not establish semantic correctness."],
|
|
6285
|
+
examples: [{ command: "ctxdb skill validate ./my-skill --json" }]
|
|
6286
|
+
})),
|
|
6287
|
+
leaf("upload", "Publish a new Skill or update an existing Skill with Base validation.", skillUpload, details({
|
|
6288
|
+
usage: ["ctxdb skill upload <path> [--source=<import|evolution>] [--skill-id=<id> --base-version-id=<id>] [--request-id=<id>] [--session=<binding-id>] [--agent=<name>] [--json]"],
|
|
6289
|
+
positionals: [positional("path", "Skill package directory or ZIP path.", true, "path")],
|
|
6290
|
+
options: [option("--source", "Publication source.", { valueName: "source", choices: ["import", "evolution"], default: "import" }), option("--skill-id", "Existing Skill UUID for an update.", { valueName: "id" }), option("--base-version-id", "Expected active version UUID for an update.", { valueName: "id" }), option("--request-id", "Idempotency UUID; retries retain the original identifier.", { valueName: "id" }), ...SKILL_SCOPE_OPTIONS],
|
|
6291
|
+
constraints: ["Supply --skill-id and --base-version-id together, or omit both to create a Skill."],
|
|
6292
|
+
notes: ["Resolve unfinished uploads with skill status --resume before changing the draft."],
|
|
6293
|
+
examples: [{ command: "ctxdb skill upload ./my-skill --source=import --json" }]
|
|
6294
|
+
})),
|
|
6295
|
+
leaf("evaluate", "Submit an evidence JSON file for Skill evaluation.", skillEvaluate, details({
|
|
6296
|
+
usage: ["ctxdb skill evaluate <evidence.json> [--request-id=<id>] [--session=<binding-id>] [--agent=<name>] [--json]"],
|
|
6297
|
+
positionals: [positional("evidence.json", "Evidence JSON object file, at most 65536 bytes.", true, "path")],
|
|
6298
|
+
options: [option("--request-id", "Idempotency UUID for this evaluation.", { valueName: "id" }), ...SKILL_SCOPE_OPTIONS],
|
|
6299
|
+
examples: [{ command: "ctxdb skill evaluate ./evidence.json --session=<binding-id> --json" }]
|
|
6300
|
+
})),
|
|
6301
|
+
leaf("status", "Inspect Skill evaluation and publication state or resume unfinished work.", skillStatus, details({
|
|
6302
|
+
usage: ["ctxdb skill status [--remote | --resume] [--event-id=<id>] [--session=<binding-id> | --session-id=<agent-session-id>] [--agent=<name>] [--json]"],
|
|
6303
|
+
options: [option("--session-id", "Agent session ID; QoderWork on macOS/Windows also accepts its UI chat ID. Requires --agent; mutually exclusive with --session. Multiple matches require an explicit Binding ID for remote/recovery operations.", { valueName: "id" }), option("--remote", "Query the selected session current server event without resuming work.", { type: "boolean" }), option("--resume", "Resume unfinished evaluations and publications; --session restricts recovery to that binding.", { type: "boolean" }), option("--event-id", "Query one server evaluation event.", { valueName: "id" }), ...SKILL_SCOPE_OPTIONS],
|
|
6304
|
+
notes: ["Default is local read-only status; without a session selector lists bindings, optionally filtered by --agent. --session filters precisely.", "--remote and --resume require --session or a uniquely resolved --session-id and cannot be combined. With --event-id, queries that event only; --resume has no effect.", "--session-id resolves existing bindings only. QoderWork UI lookup requires Node 22.13+, 23.4+, or 24+ and reads its local SQLite database read-only; missing bindings are listed separately. It never creates a binding.", "Drafts are scope-wide. Local Load records do not prove Agent business reuse."],
|
|
6305
|
+
examples: [{ command: "ctxdb skill status --resume --session=<binding-id> --json" }]
|
|
6306
|
+
})),
|
|
6307
|
+
leaf("retry-feedback", "Explicitly re-deliver a retained evaluation on the next user prompt.", skillRetryFeedback, details({
|
|
6308
|
+
usage: ["ctxdb skill retry-feedback --session=<binding-id> --event-id=<id> [--json]"],
|
|
6309
|
+
options: [option("--event-id", "Retained evaluation ID.", { valueName: "id", required: true }), ...SKILL_SCOPE_OPTIONS],
|
|
6310
|
+
notes: ["Use only after explicit user authorization; stop related Agent activity first. Does not author, upload, or re-submit evidence.", "Refuses pending evaluations and existing or uncertain publications. Check status and permissions first; resume frozen uploads separately."],
|
|
6311
|
+
examples: [{ command: "ctxdb skill retry-feedback --session=<binding-id> --event-id=<id> --json" }]
|
|
6312
|
+
})),
|
|
6313
|
+
leaf("purge", "Preview or remove verified publication payloads or the Skill cache.", skillPurge, details({
|
|
6314
|
+
usage: ["ctxdb skill purge [--cache] [--apply] [--session=<binding-id>] [--agent=<name>] [--json]"],
|
|
6315
|
+
options: [option("--cache", "Select the downloaded Skill cache instead of verified upload payloads.", { type: "boolean" }), option("--apply", "Perform deletion; otherwise only preview eligible data.", { type: "boolean" }), ...SKILL_SCOPE_OPTIONS],
|
|
6316
|
+
warnings: ["Stop related sessions and transfers before applying cache deletion. Drafts and unfinished upload payloads are preserved."],
|
|
6317
|
+
examples: [{ command: "ctxdb skill purge --json" }, { command: "ctxdb skill purge --cache --apply --session=<binding-id> --json" }]
|
|
6318
|
+
})),
|
|
5540
6319
|
leaf(
|
|
5541
6320
|
"install",
|
|
5542
6321
|
"Install ContextDB Skills to a built-in Agent or custom directory.",
|
|
@@ -6537,8 +7316,8 @@ function findChild(parent, name) {
|
|
|
6537
7316
|
|
|
6538
7317
|
// src/cli/device-auth-cli.ts
|
|
6539
7318
|
import { AuthorizationService, publicAuthorizationTarget, oauthSessionCandidate, oauthSessionFromCredential } from "@aliyunrds/ctxdb-shared";
|
|
6540
|
-
import { dirname as dirname2, join as
|
|
6541
|
-
import { createInterface } from "readline/promises";
|
|
7319
|
+
import { dirname as dirname2, join as join6 } from "node:path";
|
|
7320
|
+
import { createInterface } from "node:readline/promises";
|
|
6542
7321
|
import {
|
|
6543
7322
|
CoreDeviceClient,
|
|
6544
7323
|
normalizeCoreOrigin as normalizeCoreOrigin2,
|
|
@@ -6559,12 +7338,12 @@ import {
|
|
|
6559
7338
|
} from "@aliyunrds/ctxdb-shared";
|
|
6560
7339
|
|
|
6561
7340
|
// src/lib/oauth-login-config.ts
|
|
6562
|
-
import { existsSync as
|
|
7341
|
+
import { existsSync as existsSync7, readFileSync as readFileSync3 } from "node:fs";
|
|
6563
7342
|
import { isOfficialProductionUrl, normalizeCoreOrigin } from "@aliyunrds/ctxdb-shared";
|
|
6564
7343
|
var PRODUCTION_AUTHORIZATION_URL = "https://rdsnext.console.aliyun.com/contextDbCliAuthorization/cn-hangzhou";
|
|
6565
|
-
function authorizationPage(
|
|
6566
|
-
if (typeof
|
|
6567
|
-
const url = new URL(
|
|
7344
|
+
function authorizationPage(value2) {
|
|
7345
|
+
if (typeof value2 !== "string" || !value2.trim()) throw new Error();
|
|
7346
|
+
const url = new URL(value2);
|
|
6568
7347
|
if (url.protocol !== "https:" || url.username || url.password || url.search || url.hash) throw new Error();
|
|
6569
7348
|
return url.toString();
|
|
6570
7349
|
}
|
|
@@ -6577,7 +7356,7 @@ function consoleAuthorizationBase(path, core, loginUrl) {
|
|
|
6577
7356
|
}
|
|
6578
7357
|
}
|
|
6579
7358
|
const fallback = isOfficialProductionUrl(core) ? PRODUCTION_AUTHORIZATION_URL : void 0;
|
|
6580
|
-
if (!
|
|
7359
|
+
if (!existsSync7(path)) return fallback;
|
|
6581
7360
|
try {
|
|
6582
7361
|
const raw = JSON.parse(readFileSync3(path, "utf8"));
|
|
6583
7362
|
if (raw.version !== 1 || !Array.isArray(raw.environments) || raw.environments.length > 32) throw new Error();
|
|
@@ -6591,8 +7370,8 @@ function consoleAuthorizationBase(path, core, loginUrl) {
|
|
|
6591
7370
|
}
|
|
6592
7371
|
|
|
6593
7372
|
// src/lib/open-browser.ts
|
|
6594
|
-
import { spawn } from "child_process";
|
|
6595
|
-
import { platform } from "os";
|
|
7373
|
+
import { spawn } from "node:child_process";
|
|
7374
|
+
import { platform } from "node:os";
|
|
6596
7375
|
function openBrowser(url) {
|
|
6597
7376
|
try {
|
|
6598
7377
|
const parsed = new URL(url);
|
|
@@ -6602,19 +7381,19 @@ function openBrowser(url) {
|
|
|
6602
7381
|
}
|
|
6603
7382
|
const os = platform();
|
|
6604
7383
|
const command = os === "darwin" ? { file: "open", args: [url] } : os === "win32" ? { file: "rundll32.exe", args: ["url.dll,FileProtocolHandler", url] } : { file: "xdg-open", args: [url] };
|
|
6605
|
-
return new Promise((
|
|
7384
|
+
return new Promise((resolve5) => {
|
|
6606
7385
|
try {
|
|
6607
7386
|
const child = spawn(command.file, command.args, { detached: true, stdio: "ignore", windowsHide: true, shell: false });
|
|
6608
|
-
const timer = setTimeout(() =>
|
|
7387
|
+
const timer = setTimeout(() => resolve5(true), 2e3);
|
|
6609
7388
|
const finish = (opened) => {
|
|
6610
7389
|
clearTimeout(timer);
|
|
6611
|
-
|
|
7390
|
+
resolve5(opened);
|
|
6612
7391
|
};
|
|
6613
7392
|
child.once("error", () => finish(false));
|
|
6614
7393
|
child.once("exit", (code) => finish(code === 0));
|
|
6615
7394
|
child.unref();
|
|
6616
7395
|
} catch {
|
|
6617
|
-
|
|
7396
|
+
resolve5(false);
|
|
6618
7397
|
}
|
|
6619
7398
|
});
|
|
6620
7399
|
}
|
|
@@ -6631,7 +7410,7 @@ function createPublicAuthCommands(dependencies = {}) {
|
|
|
6631
7410
|
});
|
|
6632
7411
|
const client = dependencies.client ?? ((url) => new CoreDeviceClient(url));
|
|
6633
7412
|
const launchBrowser = dependencies.openBrowser ?? openBrowser;
|
|
6634
|
-
const output = (
|
|
7413
|
+
const output = (value2, json) => stdout(json ? JSON.stringify(value2) + "\n" : String(value2) + "\n");
|
|
6635
7414
|
function options(args, command) {
|
|
6636
7415
|
const allowed = ["agent", "json", "help", "h", ...command === "login" ? ["base-url", "login-url", "server", "device-code", "no-browser", "login", "yes"] : command === "logout" ? ["login", "yes"] : command === "status" ? ["all"] : []];
|
|
6637
7416
|
if (args.positional.length || Object.keys(args.flags).some((k) => !allowed.includes(k))) throw new Error("Unsupported authentication option.");
|
|
@@ -6677,7 +7456,7 @@ function createPublicAuthCommands(dependencies = {}) {
|
|
|
6677
7456
|
const pending = beginLogin(path, agent, name);
|
|
6678
7457
|
await confirmImpact(name ? pending.users[0] ?? agent : agent, pending.users, args, "Reauthorizing this login");
|
|
6679
7458
|
const baseUrl = normalizeCoreOrigin2(explicitBase ?? DEFAULT_BASE_URL);
|
|
6680
|
-
const consoleBase = consoleAuthorizationBase(
|
|
7459
|
+
const consoleBase = consoleAuthorizationBase(join6(dirname2(path), "device-environments.json"), baseUrl, args.flags["login-url"]);
|
|
6681
7460
|
const connection = client(baseUrl), controller = new AbortController();
|
|
6682
7461
|
let browserOpening = Promise.resolve();
|
|
6683
7462
|
const interrupt = () => controller.abort();
|
|
@@ -6986,23 +7765,23 @@ function renderRows(rows, indent = " ") {
|
|
|
6986
7765
|
return rows.map(([label, description]) => `${indent}${label.padEnd(width)} ${description}
|
|
6987
7766
|
`).join("");
|
|
6988
7767
|
}
|
|
6989
|
-
function optionLabel(
|
|
6990
|
-
const valuePart =
|
|
7768
|
+
function optionLabel(value2) {
|
|
7769
|
+
const valuePart = value2.valueName ? ` <${value2.valueName}>` : "";
|
|
6991
7770
|
const annotations = [
|
|
6992
|
-
|
|
6993
|
-
|
|
7771
|
+
value2.required ? "required" : "",
|
|
7772
|
+
value2.repeatable ? "repeatable" : ""
|
|
6994
7773
|
].filter(Boolean);
|
|
6995
|
-
return `${
|
|
7774
|
+
return `${value2.name}${valuePart}${annotations.length ? ` (${annotations.join("; ")})` : ""}`;
|
|
6996
7775
|
}
|
|
6997
|
-
function optionDescription(
|
|
7776
|
+
function optionDescription(value2) {
|
|
6998
7777
|
const details2 = [
|
|
6999
|
-
|
|
7000
|
-
|
|
7778
|
+
value2.default !== void 0 ? `Default: ${String(value2.default)}.` : "",
|
|
7779
|
+
value2.choices?.length ? `Choices: ${value2.choices.join("|")}.` : ""
|
|
7001
7780
|
].filter(Boolean);
|
|
7002
|
-
return `${
|
|
7781
|
+
return `${value2.description}${details2.length ? ` ${details2.join(" ")}` : ""}`;
|
|
7003
7782
|
}
|
|
7004
|
-
function positionalLabel(
|
|
7005
|
-
return `${
|
|
7783
|
+
function positionalLabel(value2) {
|
|
7784
|
+
return `${value2.name} <${value2.type}> (${value2.required ? "required" : "optional"})`;
|
|
7006
7785
|
}
|
|
7007
7786
|
function renderExamples(examples) {
|
|
7008
7787
|
return examples.map(
|
|
@@ -7052,7 +7831,7 @@ function renderListSection(title, values) {
|
|
|
7052
7831
|
if (values.length === 0) return "";
|
|
7053
7832
|
return `
|
|
7054
7833
|
${title}
|
|
7055
|
-
${values.map((
|
|
7834
|
+
${values.map((value2) => ` ${value2}
|
|
7056
7835
|
`).join("")}`;
|
|
7057
7836
|
}
|
|
7058
7837
|
function renderLeaf(leaf2, path) {
|
|
@@ -7062,11 +7841,11 @@ USAGE
|
|
|
7062
7841
|
${leaf2.usage.map((usage2) => ` ${usage2}
|
|
7063
7842
|
`).join("")}
|
|
7064
7843
|
ARGUMENTS
|
|
7065
|
-
${renderRows(leaf2.positionals.map((
|
|
7844
|
+
${renderRows(leaf2.positionals.map((value2) => [positionalLabel(value2), value2.description]))}
|
|
7066
7845
|
OPTIONS
|
|
7067
|
-
${renderRows(leaf2.options.map((
|
|
7846
|
+
${renderRows(leaf2.options.map((value2) => [optionLabel(value2), optionDescription(value2)]))}` + renderListSection("CONSTRAINTS", leaf2.constraints) + `
|
|
7068
7847
|
OUTPUT
|
|
7069
|
-
${renderRows(leaf2.outputModes.map((
|
|
7848
|
+
${renderRows(leaf2.outputModes.map((value2) => [value2.name, value2.description]))}` + renderListSection("NOTES", leaf2.notes) + renderListSection("WARNINGS", leaf2.warnings) + `
|
|
7070
7849
|
EXAMPLES
|
|
7071
7850
|
${renderExamples(leaf2.examples)}`;
|
|
7072
7851
|
}
|
|
@@ -7098,15 +7877,15 @@ function serializeNode(command, path, recursive) {
|
|
|
7098
7877
|
return {
|
|
7099
7878
|
...base,
|
|
7100
7879
|
usage: [...serializable.usage],
|
|
7101
|
-
positionals: serializable.positionals.map((
|
|
7102
|
-
options: serializable.options.map((
|
|
7103
|
-
...
|
|
7104
|
-
...
|
|
7880
|
+
positionals: serializable.positionals.map((value2) => ({ ...value2 })),
|
|
7881
|
+
options: serializable.options.map((value2) => ({
|
|
7882
|
+
...value2,
|
|
7883
|
+
...value2.choices ? { choices: [...value2.choices] } : {}
|
|
7105
7884
|
})),
|
|
7106
7885
|
constraints: [...serializable.constraints],
|
|
7107
|
-
outputModes: serializable.outputModes.map((
|
|
7886
|
+
outputModes: serializable.outputModes.map((value2) => ({ ...value2 })),
|
|
7108
7887
|
warnings: [...serializable.warnings],
|
|
7109
|
-
examples: serializable.examples.map((
|
|
7888
|
+
examples: serializable.examples.map((value2) => ({ ...value2 })),
|
|
7110
7889
|
notes: [...serializable.notes]
|
|
7111
7890
|
};
|
|
7112
7891
|
}
|
|
@@ -7165,8 +7944,8 @@ function resolvePath(root, tokens) {
|
|
|
7165
7944
|
}
|
|
7166
7945
|
return { node, path, consumed, parent };
|
|
7167
7946
|
}
|
|
7168
|
-
function isUnknown(
|
|
7169
|
-
return "group" in
|
|
7947
|
+
function isUnknown(value2) {
|
|
7948
|
+
return "group" in value2;
|
|
7170
7949
|
}
|
|
7171
7950
|
function writeUnknown(unknown, root, version) {
|
|
7172
7951
|
const scope = unknown.path.length === 1 ? "command" : "subcommand";
|
|
@@ -7295,8 +8074,8 @@ function runMain(root = COMMAND_TREE) {
|
|
|
7295
8074
|
}
|
|
7296
8075
|
var directEntry = (() => {
|
|
7297
8076
|
try {
|
|
7298
|
-
const modulePath =
|
|
7299
|
-
const argvPath =
|
|
8077
|
+
const modulePath = resolve4(fileURLToPath2(import.meta.url));
|
|
8078
|
+
const argvPath = resolve4(process.argv[1] ?? "");
|
|
7300
8079
|
return modulePath === argvPath || realpathSync(modulePath) === realpathSync(argvPath);
|
|
7301
8080
|
} catch {
|
|
7302
8081
|
return false;
|