@aliyunrds/ctxdb 1.0.7 → 1.0.8-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
@@ -16,11 +16,13 @@ import {
16
16
  uploadFile,
17
17
  uploadText,
18
18
  validateLocalFile
19
- } from "../chunk-QVXDI77N.js";
19
+ } from "../chunk-CAXRYH6E.js";
20
20
  import {
21
+ CtxdbError,
21
22
  DEFAULT_BASE_URL,
22
23
  DEFAULT_USER_ID,
23
24
  HttpClient,
25
+ PACKAGE_NAME,
24
26
  PACKAGE_VERSION,
25
27
  SUPPORTED_AGENTS,
26
28
  agentFromEnv,
@@ -39,12 +41,16 @@ import {
39
41
  save,
40
42
  updateConfiguredDebug,
41
43
  writeInstalledPkgVersion
42
- } from "../chunk-S5W4FQ7M.js";
44
+ } from "../chunk-AAZLOCVB.js";
43
45
  import {
44
46
  beginUpdateNotification,
45
47
  completeUpdateNotification,
46
48
  runSelfUpdate
47
- } from "../chunk-Z6OHSEF2.js";
49
+ } from "../chunk-ULAWTBBC.js";
50
+ import {
51
+ DISTRIBUTION_MANIFEST
52
+ } from "../chunk-R67JELM7.js";
53
+ import "../chunk-VIG4SYLU.js";
48
54
 
49
55
  // src/cli/util.ts
50
56
  var BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
@@ -55,6 +61,8 @@ var BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
55
61
  // setup / init
56
62
  "no-install-skill",
57
63
  "no-validate",
64
+ "no-browser",
65
+ "device-code",
58
66
  // update / upgrade
59
67
  "self-update",
60
68
  "no-self-update",
@@ -78,8 +86,34 @@ var BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
78
86
  // memory search / kb search (three-tier projection)
79
87
  "raw",
80
88
  // kb search / memory search --knowledge (W3 compaction bypass)
81
- "full"
89
+ "full",
82
90
  // debug recall full-content human output
91
+ // promotion
92
+ "is-default",
93
+ // promotion template create / update
94
+ "clear-default-kb",
95
+ // promotion settings update (clears with an empty string)
96
+ // review
97
+ "default",
98
+ // review template create/update --default
99
+ "no-default",
100
+ // review template update --no-default
101
+ "review-enabled",
102
+ // review settings update
103
+ "no-review-enabled",
104
+ // review settings update
105
+ "rewrite-enabled",
106
+ // review settings update
107
+ "no-rewrite-enabled",
108
+ // review settings update
109
+ "conflict-detection-enabled",
110
+ // review settings update
111
+ "no-conflict-detection-enabled",
112
+ // review settings update
113
+ "rewrite-auto-ingest-enabled",
114
+ // review settings update
115
+ "no-rewrite-auto-ingest-enabled"
116
+ // review settings update
83
117
  ]);
84
118
  function parseArgs(argv, booleanFlags = BOOLEAN_FLAGS) {
85
119
  const positional = [];
@@ -306,7 +340,9 @@ function fail(message, code = 1) {
306
340
  }
307
341
 
308
342
  // src/cli/main.ts
343
+ import { realpathSync } from "fs";
309
344
  import { fileURLToPath as fileURLToPath2 } from "url";
345
+ import { basename as basename2, resolve as resolve2 } from "path";
310
346
 
311
347
  // src/setup/installer.ts
312
348
  import {
@@ -327,8 +363,9 @@ import { join, dirname, resolve } from "path";
327
363
  import { fileURLToPath } from "url";
328
364
  import { execFileSync } from "child_process";
329
365
  import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
330
- var UNINSTALL_NPM_HINT = "To also remove the npm binaries: `npm uninstall -g @aliyunrds/ctxdb @aliyunrds/ctxdb-shared`";
331
- var UNINSTALL_ORDER_HINT = "When you eventually want to uninstall: run `ctxdb uninstall --purge-all` FIRST, then `npm uninstall -g @aliyunrds/ctxdb @aliyunrds/ctxdb-shared`. (npm 7+ removed uninstall lifecycle hooks, so the order matters \u2014 otherwise agent settings.json hooks + ~/.ctxdb/ residue stay behind.)";
366
+ var PACKAGE_UNINSTALL_TARGETS = DISTRIBUTION_MANIFEST.id === "internal" ? DISTRIBUTION_MANIFEST.packageName : `${PACKAGE_NAME} @aliyunrds/ctxdb-shared`;
367
+ var UNINSTALL_NPM_HINT = `To also remove the npm binaries: \`npm uninstall -g ${PACKAGE_UNINSTALL_TARGETS}\``;
368
+ var UNINSTALL_ORDER_HINT = `When you eventually want to uninstall: run \`ctxdb uninstall --purge-all\` FIRST, then \`npm uninstall -g ${PACKAGE_UNINSTALL_TARGETS}\`. (npm 7+ removed uninstall lifecycle hooks, so the order matters \u2014 otherwise agent settings.json hooks + ~/.ctxdb/ residue stay behind.)`;
332
369
  var HERMES_RESTART_HINT = "Restart any running Hermes CLI or gateway process to load the registered hooks; Hermes registers shell hooks only at process startup.";
333
370
  var HERMES_ALLOWLIST_ACTION_HINT = "Next action [hermes-hook-allowlist]: run `hermes --accept-hooks chat`; after Hermes starts, exit the chat and rerun `ctxdb setup --agent hermes`, then restart any running Hermes CLI or gateway process.";
334
371
  var HERMES_WEBUI_GATEWAY_HINT = "Using hermes-webui? Its default legacy backend does not load Hermes shell hooks. Set `HERMES_WEBUI_CHAT_BACKEND=gateway` to route chat through Hermes Gateway; if the gateway requires authentication, also set `HERMES_WEBUI_GATEWAY_API_KEY`, then restart hermes-webui. Reference: https://github.com/nesquena/hermes-webui/blob/master/docs/advanced-chat-setup.md#gateway-backed-browser-chat";
@@ -349,6 +386,8 @@ function skillInstallRoot(agent) {
349
386
  return join(homedir(), ".config", "opencode", "skills");
350
387
  case "hermes":
351
388
  return join(homedir(), ".hermes", "skills");
389
+ case "workbuddy":
390
+ return join(homedir(), ".workbuddy", "skills");
352
391
  }
353
392
  }
354
393
  var SKILL_DIRS = ["contextdb-memory", "contextdb-knowledge"];
@@ -369,6 +408,8 @@ function hookConfigPath(agent) {
369
408
  return join(homedir(), ".codex", "hooks.json");
370
409
  case "claude":
371
410
  return join(homedir(), ".claude", "settings.json");
411
+ case "workbuddy":
412
+ return join(homedir(), ".workbuddy", "settings.json");
372
413
  case "opencode":
373
414
  case "hermes":
374
415
  return null;
@@ -424,6 +465,7 @@ async function runSetup(options) {
424
465
  existingAgentHomes = inspectAgentHomes(agent).existing;
425
466
  }
426
467
  const cfg = load({ agent });
468
+ const persistedCredentialConfig = options.persistCredential === false ? load({ agent, env: {}, managedCredentials: false }) : null;
427
469
  if (options.apiKey) cfg.apiKey = options.apiKey;
428
470
  if (options.baseUrl) cfg.baseUrl = options.baseUrl.replace(/\/+$/, "");
429
471
  else if (!cfg.baseUrl) cfg.baseUrl = DEFAULT_BASE_URL;
@@ -436,19 +478,38 @@ async function runSetup(options) {
436
478
  });
437
479
  return { ok: false, steps };
438
480
  }
439
- save(cfg, void 0, { agent });
481
+ const omitApiKey = options.persistCredential === false;
482
+ const persistedCfg = omitApiKey ? {
483
+ ...cfg,
484
+ apiKey: null,
485
+ baseUrl: persistedCredentialConfig?.baseUrl ?? DEFAULT_BASE_URL
486
+ } : cfg;
487
+ save(persistedCfg, void 0, { agent, omitApiKey });
440
488
  steps.push({
441
489
  step: "write-config",
442
490
  ok: true,
443
491
  detail: `${agent}: ${cfg.baseUrl} (user_id=${cfg.userId})`
444
492
  });
445
- if (isBuiltinAgent(agent) && !configuredAgents().includes("default")) {
446
- save(cfg, void 0, { agent: "default" });
447
- steps.push({
448
- step: "write-default-config",
449
- ok: true,
450
- detail: `default: copied from ${agent}`
451
- });
493
+ if (isBuiltinAgent(agent)) {
494
+ const hasDefault = configuredAgents().includes("default");
495
+ if (!hasDefault) {
496
+ save(persistedCfg, void 0, { agent: "default", omitApiKey });
497
+ steps.push({
498
+ step: "write-default-config",
499
+ ok: true,
500
+ detail: `default: copied from ${agent}`
501
+ });
502
+ } else if (omitApiKey) {
503
+ const persistedDefault = load({
504
+ agent: "default",
505
+ env: {},
506
+ managedCredentials: false
507
+ });
508
+ save(persistedDefault, void 0, {
509
+ agent: "default",
510
+ omitApiKey: true
511
+ });
512
+ }
452
513
  }
453
514
  if (installSkill && isBuiltinAgent(agent) && existingAgentHomes.includes(agentHomeDir(agent))) {
454
515
  const installRoot = skillInstallRoot(agent);
@@ -758,6 +819,7 @@ async function runSetupAll(options = {}, dependencies = {}) {
758
819
  apiKey,
759
820
  baseUrl: options.baseUrl ?? existing.baseUrl,
760
821
  userId: options.userId ?? existing.userId,
822
+ persistCredential: options.persistCredential,
761
823
  installSkill: options.installSkill,
762
824
  validate: options.validate
763
825
  }));
@@ -1308,9 +1370,13 @@ function stripCtxdbHooks(agent) {
1308
1370
  if (!path) return 0;
1309
1371
  return stripCtxdbHooksFromFile(path);
1310
1372
  }
