@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/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-T5ZJEPR4.js";
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
- writeInstalledPkgVersion
64
- } from "../chunk-2U7G6UXE.js";
65
- import {
66
- beginUpdateNotification,
67
- completeUpdateNotification,
68
- runSelfUpdate
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 resolve3 } from "path";
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, value) => {
159
- flags[name] = value;
196
+ const setFlag = (name, value2) => {
197
+ flags[name] = value2;
160
198
  if (REPEATABLE_FLAGS.has(name)) {
161
- (repeatedFlags[name] ??= []).push(value);
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 value = v;
235
- return value.mode === "all" && (value.operation === "setup" || value.operation === "status") && typeof value.agents === "object" && value.agents !== null && Array.isArray(value.skipped) && typeof value.summary === "object" && value.summary !== null;
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(value, json, command) {
392
+ function printResult(value2, json, command) {
346
393
  if (json) {
347
- process.stdout.write(JSON.stringify(value, null, 2) + "\n");
348
- } else if (isMultiAgentResult(value)) {
349
- process.stdout.write(formatMultiAgentResult(value) + "\n");
350
- } else if (isUpgradeResult(value)) {
351
- process.stdout.write(formatUpgradeResult(value) + "\n");
352
- } else if (isSetupResult(value)) {
353
- process.stdout.write(formatSetupResult(value, command ?? "setup") + "\n");
354
- } else if (isStatusResult(value)) {
355
- process.stdout.write(formatStatusResult(value) + "\n");
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(value) + "\n");
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(value) {
1757
- return `'${value.replace(/'/g, `'\\''`)}'`;
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 value = stripped.split("=", 2)[1]?.trim();
1964
- if (value === "true") return { kind: "already-enabled" };
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 '${value}' via dotted-key \u2014 please set it to true manually`
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 value = kv[1].trim();
1993
- if (value === "true") return { kind: "already-enabled" };
1994
- if (value === "false") return { kind: "features-with-hooks-false" };
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 '${value}' \u2014 please set it to true manually`
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" ? [CODEX_HOOKS_TRUST_REMINDER] : []];
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 existsSync2,
3551
+ existsSync as existsSync6,
2884
3552
  openAsBlob,
2885
3553
  statSync as statSync2
2886
- } from "fs";
2887
- import { homedir as homedir2 } from "os";
2888
- import { basename, extname, resolve as resolve2 } from "path";
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(value) {
2905
- return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
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 value = record[field];
2909
- return typeof value === "string" ? value : "";
3576
+ const value2 = record[field];
3577
+ return typeof value2 === "string" ? value2 : "";
2910
3578
  }
2911
3579
  function pickNumber(record, field) {
2912
- const value = record[field];
2913
- return typeof value === "number" && Number.isFinite(value) ? value : void 0;
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 value = record[field];
2917
- return typeof value === "boolean" ? value : void 0;
3584
+ const value2 = record[field];
3585
+ return typeof value2 === "boolean" ? value2 : void 0;
2918
3586
  }
2919
- function parseEmbeddedJson(value) {
2920
- if (typeof value !== "string" || value.trim() === "") return void 0;
3587
+ function parseEmbeddedJson(value2) {
3588
+ if (typeof value2 !== "string" || value2.trim() === "") return void 0;
2921
3589
  try {
2922
- return JSON.parse(value);
3590
+ return JSON.parse(value2);
2923
3591
  } catch {
2924
3592
  return void 0;
2925
3593
  }
2926
3594
  }
2927
- function countArrayEntries(value) {
2928
- return Array.isArray(value) ? value.length : void 0;
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 value = pickString(r, field);
3004
- if (value) out[field] = value;
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 value = pickNumber(r, field);
3013
- if (value !== void 0) out[field] = value;
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 value = pickBoolean(r, field);
3017
- if (value !== void 0) out[field] = value;
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((value) => loadImagePart(value, usage2))) : [];
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 threshold = numFlag(args.flags["threshold"], ctx.cfg.threshold);
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((value) => typeof value === "string" && value.trim() !== "")) {
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(value) {
3421
- return typeof value === "string" ? value : void 0;
4088
+ function stringFlag(value2) {
4089
+ return typeof value2 === "string" ? value2 : void 0;
3422
4090
  }
3423
- function csvFlag(value) {
3424
- return typeof value === "string" ? value.split(",").map((item) => item.trim()).filter(Boolean) : [];
4091
+ function csvFlag(value2) {
4092
+ return typeof value2 === "string" ? value2.split(",").map((item) => item.trim()).filter(Boolean) : [];
3425
4093
  }
3426
- function jsonStringArray(value, name) {
3427
- if (value === void 0) return [];
3428
- if (typeof value !== "string") fail(`--${name} must be a JSON array of strings`, 2);
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(value);
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 value = stringFlag(args.flags[flag]);
3443
- if (value !== void 0) body[field] = value;
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 value = args.flags[name];
3456
- return value === void 0 ? [] : [value];
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 (!existsSync2(path)) fail(`image file not found: ${path}`, 2);
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 resolve2(homedir2(), path === "~" ? "" : path.slice(2));
4153
+ return resolve3(homedir3(), path === "~" ? "" : path.slice(2));
3486
4154
  }
3487
- return resolve2(path);
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 value = args.flags[name];
3525
- return typeof value === "string" && value.trim() !== "" ? value : void 0;
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 value = nonEmptyFlag(args, name);
3530
- if (value === void 0) {
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 value;
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 value = typeof raw === "string" ? Number(raw) : Number.NaN;
3607
- if (!Number.isInteger(value) || value < 0) fail(`--${name} must be a non-negative integer
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 value;
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 value of graph.relations) {
4587
+ for (const value2 of graph.relations) {
3920
4588
  if (maxEdges !== void 0 && relations.length >= maxEdges) break;
3921
- if (!value || typeof value !== "object") continue;
3922
- const relation = value;
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(value);
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 value = args.flags[flagName];
3991
- if (value === void 0) return void 0;
3992
- if (typeof value !== "string") fail(usage2, 2);
3993
- const parsed = Number(value);
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, value] of Object.entries(args.flags)) {
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 value !== "string" || !value.trim()) throw new Error(`--${flag} requires a value`);
4116
- values[flag.replaceAll("-", "_")] = value.trim();
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 value = args.flags[name];
4180
- if (typeof value !== "string" || !allowEmpty && !value.trim()) {
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 value;
4851
+ return value2;
4184
4852
  }
4185
4853
  function stringArrayFlag(args, name) {
4186
4854
  const text = stringFlag2(args, name);
4187
- let value;
4855
+ let value2;
4188
4856
  try {
4189
- value = JSON.parse(text);
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(value) || !value.every((item) => typeof item === "string")) {
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 value;
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, value] of Object.entries(args.flags)) {
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) && value !== true) {
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((resolve4) => setTimeout(resolve4, 1500));
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 threshold = stringFlag3(args, "auto-ingest-threshold");
4623
- if (threshold !== void 0) {
4624
- const n = Number(threshold);
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: ${threshold} (expected a number in [0,1])
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 value = args.flags[name];
4650
- return typeof value === "string" && value.trim() !== "" ? value : void 0;
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 value = stringFlag3(args, name);
4654
- if (value === void 0) fail(`--${name} is required
5321
+ const value2 = stringFlag3(args, name);
5322
+ if (value2 === void 0) fail(`--${name} is required
4655
5323
  ${usage2}`, 2);
4656
- return value;
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 value = source[key];
4810
- if (value !== void 0 && value !== null) out[key] = value;
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 value = args.flags[name];
4871
- return typeof value === "string" && value.trim() !== "" ? value : void 0;
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 value = positional2 !== void 0 && positional2 !== "" ? positional2 : stringValue(args, flagName);
4876
- if (value === void 0) fail(usage2, 2);
4877
- return value.trim();
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 value = stringValue(args, flagName);
4881
- if (value === void 0) fail(usage2, 2);
4882
- if (!allowed.includes(value)) {
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 value;
5554
+ return value2;
4887
5555
  }
4888
5556
  function positiveIntFlag2(args, flagName, usage2) {
4889
- const value = args.flags[flagName];
4890
- if (value === void 0) return void 0;
4891
- if (typeof value !== "string") fail(usage2, 2);
4892
- const parsed = Number(value);
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 value = args.flags[flag];
5248
- if (value === void 0) continue;
5249
- if (typeof value !== "string") fail(SETTINGS_UPDATE_USAGE2, 2);
5250
- const parsed = Number(value);
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(value) {
5973
+ function details(value2) {
5306
5974
  return {
5307
- usage: value.usage,
5308
- positionals: value.positionals ?? [],
5309
- options: value.options ?? [],
5310
- constraints: value.constraints ?? [],
5311
- outputModes: value.outputModes ?? outputs(),
5312
- warnings: value.warnings ?? [],
5313
- examples: value.examples,
5314
- notes: value.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, value, aliases = []) {
5318
- return { kind: "command", name, aliases, summary, handler, ...value };
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 skillGroup = group("skill", "Install ContextDB Skill files without configuring Hooks.", [
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 join2 } from "path";
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 existsSync3, readFileSync as readFileSync3 } from "fs";
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(value) {
6566
- if (typeof value !== "string" || !value.trim()) throw new Error();
6567
- const url = new URL(value);
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 (!existsSync3(path)) return fallback;
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((resolve4) => {
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(() => resolve4(true), 2e3);
7387
+ const timer = setTimeout(() => resolve5(true), 2e3);
6609
7388
  const finish = (opened) => {
6610
7389
  clearTimeout(timer);
6611
- resolve4(opened);
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
- resolve4(false);
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 = (value, json) => stdout(json ? JSON.stringify(value) + "\n" : String(value) + "\n");
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(join2(dirname2(path), "device-environments.json"), baseUrl, args.flags["login-url"]);
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(value) {
6990
- const valuePart = value.valueName ? ` <${value.valueName}>` : "";
7768
+ function optionLabel(value2) {
7769
+ const valuePart = value2.valueName ? ` <${value2.valueName}>` : "";
6991
7770
  const annotations = [
6992
- value.required ? "required" : "",
6993
- value.repeatable ? "repeatable" : ""
7771
+ value2.required ? "required" : "",
7772
+ value2.repeatable ? "repeatable" : ""
6994
7773
  ].filter(Boolean);
6995
- return `${value.name}${valuePart}${annotations.length ? ` (${annotations.join("; ")})` : ""}`;
7774
+ return `${value2.name}${valuePart}${annotations.length ? ` (${annotations.join("; ")})` : ""}`;
6996
7775
  }
6997
- function optionDescription(value) {
7776
+ function optionDescription(value2) {
6998
7777
  const details2 = [
6999
- value.default !== void 0 ? `Default: ${String(value.default)}.` : "",
7000
- value.choices?.length ? `Choices: ${value.choices.join("|")}.` : ""
7778
+ value2.default !== void 0 ? `Default: ${String(value2.default)}.` : "",
7779
+ value2.choices?.length ? `Choices: ${value2.choices.join("|")}.` : ""
7001
7780
  ].filter(Boolean);
7002
- return `${value.description}${details2.length ? ` ${details2.join(" ")}` : ""}`;
7781
+ return `${value2.description}${details2.length ? ` ${details2.join(" ")}` : ""}`;
7003
7782
  }
7004
- function positionalLabel(value) {
7005
- return `${value.name} <${value.type}> (${value.required ? "required" : "optional"})`;
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((value) => ` ${value}
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((value) => [positionalLabel(value), value.description]))}
7844
+ ${renderRows(leaf2.positionals.map((value2) => [positionalLabel(value2), value2.description]))}
7066
7845
  OPTIONS
7067
- ${renderRows(leaf2.options.map((value) => [optionLabel(value), optionDescription(value)]))}` + renderListSection("CONSTRAINTS", leaf2.constraints) + `
7846
+ ${renderRows(leaf2.options.map((value2) => [optionLabel(value2), optionDescription(value2)]))}` + renderListSection("CONSTRAINTS", leaf2.constraints) + `
7068
7847
  OUTPUT
7069
- ${renderRows(leaf2.outputModes.map((value) => [value.name, value.description]))}` + renderListSection("NOTES", leaf2.notes) + renderListSection("WARNINGS", leaf2.warnings) + `
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((value) => ({ ...value })),
7102
- options: serializable.options.map((value) => ({
7103
- ...value,
7104
- ...value.choices ? { choices: [...value.choices] } : {}
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((value) => ({ ...value })),
7886
+ outputModes: serializable.outputModes.map((value2) => ({ ...value2 })),
7108
7887
  warnings: [...serializable.warnings],
7109
- examples: serializable.examples.map((value) => ({ ...value })),
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(value) {
7169
- return "group" in value;
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 = resolve3(fileURLToPath2(import.meta.url));
7299
- const argvPath = resolve3(process.argv[1] ?? "");
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;