@okxweb3/a2a-node 0.2.16 → 0.2.17-beta-ab42219842-261020165552

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.
Files changed (3) hide show
  1. package/dist/cli.js +1805 -253
  2. package/dist/index.js +1730 -167
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -114,7 +114,8 @@ function resolveTaskPaths(homeDir = resolveTaskHome()) {
114
114
  completedCommandsDir: (0, import_node_path2.join)(homeDir, "commands", "completed"),
115
115
  pidPath: (0, import_node_path2.join)(homeDir, "run", "listener.pid"),
116
116
  daemonLockPath: (0, import_node_path2.join)(homeDir, "run", "daemon.lock"),
117
- listenerLogPath: (0, import_node_path2.join)(homeDir, "logs", "listener.log")
117
+ listenerLogPath: (0, import_node_path2.join)(homeDir, "logs", "listener.log"),
118
+ devkitServerDbPath: (0, import_node_path2.join)(homeDir, "sqlite", DEVKIT_SERVER_DB_NAME)
118
119
  };
119
120
  }
120
121
  function ensureTaskHome(homeDir) {
@@ -126,13 +127,14 @@ function encodeJobIdForFile(jobId) {
126
127
  function ensureTaskDir(dir) {
127
128
  return ensureA2aTaskDir(dir);
128
129
  }
129
- var import_node_path2, BACKUP_JOB_ID;
130
+ var import_node_path2, BACKUP_JOB_ID, DEVKIT_SERVER_DB_NAME;
130
131
  var init_paths = __esm({
131
132
  "src/paths.ts"() {
132
133
  "use strict";
133
134
  import_node_path2 = require("node:path");
134
135
  init_a2a_paths();
135
136
  BACKUP_JOB_ID = "backup";
137
+ DEVKIT_SERVER_DB_NAME = "devkit-server.sqlite";
136
138
  }
137
139
  });
138
140
 
@@ -4256,8 +4258,8 @@ var require_worldwide = __commonJS({
4256
4258
  function getGlobalSingleton(name, creator, obj) {
4257
4259
  const gbl = obj || GLOBAL_OBJ;
4258
4260
  const __SENTRY__ = gbl.__SENTRY__ = gbl.__SENTRY__ || {};
4259
- const singleton2 = __SENTRY__[name] || (__SENTRY__[name] = creator());
4260
- return singleton2;
4261
+ const singleton3 = __SENTRY__[name] || (__SENTRY__[name] = creator());
4262
+ return singleton3;
4261
4263
  }
4262
4264
  exports2.GLOBAL_OBJ = GLOBAL_OBJ;
4263
4265
  exports2.getGlobalObject = getGlobalObject;
@@ -19302,6 +19304,14 @@ var init_events = __esm({
19302
19304
  SYSTEM_NOTIFICATION_ROUTED: "System notification routed",
19303
19305
  HERMES_SESSION_ROUTE_BINDING: "Hermes session route binding",
19304
19306
  DOCTOR_REPORT: "Doctor report",
19307
+ // XMTP creation rate-limit cooldown (DEXMARKET-9116). All four are logger.info,
19308
+ // so each one must also be listed in SENTRY_INFO_ALLOWLIST (index.ts) or info()
19309
+ // drops it silently. Extras are bounded tokens/ints/bools only — never raw SDK
19310
+ // error text (no-content-leak invariant).
19311
+ XMTP_RATE_LIMIT_COOLDOWN_STARTED: "XMTP rate limit cooldown started",
19312
+ XMTP_RATE_LIMIT_CREATE_SUPPRESSED: "XMTP rate limit create suppressed",
19313
+ XMTP_RATE_LIMIT_PROBE: "XMTP rate limit probe",
19314
+ XMTP_RATE_LIMIT_RECOVERED: "XMTP rate limit recovered",
19305
19315
  // ── error ─────────────────────────────────────────────────────
19306
19316
  XMTP_CONNECTION_FAILED: "XMTP connection failed",
19307
19317
  CONVERSATIONS_STREAM_FAILED: "conversations.stream failed",
@@ -19367,7 +19377,28 @@ var init_events = __esm({
19367
19377
  AGENT_DB_DIR_CREATE_FAILED: "Agent DB dir create failed",
19368
19378
  AGENT_INSTALLATION_LIMIT_NEAR: "Agent installation limit near",
19369
19379
  XMTP_HISTORY_SYNC_REQUEST_FAILED: "XMTP history sync request failed",
19370
- XMTP_DEBUG_SYNC_FAILED: "XMTP debug sync failed"
19380
+ XMTP_DEBUG_SYNC_FAILED: "XMTP debug sync failed",
19381
+ // Underlying XMTP SDK client close failed during recycle/removal/shutdown
19382
+ // (DEXMARKET-9116). Error-level → NOT added to SENTRY_INFO_ALLOWLIST.
19383
+ XMTP_CLIENT_CLOSE_FAILED: "XMTP client close failed",
19384
+ // ── devkit custom-server registry + delivery (DEXMARKET-9165) ──────────────
19385
+ // info-level (registered in SENTRY_INFO_ALLOWLIST below):
19386
+ DEVKIT_REGISTER_REQUESTED: "Devkit register requested",
19387
+ DEVKIT_REGISTER_COMPLETED: "Devkit register completed",
19388
+ DEVKIT_UNREGISTER_REQUESTED: "Devkit unregister requested",
19389
+ DEVKIT_UNREGISTER_COMPLETED: "Devkit unregister completed",
19390
+ DEVKIT_DAEMON_STATUS_UNKNOWN: "Devkit daemon status unknown",
19391
+ DEVKIT_ROUTE_DEFAULT_AI: "Devkit route default AI",
19392
+ DEVKIT_ROUTE_CUSTOM_SERVER: "Devkit route custom server",
19393
+ DEVKIT_DELIVERY_ACCEPTED: "Devkit delivery accepted",
19394
+ DEVKIT_DELIVERY_HTTP_ACCEPTED: "Devkit delivery http accepted",
19395
+ DEVKIT_DELIVERY_DROPPED: "Devkit delivery dropped",
19396
+ DEVKIT_DELIVERY_CANCELLED: "Devkit delivery cancelled",
19397
+ // error-level (NOT allowlisted — logger.error):
19398
+ DEVKIT_REGISTER_REJECTED: "Devkit register rejected",
19399
+ DEVKIT_CONFIG_PERSIST_FAILED: "Devkit config persist failed",
19400
+ DEVKIT_ROUTE_CONFIG_READ_FAILED: "Devkit route config read failed",
19401
+ DEVKIT_DELIVERY_HTTP_FAILED: "Devkit delivery http failed"
19371
19402
  };
19372
19403
  }
19373
19404
  });
@@ -20212,7 +20243,26 @@ var init_sentry_logger = __esm({
20212
20243
  LogEvent.PENDING_LIST_QUERIED,
20213
20244
  LogEvent.SESSION_KEY_DERIVED,
20214
20245
  LogEvent.SESSIONS_QUERIED,
20215
- LogEvent.SYNC_TICK_COMPLETED
20246
+ LogEvent.SYNC_TICK_COMPLETED,
20247
+ // XMTP creation rate-limit cooldown checkpoints (DEXMARKET-9116). info() drops
20248
+ // any event not listed here, so these must stay registered.
20249
+ LogEvent.XMTP_RATE_LIMIT_COOLDOWN_STARTED,
20250
+ LogEvent.XMTP_RATE_LIMIT_CREATE_SUPPRESSED,
20251
+ LogEvent.XMTP_RATE_LIMIT_PROBE,
20252
+ LogEvent.XMTP_RATE_LIMIT_RECOVERED,
20253
+ // devkit custom-server registry + delivery info checkpoints (DEXMARKET-9165).
20254
+ // info() drops any event not listed here, so these must stay registered.
20255
+ LogEvent.DEVKIT_REGISTER_REQUESTED,
20256
+ LogEvent.DEVKIT_REGISTER_COMPLETED,
20257
+ LogEvent.DEVKIT_UNREGISTER_REQUESTED,
20258
+ LogEvent.DEVKIT_UNREGISTER_COMPLETED,
20259
+ LogEvent.DEVKIT_DAEMON_STATUS_UNKNOWN,
20260
+ LogEvent.DEVKIT_ROUTE_DEFAULT_AI,
20261
+ LogEvent.DEVKIT_ROUTE_CUSTOM_SERVER,
20262
+ LogEvent.DEVKIT_DELIVERY_ACCEPTED,
20263
+ LogEvent.DEVKIT_DELIVERY_HTTP_ACCEPTED,
20264
+ LogEvent.DEVKIT_DELIVERY_DROPPED,
20265
+ LogEvent.DEVKIT_DELIVERY_CANCELLED
20216
20266
  ]);
20217
20267
  MAX_EXTRA_STRING_LENGTH = 256;
20218
20268
  MAX_TAG_VALUE_LENGTH = 128;
@@ -32448,7 +32498,7 @@ var init_sentry_config = __esm({
32448
32498
  environment = process.env.SENTRY_ENV === "dev" ? "dev" : "prod";
32449
32499
  SENTRY_CONFIG = {
32450
32500
  projectName: "okx/openclaw-okx-a2a-extension",
32451
- release: "0.2.16",
32501
+ release: "0.2.17-beta-ab42219842-261020165552",
32452
32502
  environment,
32453
32503
  runtimeContainer: normalizeRuntimeContainer(process.env.OKX_A2A_RUNTIME_CONTAINER)
32454
32504
  };
@@ -32482,7 +32532,7 @@ function isPostjectRunnable() {
32482
32532
  function resolvePostjectCommand() {
32483
32533
  try {
32484
32534
  const cliPath = (0, import_node_module.createRequire)(__filename).resolve("postject/dist/cli.js");
32485
- if ((0, import_node_fs21.existsSync)(cliPath)) {
32535
+ if ((0, import_node_fs22.existsSync)(cliPath)) {
32486
32536
  return { command: process.execPath, prefixArgs: [cliPath] };
32487
32537
  }
32488
32538
  } catch {
@@ -32553,26 +32603,26 @@ function buildSeaConfig(entryPath, blobPath) {
32553
32603
  }
32554
32604
  async function installWindowsNativeLauncher(options) {
32555
32605
  const nodeExe = options.nodeExe ?? process.execPath;
32556
- if (!(0, import_node_fs21.existsSync)(options.cliPath)) {
32606
+ if (!(0, import_node_fs22.existsSync)(options.cliPath)) {
32557
32607
  throw new Error(`cannot build okx-a2a.exe: CLI entry not found at ${options.cliPath}`);
32558
32608
  }
32559
- if (!(0, import_node_fs21.existsSync)(nodeExe)) {
32609
+ if (!(0, import_node_fs22.existsSync)(nodeExe)) {
32560
32610
  throw new Error(`cannot build okx-a2a.exe: node executable not found at ${nodeExe}`);
32561
32611
  }
32562
32612
  const exePath = (0, import_node_path28.join)(options.targetDir, NATIVE_LAUNCHER_EXE_NAME);
32563
- (0, import_node_fs21.mkdirSync)(options.targetDir, { recursive: true });
32564
- const work = (0, import_node_fs21.mkdtempSync)((0, import_node_path28.join)((0, import_node_os9.tmpdir)(), "okx-a2a-sea-"));
32613
+ (0, import_node_fs22.mkdirSync)(options.targetDir, { recursive: true });
32614
+ const work = (0, import_node_fs22.mkdtempSync)((0, import_node_path28.join)((0, import_node_os9.tmpdir)(), "okx-a2a-sea-"));
32565
32615
  try {
32566
32616
  const entryPath = (0, import_node_path28.join)(work, "launcher-entry.js");
32567
32617
  const blobPath = (0, import_node_path28.join)(work, "okx-a2a.blob");
32568
32618
  const configPath = (0, import_node_path28.join)(work, "sea-config.json");
32569
- (0, import_node_fs21.writeFileSync)(entryPath, buildLauncherEntryJs(options.cliPath), "utf8");
32570
- (0, import_node_fs21.writeFileSync)(configPath, buildSeaConfig(entryPath, blobPath), "utf8");
32619
+ (0, import_node_fs22.writeFileSync)(entryPath, buildLauncherEntryJs(options.cliPath), "utf8");
32620
+ (0, import_node_fs22.writeFileSync)(configPath, buildSeaConfig(entryPath, blobPath), "utf8");
32571
32621
  (0, import_node_child_process7.execFileSync)(nodeExe, ["--experimental-sea-config", configPath], {
32572
32622
  stdio: "ignore",
32573
32623
  windowsHide: true
32574
32624
  });
32575
- (0, import_node_fs21.copyFileSync)(nodeExe, exePath);
32625
+ (0, import_node_fs22.copyFileSync)(nodeExe, exePath);
32576
32626
  const isMac = process.platform === "darwin";
32577
32627
  if (isMac) {
32578
32628
  try {
@@ -32592,10 +32642,10 @@ async function installWindowsNativeLauncher(options) {
32592
32642
  );
32593
32643
  return { exePath, cliPath: options.cliPath, nodeExe };
32594
32644
  } finally {
32595
- (0, import_node_fs21.rmSync)(work, { recursive: true, force: true });
32645
+ (0, import_node_fs22.rmSync)(work, { recursive: true, force: true });
32596
32646
  }
32597
32647
  }
32598
- function findWindowsNativeOkxA2aExe(pathValue, appData, userProfile, fileExists2 = import_node_fs21.existsSync) {
32648
+ function findWindowsNativeOkxA2aExe(pathValue, appData, userProfile, fileExists2 = import_node_fs22.existsSync) {
32599
32649
  const dirs = pathValue.split(";").map((d) => d.trim()).filter(Boolean);
32600
32650
  if (appData) {
32601
32651
  dirs.push((0, import_node_path28.join)(appData, "npm"));
@@ -32613,11 +32663,11 @@ function findWindowsNativeOkxA2aExe(pathValue, appData, userProfile, fileExists2
32613
32663
  }
32614
32664
  function resolveRunningCliPath() {
32615
32665
  const fromArgv = process.argv[1];
32616
- if (fromArgv && /(?:^|[\\/])cli\.js$/.test(fromArgv) && (0, import_node_fs21.existsSync)(fromArgv)) {
32666
+ if (fromArgv && /(?:^|[\\/])cli\.js$/.test(fromArgv) && (0, import_node_fs22.existsSync)(fromArgv)) {
32617
32667
  return fromArgv;
32618
32668
  }
32619
32669
  const beside = (0, import_node_path28.join)(__dirname, "cli.js");
32620
- if ((0, import_node_fs21.existsSync)(beside)) {
32670
+ if ((0, import_node_fs22.existsSync)(beside)) {
32621
32671
  return beside;
32622
32672
  }
32623
32673
  if (fromArgv) {
@@ -32639,12 +32689,12 @@ async function ensureWindowsNativeLauncher(options = {}) {
32639
32689
  const result = await installWindowsNativeLauncher({ cliPath: resolveRunningCliPath(), targetDir });
32640
32690
  return { exePath: result.exePath, installed: true };
32641
32691
  }
32642
- var import_node_child_process7, import_node_fs21, import_node_module, import_node_os9, import_node_path28, SEA_SENTINEL_FUSE, NATIVE_LAUNCHER_EXE_NAME, POSTJECT_SPEC, POSTJECT_BIN;
32692
+ var import_node_child_process7, import_node_fs22, import_node_module, import_node_os9, import_node_path28, SEA_SENTINEL_FUSE, NATIVE_LAUNCHER_EXE_NAME, POSTJECT_SPEC, POSTJECT_BIN;
32643
32693
  var init_win_native_launcher = __esm({
32644
32694
  "src/win-native-launcher.ts"() {
32645
32695
  "use strict";
32646
32696
  import_node_child_process7 = require("node:child_process");
32647
- import_node_fs21 = require("node:fs");
32697
+ import_node_fs22 = require("node:fs");
32648
32698
  import_node_module = require("node:module");
32649
32699
  import_node_os9 = require("node:os");
32650
32700
  import_node_path28 = require("node:path");
@@ -32786,7 +32836,7 @@ function buildProviderMismatchWarning(target, provider) {
32786
32836
  ].join("\n");
32787
32837
  }
32788
32838
  async function handleUpdateCommand(args) {
32789
- if (args.some(isHelpArg)) {
32839
+ if (args.some(isHelpArg2)) {
32790
32840
  printUpdateUsage();
32791
32841
  return;
32792
32842
  }
@@ -32827,7 +32877,7 @@ function resolveUpdateTarget(target) {
32827
32877
  return detectGatewayInvocation() ?? "node";
32828
32878
  }
32829
32879
  async function handleSetupCommand(args) {
32830
- if (args.some(isHelpArg)) {
32880
+ if (args.some(isHelpArg2)) {
32831
32881
  printSetupUsage();
32832
32882
  return;
32833
32883
  }
@@ -33404,7 +33454,7 @@ async function getCurrentNodeCliVersion() {
33404
33454
  return await getGlobalNpmPackageVersion(UPDATE_PACKAGES.node) ?? getBundledNodeCliVersion();
33405
33455
  }
33406
33456
  function getBundledNodeCliVersion() {
33407
- return true ? "0.2.16" : null;
33457
+ return true ? "0.2.17-beta-ab42219842-261020165552" : null;
33408
33458
  }
33409
33459
  function readConfiguredAiProvider() {
33410
33460
  const explicit = process.env.OKX_A2A_AI_PROVIDER || process.env.OKX_AGENT_TASK_AI_CLI;
@@ -33589,7 +33639,7 @@ async function updateHermes(release, options) {
33589
33639
  assertNotRunningInsideGateway("hermes");
33590
33640
  }
33591
33641
  const spec = buildNpmPackageSpec("hermes", release);
33592
- const workDir = await (0, import_promises11.mkdtemp)((0, import_node_path29.join)((0, import_node_os10.tmpdir)(), `okx-a2a-${label}-hermes-`));
33642
+ const workDir = await (0, import_promises12.mkdtemp)((0, import_node_path29.join)((0, import_node_os10.tmpdir)(), `okx-a2a-${label}-hermes-`));
33593
33643
  try {
33594
33644
  console.log(`[${label}] downloading ${spec}`);
33595
33645
  const npmTarball = await npmPack(spec, workDir);
@@ -33610,11 +33660,11 @@ async function updateHermes(release, options) {
33610
33660
  }
33611
33661
  console.log(`[${label}] hermes ${label} done`);
33612
33662
  } finally {
33613
- await (0, import_promises11.rm)(workDir, { recursive: true, force: true });
33663
+ await (0, import_promises12.rm)(workDir, { recursive: true, force: true });
33614
33664
  }
33615
33665
  }
33616
33666
  async function installGatewayPluginForDoctor(target) {
33617
- const release = isPrereleaseVersion("0.2.16") ? "beta" : "latest";
33667
+ const release = isPrereleaseVersion("0.2.17-beta-ab42219842-261020165552") ? "beta" : "latest";
33618
33668
  const insideTargetGateway = detectGatewayInvocation() === target;
33619
33669
  const options = {
33620
33670
  restart: !insideTargetGateway,
@@ -33641,7 +33691,7 @@ function setupReadyMessage(target) {
33641
33691
  async function normalizeHermesOkxA2aPluginConfig(configFile = resolveHermesConfigPath()) {
33642
33692
  let content;
33643
33693
  try {
33644
- content = await (0, import_promises11.readFile)(configFile, "utf8");
33694
+ content = await (0, import_promises12.readFile)(configFile, "utf8");
33645
33695
  } catch (error) {
33646
33696
  if (isNodeError(error) && error.code === "ENOENT") {
33647
33697
  return false;
@@ -33652,21 +33702,21 @@ async function normalizeHermesOkxA2aPluginConfig(configFile = resolveHermesConfi
33652
33702
  if (!normalized.changed) {
33653
33703
  return false;
33654
33704
  }
33655
- await (0, import_promises11.writeFile)(configFile, normalized.content);
33705
+ await (0, import_promises12.writeFile)(configFile, normalized.content);
33656
33706
  console.log(`[update] normalized Hermes plugins.enabled okx-a2a entry in ${configFile}`);
33657
33707
  return true;
33658
33708
  }
33659
33709
  async function ensureHermesOkxA2aPluginConfig(configFile = resolveHermesConfigPath(), options = {}) {
33660
33710
  let content;
33661
33711
  try {
33662
- content = await (0, import_promises11.readFile)(configFile, "utf8");
33712
+ content = await (0, import_promises12.readFile)(configFile, "utf8");
33663
33713
  } catch (error) {
33664
33714
  if (isNodeError(error) && error.code === "ENOENT") {
33665
33715
  if (options.dryRun) {
33666
33716
  return true;
33667
33717
  }
33668
- await (0, import_promises11.mkdir)((0, import_node_path29.resolve)(configFile, ".."), { recursive: true });
33669
- await (0, import_promises11.writeFile)(configFile, "plugins:\n enabled:\n - okx-a2a\n");
33718
+ await (0, import_promises12.mkdir)((0, import_node_path29.resolve)(configFile, ".."), { recursive: true });
33719
+ await (0, import_promises12.writeFile)(configFile, "plugins:\n enabled:\n - okx-a2a\n");
33670
33720
  console.log(`[update] added Hermes plugins.enabled okx-a2a entry in ${configFile}`);
33671
33721
  return true;
33672
33722
  }
@@ -33677,7 +33727,7 @@ async function ensureHermesOkxA2aPluginConfig(configFile = resolveHermesConfigPa
33677
33727
  if (options.dryRun) {
33678
33728
  return true;
33679
33729
  }
33680
- await (0, import_promises11.writeFile)(configFile, normalized.content);
33730
+ await (0, import_promises12.writeFile)(configFile, normalized.content);
33681
33731
  console.log(`[update] normalized Hermes plugins.enabled okx-a2a entry in ${configFile}`);
33682
33732
  return true;
33683
33733
  }
@@ -33688,7 +33738,7 @@ async function ensureHermesOkxA2aPluginConfig(configFile = resolveHermesConfigPa
33688
33738
  return true;
33689
33739
  }
33690
33740
  const updated = addHermesOkxA2aEnabled(content);
33691
- await (0, import_promises11.writeFile)(configFile, updated);
33741
+ await (0, import_promises12.writeFile)(configFile, updated);
33692
33742
  console.log(`[update] added Hermes plugins.enabled okx-a2a entry in ${configFile}`);
33693
33743
  return true;
33694
33744
  }
@@ -33989,7 +34039,7 @@ async function isGatewayPluginInstalled(target) {
33989
34039
  if (target === "openclaw") {
33990
34040
  return (await getInstalledOpenClawPluginInfo()).installed;
33991
34041
  }
33992
- return (0, import_node_fs22.existsSync)(resolveHermesPluginYamlPath());
34042
+ return (0, import_node_fs23.existsSync)(resolveHermesPluginYamlPath());
33993
34043
  }
33994
34044
  async function getInstalledGatewayPluginVersion(target) {
33995
34045
  if (target === "hermes") {
@@ -34078,7 +34128,7 @@ function parsePackageVersionFromText(output) {
34078
34128
  async function getInstalledHermesPluginVersion() {
34079
34129
  const pluginYaml = (0, import_node_path29.join)(process.env.HERMES_HOME ?? (0, import_node_path29.join)((0, import_node_os10.homedir)(), ".hermes"), "plugins", "platforms", "okx-a2a", "plugin.yaml");
34080
34130
  try {
34081
- const content = await (0, import_promises11.readFile)(pluginYaml, "utf8");
34131
+ const content = await (0, import_promises12.readFile)(pluginYaml, "utf8");
34082
34132
  return parsePluginYamlVersion(content);
34083
34133
  } catch (error) {
34084
34134
  if (isNodeError(error) && error.code === "ENOENT") {
@@ -34137,7 +34187,7 @@ async function npmPack(spec, destination) {
34137
34187
  return (0, import_node_path29.resolve)(destination, (0, import_node_path29.basename)(tarballName));
34138
34188
  }
34139
34189
  async function findHermesPluginTarball(distDir) {
34140
- const entries = await (0, import_promises11.readdir)(distDir);
34190
+ const entries = await (0, import_promises12.readdir)(distDir);
34141
34191
  const tarball = entries.find((entry) => /^okx-a2a-hermes-plugin-.+\.tar\.gz$/.test(entry));
34142
34192
  if (!tarball) {
34143
34193
  throw new Error(`Hermes npm package did not contain dist/okx-a2a-hermes-plugin-*.tar.gz`);
@@ -34145,7 +34195,7 @@ async function findHermesPluginTarball(distDir) {
34145
34195
  return (0, import_node_path29.join)(distDir, tarball);
34146
34196
  }
34147
34197
  async function findFirstDirectory(parent) {
34148
- const entries = await (0, import_promises11.readdir)(parent, { withFileTypes: true });
34198
+ const entries = await (0, import_promises12.readdir)(parent, { withFileTypes: true });
34149
34199
  const dir = entries.find((entry) => entry.isDirectory());
34150
34200
  if (!dir) {
34151
34201
  throw new Error(`No unpacked plugin directory found under ${parent}`);
@@ -34162,7 +34212,7 @@ function readOption2(args, name) {
34162
34212
  function hasFlag(args, name) {
34163
34213
  return args.includes(name);
34164
34214
  }
34165
- function isHelpArg(value) {
34215
+ function isHelpArg2(value) {
34166
34216
  return value === "-h" || value === "--help" || value === "help";
34167
34217
  }
34168
34218
  function isSupportedRelease(value) {
@@ -34371,13 +34421,13 @@ function buildExternalCommandInvocation(command, args, platform = process.platfo
34371
34421
  function formatExternalCommand(command, args) {
34372
34422
  return [command, ...args].join(" ");
34373
34423
  }
34374
- var import_node_child_process8, import_node_fs22, import_promises11, import_node_os10, import_node_path29, UPDATE_PACKAGES, CODEX_NPM_PACKAGE, OPENCLAW_FORCE_INSTALL_FLAG, OPENCLAW_UNSAFE_INSTALL_FLAG, OKX_A2A_PLUGIN_ID, OPENCLAW_SESSION_DM_SCOPE_CONFIG_PATH, OPENCLAW_SESSION_DM_SCOPE_CONFIG_VALUE, OPENCLAW_PLUGIN_ALLOW_CONFIG_PATH, OPENCLAW_OKX_A2A_CONVERSATION_HOOK_ACCESS_CONFIG_PATH, DEFAULT_AI_PROVIDER_LOGIN_TIMEOUT_MS, PROVIDER_CLI_AUTH_PROBE_TIMEOUT_MS, SetupBlockedError, redirectCommandStdoutToStderr;
34424
+ var import_node_child_process8, import_node_fs23, import_promises12, import_node_os10, import_node_path29, UPDATE_PACKAGES, CODEX_NPM_PACKAGE, OPENCLAW_FORCE_INSTALL_FLAG, OPENCLAW_UNSAFE_INSTALL_FLAG, OKX_A2A_PLUGIN_ID, OPENCLAW_SESSION_DM_SCOPE_CONFIG_PATH, OPENCLAW_SESSION_DM_SCOPE_CONFIG_VALUE, OPENCLAW_PLUGIN_ALLOW_CONFIG_PATH, OPENCLAW_OKX_A2A_CONVERSATION_HOOK_ACCESS_CONFIG_PATH, DEFAULT_AI_PROVIDER_LOGIN_TIMEOUT_MS, PROVIDER_CLI_AUTH_PROBE_TIMEOUT_MS, SetupBlockedError, redirectCommandStdoutToStderr;
34375
34425
  var init_update_cli = __esm({
34376
34426
  "src/update-cli.ts"() {
34377
34427
  "use strict";
34378
34428
  import_node_child_process8 = require("node:child_process");
34379
- import_node_fs22 = require("node:fs");
34380
- import_promises11 = require("node:fs/promises");
34429
+ import_node_fs23 = require("node:fs");
34430
+ import_promises12 = require("node:fs/promises");
34381
34431
  import_node_os10 = require("node:os");
34382
34432
  import_node_path29 = require("node:path");
34383
34433
  init_ai_command();
@@ -44330,7 +44380,22 @@ __export(index_exports, {
44330
44380
  DEFAULT_LOG_TAIL_LIMIT: () => DEFAULT_LOG_TAIL_LIMIT,
44331
44381
  DEFAULT_OFFLINE_REPLAY_INTERVAL_SEC: () => DEFAULT_OFFLINE_REPLAY_INTERVAL_SEC,
44332
44382
  DEFAULT_XMTP_CLIENT_RECYCLE_INTERVAL_SEC: () => DEFAULT_XMTP_CLIENT_RECYCLE_INTERVAL_SEC,
44383
+ DEVKIT_DROP_REASON: () => DEVKIT_DROP_REASON,
44384
+ DEVKIT_MAX_CONCURRENCY: () => DEVKIT_MAX_CONCURRENCY,
44385
+ DEVKIT_MAX_MESSAGE_BYTES: () => DEVKIT_MAX_MESSAGE_BYTES,
44386
+ DEVKIT_MAX_PENDING: () => DEVKIT_MAX_PENDING,
44387
+ DEVKIT_MAX_PENDING_BYTES: () => DEVKIT_MAX_PENDING_BYTES,
44388
+ DEVKIT_OUTCOME: () => DEVKIT_OUTCOME,
44389
+ DEVKIT_REQUEST_BUDGET_MS: () => DEVKIT_REQUEST_BUDGET_MS,
44390
+ DEVKIT_RESPONSE_DIAGNOSTIC_MAX_BYTES: () => DEVKIT_RESPONSE_DIAGNOSTIC_MAX_BYTES,
44391
+ DEVKIT_RESPONSE_SUMMARY_MAX_CHARS: () => DEVKIT_RESPONSE_SUMMARY_MAX_CHARS,
44392
+ DEVKIT_SERVER_APPLICATION_ID: () => DEVKIT_SERVER_APPLICATION_ID,
44393
+ DEVKIT_SERVER_DB_NAME: () => DEVKIT_SERVER_DB_NAME,
44394
+ DEVKIT_SERVER_SCHEMA_VERSION: () => DEVKIT_SERVER_SCHEMA_VERSION,
44333
44395
  DOCTOR_MIN_NODE_VERSION: () => DOCTOR_MIN_NODE_VERSION,
44396
+ DevkitDeliveryDispatcher: () => DevkitDeliveryDispatcher,
44397
+ DevkitServerStore: () => DevkitServerStore,
44398
+ DevkitServerStoreError: () => DevkitServerStoreError,
44334
44399
  GatewayOutboundBehavior: () => GatewayOutboundBehavior,
44335
44400
  HEARTBEAT_GATEWAY_CHECK_TIMEOUT_MS: () => HEARTBEAT_GATEWAY_CHECK_TIMEOUT_MS,
44336
44401
  InboundReplayGate: () => InboundReplayGate,
@@ -44359,6 +44424,9 @@ __export(index_exports, {
44359
44424
  UserCancelledAiProviderSelectionError: () => UserCancelledAiProviderSelectionError,
44360
44425
  WALLET_STATUS_TIMEOUT_MS: () => WALLET_STATUS_TIMEOUT_MS,
44361
44426
  XMTP_CLIENT_RECYCLE_INTERVAL_ENV: () => XMTP_CLIENT_RECYCLE_INTERVAL_ENV,
44427
+ XMTP_CREATION_COOLDOWN_MS: () => XMTP_CREATION_COOLDOWN_MS,
44428
+ XmtpCreationCooldown: () => XmtpCreationCooldown,
44429
+ XmtpCreationCooldownSkipError: () => XmtpCreationCooldownSkipError,
44362
44430
  XmtpDm: () => Dm,
44363
44431
  XmtpGroup: () => Group,
44364
44432
  XmtpService: () => XmtpService,
@@ -44385,6 +44453,7 @@ __export(index_exports, {
44385
44453
  buildExternalCommandInvocation: () => buildExternalCommandInvocation,
44386
44454
  buildGatewayOutboundExtra: () => buildGatewayOutboundExtra,
44387
44455
  buildInboundTerminalExtras: () => buildInboundTerminalExtras,
44456
+ buildJobEnvelope: () => buildJobEnvelope,
44388
44457
  buildLaunchdPlist: () => buildLaunchdPlist,
44389
44458
  buildLauncherEntryJs: () => buildLauncherEntryJs,
44390
44459
  buildMessageEligibleArgs: () => buildMessageEligibleArgs,
@@ -44395,6 +44464,7 @@ __export(index_exports, {
44395
44464
  buildSchtasksRunArgs: () => buildSchtasksRunArgs,
44396
44465
  buildSeaConfig: () => buildSeaConfig,
44397
44466
  buildServicePath: () => buildServicePath,
44467
+ buildSessionEnvelope: () => buildSessionEnvelope,
44398
44468
  buildSessionKey: () => buildSessionKey,
44399
44469
  buildSystemMessageNotice: () => buildSystemMessageNotice,
44400
44470
  buildSystemStoredMessage: () => buildSystemStoredMessage,
@@ -44412,6 +44482,8 @@ __export(index_exports, {
44412
44482
  checkCodexCliAuthStatus: () => checkCodexCliAuthStatus,
44413
44483
  checkCodexReadiness: () => checkCodexReadiness,
44414
44484
  claimActiveDaemon: () => claimActiveDaemon,
44485
+ classifyFetchFailure: () => classifyFetchFailure,
44486
+ classifyHttpOutcome: () => classifyHttpOutcome,
44415
44487
  classifyJobBindingSource: () => classifyJobBindingSource,
44416
44488
  clearCodexReadinessCache: () => clearCodexReadinessCache,
44417
44489
  codexCommandResolvesWithoutOverride: () => codexCommandResolvesWithoutOverride,
@@ -44420,6 +44492,7 @@ __export(index_exports, {
44420
44492
  collectCodexCommandCandidates: () => collectCodexCommandCandidates,
44421
44493
  commandExists: () => commandExists,
44422
44494
  createAiToolFailureTracker: () => createAiToolFailureTracker,
44495
+ createDevkitAutoRouter: () => createDevkitAutoRouter,
44423
44496
  createFileMessageHandler: () => createFileMessageHandler,
44424
44497
  createOutboundBehavior: () => createOutboundBehavior,
44425
44498
  createUserAttentionWatchParentMonitor: () => createUserAttentionWatchParentMonitor,
@@ -44430,6 +44503,7 @@ __export(index_exports, {
44430
44503
  detectGatewayInvocation: () => detectGatewayInvocation,
44431
44504
  detectMessageEligibleOfflineReplaySupport: () => detectMessageEligibleOfflineReplaySupport,
44432
44505
  detectRuntime: () => detectRuntime,
44506
+ devkitServerDbExists: () => devkitServerDbExists,
44433
44507
  ensureDaemonReady: () => ensureDaemonReady,
44434
44508
  ensureDefaultAiProvider: () => ensureDefaultAiProvider,
44435
44509
  ensureOpenClawOkxA2aPluginConfig: () => ensureOpenClawOkxA2aPluginConfig,
@@ -44439,6 +44513,7 @@ __export(index_exports, {
44439
44513
  exportDiagnosticLogs: () => exportDiagnosticLogs,
44440
44514
  extractAiSessionId: () => extractAiSessionId,
44441
44515
  extractDirectToUserNotification: () => extractDirectToUserNotification,
44516
+ extractRateLimitEndpoint: () => extractRateLimitEndpoint,
44442
44517
  extractXmtpSentAtMs: () => extractXmtpSentAtMs2,
44443
44518
  findWindowsNativeOkxA2aExe: () => findWindowsNativeOkxA2aExe,
44444
44519
  followFile: () => followFile,
@@ -44449,7 +44524,9 @@ __export(index_exports, {
44449
44524
  getResolvedOnchainosBinForTests: () => getResolvedOnchainosBinForTests,
44450
44525
  getRuntimeMetadata: () => getRuntimeMetadata,
44451
44526
  getSessionBusyTracker: () => getSessionBusyTracker,
44527
+ getXmtpCreationCooldown: () => getXmtpCreationCooldown,
44452
44528
  handleCapabilitiesCommand: () => handleCapabilitiesCommand,
44529
+ handleDevkitCommand: () => handleDevkitCommand,
44453
44530
  handleDoctorCommand: () => handleDoctorCommand,
44454
44531
  handleXmtpDebugCommand: () => handleXmtpDebugCommand,
44455
44532
  handleXmtpSendCommand: () => handleXmtpSendCommand,
@@ -44479,6 +44556,7 @@ __export(index_exports, {
44479
44556
  isTagKey: () => isTagKey,
44480
44557
  isValidExternalJobId: () => isValidExternalJobId,
44481
44558
  isWindowsElevated: () => isWindowsElevated,
44559
+ isXmtpRateLimitError: () => isXmtpRateLimitError,
44482
44560
  killProcessTree: () => killProcessTree,
44483
44561
  launchdPlistHasCurrentRestartPolicy: () => launchdPlistHasCurrentRestartPolicy,
44484
44562
  listAllAgentsWithMetadata: () => listAllAgentsWithMetadata,
@@ -44506,6 +44584,7 @@ __export(index_exports, {
44506
44584
  persistCurrentRuntimeSelectionForNewJob: () => persistCurrentRuntimeSelectionForNewJob,
44507
44585
  pickOnchainosWin32Candidate: () => pickOnchainosWin32Candidate,
44508
44586
  prepareAndBindCurrentRuntimeForNewJob: () => prepareAndBindCurrentRuntimeForNewJob,
44587
+ printDevkitUsage: () => printDevkitUsage,
44509
44588
  printLogsExportUsage: () => printLogsExportUsage,
44510
44589
  printXmtpTestUsage: () => printXmtpTestUsage,
44511
44590
  probeCodexAuthStatus: () => probeCodexAuthStatus,
@@ -44517,6 +44596,7 @@ __export(index_exports, {
44517
44596
  readLastLines: () => readLastLines,
44518
44597
  readParentProcessCommandForPlatform: () => readParentProcessCommandForPlatform,
44519
44598
  readUserAttentionWatcherEvent: () => readUserAttentionWatcherEvent,
44599
+ redactSummary: () => redactSummary,
44520
44600
  refreshAgentsAndWait: () => refreshAgentsAndWait,
44521
44601
  refreshOnchainosVersionMetadata: () => refreshOnchainosVersionMetadata,
44522
44602
  registerUserAttentionWatcher: () => registerUserAttentionWatcher,
@@ -44528,6 +44608,7 @@ __export(index_exports, {
44528
44608
  reportUserNotificationFailure: () => reportUserNotificationFailure,
44529
44609
  resetMessageEligibleOfflineReplayCapabilityForTests: () => resetMessageEligibleOfflineReplayCapabilityForTests,
44530
44610
  resetResolvedOnchainosBinForTests: () => resetResolvedOnchainosBinForTests,
44611
+ resetXmtpCreationCooldownForTests: () => resetXmtpCreationCooldownForTests,
44531
44612
  resolveAiPermissionPreset: () => resolveAiPermissionPreset,
44532
44613
  resolveAiProviderCommand: () => resolveAiProviderCommand,
44533
44614
  resolveAiProviderCommandWithSource: () => resolveAiProviderCommandWithSource,
@@ -44538,6 +44619,7 @@ __export(index_exports, {
44538
44619
  resolveCodexCommandSource: () => resolveCodexCommandSource,
44539
44620
  resolveConfiguredAiProvider: () => resolveConfiguredAiProvider,
44540
44621
  resolveConfiguredAiProviderForJob: () => resolveConfiguredAiProviderForJob,
44622
+ resolveDevkitServerDbPath: () => resolveDevkitServerDbPath,
44541
44623
  resolveDirectCommunicationSessionTarget: () => resolveDirectCommunicationSessionTarget,
44542
44624
  resolveDoctorTarget: () => resolveDoctorTarget,
44543
44625
  resolveEnvelopePayload: () => resolveEnvelopePayload,
@@ -44575,6 +44657,7 @@ __export(index_exports, {
44575
44657
  startDaemonRespectingSupervisor: () => startDaemonRespectingSupervisor,
44576
44658
  startUserAttentionEventServer: () => startUserAttentionEventServer,
44577
44659
  startUserAttentionWatcherCoordinator: () => startUserAttentionWatcherCoordinator,
44660
+ stopAndCloseXmtpClient: () => stopAndCloseXmtpClient,
44578
44661
  stopDaemon: () => stopDaemon,
44579
44662
  stopOpenClawGateway: () => stopOpenClawGateway,
44580
44663
  stopSystemdAutostart: () => stopSystemdAutostart,
@@ -56467,6 +56550,188 @@ function reportSessionExpired(command) {
56467
56550
  );
56468
56551
  }
56469
56552
 
56553
+ // ../core/src/xmtp-sdk/rate-limit-cooldown.ts
56554
+ var MAX_CAUSE_DEPTH2 = 4;
56555
+ var XMTP_CREATION_COOLDOWN_MS = 33e4;
56556
+ var RATE_LIMIT_PATTERNS = [
56557
+ /some resource has been exhausted/i,
56558
+ /exceeds rate limit/i,
56559
+ /resource_exhausted/i
56560
+ ];
56561
+ var KNOWN_RATE_LIMIT_ENDPOINTS = [
56562
+ /\bGetInboxIds\b/i,
56563
+ /\bGetIdentityUpdates\b/i
56564
+ ];
56565
+ function asErrorLike2(value) {
56566
+ return value instanceof Error ? value : void 0;
56567
+ }
56568
+ function causeChain2(err) {
56569
+ const chain = [];
56570
+ const seen = /* @__PURE__ */ new Set();
56571
+ let current = err;
56572
+ while (chain.length < MAX_CAUSE_DEPTH2) {
56573
+ chain.push(current);
56574
+ const errorLike = asErrorLike2(current);
56575
+ if (!errorLike || seen.has(errorLike)) {
56576
+ break;
56577
+ }
56578
+ seen.add(errorLike);
56579
+ current = errorLike.cause;
56580
+ if (current === void 0) {
56581
+ break;
56582
+ }
56583
+ }
56584
+ return chain;
56585
+ }
56586
+ function messageOf(node) {
56587
+ return (node instanceof Error ? node.message : String(node)).toLowerCase();
56588
+ }
56589
+ function isXmtpRateLimitError(err) {
56590
+ if (err === void 0 || err === null) {
56591
+ return false;
56592
+ }
56593
+ const chain = causeChain2(err);
56594
+ return chain.some(
56595
+ (node) => RATE_LIMIT_PATTERNS.some((pattern) => pattern.test(messageOf(node)))
56596
+ );
56597
+ }
56598
+ function extractRateLimitEndpoint(err) {
56599
+ if (err === void 0 || err === null) {
56600
+ return void 0;
56601
+ }
56602
+ const chain = causeChain2(err);
56603
+ for (const node of chain) {
56604
+ const message = messageOf(node);
56605
+ for (const pattern of KNOWN_RATE_LIMIT_ENDPOINTS) {
56606
+ const match = pattern.exec(message);
56607
+ if (match) {
56608
+ return /GetInboxIds/i.test(match[0]) ? "GetInboxIds" : "GetIdentityUpdates";
56609
+ }
56610
+ }
56611
+ }
56612
+ return void 0;
56613
+ }
56614
+ var XmtpCreationCooldownSkipError = class extends Error {
56615
+ remainingMs;
56616
+ address;
56617
+ agentId;
56618
+ constructor(remainingMs, address, agentId) {
56619
+ super("xmtp creation suppressed during rate-limit cooldown");
56620
+ this.name = "XmtpCreationCooldownSkipError";
56621
+ this.remainingMs = remainingMs;
56622
+ this.address = address;
56623
+ this.agentId = agentId;
56624
+ }
56625
+ };
56626
+ var XmtpCreationCooldown = class {
56627
+ cooldownUntilMs = null;
56628
+ probeInFlight = false;
56629
+ suppressedCreateCount = 0;
56630
+ rateLimitHitCount = 0;
56631
+ probeCount = 0;
56632
+ inFlightCreateCount = 0;
56633
+ beginCreateAttempt(nowMs = Date.now()) {
56634
+ if (this.cooldownUntilMs === null) {
56635
+ this.inFlightCreateCount++;
56636
+ return { allowed: true, mode: "normal" };
56637
+ }
56638
+ if (nowMs < this.cooldownUntilMs) {
56639
+ this.suppressedCreateCount++;
56640
+ return {
56641
+ allowed: false,
56642
+ mode: "blocked",
56643
+ remainingMs: Math.max(0, this.cooldownUntilMs - nowMs)
56644
+ };
56645
+ }
56646
+ if (this.probeInFlight) {
56647
+ this.suppressedCreateCount++;
56648
+ return { allowed: false, mode: "blocked", remainingMs: 0 };
56649
+ }
56650
+ this.probeInFlight = true;
56651
+ this.inFlightCreateCount++;
56652
+ this.probeCount++;
56653
+ return { allowed: true, mode: "probe" };
56654
+ }
56655
+ recordCreateSuccess(decision, _nowMs = Date.now()) {
56656
+ this.inFlightCreateCount = Math.max(0, this.inFlightCreateCount - 1);
56657
+ if (decision.mode === "probe") {
56658
+ this.cooldownUntilMs = null;
56659
+ this.probeInFlight = false;
56660
+ }
56661
+ }
56662
+ recordRateLimit(decision, nowMs = Date.now()) {
56663
+ this.inFlightCreateCount = Math.max(0, this.inFlightCreateCount - 1);
56664
+ this.cooldownUntilMs = nowMs + XMTP_CREATION_COOLDOWN_MS;
56665
+ this.rateLimitHitCount++;
56666
+ this.probeInFlight = false;
56667
+ void decision;
56668
+ }
56669
+ recordCreateFailure(decision, nowMs = Date.now()) {
56670
+ this.inFlightCreateCount = Math.max(0, this.inFlightCreateCount - 1);
56671
+ if (decision.mode === "probe") {
56672
+ this.cooldownUntilMs = nowMs + XMTP_CREATION_COOLDOWN_MS;
56673
+ this.probeInFlight = false;
56674
+ }
56675
+ }
56676
+ isCoolingDown(nowMs = Date.now()) {
56677
+ return this.cooldownUntilMs !== null && nowMs < this.cooldownUntilMs;
56678
+ }
56679
+ remainingMs(nowMs = Date.now()) {
56680
+ return this.cooldownUntilMs === null ? 0 : Math.max(0, this.cooldownUntilMs - nowMs);
56681
+ }
56682
+ snapshot(nowMs = Date.now()) {
56683
+ return {
56684
+ coolingDown: this.isCoolingDown(nowMs),
56685
+ cooldownUntilMs: this.cooldownUntilMs,
56686
+ remainingMs: this.remainingMs(nowMs),
56687
+ probeInFlight: this.probeInFlight,
56688
+ suppressedCreateCount: this.suppressedCreateCount,
56689
+ rateLimitHitCount: this.rateLimitHitCount,
56690
+ probeCount: this.probeCount,
56691
+ inFlightCreateCount: this.inFlightCreateCount
56692
+ };
56693
+ }
56694
+ resetForTests() {
56695
+ this.cooldownUntilMs = null;
56696
+ this.probeInFlight = false;
56697
+ this.suppressedCreateCount = 0;
56698
+ this.rateLimitHitCount = 0;
56699
+ this.probeCount = 0;
56700
+ this.inFlightCreateCount = 0;
56701
+ }
56702
+ };
56703
+ var singleton;
56704
+ function getXmtpCreationCooldown() {
56705
+ if (!singleton) {
56706
+ singleton = new XmtpCreationCooldown();
56707
+ }
56708
+ return singleton;
56709
+ }
56710
+ function resetXmtpCreationCooldownForTests() {
56711
+ getXmtpCreationCooldown().resetForTests();
56712
+ }
56713
+
56714
+ // ../core/src/xmtp-sdk/client-lifecycle.ts
56715
+ async function stopAndCloseXmtpClient(agent, ctx) {
56716
+ let stopped = true;
56717
+ try {
56718
+ await Promise.resolve(agent.stop());
56719
+ } catch {
56720
+ stopped = false;
56721
+ }
56722
+ const close2 = agent.client?.close;
56723
+ if (typeof close2 !== "function") {
56724
+ return { stopped, closed: false, closeFailed: false };
56725
+ }
56726
+ try {
56727
+ await Promise.resolve(close2.call(agent.client));
56728
+ return { stopped, closed: true, closeFailed: false };
56729
+ } catch (err) {
56730
+ ctx.onCloseError?.(err);
56731
+ return { stopped, closed: false, closeFailed: true };
56732
+ }
56733
+ }
56734
+
56470
56735
  // ../core/src/xmtp-sdk/index.ts
56471
56736
  var DEFAULT_DATA_DIR = resolveA2aTaskPaths().xmtpDir;
56472
56737
  var XMTP_INSTALLATION_WARNING_THRESHOLD = 2;
@@ -57150,21 +57415,78 @@ var XmtpService = class _XmtpService {
57150
57415
  }
57151
57416
  async createClientForAgent(agentInfo, options = {}) {
57152
57417
  const address = agentInfo.communicationAddress;
57153
- const signer = this.tools.createSigner(agentInfo);
57154
- const dbPath = (inboxId2) => `${this.dataDir}/${inboxId2}-${this.env}.db3`;
57155
- const agent = await createAgentWithInstallationPrune(signer, {
57156
- dbPath,
57157
- env: this.env
57158
- }, {
57159
- address,
57160
- agentId: agentInfo.agentId,
57161
- logPrefix: options.logPrefix
57162
- });
57163
- const inboxId = agent.client?.inboxId ?? "";
57164
- logWithTimestamp(
57165
- `[xmtp-sdk] xmtp_client_ready agentId=${agentInfo.agentId} address=${address} inboxId=${inboxId} dbPath=${inboxId ? dbPath(inboxId) : "(unknown)"} lastSync=${formatLogTimestamp2(this.syncByAddress.get(address))}`
57166
- );
57167
- return { address, agent, agentInfo };
57418
+ const phase = options.logPrefix ?? "[xmtp-sdk]";
57419
+ const cooldown = getXmtpCreationCooldown();
57420
+ const decision = cooldown.beginCreateAttempt();
57421
+ if (!decision.allowed) {
57422
+ logger.info(LogEvent.XMTP_RATE_LIMIT_CREATE_SUPPRESSED, {
57423
+ onchainosAgentId: agentInfo.agentId,
57424
+ walletAddress: address,
57425
+ cooldownRemainingMs: String(decision.remainingMs ?? 0),
57426
+ phase
57427
+ });
57428
+ throw new XmtpCreationCooldownSkipError(
57429
+ decision.remainingMs ?? 0,
57430
+ address,
57431
+ agentInfo.agentId
57432
+ );
57433
+ }
57434
+ if (decision.mode === "probe") {
57435
+ logger.info(LogEvent.XMTP_RATE_LIMIT_PROBE, {
57436
+ onchainosAgentId: agentInfo.agentId,
57437
+ walletAddress: address,
57438
+ phase: "probe-start",
57439
+ probeCount: String(cooldown.snapshot().probeCount)
57440
+ });
57441
+ }
57442
+ try {
57443
+ const signer = this.tools.createSigner(agentInfo);
57444
+ const dbPath = (inboxId2) => `${this.dataDir}/${inboxId2}-${this.env}.db3`;
57445
+ const agent = await createAgentWithInstallationPrune(signer, {
57446
+ dbPath,
57447
+ env: this.env
57448
+ }, {
57449
+ address,
57450
+ agentId: agentInfo.agentId,
57451
+ logPrefix: options.logPrefix
57452
+ });
57453
+ cooldown.recordCreateSuccess(decision);
57454
+ if (decision.mode === "probe") {
57455
+ logger.info(LogEvent.XMTP_RATE_LIMIT_RECOVERED, {
57456
+ onchainosAgentId: agentInfo.agentId,
57457
+ walletAddress: address,
57458
+ phase: "probe-success"
57459
+ });
57460
+ }
57461
+ const inboxId = agent.client?.inboxId ?? "";
57462
+ logWithTimestamp(
57463
+ `[xmtp-sdk] xmtp_client_ready agentId=${agentInfo.agentId} address=${address} inboxId=${inboxId} dbPath=${inboxId ? dbPath(inboxId) : "(unknown)"} lastSync=${formatLogTimestamp2(this.syncByAddress.get(address))}`
57464
+ );
57465
+ return { address, agent, agentInfo };
57466
+ } catch (err) {
57467
+ if (isXmtpRateLimitError(err)) {
57468
+ cooldown.recordRateLimit(decision);
57469
+ logger.info(LogEvent.XMTP_RATE_LIMIT_COOLDOWN_STARTED, {
57470
+ ...agentExtras({ walletAddress: address, onchainosAgentId: agentInfo.agentId }),
57471
+ rateLimitIdentified: "true",
57472
+ endpoint: extractRateLimitEndpoint(err) ?? "unknown",
57473
+ cooldownMs: String(XMTP_CREATION_COOLDOWN_MS),
57474
+ cooldownExpiresAtMs: String(cooldown.snapshot().cooldownUntilMs ?? ""),
57475
+ inFlightCreateCount: String(cooldown.snapshot().inFlightCreateCount),
57476
+ probe: String(decision.mode === "probe")
57477
+ });
57478
+ } else {
57479
+ cooldown.recordCreateFailure(decision);
57480
+ if (decision.mode === "probe") {
57481
+ logger.info(LogEvent.XMTP_RATE_LIMIT_PROBE, {
57482
+ onchainosAgentId: agentInfo.agentId,
57483
+ walletAddress: address,
57484
+ phase: "probe-failed-nonratelimit"
57485
+ });
57486
+ }
57487
+ }
57488
+ throw err;
57489
+ }
57168
57490
  }
57169
57491
  async recordInstallationHealth(params) {
57170
57492
  const { address, agent, agentInfo, phase, attempt } = params;
@@ -57315,22 +57637,28 @@ var XmtpService = class _XmtpService {
57315
57637
  });
57316
57638
  } else {
57317
57639
  failedAgents.push(agents[i]);
57318
- logWithTimestamp(
57319
- `[xmtp-sdk] identity init failed: ${agents[i].communicationAddress} (agentId=${agents[i].agentId})`,
57320
- r.reason
57321
- );
57322
- logger.error(
57323
- LogEvent.XMTP_CONNECTION_FAILED,
57324
- r.reason instanceof Error ? r.reason : new Error(String(r.reason)),
57325
- {
57326
- walletAddress: agents[i].communicationAddress,
57327
- onchainosAgentId: agents[i].agentId,
57328
- attempt: "1"
57329
- }
57330
- );
57640
+ if (r.reason instanceof XmtpCreationCooldownSkipError) {
57641
+ logWithTimestamp(
57642
+ `[xmtp-sdk] identity init suppressed (rate-limit cooldown): ${agents[i].communicationAddress} (agentId=${agents[i].agentId})`
57643
+ );
57644
+ } else {
57645
+ logWithTimestamp(
57646
+ `[xmtp-sdk] identity init failed: ${agents[i].communicationAddress} (agentId=${agents[i].agentId})`,
57647
+ r.reason
57648
+ );
57649
+ logger.error(
57650
+ LogEvent.XMTP_CONNECTION_FAILED,
57651
+ r.reason instanceof Error ? r.reason : new Error(String(r.reason)),
57652
+ {
57653
+ walletAddress: agents[i].communicationAddress,
57654
+ onchainosAgentId: agents[i].agentId,
57655
+ attempt: "1"
57656
+ }
57657
+ );
57658
+ }
57331
57659
  }
57332
57660
  }
57333
- if (failedAgents.length > 0) {
57661
+ if (failedAgents.length > 0 && !getXmtpCreationCooldown().isCoolingDown()) {
57334
57662
  logWithTimestamp(
57335
57663
  `[xmtp-sdk] ${failedAgents.length} client(s) failed to initialize, retrying in 1s...`
57336
57664
  );
@@ -57370,6 +57698,11 @@ var XmtpService = class _XmtpService {
57370
57698
  phase: "init",
57371
57699
  attempt: "2"
57372
57700
  });
57701
+ } else if (r.reason instanceof XmtpCreationCooldownSkipError) {
57702
+ const info = failedAgents[i];
57703
+ logWithTimestamp(
57704
+ `[xmtp-sdk] retry suppressed (rate-limit cooldown): ${info.communicationAddress} (agentId=${info.agentId})`
57705
+ );
57373
57706
  } else {
57374
57707
  const info = failedAgents[i];
57375
57708
  logWithTimestamp(
@@ -57465,7 +57798,16 @@ var XmtpService = class _XmtpService {
57465
57798
  try {
57466
57799
  this.cancelStreamRecoveryForAddress(address);
57467
57800
  this.stoppedAddresses.add(address.toLowerCase());
57468
- client.stop();
57801
+ await stopAndCloseXmtpClient(client, {
57802
+ address,
57803
+ agentId: agentInfo.agentId,
57804
+ phase: "refresh/remove",
57805
+ onCloseError: (err) => logger.error(
57806
+ LogEvent.XMTP_CLIENT_CLOSE_FAILED,
57807
+ err instanceof Error ? err : new Error(String(err)),
57808
+ { walletAddress: address, onchainosAgentId: agentInfo.agentId, phase: "refresh/remove" }
57809
+ )
57810
+ });
57469
57811
  logWithTimestamp(
57470
57812
  `[xmtp-sdk] refresh: stopped client: ${address} (agentId=${agentInfo.agentId})`
57471
57813
  );
@@ -57552,23 +57894,29 @@ var XmtpService = class _XmtpService {
57552
57894
  });
57553
57895
  } else {
57554
57896
  failedAgents.push(added[i]);
57555
- logWithTimestamp(
57556
- `[xmtp-sdk] refresh: identity init failed: ${added[i].communicationAddress} (agentId=${added[i].agentId})`,
57557
- r.reason
57558
- );
57559
- logger.error(
57560
- LogEvent.XMTP_CONNECTION_FAILED,
57561
- r.reason instanceof Error ? r.reason : new Error(String(r.reason)),
57562
- {
57563
- walletAddress: added[i].communicationAddress,
57564
- onchainosAgentId: added[i].agentId,
57565
- phase: "refresh",
57566
- attempt: "1"
57567
- }
57568
- );
57897
+ if (r.reason instanceof XmtpCreationCooldownSkipError) {
57898
+ logWithTimestamp(
57899
+ `[xmtp-sdk] refresh: identity init suppressed (rate-limit cooldown): ${added[i].communicationAddress} (agentId=${added[i].agentId})`
57900
+ );
57901
+ } else {
57902
+ logWithTimestamp(
57903
+ `[xmtp-sdk] refresh: identity init failed: ${added[i].communicationAddress} (agentId=${added[i].agentId})`,
57904
+ r.reason
57905
+ );
57906
+ logger.error(
57907
+ LogEvent.XMTP_CONNECTION_FAILED,
57908
+ r.reason instanceof Error ? r.reason : new Error(String(r.reason)),
57909
+ {
57910
+ walletAddress: added[i].communicationAddress,
57911
+ onchainosAgentId: added[i].agentId,
57912
+ phase: "refresh",
57913
+ attempt: "1"
57914
+ }
57915
+ );
57916
+ }
57569
57917
  }
57570
57918
  }
57571
- if (failedAgents.length > 0) {
57919
+ if (failedAgents.length > 0 && !getXmtpCreationCooldown().isCoolingDown()) {
57572
57920
  logWithTimestamp(
57573
57921
  `[xmtp-sdk] refresh: ${failedAgents.length} client(s) failed to initialize, retrying in 1s...`
57574
57922
  );
@@ -57611,6 +57959,11 @@ var XmtpService = class _XmtpService {
57611
57959
  phase: "refresh",
57612
57960
  attempt: "2"
57613
57961
  });
57962
+ } else if (r.reason instanceof XmtpCreationCooldownSkipError) {
57963
+ const info = failedAgents[i];
57964
+ logWithTimestamp(
57965
+ `[xmtp-sdk] refresh: retry suppressed (rate-limit cooldown): ${info.communicationAddress} (agentId=${info.agentId})`
57966
+ );
57614
57967
  } else {
57615
57968
  const info = failedAgents[i];
57616
57969
  logWithTimestamp(
@@ -57674,6 +58027,18 @@ var XmtpService = class _XmtpService {
57674
58027
  async recycleXmtpClients() {
57675
58028
  await this._backupReady;
57676
58029
  const startedAt = Date.now();
58030
+ if (getXmtpCreationCooldown().isCoolingDown()) {
58031
+ logWithTimestamp("[xmtp-sdk] recycle skipped \u2014 rate-limit cooldown active");
58032
+ return {
58033
+ clients: this.clients.size,
58034
+ recycled: 0,
58035
+ failed: 0,
58036
+ replayed: 0,
58037
+ skipped: 0,
58038
+ durationMs: Date.now() - startedAt,
58039
+ addresses: []
58040
+ };
58041
+ }
57677
58042
  const addresses = [];
57678
58043
  let recycled = 0;
57679
58044
  let failed = 0;
@@ -57692,7 +58057,16 @@ var XmtpService = class _XmtpService {
57692
58057
  try {
57693
58058
  this.cancelStreamRecoveryForAddress(address);
57694
58059
  this.stoppedAddresses.add(addressKey);
57695
- await Promise.resolve(oldClient.stop());
58060
+ await stopAndCloseXmtpClient(oldClient, {
58061
+ address,
58062
+ agentId: agentInfo.agentId,
58063
+ phase: "recycle",
58064
+ onCloseError: (err) => logger.error(
58065
+ LogEvent.XMTP_CLIENT_CLOSE_FAILED,
58066
+ err instanceof Error ? err : new Error(String(err)),
58067
+ { walletAddress: address, onchainosAgentId: agentInfo.agentId, phase: "recycle" }
58068
+ )
58069
+ });
57696
58070
  this.clients.delete(address);
57697
58071
  this.inboundReplayGates.delete(addressKey);
57698
58072
  this.replayScanFailuresByAddress.delete(addressKey);
@@ -57779,6 +58153,12 @@ var XmtpService = class _XmtpService {
57779
58153
  phase: "recycle/create-client"
57780
58154
  }
57781
58155
  );
58156
+ if (isXmtpRateLimitError(err)) {
58157
+ logWithTimestamp(
58158
+ "[xmtp-sdk] recycle: rate-limit on recreate \u2014 stopping remaining recycles"
58159
+ );
58160
+ break;
58161
+ }
57782
58162
  }
57783
58163
  }
57784
58164
  return {
@@ -60854,12 +61234,12 @@ var SessionBusyTracker = class {
60854
61234
  }
60855
61235
  }
60856
61236
  };
60857
- var singleton = null;
61237
+ var singleton2 = null;
60858
61238
  function getSessionBusyTracker() {
60859
- if (!singleton) {
60860
- singleton = new SessionBusyTracker();
61239
+ if (!singleton2) {
61240
+ singleton2 = new SessionBusyTracker();
60861
61241
  }
60862
- return singleton;
61242
+ return singleton2;
60863
61243
  }
60864
61244
 
60865
61245
  // src/openclaw-gateway.ts
@@ -61394,7 +61774,7 @@ function buildConnectParams(config, instanceId, protocolVersion) {
61394
61774
  client: {
61395
61775
  id: "gateway-client",
61396
61776
  displayName: "okx-a2a-node",
61397
- version: "0.2.16",
61777
+ version: "0.2.17-beta-ab42219842-261020165552",
61398
61778
  platform: "node",
61399
61779
  mode: "backend",
61400
61780
  instanceId
@@ -61405,7 +61785,7 @@ function buildConnectParams(config, instanceId, protocolVersion) {
61405
61785
  commands: [],
61406
61786
  permissions: {},
61407
61787
  locale: Intl.DateTimeFormat().resolvedOptions().locale || "en-US",
61408
- userAgent: `okx-a2a-node/${"0.2.16"}`,
61788
+ userAgent: `okx-a2a-node/${"0.2.17-beta-ab42219842-261020165552"}`,
61409
61789
  auth: {
61410
61790
  ...config.token ? { token: config.token } : {},
61411
61791
  ...config.password ? { password: config.password } : {}
@@ -66998,8 +67378,8 @@ function isA2AEnvelope(payload) {
66998
67378
 
66999
67379
  // src/listener.ts
67000
67380
  init_log();
67001
- var import_node_fs19 = require("node:fs");
67002
- var import_promises8 = require("node:fs/promises");
67381
+ var import_node_fs20 = require("node:fs");
67382
+ var import_promises9 = require("node:fs/promises");
67003
67383
  var import_node_os8 = require("node:os");
67004
67384
  var import_node_path25 = require("node:path");
67005
67385
 
@@ -67110,6 +67490,398 @@ function createOnchainosSigner(agent) {
67110
67490
  // src/listener.ts
67111
67491
  init_session_store();
67112
67492
 
67493
+ // src/devkit-delivery.ts
67494
+ var import_node_net2 = require("node:net");
67495
+ var import_promises8 = require("node:dns/promises");
67496
+ init_sentry_logger();
67497
+ init_error_diagnostics();
67498
+
67499
+ // src/devkit-types.ts
67500
+ var DEVKIT_MAX_CONCURRENCY = 16;
67501
+ var DEVKIT_MAX_PENDING = 256;
67502
+ var DEVKIT_MAX_PENDING_BYTES = 16 * 1024 * 1024;
67503
+ var DEVKIT_MAX_MESSAGE_BYTES = 1 * 1024 * 1024;
67504
+ var DEVKIT_REQUEST_BUDGET_MS = 5e3;
67505
+ var DEVKIT_RESPONSE_DIAGNOSTIC_MAX_BYTES = 4 * 1024;
67506
+ var DEVKIT_RESPONSE_SUMMARY_MAX_CHARS = 256;
67507
+ var DEVKIT_OUTCOME = {
67508
+ HTTP_ACCEPTED: "http_accepted",
67509
+ DROPPED: "dropped"
67510
+ };
67511
+ var DEVKIT_DROP_REASON = {
67512
+ REQUEST_TOO_LARGE: "request_too_large",
67513
+ // serialized > 1 MiB (FR-3-AC-6)
67514
+ PENDING_OVERFLOW: "pending_overflow",
67515
+ // > 256 items or > 16 MiB total pending (NFR-2-AC-1)
67516
+ CONFIG_CHANGED: "config_changed",
67517
+ // snapshot version changed/removed before send (FR-2-AC-6)
67518
+ CONFIG_READ_FAILED: "config_read_failed",
67519
+ // snapshot unreadable/corrupt (FR-2-AC-5)
67520
+ HTTP_STATUS: "http_status",
67521
+ // non-2xx response (FR-3-AC-3)
67522
+ REDIRECT_BLOCKED: "redirect_blocked",
67523
+ // 3xx response, not followed (NFR-3-AC-2)
67524
+ CONNECTION_FAILED: "connection_failed",
67525
+ // ECONNREFUSED / reset / unreachable (FR-3-AC-4)
67526
+ TIMEOUT: "timeout",
67527
+ // exceeded the 5 s budget (FR-3-AC-4)
67528
+ REQUEST_BUILD_ERROR: "request_build_error",
67529
+ // serialization / target build failure
67530
+ RESPONSE_READ_ERROR: "response_read_error",
67531
+ // diagnostic read failure
67532
+ SHUTDOWN_CANCELLED: "shutdown_cancelled"
67533
+ // daemon stopped before send (NFR-2-AC-3)
67534
+ };
67535
+
67536
+ // src/devkit-delivery.ts
67537
+ var COMPONENT = "node_devkit";
67538
+ var SECRET_KEYS = "authorization|bearer|basic|jwt|password|api[_-]?key|secret|token";
67539
+ var SECRET_SCHEME_PATTERN = new RegExp(`\\b(?:${SECRET_KEYS})\\s+\\S+`, "gi");
67540
+ var SECRET_KV_PATTERN = new RegExp(
67541
+ `("?)(${SECRET_KEYS})("?)\\s*([:=])\\s*"?[^"\\s,}]+`,
67542
+ "gi"
67543
+ );
67544
+ function fallbackDeliveryId(parts) {
67545
+ return `devkit-${parts.jobId ?? "none"}-${parts.sessionKey ?? "none"}-${parts.receivedAt}`;
67546
+ }
67547
+ function buildSessionEnvelope(ev, ctx = {}) {
67548
+ const now = ctx.now ?? Date.now;
67549
+ const receivedAt = Math.floor(now() / 1e3);
67550
+ const jobId = ev.jobId ?? null;
67551
+ const agentId = ev.agentId ?? null;
67552
+ const deliveryId = ev.messageId ?? fallbackDeliveryId({ jobId, sessionKey: ev.sessionKey, receivedAt });
67553
+ const messageId = ev.messageId ?? deliveryId;
67554
+ return {
67555
+ deliveryId,
67556
+ receivedAt,
67557
+ kind: "session",
67558
+ agentId,
67559
+ event: {
67560
+ sessionKey: ev.sessionKey,
67561
+ content: ev.content,
67562
+ messageId,
67563
+ jobId,
67564
+ agentId
67565
+ }
67566
+ };
67567
+ }
67568
+ function buildJobEnvelope(ev, _ctx = {}) {
67569
+ const sessionAgentId = ev.sessionAgentId ?? null;
67570
+ const receivedAt = Math.floor(ev.message.receivedAtMs / 1e3);
67571
+ return {
67572
+ deliveryId: ev.message.id,
67573
+ receivedAt,
67574
+ kind: "job",
67575
+ agentId: sessionAgentId,
67576
+ event: {
67577
+ jobId: ev.jobId,
67578
+ sessionAgentId,
67579
+ message: {
67580
+ ...ev.message,
67581
+ content: ev.message.rawText
67582
+ }
67583
+ }
67584
+ };
67585
+ }
67586
+ function classifyHttpOutcome(status) {
67587
+ if (status >= 200 && status < 300) {
67588
+ return { outcome: DEVKIT_OUTCOME.HTTP_ACCEPTED };
67589
+ }
67590
+ if (status >= 300 && status < 400) {
67591
+ return { outcome: DEVKIT_OUTCOME.DROPPED, reason: DEVKIT_DROP_REASON.REDIRECT_BLOCKED };
67592
+ }
67593
+ return { outcome: DEVKIT_OUTCOME.DROPPED, reason: DEVKIT_DROP_REASON.HTTP_STATUS };
67594
+ }
67595
+ function classifyFetchFailure(params) {
67596
+ if (params.cancelledByShutdown) {
67597
+ return DEVKIT_DROP_REASON.SHUTDOWN_CANCELLED;
67598
+ }
67599
+ if (params.timedOut || params.errorCategory === "timeout") {
67600
+ return DEVKIT_DROP_REASON.TIMEOUT;
67601
+ }
67602
+ return DEVKIT_DROP_REASON.CONNECTION_FAILED;
67603
+ }
67604
+ function redactSummary(raw) {
67605
+ const collapsed = raw.replace(/\s+/g, " ").trim();
67606
+ const redacted = collapsed.replace(SECRET_SCHEME_PATTERN, "[REDACTED]").replace(
67607
+ SECRET_KV_PATTERN,
67608
+ (_match, keyQuote, key, keyQuoteClose, sep3) => `${keyQuote}${key}${keyQuoteClose}${sep3}[REDACTED]`
67609
+ );
67610
+ const truncated = redacted.length > DEVKIT_RESPONSE_SUMMARY_MAX_CHARS;
67611
+ return { text: redacted.slice(0, DEVKIT_RESPONSE_SUMMARY_MAX_CHARS), truncated };
67612
+ }
67613
+ async function readRedactedResponse(response) {
67614
+ let bodyText;
67615
+ try {
67616
+ bodyText = await response.text();
67617
+ } catch {
67618
+ return { responseBytesRead: 0, responseTruncated: false, responseSummary: "" };
67619
+ }
67620
+ const bytes = Buffer.from(bodyText, "utf8");
67621
+ const diagnosticSlice = bytes.subarray(0, DEVKIT_RESPONSE_DIAGNOSTIC_MAX_BYTES);
67622
+ const sliceTruncated = bytes.byteLength > DEVKIT_RESPONSE_DIAGNOSTIC_MAX_BYTES;
67623
+ const summary = redactSummary(diagnosticSlice.toString("utf8"));
67624
+ return {
67625
+ responseBytesRead: diagnosticSlice.byteLength,
67626
+ responseTruncated: sliceTruncated || summary.truncated,
67627
+ responseSummary: summary.text
67628
+ };
67629
+ }
67630
+ async function isLoopbackTarget(origin) {
67631
+ let hostname;
67632
+ try {
67633
+ hostname = new URL(origin).hostname;
67634
+ } catch {
67635
+ return false;
67636
+ }
67637
+ const version3 = (0, import_node_net2.isIP)(hostname);
67638
+ if (version3 === 4) {
67639
+ return hostname.startsWith("127.");
67640
+ }
67641
+ if (version3 === 6) {
67642
+ return hostname === "::1";
67643
+ }
67644
+ if (hostname.toLowerCase() !== "localhost") {
67645
+ return false;
67646
+ }
67647
+ try {
67648
+ const resolved = await (0, import_promises8.lookup)(hostname);
67649
+ return resolved.family === 4 ? resolved.address.startsWith("127.") : resolved.address === "::1";
67650
+ } catch {
67651
+ return false;
67652
+ }
67653
+ }
67654
+ function orderingKeyFor(envelope) {
67655
+ if (envelope.kind === "session") {
67656
+ return `session:${envelope.event.sessionKey}`;
67657
+ }
67658
+ return `job:${envelope.event.jobId}`;
67659
+ }
67660
+ function sleep4(ms) {
67661
+ return new Promise((resolve11) => setTimeout(resolve11, Math.max(0, ms)));
67662
+ }
67663
+ var DevkitDeliveryDispatcher = class {
67664
+ readSnapshot;
67665
+ now;
67666
+ fetchImpl;
67667
+ pendingQueue = [];
67668
+ pendingBytes = 0;
67669
+ activeKeys = /* @__PURE__ */ new Set();
67670
+ inFlight = /* @__PURE__ */ new Set();
67671
+ activeControllers = /* @__PURE__ */ new Map();
67672
+ shuttingDown = false;
67673
+ constructor(options) {
67674
+ this.readSnapshot = options.readSnapshot;
67675
+ this.now = options.now ?? Date.now;
67676
+ this.fetchImpl = options.fetchImpl ?? fetch;
67677
+ }
67678
+ enqueue(input) {
67679
+ const serialized = JSON.stringify(input.envelope);
67680
+ const bytes = Buffer.byteLength(serialized, "utf8");
67681
+ const kind = input.envelope.kind;
67682
+ const deliveryId = input.envelope.deliveryId;
67683
+ if (bytes > DEVKIT_MAX_MESSAGE_BYTES) {
67684
+ this.emitDropped({ deliveryId, kind, reason: DEVKIT_DROP_REASON.REQUEST_TOO_LARGE, durationMs: 0 });
67685
+ return true;
67686
+ }
67687
+ if (this.pendingQueue.length >= DEVKIT_MAX_PENDING || this.pendingBytes + bytes > DEVKIT_MAX_PENDING_BYTES) {
67688
+ this.emitDropped({ deliveryId, kind, reason: DEVKIT_DROP_REASON.PENDING_OVERFLOW, durationMs: 0 });
67689
+ return false;
67690
+ }
67691
+ this.pendingQueue.push({
67692
+ envelope: input.envelope,
67693
+ config: input.config,
67694
+ serialized,
67695
+ bytes,
67696
+ cancelledByShutdown: false,
67697
+ timedOut: false
67698
+ });
67699
+ this.pendingBytes += bytes;
67700
+ logger.info(LogEvent.DEVKIT_DELIVERY_ACCEPTED, {
67701
+ component: COMPONENT,
67702
+ deliveryId,
67703
+ kind,
67704
+ agentId: input.envelope.agentId ?? void 0
67705
+ });
67706
+ this.pump();
67707
+ return true;
67708
+ }
67709
+ pump() {
67710
+ if (this.shuttingDown) {
67711
+ return;
67712
+ }
67713
+ while (this.activeKeys.size < DEVKIT_MAX_CONCURRENCY) {
67714
+ const index2 = this.pendingQueue.findIndex((item2) => !this.activeKeys.has(orderingKeyFor(item2.envelope)));
67715
+ if (index2 === -1) {
67716
+ break;
67717
+ }
67718
+ const [item] = this.pendingQueue.splice(index2, 1);
67719
+ this.pendingBytes -= item.bytes;
67720
+ const key = orderingKeyFor(item.envelope);
67721
+ this.activeKeys.add(key);
67722
+ const promise = this.send(item).finally(() => {
67723
+ this.activeKeys.delete(key);
67724
+ this.inFlight.delete(promise);
67725
+ this.pump();
67726
+ });
67727
+ this.inFlight.add(promise);
67728
+ }
67729
+ }
67730
+ async send(item) {
67731
+ const startedAt = this.now();
67732
+ const { envelope } = item;
67733
+ let snapshot;
67734
+ try {
67735
+ snapshot = this.readSnapshot();
67736
+ } catch {
67737
+ this.emitDropped({
67738
+ deliveryId: envelope.deliveryId,
67739
+ kind: envelope.kind,
67740
+ reason: DEVKIT_DROP_REASON.CONFIG_READ_FAILED,
67741
+ durationMs: this.now() - startedAt
67742
+ });
67743
+ return;
67744
+ }
67745
+ if (snapshot?.configVersion !== item.config.configVersion) {
67746
+ this.emitDropped({
67747
+ deliveryId: envelope.deliveryId,
67748
+ kind: envelope.kind,
67749
+ reason: DEVKIT_DROP_REASON.CONFIG_CHANGED,
67750
+ durationMs: this.now() - startedAt
67751
+ });
67752
+ return;
67753
+ }
67754
+ const loopbackOk = await isLoopbackTarget(snapshot.origin);
67755
+ if (!loopbackOk) {
67756
+ this.emitHttpFailed(
67757
+ item,
67758
+ DEVKIT_DROP_REASON.CONNECTION_FAILED,
67759
+ { errorCategory: "network_unavailable" },
67760
+ this.now() - startedAt
67761
+ );
67762
+ return;
67763
+ }
67764
+ const url = `${snapshot.origin}:${snapshot.port}${snapshot.eventPath}`;
67765
+ const controller = new AbortController();
67766
+ this.activeControllers.set(item, controller);
67767
+ const timeoutTimer = setTimeout(() => {
67768
+ item.timedOut = true;
67769
+ controller.abort();
67770
+ }, DEVKIT_REQUEST_BUDGET_MS);
67771
+ let response;
67772
+ try {
67773
+ response = await this.fetchImpl(url, {
67774
+ method: "POST",
67775
+ headers: { "content-type": "application/json" },
67776
+ body: item.serialized,
67777
+ redirect: "manual",
67778
+ signal: controller.signal
67779
+ });
67780
+ } catch (err) {
67781
+ clearTimeout(timeoutTimer);
67782
+ this.activeControllers.delete(item);
67783
+ const durationMs2 = this.now() - startedAt;
67784
+ if (item.cancelledByShutdown) {
67785
+ this.emitCancelled(item, durationMs2);
67786
+ return;
67787
+ }
67788
+ const diagnostics = buildErrorDiagnostics(
67789
+ LogEvent.DEVKIT_DELIVERY_HTTP_FAILED,
67790
+ err instanceof Error ? err : void 0,
67791
+ {}
67792
+ );
67793
+ const reason = classifyFetchFailure({
67794
+ cancelledByShutdown: item.cancelledByShutdown,
67795
+ timedOut: item.timedOut,
67796
+ errorCategory: diagnostics.errorCategory
67797
+ });
67798
+ this.emitHttpFailed(item, reason, diagnostics, durationMs2, err instanceof Error ? err : void 0);
67799
+ return;
67800
+ }
67801
+ clearTimeout(timeoutTimer);
67802
+ this.activeControllers.delete(item);
67803
+ const durationMs = this.now() - startedAt;
67804
+ if (item.cancelledByShutdown) {
67805
+ this.emitCancelled(item, durationMs);
67806
+ return;
67807
+ }
67808
+ const status = response.status;
67809
+ const classified = classifyHttpOutcome(status);
67810
+ if (classified.outcome === DEVKIT_OUTCOME.HTTP_ACCEPTED) {
67811
+ logger.info(LogEvent.DEVKIT_DELIVERY_HTTP_ACCEPTED, {
67812
+ component: COMPONENT,
67813
+ deliveryId: envelope.deliveryId,
67814
+ kind: envelope.kind,
67815
+ statusCode: status,
67816
+ durationMs
67817
+ });
67818
+ return;
67819
+ }
67820
+ const redaction = await readRedactedResponse(response);
67821
+ this.emitDropped({
67822
+ deliveryId: envelope.deliveryId,
67823
+ kind: envelope.kind,
67824
+ reason: classified.reason,
67825
+ statusCode: status,
67826
+ durationMs,
67827
+ ...redaction
67828
+ });
67829
+ }
67830
+ async shutdown(deadlineMs) {
67831
+ this.shuttingDown = true;
67832
+ const deadline = this.now() + Math.max(0, deadlineMs);
67833
+ if (this.inFlight.size > 0) {
67834
+ const remaining = Math.max(0, deadline - this.now());
67835
+ await Promise.race([Promise.allSettled(Array.from(this.inFlight)), sleep4(remaining)]);
67836
+ }
67837
+ for (const [item, controller] of this.activeControllers) {
67838
+ item.cancelledByShutdown = true;
67839
+ controller.abort();
67840
+ }
67841
+ const stillPending = this.pendingQueue.splice(0, this.pendingQueue.length);
67842
+ this.pendingBytes = 0;
67843
+ for (const item of stillPending) {
67844
+ this.emitCancelled(item, 0);
67845
+ }
67846
+ }
67847
+ emitDropped(params) {
67848
+ logger.info(LogEvent.DEVKIT_DELIVERY_DROPPED, {
67849
+ component: COMPONENT,
67850
+ outcome: DEVKIT_OUTCOME.DROPPED,
67851
+ deliveryId: params.deliveryId,
67852
+ kind: params.kind,
67853
+ reason: params.reason,
67854
+ durationMs: params.durationMs,
67855
+ ...params.statusCode !== void 0 ? { statusCode: params.statusCode } : {},
67856
+ ...params.responseBytesRead !== void 0 ? { responseBytesRead: params.responseBytesRead } : {},
67857
+ ...params.responseTruncated !== void 0 ? { responseTruncated: params.responseTruncated } : {},
67858
+ ...params.responseSummary !== void 0 ? { responseSummary: params.responseSummary } : {}
67859
+ });
67860
+ }
67861
+ emitHttpFailed(item, reason, diagnostics, durationMs, err) {
67862
+ logger.error(LogEvent.DEVKIT_DELIVERY_HTTP_FAILED, err, {
67863
+ component: COMPONENT,
67864
+ outcome: DEVKIT_OUTCOME.DROPPED,
67865
+ deliveryId: item.envelope.deliveryId,
67866
+ kind: item.envelope.kind,
67867
+ reason,
67868
+ durationMs,
67869
+ ...diagnostics.errorCategory ? { errorCategory: diagnostics.errorCategory } : {},
67870
+ ...diagnostics.errorCode ? { errorCode: diagnostics.errorCode } : {}
67871
+ });
67872
+ }
67873
+ emitCancelled(item, durationMs) {
67874
+ logger.info(LogEvent.DEVKIT_DELIVERY_CANCELLED, {
67875
+ component: COMPONENT,
67876
+ outcome: DEVKIT_OUTCOME.DROPPED,
67877
+ deliveryId: item.envelope.deliveryId,
67878
+ kind: item.envelope.kind,
67879
+ reason: DEVKIT_DROP_REASON.SHUTDOWN_CANCELLED,
67880
+ durationMs
67881
+ });
67882
+ }
67883
+ };
67884
+
67113
67885
  // src/ai-dispatch-queue.ts
67114
67886
  async function enqueueAiJobMessageDispatch(params) {
67115
67887
  const commands = params.commands ?? new CommandStore(params.homeDir);
@@ -67135,6 +67907,381 @@ async function enqueueAiSessionMessageDispatch(params) {
67135
67907
  return command;
67136
67908
  }
67137
67909
 
67910
+ // src/devkit-router.ts
67911
+ init_sentry_logger();
67912
+ function createDevkitAutoRouter(deps) {
67913
+ const { commands, dispatcher, readSnapshot } = deps;
67914
+ function readConfigOrNull(phase) {
67915
+ try {
67916
+ return { ok: true, config: readSnapshot() };
67917
+ } catch (err) {
67918
+ logger.error(
67919
+ LogEvent.DEVKIT_ROUTE_CONFIG_READ_FAILED,
67920
+ err instanceof Error ? err : new Error(String(err)),
67921
+ {
67922
+ component: "node_devkit",
67923
+ phase,
67924
+ outcome: "dropped",
67925
+ reason: "config_read_failed"
67926
+ }
67927
+ );
67928
+ return { ok: false };
67929
+ }
67930
+ }
67931
+ async function routeSession(event) {
67932
+ const read = readConfigOrNull("session");
67933
+ if (!read.ok) {
67934
+ return;
67935
+ }
67936
+ if (read.config === null) {
67937
+ await enqueueAiSessionMessageDispatch({ commands, event });
67938
+ logger.info(LogEvent.DEVKIT_ROUTE_DEFAULT_AI, {
67939
+ component: "node_devkit",
67940
+ phase: "session",
67941
+ kind: "session",
67942
+ messageId: event.messageId ?? "",
67943
+ jobId: event.jobId ?? "",
67944
+ agentId: event.agentId ?? ""
67945
+ });
67946
+ return;
67947
+ }
67948
+ const config = read.config;
67949
+ const envelope = buildSessionEnvelope(event);
67950
+ dispatcher.enqueue({ envelope, config });
67951
+ logger.info(LogEvent.DEVKIT_ROUTE_CUSTOM_SERVER, {
67952
+ component: "node_devkit",
67953
+ phase: "session",
67954
+ kind: "session",
67955
+ deliveryId: envelope.deliveryId,
67956
+ messageId: event.messageId ?? "",
67957
+ jobId: event.jobId ?? "",
67958
+ agentId: event.agentId ?? ""
67959
+ });
67960
+ }
67961
+ async function routeJob(event) {
67962
+ const read = readConfigOrNull("job");
67963
+ if (!read.ok) {
67964
+ return;
67965
+ }
67966
+ if (read.config === null) {
67967
+ await enqueueAiJobMessageDispatch({ commands, event });
67968
+ logger.info(LogEvent.DEVKIT_ROUTE_DEFAULT_AI, {
67969
+ component: "node_devkit",
67970
+ phase: "job",
67971
+ kind: "job",
67972
+ jobId: event.jobId,
67973
+ agentId: event.sessionAgentId ?? ""
67974
+ });
67975
+ return;
67976
+ }
67977
+ const config = read.config;
67978
+ const envelope = buildJobEnvelope(event);
67979
+ dispatcher.enqueue({ envelope, config });
67980
+ logger.info(LogEvent.DEVKIT_ROUTE_CUSTOM_SERVER, {
67981
+ component: "node_devkit",
67982
+ phase: "job",
67983
+ kind: "job",
67984
+ deliveryId: envelope.deliveryId,
67985
+ jobId: event.jobId,
67986
+ agentId: event.sessionAgentId ?? ""
67987
+ });
67988
+ }
67989
+ return { routeJob, routeSession };
67990
+ }
67991
+
67992
+ // src/devkit-server-store.ts
67993
+ var import_node_fs19 = require("node:fs");
67994
+ init_paths();
67995
+ init_session_store();
67996
+ var { DatabaseSync: DatabaseSync4 } = loadSqlite4();
67997
+ var DEVKIT_SERVER_APPLICATION_ID = 1329677395;
67998
+ var DEVKIT_SERVER_SCHEMA_VERSION = 1;
67999
+ var TABLE_NAME = `"devkit-server"`;
68000
+ var WRITE_RETRY_ATTEMPTS = 6;
68001
+ var DevkitServerStoreError = class extends Error {
68002
+ code;
68003
+ constructor(code, message) {
68004
+ super(message);
68005
+ this.name = "DevkitServerStoreError";
68006
+ this.code = code;
68007
+ }
68008
+ };
68009
+ function resolveDevkitServerDbPath(homeDir) {
68010
+ return resolveTaskPaths(homeDir).devkitServerDbPath;
68011
+ }
68012
+ function devkitServerDbExists(homeDir) {
68013
+ return (0, import_node_fs19.existsSync)(resolveDevkitServerDbPath(homeDir));
68014
+ }
68015
+ var DevkitServerStore = class _DevkitServerStore {
68016
+ dbPath;
68017
+ db;
68018
+ constructor(dbPath, db) {
68019
+ this.dbPath = dbPath;
68020
+ this.db = db;
68021
+ }
68022
+ static openForWrite(homeDir) {
68023
+ const paths = resolveTaskPaths(homeDir);
68024
+ const dbPath = paths.devkitServerDbPath;
68025
+ assertNotSymlink(paths.sqliteDir, "devkit server directory");
68026
+ ensureTaskDir(paths.sqliteDir);
68027
+ assertNotSymlink(paths.sqliteDir, "devkit server directory");
68028
+ assertSafeDatabasePath(dbPath);
68029
+ const db = new DatabaseSync4(dbPath);
68030
+ const store = new _DevkitServerStore(dbPath, db);
68031
+ try {
68032
+ store.configureConnectionForWrite();
68033
+ store.ensureSchemaForWrite();
68034
+ return store;
68035
+ } catch (error) {
68036
+ db.close();
68037
+ throw error;
68038
+ }
68039
+ }
68040
+ static openForRead(homeDir) {
68041
+ const dbPath = resolveDevkitServerDbPath(homeDir);
68042
+ if (!(0, import_node_fs19.existsSync)(dbPath)) {
68043
+ return null;
68044
+ }
68045
+ assertSafeDatabaseFile(dbPath);
68046
+ const db = new DatabaseSync4(dbPath, { readOnly: true });
68047
+ const store = new _DevkitServerStore(dbPath, db);
68048
+ try {
68049
+ db.exec("PRAGMA query_only=ON");
68050
+ store.assertReadableSchema();
68051
+ return store;
68052
+ } catch (error) {
68053
+ db.close();
68054
+ throw error;
68055
+ }
68056
+ }
68057
+ close() {
68058
+ this.db.close();
68059
+ }
68060
+ register(input) {
68061
+ return this.withWriteTransaction(() => {
68062
+ const existing = this.db.prepare(`SELECT config_version FROM ${TABLE_NAME} WHERE id = 1`).get();
68063
+ const configVersion = (existing?.config_version ?? 0) + 1;
68064
+ const updatedAt = Date.now();
68065
+ this.db.prepare(`
68066
+ INSERT INTO ${TABLE_NAME} (
68067
+ id, origin, port, event_path, health_path, config_version, updated_at
68068
+ ) VALUES (1, ?, ?, ?, ?, ?, ?)
68069
+ ON CONFLICT(id) DO UPDATE SET
68070
+ origin = excluded.origin,
68071
+ port = excluded.port,
68072
+ event_path = excluded.event_path,
68073
+ health_path = excluded.health_path,
68074
+ config_version = excluded.config_version,
68075
+ updated_at = excluded.updated_at
68076
+ `).run(input.origin, input.port, input.eventPath, input.healthPath, configVersion, updatedAt);
68077
+ return {
68078
+ origin: input.origin,
68079
+ port: input.port,
68080
+ eventPath: input.eventPath,
68081
+ healthPath: input.healthPath,
68082
+ configVersion,
68083
+ updatedAt
68084
+ };
68085
+ });
68086
+ }
68087
+ unregister() {
68088
+ return this.withWriteTransaction(() => {
68089
+ const result = this.db.prepare(`DELETE FROM ${TABLE_NAME} WHERE id = 1`).run();
68090
+ return { removed: Number(result.changes) > 0 };
68091
+ });
68092
+ }
68093
+ readSnapshot() {
68094
+ let row;
68095
+ try {
68096
+ row = this.db.prepare(`
68097
+ SELECT origin, port, event_path, health_path, config_version, updated_at
68098
+ FROM ${TABLE_NAME} WHERE id = 1
68099
+ `).get();
68100
+ } catch (error) {
68101
+ throw new DevkitServerStoreError(
68102
+ "DATABASE_READ_FAILED",
68103
+ `failed to read devkit server config: ${error instanceof Error ? error.message : String(error)}`
68104
+ );
68105
+ }
68106
+ if (!row) {
68107
+ return null;
68108
+ }
68109
+ return {
68110
+ origin: row.origin,
68111
+ port: row.port,
68112
+ eventPath: row.event_path,
68113
+ healthPath: row.health_path,
68114
+ configVersion: row.config_version,
68115
+ updatedAt: row.updated_at
68116
+ };
68117
+ }
68118
+ configureConnectionForWrite() {
68119
+ this.db.exec("PRAGMA busy_timeout=5000");
68120
+ }
68121
+ ensureSchemaForWrite() {
68122
+ withBusyRetry(() => {
68123
+ this.db.exec("BEGIN IMMEDIATE");
68124
+ try {
68125
+ const applicationId = readPragmaNumber(this.db, "application_id");
68126
+ const userVersion = readPragmaNumber(this.db, "user_version");
68127
+ const hasTables = Boolean(
68128
+ this.db.prepare("SELECT 1 AS present FROM sqlite_master WHERE type = 'table' LIMIT 1").get()
68129
+ );
68130
+ if (applicationId === 0 && !hasTables && userVersion === 0) {
68131
+ this.db.exec(`PRAGMA application_id=${DEVKIT_SERVER_APPLICATION_ID}`);
68132
+ } else if (applicationId !== DEVKIT_SERVER_APPLICATION_ID) {
68133
+ throw new DevkitServerStoreError(
68134
+ "DATABASE_IDENTITY_MISMATCH",
68135
+ "devkit server database identity does not match"
68136
+ );
68137
+ }
68138
+ if (userVersion > DEVKIT_SERVER_SCHEMA_VERSION) {
68139
+ throw new DevkitServerStoreError(
68140
+ "DATABASE_SCHEMA_TOO_NEW",
68141
+ `devkit server schema version ${userVersion} is newer than supported ${DEVKIT_SERVER_SCHEMA_VERSION}`
68142
+ );
68143
+ }
68144
+ if (userVersion < 1) {
68145
+ applyMigrationV1(this.db);
68146
+ this.db.exec("PRAGMA user_version=1");
68147
+ }
68148
+ this.db.exec("COMMIT");
68149
+ } catch (error) {
68150
+ rollbackQuietly(this.db);
68151
+ throw error;
68152
+ }
68153
+ });
68154
+ withBusyRetry(() => {
68155
+ this.db.exec("PRAGMA journal_mode=WAL");
68156
+ this.db.exec("PRAGMA synchronous=FULL");
68157
+ });
68158
+ }
68159
+ assertReadableSchema() {
68160
+ const applicationId = readPragmaNumber(this.db, "application_id");
68161
+ if (applicationId !== DEVKIT_SERVER_APPLICATION_ID) {
68162
+ throw new DevkitServerStoreError(
68163
+ "DATABASE_IDENTITY_MISMATCH",
68164
+ "devkit server database identity does not match"
68165
+ );
68166
+ }
68167
+ const userVersion = readPragmaNumber(this.db, "user_version");
68168
+ if (userVersion > DEVKIT_SERVER_SCHEMA_VERSION) {
68169
+ throw new DevkitServerStoreError(
68170
+ "DATABASE_SCHEMA_TOO_NEW",
68171
+ `devkit server schema version ${userVersion} is newer than supported ${DEVKIT_SERVER_SCHEMA_VERSION}`
68172
+ );
68173
+ }
68174
+ if (userVersion < DEVKIT_SERVER_SCHEMA_VERSION) {
68175
+ throw new DevkitServerStoreError(
68176
+ "DATABASE_MIGRATION_REQUIRED",
68177
+ "devkit server database requires a write command to finish migration"
68178
+ );
68179
+ }
68180
+ }
68181
+ withWriteTransaction(operation) {
68182
+ return withBusyRetry(() => {
68183
+ this.db.exec("BEGIN IMMEDIATE");
68184
+ try {
68185
+ const result = operation();
68186
+ this.db.exec("COMMIT");
68187
+ return result;
68188
+ } catch (error) {
68189
+ rollbackQuietly(this.db);
68190
+ throw error;
68191
+ }
68192
+ });
68193
+ }
68194
+ };
68195
+ function applyMigrationV1(db) {
68196
+ db.exec(`
68197
+ CREATE TABLE ${TABLE_NAME} (
68198
+ id INTEGER PRIMARY KEY CHECK (id = 1),
68199
+ origin TEXT NOT NULL,
68200
+ port INTEGER NOT NULL CHECK (port >= 1 AND port <= 65535),
68201
+ event_path TEXT NOT NULL,
68202
+ health_path TEXT NOT NULL,
68203
+ config_version INTEGER NOT NULL,
68204
+ updated_at INTEGER NOT NULL,
68205
+ CHECK (length(origin) > 0),
68206
+ CHECK (substr(event_path,1,1) = '/'),
68207
+ CHECK (substr(health_path,1,1) = '/')
68208
+ )
68209
+ `);
68210
+ }
68211
+ function readPragmaNumber(db, name) {
68212
+ const row = db.prepare(`PRAGMA ${name}`).get();
68213
+ return Number(row[name] ?? 0);
68214
+ }
68215
+ function assertNotSymlink(path2, label) {
68216
+ if (!(0, import_node_fs19.existsSync)(path2)) {
68217
+ return;
68218
+ }
68219
+ if ((0, import_node_fs19.lstatSync)(path2).isSymbolicLink()) {
68220
+ throw new DevkitServerStoreError("DATABASE_PATH_UNSAFE", `${label} must not be a symbolic link`);
68221
+ }
68222
+ }
68223
+ function assertSafeDatabasePath(dbPath) {
68224
+ assertSafeDatabaseFile(dbPath);
68225
+ for (const suffix of ["-journal", "-wal", "-shm"]) {
68226
+ assertNotSymlink(`${dbPath}${suffix}`, `devkit server database sidecar ${suffix}`);
68227
+ }
68228
+ }
68229
+ function assertSafeDatabaseFile(dbPath) {
68230
+ if (!(0, import_node_fs19.existsSync)(dbPath)) {
68231
+ return;
68232
+ }
68233
+ const stat4 = (0, import_node_fs19.lstatSync)(dbPath);
68234
+ if (stat4.isSymbolicLink()) {
68235
+ throw new DevkitServerStoreError(
68236
+ "DATABASE_PATH_UNSAFE",
68237
+ "devkit server database must not be a symbolic link"
68238
+ );
68239
+ }
68240
+ if (!stat4.isFile() || stat4.nlink !== 1) {
68241
+ throw new DevkitServerStoreError(
68242
+ "DATABASE_PATH_UNSAFE",
68243
+ "devkit server database must be a regular file with one hard link"
68244
+ );
68245
+ }
68246
+ }
68247
+ function rollbackQuietly(db) {
68248
+ try {
68249
+ db.exec("ROLLBACK");
68250
+ } catch {
68251
+ }
68252
+ }
68253
+ function withBusyRetry(operation) {
68254
+ for (let attempt = 1; ; attempt += 1) {
68255
+ try {
68256
+ return operation();
68257
+ } catch (error) {
68258
+ if (!isSqliteBusyError(error) || attempt >= WRITE_RETRY_ATTEMPTS) {
68259
+ throw error;
68260
+ }
68261
+ sleepSyncMs2(Math.min(100 * 2 ** (attempt - 1), 1600));
68262
+ }
68263
+ }
68264
+ }
68265
+ function sleepSyncMs2(ms) {
68266
+ const buffer2 = new Int32Array(new SharedArrayBuffer(4));
68267
+ Atomics.wait(buffer2, 0, 0, ms);
68268
+ }
68269
+ function loadSqlite4() {
68270
+ const originalEmitWarning = process.emitWarning;
68271
+ process.emitWarning = ((warning, ...args) => {
68272
+ const message = typeof warning === "string" ? warning : warning.message;
68273
+ if (message.includes("SQLite is an experimental feature") && args.some((arg) => arg === "ExperimentalWarning")) {
68274
+ return;
68275
+ }
68276
+ return originalEmitWarning.call(process, warning, ...args);
68277
+ });
68278
+ try {
68279
+ return require("node:sqlite");
68280
+ } finally {
68281
+ process.emitWarning = originalEmitWarning;
68282
+ }
68283
+ }
68284
+
67138
68285
  // src/listener.ts
67139
68286
  init_paths();
67140
68287
 
@@ -67509,13 +68656,13 @@ async function getHermesGatewayPluginStatus(options = {}) {
67509
68656
  const env = options.env ?? process.env;
67510
68657
  const hermesHome = env.HERMES_HOME?.trim() || (0, import_node_path25.join)((0, import_node_os8.homedir)(), ".hermes");
67511
68658
  const pluginYamlPath = (0, import_node_path25.join)(hermesHome, "plugins", "platforms", "okx-a2a", "plugin.yaml");
67512
- if (!(0, import_node_fs19.existsSync)(pluginYamlPath)) {
68659
+ if (!(0, import_node_fs20.existsSync)(pluginYamlPath)) {
67513
68660
  return { enabled: false, reason: "plugin_yaml_missing", hermesHome, checkedPath: pluginYamlPath };
67514
68661
  }
67515
68662
  const configPath = (0, import_node_path25.join)(hermesHome, "config.yaml");
67516
68663
  let content;
67517
68664
  try {
67518
- content = await (0, import_promises8.readFile)(configPath, "utf8");
68665
+ content = await (0, import_promises9.readFile)(configPath, "utf8");
67519
68666
  } catch {
67520
68667
  return { enabled: false, reason: "config_read_error", hermesHome, checkedPath: configPath };
67521
68668
  }
@@ -67600,12 +68747,12 @@ function parseYamlInlineEnabledList(line) {
67600
68747
  var SHUTDOWN_FORCE_RESOLVE_MS = 5e3;
67601
68748
  function stopClients(service) {
67602
68749
  for (const [address, client] of service.getClients()) {
67603
- try {
67604
- client.stop();
67605
- logWithTimestamp(`[okx-agent-task] stopped XMTP client ${address}`);
67606
- } catch (err) {
67607
- logWithTimestamp(`[okx-agent-task] failed to stop XMTP client ${address}:`, err);
67608
- }
68750
+ void stopAndCloseXmtpClient(client, {
68751
+ address,
68752
+ agentId: "",
68753
+ phase: "shutdown",
68754
+ onCloseError: (err) => logWithTimestamp(`[okx-agent-task] failed to close XMTP client ${address}:`, err)
68755
+ }).then(() => logWithTimestamp(`[okx-agent-task] stopped XMTP client ${address}`)).catch((err) => logWithTimestamp(`[okx-agent-task] failed to stop XMTP client ${address}:`, err));
67609
68756
  }
67610
68757
  }
67611
68758
  async function runListener(options = {}) {
@@ -67637,6 +68784,27 @@ async function runListenerWithLock(options, paths) {
67637
68784
  const store = new TaskMessageStore(options.homeDir);
67638
68785
  const sessionStore = new SessionStore({ homeDir: options.homeDir });
67639
68786
  const commands = new CommandStore(options.homeDir);
68787
+ const devkitReadSnapshot = () => {
68788
+ const snapshotStore = DevkitServerStore.openForRead(options.homeDir);
68789
+ if (!snapshotStore) {
68790
+ return null;
68791
+ }
68792
+ try {
68793
+ return snapshotStore.readSnapshot();
68794
+ } finally {
68795
+ snapshotStore.close();
68796
+ }
68797
+ };
68798
+ const devkitDispatcher = new DevkitDeliveryDispatcher({
68799
+ homeDir: options.homeDir,
68800
+ readSnapshot: devkitReadSnapshot
68801
+ });
68802
+ const devkitRouter = createDevkitAutoRouter({
68803
+ homeDir: options.homeDir,
68804
+ commands,
68805
+ dispatcher: devkitDispatcher,
68806
+ readSnapshot: devkitReadSnapshot
68807
+ });
67640
68808
  await store.ensureReady();
67641
68809
  let userAttentionEvents = null;
67642
68810
  try {
@@ -67700,20 +68868,20 @@ async function runListenerWithLock(options, paths) {
67700
68868
  createInboundMiddleware: (deps) => createMiddlewareFromCoreDeps(store, deps, {
67701
68869
  sessionStore,
67702
68870
  onJobMessageStored: async (event) => {
67703
- await enqueueAiJobMessageDispatch({ commands, event });
68871
+ await devkitRouter.routeJob(event);
67704
68872
  },
67705
68873
  onSessionMessage: async (event) => {
67706
- await enqueueAiSessionMessageDispatch({ commands, event });
68874
+ await devkitRouter.routeSession(event);
67707
68875
  }
67708
68876
  }),
67709
68877
  processOfflineMessage: (ctx, deps, replayOptions) => processOfflineFromCoreDeps(store, ctx, deps, {
67710
68878
  ...replayOptions,
67711
68879
  sessionStore,
67712
68880
  onJobMessageStored: async (event) => {
67713
- await enqueueAiJobMessageDispatch({ commands, event });
68881
+ await devkitRouter.routeJob(event);
67714
68882
  },
67715
68883
  onSessionMessage: async (event) => {
67716
- await enqueueAiSessionMessageDispatch({ commands, event });
68884
+ await devkitRouter.routeSession(event);
67717
68885
  }
67718
68886
  }),
67719
68887
  notifySessionExpired: (command) => {
@@ -67745,12 +68913,12 @@ async function runListenerWithLock(options, paths) {
67745
68913
  });
67746
68914
  }
67747
68915
  });
67748
- service.setPluginVersion("0.2.16");
68916
+ service.setPluginVersion("0.2.17-beta-ab42219842-261020165552");
67749
68917
  await service.init();
67750
68918
  const pluginVersionStatus = service.pluginVersionStatus;
67751
68919
  if (pluginVersionStatus.unavailable) {
67752
68920
  throw new Error(
67753
- `@okxweb3/a2a-node v${"0.2.16"} is below the required minimum v${pluginVersionStatus.minVersion}`
68921
+ `@okxweb3/a2a-node v${"0.2.17-beta-ab42219842-261020165552"} is below the required minimum v${pluginVersionStatus.minVersion}`
67754
68922
  );
67755
68923
  }
67756
68924
  const systemConfig = service.getSystemConfig();
@@ -67778,7 +68946,7 @@ async function runListenerWithLock(options, paths) {
67778
68946
  onchainosAgentId: "*",
67779
68947
  reason: "system-config missing sentryDsn",
67780
68948
  pluginId: "@okxweb3/a2a-node",
67781
- pluginVersion: "0.2.16"
68949
+ pluginVersion: "0.2.17-beta-ab42219842-261020165552"
67782
68950
  });
67783
68951
  }
67784
68952
  logWithTimestamp(
@@ -68110,6 +69278,7 @@ async function runListenerWithLock(options, paths) {
68110
69278
  logWithTimestamp("[okx-agent-task] failed to close user_attention IPC wake:", err);
68111
69279
  }
68112
69280
  stopClients(service);
69281
+ await devkitDispatcher.shutdown(SHUTDOWN_FORCE_RESOLVE_MS);
68113
69282
  sessionStore.close();
68114
69283
  clearTimeout(forceResolve);
68115
69284
  resolve11();
@@ -68132,14 +69301,375 @@ async function timeSettled(fn) {
68132
69301
  // src/index.ts
68133
69302
  init_paths();
68134
69303
 
69304
+ // src/devkit-cli.ts
69305
+ var import_node_crypto14 = require("node:crypto");
69306
+ init_daemon();
69307
+ init_sentry_logger();
69308
+ var DAEMON_NOT_RUNNING_MESSAGE = "\u5F53\u524D daemon \u672A\u8FD0\u884C,\u8BF7\u4F7F\u7528 okx-a2a start \u542F\u52A8 daemon";
69309
+ var DAEMON_STATUS_UNKNOWN_MESSAGE = "\u914D\u7F6E\u5DF2\u5199\u5165,\u4F46\u65E0\u6CD5\u786E\u8BA4 daemon \u8FD0\u884C\u72B6\u6001";
69310
+ var LOOPBACK_IPV4_PATTERN = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/;
69311
+ var DevkitCliError = class extends Error {
69312
+ field;
69313
+ constructor(field, reason) {
69314
+ super(reason);
69315
+ this.name = "DevkitCliError";
69316
+ this.field = field;
69317
+ }
69318
+ toValidationError() {
69319
+ return { field: this.field, reason: this.message };
69320
+ }
69321
+ };
69322
+ async function handleDevkitCommand(args) {
69323
+ const wantsJson = args.includes("--json");
69324
+ const subcommand = args[0];
69325
+ if (!subcommand || isHelpArg(subcommand)) {
69326
+ printDevkitUsage();
69327
+ return;
69328
+ }
69329
+ if (args.slice(1).some(isHelpArg)) {
69330
+ printDevkitUsage();
69331
+ return;
69332
+ }
69333
+ if (subcommand === "register") {
69334
+ await handleRegister(args.slice(1), wantsJson);
69335
+ return;
69336
+ }
69337
+ if (subcommand === "unregister") {
69338
+ await handleUnregister(args.slice(1), wantsJson);
69339
+ return;
69340
+ }
69341
+ outputError(wantsJson, { field: "command", reason: `unknown devkit command: ${subcommand}` });
69342
+ process.exitCode = 1;
69343
+ }
69344
+ function printDevkitUsage() {
69345
+ console.log(`Usage: okx-a2a devkit <register|unregister> [options]
69346
+
69347
+ Commands:
69348
+ register Register a local custom server for daemon auto-message delivery.
69349
+ --url <origin> --port <n> --paths '{"event":"/path","health":"/path"}'
69350
+ unregister Remove the registered custom server; daemon reverts to default AI delivery.
69351
+
69352
+ Options:
69353
+ --json Print machine-readable output.`);
69354
+ }
69355
+ async function handleRegister(args, wantsJson) {
69356
+ const operationId = (0, import_node_crypto14.randomUUID)();
69357
+ const startedAt = Date.now();
69358
+ logger.info(LogEvent.DEVKIT_REGISTER_REQUESTED, devkitSentryExtra({ operationId, phase: "requested" }));
69359
+ try {
69360
+ const parsed = parseArgs(args, { options: /* @__PURE__ */ new Set(["url", "port", "paths"]), flags: /* @__PURE__ */ new Set(["json"]) });
69361
+ const origin = validateUrl(requireOption(parsed, "url"));
69362
+ const port = validatePort(requireOption(parsed, "port"));
69363
+ const { eventPath, healthPath } = validatePaths(requireOption(parsed, "paths"));
69364
+ let config;
69365
+ try {
69366
+ const store = DevkitServerStore.openForWrite();
69367
+ try {
69368
+ config = store.register({ origin, port, eventPath, healthPath });
69369
+ } finally {
69370
+ store.close();
69371
+ }
69372
+ } catch (error) {
69373
+ logger.error(
69374
+ LogEvent.DEVKIT_CONFIG_PERSIST_FAILED,
69375
+ error instanceof Error ? error : new Error(String(error)),
69376
+ devkitSentryExtra({ operationId, phase: "persist_failed", durationMs: Date.now() - startedAt })
69377
+ );
69378
+ outputError(wantsJson, {
69379
+ field: "config",
69380
+ reason: error instanceof DevkitServerStoreError ? error.message : "failed to persist devkit configuration"
69381
+ });
69382
+ process.exitCode = 1;
69383
+ return;
69384
+ }
69385
+ const outcome = config.configVersion === 1 ? "created" : "replaced";
69386
+ const { daemonRunning, warning } = await resolveDaemonStatus(operationId);
69387
+ logger.info(
69388
+ LogEvent.DEVKIT_REGISTER_COMPLETED,
69389
+ devkitSentryExtra({
69390
+ operationId,
69391
+ phase: "completed",
69392
+ outcome,
69393
+ registrationId: String(config.configVersion),
69394
+ daemonRunning: String(daemonRunning),
69395
+ durationMs: Date.now() - startedAt
69396
+ })
69397
+ );
69398
+ outputSuccess(wantsJson, { daemonRunning, warning, configVersion: config.configVersion });
69399
+ } catch (error) {
69400
+ const detail = normalizeError(error);
69401
+ logger.error(
69402
+ LogEvent.DEVKIT_REGISTER_REJECTED,
69403
+ error instanceof Error ? error : new Error(String(error)),
69404
+ devkitSentryExtra({ operationId, phase: "rejected", reason: detail.field, durationMs: Date.now() - startedAt })
69405
+ );
69406
+ outputError(wantsJson, detail);
69407
+ process.exitCode = 1;
69408
+ }
69409
+ }
69410
+ async function handleUnregister(args, wantsJson) {
69411
+ const operationId = (0, import_node_crypto14.randomUUID)();
69412
+ const startedAt = Date.now();
69413
+ logger.info(LogEvent.DEVKIT_UNREGISTER_REQUESTED, devkitSentryExtra({ operationId, phase: "requested" }));
69414
+ try {
69415
+ parseArgs(args, { options: /* @__PURE__ */ new Set(), flags: /* @__PURE__ */ new Set(["json"]) });
69416
+ let removed;
69417
+ try {
69418
+ const store = DevkitServerStore.openForWrite();
69419
+ try {
69420
+ removed = store.unregister().removed;
69421
+ } finally {
69422
+ store.close();
69423
+ }
69424
+ } catch (error) {
69425
+ logger.error(
69426
+ LogEvent.DEVKIT_CONFIG_PERSIST_FAILED,
69427
+ error instanceof Error ? error : new Error(String(error)),
69428
+ devkitSentryExtra({ operationId, phase: "persist_failed", durationMs: Date.now() - startedAt })
69429
+ );
69430
+ outputError(wantsJson, {
69431
+ field: "config",
69432
+ reason: error instanceof DevkitServerStoreError ? error.message : "failed to persist devkit configuration"
69433
+ });
69434
+ process.exitCode = 1;
69435
+ return;
69436
+ }
69437
+ const outcome = removed ? "removed" : "noop";
69438
+ const { daemonRunning, warning } = await resolveDaemonStatus(operationId);
69439
+ logger.info(
69440
+ LogEvent.DEVKIT_UNREGISTER_COMPLETED,
69441
+ devkitSentryExtra({
69442
+ operationId,
69443
+ phase: "completed",
69444
+ outcome,
69445
+ daemonRunning: String(daemonRunning),
69446
+ durationMs: Date.now() - startedAt
69447
+ })
69448
+ );
69449
+ outputSuccess(wantsJson, { daemonRunning, warning });
69450
+ } catch (error) {
69451
+ const detail = normalizeError(error);
69452
+ logger.error(
69453
+ LogEvent.DEVKIT_REGISTER_REJECTED,
69454
+ error instanceof Error ? error : new Error(String(error)),
69455
+ devkitSentryExtra({ operationId, phase: "rejected", reason: detail.field, durationMs: Date.now() - startedAt })
69456
+ );
69457
+ outputError(wantsJson, detail);
69458
+ process.exitCode = 1;
69459
+ }
69460
+ }
69461
+ async function resolveDaemonStatus(operationId) {
69462
+ try {
69463
+ const status = await getDaemonStatus();
69464
+ if (status.running) {
69465
+ return { daemonRunning: true };
69466
+ }
69467
+ return {
69468
+ daemonRunning: false,
69469
+ warning: { code: "DAEMON_NOT_RUNNING", message: DAEMON_NOT_RUNNING_MESSAGE }
69470
+ };
69471
+ } catch {
69472
+ logger.info(LogEvent.DEVKIT_DAEMON_STATUS_UNKNOWN, devkitSentryExtra({ operationId, phase: "status_unknown" }));
69473
+ return {
69474
+ daemonRunning: null,
69475
+ warning: { code: "DAEMON_STATUS_UNKNOWN", message: DAEMON_STATUS_UNKNOWN_MESSAGE }
69476
+ };
69477
+ }
69478
+ }
69479
+ function validateUrl(raw) {
69480
+ if (raw.includes("\\")) {
69481
+ throw new DevkitCliError("url", "--url must not contain a backslash");
69482
+ }
69483
+ let url;
69484
+ try {
69485
+ url = new URL(raw);
69486
+ } catch {
69487
+ throw new DevkitCliError("url", "--url must be a valid HTTP/HTTPS origin");
69488
+ }
69489
+ if (url.protocol !== "http:" && url.protocol !== "https:") {
69490
+ throw new DevkitCliError("url", "--url scheme must be http or https");
69491
+ }
69492
+ if (url.username !== "" || url.password !== "") {
69493
+ throw new DevkitCliError("url", "--url must not contain userinfo");
69494
+ }
69495
+ if (url.port !== "") {
69496
+ throw new DevkitCliError("url", "--url must not contain an embedded port; use --port");
69497
+ }
69498
+ if (url.pathname !== "/" && url.pathname !== "") {
69499
+ throw new DevkitCliError("url", "--url must not contain a path");
69500
+ }
69501
+ if (url.search !== "") {
69502
+ throw new DevkitCliError("url", "--url must not contain a query");
69503
+ }
69504
+ if (url.hash !== "") {
69505
+ throw new DevkitCliError("url", "--url must not contain a fragment");
69506
+ }
69507
+ const hostname = url.hostname.toLowerCase();
69508
+ if (!isLoopbackHostname(hostname)) {
69509
+ throw new DevkitCliError(
69510
+ "url",
69511
+ "--url host must be a loopback address (127.0.0.0/8, ::1, or localhost)"
69512
+ );
69513
+ }
69514
+ return `${url.protocol}//${hostname}`;
69515
+ }
69516
+ function isLoopbackHostname(hostname) {
69517
+ if (hostname === "localhost") {
69518
+ return true;
69519
+ }
69520
+ if (hostname === "::1") {
69521
+ return true;
69522
+ }
69523
+ const match = LOOPBACK_IPV4_PATTERN.exec(hostname);
69524
+ if (!match) {
69525
+ return false;
69526
+ }
69527
+ const octets = match.slice(1, 5).map((segment) => Number(segment));
69528
+ if (octets.some((octet) => !Number.isInteger(octet) || octet < 0 || octet > 255)) {
69529
+ return false;
69530
+ }
69531
+ return octets[0] === 127;
69532
+ }
69533
+ function validatePort(raw) {
69534
+ if (!/^[1-9][0-9]{0,4}$/.test(raw)) {
69535
+ throw new DevkitCliError("port", "--port must be an integer between 1 and 65535");
69536
+ }
69537
+ const port = Number(raw);
69538
+ if (!Number.isInteger(port) || port < 1 || port > 65535) {
69539
+ throw new DevkitCliError("port", "--port must be an integer between 1 and 65535");
69540
+ }
69541
+ return port;
69542
+ }
69543
+ function validatePaths(raw) {
69544
+ let parsed;
69545
+ try {
69546
+ parsed = JSON.parse(raw);
69547
+ } catch {
69548
+ throw new DevkitCliError("paths", "--paths must be valid JSON");
69549
+ }
69550
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
69551
+ throw new DevkitCliError("paths", "--paths must be a JSON object");
69552
+ }
69553
+ const record = parsed;
69554
+ const keys = Object.keys(record);
69555
+ if (keys.length !== 2 || !keys.includes("event") || !keys.includes("health")) {
69556
+ throw new DevkitCliError("paths", '--paths must contain exactly the keys "event" and "health"');
69557
+ }
69558
+ const eventPath = validatePathValue(record.event, "event");
69559
+ const healthPath = validatePathValue(record.health, "health");
69560
+ return { eventPath, healthPath };
69561
+ }
69562
+ function validatePathValue(value, key) {
69563
+ if (typeof value !== "string" || value.length === 0) {
69564
+ throw new DevkitCliError("paths", `--paths.${key} must be a non-empty string`);
69565
+ }
69566
+ if (!value.startsWith("/") || value.startsWith("//")) {
69567
+ throw new DevkitCliError("paths", `--paths.${key} must start with a single "/"`);
69568
+ }
69569
+ if (value.includes("\\") || value.includes("?") || value.includes("#") || value.includes("..")) {
69570
+ throw new DevkitCliError(
69571
+ "paths",
69572
+ `--paths.${key} must not contain a query, fragment, backslash, "..", or an absolute URL`
69573
+ );
69574
+ }
69575
+ if (/^\/[a-zA-Z][a-zA-Z0-9+.-]*:/.test(value)) {
69576
+ throw new DevkitCliError("paths", `--paths.${key} must not be an absolute URL`);
69577
+ }
69578
+ return value;
69579
+ }
69580
+ function parseArgs(args, spec) {
69581
+ const options = /* @__PURE__ */ new Map();
69582
+ const flags = /* @__PURE__ */ new Set();
69583
+ for (let index2 = 0; index2 < args.length; index2 += 1) {
69584
+ const token = args[index2];
69585
+ if (!token.startsWith("--")) {
69586
+ throw new DevkitCliError("command", `unexpected positional argument: ${token}`);
69587
+ }
69588
+ const name = token.slice(2);
69589
+ if (spec.flags.has(name)) {
69590
+ if (flags.has(name)) {
69591
+ throw new DevkitCliError("command", `${token} must not be repeated`);
69592
+ }
69593
+ flags.add(name);
69594
+ continue;
69595
+ }
69596
+ if (!spec.options.has(name)) {
69597
+ throw new DevkitCliError("command", `unknown option ${token}`);
69598
+ }
69599
+ if (index2 + 1 >= args.length) {
69600
+ throw new DevkitCliError("command", `${token} requires a value`);
69601
+ }
69602
+ const value = args[++index2];
69603
+ if (value.startsWith("--")) {
69604
+ throw new DevkitCliError("command", `${token} requires a value`);
69605
+ }
69606
+ if (options.has(name)) {
69607
+ throw new DevkitCliError("command", `${token} must not be repeated`);
69608
+ }
69609
+ options.set(name, [value]);
69610
+ }
69611
+ return { options, flags };
69612
+ }
69613
+ function requireOption(parsed, name) {
69614
+ const value = parsed.options.get(name)?.[0];
69615
+ if (value === void 0 || value.length === 0) {
69616
+ throw new DevkitCliError(name, `--${name} is required`);
69617
+ }
69618
+ return value;
69619
+ }
69620
+ function outputSuccess(json, result) {
69621
+ if (json) {
69622
+ console.log(JSON.stringify({
69623
+ ok: true,
69624
+ daemonRunning: result.daemonRunning,
69625
+ ...result.warning ? { warning: result.warning } : {},
69626
+ ...result.configVersion === void 0 ? {} : { configVersion: result.configVersion }
69627
+ }));
69628
+ return;
69629
+ }
69630
+ const daemonText = result.daemonRunning === null ? "unknown" : String(result.daemonRunning);
69631
+ console.log(`ok=true daemonRunning=${daemonText}${result.warning ? ` warning=${result.warning.code}` : ""}`);
69632
+ if (result.warning) {
69633
+ console.log(result.warning.message);
69634
+ }
69635
+ }
69636
+ function outputError(json, detail) {
69637
+ if (json) {
69638
+ console.log(JSON.stringify({ ok: false, error: detail.reason }));
69639
+ return;
69640
+ }
69641
+ console.error(`ok=false field=${detail.field} error=${detail.reason}`);
69642
+ }
69643
+ function normalizeError(error) {
69644
+ if (error instanceof DevkitCliError) {
69645
+ return error.toValidationError();
69646
+ }
69647
+ if (error instanceof DevkitServerStoreError) {
69648
+ return { field: "config", reason: error.message };
69649
+ }
69650
+ return { field: "unknown", reason: error instanceof Error ? error.message : String(error) };
69651
+ }
69652
+ function devkitSentryExtra(extra) {
69653
+ const normalized = { component: "node_devkit" };
69654
+ for (const [key, value] of Object.entries(extra)) {
69655
+ if (value !== void 0) {
69656
+ normalized[key] = String(value);
69657
+ }
69658
+ }
69659
+ return normalized;
69660
+ }
69661
+ function isHelpArg(value) {
69662
+ return value === "help" || value === "-h" || value === "--help";
69663
+ }
69664
+
68135
69665
  // src/xmtp-test-cli.ts
68136
- var import_promises10 = require("node:fs/promises");
69666
+ var import_promises11 = require("node:fs/promises");
68137
69667
  var import_node_path27 = require("node:path");
68138
69668
  init_daemon();
68139
69669
 
68140
69670
  // src/log-tail.ts
68141
- var import_node_fs20 = require("node:fs");
68142
- var import_promises9 = require("node:fs/promises");
69671
+ var import_node_fs21 = require("node:fs");
69672
+ var import_promises10 = require("node:fs/promises");
68143
69673
  var import_node_path26 = require("node:path");
68144
69674
  var import_node_string_decoder = require("node:string_decoder");
68145
69675
  init_win_spawn();
@@ -68234,7 +69764,7 @@ async function followFile(filePath, onData, options = {}) {
68234
69764
  let handle;
68235
69765
  try {
68236
69766
  try {
68237
- handle = await (0, import_promises9.open)(filePath, "r");
69767
+ handle = await (0, import_promises10.open)(filePath, "r");
68238
69768
  } catch (error) {
68239
69769
  if (error.code === "ENOENT") {
68240
69770
  markMissing();
@@ -68299,7 +69829,7 @@ async function followFile(filePath, onData, options = {}) {
68299
69829
  }, pollIntervalMs);
68300
69830
  const targetName = (0, import_node_path26.basename)(filePath);
68301
69831
  try {
68302
- watcher = (0, import_node_fs20.watch)((0, import_node_path26.dirname)(filePath), (_eventType, filename) => {
69832
+ watcher = (0, import_node_fs21.watch)((0, import_node_path26.dirname)(filePath), (_eventType, filename) => {
68303
69833
  if (filename === null || filename.toString() === targetName) {
68304
69834
  void check();
68305
69835
  }
@@ -68340,7 +69870,7 @@ async function readTailSnapshot(filePath, maxLines) {
68340
69870
  async function readTailSnapshotOnce(filePath, maxLines) {
68341
69871
  let handle;
68342
69872
  try {
68343
- handle = await (0, import_promises9.open)(filePath, "r");
69873
+ handle = await (0, import_promises10.open)(filePath, "r");
68344
69874
  } catch (error) {
68345
69875
  if (error.code === "ENOENT") {
68346
69876
  return { text: "", offset: 0, fileIdentity: null };
@@ -68397,7 +69927,7 @@ async function readTailSnapshotOnce(filePath, maxLines) {
68397
69927
  }
68398
69928
  async function currentPositionOrMissing(filePath) {
68399
69929
  try {
68400
- const stats = await (0, import_promises9.stat)(filePath);
69930
+ const stats = await (0, import_promises10.stat)(filePath);
68401
69931
  return { offset: stats.size, fileIdentity: identityForStats(stats) };
68402
69932
  } catch (error) {
68403
69933
  if (error.code === "ENOENT") {
@@ -68494,7 +70024,7 @@ async function startXmtpTest(args, releaseInfo) {
68494
70024
  const runId = requestedRunId ? validateRunId(requestedRunId) : createRunId(requestedName);
68495
70025
  const files = resolveRunFiles(testsDir, runId);
68496
70026
  try {
68497
- await (0, import_promises10.stat)(files.runDir);
70027
+ await (0, import_promises11.stat)(files.runDir);
68498
70028
  throw new Error(`XMTP test run already exists: ${runId}`);
68499
70029
  } catch (error) {
68500
70030
  if (error.code !== "ENOENT") {
@@ -68502,7 +70032,7 @@ async function startXmtpTest(args, releaseInfo) {
68502
70032
  }
68503
70033
  }
68504
70034
  await ensurePrivateDir(files.runDir);
68505
- await (0, import_promises10.writeFile)(files.eventsPath, "", { encoding: "utf8", mode: 384 });
70035
+ await (0, import_promises11.writeFile)(files.eventsPath, "", { encoding: "utf8", mode: 384 });
68506
70036
  const manifest = {
68507
70037
  runId,
68508
70038
  name: requestedName,
@@ -68546,7 +70076,7 @@ async function stopXmtpTest(args) {
68546
70076
  }
68547
70077
  const runId = validateRunId(active.runId);
68548
70078
  const files = resolveRunFiles(testsDir, runId);
68549
- await (0, import_promises10.unlink)(activePath);
70079
+ await (0, import_promises11.unlink)(activePath);
68550
70080
  const manifest = await readRequiredJson(files.manifestPath);
68551
70081
  const completed = {
68552
70082
  ...manifest,
@@ -68864,7 +70394,7 @@ async function resolveRequestedRunId(testsDir, args, preferActive = false) {
68864
70394
  async function findLatestRunId(testsDir) {
68865
70395
  let entries;
68866
70396
  try {
68867
- entries = await (0, import_promises10.readdir)(testsDir, { withFileTypes: true });
70397
+ entries = await (0, import_promises11.readdir)(testsDir, { withFileTypes: true });
68868
70398
  } catch (error) {
68869
70399
  if (error.code === "ENOENT") {
68870
70400
  return null;
@@ -68889,7 +70419,7 @@ async function findLatestRunId(testsDir) {
68889
70419
  async function readMetricEvents(path2) {
68890
70420
  let text;
68891
70421
  try {
68892
- text = await (0, import_promises10.readFile)(path2, "utf8");
70422
+ text = await (0, import_promises11.readFile)(path2, "utf8");
68893
70423
  } catch (error) {
68894
70424
  if (error.code === "ENOENT") {
68895
70425
  return [];
@@ -68913,9 +70443,9 @@ function parseMetricEvent(line) {
68913
70443
  }
68914
70444
  }
68915
70445
  async function ensurePrivateDir(path2) {
68916
- await (0, import_promises10.mkdir)(path2, { recursive: true, mode: 448 });
70446
+ await (0, import_promises11.mkdir)(path2, { recursive: true, mode: 448 });
68917
70447
  try {
68918
- await (0, import_promises10.chmod)(path2, 448);
70448
+ await (0, import_promises11.chmod)(path2, 448);
68919
70449
  } catch (error) {
68920
70450
  const code = error.code;
68921
70451
  if (code !== "EPERM" && code !== "EACCES") {
@@ -68925,12 +70455,12 @@ async function ensurePrivateDir(path2) {
68925
70455
  }
68926
70456
  async function writeJson(path2, value) {
68927
70457
  const temporary = `${path2}.${process.pid}.tmp`;
68928
- await (0, import_promises10.writeFile)(temporary, `${JSON.stringify(value, null, 2)}
70458
+ await (0, import_promises11.writeFile)(temporary, `${JSON.stringify(value, null, 2)}
68929
70459
  `, {
68930
70460
  encoding: "utf8",
68931
70461
  mode: 384
68932
70462
  });
68933
- await (0, import_promises10.rename)(temporary, path2);
70463
+ await (0, import_promises11.rename)(temporary, path2);
68934
70464
  }
68935
70465
  async function readRequiredJson(path2) {
68936
70466
  const value = await readJsonIfExists(path2);
@@ -68941,7 +70471,7 @@ async function readRequiredJson(path2) {
68941
70471
  }
68942
70472
  async function readJsonIfExists(path2) {
68943
70473
  try {
68944
- return JSON.parse(await (0, import_promises10.readFile)(path2, "utf8"));
70474
+ return JSON.parse(await (0, import_promises11.readFile)(path2, "utf8"));
68945
70475
  } catch (error) {
68946
70476
  if (error.code === "ENOENT") {
68947
70477
  return null;
@@ -69233,21 +70763,21 @@ function parseLogsTailArgs(args, subcommand) {
69233
70763
 
69234
70764
  // src/logs-export.ts
69235
70765
  var import_node_child_process10 = require("node:child_process");
69236
- var import_node_fs27 = require("node:fs");
69237
- var import_promises15 = require("node:fs/promises");
70766
+ var import_node_fs28 = require("node:fs");
70767
+ var import_promises16 = require("node:fs/promises");
69238
70768
  var import_node_os12 = require("node:os");
69239
70769
  var import_node_path34 = require("node:path");
69240
70770
  var import_jszip = __toESM(require_lib3());
69241
70771
 
69242
70772
  // src/logs-export-archive.ts
69243
- var import_node_crypto14 = require("node:crypto");
69244
- var import_node_fs24 = require("node:fs");
69245
- var import_promises13 = require("node:fs/promises");
70773
+ var import_node_crypto15 = require("node:crypto");
70774
+ var import_node_fs25 = require("node:fs");
70775
+ var import_promises14 = require("node:fs/promises");
69246
70776
  var import_node_path31 = require("node:path");
69247
70777
 
69248
70778
  // src/logs-export-filter.ts
69249
- var import_node_fs23 = require("node:fs");
69250
- var import_promises12 = require("node:fs/promises");
70779
+ var import_node_fs24 = require("node:fs");
70780
+ var import_promises13 = require("node:fs/promises");
69251
70781
  var import_node_path30 = require("node:path");
69252
70782
  var import_node_readline2 = require("node:readline");
69253
70783
  var MAX_SINGLE_RECORD_BYTES = 2 * 1024 * 1024;
@@ -69357,7 +70887,7 @@ async function readFilteredLog(path2, options, correlationIds, requireCorrelatio
69357
70887
  };
69358
70888
  }
69359
70889
  async function* streamLogRecords(path2, mode) {
69360
- const input = (0, import_node_fs23.createReadStream)(path2, { encoding: "utf8" });
70890
+ const input = (0, import_node_fs24.createReadStream)(path2, { encoding: "utf8" });
69361
70891
  const lines = (0, import_node_readline2.createInterface)({ input, crlfDelay: Infinity });
69362
70892
  let current = null;
69363
70893
  try {
@@ -69774,7 +71304,7 @@ function escapeRegExp2(value) {
69774
71304
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
69775
71305
  }
69776
71306
  async function assertRegularFile(path2) {
69777
- const file = await (0, import_promises12.lstat)(path2);
71307
+ const file = await (0, import_promises13.lstat)(path2);
69778
71308
  if (file.isSymbolicLink() || !file.isFile()) {
69779
71309
  throw Object.assign(
69780
71310
  new Error(`Refusing non-regular diagnostic source: ${(0, import_node_path30.basename)(path2)}`),
@@ -69859,7 +71389,7 @@ function recordCollector(state, result) {
69859
71389
  async function resolveOutputPath(requested, input) {
69860
71390
  if (requested) {
69861
71391
  const output2 = (0, import_node_path31.isAbsolute)(requested) ? requested : (0, import_node_path31.resolve)(input.cwd, requested);
69862
- if ((0, import_node_fs24.existsSync)(output2) && !input.overwrite) {
71392
+ if ((0, import_node_fs25.existsSync)(output2) && !input.overwrite) {
69863
71393
  throw new Error(`Output already exists: ${output2}. Pass --overwrite to replace it.`);
69864
71394
  }
69865
71395
  return output2;
@@ -69867,42 +71397,42 @@ async function resolveOutputPath(requested, input) {
69867
71397
  const stamp = input.now.toISOString().replace(/[-:]/g, "").replace(/\.\d{3}Z$/, "Z");
69868
71398
  const base = `okx-a2a-diagnostics-${stamp}.zip`;
69869
71399
  let output = (0, import_node_path31.join)(input.cwd, base);
69870
- for (let suffix = 2; (0, import_node_fs24.existsSync)(output); suffix += 1) {
71400
+ for (let suffix = 2; (0, import_node_fs25.existsSync)(output); suffix += 1) {
69871
71401
  output = (0, import_node_path31.join)(input.cwd, `okx-a2a-diagnostics-${stamp}-${suffix}.zip`);
69872
71402
  }
69873
71403
  return output;
69874
71404
  }
69875
71405
  async function writeArchiveAtomically(outputPath, archive, overwrite) {
69876
- await (0, import_promises13.mkdir)((0, import_node_path31.dirname)(outputPath), { recursive: true });
71406
+ await (0, import_promises14.mkdir)((0, import_node_path31.dirname)(outputPath), { recursive: true });
69877
71407
  const temporaryPath = (0, import_node_path31.join)(
69878
71408
  (0, import_node_path31.dirname)(outputPath),
69879
- `.${(0, import_node_path31.basename)(outputPath)}.${(0, import_node_crypto14.randomUUID)()}.tmp`
71409
+ `.${(0, import_node_path31.basename)(outputPath)}.${(0, import_node_crypto15.randomUUID)()}.tmp`
69880
71410
  );
69881
71411
  try {
69882
- await (0, import_promises13.writeFile)(temporaryPath, archive, { flag: "wx", mode: 384 });
71412
+ await (0, import_promises14.writeFile)(temporaryPath, archive, { flag: "wx", mode: 384 });
69883
71413
  if (overwrite) {
69884
- if ((0, import_node_fs24.existsSync)(outputPath)) {
69885
- await (0, import_promises13.rm)(outputPath, { force: true });
71414
+ if ((0, import_node_fs25.existsSync)(outputPath)) {
71415
+ await (0, import_promises14.rm)(outputPath, { force: true });
69886
71416
  }
69887
- await (0, import_promises13.rename)(temporaryPath, outputPath);
71417
+ await (0, import_promises14.rename)(temporaryPath, outputPath);
69888
71418
  } else {
69889
- await (0, import_promises13.link)(temporaryPath, outputPath);
69890
- await (0, import_promises13.rm)(temporaryPath, { force: true });
71419
+ await (0, import_promises14.link)(temporaryPath, outputPath);
71420
+ await (0, import_promises14.rm)(temporaryPath, { force: true });
69891
71421
  }
69892
71422
  } catch (err) {
69893
- await (0, import_promises13.rm)(temporaryPath, { force: true }).catch(() => void 0);
71423
+ await (0, import_promises14.rm)(temporaryPath, { force: true }).catch(() => void 0);
69894
71424
  throw err;
69895
71425
  }
69896
71426
  }
69897
71427
  function hashDiagnosticFileContent(content) {
69898
- return (0, import_node_crypto14.createHash)("sha256").update(content).digest("hex");
71428
+ return (0, import_node_crypto15.createHash)("sha256").update(content).digest("hex");
69899
71429
  }
69900
71430
  function isUnavailableError(err) {
69901
71431
  return !!err && typeof err === "object" && "diagnosticUnavailable" in err;
69902
71432
  }
69903
71433
 
69904
71434
  // src/logs-export-database.ts
69905
- var import_node_fs25 = require("node:fs");
71435
+ var import_node_fs26 = require("node:fs");
69906
71436
  var PROVIDERS = ["codex", "claude", "openclaw", "hermes"];
69907
71437
  function readSessionSqliteSnapshot(dbPath, options, selectedJobIds) {
69908
71438
  const hasTimeWindow2 = options.fromMs !== void 0 && options.toMs !== void 0;
@@ -70000,11 +71530,11 @@ function readSessionSqliteSnapshot(dbPath, options, selectedJobIds) {
70000
71530
  };
70001
71531
  }
70002
71532
  function readSqliteRows(dbPath, sql, params = []) {
70003
- if (!(0, import_node_fs25.existsSync)(dbPath)) {
71533
+ if (!(0, import_node_fs26.existsSync)(dbPath)) {
70004
71534
  throw unavailable(`SQLite database not found: ${dbPath}`);
70005
71535
  }
70006
- const { DatabaseSync: DatabaseSync4 } = loadSqlite4();
70007
- const db = new DatabaseSync4(dbPath, { readOnly: true });
71536
+ const { DatabaseSync: DatabaseSync5 } = loadSqlite5();
71537
+ const db = new DatabaseSync5(dbPath, { readOnly: true });
70008
71538
  try {
70009
71539
  return db.prepare(sql).all(...params);
70010
71540
  } finally {
@@ -70022,7 +71552,7 @@ function emptySqliteSnapshot() {
70022
71552
  storedProviderCommands: {}
70023
71553
  };
70024
71554
  }
70025
- function loadSqlite4() {
71555
+ function loadSqlite5() {
70026
71556
  const originalEmitWarning = process.emitWarning;
70027
71557
  process.emitWarning = ((warning, ...args) => {
70028
71558
  const message = typeof warning === "string" ? warning : warning.message;
@@ -70155,9 +71685,9 @@ function isProvider2(value) {
70155
71685
  }
70156
71686
 
70157
71687
  // src/logs-export-utils.ts
70158
- var import_node_crypto15 = require("node:crypto");
70159
- var import_node_fs26 = require("node:fs");
70160
- var import_promises14 = require("node:fs/promises");
71688
+ var import_node_crypto16 = require("node:crypto");
71689
+ var import_node_fs27 = require("node:fs");
71690
+ var import_promises15 = require("node:fs/promises");
70161
71691
  var import_node_path33 = require("node:path");
70162
71692
  var MAX_JSON_FILE_BYTES = 20 * 1024 * 1024;
70163
71693
  var STRONG_CORRELATION_KEYS = /* @__PURE__ */ new Set([
@@ -70273,7 +71803,7 @@ function collectCorrelationIds(value, output, key = "", depth = 0) {
70273
71803
  }
70274
71804
  async function safeReadDir(path2) {
70275
71805
  try {
70276
- return await (0, import_promises14.readdir)(path2);
71806
+ return await (0, import_promises15.readdir)(path2);
70277
71807
  } catch (err) {
70278
71808
  if (err.code === "ENOENT") {
70279
71809
  return [];
@@ -70286,11 +71816,11 @@ async function readJsonObject(path2) {
70286
71816
  if (file.size > MAX_JSON_FILE_BYTES) {
70287
71817
  throw unavailable2(`JSON source exceeds ${MAX_JSON_FILE_BYTES} bytes`);
70288
71818
  }
70289
- const value = parseJsonValue3(await (0, import_promises14.readFile)(path2, "utf8"));
71819
+ const value = parseJsonValue3(await (0, import_promises15.readFile)(path2, "utf8"));
70290
71820
  return isRecord7(value) ? value : null;
70291
71821
  }
70292
71822
  async function assertRegularFile2(path2) {
70293
- const file = await (0, import_promises14.lstat)(path2);
71823
+ const file = await (0, import_promises15.lstat)(path2);
70294
71824
  if (file.isSymbolicLink() || !file.isFile()) {
70295
71825
  throw unavailable2(`Refusing non-regular diagnostic source: ${(0, import_node_path33.basename)(path2)}`);
70296
71826
  }
@@ -70298,8 +71828,8 @@ async function assertRegularFile2(path2) {
70298
71828
  }
70299
71829
  async function inspectRegularFile(path2) {
70300
71830
  const file = await assertRegularFile2(path2);
70301
- const hash2 = (0, import_node_crypto15.createHash)("sha256");
70302
- for await (const chunk of (0, import_node_fs26.createReadStream)(path2)) {
71831
+ const hash2 = (0, import_node_crypto16.createHash)("sha256");
71832
+ for await (const chunk of (0, import_node_fs27.createReadStream)(path2)) {
70303
71833
  hash2.update(chunk);
70304
71834
  }
70305
71835
  return {
@@ -70551,7 +72081,7 @@ async function exportDiagnosticLogs(options) {
70551
72081
  node: process.version,
70552
72082
  platform: process.platform,
70553
72083
  arch: process.arch,
70554
- packageVersion: true ? "0.2.16" : "unknown",
72084
+ packageVersion: true ? "0.2.17-beta-ab42219842-261020165552" : "unknown",
70555
72085
  sensitiveContentIncluded: options.includeSensitiveContent,
70556
72086
  listenerAndLlmContentIncluded: true,
70557
72087
  credentialsAlwaysRedacted: true,
@@ -70968,7 +72498,7 @@ async function collectProviderDiagnostics(state, provider, storedCommand, option
70968
72498
  const configCandidates = providerConfigCandidates(provider, paths.taskHome);
70969
72499
  const configNotes = [];
70970
72500
  for (const candidate of configCandidates) {
70971
- if (!(0, import_node_fs27.existsSync)(candidate.path)) {
72501
+ if (!(0, import_node_fs28.existsSync)(candidate.path)) {
70972
72502
  continue;
70973
72503
  }
70974
72504
  let info;
@@ -71019,7 +72549,7 @@ async function collectOpenClawSessionStore(state, options) {
71019
72549
  for (const agentId of allAgentNames.slice(0, MAX_OPENCLAW_AGENTS)) {
71020
72550
  const sessionsDir = (0, import_node_path34.join)(agentsDir, agentId, "sessions");
71021
72551
  try {
71022
- const info = await (0, import_promises15.lstat)(sessionsDir);
72552
+ const info = await (0, import_promises16.lstat)(sessionsDir);
71023
72553
  if (info.isSymbolicLink() || !info.isDirectory()) {
71024
72554
  skippedSources += 1;
71025
72555
  continue;
@@ -71196,7 +72726,7 @@ async function collectGatewayLogs(state, provider, paths, options, correlationId
71196
72726
  async function collectDoctorSnapshot(state, options) {
71197
72727
  await runCollector(state, "doctor", async () => {
71198
72728
  const cliPath = process.argv[1];
71199
- if (!cliPath || !(0, import_node_fs27.existsSync)(cliPath)) {
72729
+ if (!cliPath || !(0, import_node_fs28.existsSync)(cliPath)) {
71200
72730
  throw unavailable2("Unable to resolve the running okx-a2a CLI path");
71201
72731
  }
71202
72732
  const result = (0, import_node_child_process10.spawnSync)(process.execPath, [
@@ -72463,7 +73993,7 @@ async function runDoctor(options = {}) {
72463
73993
  platform: options.platform ?? process.platform,
72464
73994
  env: options.env ?? process.env,
72465
73995
  target: options.target ?? resolveDoctorTarget(options.env ?? process.env),
72466
- cliVersion: options.cliVersion ?? (true ? "0.2.16" : "0.0.0"),
73996
+ cliVersion: options.cliVersion ?? (true ? "0.2.17-beta-ab42219842-261020165552" : "0.0.0"),
72467
73997
  fixMode: options.fix === true,
72468
73998
  nonInteractive: options.nonInteractive === true,
72469
73999
  packageChanged: false,
@@ -72704,7 +74234,22 @@ init_autostart_windows();
72704
74234
  DEFAULT_LOG_TAIL_LIMIT,
72705
74235
  DEFAULT_OFFLINE_REPLAY_INTERVAL_SEC,
72706
74236
  DEFAULT_XMTP_CLIENT_RECYCLE_INTERVAL_SEC,
74237
+ DEVKIT_DROP_REASON,
74238
+ DEVKIT_MAX_CONCURRENCY,
74239
+ DEVKIT_MAX_MESSAGE_BYTES,
74240
+ DEVKIT_MAX_PENDING,
74241
+ DEVKIT_MAX_PENDING_BYTES,
74242
+ DEVKIT_OUTCOME,
74243
+ DEVKIT_REQUEST_BUDGET_MS,
74244
+ DEVKIT_RESPONSE_DIAGNOSTIC_MAX_BYTES,
74245
+ DEVKIT_RESPONSE_SUMMARY_MAX_CHARS,
74246
+ DEVKIT_SERVER_APPLICATION_ID,
74247
+ DEVKIT_SERVER_DB_NAME,
74248
+ DEVKIT_SERVER_SCHEMA_VERSION,
72707
74249
  DOCTOR_MIN_NODE_VERSION,
74250
+ DevkitDeliveryDispatcher,
74251
+ DevkitServerStore,
74252
+ DevkitServerStoreError,
72708
74253
  GatewayOutboundBehavior,
72709
74254
  HEARTBEAT_GATEWAY_CHECK_TIMEOUT_MS,
72710
74255
  InboundReplayGate,
@@ -72733,6 +74278,9 @@ init_autostart_windows();
72733
74278
  UserCancelledAiProviderSelectionError,
72734
74279
  WALLET_STATUS_TIMEOUT_MS,
72735
74280
  XMTP_CLIENT_RECYCLE_INTERVAL_ENV,
74281
+ XMTP_CREATION_COOLDOWN_MS,
74282
+ XmtpCreationCooldown,
74283
+ XmtpCreationCooldownSkipError,
72736
74284
  XmtpDm,
72737
74285
  XmtpGroup,
72738
74286
  XmtpService,
@@ -72759,6 +74307,7 @@ init_autostart_windows();
72759
74307
  buildExternalCommandInvocation,
72760
74308
  buildGatewayOutboundExtra,
72761
74309
  buildInboundTerminalExtras,
74310
+ buildJobEnvelope,
72762
74311
  buildLaunchdPlist,
72763
74312
  buildLauncherEntryJs,
72764
74313
  buildMessageEligibleArgs,
@@ -72769,6 +74318,7 @@ init_autostart_windows();
72769
74318
  buildSchtasksRunArgs,
72770
74319
  buildSeaConfig,
72771
74320
  buildServicePath,
74321
+ buildSessionEnvelope,
72772
74322
  buildSessionKey,
72773
74323
  buildSystemMessageNotice,
72774
74324
  buildSystemStoredMessage,
@@ -72786,6 +74336,8 @@ init_autostart_windows();
72786
74336
  checkCodexCliAuthStatus,
72787
74337
  checkCodexReadiness,
72788
74338
  claimActiveDaemon,
74339
+ classifyFetchFailure,
74340
+ classifyHttpOutcome,
72789
74341
  classifyJobBindingSource,
72790
74342
  clearCodexReadinessCache,
72791
74343
  codexCommandResolvesWithoutOverride,
@@ -72794,6 +74346,7 @@ init_autostart_windows();
72794
74346
  collectCodexCommandCandidates,
72795
74347
  commandExists,
72796
74348
  createAiToolFailureTracker,
74349
+ createDevkitAutoRouter,
72797
74350
  createFileMessageHandler,
72798
74351
  createOutboundBehavior,
72799
74352
  createUserAttentionWatchParentMonitor,
@@ -72804,6 +74357,7 @@ init_autostart_windows();
72804
74357
  detectGatewayInvocation,
72805
74358
  detectMessageEligibleOfflineReplaySupport,
72806
74359
  detectRuntime,
74360
+ devkitServerDbExists,
72807
74361
  ensureDaemonReady,
72808
74362
  ensureDefaultAiProvider,
72809
74363
  ensureOpenClawOkxA2aPluginConfig,
@@ -72813,6 +74367,7 @@ init_autostart_windows();
72813
74367
  exportDiagnosticLogs,
72814
74368
  extractAiSessionId,
72815
74369
  extractDirectToUserNotification,
74370
+ extractRateLimitEndpoint,
72816
74371
  extractXmtpSentAtMs,
72817
74372
  findWindowsNativeOkxA2aExe,
72818
74373
  followFile,
@@ -72823,7 +74378,9 @@ init_autostart_windows();
72823
74378
  getResolvedOnchainosBinForTests,
72824
74379
  getRuntimeMetadata,
72825
74380
  getSessionBusyTracker,
74381
+ getXmtpCreationCooldown,
72826
74382
  handleCapabilitiesCommand,
74383
+ handleDevkitCommand,
72827
74384
  handleDoctorCommand,
72828
74385
  handleXmtpDebugCommand,
72829
74386
  handleXmtpSendCommand,
@@ -72853,6 +74410,7 @@ init_autostart_windows();
72853
74410
  isTagKey,
72854
74411
  isValidExternalJobId,
72855
74412
  isWindowsElevated,
74413
+ isXmtpRateLimitError,
72856
74414
  killProcessTree,
72857
74415
  launchdPlistHasCurrentRestartPolicy,
72858
74416
  listAllAgentsWithMetadata,
@@ -72880,6 +74438,7 @@ init_autostart_windows();
72880
74438
  persistCurrentRuntimeSelectionForNewJob,
72881
74439
  pickOnchainosWin32Candidate,
72882
74440
  prepareAndBindCurrentRuntimeForNewJob,
74441
+ printDevkitUsage,
72883
74442
  printLogsExportUsage,
72884
74443
  printXmtpTestUsage,
72885
74444
  probeCodexAuthStatus,
@@ -72891,6 +74450,7 @@ init_autostart_windows();
72891
74450
  readLastLines,
72892
74451
  readParentProcessCommandForPlatform,
72893
74452
  readUserAttentionWatcherEvent,
74453
+ redactSummary,
72894
74454
  refreshAgentsAndWait,
72895
74455
  refreshOnchainosVersionMetadata,
72896
74456
  registerUserAttentionWatcher,
@@ -72902,6 +74462,7 @@ init_autostart_windows();
72902
74462
  reportUserNotificationFailure,
72903
74463
  resetMessageEligibleOfflineReplayCapabilityForTests,
72904
74464
  resetResolvedOnchainosBinForTests,
74465
+ resetXmtpCreationCooldownForTests,
72905
74466
  resolveAiPermissionPreset,
72906
74467
  resolveAiProviderCommand,
72907
74468
  resolveAiProviderCommandWithSource,
@@ -72912,6 +74473,7 @@ init_autostart_windows();
72912
74473
  resolveCodexCommandSource,
72913
74474
  resolveConfiguredAiProvider,
72914
74475
  resolveConfiguredAiProviderForJob,
74476
+ resolveDevkitServerDbPath,
72915
74477
  resolveDirectCommunicationSessionTarget,
72916
74478
  resolveDoctorTarget,
72917
74479
  resolveEnvelopePayload,
@@ -72949,6 +74511,7 @@ init_autostart_windows();
72949
74511
  startDaemonRespectingSupervisor,
72950
74512
  startUserAttentionEventServer,
72951
74513
  startUserAttentionWatcherCoordinator,
74514
+ stopAndCloseXmtpClient,
72952
74515
  stopDaemon,
72953
74516
  stopOpenClawGateway,
72954
74517
  stopSystemdAutostart,