1373
+ var CTXDB_PACKAGE_NAMES = [
1374
+ "@aliyunrds/ctxdb",
1375
+ "@ali/ctxdb-internal"
1376
+ ];
1311
1377
  function locateHookPaths() {
1312
1378
  const here = dirname(fileURLToPath(import.meta.url));
1313
- const pkgRoot = walkUpToPackageJson(here, "@aliyunrds/ctxdb");
1379
+ const pkgRoot = walkUpToPackageJson(here, CTXDB_PACKAGE_NAMES);
1314
1380
  if (!pkgRoot) return null;
1315
1381
  const preferSrc = here.includes("/src/") || here.includes("\\src\\");
1316
1382
  if (preferSrc) {
@@ -1344,7 +1410,7 @@ function hookPathsFromDir(dir, ext) {
1344
1410
  }
1345
1411
  function locateSkillDir(variant) {
1346
1412
  const here = dirname(fileURLToPath(import.meta.url));
1347
- const pkgRoot = walkUpToPackageJson(here, "@aliyunrds/ctxdb");
1413
+ const pkgRoot = walkUpToPackageJson(here, CTXDB_PACKAGE_NAMES);
1348
1414
  if (!pkgRoot) return null;
1349
1415
  const preferSrc = here.includes("/src/") || here.includes("\\src\\");
1350
1416
  if (preferSrc) {
@@ -1358,13 +1424,14 @@ function locateSkillDir(variant) {
1358
1424
  return null;
1359
1425
  }
1360
1426
  function walkUpToPackageJson(start, expectedName) {
1427
+ const expectedNames = Array.isArray(expectedName) ? expectedName : [expectedName];
1361
1428
  let cur = start;
1362
1429
  for (let i = 0; i < 8; i++) {
1363
1430
  const p = join(cur, "package.json");
1364
1431
  if (existsSync(p)) {
1365
1432
  try {
1366
1433
  const pkg = JSON.parse(readFileSync(p, "utf-8"));
1367
- if (pkg.name === expectedName) return cur;
1434
+ if (expectedNames.includes(pkg.name)) return cur;
1368
1435
  } catch {
1369
1436
  }
1370
1437
  }
@@ -1403,7 +1470,8 @@ var SKILL_INSTALL_TARGETS = {
1403
1470
  claude: join(homedir(), ".claude", "skills"),
1404
1471
  opencode: join(homedir(), ".config", "opencode", "skills"),
1405
1472
  openclaw: join(homedir(), ".openclaw", "skills"),
1406
- hermes: join(homedir(), ".hermes", "skills")
1473
+ hermes: join(homedir(), ".hermes", "skills"),
1474
+ workbuddy: join(homedir(), ".workbuddy", "skills")
1407
1475
  };
1408
1476
  function skillInstallTargetPath(target) {
1409
1477
  return SKILL_INSTALL_TARGETS[target] ?? null;
@@ -1467,7 +1535,7 @@ function opencodeBundlePath() {
1467
1535
  }
1468
1536
  function resolveOpencodePluginEntry() {
1469
1537
  const here = dirname(fileURLToPath(import.meta.url));
1470
- const pkgRoot = walkUpToPackageJson(here, "@aliyunrds/ctxdb");
1538
+ const pkgRoot = walkUpToPackageJson(here, CTXDB_PACKAGE_NAMES);
1471
1539
  if (!pkgRoot) return null;
1472
1540
  const candidates = [
1473
1541
  join(pkgRoot, "dist", "opencode", "index.js"),
@@ -1508,7 +1576,7 @@ var LEGACY_MARKER_VALUES = ["@aliyunrds/ctxdb-qoder"];
1508
1576
  var TOOL_SCOPED_EVENTS = /* @__PURE__ */ new Set(["PreToolUse", "PostToolUse"]);
1509
1577
  function appendOne(hooks, event, command, agent) {
1510
1578
  if (!Array.isArray(hooks[event])) hooks[event] = [];
1511
- const useExecForm = agent === "claude";
1579
+ const useExecForm = agent === "claude" || agent === "workbuddy";
1512
1580
  const cmdRunner = agent === "qoder";
1513
1581
  const shellCmd = process.platform === "win32" ? cmdRunner ? `node ${command.replace(/\\/g, "/")} --agent=${agent}` : `"${process.execPath.replace(/\\/g, "/")}" "${command.replace(/\\/g, "/")}" --agent=${agent}` : `${process.execPath} ${command} --agent=${agent}`;
1514
1582
  const dup = hooks[event].some(
@@ -1997,6 +2065,7 @@ async function runUpgrade(options = {}) {
1997
2065
  for (const agent of agents) {
1998
2066
  results[agent] = await runSetup({
1999
2067
  agent,
2068
+ persistCredential: options.persistCredential,
2000
2069
  // Updating local package artifacts must not depend on service
2001
2070
  // connectivity. Users can run `ctxdb ping` separately.
2002
2071
  validate: false
@@ -2200,20 +2269,49 @@ function parseAgent(args) {
2200
2269
  }
2201
2270
  async function setup(args) {
2202
2271
  if (args.flags.help || args.flags.h) {
2203
- process.stdout.write(HELP);
2272
+ process.stdout.write(
2273
+ DISTRIBUTION_MANIFEST.capabilities.managedCredentials ? HELP.replace(
2274
+ " [--api-key=K] [--base-url=URL] [--user-id=ID]",
2275
+ " [--user-id=ID]"
2276
+ ).replace(
2277
+ " Rerun for a new Agent, to repair integration files, or\n with --api-key <new-key> to replace that Agent's key.\n",
2278
+ " Rerun after ctxdb login to add or repair Agent integration files.\n"
2279
+ ).replace(
2280
+ " --api-key <key> API key (required on first setup)\n",
2281
+ ""
2282
+ ).replace(
2283
+ " --base-url <url> Server URL (default: https://context-database.aliyuncs.com)\n",
2284
+ ""
2285
+ ) : HELP
2286
+ );
2204
2287
  return 0;
2205
2288
  }
2206
2289
  const json = !!args.flags.json;
2207
2290
  const all = args.flags.all === true;
2291
+ const explicitApiKey = typeof args.flags["api-key"] === "string" ? args.flags["api-key"] : void 0;
2292
+ if (DISTRIBUTION_MANIFEST.capabilities.managedCredentials && explicitApiKey) {
2293
+ process.stderr.write(
2294
+ "--api-key is not supported by this distribution; use ctxdb login so the credential is stored in credentials.json\n"
2295
+ );
2296
+ return 2;
2297
+ }
2298
+ if (DISTRIBUTION_MANIFEST.capabilities.managedCredentials && typeof args.flags["base-url"] === "string") {
2299
+ process.stderr.write(
2300
+ "--base-url is not supported by this distribution; use ctxdb login --server so the DATA URL is supplied by the login service\n"
2301
+ );
2302
+ return 2;
2303
+ }
2304
+ const persistCredential = !DISTRIBUTION_MANIFEST.capabilities.managedCredentials;
2208
2305
  if (all && args.flags.agent !== void 0) {
2209
2306
  process.stderr.write("cannot use --all and --agent together\n");
2210
2307
  return 2;
2211
2308
  }
2212
2309
  if (all) {
2213
2310
  const result2 = await runSetupAll({
2214
- apiKey: typeof args.flags["api-key"] === "string" ? args.flags["api-key"] : void 0,
2311
+ apiKey: explicitApiKey,
2215
2312
  baseUrl: typeof args.flags["base-url"] === "string" ? args.flags["base-url"] : void 0,
2216
2313
  userId: typeof args.flags["user-id"] === "string" ? args.flags["user-id"] : void 0,
2314
+ persistCredential,
2217
2315
  installSkill: !args.flags["no-install-skill"],
2218
2316
  validate: !args.flags["no-validate"]
2219
2317
  });
@@ -2243,9 +2341,10 @@ ${highlightInlineCode(hint)}
2243
2341
  }
2244
2342
  const result = await runSetup({
2245
2343
  agent,
2246
- apiKey: typeof args.flags["api-key"] === "string" ? args.flags["api-key"] : void 0,
2344
+ apiKey: explicitApiKey,
2247
2345
  baseUrl: typeof args.flags["base-url"] === "string" ? args.flags["base-url"] : void 0,
2248
2346
  userId: typeof args.flags["user-id"] === "string" ? args.flags["user-id"] : void 0,
2347
+ persistCredential,
2249
2348
  installSkill: !args.flags["no-install-skill"],
2250
2349
  validate: !args.flags["no-validate"]
2251
2350
  });
@@ -2264,6 +2363,7 @@ ${highlightInlineCode(h)}
2264
2363
  }
2265
2364
 
2266
2365
  // src/cli/teardown.ts
2366
+ var PACKAGE_UNINSTALL_TARGETS2 = DISTRIBUTION_MANIFEST.id === "internal" ? DISTRIBUTION_MANIFEST.packageName : `${PACKAGE_NAME} @aliyunrds/ctxdb-shared`;
2267
2367
  var HELP2 = `ctxdb uninstall \u2014 remove hooks + skills
2268
2368
 
2269
2369
  USAGE
@@ -2287,7 +2387,7 @@ FLAGS
2287
2387
 
2288
2388
  NOTE
2289
2389
  Does not run \`npm uninstall\`. After uninstall completes, remove the
2290
- npm package separately: npm uninstall -g @aliyunrds/ctxdb @aliyunrds/ctxdb-shared
2390
+ npm package separately: npm uninstall -g ${PACKAGE_UNINSTALL_TARGETS2}
2291
2391
  `;
2292
2392
  function uninstall(args) {
2293
2393
  if (args.flags.help || args.flags.h) {
@@ -2328,13 +2428,15 @@ ${h}
2328
2428
  }
2329
2429
 
2330
2430
  // src/cli/upgrade.ts
2431
+ var UPDATE_PACKAGE_NAME = DISTRIBUTION_MANIFEST.packageName || PACKAGE_NAME;
2432
+ var UPDATE_REGISTRY_ARG = DISTRIBUTION_MANIFEST.packageRegistry ? ` --registry ${DISTRIBUTION_MANIFEST.packageRegistry}` : "";
2331
2433
  var HELP3 = `ctxdb upgrade \u2014 refresh skills + hooks
2332
2434
 
2333
2435
  USAGE
2334
2436
  ctxdb upgrade [--agent <qoder|qoderwork|qwenwork|codex|claude|opencode|hermes>] [--no-self-update] [--json]
2335
2437
 
2336
2438
  BEHAVIOR
2337
- Pulls the latest @aliyunrds/ctxdb package from npm, then re-runs setup
2439
+ Pulls the latest ${UPDATE_PACKAGE_NAME} package from npm, then re-runs setup
2338
2440
  for configured agents using their existing credentials.
2339
2441
 
2340
2442
  Without --agent: sets up all configured built-in agents.
@@ -2346,7 +2448,9 @@ FLAGS
2346
2448
  --no-self-update Skip the npm package update and only re-run setup
2347
2449
  --json Machine-readable JSON output
2348
2450
  `;
2349
- var MANUAL_UPDATE_HINT = "Automatic update failed. Please run manually:\n npm install -g @aliyunrds/ctxdb\n ctxdb setup";
2451
+ var MANUAL_UPDATE_HINT = `Automatic update failed. Please run manually:
2452
+ npm install -g ${UPDATE_PACKAGE_NAME}${UPDATE_REGISTRY_ARG}
2453
+ ctxdb setup`;
2350
2454
  function printUpdateFailure(error, json) {
2351
2455
  if (json) {
2352
2456
  process.stdout.write(JSON.stringify({ ok: false, error, hint: MANUAL_UPDATE_HINT }) + "\n");
@@ -2392,7 +2496,10 @@ async function upgrade(args) {
2392
2496
  process.stderr.write("nothing to upgrade for default agent (no hooks or skills)\n");
2393
2497
  return 0;
2394
2498
  }
2395
- const result = await runUpgrade({ agent: agentFlag });
2499
+ const result = await runUpgrade({
2500
+ agent: agentFlag,
2501
+ persistCredential: !DISTRIBUTION_MANIFEST.capabilities.managedCredentials
2502
+ });
2396
2503
  if (result.ok) {
2397
2504
  try {
2398
2505
  writeInstalledPkgVersion(PACKAGE_VERSION);
@@ -2993,6 +3100,1195 @@ async function debugRecall(args) {
2993
3100
  return 0;
2994
3101
  }
2995
3102
 
3103
+ // src/cli/promotion-cli.ts
3104
+ var GENERATE_USAGE = "usage: ctxdb memory promotion generate <topic> [--knowledge-base-id=<kb-id>] [--agent=<name>] [--json]";
3105
+ var LIST_USAGE = "usage: ctxdb memory promotion list [--status=<generating|pending_review|approving|approved|rejected|generation_failed>] [--page=N] [--page-size=N] [--sort-by=quality_score] [--sort-order=asc|desc] [--raw] [--agent=<name>] [--json]";
3106
+ var GET_USAGE = "usage: ctxdb memory promotion get <promotion-id> [--raw] [--agent=<name>] [--json]";
3107
+ var APPROVE_USAGE = "usage: ctxdb memory promotion approve --promotion-id=<id> --knowledge-base-id=<kb-id> [--agent=<name>] [--json]";
3108
+ var REJECT_USAGE = "usage: ctxdb memory promotion reject --promotion-id=<id> [--reason=<text>] [--agent=<name>] [--json]";
3109
+ var BATCH_ACTION_USAGE = "usage: ctxdb memory promotion batch-action --action=<approve|reject> --ids=<id1,id2,...> [--knowledge-base-id=<kb-id> (required for approve)] [--reason=<text>] [--agent=<name>] [--json]";
3110
+ var BATCH_DELETE_USAGE = "usage: ctxdb memory promotion batch-delete --ids=<id1,id2,...> [--agent=<name>] [--json]";
3111
+ var RESOLVE_DOUBTS_USAGE = `usage: ctxdb memory promotion resolve-doubts --promotion-id=<id> --resolutions-json='[{"index":0,"choice":"<label-or-custom>","comment":"..."}]' [--title=<title>] [--content=<markdown>] [--agent=<name>] [--json]`;
3112
+ var TEMPLATE_CREATE_USAGE = `usage: ctxdb memory promotion template create --name=<name> --sections-json='[{"title":"...","guidance":"...","level":1}]' [--is-default] [--agent=<name>] [--json]`;
3113
+ var TEMPLATE_GET_USAGE = "usage: ctxdb memory promotion template get <template-id> [--agent=<name>] [--json]";
3114
+ var TEMPLATE_UPDATE_USAGE = `usage: ctxdb memory promotion template update <template-id> --name=<name> --sections-json='[{"title":"...","guidance":"...","level":1}]' [--is-default] [--agent=<name>] [--json]`;
3115
+ var TEMPLATE_DELETE_USAGE = "usage: ctxdb memory promotion template delete <template-id> [--agent=<name>] [--json]";
3116
+ var TEMPLATE_SET_DEFAULT_USAGE = "usage: ctxdb memory promotion template set-default <template-id> [--agent=<name>] [--json]";
3117
+ var TEMPLATE_CLEAR_DEFAULT_USAGE = "usage: ctxdb memory promotion template clear-default [--agent=<name>] [--json]";
3118
+ var SETTINGS_UPDATE_USAGE = "usage: ctxdb memory promotion settings update [--auto-ingest-enabled=<true|false>] [--auto-ingest-threshold=<0..1>] [--default-kb-id=<kb-id> | --clear-default-kb] [--agent=<name>] [--json]";
3119
+ var PROMOTION_STATUSES = [
3120
+ "generating",
3121
+ "pending_review",
3122
+ "approving",
3123
+ "approved",
3124
+ "rejected",
3125
+ "generation_failed"
3126
+ ];
3127
+ var BATCH_ACTIONS = ["approve", "reject"];
3128
+ var BATCH_MAX_ITEMS = 50;
3129
+ var TEMPLATE_SECTIONS_MAX = 15;
3130
+ var PROMOTION_LIST_FIELDS = [
3131
+ "promotion_id",
3132
+ "topic",
3133
+ "title",
3134
+ "status",
3135
+ "source_type",
3136
+ "quality_score",
3137
+ "auto_ingested",
3138
+ "target_kb_id",
3139
+ "updated_at"
3140
+ ];
3141
+ var PROMOTION_DETAIL_FIELDS = [
3142
+ "promotion_id",
3143
+ "topic",
3144
+ "title",
3145
+ "content",
3146
+ "whats_new",
3147
+ "status",
3148
+ "source_type",
3149
+ "quality_score",
3150
+ "auto_ingested",
3151
+ "doubts",
3152
+ "doubt_resolutions",
3153
+ "memory_count",
3154
+ "rejection_reason",
3155
+ "target_kb_id",
3156
+ "target_document_id",
3157
+ "last_error",
3158
+ "reviewed_by",
3159
+ "reviewed_at",
3160
+ "created_at",
3161
+ "updated_at"
3162
+ ];
3163
+ async function promotionGenerate(args) {
3164
+ const topic = args.positional[0];
3165
+ if (!topic || topic.trim() === "") fail(GENERATE_USAGE, 2);
3166
+ const ctx = buildContext(args);
3167
+ const body = { topic };
3168
+ const kbId = stringFlag(args, "knowledge-base-id");
3169
+ if (kbId !== void 0) body.knowledge_base_id = kbId;
3170
+ const resp = await ctx.client.postJson("/v1/memory_promotions/generate", body);
3171
+ emit(args, resp, "memory promotion generate", (data) => data);
3172
+ return 0;
3173
+ }
3174
+ async function promotionList(args) {
3175
+ const params = {};
3176
+ const status2 = stringFlag(args, "status");
3177
+ if (status2 !== void 0) {
3178
+ if (!PROMOTION_STATUSES.includes(status2)) {
3179
+ fail(`invalid --status: ${status2} (expected one of ${PROMOTION_STATUSES.join("|")})
3180
+ ${LIST_USAGE}`, 2);
3181
+ }
3182
+ params.status = status2;
3183
+ }
3184
+ const page = intFlag(args, "page", LIST_USAGE);
3185
+ if (page !== void 0) params.page = page;
3186
+ const pageSize = intFlag(args, "page-size", LIST_USAGE);
3187
+ if (pageSize !== void 0) params.page_size = pageSize;
3188
+ const sortBy = stringFlag(args, "sort-by");
3189
+ if (sortBy !== void 0) {
3190
+ if (sortBy !== "quality_score") {
3191
+ fail(`invalid --sort-by: ${sortBy} (expected quality_score)
3192
+ ${LIST_USAGE}`, 2);
3193
+ }
3194
+ params.sort_by = sortBy;
3195
+ }
3196
+ const sortOrder = stringFlag(args, "sort-order");
3197
+ if (sortOrder !== void 0) {
3198
+ if (sortOrder !== "asc" && sortOrder !== "desc") {
3199
+ fail(`invalid --sort-order: ${sortOrder} (expected asc|desc)
3200
+ ${LIST_USAGE}`, 2);
3201
+ }
3202
+ params.sort_order = sortOrder;
3203
+ }
3204
+ const ctx = buildContext(args);
3205
+ const resp = await ctx.client.get("/v1/memory_promotions", params);
3206
+ emit(args, resp, "memory promotion list", compactList);
3207
+ return 0;
3208
+ }
3209
+ async function promotionGet(args) {
3210
+ const promotionId = args.positional[0];
3211
+ if (!promotionId || promotionId.trim() === "") fail(GET_USAGE, 2);
3212
+ const ctx = buildContext(args);
3213
+ const resp = await ctx.client.get("/v1/memory_promotions/detail", {
3214
+ promotion_id: promotionId
3215
+ });
3216
+ emit(args, resp, "memory promotion get", compactDetail);
3217
+ return 0;
3218
+ }
3219
+ async function promotionApprove(args) {
3220
+ const promotionId = requireIdFlag(args, "promotion-id", APPROVE_USAGE);
3221
+ const kbId = requireIdFlag(args, "knowledge-base-id", APPROVE_USAGE);
3222
+ const ctx = buildContext(args);
3223
+ const body = {
3224
+ promotion_id: promotionId,
3225
+ knowledge_base_id: kbId
3226
+ };
3227
+ const resp = await ctx.client.postJson("/v1/memory_promotions/approve", body);
3228
+ emit(args, resp, "memory promotion approve", (data) => data);
3229
+ return 0;
3230
+ }
3231
+ async function promotionReject(args) {
3232
+ const promotionId = requireIdFlag(args, "promotion-id", REJECT_USAGE);
3233
+ const ctx = buildContext(args);
3234
+ const body = { promotion_id: promotionId };
3235
+ const reason = stringFlag(args, "reason");
3236
+ if (reason !== void 0) body.reason = reason;
3237
+ const resp = await ctx.client.postJson("/v1/memory_promotions/reject", body);
3238
+ emit(args, resp, "memory promotion reject", (data) => data);
3239
+ return 0;
3240
+ }
3241
+ async function promotionBatchAction(args) {
3242
+ const action = stringFlag(args, "action");
3243
+ if (action === void 0 || !BATCH_ACTIONS.includes(action)) {
3244
+ fail(`--action is required and must be one of ${BATCH_ACTIONS.join("|")}
3245
+ ${BATCH_ACTION_USAGE}`, 2);
3246
+ }
3247
+ const ids = parseIdsFlag(args, BATCH_ACTION_USAGE);
3248
+ const kbId = action === "approve" ? requireIdFlag(args, "knowledge-base-id", BATCH_ACTION_USAGE) : stringFlag(args, "knowledge-base-id");
3249
+ const ctx = buildContext(args);
3250
+ const body = { action, ids };
3251
+ if (kbId !== void 0) body.knowledge_base_id = kbId;
3252
+ const reason = stringFlag(args, "reason");
3253
+ if (reason !== void 0) body.reason = reason;
3254
+ const resp = await ctx.client.postJson("/v1/memory_promotions/batch", body);
3255
+ const data = emit(args, resp, "memory promotion batch-action", (data2) => data2);
3256
+ return batchExitCode(data);
3257
+ }
3258
+ async function promotionBatchDelete(args) {
3259
+ const ids = parseIdsFlag(args, BATCH_DELETE_USAGE);
3260
+ const ctx = buildContext(args);
3261
+ const resp = await ctx.client.deleteJson(
3262
+ "/v1/memory_promotions/batch",
3263
+ { ids }
3264
+ );
3265
+ const data = emit(args, resp, "memory promotion batch-delete", (data2) => data2);
3266
+ return batchExitCode(data);
3267
+ }
3268
+ async function promotionResolveDoubts(args) {
3269
+ const promotionId = requireIdFlag(args, "promotion-id", RESOLVE_DOUBTS_USAGE);
3270
+ const resolutionsRaw = args.flags["resolutions-json"];
3271
+ if (typeof resolutionsRaw !== "string" || resolutionsRaw.trim() === "") {
3272
+ fail(`--resolutions-json is required
3273
+ ${RESOLVE_DOUBTS_USAGE}`, 2);
3274
+ }
3275
+ const resolutions = parseResolutions(resolutionsRaw, RESOLVE_DOUBTS_USAGE);
3276
+ const ctx = buildContext(args);
3277
+ const body = {
3278
+ promotion_id: promotionId,
3279
+ doubt_resolutions: resolutions
3280
+ };
3281
+ const title = stringFlag(args, "title");
3282
+ if (title !== void 0) body.title = title;
3283
+ const content = stringFlag(args, "content");
3284
+ if (content !== void 0) body.content = content;
3285
+ const resp = await ctx.client.postJson(
3286
+ "/v1/memory_promotions/resolve_doubts",
3287
+ body
3288
+ );
3289
+ emit(args, resp, "memory promotion resolve-doubts", (data) => data);
3290
+ return 0;
3291
+ }
3292
+ async function promotionTemplateList(args) {
3293
+ const ctx = buildContext(args);
3294
+ const resp = await ctx.client.get("/v1/memory_promotions/templates");
3295
+ emit(args, resp, "memory promotion template list", compactTemplateList);
3296
+ return 0;
3297
+ }
3298
+ async function promotionTemplateCreate(args) {
3299
+ const body = buildTemplateUpsertBody(args, TEMPLATE_CREATE_USAGE);
3300
+ const ctx = buildContext(args);
3301
+ const resp = await ctx.client.postJson("/v1/memory_promotions/templates", body);
3302
+ emit(args, resp, "memory promotion template create", (data) => data);
3303
+ return 0;
3304
+ }
3305
+ async function promotionTemplateGet(args) {
3306
+ const templateId = requireTemplateIdPositional(args, TEMPLATE_GET_USAGE);
3307
+ const ctx = buildContext(args);
3308
+ const resp = await ctx.client.get(
3309
+ `/v1/memory_promotions/templates/${encodeURIComponent(templateId)}`
3310
+ );
3311
+ emit(args, resp, "memory promotion template get", (data) => data);
3312
+ return 0;
3313
+ }
3314
+ async function promotionTemplateUpdate(args) {
3315
+ const templateId = requireTemplateIdPositional(args, TEMPLATE_UPDATE_USAGE);
3316
+ const body = buildTemplateUpsertBody(args, TEMPLATE_UPDATE_USAGE);
3317
+ const ctx = buildContext(args);
3318
+ const resp = await ctx.client.putJson(
3319
+ `/v1/memory_promotions/templates/${encodeURIComponent(templateId)}`,
3320
+ body
3321
+ );
3322
+ emit(args, resp, "memory promotion template update", (data) => data);
3323
+ return 0;
3324
+ }
3325
+ async function promotionTemplateDelete(args) {
3326
+ const templateId = requireTemplateIdPositional(args, TEMPLATE_DELETE_USAGE);
3327
+ const ctx = buildContext(args);
3328
+ const resp = await ctx.client.delete(
3329
+ `/v1/memory_promotions/templates/${encodeURIComponent(templateId)}`
3330
+ );
3331
+ emit(args, resp, "memory promotion template delete", (data) => data);
3332
+ return 0;
3333
+ }
3334
+ async function promotionTemplateSetDefault(args) {
3335
+ const templateId = requireTemplateIdPositional(args, TEMPLATE_SET_DEFAULT_USAGE);
3336
+ const ctx = buildContext(args);
3337
+ const resp = await ctx.client.postJson(
3338
+ `/v1/memory_promotions/templates/${encodeURIComponent(templateId)}/set_default`
3339
+ );
3340
+ emit(args, resp, "memory promotion template set-default", (data) => data);
3341
+ return 0;
3342
+ }
3343
+ async function promotionTemplateClearDefault(args) {
3344
+ if (args.positional.length > 0) fail(TEMPLATE_CLEAR_DEFAULT_USAGE, 2);
3345
+ const ctx = buildContext(args);
3346
+ const resp = await ctx.client.delete("/v1/memory_promotions/templates/default");
3347
+ emit(args, resp, "memory promotion template clear-default", (data) => data);
3348
+ return 0;
3349
+ }
3350
+ async function promotionSettingsGet(args) {
3351
+ const ctx = buildContext(args);
3352
+ const resp = await ctx.client.get("/v1/memory_promotions/settings");
3353
+ emit(args, resp, "memory promotion settings get", (data) => data);
3354
+ return 0;
3355
+ }
3356
+ async function promotionSettingsUpdate(args) {
3357
+ const body = {};
3358
+ const enabled = stringFlag(args, "auto-ingest-enabled");
3359
+ if (enabled !== void 0) {
3360
+ if (enabled !== "true" && enabled !== "false") {
3361
+ fail(`invalid --auto-ingest-enabled: ${enabled} (expected true|false)
3362
+ ${SETTINGS_UPDATE_USAGE}`, 2);
3363
+ }
3364
+ body.auto_ingest_enabled = enabled === "true";
3365
+ }
3366
+ const threshold = stringFlag(args, "auto-ingest-threshold");
3367
+ if (threshold !== void 0) {
3368
+ const n = Number(threshold);
3369
+ if (!Number.isFinite(n) || n < 0 || n > 1) {
3370
+ fail(`invalid --auto-ingest-threshold: ${threshold} (expected a number in [0,1])
3371
+ ${SETTINGS_UPDATE_USAGE}`, 2);
3372
+ }
3373
+ body.auto_ingest_threshold = n;
3374
+ }
3375
+ const defaultKbId = stringFlag(args, "default-kb-id");
3376
+ const clearDefaultKb = args.flags["clear-default-kb"] === true;
3377
+ if (defaultKbId !== void 0 && clearDefaultKb) {
3378
+ fail(`cannot use --default-kb-id and --clear-default-kb together
3379
+ ${SETTINGS_UPDATE_USAGE}`, 2);
3380
+ }
3381
+ if (defaultKbId !== void 0) body.default_kb_id = defaultKbId;
3382
+ if (clearDefaultKb) body.default_kb_id = "";
3383
+ if (Object.keys(body).length === 0) {
3384
+ fail(`at least one setting flag is required
3385
+ ${SETTINGS_UPDATE_USAGE}`, 2);
3386
+ }
3387
+ const ctx = buildContext(args);
3388
+ const resp = await ctx.client.putJson("/v1/memory_promotions/settings", body);
3389
+ emit(args, resp, "memory promotion settings update", (data) => data);
3390
+ return 0;
3391
+ }
3392
+ function stringFlag(args, name) {
3393
+ const value = args.flags[name];
3394
+ return typeof value === "string" && value.trim() !== "" ? value : void 0;
3395
+ }
3396
+ function requireIdFlag(args, name, usage) {
3397
+ const value = stringFlag(args, name);
3398
+ if (value === void 0) fail(`--${name} is required
3399
+ ${usage}`, 2);
3400
+ return value;
3401
+ }
3402
+ function requireTemplateIdPositional(args, usage) {
3403
+ const templateId = args.positional[0];
3404
+ if (!templateId || templateId.trim() === "") fail(usage, 2);
3405
+ return templateId;
3406
+ }
3407
+ function intFlag(args, name, usage) {
3408
+ const raw = stringFlag(args, name);
3409
+ if (raw === void 0) return void 0;
3410
+ const n = Number(raw);
3411
+ if (!Number.isInteger(n) || n < 1) {
3412
+ fail(`invalid --${name}: ${raw} (expected a positive integer)
3413
+ ${usage}`, 2);
3414
+ }
3415
+ return n;
3416
+ }
3417
+ function parseIdsFlag(args, usage) {
3418
+ const raw = stringFlag(args, "ids");
3419
+ if (raw === void 0) fail(`--ids is required (comma-separated)
3420
+ ${usage}`, 2);
3421
+ const ids = raw.split(",").map((s) => s.trim()).filter(Boolean);
3422
+ if (ids.length === 0) fail(`--ids must contain at least one id
3423
+ ${usage}`, 2);
3424
+ if (ids.length > BATCH_MAX_ITEMS) {
3425
+ fail(`--ids accepts at most ${BATCH_MAX_ITEMS} items per request (got ${ids.length})
3426
+ ${usage}`, 2);
3427
+ }
3428
+ return ids;
3429
+ }
3430
+ function parseResolutions(raw, usage) {
3431
+ let parsed;
3432
+ try {
3433
+ parsed = JSON.parse(raw);
3434
+ } catch {
3435
+ fail(`--resolutions-json is not valid JSON
3436
+ ${usage}`, 2);
3437
+ }
3438
+ if (!Array.isArray(parsed) || parsed.length === 0) {
3439
+ fail(`--resolutions-json must be a non-empty array
3440
+ ${usage}`, 2);
3441
+ }
3442
+ return parsed.map((entry, i) => {
3443
+ if (!entry || typeof entry !== "object" || Array.isArray(entry)) {
3444
+ fail(`--resolutions-json[${i}] must be an object
3445
+ ${usage}`, 2);
3446
+ }
3447
+ const e = entry;
3448
+ if (typeof e.index !== "number" || !Number.isInteger(e.index) || e.index < 0) {
3449
+ fail(`--resolutions-json[${i}].index must be a non-negative integer
3450
+ ${usage}`, 2);
3451
+ }
3452
+ if (typeof e.choice !== "string" || e.choice.trim() === "") {
3453
+ fail(`--resolutions-json[${i}].choice must be a non-empty string
3454
+ ${usage}`, 2);
3455
+ }
3456
+ const out = { index: e.index, choice: e.choice };
3457
+ if (e.comment !== void 0 && e.comment !== null) {
3458
+ if (typeof e.comment !== "string") {
3459
+ fail(`--resolutions-json[${i}].comment must be a string
3460
+ ${usage}`, 2);
3461
+ }
3462
+ out.comment = e.comment;
3463
+ }
3464
+ return out;
3465
+ });
3466
+ }
3467
+ function buildTemplateUpsertBody(args, usage) {
3468
+ const name = stringFlag(args, "name");
3469
+ if (name === void 0) fail(`--name is required
3470
+ ${usage}`, 2);
3471
+ const sectionsRaw = args.flags["sections-json"];
3472
+ if (typeof sectionsRaw !== "string" || sectionsRaw.trim() === "") {
3473
+ fail(`--sections-json is required
3474
+ ${usage}`, 2);
3475
+ }
3476
+ const sections = parseSections(sectionsRaw, usage);
3477
+ const body = { name, sections };
3478
+ if (args.flags["is-default"] === true) body.is_default = true;
3479
+ return body;
3480
+ }
3481
+ function parseSections(raw, usage) {
3482
+ let parsed;
3483
+ try {
3484
+ parsed = JSON.parse(raw);
3485
+ } catch {
3486
+ fail(`--sections-json is not valid JSON
3487
+ ${usage}`, 2);
3488
+ }
3489
+ if (!Array.isArray(parsed) || parsed.length === 0) {
3490
+ fail(`--sections-json must be a non-empty array
3491
+ ${usage}`, 2);
3492
+ }
3493
+ if (parsed.length > TEMPLATE_SECTIONS_MAX) {
3494
+ fail(`--sections-json accepts at most ${TEMPLATE_SECTIONS_MAX} sections (got ${parsed.length})
3495
+ ${usage}`, 2);
3496
+ }
3497
+ return parsed.map((entry, i) => {
3498
+ if (!entry || typeof entry !== "object" || Array.isArray(entry)) {
3499
+ fail(`--sections-json[${i}] must be an object
3500
+ ${usage}`, 2);
3501
+ }
3502
+ const e = entry;
3503
+ if (typeof e.title !== "string" || e.title.trim() === "") {
3504
+ fail(`--sections-json[${i}].title must be a non-empty string
3505
+ ${usage}`, 2);
3506
+ }
3507
+ if (/[\r\n]/.test(e.title.trim())) {
3508
+ fail(`--sections-json[${i}].title must not contain line breaks
3509
+ ${usage}`, 2);
3510
+ }
3511
+ if (typeof e.guidance !== "string" || e.guidance.trim() === "") {
3512
+ fail(`--sections-json[${i}].guidance must be a non-empty string
3513
+ ${usage}`, 2);
3514
+ }
3515
+ const out = { title: e.title, guidance: e.guidance };
3516
+ if (e.level !== void 0 && e.level !== null) {
3517
+ if (typeof e.level !== "number" || !Number.isInteger(e.level) || e.level < 1 || e.level > 3) {
3518
+ fail(`--sections-json[${i}].level must be an integer in 1-3
3519
+ ${usage}`, 2);
3520
+ }
3521
+ out.level = e.level;
3522
+ }
3523
+ return out;
3524
+ });
3525
+ }
3526
+ function unwrapBox(response, operation) {
3527
+ if (!response || typeof response !== "object" || Array.isArray(response)) {
3528
+ throw new CtxdbError(`${operation} returned an invalid response`);
3529
+ }
3530
+ const box = response;
3531
+ const errorCode = box.errorCode;
3532
+ const failed = typeof errorCode === "number" && errorCode !== 0 || typeof errorCode === "string" && errorCode.trim() !== "" && errorCode.trim() !== "0";
3533
+ if (failed) {
3534
+ const message = typeof box.errorMessage === "string" && box.errorMessage ? box.errorMessage : `errorCode=${box.errorCode}`;
3535
+ throw new CtxdbError(`${operation} failed: ${message}`);
3536
+ }
3537
+ return Object.hasOwn(box, "data") ? box.data : response;
3538
+ }
3539
+ function emit(args, response, operation, compact) {
3540
+ const data = unwrapBox(response, operation);
3541
+ const out = args.flags.raw ? response : compact(data);
3542
+ printResult(out, !!args.flags.json);
3543
+ return data;
3544
+ }
3545
+ function batchExitCode(data) {
3546
+ if (!data || typeof data !== "object" || Array.isArray(data)) return 0;
3547
+ const failed = data.failed;
3548
+ return typeof failed === "number" && failed > 0 ? 1 : 0;
3549
+ }
3550
+ function pickFields(source, fields) {
3551
+ const out = {};
3552
+ for (const key of fields) {
3553
+ const value = source[key];
3554
+ if (value !== void 0 && value !== null) out[key] = value;
3555
+ }
3556
+ return out;
3557
+ }
3558
+ function compactList(data) {
3559
+ if (!data || typeof data !== "object" || Array.isArray(data)) return data;
3560
+ const d = data;
3561
+ const rows = Array.isArray(d.promotions) ? d.promotions : [];
3562
+ const out = {
3563
+ promotions: rows.filter((p) => p && typeof p === "object" && !Array.isArray(p)).map((p) => pickFields(p, PROMOTION_LIST_FIELDS))
3564
+ };
3565
+ for (const key of ["total", "page", "page_size"]) {
3566
+ if (typeof d[key] === "number") out[key] = d[key];
3567
+ }
3568
+ return out;
3569
+ }
3570
+ function compactDetail(data) {
3571
+ if (!data || typeof data !== "object" || Array.isArray(data)) return data;
3572
+ return pickFields(data, PROMOTION_DETAIL_FIELDS);
3573
+ }
3574
+ function compactTemplateList(data) {
3575
+ if (!Array.isArray(data)) return data;
3576
+ return data.filter((t) => t && typeof t === "object" && !Array.isArray(t)).map((t) => {
3577
+ const template = t;
3578
+ const out = pickFields(template, [
3579
+ "id",
3580
+ "name",
3581
+ "is_default",
3582
+ "updatedAt"
3583
+ ]);
3584
+ if (Array.isArray(template.sections)) {
3585
+ out.sections = template.sections.filter((s) => s && typeof s === "object" && !Array.isArray(s)).map(
3586
+ (s) => pickFields(s, ["level", "title"])
3587
+ );
3588
+ }
3589
+ return out;
3590
+ });
3591
+ }
3592
+
3593
+ // src/cli/review-cli.ts
3594
+ import { readFileSync as readFileSync2 } from "fs";
3595
+
3596
+ // src/lib/review.ts
3597
+ function unwrapReviewData(response, operation) {
3598
+ if (!response || typeof response !== "object" || Array.isArray(response)) {
3599
+ throw new CtxdbError(`${operation} returned an invalid response`);
3600
+ }
3601
+ const box = response;
3602
+ const errorCode = box.errorCode;
3603
+ const failed = typeof errorCode === "number" && errorCode !== 0 || typeof errorCode === "string" && errorCode.trim() !== "" && errorCode.trim() !== "0";
3604
+ if (failed) {
3605
+ const message = typeof box.errorMessage === "string" && box.errorMessage ? box.errorMessage : `errorCode=${errorCode}`;
3606
+ throw new CtxdbError(`${operation} failed: ${message}`);
3607
+ }
3608
+ return box.data ?? null;
3609
+ }
3610
+ function asRecord(value) {
3611
+ return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
3612
+ }
3613
+ function pickString(record, field) {
3614
+ const value = record[field];
3615
+ return typeof value === "string" ? value : "";
3616
+ }
3617
+ function pickNumber(record, field) {
3618
+ const value = record[field];
3619
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
3620
+ }
3621
+ function pickBoolean(record, field) {
3622
+ const value = record[field];
3623
+ return typeof value === "boolean" ? value : void 0;
3624
+ }
3625
+ function parseEmbeddedJson(value) {
3626
+ if (typeof value !== "string" || value.trim() === "") return void 0;
3627
+ try {
3628
+ return JSON.parse(value);
3629
+ } catch {
3630
+ return void 0;
3631
+ }
3632
+ }
3633
+ function countArrayEntries(value) {
3634
+ return Array.isArray(value) ? value.length : void 0;
3635
+ }
3636
+ function readReviewListData(data) {
3637
+ const record = asRecord(data);
3638
+ return {
3639
+ reviews: record && Array.isArray(record.reviews) ? record.reviews : [],
3640
+ total: record ? pickNumber(record, "total") : void 0,
3641
+ page: record ? pickNumber(record, "page") : void 0,
3642
+ page_size: record ? pickNumber(record, "page_size") : void 0
3643
+ };
3644
+ }
3645
+ function minimalReviewListItem(raw) {
3646
+ const r = asRecord(raw) ?? {};
3647
+ const out = {
3648
+ review_id: pickString(r, "review_id"),
3649
+ document_name: pickString(r, "document_name"),
3650
+ decision: pickString(r, "decision"),
3651
+ review_status: pickString(r, "review_status")
3652
+ };
3653
+ const score = pickNumber(r, "confidence_score");
3654
+ if (score !== void 0) out.confidence_score = score;
3655
+ const canApproveReview = pickBoolean(r, "can_approve_review");
3656
+ if (canApproveReview !== void 0) out.can_approve_review = canApproveReview;
3657
+ const createdAt = pickString(r, "created_at");
3658
+ if (createdAt) out.created_at = createdAt;
3659
+ return out;
3660
+ }
3661
+ function compactReviewListItem(raw) {
3662
+ const r = asRecord(raw) ?? {};
3663
+ const out = {
3664
+ ...minimalReviewListItem(raw),
3665
+ document_id: pickString(r, "document_id"),
3666
+ knowledge_base_id: pickString(r, "knowledge_base_id")
3667
+ };
3668
+ const hasConflicts = pickBoolean(r, "has_conflicts");
3669
+ if (hasConflicts !== void 0) out.has_conflicts = hasConflicts;
3670
+ const hasContradictions = pickBoolean(r, "has_contradictions");
3671
+ if (hasContradictions !== void 0) out.has_contradictions = hasContradictions;
3672
+ const rewriteNeeded = pickBoolean(r, "rewrite_needed");
3673
+ if (rewriteNeeded !== void 0) out.rewrite_needed = rewriteNeeded;
3674
+ const humanAction = pickString(r, "human_action");
3675
+ if (humanAction) out.human_action = humanAction;
3676
+ return out;
3677
+ }
3678
+ function projectReviewList(data, projectItem) {
3679
+ const { reviews, total, page, page_size } = readReviewListData(data);
3680
+ const out = { reviews: reviews.map(projectItem) };
3681
+ if (total !== void 0) out.total = total;
3682
+ if (page !== void 0) out.page = page;
3683
+ if (page_size !== void 0) out.page_size = page_size;
3684
+ return out;
3685
+ }
3686
+ function minimalReviewListResponse(data) {
3687
+ return projectReviewList(data, minimalReviewListItem);
3688
+ }
3689
+ function compactReviewListResponse(data) {
3690
+ return projectReviewList(data, compactReviewListItem);
3691
+ }
3692
+ function minimalReviewDetail(raw) {
3693
+ const r = asRecord(raw);
3694
+ if (!r) return {};
3695
+ const out = {
3696
+ review_id: pickString(r, "review_id"),
3697
+ document_name: pickString(r, "document_name"),
3698
+ decision: pickString(r, "decision"),
3699
+ review_status: pickString(r, "review_status")
3700
+ };
3701
+ for (const field of [
3702
+ "document_id",
3703
+ "knowledge_base_id",
3704
+ "decision_reason",
3705
+ "rewrite_strategy",
3706
+ "human_action",
3707
+ "created_at"
3708
+ ]) {
3709
+ const value = pickString(r, field);
3710
+ if (value) out[field] = value;
3711
+ }
3712
+ for (const field of [
3713
+ "confidence_score",
3714
+ "logic_score",
3715
+ "noise_score",
3716
+ "contradiction_score"
3717
+ ]) {
3718
+ const value = pickNumber(r, field);
3719
+ if (value !== void 0) out[field] = value;
3720
+ }
3721
+ for (const field of ["has_contradictions", "rewrite_needed"]) {
3722
+ const value = pickBoolean(r, field);
3723
+ if (value !== void 0) out[field] = value;
3724
+ }
3725
+ const conflictCount = countArrayEntries(parseEmbeddedJson(r.conflicts));
3726
+ if (conflictCount !== void 0) out.conflict_count = conflictCount;
3727
+ const originalContent = asRecord(r.original_content);
3728
+ if (originalContent) {
3729
+ const contentPage = pickNumber(originalContent, "page");
3730
+ if (contentPage !== void 0) out.content_page = contentPage;
3731
+ const totalPages = pickNumber(originalContent, "total_pages");
3732
+ if (totalPages !== void 0) out.content_total_pages = totalPages;
3733
+ const totalChars = pickNumber(originalContent, "total_chars");
3734
+ if (totalChars !== void 0) out.content_total_chars = totalChars;
3735
+ }
3736
+ return out;
3737
+ }
3738
+ var DETAIL_JSON_STRING_FIELDS = [
3739
+ "contradictions",
3740
+ "conflicts",
3741
+ "quality_details",
3742
+ "original_contradictions",
3743
+ "rewrite_info_check",
3744
+ "human_conflict_resolutions"
3745
+ ];
3746
+ function compactReviewDetail(raw) {
3747
+ const r = asRecord(raw);
3748
+ if (!r) return {};
3749
+ const out = { ...r };
3750
+ for (const field of DETAIL_JSON_STRING_FIELDS) {
3751
+ const parsed = parseEmbeddedJson(r[field]);
3752
+ if (parsed !== void 0) out[field] = parsed;
3753
+ }
3754
+ return out;
3755
+ }
3756
+ function minimalReviewTemplate(raw) {
3757
+ const r = asRecord(raw) ?? {};
3758
+ return {
3759
+ id: pickString(r, "id"),
3760
+ name: pickString(r, "name"),
3761
+ is_default: pickBoolean(r, "is_default") ?? false,
3762
+ knowledge_base_id: pickString(r, "knowledge_base_id"),
3763
+ section_count: Array.isArray(r.sections) ? r.sections.length : 0
3764
+ };
3765
+ }
3766
+ function compactReviewTemplate(raw) {
3767
+ return asRecord(raw) ?? {};
3768
+ }
3769
+ function minimalReviewTemplateListResponse(data) {
3770
+ const items = Array.isArray(data) ? data : [];
3771
+ const templates = items.map(minimalReviewTemplate);
3772
+ return { templates, count: templates.length };
3773
+ }
3774
+ function minimalReviewTemplateDetail(raw) {
3775
+ const r = asRecord(raw);
3776
+ if (!r) return {};
3777
+ const out = { ...r };
3778
+ delete out.content;
3779
+ return out;
3780
+ }
3781
+ var REVIEW_ACTIONS = [
3782
+ "confirm",
3783
+ "force_accept",
3784
+ "accept_rewrite",
3785
+ "reject",
3786
+ "reject_reupload"
3787
+ ];
3788
+ var REVIEW_BATCH_ACTIONS = ["confirm", "reject"];
3789
+ var CONFLICT_RESOLUTIONS = [
3790
+ "use_new",
3791
+ "keep_old",
3792
+ "merge",
3793
+ "annotate_divergence"
3794
+ ];
3795
+ var REVIEW_STATUS_FILTERS = ["pending", "reviewed", "rejected"];
3796
+ var BATCH_MAX_ITEMS2 = 50;
3797
+ var TEMPLATE_MAX_SECTIONS = 15;
3798
+ var TEMPLATE_MAX_NAME_LENGTH = 128;
3799
+ function reviewBatchExitCode(data) {
3800
+ const failed = asRecord(data)?.failed;
3801
+ return typeof failed === "number" && failed > 0 ? 1 : 0;
3802
+ }
3803
+ function parseIdList(raw) {
3804
+ return raw.split(",").map((s) => s.trim()).filter(Boolean);
3805
+ }
3806
+ function parseConflictResolutions(raw) {
3807
+ let parsed;
3808
+ try {
3809
+ parsed = JSON.parse(raw);
3810
+ } catch {
3811
+ throw new Error(
3812
+ 'resolutions must be a JSON array: [{"conflict_id": "...", "resolution": "use_new|keep_old|merge|annotate_divergence"}]'
3813
+ );
3814
+ }
3815
+ if (!Array.isArray(parsed) || parsed.length === 0) {
3816
+ throw new Error("resolutions must be a non-empty JSON array");
3817
+ }
3818
+ return parsed.map((entry, index) => {
3819
+ const record = asRecord(entry);
3820
+ const conflictId = record ? record.conflict_id : void 0;
3821
+ const resolution = record ? record.resolution : void 0;
3822
+ if (typeof conflictId !== "string" || conflictId.trim() === "") {
3823
+ throw new Error(`resolutions[${index}].conflict_id must be a non-empty string`);
3824
+ }
3825
+ if (typeof resolution !== "string" || !CONFLICT_RESOLUTIONS.includes(resolution)) {
3826
+ throw new Error(
3827
+ `resolutions[${index}].resolution must be one of ${CONFLICT_RESOLUTIONS.join("|")}`
3828
+ );
3829
+ }
3830
+ return { conflict_id: conflictId.trim(), resolution };
3831
+ });
3832
+ }
3833
+ function parseTemplateSections(raw) {
3834
+ let parsed;
3835
+ try {
3836
+ parsed = JSON.parse(raw);
3837
+ } catch {
3838
+ throw new Error(
3839
+ 'sections must be a JSON array: [{"level": 1, "title": "...", "guidance": "..."}]'
3840
+ );
3841
+ }
3842
+ if (!Array.isArray(parsed) || parsed.length === 0) {
3843
+ throw new Error("sections must be a non-empty JSON array");
3844
+ }
3845
+ if (parsed.length > TEMPLATE_MAX_SECTIONS) {
3846
+ throw new Error(`sections must have at most ${TEMPLATE_MAX_SECTIONS} entries`);
3847
+ }
3848
+ return parsed.map((entry, index) => {
3849
+ const record = asRecord(entry);
3850
+ const title = record ? record.title : void 0;
3851
+ const guidance = record ? record.guidance : void 0;
3852
+ if (typeof title !== "string" || title.trim() === "") {
3853
+ throw new Error(`sections[${index}].title must be a non-empty string`);
3854
+ }
3855
+ if (title.includes("\n")) {
3856
+ throw new Error(`sections[${index}].title must be a single line`);
3857
+ }
3858
+ if (typeof guidance !== "string" || guidance.trim() === "") {
3859
+ throw new Error(`sections[${index}].guidance must be a non-empty string`);
3860
+ }
3861
+ const out = { title, guidance };
3862
+ if (record && record.level !== void 0) {
3863
+ const level = record.level;
3864
+ if (typeof level !== "number" || !Number.isInteger(level) || level < 1 || level > 3) {
3865
+ throw new Error(`sections[${index}].level must be an integer between 1 and 3`);
3866
+ }
3867
+ out.level = level;
3868
+ }
3869
+ return out;
3870
+ });
3871
+ }
3872
+
3873
+ // src/cli/review-cli.ts
3874
+ 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]";
3875
+ var REVIEW_GET_USAGE = "usage: ctxdb kb review get <review-id> [--content-page=N] [--verbose] [--raw] [--json]";
3876
+ var REVIEW_ACTION_USAGE = `usage: ctxdb kb review action <review-id> --action=<${REVIEW_ACTIONS.join("|")}>
3877
+ [--edited-content=<text> | --edited-content-file=<path>]
3878
+ [--conflict-resolutions=<json>] [--verbose] [--raw] [--json]`;
3879
+ var REVIEW_RESOLVE_USAGE = 'usage: ctxdb kb review resolve-conflicts <review-id>\n (--resolutions=<json> | --resolutions-file=<path>) [--verbose] [--raw] [--json]\n resolutions: [{"conflict_id": "...", "resolution": "' + CONFLICT_RESOLUTIONS.join("|") + '"}]';
3880
+ var REVIEW_BATCH_ACTION_USAGE = `usage: ctxdb kb review batch-action --action=<${REVIEW_BATCH_ACTIONS.join("|")}> --ids=<id1,id2,...> [--json] (max ${BATCH_MAX_ITEMS2} ids)`;
3881
+ var REVIEW_BATCH_DELETE_USAGE = `usage: ctxdb kb review batch-delete --ids=<id1,id2,...> [--json] (max ${BATCH_MAX_ITEMS2} ids)`;
3882
+ var REVIEW_DELETE_USAGE = "usage: ctxdb kb review delete <review-id> [--json]";
3883
+ var TEMPLATE_LIST_USAGE = "usage: ctxdb kb review template list <knowledge-base-id> [--verbose] [--raw] [--json]";
3884
+ var TEMPLATE_CREATE_USAGE2 = 'usage: ctxdb kb review template create <knowledge-base-id> --name=<name>\n (--sections=<json> | --sections-file=<path>) [--default] [--verbose] [--raw] [--json]\n sections: [{"level": 1, "title": "...", "guidance": "..."}] (max 15)';
3885
+ var TEMPLATE_UPDATE_USAGE2 = "usage: ctxdb kb review template update <knowledge-base-id> <template-id>\n [--name=<name>] [--sections=<json> | --sections-file=<path>]\n [--default | --no-default] [--verbose] [--raw] [--json]";
3886
+ var TEMPLATE_DELETE_USAGE2 = "usage: ctxdb kb review template delete <knowledge-base-id> <template-id> [--json]";
3887
+ var TEMPLATE_GET_USAGE2 = "usage: ctxdb kb review template get <knowledge-base-id> <template-id> [--verbose] [--raw] [--json]";
3888
+ var TEMPLATE_SET_DEFAULT_USAGE2 = "usage: ctxdb kb review template set-default <knowledge-base-id> <template-id> [--verbose] [--raw] [--json]";
3889
+ var TEMPLATE_CLEAR_DEFAULT_USAGE2 = "usage: ctxdb kb review template clear-default <knowledge-base-id> [--json]";
3890
+ var SETTINGS_GET_USAGE = "usage: ctxdb kb review settings get <knowledge-base-id> [--json]";
3891
+ 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]";
3892
+ function stringValue(args, name) {
3893
+ const value = args.flags[name];
3894
+ return typeof value === "string" && value.trim() !== "" ? value : void 0;
3895
+ }
3896
+ function requireId(args, flagName, positionalIndex, usage) {
3897
+ const positional = args.positional[positionalIndex]?.trim();
3898
+ const value = positional !== void 0 && positional !== "" ? positional : stringValue(args, flagName);
3899
+ if (value === void 0) fail(usage, 2);
3900
+ return value.trim();
3901
+ }
3902
+ function requireEnumFlag(args, flagName, allowed, usage) {
3903
+ const value = stringValue(args, flagName);
3904
+ if (value === void 0) fail(usage, 2);
3905
+ if (!allowed.includes(value)) {
3906
+ fail(`${flagName} must be one of ${allowed.join("|")}
3907
+ ${usage}`, 2);
3908
+ }
3909
+ return value;
3910
+ }
3911
+ function positiveIntFlag(args, flagName, usage) {
3912
+ const value = args.flags[flagName];
3913
+ if (value === void 0) return void 0;
3914
+ if (typeof value !== "string") fail(usage, 2);
3915
+ const parsed = Number(value);
3916
+ if (!Number.isInteger(parsed) || parsed < 1) {
3917
+ fail(`${flagName} must be a positive integer
3918
+ ${usage}`, 2);
3919
+ }
3920
+ return parsed;
3921
+ }
3922
+ function readPayloadInput(args, inlineFlag, fileFlag, usage) {
3923
+ const inline = stringValue(args, inlineFlag);
3924
+ const filePath = stringValue(args, fileFlag);
3925
+ if (inline !== void 0 && filePath !== void 0) {
3926
+ fail(`cannot use --${inlineFlag} and --${fileFlag} together
3927
+ ${usage}`, 2);
3928
+ }
3929
+ if (inline !== void 0) return inline;
3930
+ if (filePath !== void 0) {
3931
+ try {
3932
+ return readFileSync2(filePath, "utf-8");
3933
+ } catch (error) {
3934
+ fail(
3935
+ `cannot read --${fileFlag} ${filePath}: ${error instanceof Error ? error.message : String(error)}`,
3936
+ 2
3937
+ );
3938
+ }
3939
+ }
3940
+ fail(usage, 2);
3941
+ }
3942
+ function parseIdsFlag2(args, usage) {
3943
+ const raw = stringValue(args, "ids");
3944
+ if (raw === void 0) fail(usage, 2);
3945
+ const ids = parseIdList(raw);
3946
+ if (ids.length === 0) fail(`--ids must contain at least one id
3947
+ ${usage}`, 2);
3948
+ if (ids.length > BATCH_MAX_ITEMS2) {
3949
+ fail(`--ids accepts at most ${BATCH_MAX_ITEMS2} ids per request
3950
+ ${usage}`, 2);
3951
+ }
3952
+ return ids;
3953
+ }
3954
+ function project(args, response, operation, minimal, compact) {
3955
+ const data = unwrapReviewData(response, operation);
3956
+ if (args.flags.raw) return response;
3957
+ if (args.flags.verbose) return compact(data);
3958
+ return minimal(data);
3959
+ }
3960
+ async function reviewList(args) {
3961
+ const params = {};
3962
+ const knowledgeBaseId = stringValue(args, "knowledge-base-id");
3963
+ if (knowledgeBaseId !== void 0) params.knowledge_base_id = knowledgeBaseId;
3964
+ const decision = stringValue(args, "decision");
3965
+ if (decision !== void 0) params.decision = decision;
3966
+ const reviewStatus = stringValue(args, "review-status");
3967
+ if (reviewStatus !== void 0) {
3968
+ if (!REVIEW_STATUS_FILTERS.includes(reviewStatus)) {
3969
+ fail(`review-status must be one of ${REVIEW_STATUS_FILTERS.join("|")}
3970
+ ${REVIEW_LIST_USAGE}`, 2);
3971
+ }
3972
+ params.review_status = reviewStatus;
3973
+ }
3974
+ const page = positiveIntFlag(args, "page", REVIEW_LIST_USAGE);
3975
+ if (page !== void 0) params.page = page;
3976
+ const pageSize = positiveIntFlag(args, "page-size", REVIEW_LIST_USAGE);
3977
+ if (pageSize !== void 0) params.page_size = pageSize;
3978
+ const sortBy = stringValue(args, "sort-by");
3979
+ if (sortBy !== void 0) {
3980
+ if (sortBy !== "confidence_score") {
3981
+ fail(`sort-by only supports confidence_score
3982
+ ${REVIEW_LIST_USAGE}`, 2);
3983
+ }
3984
+ params.sort_by = sortBy;
3985
+ }
3986
+ const sortOrder = stringValue(args, "sort-order");
3987
+ if (sortOrder !== void 0) {
3988
+ if (sortBy === void 0) {
3989
+ fail(`sort-order requires sort-by
3990
+ ${REVIEW_LIST_USAGE}`, 2);
3991
+ }
3992
+ if (sortOrder !== "asc" && sortOrder !== "desc") {
3993
+ fail(`sort-order must be asc or desc
3994
+ ${REVIEW_LIST_USAGE}`, 2);
3995
+ }
3996
+ params.sort_order = sortOrder;
3997
+ }
3998
+ const ctx = buildContext(args);
3999
+ const resp = await ctx.client.get("/v1/knowledge/reviews", params);
4000
+ const out = project(
4001
+ args,
4002
+ resp,
4003
+ "review list",
4004
+ minimalReviewListResponse,
4005
+ compactReviewListResponse
4006
+ );
4007
+ printResult(out, !!args.flags.json);
4008
+ return 0;
4009
+ }
4010
+ async function reviewGet(args) {
4011
+ const reviewId = requireId(args, "review-id", 0, REVIEW_GET_USAGE);
4012
+ const contentPage = positiveIntFlag(args, "content-page", REVIEW_GET_USAGE);
4013
+ const params = { review_id: reviewId };
4014
+ if (contentPage !== void 0) params.content_page = contentPage;
4015
+ const ctx = buildContext(args);
4016
+ const resp = await ctx.client.get("/v1/knowledge/reviews/detail", params);
4017
+ const out = project(args, resp, "review get", minimalReviewDetail, compactReviewDetail);
4018
+ printResult(out, !!args.flags.json);
4019
+ return 0;
4020
+ }
4021
+ async function reviewAction(args) {
4022
+ const reviewId = requireId(args, "review-id", 0, REVIEW_ACTION_USAGE);
4023
+ const action = requireEnumFlag(args, "action", REVIEW_ACTIONS, REVIEW_ACTION_USAGE);
4024
+ const body = { review_id: reviewId, action };
4025
+ const editedContent = stringValue(args, "edited-content");
4026
+ const editedContentFile = stringValue(args, "edited-content-file");
4027
+ if (editedContent !== void 0 && editedContentFile !== void 0) {
4028
+ fail(`cannot use --edited-content and --edited-content-file together
4029
+ ${REVIEW_ACTION_USAGE}`, 2);
4030
+ }
4031
+ if (editedContent !== void 0) body.edited_content = editedContent;
4032
+ else if (editedContentFile !== void 0) {
4033
+ try {
4034
+ body.edited_content = readFileSync2(editedContentFile, "utf-8");
4035
+ } catch (error) {
4036
+ fail(
4037
+ `cannot read --edited-content-file ${editedContentFile}: ${error instanceof Error ? error.message : String(error)}`,
4038
+ 2
4039
+ );
4040
+ }
4041
+ }
4042
+ const conflictResolutionsRaw = stringValue(args, "conflict-resolutions");
4043
+ if (conflictResolutionsRaw !== void 0) {
4044
+ try {
4045
+ body.conflict_resolutions = parseConflictResolutions(conflictResolutionsRaw);
4046
+ } catch (error) {
4047
+ fail(`${error instanceof Error ? error.message : String(error)}
4048
+ ${REVIEW_ACTION_USAGE}`, 2);
4049
+ }
4050
+ }
4051
+ const ctx = buildContext(args);
4052
+ const resp = await ctx.client.postJson("/v1/knowledge/reviews/action", body);
4053
+ const out = project(args, resp, "review action", minimalReviewDetail, compactReviewDetail);
4054
+ printResult(out, !!args.flags.json);
4055
+ return 0;
4056
+ }
4057
+ async function reviewResolveConflicts(args) {
4058
+ const reviewId = requireId(args, "review-id", 0, REVIEW_RESOLVE_USAGE);
4059
+ const raw = readPayloadInput(args, "resolutions", "resolutions-file", REVIEW_RESOLVE_USAGE);
4060
+ let resolutions;
4061
+ try {
4062
+ resolutions = parseConflictResolutions(raw);
4063
+ } catch (error) {
4064
+ fail(`${error instanceof Error ? error.message : String(error)}
4065
+ ${REVIEW_RESOLVE_USAGE}`, 2);
4066
+ }
4067
+ const ctx = buildContext(args);
4068
+ const resp = await ctx.client.postJson("/v1/knowledge/reviews/resolve-conflicts", {
4069
+ review_id: reviewId,
4070
+ resolutions
4071
+ });
4072
+ const out = project(args, resp, "review resolve-conflicts", minimalReviewDetail, compactReviewDetail);
4073
+ printResult(out, !!args.flags.json);
4074
+ return 0;
4075
+ }
4076
+ async function reviewBatchAction(args) {
4077
+ const action = requireEnumFlag(args, "action", REVIEW_BATCH_ACTIONS, REVIEW_BATCH_ACTION_USAGE);
4078
+ const ids = parseIdsFlag2(args, REVIEW_BATCH_ACTION_USAGE);
4079
+ const ctx = buildContext(args);
4080
+ const resp = await ctx.client.postJson("/v1/knowledge/reviews/batch", { action, ids });
4081
+ const data = unwrapReviewData(resp, "review batch-action");
4082
+ printResult(data, !!args.flags.json);
4083
+ return reviewBatchExitCode(data);
4084
+ }
4085
+ async function reviewBatchDelete(args) {
4086
+ const ids = parseIdsFlag2(args, REVIEW_BATCH_DELETE_USAGE);
4087
+ const ctx = buildContext(args);
4088
+ const resp = await ctx.client.deleteJson("/v1/knowledge/reviews/batch", { ids });
4089
+ const data = unwrapReviewData(resp, "review batch-delete");
4090
+ printResult(data, !!args.flags.json);
4091
+ return reviewBatchExitCode(data);
4092
+ }
4093
+ async function reviewDelete(args) {
4094
+ const reviewId = requireId(args, "review-id", 0, REVIEW_DELETE_USAGE);
4095
+ const ctx = buildContext(args);
4096
+ const resp = await ctx.client.delete("/v1/knowledge/reviews", { review_id: reviewId });
4097
+ printResult(unwrapReviewData(resp, "review delete"), !!args.flags.json);
4098
+ return 0;
4099
+ }
4100
+ async function reviewTemplateList(args) {
4101
+ const kbId = requireId(args, "kb-id", 0, TEMPLATE_LIST_USAGE);
4102
+ const ctx = buildContext(args);
4103
+ const resp = await ctx.client.get("/v1/knowledge/review_templates", {
4104
+ knowledge_base_id: kbId
4105
+ });
4106
+ const data = unwrapReviewData(resp, "review template list");
4107
+ if (args.flags.raw) {
4108
+ printResult(resp, !!args.flags.json);
4109
+ return 0;
4110
+ }
4111
+ const out = args.flags.verbose ? Array.isArray(data) ? data.map(compactReviewTemplate) : [] : minimalReviewTemplateListResponse(data);
4112
+ printResult(out, !!args.flags.json);
4113
+ return 0;
4114
+ }
4115
+ function buildTemplateUpsertBody2(args, usage, requireNameAndSections) {
4116
+ const body = {};
4117
+ const name = stringValue(args, "name");
4118
+ if (name !== void 0) {
4119
+ if (name.length > TEMPLATE_MAX_NAME_LENGTH) {
4120
+ fail(`--name must be at most ${TEMPLATE_MAX_NAME_LENGTH} characters
4121
+ ${usage}`, 2);
4122
+ }
4123
+ body.name = name;
4124
+ }
4125
+ const hasSectionsInput = Object.hasOwn(args.flags, "sections") || Object.hasOwn(args.flags, "sections-file");
4126
+ if (hasSectionsInput) {
4127
+ const raw = readPayloadInput(args, "sections", "sections-file", usage);
4128
+ try {
4129
+ body.sections = parseTemplateSections(raw);
4130
+ } catch (error) {
4131
+ fail(`${error instanceof Error ? error.message : String(error)}
4132
+ ${usage}`, 2);
4133
+ }
4134
+ }
4135
+ if (requireNameAndSections && (body.name === void 0 || body.sections === void 0)) {
4136
+ fail(usage, 2);
4137
+ }
4138
+ return body;
4139
+ }
4140
+ function projectTemplateResult(args, resp, operation) {
4141
+ const data = unwrapReviewData(resp, operation);
4142
+ if (args.flags.raw) return resp;
4143
+ if (data === null) return { ok: true };
4144
+ if (args.flags.verbose) return compactReviewTemplate(data);
4145
+ return minimalReviewTemplateDetail(data);
4146
+ }
4147
+ async function reviewTemplateCreate(args) {
4148
+ const kbId = requireId(args, "kb-id", 0, TEMPLATE_CREATE_USAGE2);
4149
+ const body = buildTemplateUpsertBody2(args, TEMPLATE_CREATE_USAGE2, true);
4150
+ if (args.flags.default) body.is_default = true;
4151
+ const ctx = buildContext(args);
4152
+ const resp = await ctx.client.postJson("/v1/knowledge/review_templates", body, {
4153
+ knowledge_base_id: kbId
4154
+ });
4155
+ printResult(projectTemplateResult(args, resp, "review template create"), !!args.flags.json);
4156
+ return 0;
4157
+ }
4158
+ async function reviewTemplateUpdate(args) {
4159
+ const kbId = requireId(args, "kb-id", 0, TEMPLATE_UPDATE_USAGE2);
4160
+ const templateId = requireId(args, "template-id", 1, TEMPLATE_UPDATE_USAGE2);
4161
+ const body = buildTemplateUpsertBody2(args, TEMPLATE_UPDATE_USAGE2, false);
4162
+ const setDefault = args.flags.default !== void 0;
4163
+ const clearDefault = args.flags["no-default"] !== void 0;
4164
+ if (setDefault && clearDefault) {
4165
+ fail(`cannot use --default and --no-default together
4166
+ ${TEMPLATE_UPDATE_USAGE2}`, 2);
4167
+ }
4168
+ if (setDefault) body.is_default = true;
4169
+ else if (clearDefault) body.is_default = false;
4170
+ if (Object.keys(body).length === 0) {
4171
+ fail(`nothing to update: provide --name, --sections/--sections-file or --default/--no-default
4172
+ ${TEMPLATE_UPDATE_USAGE2}`, 2);
4173
+ }
4174
+ const ctx = buildContext(args);
4175
+ const resp = await ctx.client.putJson("/v1/knowledge/review_templates", body, {
4176
+ knowledge_base_id: kbId,
4177
+ template_id: templateId
4178
+ });
4179
+ printResult(projectTemplateResult(args, resp, "review template update"), !!args.flags.json);
4180
+ return 0;
4181
+ }
4182
+ async function reviewTemplateDelete(args) {
4183
+ const kbId = requireId(args, "kb-id", 0, TEMPLATE_DELETE_USAGE2);
4184
+ const templateId = requireId(args, "template-id", 1, TEMPLATE_DELETE_USAGE2);
4185
+ const ctx = buildContext(args);
4186
+ const resp = await ctx.client.delete("/v1/knowledge/review_templates", {
4187
+ knowledge_base_id: kbId,
4188
+ template_id: templateId
4189
+ });
4190
+ printResult(unwrapReviewData(resp, "review template delete"), !!args.flags.json);
4191
+ return 0;
4192
+ }
4193
+ async function reviewTemplateGet(args) {
4194
+ const kbId = requireId(args, "kb-id", 0, TEMPLATE_GET_USAGE2);
4195
+ const templateId = requireId(args, "template-id", 1, TEMPLATE_GET_USAGE2);
4196
+ const ctx = buildContext(args);
4197
+ const resp = await ctx.client.get("/v1/knowledge/review_templates/detail", {
4198
+ knowledge_base_id: kbId,
4199
+ template_id: templateId
4200
+ });
4201
+ const data = unwrapReviewData(resp, "review template get");
4202
+ if (args.flags.raw) {
4203
+ printResult(resp, !!args.flags.json);
4204
+ return 0;
4205
+ }
4206
+ if (data === null) {
4207
+ printResult({ found: false, template_id: templateId }, !!args.flags.json);
4208
+ return 0;
4209
+ }
4210
+ const out = args.flags.verbose ? compactReviewTemplate(data) : minimalReviewTemplateDetail(data);
4211
+ printResult(out, !!args.flags.json);
4212
+ return 0;
4213
+ }
4214
+ async function reviewTemplateSetDefault(args) {
4215
+ const kbId = requireId(args, "kb-id", 0, TEMPLATE_SET_DEFAULT_USAGE2);
4216
+ const templateId = requireId(args, "template-id", 1, TEMPLATE_SET_DEFAULT_USAGE2);
4217
+ const ctx = buildContext(args);
4218
+ const resp = await ctx.client.postJson(
4219
+ "/v1/knowledge/review_templates/set_default",
4220
+ {},
4221
+ { knowledge_base_id: kbId, template_id: templateId }
4222
+ );
4223
+ printResult(projectTemplateResult(args, resp, "review template set-default"), !!args.flags.json);
4224
+ return 0;
4225
+ }
4226
+ async function reviewTemplateClearDefault(args) {
4227
+ const kbId = requireId(args, "kb-id", 0, TEMPLATE_CLEAR_DEFAULT_USAGE2);
4228
+ const ctx = buildContext(args);
4229
+ const resp = await ctx.client.delete("/v1/knowledge/review_templates/default", {
4230
+ knowledge_base_id: kbId
4231
+ });
4232
+ printResult(unwrapReviewData(resp, "review template clear-default"), !!args.flags.json);
4233
+ return 0;
4234
+ }
4235
+ async function reviewSettingsGet(args) {
4236
+ const kbId = requireId(args, "kb-id", 0, SETTINGS_GET_USAGE);
4237
+ const ctx = buildContext(args);
4238
+ const resp = await ctx.client.get("/v1/knowledge/review_settings", {
4239
+ knowledge_base_id: kbId
4240
+ });
4241
+ printResult(unwrapReviewData(resp, "review settings get"), !!args.flags.json);
4242
+ return 0;
4243
+ }
4244
+ var SETTINGS_BOOL_FLAG_FIELDS = [
4245
+ ["review-enabled", "review_enabled"],
4246
+ ["rewrite-enabled", "rewrite_enabled"],
4247
+ ["conflict-detection-enabled", "conflict_detection_enabled"],
4248
+ ["rewrite-auto-ingest-enabled", "rewrite_auto_ingest_enabled"]
4249
+ ];
4250
+ var SETTINGS_NUMBER_FLAG_FIELDS = [
4251
+ ["high-threshold", "high_threshold", false],
4252
+ ["logic-rewrite-threshold", "logic_rewrite_threshold", false],
4253
+ ["noise-rewrite-threshold", "noise_rewrite_threshold", false],
4254
+ ["max-rewrite-iterations", "max_rewrite_iterations", true]
4255
+ ];
4256
+ async function reviewSettingsUpdate(args) {
4257
+ const kbId = requireId(args, "kb-id", 0, SETTINGS_UPDATE_USAGE2);
4258
+ const body = {};
4259
+ for (const [flag, field] of SETTINGS_BOOL_FLAG_FIELDS) {
4260
+ const on = args.flags[flag] !== void 0;
4261
+ const off = args.flags[`no-${flag}`] !== void 0;
4262
+ if (on && off) {
4263
+ fail(`cannot use --${flag} and --no-${flag} together
4264
+ ${SETTINGS_UPDATE_USAGE2}`, 2);
4265
+ }
4266
+ if (on) body[field] = true;
4267
+ else if (off) body[field] = false;
4268
+ }
4269
+ for (const [flag, field, integer] of SETTINGS_NUMBER_FLAG_FIELDS) {
4270
+ const value = args.flags[flag];
4271
+ if (value === void 0) continue;
4272
+ if (typeof value !== "string") fail(SETTINGS_UPDATE_USAGE2, 2);
4273
+ const parsed = Number(value);
4274
+ if (!Number.isFinite(parsed) || integer && !Number.isInteger(parsed)) {
4275
+ fail(`--${flag} must be ${integer ? "an integer" : "a number"}
4276
+ ${SETTINGS_UPDATE_USAGE2}`, 2);
4277
+ }
4278
+ body[field] = parsed;
4279
+ }
4280
+ if (Object.keys(body).length === 0) {
4281
+ fail(`nothing to update: provide at least one settings field
4282
+ ${SETTINGS_UPDATE_USAGE2}`, 2);
4283
+ }
4284
+ body.knowledge_base_id = kbId;
4285
+ const ctx = buildContext(args);
4286
+ const resp = await ctx.client.patchJson("/v1/knowledge/review_settings", body);
4287
+ const data = unwrapReviewData(resp, "review settings update");
4288
+ printResult(data ?? { ok: true }, !!args.flags.json);
4289
+ return 0;
4290
+ }
4291
+
2996
4292
  // src/cli/main.ts
2997
4293
  var HELP5 = `ctxdb v${PACKAGE_VERSION} \u2014 RDS ContextDatabase CLI (multi-agent)
2998
4294
 
@@ -3047,6 +4343,42 @@ COMMANDS
3047
4343
  memory update <memory-id> --text=<new-text> [--agent=<name>]
3048
4344
  memory delete <memory-id> | --all [--agent=<name>]
3049
4345
 
4346
+ memory promotion generate <topic> [--knowledge-base-id=<kb-id>] [--agent=<name>]
4347
+ memory promotion list [--status=<generating|pending_review|approving|approved|rejected|generation_failed>]
4348
+ [--page=N] [--page-size=N] [--sort-by=quality_score]
4349
+ [--sort-order=asc|desc] [--raw] [--agent=<name>]
4350
+ memory promotion get <promotion-id> [--raw] [--agent=<name>]
4351
+ memory promotion approve --promotion-id=<id> --knowledge-base-id=<kb-id> [--agent=<name>]
4352
+ memory promotion reject --promotion-id=<id> [--reason=<text>] [--agent=<name>]
4353
+ memory promotion batch-action --action=<approve|reject> --ids=<id1,id2,...>
4354
+ [--knowledge-base-id=<kb-id> (required for approve)] [--reason=<text>] [--agent=<name>]
4355
+ memory promotion batch-delete --ids=<id1,id2,...> [--agent=<name>]
4356
+ memory promotion resolve-doubts --promotion-id=<id>
4357
+ --resolutions-json='[{"index":0,"choice":"<label>","comment":"..."}]'
4358
+ [--title=<title>] [--content=<markdown>] [--agent=<name>]
4359
+ memory promotion template list [--raw] [--agent=<name>]
4360
+ memory promotion template create --name=<name>
4361
+ --sections-json='[{"title":"...","guidance":"...","level":1}]'
4362
+ [--is-default] [--agent=<name>]
4363
+ memory promotion template get <template-id> [--agent=<name>]
4364
+ memory promotion template update <template-id> --name=<name> --sections-json='[...]'
4365
+ [--is-default] [--agent=<name>]
4366
+ memory promotion template delete <template-id> [--agent=<name>]
4367
+ memory promotion template set-default <template-id> [--agent=<name>]
4368
+ memory promotion template clear-default [--agent=<name>]
4369
+ memory promotion settings get [--agent=<name>]
4370
+ memory promotion settings update [--auto-ingest-enabled=<true|false>]
4371
+ [--auto-ingest-threshold=<0..1>]
4372
+ [--default-kb-id=<kb-id> | --clear-default-kb] [--agent=<name>]
4373
+ Memory promotion (\u8BB0\u5FC6\u6210\u6587): generate, review,
4374
+ approve/reject promotion tasks; manage doc
4375
+ templates and auto-ingest settings. Batch
4376
+ requests accept at most 50 ids.
4377
+ Default output is a compact agent-friendly
4378
+ view; --raw returns the server envelope
4379
+ verbatim.
4380
+
4381
+
3050
4382
  kb create <kb-name> [--description=<desc>] [--agent=<name>]
3051
4383
  kb upload-text <kb-name> <doc-name> --text=<body> [--agent=<name>]
3052
4384
  [--file-path=<server-logical-path>] [--wait|--no-wait]
@@ -3073,6 +4405,56 @@ COMMANDS
3073
4405
  --verbose: compact view adds doc_name/kb_id/
3074
4406
  doc_id?/tags? for citation.
3075
4407
  --raw: server response verbatim (curl parity).
4408
+ kb review list [--knowledge-base-id=<id>] [--decision=<d>]
4409
+ [--review-status=<pending|reviewed|rejected>]
4410
+ [--page=N] [--page-size=N] [--sort-by=confidence_score]
4411
+ [--sort-order=asc|desc] [--verbose] [--raw]
4412
+ List knowledge review records (newest first
4413
+ by default; --sort-by sorts by quality score).
4414
+ kb review get <review-id> [--content-page=N] [--verbose] [--raw]
4415
+ Review detail: scores, decision, conflicts
4416
+ and paginated original content.
4417
+ kb review action <review-id> --action=<confirm|force_accept|accept_rewrite|reject|reject_reupload>
4418
+ [--edited-content=<text> | --edited-content-file=<path>]
4419
+ [--conflict-resolutions=<json>] [--verbose] [--raw]
4420
+ Perform one human review action.
4421
+ kb review resolve-conflicts <review-id>
4422
+ (--resolutions=<json> | --resolutions-file=<path>) [--verbose] [--raw]
4423
+ Resolve conflicts one by one. resolutions:
4424
+ [{"conflict_id": "...", "resolution":
4425
+ "use_new|keep_old|merge|annotate_divergence"}]
4426
+ kb review batch-action --action=<confirm|reject> --ids=<id1,id2,...>
4427
+ Batch confirm/reject up to 50 reviews.
4428
+ kb review batch-delete --ids=<id1,id2,...>
4429
+ Batch delete up to 50 reviewed/rejected records.
4430
+ kb review delete <review-id> Delete one reviewed/rejected record.
4431
+ kb review template list <kb-id> [--verbose] [--raw]
4432
+ kb review template create <kb-id> --name=<name>
4433
+ (--sections=<json> | --sections-file=<path>) [--default]
4434
+ kb review template update <kb-id> <template-id> [--name=<name>]
4435
+ [--sections=<json> | --sections-file=<path>]
4436
+ [--default | --no-default]
4437
+ kb review template delete <kb-id> <template-id>
4438
+ kb review template get <kb-id> <template-id> [--verbose] [--raw]
4439
+ kb review template set-default <kb-id> <template-id>
4440
+ kb review template clear-default <kb-id>
4441
+ Manage KB review-rewrite templates
4442
+ (max 5 per KB). sections JSON:
4443
+ [{"level": 1, "title": "...", "guidance": "..."}]
4444
+ kb review settings get <kb-id> [--json]
4445
+ kb review settings update <kb-id> [--review-enabled | --no-review-enabled]
4446
+ [--high-threshold=F] [--logic-rewrite-threshold=F]
4447
+ [--noise-rewrite-threshold=F] [--max-rewrite-iterations=N]
4448
+ [--rewrite-enabled | --no-rewrite-enabled]
4449
+ [--conflict-detection-enabled | --no-conflict-detection-enabled]
4450
+ [--rewrite-auto-ingest-enabled | --no-rewrite-auto-ingest-enabled]
4451
+ Per-KB knowledge-review enablement, thresholds,
4452
+ and rewrite/auto-ingest switches.
4453
+ kb review list/detail/template default to the
4454
+ minimal agent view; --verbose adds fields,
4455
+ --raw ships the server envelope verbatim.
4456
+ All kb review commands accept --json.
4457
+
3076
4458
 
3077
4459
  skill install --target <qoder|qoderwork|qwenwork|codex|claude|opencode|openclaw|hermes> [--json]
3078
4460
  skill install --path <dir> [--json]
@@ -3121,7 +4503,30 @@ var ROUTES = {
3121
4503
  list: memoryList,
3122
4504
  get: memoryGet,
3123
4505
  update: memoryUpdate,
3124
- delete: memoryDelete
4506
+ delete: memoryDelete,
4507
+ promotion: {
4508
+ generate: promotionGenerate,
4509
+ list: promotionList,
4510
+ get: promotionGet,
4511
+ approve: promotionApprove,
4512
+ reject: promotionReject,
4513
+ "batch-action": promotionBatchAction,
4514
+ "batch-delete": promotionBatchDelete,
4515
+ "resolve-doubts": promotionResolveDoubts,
4516
+ template: {
4517
+ list: promotionTemplateList,
4518
+ create: promotionTemplateCreate,
4519
+ get: promotionTemplateGet,
4520
+ update: promotionTemplateUpdate,
4521
+ delete: promotionTemplateDelete,
4522
+ "set-default": promotionTemplateSetDefault,
4523
+ "clear-default": promotionTemplateClearDefault
4524
+ },
4525
+ settings: {
4526
+ get: promotionSettingsGet,
4527
+ update: promotionSettingsUpdate
4528
+ }
4529
+ }
3125
4530
  },
3126
4531
  kb: {
3127
4532
  create: kbCreate,
@@ -3132,12 +4537,34 @@ var ROUTES = {
3132
4537
  list: kbList,
3133
4538
  "documents-list": kbDocumentsList,
3134
4539
  "document-get": kbDocumentGet,
3135
- search: kbSearch
4540
+ search: kbSearch,
4541
+ review: {
4542
+ list: reviewList,
4543
+ get: reviewGet,
4544
+ action: reviewAction,
4545
+ "resolve-conflicts": reviewResolveConflicts,
4546
+ "batch-action": reviewBatchAction,
4547
+ "batch-delete": reviewBatchDelete,
4548
+ delete: reviewDelete,
4549
+ template: {
4550
+ list: reviewTemplateList,
4551
+ create: reviewTemplateCreate,
4552
+ update: reviewTemplateUpdate,
4553
+ delete: reviewTemplateDelete,
4554
+ get: reviewTemplateGet,
4555
+ "set-default": reviewTemplateSetDefault,
4556
+ "clear-default": reviewTemplateClearDefault
4557
+ },
4558
+ settings: {
4559
+ get: reviewSettingsGet,
4560
+ update: reviewSettingsUpdate
4561
+ }
4562
+ }
3136
4563
  }
3137
4564
  };
3138
- async function dispatch(argv) {
4565
+ async function dispatch(argv, routes = ROUTES, help = HELP5) {
3139
4566
  if (argv.length === 0 || argv[0] === "-h" || argv[0] === "--help") {
3140
- process.stdout.write(HELP5);
4567
+ process.stdout.write(help);
3141
4568
  return 0;
3142
4569
  }
3143
4570
  if (argv[0] === "-v" || argv[0] === "--version") {
@@ -3146,61 +4573,82 @@ async function dispatch(argv) {
3146
4573
  return 0;
3147
4574
  }
3148
4575
  const [first, ...rest] = argv;
3149
- const route = ROUTES[first];
4576
+ const route = routes[first];
3150
4577
  if (!route) {
3151
4578
  process.stderr.write(`unknown command: ${first}
3152
4579
  `);
3153
- process.stderr.write(HELP5);
4580
+ process.stderr.write(help);
3154
4581
  return 2;
3155
4582
  }
3156
4583
  if (typeof route === "function") {
3157
4584
  return Promise.resolve(route(parseArgs(rest)));
3158
4585
  }
3159
- if (rest.length === 0) {
3160
- process.stderr.write(
3161
- `usage: ctxdb ${first} <${Object.keys(route).join("|")}> ...
3162
- `
3163
- );
4586
+ return dispatchGroup([first], route, rest);
4587
+ }
4588
+ async function dispatchGroup(path, group, argv) {
4589
+ const usage = `usage: ctxdb ${path.join(" ")} <${Object.keys(group).join("|")}> ...
4590
+ `;
4591
+ if (argv.length === 0) {
4592
+ process.stderr.write(usage);
3164
4593
  return 2;
3165
4594
  }
3166
- if (rest[0] === "-h" || rest[0] === "--help") {
3167
- process.stdout.write(
3168
- `usage: ctxdb ${first} <${Object.keys(route).join("|")}> ...
3169
- `
3170
- );
4595
+ if (argv[0] === "-h" || argv[0] === "--help") {
4596
+ process.stdout.write(usage);
3171
4597
  return 0;
3172
4598
  }
3173
- const [sub, ...subRest] = rest;
3174
- const handler = route[sub];
4599
+ const [sub, ...subRest] = argv;
4600
+ const handler = group[sub];
3175
4601
  if (!handler) {
3176
- process.stderr.write(`unknown subcommand: ${first} ${sub}
4602
+ process.stderr.write(`unknown subcommand: ${[...path, sub].join(" ")}
3177
4603
  `);
3178
4604
  return 2;
3179
4605
  }
3180
- return Promise.resolve(handler(parseArgs(subRest)));
4606
+ if (typeof handler === "function") {
4607
+ return Promise.resolve(handler(parseArgs(subRest)));
4608
+ }
4609
+ return dispatchGroup([...path, sub], handler, subRest);
3181
4610
  }
3182
- async function main(argv = process.argv.slice(2)) {
4611
+ async function main(argv = process.argv.slice(2), routes = ROUTES, help = HELP5) {
3183
4612
  const notification = beginUpdateNotification(argv, {
3184
4613
  currentVersion: PACKAGE_VERSION,
3185
4614
  workerPath: fileURLToPath2(new URL("../workers/version-check.js", import.meta.url))
3186
4615
  });
3187
- const code = await dispatch(argv);
4616
+ const code = await dispatch(argv, routes, help);
3188
4617
  completeUpdateNotification(notification, code);
3189
4618
  return code;
3190
4619
  }
3191
- main().then(
3192
- (code) => {
3193
- if (typeof code === "number") process.exitCode = code;
3194
- },
3195
- (err) => {
3196
- process.stderr.write(`error: ${err?.message ?? err}
4620
+ function runMain(routes = ROUTES, help = HELP5) {
4621
+ main(process.argv.slice(2), routes, help).then(
4622
+ (code) => {
4623
+ if (typeof code === "number") process.exitCode = code;
4624
+ },
4625
+ (err) => {
4626
+ process.stderr.write(`error: ${err?.message ?? err}
3197
4627
  `);
3198
- if (process.env.RDS_CTXDB_DEBUG === "1" && err?.stack) {
3199
- process.stderr.write(err.stack + "\n");
4628
+ if (process.env.RDS_CTXDB_DEBUG === "1" && err?.stack) {
4629
+ process.stderr.write(err.stack + "\n");
4630
+ }
4631
+ process.exitCode = 1;
3200
4632
  }
3201
- process.exitCode = 1;
4633
+ );
4634
+ }
4635
+ var directEntry = (() => {
4636
+ try {
4637
+ const modulePath = resolve2(fileURLToPath2(import.meta.url));
4638
+ const argvPath = resolve2(process.argv[1] ?? "");
4639
+ return modulePath === argvPath || realpathSync(modulePath) === realpathSync(argvPath);
4640
+ } catch {
4641
+ return false;
3202
4642
  }
3203
- );
4643
+ })();
4644
+ var directEntryName = basename2(fileURLToPath2(import.meta.url));
4645
+ if (directEntry && (directEntryName === "main.ts" || directEntryName === "main.js")) {
4646
+ runMain();
4647
+ }
3204
4648
  export {
3205
- main
4649
+ HELP5 as HELP,
4650
+ ROUTES,
4651
+ dispatch,
4652
+ main,
4653
+ runMain
3206
4654
  };