@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/cli.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
 
@@ -4935,8 +4937,8 @@ var require_worldwide = __commonJS({
4935
4937
  function getGlobalSingleton(name, creator, obj) {
4936
4938
  const gbl = obj || GLOBAL_OBJ;
4937
4939
  const __SENTRY__ = gbl.__SENTRY__ = gbl.__SENTRY__ || {};
4938
- const singleton2 = __SENTRY__[name] || (__SENTRY__[name] = creator());
4939
- return singleton2;
4940
+ const singleton3 = __SENTRY__[name] || (__SENTRY__[name] = creator());
4941
+ return singleton3;
4940
4942
  }
4941
4943
  exports2.GLOBAL_OBJ = GLOBAL_OBJ;
4942
4944
  exports2.getGlobalObject = getGlobalObject;
@@ -19981,6 +19983,14 @@ var init_events = __esm({
19981
19983
  SYSTEM_NOTIFICATION_ROUTED: "System notification routed",
19982
19984
  HERMES_SESSION_ROUTE_BINDING: "Hermes session route binding",
19983
19985
  DOCTOR_REPORT: "Doctor report",
19986
+ // XMTP creation rate-limit cooldown (DEXMARKET-9116). All four are logger.info,
19987
+ // so each one must also be listed in SENTRY_INFO_ALLOWLIST (index.ts) or info()
19988
+ // drops it silently. Extras are bounded tokens/ints/bools only — never raw SDK
19989
+ // error text (no-content-leak invariant).
19990
+ XMTP_RATE_LIMIT_COOLDOWN_STARTED: "XMTP rate limit cooldown started",
19991
+ XMTP_RATE_LIMIT_CREATE_SUPPRESSED: "XMTP rate limit create suppressed",
19992
+ XMTP_RATE_LIMIT_PROBE: "XMTP rate limit probe",
19993
+ XMTP_RATE_LIMIT_RECOVERED: "XMTP rate limit recovered",
19984
19994
  // ── error ─────────────────────────────────────────────────────
19985
19995
  XMTP_CONNECTION_FAILED: "XMTP connection failed",
19986
19996
  CONVERSATIONS_STREAM_FAILED: "conversations.stream failed",
@@ -20046,7 +20056,28 @@ var init_events = __esm({
20046
20056
  AGENT_DB_DIR_CREATE_FAILED: "Agent DB dir create failed",
20047
20057
  AGENT_INSTALLATION_LIMIT_NEAR: "Agent installation limit near",
20048
20058
  XMTP_HISTORY_SYNC_REQUEST_FAILED: "XMTP history sync request failed",
20049
- XMTP_DEBUG_SYNC_FAILED: "XMTP debug sync failed"
20059
+ XMTP_DEBUG_SYNC_FAILED: "XMTP debug sync failed",
20060
+ // Underlying XMTP SDK client close failed during recycle/removal/shutdown
20061
+ // (DEXMARKET-9116). Error-level → NOT added to SENTRY_INFO_ALLOWLIST.
20062
+ XMTP_CLIENT_CLOSE_FAILED: "XMTP client close failed",
20063
+ // ── devkit custom-server registry + delivery (DEXMARKET-9165) ──────────────
20064
+ // info-level (registered in SENTRY_INFO_ALLOWLIST below):
20065
+ DEVKIT_REGISTER_REQUESTED: "Devkit register requested",
20066
+ DEVKIT_REGISTER_COMPLETED: "Devkit register completed",
20067
+ DEVKIT_UNREGISTER_REQUESTED: "Devkit unregister requested",
20068
+ DEVKIT_UNREGISTER_COMPLETED: "Devkit unregister completed",
20069
+ DEVKIT_DAEMON_STATUS_UNKNOWN: "Devkit daemon status unknown",
20070
+ DEVKIT_ROUTE_DEFAULT_AI: "Devkit route default AI",
20071
+ DEVKIT_ROUTE_CUSTOM_SERVER: "Devkit route custom server",
20072
+ DEVKIT_DELIVERY_ACCEPTED: "Devkit delivery accepted",
20073
+ DEVKIT_DELIVERY_HTTP_ACCEPTED: "Devkit delivery http accepted",
20074
+ DEVKIT_DELIVERY_DROPPED: "Devkit delivery dropped",
20075
+ DEVKIT_DELIVERY_CANCELLED: "Devkit delivery cancelled",
20076
+ // error-level (NOT allowlisted — logger.error):
20077
+ DEVKIT_REGISTER_REJECTED: "Devkit register rejected",
20078
+ DEVKIT_CONFIG_PERSIST_FAILED: "Devkit config persist failed",
20079
+ DEVKIT_ROUTE_CONFIG_READ_FAILED: "Devkit route config read failed",
20080
+ DEVKIT_DELIVERY_HTTP_FAILED: "Devkit delivery http failed"
20050
20081
  };
20051
20082
  }
20052
20083
  });
@@ -20885,7 +20916,26 @@ var init_sentry_logger = __esm({
20885
20916
  LogEvent.PENDING_LIST_QUERIED,
20886
20917
  LogEvent.SESSION_KEY_DERIVED,
20887
20918
  LogEvent.SESSIONS_QUERIED,
20888
- LogEvent.SYNC_TICK_COMPLETED
20919
+ LogEvent.SYNC_TICK_COMPLETED,
20920
+ // XMTP creation rate-limit cooldown checkpoints (DEXMARKET-9116). info() drops
20921
+ // any event not listed here, so these must stay registered.
20922
+ LogEvent.XMTP_RATE_LIMIT_COOLDOWN_STARTED,
20923
+ LogEvent.XMTP_RATE_LIMIT_CREATE_SUPPRESSED,
20924
+ LogEvent.XMTP_RATE_LIMIT_PROBE,
20925
+ LogEvent.XMTP_RATE_LIMIT_RECOVERED,
20926
+ // devkit custom-server registry + delivery info checkpoints (DEXMARKET-9165).
20927
+ // info() drops any event not listed here, so these must stay registered.
20928
+ LogEvent.DEVKIT_REGISTER_REQUESTED,
20929
+ LogEvent.DEVKIT_REGISTER_COMPLETED,
20930
+ LogEvent.DEVKIT_UNREGISTER_REQUESTED,
20931
+ LogEvent.DEVKIT_UNREGISTER_COMPLETED,
20932
+ LogEvent.DEVKIT_DAEMON_STATUS_UNKNOWN,
20933
+ LogEvent.DEVKIT_ROUTE_DEFAULT_AI,
20934
+ LogEvent.DEVKIT_ROUTE_CUSTOM_SERVER,
20935
+ LogEvent.DEVKIT_DELIVERY_ACCEPTED,
20936
+ LogEvent.DEVKIT_DELIVERY_HTTP_ACCEPTED,
20937
+ LogEvent.DEVKIT_DELIVERY_DROPPED,
20938
+ LogEvent.DEVKIT_DELIVERY_CANCELLED
20889
20939
  ]);
20890
20940
  MAX_EXTRA_STRING_LENGTH = 256;
20891
20941
  MAX_TAG_VALUE_LENGTH = 128;
@@ -27001,7 +27051,7 @@ function buildConnectParams(config, instanceId, protocolVersion) {
27001
27051
  client: {
27002
27052
  id: "gateway-client",
27003
27053
  displayName: "okx-a2a-node",
27004
- version: "0.2.16",
27054
+ version: "0.2.17-beta-ab42219842-261020165552",
27005
27055
  platform: "node",
27006
27056
  mode: "backend",
27007
27057
  instanceId
@@ -27012,7 +27062,7 @@ function buildConnectParams(config, instanceId, protocolVersion) {
27012
27062
  commands: [],
27013
27063
  permissions: {},
27014
27064
  locale: Intl.DateTimeFormat().resolvedOptions().locale || "en-US",
27015
- userAgent: `okx-a2a-node/${"0.2.16"}`,
27065
+ userAgent: `okx-a2a-node/${"0.2.17-beta-ab42219842-261020165552"}`,
27016
27066
  auth: {
27017
27067
  ...config.token ? { token: config.token } : {},
27018
27068
  ...config.password ? { password: config.password } : {}
@@ -29072,7 +29122,7 @@ var init_sentry_config = __esm({
29072
29122
  environment = process.env.SENTRY_ENV === "dev" ? "dev" : "prod";
29073
29123
  SENTRY_CONFIG = {
29074
29124
  projectName: "okx/openclaw-okx-a2a-extension",
29075
- release: "0.2.16",
29125
+ release: "0.2.17-beta-ab42219842-261020165552",
29076
29126
  environment,
29077
29127
  runtimeContainer: normalizeRuntimeContainer(process.env.OKX_A2A_RUNTIME_CONTAINER)
29078
29128
  };
@@ -39642,8 +39692,8 @@ function readSqliteRows(dbPath, sql, params = []) {
39642
39692
  if (!(0, import_node_fs17.existsSync)(dbPath)) {
39643
39693
  throw unavailable(`SQLite database not found: ${dbPath}`);
39644
39694
  }
39645
- const { DatabaseSync: DatabaseSync5 } = loadSqlite3();
39646
- const db = new DatabaseSync5(dbPath, { readOnly: true });
39695
+ const { DatabaseSync: DatabaseSync6 } = loadSqlite3();
39696
+ const db = new DatabaseSync6(dbPath, { readOnly: true });
39647
39697
  try {
39648
39698
  return db.prepare(sql).all(...params);
39649
39699
  } finally {
@@ -40242,7 +40292,7 @@ async function exportDiagnosticLogs(options) {
40242
40292
  node: process.version,
40243
40293
  platform: process.platform,
40244
40294
  arch: process.arch,
40245
- packageVersion: true ? "0.2.16" : "unknown",
40295
+ packageVersion: true ? "0.2.17-beta-ab42219842-261020165552" : "unknown",
40246
40296
  sensitiveContentIncluded: options.includeSensitiveContent,
40247
40297
  listenerAndLlmContentIncluded: true,
40248
40298
  credentialsAlwaysRedacted: true,
@@ -42221,6 +42271,701 @@ var init_trade_records_cli = __esm({
42221
42271
  }
42222
42272
  });
42223
42273
 
42274
+ // src/devkit-server-store.ts
42275
+ function resolveDevkitServerDbPath(homeDir) {
42276
+ return resolveTaskPaths(homeDir).devkitServerDbPath;
42277
+ }
42278
+ function applyMigrationV12(db) {
42279
+ db.exec(`
42280
+ CREATE TABLE ${TABLE_NAME2} (
42281
+ id INTEGER PRIMARY KEY CHECK (id = 1),
42282
+ origin TEXT NOT NULL,
42283
+ port INTEGER NOT NULL CHECK (port >= 1 AND port <= 65535),
42284
+ event_path TEXT NOT NULL,
42285
+ health_path TEXT NOT NULL,
42286
+ config_version INTEGER NOT NULL,
42287
+ updated_at INTEGER NOT NULL,
42288
+ CHECK (length(origin) > 0),
42289
+ CHECK (substr(event_path,1,1) = '/'),
42290
+ CHECK (substr(health_path,1,1) = '/')
42291
+ )
42292
+ `);
42293
+ }
42294
+ function readPragmaNumber2(db, name) {
42295
+ const row = db.prepare(`PRAGMA ${name}`).get();
42296
+ return Number(row[name] ?? 0);
42297
+ }
42298
+ function assertNotSymlink2(path2, label) {
42299
+ if (!(0, import_node_fs22.existsSync)(path2)) {
42300
+ return;
42301
+ }
42302
+ if ((0, import_node_fs22.lstatSync)(path2).isSymbolicLink()) {
42303
+ throw new DevkitServerStoreError("DATABASE_PATH_UNSAFE", `${label} must not be a symbolic link`);
42304
+ }
42305
+ }
42306
+ function assertSafeDatabasePath2(dbPath) {
42307
+ assertSafeDatabaseFile2(dbPath);
42308
+ for (const suffix of ["-journal", "-wal", "-shm"]) {
42309
+ assertNotSymlink2(`${dbPath}${suffix}`, `devkit server database sidecar ${suffix}`);
42310
+ }
42311
+ }
42312
+ function assertSafeDatabaseFile2(dbPath) {
42313
+ if (!(0, import_node_fs22.existsSync)(dbPath)) {
42314
+ return;
42315
+ }
42316
+ const stat4 = (0, import_node_fs22.lstatSync)(dbPath);
42317
+ if (stat4.isSymbolicLink()) {
42318
+ throw new DevkitServerStoreError(
42319
+ "DATABASE_PATH_UNSAFE",
42320
+ "devkit server database must not be a symbolic link"
42321
+ );
42322
+ }
42323
+ if (!stat4.isFile() || stat4.nlink !== 1) {
42324
+ throw new DevkitServerStoreError(
42325
+ "DATABASE_PATH_UNSAFE",
42326
+ "devkit server database must be a regular file with one hard link"
42327
+ );
42328
+ }
42329
+ }
42330
+ function rollbackQuietly2(db) {
42331
+ try {
42332
+ db.exec("ROLLBACK");
42333
+ } catch {
42334
+ }
42335
+ }
42336
+ function withBusyRetry2(operation) {
42337
+ for (let attempt = 1; ; attempt += 1) {
42338
+ try {
42339
+ return operation();
42340
+ } catch (error) {
42341
+ if (!isSqliteBusyError(error) || attempt >= WRITE_RETRY_ATTEMPTS2) {
42342
+ throw error;
42343
+ }
42344
+ sleepSyncMs3(Math.min(100 * 2 ** (attempt - 1), 1600));
42345
+ }
42346
+ }
42347
+ }
42348
+ function sleepSyncMs3(ms) {
42349
+ const buffer2 = new Int32Array(new SharedArrayBuffer(4));
42350
+ Atomics.wait(buffer2, 0, 0, ms);
42351
+ }
42352
+ function loadSqlite5() {
42353
+ const originalEmitWarning = process.emitWarning;
42354
+ process.emitWarning = ((warning, ...args) => {
42355
+ const message = typeof warning === "string" ? warning : warning.message;
42356
+ if (message.includes("SQLite is an experimental feature") && args.some((arg) => arg === "ExperimentalWarning")) {
42357
+ return;
42358
+ }
42359
+ return originalEmitWarning.call(process, warning, ...args);
42360
+ });
42361
+ try {
42362
+ return require("node:sqlite");
42363
+ } finally {
42364
+ process.emitWarning = originalEmitWarning;
42365
+ }
42366
+ }
42367
+ var import_node_fs22, DatabaseSync4, DEVKIT_SERVER_APPLICATION_ID, DEVKIT_SERVER_SCHEMA_VERSION, TABLE_NAME2, WRITE_RETRY_ATTEMPTS2, DevkitServerStoreError, DevkitServerStore;
42368
+ var init_devkit_server_store = __esm({
42369
+ "src/devkit-server-store.ts"() {
42370
+ "use strict";
42371
+ import_node_fs22 = require("node:fs");
42372
+ init_paths();
42373
+ init_session_store();
42374
+ ({ DatabaseSync: DatabaseSync4 } = loadSqlite5());
42375
+ DEVKIT_SERVER_APPLICATION_ID = 1329677395;
42376
+ DEVKIT_SERVER_SCHEMA_VERSION = 1;
42377
+ TABLE_NAME2 = `"devkit-server"`;
42378
+ WRITE_RETRY_ATTEMPTS2 = 6;
42379
+ DevkitServerStoreError = class extends Error {
42380
+ code;
42381
+ constructor(code, message) {
42382
+ super(message);
42383
+ this.name = "DevkitServerStoreError";
42384
+ this.code = code;
42385
+ }
42386
+ };
42387
+ DevkitServerStore = class _DevkitServerStore {
42388
+ dbPath;
42389
+ db;
42390
+ constructor(dbPath, db) {
42391
+ this.dbPath = dbPath;
42392
+ this.db = db;
42393
+ }
42394
+ static openForWrite(homeDir) {
42395
+ const paths = resolveTaskPaths(homeDir);
42396
+ const dbPath = paths.devkitServerDbPath;
42397
+ assertNotSymlink2(paths.sqliteDir, "devkit server directory");
42398
+ ensureTaskDir(paths.sqliteDir);
42399
+ assertNotSymlink2(paths.sqliteDir, "devkit server directory");
42400
+ assertSafeDatabasePath2(dbPath);
42401
+ const db = new DatabaseSync4(dbPath);
42402
+ const store = new _DevkitServerStore(dbPath, db);
42403
+ try {
42404
+ store.configureConnectionForWrite();
42405
+ store.ensureSchemaForWrite();
42406
+ return store;
42407
+ } catch (error) {
42408
+ db.close();
42409
+ throw error;
42410
+ }
42411
+ }
42412
+ static openForRead(homeDir) {
42413
+ const dbPath = resolveDevkitServerDbPath(homeDir);
42414
+ if (!(0, import_node_fs22.existsSync)(dbPath)) {
42415
+ return null;
42416
+ }
42417
+ assertSafeDatabaseFile2(dbPath);
42418
+ const db = new DatabaseSync4(dbPath, { readOnly: true });
42419
+ const store = new _DevkitServerStore(dbPath, db);
42420
+ try {
42421
+ db.exec("PRAGMA query_only=ON");
42422
+ store.assertReadableSchema();
42423
+ return store;
42424
+ } catch (error) {
42425
+ db.close();
42426
+ throw error;
42427
+ }
42428
+ }
42429
+ close() {
42430
+ this.db.close();
42431
+ }
42432
+ register(input) {
42433
+ return this.withWriteTransaction(() => {
42434
+ const existing = this.db.prepare(`SELECT config_version FROM ${TABLE_NAME2} WHERE id = 1`).get();
42435
+ const configVersion = (existing?.config_version ?? 0) + 1;
42436
+ const updatedAt = Date.now();
42437
+ this.db.prepare(`
42438
+ INSERT INTO ${TABLE_NAME2} (
42439
+ id, origin, port, event_path, health_path, config_version, updated_at
42440
+ ) VALUES (1, ?, ?, ?, ?, ?, ?)
42441
+ ON CONFLICT(id) DO UPDATE SET
42442
+ origin = excluded.origin,
42443
+ port = excluded.port,
42444
+ event_path = excluded.event_path,
42445
+ health_path = excluded.health_path,
42446
+ config_version = excluded.config_version,
42447
+ updated_at = excluded.updated_at
42448
+ `).run(input.origin, input.port, input.eventPath, input.healthPath, configVersion, updatedAt);
42449
+ return {
42450
+ origin: input.origin,
42451
+ port: input.port,
42452
+ eventPath: input.eventPath,
42453
+ healthPath: input.healthPath,
42454
+ configVersion,
42455
+ updatedAt
42456
+ };
42457
+ });
42458
+ }
42459
+ unregister() {
42460
+ return this.withWriteTransaction(() => {
42461
+ const result = this.db.prepare(`DELETE FROM ${TABLE_NAME2} WHERE id = 1`).run();
42462
+ return { removed: Number(result.changes) > 0 };
42463
+ });
42464
+ }
42465
+ readSnapshot() {
42466
+ let row;
42467
+ try {
42468
+ row = this.db.prepare(`
42469
+ SELECT origin, port, event_path, health_path, config_version, updated_at
42470
+ FROM ${TABLE_NAME2} WHERE id = 1
42471
+ `).get();
42472
+ } catch (error) {
42473
+ throw new DevkitServerStoreError(
42474
+ "DATABASE_READ_FAILED",
42475
+ `failed to read devkit server config: ${error instanceof Error ? error.message : String(error)}`
42476
+ );
42477
+ }
42478
+ if (!row) {
42479
+ return null;
42480
+ }
42481
+ return {
42482
+ origin: row.origin,
42483
+ port: row.port,
42484
+ eventPath: row.event_path,
42485
+ healthPath: row.health_path,
42486
+ configVersion: row.config_version,
42487
+ updatedAt: row.updated_at
42488
+ };
42489
+ }
42490
+ configureConnectionForWrite() {
42491
+ this.db.exec("PRAGMA busy_timeout=5000");
42492
+ }
42493
+ ensureSchemaForWrite() {
42494
+ withBusyRetry2(() => {
42495
+ this.db.exec("BEGIN IMMEDIATE");
42496
+ try {
42497
+ const applicationId = readPragmaNumber2(this.db, "application_id");
42498
+ const userVersion = readPragmaNumber2(this.db, "user_version");
42499
+ const hasTables = Boolean(
42500
+ this.db.prepare("SELECT 1 AS present FROM sqlite_master WHERE type = 'table' LIMIT 1").get()
42501
+ );
42502
+ if (applicationId === 0 && !hasTables && userVersion === 0) {
42503
+ this.db.exec(`PRAGMA application_id=${DEVKIT_SERVER_APPLICATION_ID}`);
42504
+ } else if (applicationId !== DEVKIT_SERVER_APPLICATION_ID) {
42505
+ throw new DevkitServerStoreError(
42506
+ "DATABASE_IDENTITY_MISMATCH",
42507
+ "devkit server database identity does not match"
42508
+ );
42509
+ }
42510
+ if (userVersion > DEVKIT_SERVER_SCHEMA_VERSION) {
42511
+ throw new DevkitServerStoreError(
42512
+ "DATABASE_SCHEMA_TOO_NEW",
42513
+ `devkit server schema version ${userVersion} is newer than supported ${DEVKIT_SERVER_SCHEMA_VERSION}`
42514
+ );
42515
+ }
42516
+ if (userVersion < 1) {
42517
+ applyMigrationV12(this.db);
42518
+ this.db.exec("PRAGMA user_version=1");
42519
+ }
42520
+ this.db.exec("COMMIT");
42521
+ } catch (error) {
42522
+ rollbackQuietly2(this.db);
42523
+ throw error;
42524
+ }
42525
+ });
42526
+ withBusyRetry2(() => {
42527
+ this.db.exec("PRAGMA journal_mode=WAL");
42528
+ this.db.exec("PRAGMA synchronous=FULL");
42529
+ });
42530
+ }
42531
+ assertReadableSchema() {
42532
+ const applicationId = readPragmaNumber2(this.db, "application_id");
42533
+ if (applicationId !== DEVKIT_SERVER_APPLICATION_ID) {
42534
+ throw new DevkitServerStoreError(
42535
+ "DATABASE_IDENTITY_MISMATCH",
42536
+ "devkit server database identity does not match"
42537
+ );
42538
+ }
42539
+ const userVersion = readPragmaNumber2(this.db, "user_version");
42540
+ if (userVersion > DEVKIT_SERVER_SCHEMA_VERSION) {
42541
+ throw new DevkitServerStoreError(
42542
+ "DATABASE_SCHEMA_TOO_NEW",
42543
+ `devkit server schema version ${userVersion} is newer than supported ${DEVKIT_SERVER_SCHEMA_VERSION}`
42544
+ );
42545
+ }
42546
+ if (userVersion < DEVKIT_SERVER_SCHEMA_VERSION) {
42547
+ throw new DevkitServerStoreError(
42548
+ "DATABASE_MIGRATION_REQUIRED",
42549
+ "devkit server database requires a write command to finish migration"
42550
+ );
42551
+ }
42552
+ }
42553
+ withWriteTransaction(operation) {
42554
+ return withBusyRetry2(() => {
42555
+ this.db.exec("BEGIN IMMEDIATE");
42556
+ try {
42557
+ const result = operation();
42558
+ this.db.exec("COMMIT");
42559
+ return result;
42560
+ } catch (error) {
42561
+ rollbackQuietly2(this.db);
42562
+ throw error;
42563
+ }
42564
+ });
42565
+ }
42566
+ };
42567
+ }
42568
+ });
42569
+
42570
+ // src/devkit-cli.ts
42571
+ var devkit_cli_exports = {};
42572
+ __export(devkit_cli_exports, {
42573
+ handleDevkitCommand: () => handleDevkitCommand,
42574
+ printDevkitUsage: () => printDevkitUsage
42575
+ });
42576
+ async function handleDevkitCommand(args) {
42577
+ const wantsJson = args.includes("--json");
42578
+ const subcommand = args[0];
42579
+ if (!subcommand || isHelpArg2(subcommand)) {
42580
+ printDevkitUsage();
42581
+ return;
42582
+ }
42583
+ if (args.slice(1).some(isHelpArg2)) {
42584
+ printDevkitUsage();
42585
+ return;
42586
+ }
42587
+ if (subcommand === "register") {
42588
+ await handleRegister(args.slice(1), wantsJson);
42589
+ return;
42590
+ }
42591
+ if (subcommand === "unregister") {
42592
+ await handleUnregister(args.slice(1), wantsJson);
42593
+ return;
42594
+ }
42595
+ outputError2(wantsJson, { field: "command", reason: `unknown devkit command: ${subcommand}` });
42596
+ process.exitCode = 1;
42597
+ }
42598
+ function printDevkitUsage() {
42599
+ console.log(`Usage: okx-a2a devkit <register|unregister> [options]
42600
+
42601
+ Commands:
42602
+ register Register a local custom server for daemon auto-message delivery.
42603
+ --url <origin> --port <n> --paths '{"event":"/path","health":"/path"}'
42604
+ unregister Remove the registered custom server; daemon reverts to default AI delivery.
42605
+
42606
+ Options:
42607
+ --json Print machine-readable output.`);
42608
+ }
42609
+ async function handleRegister(args, wantsJson) {
42610
+ const operationId = (0, import_node_crypto9.randomUUID)();
42611
+ const startedAt = Date.now();
42612
+ logger.info(LogEvent.DEVKIT_REGISTER_REQUESTED, devkitSentryExtra({ operationId, phase: "requested" }));
42613
+ try {
42614
+ const parsed = parseArgs2(args, { options: /* @__PURE__ */ new Set(["url", "port", "paths"]), flags: /* @__PURE__ */ new Set(["json"]) });
42615
+ const origin = validateUrl(requireOption(parsed, "url"));
42616
+ const port = validatePort(requireOption(parsed, "port"));
42617
+ const { eventPath, healthPath } = validatePaths(requireOption(parsed, "paths"));
42618
+ let config;
42619
+ try {
42620
+ const store = DevkitServerStore.openForWrite();
42621
+ try {
42622
+ config = store.register({ origin, port, eventPath, healthPath });
42623
+ } finally {
42624
+ store.close();
42625
+ }
42626
+ } catch (error) {
42627
+ logger.error(
42628
+ LogEvent.DEVKIT_CONFIG_PERSIST_FAILED,
42629
+ error instanceof Error ? error : new Error(String(error)),
42630
+ devkitSentryExtra({ operationId, phase: "persist_failed", durationMs: Date.now() - startedAt })
42631
+ );
42632
+ outputError2(wantsJson, {
42633
+ field: "config",
42634
+ reason: error instanceof DevkitServerStoreError ? error.message : "failed to persist devkit configuration"
42635
+ });
42636
+ process.exitCode = 1;
42637
+ return;
42638
+ }
42639
+ const outcome = config.configVersion === 1 ? "created" : "replaced";
42640
+ const { daemonRunning, warning } = await resolveDaemonStatus(operationId);
42641
+ logger.info(
42642
+ LogEvent.DEVKIT_REGISTER_COMPLETED,
42643
+ devkitSentryExtra({
42644
+ operationId,
42645
+ phase: "completed",
42646
+ outcome,
42647
+ registrationId: String(config.configVersion),
42648
+ daemonRunning: String(daemonRunning),
42649
+ durationMs: Date.now() - startedAt
42650
+ })
42651
+ );
42652
+ outputSuccess(wantsJson, { daemonRunning, warning, configVersion: config.configVersion });
42653
+ } catch (error) {
42654
+ const detail = normalizeError2(error);
42655
+ logger.error(
42656
+ LogEvent.DEVKIT_REGISTER_REJECTED,
42657
+ error instanceof Error ? error : new Error(String(error)),
42658
+ devkitSentryExtra({ operationId, phase: "rejected", reason: detail.field, durationMs: Date.now() - startedAt })
42659
+ );
42660
+ outputError2(wantsJson, detail);
42661
+ process.exitCode = 1;
42662
+ }
42663
+ }
42664
+ async function handleUnregister(args, wantsJson) {
42665
+ const operationId = (0, import_node_crypto9.randomUUID)();
42666
+ const startedAt = Date.now();
42667
+ logger.info(LogEvent.DEVKIT_UNREGISTER_REQUESTED, devkitSentryExtra({ operationId, phase: "requested" }));
42668
+ try {
42669
+ parseArgs2(args, { options: /* @__PURE__ */ new Set(), flags: /* @__PURE__ */ new Set(["json"]) });
42670
+ let removed;
42671
+ try {
42672
+ const store = DevkitServerStore.openForWrite();
42673
+ try {
42674
+ removed = store.unregister().removed;
42675
+ } finally {
42676
+ store.close();
42677
+ }
42678
+ } catch (error) {
42679
+ logger.error(
42680
+ LogEvent.DEVKIT_CONFIG_PERSIST_FAILED,
42681
+ error instanceof Error ? error : new Error(String(error)),
42682
+ devkitSentryExtra({ operationId, phase: "persist_failed", durationMs: Date.now() - startedAt })
42683
+ );
42684
+ outputError2(wantsJson, {
42685
+ field: "config",
42686
+ reason: error instanceof DevkitServerStoreError ? error.message : "failed to persist devkit configuration"
42687
+ });
42688
+ process.exitCode = 1;
42689
+ return;
42690
+ }
42691
+ const outcome = removed ? "removed" : "noop";
42692
+ const { daemonRunning, warning } = await resolveDaemonStatus(operationId);
42693
+ logger.info(
42694
+ LogEvent.DEVKIT_UNREGISTER_COMPLETED,
42695
+ devkitSentryExtra({
42696
+ operationId,
42697
+ phase: "completed",
42698
+ outcome,
42699
+ daemonRunning: String(daemonRunning),
42700
+ durationMs: Date.now() - startedAt
42701
+ })
42702
+ );
42703
+ outputSuccess(wantsJson, { daemonRunning, warning });
42704
+ } catch (error) {
42705
+ const detail = normalizeError2(error);
42706
+ logger.error(
42707
+ LogEvent.DEVKIT_REGISTER_REJECTED,
42708
+ error instanceof Error ? error : new Error(String(error)),
42709
+ devkitSentryExtra({ operationId, phase: "rejected", reason: detail.field, durationMs: Date.now() - startedAt })
42710
+ );
42711
+ outputError2(wantsJson, detail);
42712
+ process.exitCode = 1;
42713
+ }
42714
+ }
42715
+ async function resolveDaemonStatus(operationId) {
42716
+ try {
42717
+ const status = await getDaemonStatus();
42718
+ if (status.running) {
42719
+ return { daemonRunning: true };
42720
+ }
42721
+ return {
42722
+ daemonRunning: false,
42723
+ warning: { code: "DAEMON_NOT_RUNNING", message: DAEMON_NOT_RUNNING_MESSAGE }
42724
+ };
42725
+ } catch {
42726
+ logger.info(LogEvent.DEVKIT_DAEMON_STATUS_UNKNOWN, devkitSentryExtra({ operationId, phase: "status_unknown" }));
42727
+ return {
42728
+ daemonRunning: null,
42729
+ warning: { code: "DAEMON_STATUS_UNKNOWN", message: DAEMON_STATUS_UNKNOWN_MESSAGE }
42730
+ };
42731
+ }
42732
+ }
42733
+ function validateUrl(raw) {
42734
+ if (raw.includes("\\")) {
42735
+ throw new DevkitCliError("url", "--url must not contain a backslash");
42736
+ }
42737
+ let url;
42738
+ try {
42739
+ url = new URL(raw);
42740
+ } catch {
42741
+ throw new DevkitCliError("url", "--url must be a valid HTTP/HTTPS origin");
42742
+ }
42743
+ if (url.protocol !== "http:" && url.protocol !== "https:") {
42744
+ throw new DevkitCliError("url", "--url scheme must be http or https");
42745
+ }
42746
+ if (url.username !== "" || url.password !== "") {
42747
+ throw new DevkitCliError("url", "--url must not contain userinfo");
42748
+ }
42749
+ if (url.port !== "") {
42750
+ throw new DevkitCliError("url", "--url must not contain an embedded port; use --port");
42751
+ }
42752
+ if (url.pathname !== "/" && url.pathname !== "") {
42753
+ throw new DevkitCliError("url", "--url must not contain a path");
42754
+ }
42755
+ if (url.search !== "") {
42756
+ throw new DevkitCliError("url", "--url must not contain a query");
42757
+ }
42758
+ if (url.hash !== "") {
42759
+ throw new DevkitCliError("url", "--url must not contain a fragment");
42760
+ }
42761
+ const hostname = url.hostname.toLowerCase();
42762
+ if (!isLoopbackHostname(hostname)) {
42763
+ throw new DevkitCliError(
42764
+ "url",
42765
+ "--url host must be a loopback address (127.0.0.0/8, ::1, or localhost)"
42766
+ );
42767
+ }
42768
+ return `${url.protocol}//${hostname}`;
42769
+ }
42770
+ function isLoopbackHostname(hostname) {
42771
+ if (hostname === "localhost") {
42772
+ return true;
42773
+ }
42774
+ if (hostname === "::1") {
42775
+ return true;
42776
+ }
42777
+ const match = LOOPBACK_IPV4_PATTERN.exec(hostname);
42778
+ if (!match) {
42779
+ return false;
42780
+ }
42781
+ const octets = match.slice(1, 5).map((segment) => Number(segment));
42782
+ if (octets.some((octet) => !Number.isInteger(octet) || octet < 0 || octet > 255)) {
42783
+ return false;
42784
+ }
42785
+ return octets[0] === 127;
42786
+ }
42787
+ function validatePort(raw) {
42788
+ if (!/^[1-9][0-9]{0,4}$/.test(raw)) {
42789
+ throw new DevkitCliError("port", "--port must be an integer between 1 and 65535");
42790
+ }
42791
+ const port = Number(raw);
42792
+ if (!Number.isInteger(port) || port < 1 || port > 65535) {
42793
+ throw new DevkitCliError("port", "--port must be an integer between 1 and 65535");
42794
+ }
42795
+ return port;
42796
+ }
42797
+ function validatePaths(raw) {
42798
+ let parsed;
42799
+ try {
42800
+ parsed = JSON.parse(raw);
42801
+ } catch {
42802
+ throw new DevkitCliError("paths", "--paths must be valid JSON");
42803
+ }
42804
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
42805
+ throw new DevkitCliError("paths", "--paths must be a JSON object");
42806
+ }
42807
+ const record = parsed;
42808
+ const keys = Object.keys(record);
42809
+ if (keys.length !== 2 || !keys.includes("event") || !keys.includes("health")) {
42810
+ throw new DevkitCliError("paths", '--paths must contain exactly the keys "event" and "health"');
42811
+ }
42812
+ const eventPath = validatePathValue(record.event, "event");
42813
+ const healthPath = validatePathValue(record.health, "health");
42814
+ return { eventPath, healthPath };
42815
+ }
42816
+ function validatePathValue(value, key) {
42817
+ if (typeof value !== "string" || value.length === 0) {
42818
+ throw new DevkitCliError("paths", `--paths.${key} must be a non-empty string`);
42819
+ }
42820
+ if (!value.startsWith("/") || value.startsWith("//")) {
42821
+ throw new DevkitCliError("paths", `--paths.${key} must start with a single "/"`);
42822
+ }
42823
+ if (value.includes("\\") || value.includes("?") || value.includes("#") || value.includes("..")) {
42824
+ throw new DevkitCliError(
42825
+ "paths",
42826
+ `--paths.${key} must not contain a query, fragment, backslash, "..", or an absolute URL`
42827
+ );
42828
+ }
42829
+ if (/^\/[a-zA-Z][a-zA-Z0-9+.-]*:/.test(value)) {
42830
+ throw new DevkitCliError("paths", `--paths.${key} must not be an absolute URL`);
42831
+ }
42832
+ return value;
42833
+ }
42834
+ function parseArgs2(args, spec) {
42835
+ const options = /* @__PURE__ */ new Map();
42836
+ const flags = /* @__PURE__ */ new Set();
42837
+ for (let index2 = 0; index2 < args.length; index2 += 1) {
42838
+ const token = args[index2];
42839
+ if (!token.startsWith("--")) {
42840
+ throw new DevkitCliError("command", `unexpected positional argument: ${token}`);
42841
+ }
42842
+ const name = token.slice(2);
42843
+ if (spec.flags.has(name)) {
42844
+ if (flags.has(name)) {
42845
+ throw new DevkitCliError("command", `${token} must not be repeated`);
42846
+ }
42847
+ flags.add(name);
42848
+ continue;
42849
+ }
42850
+ if (!spec.options.has(name)) {
42851
+ throw new DevkitCliError("command", `unknown option ${token}`);
42852
+ }
42853
+ if (index2 + 1 >= args.length) {
42854
+ throw new DevkitCliError("command", `${token} requires a value`);
42855
+ }
42856
+ const value = args[++index2];
42857
+ if (value.startsWith("--")) {
42858
+ throw new DevkitCliError("command", `${token} requires a value`);
42859
+ }
42860
+ if (options.has(name)) {
42861
+ throw new DevkitCliError("command", `${token} must not be repeated`);
42862
+ }
42863
+ options.set(name, [value]);
42864
+ }
42865
+ return { options, flags };
42866
+ }
42867
+ function requireOption(parsed, name) {
42868
+ const value = parsed.options.get(name)?.[0];
42869
+ if (value === void 0 || value.length === 0) {
42870
+ throw new DevkitCliError(name, `--${name} is required`);
42871
+ }
42872
+ return value;
42873
+ }
42874
+ function outputSuccess(json, result) {
42875
+ if (json) {
42876
+ console.log(JSON.stringify({
42877
+ ok: true,
42878
+ daemonRunning: result.daemonRunning,
42879
+ ...result.warning ? { warning: result.warning } : {},
42880
+ ...result.configVersion === void 0 ? {} : { configVersion: result.configVersion }
42881
+ }));
42882
+ return;
42883
+ }
42884
+ const daemonText = result.daemonRunning === null ? "unknown" : String(result.daemonRunning);
42885
+ console.log(`ok=true daemonRunning=${daemonText}${result.warning ? ` warning=${result.warning.code}` : ""}`);
42886
+ if (result.warning) {
42887
+ console.log(result.warning.message);
42888
+ }
42889
+ }
42890
+ function outputError2(json, detail) {
42891
+ if (json) {
42892
+ console.log(JSON.stringify({ ok: false, error: detail.reason }));
42893
+ return;
42894
+ }
42895
+ console.error(`ok=false field=${detail.field} error=${detail.reason}`);
42896
+ }
42897
+ function normalizeError2(error) {
42898
+ if (error instanceof DevkitCliError) {
42899
+ return error.toValidationError();
42900
+ }
42901
+ if (error instanceof DevkitServerStoreError) {
42902
+ return { field: "config", reason: error.message };
42903
+ }
42904
+ return { field: "unknown", reason: error instanceof Error ? error.message : String(error) };
42905
+ }
42906
+ function devkitSentryExtra(extra) {
42907
+ const normalized = { component: "node_devkit" };
42908
+ for (const [key, value] of Object.entries(extra)) {
42909
+ if (value !== void 0) {
42910
+ normalized[key] = String(value);
42911
+ }
42912
+ }
42913
+ return normalized;
42914
+ }
42915
+ function isHelpArg2(value) {
42916
+ return value === "help" || value === "-h" || value === "--help";
42917
+ }
42918
+ var import_node_crypto9, DAEMON_NOT_RUNNING_MESSAGE, DAEMON_STATUS_UNKNOWN_MESSAGE, LOOPBACK_IPV4_PATTERN, DevkitCliError;
42919
+ var init_devkit_cli = __esm({
42920
+ "src/devkit-cli.ts"() {
42921
+ "use strict";
42922
+ import_node_crypto9 = require("node:crypto");
42923
+ init_daemon();
42924
+ init_devkit_server_store();
42925
+ init_sentry_logger();
42926
+ DAEMON_NOT_RUNNING_MESSAGE = "\u5F53\u524D daemon \u672A\u8FD0\u884C,\u8BF7\u4F7F\u7528 okx-a2a start \u542F\u52A8 daemon";
42927
+ DAEMON_STATUS_UNKNOWN_MESSAGE = "\u914D\u7F6E\u5DF2\u5199\u5165,\u4F46\u65E0\u6CD5\u786E\u8BA4 daemon \u8FD0\u884C\u72B6\u6001";
42928
+ LOOPBACK_IPV4_PATTERN = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/;
42929
+ DevkitCliError = class extends Error {
42930
+ field;
42931
+ constructor(field, reason) {
42932
+ super(reason);
42933
+ this.name = "DevkitCliError";
42934
+ this.field = field;
42935
+ }
42936
+ toValidationError() {
42937
+ return { field: this.field, reason: this.message };
42938
+ }
42939
+ };
42940
+ }
42941
+ });
42942
+
42943
+ // ../core/src/xmtp-sdk/client-lifecycle.ts
42944
+ async function stopAndCloseXmtpClient(agent, ctx) {
42945
+ let stopped = true;
42946
+ try {
42947
+ await Promise.resolve(agent.stop());
42948
+ } catch {
42949
+ stopped = false;
42950
+ }
42951
+ const close2 = agent.client?.close;
42952
+ if (typeof close2 !== "function") {
42953
+ return { stopped, closed: false, closeFailed: false };
42954
+ }
42955
+ try {
42956
+ await Promise.resolve(close2.call(agent.client));
42957
+ return { stopped, closed: true, closeFailed: false };
42958
+ } catch (err2) {
42959
+ ctx.onCloseError?.(err2);
42960
+ return { stopped, closed: false, closeFailed: true };
42961
+ }
42962
+ }
42963
+ var init_client_lifecycle = __esm({
42964
+ "../core/src/xmtp-sdk/client-lifecycle.ts"() {
42965
+ "use strict";
42966
+ }
42967
+ });
42968
+
42224
42969
  // ../core/src/xmtp-sdk/onchainos/bin.ts
42225
42970
  async function refreshOnchainosVersionMetadata(options = {}) {
42226
42971
  const now = options.now ?? Date.now;
@@ -42340,7 +43085,7 @@ function isResolvedBinUsable(bin) {
42340
43085
  if (!isPathLikeCommand(bin)) {
42341
43086
  return true;
42342
43087
  }
42343
- return process.platform === "win32" ? (0, import_node_fs22.existsSync)(bin) : isExecutable2(bin);
43088
+ return process.platform === "win32" ? (0, import_node_fs23.existsSync)(bin) : isExecutable2(bin);
42344
43089
  }
42345
43090
  function resolvePosixBareCommand(command, pathValue) {
42346
43091
  for (const dir of pathValue.split(":")) {
@@ -42677,7 +43422,7 @@ function isWindowsAppsAlias(candidate) {
42677
43422
  return candidate.toLowerCase().includes(WINDOWS_APPS_ALIAS_MARKER);
42678
43423
  }
42679
43424
  function win32FileExists(path2) {
42680
- return (0, import_node_fs22.existsSync)(path2);
43425
+ return (0, import_node_fs23.existsSync)(path2);
42681
43426
  }
42682
43427
  function pickOnchainosWin32Candidate(lines, fileExists2 = win32FileExists) {
42683
43428
  const candidates = lines.map((line) => {
@@ -42733,7 +43478,7 @@ function extractExecutablePath(stdout) {
42733
43478
  }
42734
43479
  function isExecutable2(path2) {
42735
43480
  try {
42736
- (0, import_node_fs22.accessSync)(path2, import_node_fs22.constants.X_OK);
43481
+ (0, import_node_fs23.accessSync)(path2, import_node_fs23.constants.X_OK);
42737
43482
  return true;
42738
43483
  } catch {
42739
43484
  return false;
@@ -42838,12 +43583,12 @@ async function exec(args, options = {}) {
42838
43583
  }
42839
43584
  throw new Error("OnchainOS command retry exhausted");
42840
43585
  }
42841
- var import_node_fs22, import_node_child_process8, import_node_path25, import_node_util2, execFileAsync2, resolvedBin, resolvedForEnvBin, resolverRevision, versionProbeInFlight, posixDiscoveryFlights, REDACTED_VALUE_FLAGS, COMMAND_UNAVAILABLE_CODES, ONCHAINOS_VERSION_PROBE_TIMEOUT_MS, ONCHAINOS_BIN_RESOLVE_TIMEOUT_MS, WINDOWS_APPS_ALIAS_MARKER;
43586
+ var import_node_fs23, import_node_child_process8, import_node_path25, import_node_util2, execFileAsync2, resolvedBin, resolvedForEnvBin, resolverRevision, versionProbeInFlight, posixDiscoveryFlights, REDACTED_VALUE_FLAGS, COMMAND_UNAVAILABLE_CODES, ONCHAINOS_VERSION_PROBE_TIMEOUT_MS, ONCHAINOS_BIN_RESOLVE_TIMEOUT_MS, WINDOWS_APPS_ALIAS_MARKER;
42842
43587
  var init_bin = __esm({
42843
43588
  "../core/src/xmtp-sdk/onchainos/bin.ts"() {
42844
43589
  "use strict";
42845
43590
  init_log();
42846
- import_node_fs22 = require("node:fs");
43591
+ import_node_fs23 = require("node:fs");
42847
43592
  import_node_child_process8 = require("node:child_process");
42848
43593
  import_node_path25 = require("node:path");
42849
43594
  import_node_util2 = require("node:util");
@@ -42907,12 +43652,12 @@ function createAsyncStreamProxy(stream) {
42907
43652
  }
42908
43653
  });
42909
43654
  }
42910
- var import_node_bindings, import_node_bindings2, import_node_crypto9, import_types, import_node_path26, import_node_process, HistorySyncUrls, envMap, reverseEnvMap, envToString, createBackend, InboxReassignError, AccountAlreadyAssociatedError, MissingContentTypeError, SignerUnavailableError, ClientNotInitializedError, StreamFailedError, StreamInvalidRetryAttemptsError, generateInboxId, getInboxIdForIdentifier, isReaction, isReply, isText, isRemoteAttachment, isAttachment, isMultiRemoteAttachment, isTransactionReference, isGroupUpdated, isReadReceipt, isLeaveRequest, isWalletSendCalls, isIntent, isActions, isMarkdown, CodecRegistry, getContentFromDecodedMessageContent, getContentTypeFromDecodedMessageContent, DecodedMessage, AsyncStream, usableProperties, isUsableProperty, wait, DEFAULT_RETRY_DELAY, DEFAULT_RETRY_ATTEMPTS, createStream, Conversation, Dm, Group, Conversations, DebugInformation, Preferences, networkOptionKeys, hasBackend, resolveBackend$1, createClient, resolveBackend, createEphemeralIdentifier, toInboxUpdatesCountMap, Client;
43655
+ var import_node_bindings, import_node_bindings2, import_node_crypto10, import_types, import_node_path26, import_node_process, HistorySyncUrls, envMap, reverseEnvMap, envToString, createBackend, InboxReassignError, AccountAlreadyAssociatedError, MissingContentTypeError, SignerUnavailableError, ClientNotInitializedError, StreamFailedError, StreamInvalidRetryAttemptsError, generateInboxId, getInboxIdForIdentifier, isReaction, isReply, isText, isRemoteAttachment, isAttachment, isMultiRemoteAttachment, isTransactionReference, isGroupUpdated, isReadReceipt, isLeaveRequest, isWalletSendCalls, isIntent, isActions, isMarkdown, CodecRegistry, getContentFromDecodedMessageContent, getContentTypeFromDecodedMessageContent, DecodedMessage, AsyncStream, usableProperties, isUsableProperty, wait, DEFAULT_RETRY_DELAY, DEFAULT_RETRY_ATTEMPTS, createStream, Conversation, Dm, Group, Conversations, DebugInformation, Preferences, networkOptionKeys, hasBackend, resolveBackend$1, createClient, resolveBackend, createEphemeralIdentifier, toInboxUpdatesCountMap, Client;
42911
43656
  var init_dist2 = __esm({
42912
43657
  "../../node_modules/@xmtp/node-sdk/dist/index.js"() {
42913
43658
  import_node_bindings = require("@xmtp/node-bindings");
42914
43659
  import_node_bindings2 = require("@xmtp/node-bindings");
42915
- import_node_crypto9 = require("node:crypto");
43660
+ import_node_crypto10 = require("node:crypto");
42916
43661
  init_dist();
42917
43662
  import_types = require("node:util/types");
42918
43663
  import_node_path26 = require("node:path");
@@ -44596,7 +45341,7 @@ var init_dist2 = __esm({
44596
45341
  return createBackend({ env: envOrBackend, gatewayHost });
44597
45342
  };
44598
45343
  createEphemeralIdentifier = () => ({
44599
- identifier: `0x${(0, import_node_crypto9.randomBytes)(20).toString("hex")}`,
45344
+ identifier: `0x${(0, import_node_crypto10.randomBytes)(20).toString("hex")}`,
44600
45345
  identifierKind: 0
44601
45346
  });
44602
45347
  toInboxUpdatesCountMap = (value) => {
@@ -56845,20 +57590,20 @@ async function createRemoteAttachmentFromFile(unencryptedFile, uploadCallback) {
56845
57590
  const fileUrl = await uploadCallback(encryptedAttachment);
56846
57591
  return createRemoteAttachment(encryptedAttachment, fileUrl);
56847
57592
  }
56848
- var import_node_events, import_node_fs23, import_node_path27, import_ts_retry_promise, import_node_crypto10, version2, fromSelf, hasContent, isDM, isGroup, isGroupAdmin, isGroupSuperAdmin, usesCodec, filter, validLogLevels, isLogLevel, getValidLogLevels, parseLogLevel, logDetails, getInstallationInfo, createUser, createIdentifier, createSigner, AgentError, AgentStreamingError, ClientContext, ConversationContext, MessageContext, Agent, CANCEL_ACTION_ID, LimitedMap, cache;
57593
+ var import_node_events, import_node_fs24, import_node_path27, import_ts_retry_promise, import_node_crypto11, version2, fromSelf, hasContent, isDM, isGroup, isGroupAdmin, isGroupSuperAdmin, usesCodec, filter, validLogLevels, isLogLevel, getValidLogLevels, parseLogLevel, logDetails, getInstallationInfo, createUser, createIdentifier, createSigner, AgentError, AgentStreamingError, ClientContext, ConversationContext, MessageContext, Agent, CANCEL_ACTION_ID, LimitedMap, cache;
56849
57594
  var init_dist4 = __esm({
56850
57595
  "../../node_modules/@xmtp/agent-sdk/dist/index.js"() {
56851
57596
  init_dist2();
56852
57597
  init_dist2();
56853
57598
  import_node_events = __toESM(require("node:events"), 1);
56854
- import_node_fs23 = __toESM(require("node:fs"), 1);
57599
+ import_node_fs24 = __toESM(require("node:fs"), 1);
56855
57600
  import_node_path27 = __toESM(require("node:path"), 1);
56856
57601
  import_ts_retry_promise = __toESM(require_retry_promise(), 1);
56857
57602
  init_dist3();
56858
57603
  init_esm();
56859
57604
  init_accounts();
56860
57605
  init_chains();
56861
- import_node_crypto10 = require("node:crypto");
57606
+ import_node_crypto11 = require("node:crypto");
56862
57607
  version2 = "2.3.0";
56863
57608
  fromSelf = (message, client) => {
56864
57609
  return message.senderInboxId === client.inboxId;
@@ -57218,7 +57963,7 @@ var init_dist4 = __esm({
57218
57963
  initializedOptions.gatewayHost = XMTP_GATEWAY_HOST;
57219
57964
  }
57220
57965
  if (typeof XMTP_DB_DIRECTORY === "string") {
57221
- import_node_fs23.default.mkdirSync(XMTP_DB_DIRECTORY, { recursive: true, mode: 448 });
57966
+ import_node_fs24.default.mkdirSync(XMTP_DB_DIRECTORY, { recursive: true, mode: 448 });
57222
57967
  initializedOptions.dbPath = (inboxId) => {
57223
57968
  const dbPath = import_node_path27.default.join(XMTP_DB_DIRECTORY, `xmtp-${inboxId}.db3`);
57224
57969
  console.info(`Saving local database to "${dbPath}"`);
@@ -57528,7 +58273,7 @@ var init_dist4 = __esm({
57528
58273
  return this.#client.accountIdentifier?.identifier;
57529
58274
  }
57530
58275
  };
57531
- CANCEL_ACTION_ID = (0, import_node_crypto10.randomUUID)();
58276
+ CANCEL_ACTION_ID = (0, import_node_crypto11.randomUUID)();
57532
58277
  LimitedMap = class {
57533
58278
  #map = /* @__PURE__ */ new Map();
57534
58279
  #limit;
@@ -58261,6 +59006,169 @@ var init_session_expired = __esm({
58261
59006
  }
58262
59007
  });
58263
59008
 
59009
+ // ../core/src/xmtp-sdk/rate-limit-cooldown.ts
59010
+ function asErrorLike2(value) {
59011
+ return value instanceof Error ? value : void 0;
59012
+ }
59013
+ function causeChain2(err2) {
59014
+ const chain = [];
59015
+ const seen = /* @__PURE__ */ new Set();
59016
+ let current = err2;
59017
+ while (chain.length < MAX_CAUSE_DEPTH2) {
59018
+ chain.push(current);
59019
+ const errorLike = asErrorLike2(current);
59020
+ if (!errorLike || seen.has(errorLike)) {
59021
+ break;
59022
+ }
59023
+ seen.add(errorLike);
59024
+ current = errorLike.cause;
59025
+ if (current === void 0) {
59026
+ break;
59027
+ }
59028
+ }
59029
+ return chain;
59030
+ }
59031
+ function messageOf(node) {
59032
+ return (node instanceof Error ? node.message : String(node)).toLowerCase();
59033
+ }
59034
+ function isXmtpRateLimitError(err2) {
59035
+ if (err2 === void 0 || err2 === null) {
59036
+ return false;
59037
+ }
59038
+ const chain = causeChain2(err2);
59039
+ return chain.some(
59040
+ (node) => RATE_LIMIT_PATTERNS.some((pattern) => pattern.test(messageOf(node)))
59041
+ );
59042
+ }
59043
+ function extractRateLimitEndpoint(err2) {
59044
+ if (err2 === void 0 || err2 === null) {
59045
+ return void 0;
59046
+ }
59047
+ const chain = causeChain2(err2);
59048
+ for (const node of chain) {
59049
+ const message = messageOf(node);
59050
+ for (const pattern of KNOWN_RATE_LIMIT_ENDPOINTS) {
59051
+ const match = pattern.exec(message);
59052
+ if (match) {
59053
+ return /GetInboxIds/i.test(match[0]) ? "GetInboxIds" : "GetIdentityUpdates";
59054
+ }
59055
+ }
59056
+ }
59057
+ return void 0;
59058
+ }
59059
+ function getXmtpCreationCooldown() {
59060
+ if (!singleton2) {
59061
+ singleton2 = new XmtpCreationCooldown();
59062
+ }
59063
+ return singleton2;
59064
+ }
59065
+ var MAX_CAUSE_DEPTH2, XMTP_CREATION_COOLDOWN_MS, RATE_LIMIT_PATTERNS, KNOWN_RATE_LIMIT_ENDPOINTS, XmtpCreationCooldownSkipError, XmtpCreationCooldown, singleton2;
59066
+ var init_rate_limit_cooldown = __esm({
59067
+ "../core/src/xmtp-sdk/rate-limit-cooldown.ts"() {
59068
+ "use strict";
59069
+ MAX_CAUSE_DEPTH2 = 4;
59070
+ XMTP_CREATION_COOLDOWN_MS = 33e4;
59071
+ RATE_LIMIT_PATTERNS = [
59072
+ /some resource has been exhausted/i,
59073
+ /exceeds rate limit/i,
59074
+ /resource_exhausted/i
59075
+ ];
59076
+ KNOWN_RATE_LIMIT_ENDPOINTS = [
59077
+ /\bGetInboxIds\b/i,
59078
+ /\bGetIdentityUpdates\b/i
59079
+ ];
59080
+ XmtpCreationCooldownSkipError = class extends Error {
59081
+ remainingMs;
59082
+ address;
59083
+ agentId;
59084
+ constructor(remainingMs, address, agentId) {
59085
+ super("xmtp creation suppressed during rate-limit cooldown");
59086
+ this.name = "XmtpCreationCooldownSkipError";
59087
+ this.remainingMs = remainingMs;
59088
+ this.address = address;
59089
+ this.agentId = agentId;
59090
+ }
59091
+ };
59092
+ XmtpCreationCooldown = class {
59093
+ cooldownUntilMs = null;
59094
+ probeInFlight = false;
59095
+ suppressedCreateCount = 0;
59096
+ rateLimitHitCount = 0;
59097
+ probeCount = 0;
59098
+ inFlightCreateCount = 0;
59099
+ beginCreateAttempt(nowMs = Date.now()) {
59100
+ if (this.cooldownUntilMs === null) {
59101
+ this.inFlightCreateCount++;
59102
+ return { allowed: true, mode: "normal" };
59103
+ }
59104
+ if (nowMs < this.cooldownUntilMs) {
59105
+ this.suppressedCreateCount++;
59106
+ return {
59107
+ allowed: false,
59108
+ mode: "blocked",
59109
+ remainingMs: Math.max(0, this.cooldownUntilMs - nowMs)
59110
+ };
59111
+ }
59112
+ if (this.probeInFlight) {
59113
+ this.suppressedCreateCount++;
59114
+ return { allowed: false, mode: "blocked", remainingMs: 0 };
59115
+ }
59116
+ this.probeInFlight = true;
59117
+ this.inFlightCreateCount++;
59118
+ this.probeCount++;
59119
+ return { allowed: true, mode: "probe" };
59120
+ }
59121
+ recordCreateSuccess(decision, _nowMs = Date.now()) {
59122
+ this.inFlightCreateCount = Math.max(0, this.inFlightCreateCount - 1);
59123
+ if (decision.mode === "probe") {
59124
+ this.cooldownUntilMs = null;
59125
+ this.probeInFlight = false;
59126
+ }
59127
+ }
59128
+ recordRateLimit(decision, nowMs = Date.now()) {
59129
+ this.inFlightCreateCount = Math.max(0, this.inFlightCreateCount - 1);
59130
+ this.cooldownUntilMs = nowMs + XMTP_CREATION_COOLDOWN_MS;
59131
+ this.rateLimitHitCount++;
59132
+ this.probeInFlight = false;
59133
+ void decision;
59134
+ }
59135
+ recordCreateFailure(decision, nowMs = Date.now()) {
59136
+ this.inFlightCreateCount = Math.max(0, this.inFlightCreateCount - 1);
59137
+ if (decision.mode === "probe") {
59138
+ this.cooldownUntilMs = nowMs + XMTP_CREATION_COOLDOWN_MS;
59139
+ this.probeInFlight = false;
59140
+ }
59141
+ }
59142
+ isCoolingDown(nowMs = Date.now()) {
59143
+ return this.cooldownUntilMs !== null && nowMs < this.cooldownUntilMs;
59144
+ }
59145
+ remainingMs(nowMs = Date.now()) {
59146
+ return this.cooldownUntilMs === null ? 0 : Math.max(0, this.cooldownUntilMs - nowMs);
59147
+ }
59148
+ snapshot(nowMs = Date.now()) {
59149
+ return {
59150
+ coolingDown: this.isCoolingDown(nowMs),
59151
+ cooldownUntilMs: this.cooldownUntilMs,
59152
+ remainingMs: this.remainingMs(nowMs),
59153
+ probeInFlight: this.probeInFlight,
59154
+ suppressedCreateCount: this.suppressedCreateCount,
59155
+ rateLimitHitCount: this.rateLimitHitCount,
59156
+ probeCount: this.probeCount,
59157
+ inFlightCreateCount: this.inFlightCreateCount
59158
+ };
59159
+ }
59160
+ resetForTests() {
59161
+ this.cooldownUntilMs = null;
59162
+ this.probeInFlight = false;
59163
+ this.suppressedCreateCount = 0;
59164
+ this.rateLimitHitCount = 0;
59165
+ this.probeCount = 0;
59166
+ this.inFlightCreateCount = 0;
59167
+ }
59168
+ };
59169
+ }
59170
+ });
59171
+
58264
59172
  // ../core/src/xmtp-sdk/index.ts
58265
59173
  function cachePath(dataDir, fileName) {
58266
59174
  return (0, import_node_path28.join)(dataDir, fileName);
@@ -58291,10 +59199,10 @@ function ensureCacheDir(dataDir) {
58291
59199
  function loadSensitiveWordsFromCache(dataDir) {
58292
59200
  try {
58293
59201
  const path2 = cachePath(dataDir, "sensitive-words.json");
58294
- if (!(0, import_node_fs24.existsSync)(path2)) {
59202
+ if (!(0, import_node_fs25.existsSync)(path2)) {
58295
59203
  return null;
58296
59204
  }
58297
- const data = JSON.parse((0, import_node_fs24.readFileSync)(path2, "utf-8"));
59205
+ const data = JSON.parse((0, import_node_fs25.readFileSync)(path2, "utf-8"));
58298
59206
  if (Array.isArray(data)) {
58299
59207
  return data;
58300
59208
  }
@@ -58308,7 +59216,7 @@ function loadSensitiveWordsFromCache(dataDir) {
58308
59216
  function saveSensitiveWordsToCache(dataDir, words) {
58309
59217
  try {
58310
59218
  ensureCacheDir(dataDir);
58311
- (0, import_node_fs24.writeFileSync)(cachePath(dataDir, "sensitive-words.json"), JSON.stringify(words));
59219
+ (0, import_node_fs25.writeFileSync)(cachePath(dataDir, "sensitive-words.json"), JSON.stringify(words));
58312
59220
  } catch (err2) {
58313
59221
  logWithTimestamp(`[xmtp-sdk] failed to write sensitive-words.json:`, err2);
58314
59222
  logger.error(LogEvent.CACHE_WRITE_FAILED, err2 instanceof Error ? err2 : new Error(String(err2)), { cacheName: "sensitive-words" });
@@ -58350,10 +59258,10 @@ async function loadSensitiveWordsWith(dataDir, fetcher) {
58350
59258
  function loadSystemConfigFromCache(dataDir) {
58351
59259
  try {
58352
59260
  const path2 = cachePath(dataDir, "system-config.json");
58353
- if (!(0, import_node_fs24.existsSync)(path2)) {
59261
+ if (!(0, import_node_fs25.existsSync)(path2)) {
58354
59262
  return null;
58355
59263
  }
58356
- const data = JSON.parse((0, import_node_fs24.readFileSync)(path2, "utf-8"));
59264
+ const data = JSON.parse((0, import_node_fs25.readFileSync)(path2, "utf-8"));
58357
59265
  if (data && typeof data === "object" && !Array.isArray(data)) {
58358
59266
  return data;
58359
59267
  }
@@ -58367,7 +59275,7 @@ function loadSystemConfigFromCache(dataDir) {
58367
59275
  function saveSystemConfigToCache(dataDir, config) {
58368
59276
  try {
58369
59277
  ensureCacheDir(dataDir);
58370
- (0, import_node_fs24.writeFileSync)(cachePath(dataDir, "system-config.json"), JSON.stringify(config));
59278
+ (0, import_node_fs25.writeFileSync)(cachePath(dataDir, "system-config.json"), JSON.stringify(config));
58371
59279
  } catch (err2) {
58372
59280
  logWithTimestamp(`[xmtp-sdk] failed to write system-config.json:`, err2);
58373
59281
  logger.error(LogEvent.CACHE_WRITE_FAILED, err2 instanceof Error ? err2 : new Error(String(err2)), { cacheName: "system-config" });
@@ -58417,10 +59325,10 @@ function loadSyncByAddress(dataDir) {
58417
59325
  const map = /* @__PURE__ */ new Map();
58418
59326
  try {
58419
59327
  const path2 = cachePath(dataDir, "last-sync.json");
58420
- if (!(0, import_node_fs24.existsSync)(path2)) {
59328
+ if (!(0, import_node_fs25.existsSync)(path2)) {
58421
59329
  return map;
58422
59330
  }
58423
- const data = JSON.parse((0, import_node_fs24.readFileSync)(path2, "utf-8"));
59331
+ const data = JSON.parse((0, import_node_fs25.readFileSync)(path2, "utf-8"));
58424
59332
  const obj = data?.syncByAddress;
58425
59333
  if (obj && typeof obj === "object" && !Array.isArray(obj)) {
58426
59334
  for (const [addr, ts] of Object.entries(obj)) {
@@ -58439,9 +59347,9 @@ function saveSyncForAddress(dataDir, address, timestampMs) {
58439
59347
  try {
58440
59348
  let data = {};
58441
59349
  const path2 = cachePath(dataDir, "last-sync.json");
58442
- if ((0, import_node_fs24.existsSync)(path2)) {
59350
+ if ((0, import_node_fs25.existsSync)(path2)) {
58443
59351
  try {
58444
- const raw = JSON.parse((0, import_node_fs24.readFileSync)(path2, "utf-8"));
59352
+ const raw = JSON.parse((0, import_node_fs25.readFileSync)(path2, "utf-8"));
58445
59353
  if (raw && typeof raw === "object" && !Array.isArray(raw)) {
58446
59354
  data = raw;
58447
59355
  }
@@ -58452,7 +59360,7 @@ function saveSyncForAddress(dataDir, address, timestampMs) {
58452
59360
  data.syncByAddress = {};
58453
59361
  }
58454
59362
  data.syncByAddress[address] = timestampMs;
58455
- (0, import_node_fs24.writeFileSync)(path2, JSON.stringify(data, null, 2));
59363
+ (0, import_node_fs25.writeFileSync)(path2, JSON.stringify(data, null, 2));
58456
59364
  } catch (err2) {
58457
59365
  logWithTimestamp(
58458
59366
  `[xmtp-sdk] failed to write last-sync.json (address=${address}):`,
@@ -58671,12 +59579,12 @@ function createOfflineReplayAddressSummary(address) {
58671
59579
  durationMs: 0
58672
59580
  };
58673
59581
  }
58674
- var import_node_fs24, import_node_path28, DEFAULT_DATA_DIR, XMTP_INSTALLATION_WARNING_THRESHOLD, XMTP_INSTALLATION_NEAR_LIMIT_THRESHOLD, REPLAY_SCAN_INITIAL_BACKOFF_MS, REPLAY_SCAN_MAX_BACKOFF_MS, SENSITIVE_WORDS_LAZY_RETRY_COOLDOWN_MS, InboundReplayGate, SYSTEM_CONFIG_DEFAULTS, STREAM_RECOVERY_ALERT_THRESHOLD_MS, STREAM_RECOVERY_STABILITY_WINDOW_MS, REPLAY_GATE_DRAIN_MAX_ATTEMPTS, REPLAY_GATE_DRAIN_RETRY_DELAY_MS, SEMVER_RE, isRecord5, isPositiveNumber, SYSTEM_CONFIG_VALIDATORS, XmtpService;
59582
+ var import_node_fs25, import_node_path28, DEFAULT_DATA_DIR, XMTP_INSTALLATION_WARNING_THRESHOLD, XMTP_INSTALLATION_NEAR_LIMIT_THRESHOLD, REPLAY_SCAN_INITIAL_BACKOFF_MS, REPLAY_SCAN_MAX_BACKOFF_MS, SENSITIVE_WORDS_LAZY_RETRY_COOLDOWN_MS, InboundReplayGate, SYSTEM_CONFIG_DEFAULTS, STREAM_RECOVERY_ALERT_THRESHOLD_MS, STREAM_RECOVERY_STABILITY_WINDOW_MS, REPLAY_GATE_DRAIN_MAX_ATTEMPTS, REPLAY_GATE_DRAIN_RETRY_DELAY_MS, SEMVER_RE, isRecord5, isPositiveNumber, SYSTEM_CONFIG_VALIDATORS, XmtpService;
58675
59583
  var init_xmtp_sdk = __esm({
58676
59584
  "../core/src/xmtp-sdk/index.ts"() {
58677
59585
  "use strict";
58678
59586
  init_log();
58679
- import_node_fs24 = require("node:fs");
59587
+ import_node_fs25 = require("node:fs");
58680
59588
  import_node_path28 = require("node:path");
58681
59589
  init_dist4();
58682
59590
  init_dist2();
@@ -58690,6 +59598,8 @@ var init_xmtp_sdk = __esm({
58690
59598
  init_a2a_paths();
58691
59599
  init_installation_prune();
58692
59600
  init_session_expired();
59601
+ init_rate_limit_cooldown();
59602
+ init_client_lifecycle();
58693
59603
  DEFAULT_DATA_DIR = resolveA2aTaskPaths().xmtpDir;
58694
59604
  XMTP_INSTALLATION_WARNING_THRESHOLD = 2;
58695
59605
  XMTP_INSTALLATION_NEAR_LIMIT_THRESHOLD = 8;
@@ -58987,21 +59897,78 @@ var init_xmtp_sdk = __esm({
58987
59897
  }
58988
59898
  async createClientForAgent(agentInfo, options = {}) {
58989
59899
  const address = agentInfo.communicationAddress;
58990
- const signer = this.tools.createSigner(agentInfo);
58991
- const dbPath = (inboxId2) => `${this.dataDir}/${inboxId2}-${this.env}.db3`;
58992
- const agent = await createAgentWithInstallationPrune(signer, {
58993
- dbPath,
58994
- env: this.env
58995
- }, {
58996
- address,
58997
- agentId: agentInfo.agentId,
58998
- logPrefix: options.logPrefix
58999
- });
59000
- const inboxId = agent.client?.inboxId ?? "";
59001
- logWithTimestamp(
59002
- `[xmtp-sdk] xmtp_client_ready agentId=${agentInfo.agentId} address=${address} inboxId=${inboxId} dbPath=${inboxId ? dbPath(inboxId) : "(unknown)"} lastSync=${formatLogTimestamp2(this.syncByAddress.get(address))}`
59003
- );
59004
- return { address, agent, agentInfo };
59900
+ const phase = options.logPrefix ?? "[xmtp-sdk]";
59901
+ const cooldown = getXmtpCreationCooldown();
59902
+ const decision = cooldown.beginCreateAttempt();
59903
+ if (!decision.allowed) {
59904
+ logger.info(LogEvent.XMTP_RATE_LIMIT_CREATE_SUPPRESSED, {
59905
+ onchainosAgentId: agentInfo.agentId,
59906
+ walletAddress: address,
59907
+ cooldownRemainingMs: String(decision.remainingMs ?? 0),
59908
+ phase
59909
+ });
59910
+ throw new XmtpCreationCooldownSkipError(
59911
+ decision.remainingMs ?? 0,
59912
+ address,
59913
+ agentInfo.agentId
59914
+ );
59915
+ }
59916
+ if (decision.mode === "probe") {
59917
+ logger.info(LogEvent.XMTP_RATE_LIMIT_PROBE, {
59918
+ onchainosAgentId: agentInfo.agentId,
59919
+ walletAddress: address,
59920
+ phase: "probe-start",
59921
+ probeCount: String(cooldown.snapshot().probeCount)
59922
+ });
59923
+ }
59924
+ try {
59925
+ const signer = this.tools.createSigner(agentInfo);
59926
+ const dbPath = (inboxId2) => `${this.dataDir}/${inboxId2}-${this.env}.db3`;
59927
+ const agent = await createAgentWithInstallationPrune(signer, {
59928
+ dbPath,
59929
+ env: this.env
59930
+ }, {
59931
+ address,
59932
+ agentId: agentInfo.agentId,
59933
+ logPrefix: options.logPrefix
59934
+ });
59935
+ cooldown.recordCreateSuccess(decision);
59936
+ if (decision.mode === "probe") {
59937
+ logger.info(LogEvent.XMTP_RATE_LIMIT_RECOVERED, {
59938
+ onchainosAgentId: agentInfo.agentId,
59939
+ walletAddress: address,
59940
+ phase: "probe-success"
59941
+ });
59942
+ }
59943
+ const inboxId = agent.client?.inboxId ?? "";
59944
+ logWithTimestamp(
59945
+ `[xmtp-sdk] xmtp_client_ready agentId=${agentInfo.agentId} address=${address} inboxId=${inboxId} dbPath=${inboxId ? dbPath(inboxId) : "(unknown)"} lastSync=${formatLogTimestamp2(this.syncByAddress.get(address))}`
59946
+ );
59947
+ return { address, agent, agentInfo };
59948
+ } catch (err2) {
59949
+ if (isXmtpRateLimitError(err2)) {
59950
+ cooldown.recordRateLimit(decision);
59951
+ logger.info(LogEvent.XMTP_RATE_LIMIT_COOLDOWN_STARTED, {
59952
+ ...agentExtras({ walletAddress: address, onchainosAgentId: agentInfo.agentId }),
59953
+ rateLimitIdentified: "true",
59954
+ endpoint: extractRateLimitEndpoint(err2) ?? "unknown",
59955
+ cooldownMs: String(XMTP_CREATION_COOLDOWN_MS),
59956
+ cooldownExpiresAtMs: String(cooldown.snapshot().cooldownUntilMs ?? ""),
59957
+ inFlightCreateCount: String(cooldown.snapshot().inFlightCreateCount),
59958
+ probe: String(decision.mode === "probe")
59959
+ });
59960
+ } else {
59961
+ cooldown.recordCreateFailure(decision);
59962
+ if (decision.mode === "probe") {
59963
+ logger.info(LogEvent.XMTP_RATE_LIMIT_PROBE, {
59964
+ onchainosAgentId: agentInfo.agentId,
59965
+ walletAddress: address,
59966
+ phase: "probe-failed-nonratelimit"
59967
+ });
59968
+ }
59969
+ }
59970
+ throw err2;
59971
+ }
59005
59972
  }
59006
59973
  async recordInstallationHealth(params) {
59007
59974
  const { address, agent, agentInfo, phase, attempt } = params;
@@ -59152,22 +60119,28 @@ var init_xmtp_sdk = __esm({
59152
60119
  });
59153
60120
  } else {
59154
60121
  failedAgents.push(agents[i]);
59155
- logWithTimestamp(
59156
- `[xmtp-sdk] identity init failed: ${agents[i].communicationAddress} (agentId=${agents[i].agentId})`,
59157
- r.reason
59158
- );
59159
- logger.error(
59160
- LogEvent.XMTP_CONNECTION_FAILED,
59161
- r.reason instanceof Error ? r.reason : new Error(String(r.reason)),
59162
- {
59163
- walletAddress: agents[i].communicationAddress,
59164
- onchainosAgentId: agents[i].agentId,
59165
- attempt: "1"
59166
- }
59167
- );
60122
+ if (r.reason instanceof XmtpCreationCooldownSkipError) {
60123
+ logWithTimestamp(
60124
+ `[xmtp-sdk] identity init suppressed (rate-limit cooldown): ${agents[i].communicationAddress} (agentId=${agents[i].agentId})`
60125
+ );
60126
+ } else {
60127
+ logWithTimestamp(
60128
+ `[xmtp-sdk] identity init failed: ${agents[i].communicationAddress} (agentId=${agents[i].agentId})`,
60129
+ r.reason
60130
+ );
60131
+ logger.error(
60132
+ LogEvent.XMTP_CONNECTION_FAILED,
60133
+ r.reason instanceof Error ? r.reason : new Error(String(r.reason)),
60134
+ {
60135
+ walletAddress: agents[i].communicationAddress,
60136
+ onchainosAgentId: agents[i].agentId,
60137
+ attempt: "1"
60138
+ }
60139
+ );
60140
+ }
59168
60141
  }
59169
60142
  }
59170
- if (failedAgents.length > 0) {
60143
+ if (failedAgents.length > 0 && !getXmtpCreationCooldown().isCoolingDown()) {
59171
60144
  logWithTimestamp(
59172
60145
  `[xmtp-sdk] ${failedAgents.length} client(s) failed to initialize, retrying in 1s...`
59173
60146
  );
@@ -59207,6 +60180,11 @@ var init_xmtp_sdk = __esm({
59207
60180
  phase: "init",
59208
60181
  attempt: "2"
59209
60182
  });
60183
+ } else if (r.reason instanceof XmtpCreationCooldownSkipError) {
60184
+ const info = failedAgents[i];
60185
+ logWithTimestamp(
60186
+ `[xmtp-sdk] retry suppressed (rate-limit cooldown): ${info.communicationAddress} (agentId=${info.agentId})`
60187
+ );
59210
60188
  } else {
59211
60189
  const info = failedAgents[i];
59212
60190
  logWithTimestamp(
@@ -59302,7 +60280,16 @@ var init_xmtp_sdk = __esm({
59302
60280
  try {
59303
60281
  this.cancelStreamRecoveryForAddress(address);
59304
60282
  this.stoppedAddresses.add(address.toLowerCase());
59305
- client.stop();
60283
+ await stopAndCloseXmtpClient(client, {
60284
+ address,
60285
+ agentId: agentInfo.agentId,
60286
+ phase: "refresh/remove",
60287
+ onCloseError: (err2) => logger.error(
60288
+ LogEvent.XMTP_CLIENT_CLOSE_FAILED,
60289
+ err2 instanceof Error ? err2 : new Error(String(err2)),
60290
+ { walletAddress: address, onchainosAgentId: agentInfo.agentId, phase: "refresh/remove" }
60291
+ )
60292
+ });
59306
60293
  logWithTimestamp(
59307
60294
  `[xmtp-sdk] refresh: stopped client: ${address} (agentId=${agentInfo.agentId})`
59308
60295
  );
@@ -59389,23 +60376,29 @@ var init_xmtp_sdk = __esm({
59389
60376
  });
59390
60377
  } else {
59391
60378
  failedAgents.push(added[i]);
59392
- logWithTimestamp(
59393
- `[xmtp-sdk] refresh: identity init failed: ${added[i].communicationAddress} (agentId=${added[i].agentId})`,
59394
- r.reason
59395
- );
59396
- logger.error(
59397
- LogEvent.XMTP_CONNECTION_FAILED,
59398
- r.reason instanceof Error ? r.reason : new Error(String(r.reason)),
59399
- {
59400
- walletAddress: added[i].communicationAddress,
59401
- onchainosAgentId: added[i].agentId,
59402
- phase: "refresh",
59403
- attempt: "1"
59404
- }
59405
- );
60379
+ if (r.reason instanceof XmtpCreationCooldownSkipError) {
60380
+ logWithTimestamp(
60381
+ `[xmtp-sdk] refresh: identity init suppressed (rate-limit cooldown): ${added[i].communicationAddress} (agentId=${added[i].agentId})`
60382
+ );
60383
+ } else {
60384
+ logWithTimestamp(
60385
+ `[xmtp-sdk] refresh: identity init failed: ${added[i].communicationAddress} (agentId=${added[i].agentId})`,
60386
+ r.reason
60387
+ );
60388
+ logger.error(
60389
+ LogEvent.XMTP_CONNECTION_FAILED,
60390
+ r.reason instanceof Error ? r.reason : new Error(String(r.reason)),
60391
+ {
60392
+ walletAddress: added[i].communicationAddress,
60393
+ onchainosAgentId: added[i].agentId,
60394
+ phase: "refresh",
60395
+ attempt: "1"
60396
+ }
60397
+ );
60398
+ }
59406
60399
  }
59407
60400
  }
59408
- if (failedAgents.length > 0) {
60401
+ if (failedAgents.length > 0 && !getXmtpCreationCooldown().isCoolingDown()) {
59409
60402
  logWithTimestamp(
59410
60403
  `[xmtp-sdk] refresh: ${failedAgents.length} client(s) failed to initialize, retrying in 1s...`
59411
60404
  );
@@ -59448,6 +60441,11 @@ var init_xmtp_sdk = __esm({
59448
60441
  phase: "refresh",
59449
60442
  attempt: "2"
59450
60443
  });
60444
+ } else if (r.reason instanceof XmtpCreationCooldownSkipError) {
60445
+ const info = failedAgents[i];
60446
+ logWithTimestamp(
60447
+ `[xmtp-sdk] refresh: retry suppressed (rate-limit cooldown): ${info.communicationAddress} (agentId=${info.agentId})`
60448
+ );
59451
60449
  } else {
59452
60450
  const info = failedAgents[i];
59453
60451
  logWithTimestamp(
@@ -59511,6 +60509,18 @@ var init_xmtp_sdk = __esm({
59511
60509
  async recycleXmtpClients() {
59512
60510
  await this._backupReady;
59513
60511
  const startedAt = Date.now();
60512
+ if (getXmtpCreationCooldown().isCoolingDown()) {
60513
+ logWithTimestamp("[xmtp-sdk] recycle skipped \u2014 rate-limit cooldown active");
60514
+ return {
60515
+ clients: this.clients.size,
60516
+ recycled: 0,
60517
+ failed: 0,
60518
+ replayed: 0,
60519
+ skipped: 0,
60520
+ durationMs: Date.now() - startedAt,
60521
+ addresses: []
60522
+ };
60523
+ }
59514
60524
  const addresses = [];
59515
60525
  let recycled = 0;
59516
60526
  let failed = 0;
@@ -59529,7 +60539,16 @@ var init_xmtp_sdk = __esm({
59529
60539
  try {
59530
60540
  this.cancelStreamRecoveryForAddress(address);
59531
60541
  this.stoppedAddresses.add(addressKey);
59532
- await Promise.resolve(oldClient.stop());
60542
+ await stopAndCloseXmtpClient(oldClient, {
60543
+ address,
60544
+ agentId: agentInfo.agentId,
60545
+ phase: "recycle",
60546
+ onCloseError: (err2) => logger.error(
60547
+ LogEvent.XMTP_CLIENT_CLOSE_FAILED,
60548
+ err2 instanceof Error ? err2 : new Error(String(err2)),
60549
+ { walletAddress: address, onchainosAgentId: agentInfo.agentId, phase: "recycle" }
60550
+ )
60551
+ });
59533
60552
  this.clients.delete(address);
59534
60553
  this.inboundReplayGates.delete(addressKey);
59535
60554
  this.replayScanFailuresByAddress.delete(addressKey);
@@ -59616,6 +60635,12 @@ var init_xmtp_sdk = __esm({
59616
60635
  phase: "recycle/create-client"
59617
60636
  }
59618
60637
  );
60638
+ if (isXmtpRateLimitError(err2)) {
60639
+ logWithTimestamp(
60640
+ "[xmtp-sdk] recycle: rate-limit on recreate \u2014 stopping remaining recycles"
60641
+ );
60642
+ break;
60643
+ }
59619
60644
  }
59620
60645
  }
59621
60646
  return {
@@ -61867,7 +62892,7 @@ var init_envelope = __esm({
61867
62892
  });
61868
62893
 
61869
62894
  // src/invalid-message-store.ts
61870
- function loadSqlite5() {
62895
+ function loadSqlite6() {
61871
62896
  const originalEmitWarning = process.emitWarning;
61872
62897
  process.emitWarning = ((warning, ...args) => {
61873
62898
  const message = typeof warning === "string" ? warning : warning.message;
@@ -61882,22 +62907,22 @@ function loadSqlite5() {
61882
62907
  process.emitWarning = originalEmitWarning;
61883
62908
  }
61884
62909
  }
61885
- var import_node_fs25, import_node_path29, DatabaseSync4, InvalidXmtpMessageStore;
62910
+ var import_node_fs26, import_node_path29, DatabaseSync5, InvalidXmtpMessageStore;
61886
62911
  var init_invalid_message_store = __esm({
61887
62912
  "src/invalid-message-store.ts"() {
61888
62913
  "use strict";
61889
- import_node_fs25 = require("node:fs");
62914
+ import_node_fs26 = require("node:fs");
61890
62915
  import_node_path29 = require("node:path");
61891
62916
  init_paths();
61892
- ({ DatabaseSync: DatabaseSync4 } = loadSqlite5());
62917
+ ({ DatabaseSync: DatabaseSync5 } = loadSqlite6());
61893
62918
  InvalidXmtpMessageStore = class {
61894
62919
  dbPath;
61895
62920
  db;
61896
62921
  constructor(homeDir) {
61897
62922
  const paths = resolveTaskPaths(homeDir);
61898
62923
  this.dbPath = (0, import_node_path29.join)(paths.sqliteDir, "invalid-xmtp-messages.sqlite");
61899
- (0, import_node_fs25.mkdirSync)((0, import_node_path29.dirname)(this.dbPath), { recursive: true });
61900
- this.db = new DatabaseSync4(this.dbPath);
62924
+ (0, import_node_fs26.mkdirSync)((0, import_node_path29.dirname)(this.dbPath), { recursive: true });
62925
+ this.db = new DatabaseSync5(this.dbPath);
61901
62926
  this.ensureReady();
61902
62927
  }
61903
62928
  close() {
@@ -62273,14 +63298,14 @@ function buildSystemMessageIdempotencyKey(input) {
62273
63298
  return `system-message:${identity}`;
62274
63299
  }
62275
63300
  function stableHash(value) {
62276
- return (0, import_node_crypto11.createHash)("sha256").update(value).digest("hex").slice(0, 24);
63301
+ return (0, import_node_crypto12.createHash)("sha256").update(value).digest("hex").slice(0, 24);
62277
63302
  }
62278
- var import_node_crypto11, DIRECTION_PREFIX, CONTENT_SEPARATOR, ADDRESS_SHORT_HEAD, ADDRESS_SHORT_TAIL, JOB_ID_HEAD, JOB_ID_TAIL, ELLIPSIS, CONTENT_MAX_LINES;
63303
+ var import_node_crypto12, DIRECTION_PREFIX, CONTENT_SEPARATOR, ADDRESS_SHORT_HEAD, ADDRESS_SHORT_TAIL, JOB_ID_HEAD, JOB_ID_TAIL, ELLIPSIS, CONTENT_MAX_LINES;
62279
63304
  var init_agent_message_notice = __esm({
62280
63305
  "src/agent-message-notice.ts"() {
62281
63306
  "use strict";
62282
63307
  init_log();
62283
- import_node_crypto11 = require("node:crypto");
63308
+ import_node_crypto12 = require("node:crypto");
62284
63309
  init_session_store();
62285
63310
  init_ai_provider();
62286
63311
  init_outbound_behavior();
@@ -62763,7 +63788,7 @@ async function handleSqliteGroupSendCommand(params) {
62763
63788
  role: senderAgent?.role,
62764
63789
  sendDurationMs: Date.now() - sendStartMs
62765
63790
  });
62766
- const messageId = `outbound-${(0, import_node_crypto12.randomUUID)()}`;
63791
+ const messageId = `outbound-${(0, import_node_crypto13.randomUUID)()}`;
62767
63792
  await notifyAgentMessageToUserAttention({
62768
63793
  direction: "outbound" /* OUTBOUND */,
62769
63794
  sender: {
@@ -62884,7 +63909,7 @@ async function handleGroupSendCommand(params) {
62884
63909
  sendDurationMs: Date.now() - sendStartMs
62885
63910
  });
62886
63911
  const now = Date.now();
62887
- const messageId = `outbound-${(0, import_node_crypto12.randomUUID)()}`;
63912
+ const messageId = `outbound-${(0, import_node_crypto13.randomUUID)()}`;
62888
63913
  const stored = {
62889
63914
  id: messageId,
62890
63915
  direction: "outbound",
@@ -63103,7 +64128,7 @@ async function handleXmtpSendCommand(params) {
63103
64128
  sendDurationMs: Date.now() - sendStartMs
63104
64129
  });
63105
64130
  const now = Date.now();
63106
- const messageId = `outbound-${(0, import_node_crypto12.randomUUID)()}`;
64131
+ const messageId = `outbound-${(0, import_node_crypto13.randomUUID)()}`;
63107
64132
  const stored = {
63108
64133
  id: messageId,
63109
64134
  direction: "outbound",
@@ -63149,14 +64174,14 @@ async function handleXmtpSendCommand(params) {
63149
64174
  ownedStore?.close();
63150
64175
  }
63151
64176
  }
63152
- var import_node_crypto12, TASK_MIN_VERSION, sqliteGroupSessionPromises, conversationSyncPromises, XMTP_SEND_CHECKPOINT, resolvedAgentByIdCache;
64177
+ var import_node_crypto13, TASK_MIN_VERSION, sqliteGroupSessionPromises, conversationSyncPromises, XMTP_SEND_CHECKPOINT, resolvedAgentByIdCache;
63153
64178
  var init_xmtp_send = __esm({
63154
64179
  "src/xmtp-send.ts"() {
63155
64180
  "use strict";
63156
64181
  init_log();
63157
64182
  init_sentry_logger();
63158
64183
  init_log_fields();
63159
- import_node_crypto12 = require("node:crypto");
64184
+ import_node_crypto13 = require("node:crypto");
63160
64185
  init_dist2();
63161
64186
  init_envelope();
63162
64187
  init_concurrency2();
@@ -63695,7 +64720,7 @@ function safeProcessCwd() {
63695
64720
  }
63696
64721
  function isDirectory(path2) {
63697
64722
  try {
63698
- return (0, import_node_fs26.statSync)(path2).isDirectory();
64723
+ return (0, import_node_fs27.statSync)(path2).isDirectory();
63699
64724
  } catch {
63700
64725
  return false;
63701
64726
  }
@@ -65021,7 +66046,7 @@ function normalizeAttentionProvider(provider) {
65021
66046
  return provider === "unknown" ? null : provider;
65022
66047
  }
65023
66048
  function stableHash2(value) {
65024
- return (0, import_node_crypto13.createHash)("sha256").update(value).digest("hex").slice(0, 24);
66049
+ return (0, import_node_crypto14.createHash)("sha256").update(value).digest("hex").slice(0, 24);
65025
66050
  }
65026
66051
  function formatCommand(args) {
65027
66052
  return args.map(shellQuote).join(" ");
@@ -65045,13 +66070,13 @@ function shortenJobId2(jobId) {
65045
66070
  }
65046
66071
  return `${jobId.slice(0, 6)}\u2026${jobId.slice(-4)}`;
65047
66072
  }
65048
- var import_node_crypto13, import_node_fs26, import_promises12, import_node_os9, import_node_path31, AiRunner, CODEX_TOOL_FAILURE_MARKER;
66073
+ var import_node_crypto14, import_node_fs27, import_promises12, import_node_os9, import_node_path31, AiRunner, CODEX_TOOL_FAILURE_MARKER;
65049
66074
  var init_ai_runner = __esm({
65050
66075
  "src/ai-runner.ts"() {
65051
66076
  "use strict";
65052
66077
  init_log();
65053
- import_node_crypto13 = require("node:crypto");
65054
- import_node_fs26 = require("node:fs");
66078
+ import_node_crypto14 = require("node:crypto");
66079
+ import_node_fs27 = require("node:fs");
65055
66080
  import_promises12 = require("node:fs/promises");
65056
66081
  import_node_os9 = require("node:os");
65057
66082
  import_node_path31 = require("node:path");
@@ -65199,7 +66224,7 @@ var init_ai_runner = __esm({
65199
66224
  ensureTaskDir(this.logsDir);
65200
66225
  const lifecycleLogsEnabled = isAiLifecycleLoggingEnabled();
65201
66226
  const logPath = lifecycleLogsEnabled ? this.buildRunLogPath(request) : "";
65202
- const log = lifecycleLogsEnabled ? (0, import_node_fs26.createWriteStream)(logPath, { flags: "a" }) : null;
66227
+ const log = lifecycleLogsEnabled ? (0, import_node_fs27.createWriteStream)(logPath, { flags: "a" }) : null;
65203
66228
  let existing = null;
65204
66229
  let storeReadStartedAt;
65205
66230
  let storeReadEndedAt;
@@ -67671,6 +68696,409 @@ var init_command_processor = __esm({
67671
68696
  }
67672
68697
  });
67673
68698
 
68699
+ // src/devkit-types.ts
68700
+ var DEVKIT_MAX_CONCURRENCY, DEVKIT_MAX_PENDING, DEVKIT_MAX_PENDING_BYTES, DEVKIT_MAX_MESSAGE_BYTES, DEVKIT_REQUEST_BUDGET_MS, DEVKIT_RESPONSE_DIAGNOSTIC_MAX_BYTES, DEVKIT_RESPONSE_SUMMARY_MAX_CHARS, DEVKIT_OUTCOME, DEVKIT_DROP_REASON;
68701
+ var init_devkit_types = __esm({
68702
+ "src/devkit-types.ts"() {
68703
+ "use strict";
68704
+ DEVKIT_MAX_CONCURRENCY = 16;
68705
+ DEVKIT_MAX_PENDING = 256;
68706
+ DEVKIT_MAX_PENDING_BYTES = 16 * 1024 * 1024;
68707
+ DEVKIT_MAX_MESSAGE_BYTES = 1 * 1024 * 1024;
68708
+ DEVKIT_REQUEST_BUDGET_MS = 5e3;
68709
+ DEVKIT_RESPONSE_DIAGNOSTIC_MAX_BYTES = 4 * 1024;
68710
+ DEVKIT_RESPONSE_SUMMARY_MAX_CHARS = 256;
68711
+ DEVKIT_OUTCOME = {
68712
+ HTTP_ACCEPTED: "http_accepted",
68713
+ DROPPED: "dropped"
68714
+ };
68715
+ DEVKIT_DROP_REASON = {
68716
+ REQUEST_TOO_LARGE: "request_too_large",
68717
+ // serialized > 1 MiB (FR-3-AC-6)
68718
+ PENDING_OVERFLOW: "pending_overflow",
68719
+ // > 256 items or > 16 MiB total pending (NFR-2-AC-1)
68720
+ CONFIG_CHANGED: "config_changed",
68721
+ // snapshot version changed/removed before send (FR-2-AC-6)
68722
+ CONFIG_READ_FAILED: "config_read_failed",
68723
+ // snapshot unreadable/corrupt (FR-2-AC-5)
68724
+ HTTP_STATUS: "http_status",
68725
+ // non-2xx response (FR-3-AC-3)
68726
+ REDIRECT_BLOCKED: "redirect_blocked",
68727
+ // 3xx response, not followed (NFR-3-AC-2)
68728
+ CONNECTION_FAILED: "connection_failed",
68729
+ // ECONNREFUSED / reset / unreachable (FR-3-AC-4)
68730
+ TIMEOUT: "timeout",
68731
+ // exceeded the 5 s budget (FR-3-AC-4)
68732
+ REQUEST_BUILD_ERROR: "request_build_error",
68733
+ // serialization / target build failure
68734
+ RESPONSE_READ_ERROR: "response_read_error",
68735
+ // diagnostic read failure
68736
+ SHUTDOWN_CANCELLED: "shutdown_cancelled"
68737
+ // daemon stopped before send (NFR-2-AC-3)
68738
+ };
68739
+ }
68740
+ });
68741
+
68742
+ // src/devkit-delivery.ts
68743
+ function fallbackDeliveryId(parts) {
68744
+ return `devkit-${parts.jobId ?? "none"}-${parts.sessionKey ?? "none"}-${parts.receivedAt}`;
68745
+ }
68746
+ function buildSessionEnvelope(ev, ctx = {}) {
68747
+ const now = ctx.now ?? Date.now;
68748
+ const receivedAt = Math.floor(now() / 1e3);
68749
+ const jobId = ev.jobId ?? null;
68750
+ const agentId = ev.agentId ?? null;
68751
+ const deliveryId = ev.messageId ?? fallbackDeliveryId({ jobId, sessionKey: ev.sessionKey, receivedAt });
68752
+ const messageId = ev.messageId ?? deliveryId;
68753
+ return {
68754
+ deliveryId,
68755
+ receivedAt,
68756
+ kind: "session",
68757
+ agentId,
68758
+ event: {
68759
+ sessionKey: ev.sessionKey,
68760
+ content: ev.content,
68761
+ messageId,
68762
+ jobId,
68763
+ agentId
68764
+ }
68765
+ };
68766
+ }
68767
+ function buildJobEnvelope(ev, _ctx = {}) {
68768
+ const sessionAgentId = ev.sessionAgentId ?? null;
68769
+ const receivedAt = Math.floor(ev.message.receivedAtMs / 1e3);
68770
+ return {
68771
+ deliveryId: ev.message.id,
68772
+ receivedAt,
68773
+ kind: "job",
68774
+ agentId: sessionAgentId,
68775
+ event: {
68776
+ jobId: ev.jobId,
68777
+ sessionAgentId,
68778
+ message: {
68779
+ ...ev.message,
68780
+ content: ev.message.rawText
68781
+ }
68782
+ }
68783
+ };
68784
+ }
68785
+ function classifyHttpOutcome(status) {
68786
+ if (status >= 200 && status < 300) {
68787
+ return { outcome: DEVKIT_OUTCOME.HTTP_ACCEPTED };
68788
+ }
68789
+ if (status >= 300 && status < 400) {
68790
+ return { outcome: DEVKIT_OUTCOME.DROPPED, reason: DEVKIT_DROP_REASON.REDIRECT_BLOCKED };
68791
+ }
68792
+ return { outcome: DEVKIT_OUTCOME.DROPPED, reason: DEVKIT_DROP_REASON.HTTP_STATUS };
68793
+ }
68794
+ function classifyFetchFailure(params) {
68795
+ if (params.cancelledByShutdown) {
68796
+ return DEVKIT_DROP_REASON.SHUTDOWN_CANCELLED;
68797
+ }
68798
+ if (params.timedOut || params.errorCategory === "timeout") {
68799
+ return DEVKIT_DROP_REASON.TIMEOUT;
68800
+ }
68801
+ return DEVKIT_DROP_REASON.CONNECTION_FAILED;
68802
+ }
68803
+ function redactSummary(raw) {
68804
+ const collapsed = raw.replace(/\s+/g, " ").trim();
68805
+ const redacted = collapsed.replace(SECRET_SCHEME_PATTERN, "[REDACTED]").replace(
68806
+ SECRET_KV_PATTERN,
68807
+ (_match, keyQuote, key, keyQuoteClose, sep4) => `${keyQuote}${key}${keyQuoteClose}${sep4}[REDACTED]`
68808
+ );
68809
+ const truncated = redacted.length > DEVKIT_RESPONSE_SUMMARY_MAX_CHARS;
68810
+ return { text: redacted.slice(0, DEVKIT_RESPONSE_SUMMARY_MAX_CHARS), truncated };
68811
+ }
68812
+ async function readRedactedResponse(response) {
68813
+ let bodyText;
68814
+ try {
68815
+ bodyText = await response.text();
68816
+ } catch {
68817
+ return { responseBytesRead: 0, responseTruncated: false, responseSummary: "" };
68818
+ }
68819
+ const bytes = Buffer.from(bodyText, "utf8");
68820
+ const diagnosticSlice = bytes.subarray(0, DEVKIT_RESPONSE_DIAGNOSTIC_MAX_BYTES);
68821
+ const sliceTruncated = bytes.byteLength > DEVKIT_RESPONSE_DIAGNOSTIC_MAX_BYTES;
68822
+ const summary = redactSummary(diagnosticSlice.toString("utf8"));
68823
+ return {
68824
+ responseBytesRead: diagnosticSlice.byteLength,
68825
+ responseTruncated: sliceTruncated || summary.truncated,
68826
+ responseSummary: summary.text
68827
+ };
68828
+ }
68829
+ async function isLoopbackTarget(origin) {
68830
+ let hostname;
68831
+ try {
68832
+ hostname = new URL(origin).hostname;
68833
+ } catch {
68834
+ return false;
68835
+ }
68836
+ const version3 = (0, import_node_net2.isIP)(hostname);
68837
+ if (version3 === 4) {
68838
+ return hostname.startsWith("127.");
68839
+ }
68840
+ if (version3 === 6) {
68841
+ return hostname === "::1";
68842
+ }
68843
+ if (hostname.toLowerCase() !== "localhost") {
68844
+ return false;
68845
+ }
68846
+ try {
68847
+ const resolved = await (0, import_promises13.lookup)(hostname);
68848
+ return resolved.family === 4 ? resolved.address.startsWith("127.") : resolved.address === "::1";
68849
+ } catch {
68850
+ return false;
68851
+ }
68852
+ }
68853
+ function orderingKeyFor(envelope) {
68854
+ if (envelope.kind === "session") {
68855
+ return `session:${envelope.event.sessionKey}`;
68856
+ }
68857
+ return `job:${envelope.event.jobId}`;
68858
+ }
68859
+ function sleep4(ms) {
68860
+ return new Promise((resolve14) => setTimeout(resolve14, Math.max(0, ms)));
68861
+ }
68862
+ var import_node_net2, import_promises13, COMPONENT, SECRET_KEYS, SECRET_SCHEME_PATTERN, SECRET_KV_PATTERN, DevkitDeliveryDispatcher;
68863
+ var init_devkit_delivery = __esm({
68864
+ "src/devkit-delivery.ts"() {
68865
+ "use strict";
68866
+ import_node_net2 = require("node:net");
68867
+ import_promises13 = require("node:dns/promises");
68868
+ init_sentry_logger();
68869
+ init_error_diagnostics();
68870
+ init_devkit_types();
68871
+ COMPONENT = "node_devkit";
68872
+ SECRET_KEYS = "authorization|bearer|basic|jwt|password|api[_-]?key|secret|token";
68873
+ SECRET_SCHEME_PATTERN = new RegExp(`\\b(?:${SECRET_KEYS})\\s+\\S+`, "gi");
68874
+ SECRET_KV_PATTERN = new RegExp(
68875
+ `("?)(${SECRET_KEYS})("?)\\s*([:=])\\s*"?[^"\\s,}]+`,
68876
+ "gi"
68877
+ );
68878
+ DevkitDeliveryDispatcher = class {
68879
+ readSnapshot;
68880
+ now;
68881
+ fetchImpl;
68882
+ pendingQueue = [];
68883
+ pendingBytes = 0;
68884
+ activeKeys = /* @__PURE__ */ new Set();
68885
+ inFlight = /* @__PURE__ */ new Set();
68886
+ activeControllers = /* @__PURE__ */ new Map();
68887
+ shuttingDown = false;
68888
+ constructor(options) {
68889
+ this.readSnapshot = options.readSnapshot;
68890
+ this.now = options.now ?? Date.now;
68891
+ this.fetchImpl = options.fetchImpl ?? fetch;
68892
+ }
68893
+ enqueue(input) {
68894
+ const serialized = JSON.stringify(input.envelope);
68895
+ const bytes = Buffer.byteLength(serialized, "utf8");
68896
+ const kind = input.envelope.kind;
68897
+ const deliveryId = input.envelope.deliveryId;
68898
+ if (bytes > DEVKIT_MAX_MESSAGE_BYTES) {
68899
+ this.emitDropped({ deliveryId, kind, reason: DEVKIT_DROP_REASON.REQUEST_TOO_LARGE, durationMs: 0 });
68900
+ return true;
68901
+ }
68902
+ if (this.pendingQueue.length >= DEVKIT_MAX_PENDING || this.pendingBytes + bytes > DEVKIT_MAX_PENDING_BYTES) {
68903
+ this.emitDropped({ deliveryId, kind, reason: DEVKIT_DROP_REASON.PENDING_OVERFLOW, durationMs: 0 });
68904
+ return false;
68905
+ }
68906
+ this.pendingQueue.push({
68907
+ envelope: input.envelope,
68908
+ config: input.config,
68909
+ serialized,
68910
+ bytes,
68911
+ cancelledByShutdown: false,
68912
+ timedOut: false
68913
+ });
68914
+ this.pendingBytes += bytes;
68915
+ logger.info(LogEvent.DEVKIT_DELIVERY_ACCEPTED, {
68916
+ component: COMPONENT,
68917
+ deliveryId,
68918
+ kind,
68919
+ agentId: input.envelope.agentId ?? void 0
68920
+ });
68921
+ this.pump();
68922
+ return true;
68923
+ }
68924
+ pump() {
68925
+ if (this.shuttingDown) {
68926
+ return;
68927
+ }
68928
+ while (this.activeKeys.size < DEVKIT_MAX_CONCURRENCY) {
68929
+ const index2 = this.pendingQueue.findIndex((item2) => !this.activeKeys.has(orderingKeyFor(item2.envelope)));
68930
+ if (index2 === -1) {
68931
+ break;
68932
+ }
68933
+ const [item] = this.pendingQueue.splice(index2, 1);
68934
+ this.pendingBytes -= item.bytes;
68935
+ const key = orderingKeyFor(item.envelope);
68936
+ this.activeKeys.add(key);
68937
+ const promise = this.send(item).finally(() => {
68938
+ this.activeKeys.delete(key);
68939
+ this.inFlight.delete(promise);
68940
+ this.pump();
68941
+ });
68942
+ this.inFlight.add(promise);
68943
+ }
68944
+ }
68945
+ async send(item) {
68946
+ const startedAt = this.now();
68947
+ const { envelope } = item;
68948
+ let snapshot;
68949
+ try {
68950
+ snapshot = this.readSnapshot();
68951
+ } catch {
68952
+ this.emitDropped({
68953
+ deliveryId: envelope.deliveryId,
68954
+ kind: envelope.kind,
68955
+ reason: DEVKIT_DROP_REASON.CONFIG_READ_FAILED,
68956
+ durationMs: this.now() - startedAt
68957
+ });
68958
+ return;
68959
+ }
68960
+ if (snapshot?.configVersion !== item.config.configVersion) {
68961
+ this.emitDropped({
68962
+ deliveryId: envelope.deliveryId,
68963
+ kind: envelope.kind,
68964
+ reason: DEVKIT_DROP_REASON.CONFIG_CHANGED,
68965
+ durationMs: this.now() - startedAt
68966
+ });
68967
+ return;
68968
+ }
68969
+ const loopbackOk = await isLoopbackTarget(snapshot.origin);
68970
+ if (!loopbackOk) {
68971
+ this.emitHttpFailed(
68972
+ item,
68973
+ DEVKIT_DROP_REASON.CONNECTION_FAILED,
68974
+ { errorCategory: "network_unavailable" },
68975
+ this.now() - startedAt
68976
+ );
68977
+ return;
68978
+ }
68979
+ const url = `${snapshot.origin}:${snapshot.port}${snapshot.eventPath}`;
68980
+ const controller = new AbortController();
68981
+ this.activeControllers.set(item, controller);
68982
+ const timeoutTimer = setTimeout(() => {
68983
+ item.timedOut = true;
68984
+ controller.abort();
68985
+ }, DEVKIT_REQUEST_BUDGET_MS);
68986
+ let response;
68987
+ try {
68988
+ response = await this.fetchImpl(url, {
68989
+ method: "POST",
68990
+ headers: { "content-type": "application/json" },
68991
+ body: item.serialized,
68992
+ redirect: "manual",
68993
+ signal: controller.signal
68994
+ });
68995
+ } catch (err2) {
68996
+ clearTimeout(timeoutTimer);
68997
+ this.activeControllers.delete(item);
68998
+ const durationMs2 = this.now() - startedAt;
68999
+ if (item.cancelledByShutdown) {
69000
+ this.emitCancelled(item, durationMs2);
69001
+ return;
69002
+ }
69003
+ const diagnostics = buildErrorDiagnostics(
69004
+ LogEvent.DEVKIT_DELIVERY_HTTP_FAILED,
69005
+ err2 instanceof Error ? err2 : void 0,
69006
+ {}
69007
+ );
69008
+ const reason = classifyFetchFailure({
69009
+ cancelledByShutdown: item.cancelledByShutdown,
69010
+ timedOut: item.timedOut,
69011
+ errorCategory: diagnostics.errorCategory
69012
+ });
69013
+ this.emitHttpFailed(item, reason, diagnostics, durationMs2, err2 instanceof Error ? err2 : void 0);
69014
+ return;
69015
+ }
69016
+ clearTimeout(timeoutTimer);
69017
+ this.activeControllers.delete(item);
69018
+ const durationMs = this.now() - startedAt;
69019
+ if (item.cancelledByShutdown) {
69020
+ this.emitCancelled(item, durationMs);
69021
+ return;
69022
+ }
69023
+ const status = response.status;
69024
+ const classified = classifyHttpOutcome(status);
69025
+ if (classified.outcome === DEVKIT_OUTCOME.HTTP_ACCEPTED) {
69026
+ logger.info(LogEvent.DEVKIT_DELIVERY_HTTP_ACCEPTED, {
69027
+ component: COMPONENT,
69028
+ deliveryId: envelope.deliveryId,
69029
+ kind: envelope.kind,
69030
+ statusCode: status,
69031
+ durationMs
69032
+ });
69033
+ return;
69034
+ }
69035
+ const redaction = await readRedactedResponse(response);
69036
+ this.emitDropped({
69037
+ deliveryId: envelope.deliveryId,
69038
+ kind: envelope.kind,
69039
+ reason: classified.reason,
69040
+ statusCode: status,
69041
+ durationMs,
69042
+ ...redaction
69043
+ });
69044
+ }
69045
+ async shutdown(deadlineMs) {
69046
+ this.shuttingDown = true;
69047
+ const deadline = this.now() + Math.max(0, deadlineMs);
69048
+ if (this.inFlight.size > 0) {
69049
+ const remaining = Math.max(0, deadline - this.now());
69050
+ await Promise.race([Promise.allSettled(Array.from(this.inFlight)), sleep4(remaining)]);
69051
+ }
69052
+ for (const [item, controller] of this.activeControllers) {
69053
+ item.cancelledByShutdown = true;
69054
+ controller.abort();
69055
+ }
69056
+ const stillPending = this.pendingQueue.splice(0, this.pendingQueue.length);
69057
+ this.pendingBytes = 0;
69058
+ for (const item of stillPending) {
69059
+ this.emitCancelled(item, 0);
69060
+ }
69061
+ }
69062
+ emitDropped(params) {
69063
+ logger.info(LogEvent.DEVKIT_DELIVERY_DROPPED, {
69064
+ component: COMPONENT,
69065
+ outcome: DEVKIT_OUTCOME.DROPPED,
69066
+ deliveryId: params.deliveryId,
69067
+ kind: params.kind,
69068
+ reason: params.reason,
69069
+ durationMs: params.durationMs,
69070
+ ...params.statusCode !== void 0 ? { statusCode: params.statusCode } : {},
69071
+ ...params.responseBytesRead !== void 0 ? { responseBytesRead: params.responseBytesRead } : {},
69072
+ ...params.responseTruncated !== void 0 ? { responseTruncated: params.responseTruncated } : {},
69073
+ ...params.responseSummary !== void 0 ? { responseSummary: params.responseSummary } : {}
69074
+ });
69075
+ }
69076
+ emitHttpFailed(item, reason, diagnostics, durationMs, err2) {
69077
+ logger.error(LogEvent.DEVKIT_DELIVERY_HTTP_FAILED, err2, {
69078
+ component: COMPONENT,
69079
+ outcome: DEVKIT_OUTCOME.DROPPED,
69080
+ deliveryId: item.envelope.deliveryId,
69081
+ kind: item.envelope.kind,
69082
+ reason,
69083
+ durationMs,
69084
+ ...diagnostics.errorCategory ? { errorCategory: diagnostics.errorCategory } : {},
69085
+ ...diagnostics.errorCode ? { errorCode: diagnostics.errorCode } : {}
69086
+ });
69087
+ }
69088
+ emitCancelled(item, durationMs) {
69089
+ logger.info(LogEvent.DEVKIT_DELIVERY_CANCELLED, {
69090
+ component: COMPONENT,
69091
+ outcome: DEVKIT_OUTCOME.DROPPED,
69092
+ deliveryId: item.envelope.deliveryId,
69093
+ kind: item.envelope.kind,
69094
+ reason: DEVKIT_DROP_REASON.SHUTDOWN_CANCELLED,
69095
+ durationMs
69096
+ });
69097
+ }
69098
+ };
69099
+ }
69100
+ });
69101
+
67674
69102
  // src/ai-dispatch-queue.ts
67675
69103
  async function enqueueAiJobMessageDispatch(params) {
67676
69104
  const commands = params.commands ?? new CommandStore(params.homeDir);
@@ -67702,6 +69130,95 @@ var init_ai_dispatch_queue = __esm({
67702
69130
  }
67703
69131
  });
67704
69132
 
69133
+ // src/devkit-router.ts
69134
+ function createDevkitAutoRouter(deps) {
69135
+ const { commands, dispatcher, readSnapshot } = deps;
69136
+ function readConfigOrNull(phase) {
69137
+ try {
69138
+ return { ok: true, config: readSnapshot() };
69139
+ } catch (err2) {
69140
+ logger.error(
69141
+ LogEvent.DEVKIT_ROUTE_CONFIG_READ_FAILED,
69142
+ err2 instanceof Error ? err2 : new Error(String(err2)),
69143
+ {
69144
+ component: "node_devkit",
69145
+ phase,
69146
+ outcome: "dropped",
69147
+ reason: "config_read_failed"
69148
+ }
69149
+ );
69150
+ return { ok: false };
69151
+ }
69152
+ }
69153
+ async function routeSession(event) {
69154
+ const read = readConfigOrNull("session");
69155
+ if (!read.ok) {
69156
+ return;
69157
+ }
69158
+ if (read.config === null) {
69159
+ await enqueueAiSessionMessageDispatch({ commands, event });
69160
+ logger.info(LogEvent.DEVKIT_ROUTE_DEFAULT_AI, {
69161
+ component: "node_devkit",
69162
+ phase: "session",
69163
+ kind: "session",
69164
+ messageId: event.messageId ?? "",
69165
+ jobId: event.jobId ?? "",
69166
+ agentId: event.agentId ?? ""
69167
+ });
69168
+ return;
69169
+ }
69170
+ const config = read.config;
69171
+ const envelope = buildSessionEnvelope(event);
69172
+ dispatcher.enqueue({ envelope, config });
69173
+ logger.info(LogEvent.DEVKIT_ROUTE_CUSTOM_SERVER, {
69174
+ component: "node_devkit",
69175
+ phase: "session",
69176
+ kind: "session",
69177
+ deliveryId: envelope.deliveryId,
69178
+ messageId: event.messageId ?? "",
69179
+ jobId: event.jobId ?? "",
69180
+ agentId: event.agentId ?? ""
69181
+ });
69182
+ }
69183
+ async function routeJob(event) {
69184
+ const read = readConfigOrNull("job");
69185
+ if (!read.ok) {
69186
+ return;
69187
+ }
69188
+ if (read.config === null) {
69189
+ await enqueueAiJobMessageDispatch({ commands, event });
69190
+ logger.info(LogEvent.DEVKIT_ROUTE_DEFAULT_AI, {
69191
+ component: "node_devkit",
69192
+ phase: "job",
69193
+ kind: "job",
69194
+ jobId: event.jobId,
69195
+ agentId: event.sessionAgentId ?? ""
69196
+ });
69197
+ return;
69198
+ }
69199
+ const config = read.config;
69200
+ const envelope = buildJobEnvelope(event);
69201
+ dispatcher.enqueue({ envelope, config });
69202
+ logger.info(LogEvent.DEVKIT_ROUTE_CUSTOM_SERVER, {
69203
+ component: "node_devkit",
69204
+ phase: "job",
69205
+ kind: "job",
69206
+ deliveryId: envelope.deliveryId,
69207
+ jobId: event.jobId,
69208
+ agentId: event.sessionAgentId ?? ""
69209
+ });
69210
+ }
69211
+ return { routeJob, routeSession };
69212
+ }
69213
+ var init_devkit_router = __esm({
69214
+ "src/devkit-router.ts"() {
69215
+ "use strict";
69216
+ init_ai_dispatch_queue();
69217
+ init_devkit_delivery();
69218
+ init_sentry_logger();
69219
+ }
69220
+ });
69221
+
67705
69222
  // src/message-handler.ts
67706
69223
  function tryMarkProcessed(messageId) {
67707
69224
  if (processedMessageIds.has(messageId)) {
@@ -68691,7 +70208,7 @@ async function processFileMessage(ctx, deps, options = {}) {
68691
70208
  timing.mark("payloadParse", parseStartedAt);
68692
70209
  const directToUser = chatType === "dm" && parseResult.ok ? extractDirectToUserNotification(parseResult.data) : { kind: "none" };
68693
70210
  if (directToUser.kind === "invalid") {
68694
- const droppedMessageId = messageId || `direct-to-user-${(0, import_node_crypto14.randomUUID)()}`;
70211
+ const droppedMessageId = messageId || `direct-to-user-${(0, import_node_crypto15.randomUUID)()}`;
68695
70212
  logger.error(
68696
70213
  LogEvent.INBOUND_DROP_DM_INVALID_PAYLOAD,
68697
70214
  new Error("Invalid direct-to-user system DM"),
@@ -68715,7 +70232,7 @@ async function processFileMessage(ctx, deps, options = {}) {
68715
70232
  await dispatchDirectToUserNotification({
68716
70233
  deps,
68717
70234
  notification: directToUser.notification,
68718
- messageId: messageId || `direct-to-user-${(0, import_node_crypto14.randomUUID)()}`,
70235
+ messageId: messageId || `direct-to-user-${(0, import_node_crypto15.randomUUID)()}`,
68719
70236
  timing,
68720
70237
  source: options.source ?? "live"
68721
70238
  });
@@ -68723,7 +70240,7 @@ async function processFileMessage(ctx, deps, options = {}) {
68723
70240
  }
68724
70241
  const systemNotification = chatType === "dm" && parseResult.ok ? extractSystemNotification(parseResult.data) : null;
68725
70242
  if (systemNotification) {
68726
- const systemMessageId = messageId || `system-${(0, import_node_crypto14.randomUUID)()}`;
70243
+ const systemMessageId = messageId || `system-${(0, import_node_crypto15.randomUUID)()}`;
68727
70244
  logWithTimestamp(
68728
70245
  `[okx-agent-task:${deps.myXmtpAddress}] xmtp_system_message_received agentId=${systemNotification.agentId ?? ""} msg=${shortenLogValue(systemMessageId)} event=${systemNotification.event ?? ""} job=${shortenLogValue(systemNotification.jobId)} conv=${conversationId} source=${options.source ?? "live"} rawBytes=${Buffer.byteLength(rawText, "utf8")} rawPreview=${previewRawEnvelope(rawText)}`
68729
70246
  );
@@ -69019,7 +70536,7 @@ async function processFileMessage(ctx, deps, options = {}) {
69019
70536
  }));
69020
70537
  return true;
69021
70538
  }
69022
- const routedMessageId = messageId || `group-${(0, import_node_crypto14.randomUUID)()}`;
70539
+ const routedMessageId = messageId || `group-${(0, import_node_crypto15.randomUUID)()}`;
69023
70540
  const sessionKey = ensureInboundGroupSession(deps, {
69024
70541
  jobId: route.jobId,
69025
70542
  myAgentId,
@@ -69085,7 +70602,7 @@ async function processFileMessage(ctx, deps, options = {}) {
69085
70602
  return true;
69086
70603
  }
69087
70604
  const stored = {
69088
- id: messageId || `local-${(0, import_node_crypto14.randomUUID)()}`,
70605
+ id: messageId || `local-${(0, import_node_crypto15.randomUUID)()}`,
69089
70606
  direction: "inbound",
69090
70607
  route: route.route,
69091
70608
  routeReason: route.routeReason,
@@ -69266,7 +70783,7 @@ function processOfflineFromCoreDeps(store, ctx, deps, options) {
69266
70783
  function buildSystemStoredMessage(params) {
69267
70784
  const now = Date.now();
69268
70785
  return {
69269
- id: params.id ?? `system-${now}-${(0, import_node_crypto14.randomUUID)()}`,
70786
+ id: params.id ?? `system-${now}-${(0, import_node_crypto15.randomUUID)()}`,
69270
70787
  direction: "system",
69271
70788
  route: "backup",
69272
70789
  routeReason: params.reason,
@@ -69284,12 +70801,12 @@ function buildSystemStoredMessage(params) {
69284
70801
  function isA2AEnvelope(payload) {
69285
70802
  return isPlainObject3(payload) && payload.msgType === A2A_MESSAGE_TYPE;
69286
70803
  }
69287
- var import_node_crypto14, PROCESSED_IDS_MAX, processedMessageIds, EXTERNAL_JOB_ID_PATTERN, INBOUND_TRANSPORT, INBOUND_EVENT_FAMILY, INBOUND_TERMINAL_FIELDS;
70804
+ var import_node_crypto15, PROCESSED_IDS_MAX, processedMessageIds, EXTERNAL_JOB_ID_PATTERN, INBOUND_TRANSPORT, INBOUND_EVENT_FAMILY, INBOUND_TERMINAL_FIELDS;
69288
70805
  var init_message_handler = __esm({
69289
70806
  "src/message-handler.ts"() {
69290
70807
  "use strict";
69291
70808
  init_log();
69292
- import_node_crypto14 = require("node:crypto");
70809
+ import_node_crypto15 = require("node:crypto");
69293
70810
  init_dist2();
69294
70811
  init_a2a();
69295
70812
  init_envelope_shared();
@@ -69357,7 +70874,7 @@ function isOriginalParentProcessAlive(options) {
69357
70874
  }
69358
70875
  function registerUserAttentionWatcher(options) {
69359
70876
  return options.store.registerUserAttentionWatcher({
69360
- id: options.id ?? (0, import_node_crypto15.randomUUID)(),
70877
+ id: options.id ?? (0, import_node_crypto16.randomUUID)(),
69361
70878
  provider: options.provider,
69362
70879
  jobId: options.jobId,
69363
70880
  nowMs: options.nowMs ?? Date.now(),
@@ -69436,11 +70953,11 @@ function userWatchEventDeliveredSentryExtra(event) {
69436
70953
  hasDecision: String(event.hasDecision)
69437
70954
  };
69438
70955
  }
69439
- var import_node_crypto15, USER_ATTENTION_WATCH_REPLACED_MESSAGE, USER_ATTENTION_WATCHER_SCAN_MS, USER_ATTENTION_WATCHER_TTL_MS, USER_ATTENTION_WATCH_PARENT_CHECK_MS;
70956
+ var import_node_crypto16, USER_ATTENTION_WATCH_REPLACED_MESSAGE, USER_ATTENTION_WATCHER_SCAN_MS, USER_ATTENTION_WATCHER_TTL_MS, USER_ATTENTION_WATCH_PARENT_CHECK_MS;
69440
70957
  var init_user_attention_watchers = __esm({
69441
70958
  "src/user-attention-watchers.ts"() {
69442
70959
  "use strict";
69443
- import_node_crypto15 = require("node:crypto");
70960
+ import_node_crypto16 = require("node:crypto");
69444
70961
  init_sentry_logger();
69445
70962
  USER_ATTENTION_WATCH_REPLACED_MESSAGE = "Another okx-a2a user watch with the same job scope was started, so this watcher has been closed. Do not run this watch command again automatically, because starting another watcher may interrupt a different session that is already monitoring task progress.";
69446
70963
  USER_ATTENTION_WATCHER_SCAN_MS = 500;
@@ -69513,13 +71030,13 @@ async function getHermesGatewayPluginStatus(options = {}) {
69513
71030
  const env = options.env ?? process.env;
69514
71031
  const hermesHome = env.HERMES_HOME?.trim() || (0, import_node_path32.join)((0, import_node_os10.homedir)(), ".hermes");
69515
71032
  const pluginYamlPath = (0, import_node_path32.join)(hermesHome, "plugins", "platforms", "okx-a2a", "plugin.yaml");
69516
- if (!(0, import_node_fs27.existsSync)(pluginYamlPath)) {
71033
+ if (!(0, import_node_fs28.existsSync)(pluginYamlPath)) {
69517
71034
  return { enabled: false, reason: "plugin_yaml_missing", hermesHome, checkedPath: pluginYamlPath };
69518
71035
  }
69519
71036
  const configPath = (0, import_node_path32.join)(hermesHome, "config.yaml");
69520
71037
  let content2;
69521
71038
  try {
69522
- content2 = await (0, import_promises13.readFile)(configPath, "utf8");
71039
+ content2 = await (0, import_promises14.readFile)(configPath, "utf8");
69523
71040
  } catch {
69524
71041
  return { enabled: false, reason: "config_read_error", hermesHome, checkedPath: configPath };
69525
71042
  }
@@ -69603,12 +71120,12 @@ function parseYamlInlineEnabledList(line) {
69603
71120
  }
69604
71121
  function stopClients(service) {
69605
71122
  for (const [address, client] of service.getClients()) {
69606
- try {
69607
- client.stop();
69608
- logWithTimestamp(`[okx-agent-task] stopped XMTP client ${address}`);
69609
- } catch (err2) {
69610
- logWithTimestamp(`[okx-agent-task] failed to stop XMTP client ${address}:`, err2);
69611
- }
71123
+ void stopAndCloseXmtpClient(client, {
71124
+ address,
71125
+ agentId: "",
71126
+ phase: "shutdown",
71127
+ onCloseError: (err2) => logWithTimestamp(`[okx-agent-task] failed to close XMTP client ${address}:`, err2)
71128
+ }).then(() => logWithTimestamp(`[okx-agent-task] stopped XMTP client ${address}`)).catch((err2) => logWithTimestamp(`[okx-agent-task] failed to stop XMTP client ${address}:`, err2));
69612
71129
  }
69613
71130
  }
69614
71131
  async function runListener(options = {}) {
@@ -69640,6 +71157,27 @@ async function runListenerWithLock(options, paths) {
69640
71157
  const store = new TaskMessageStore(options.homeDir);
69641
71158
  const sessionStore = new SessionStore({ homeDir: options.homeDir });
69642
71159
  const commands = new CommandStore(options.homeDir);
71160
+ const devkitReadSnapshot = () => {
71161
+ const snapshotStore = DevkitServerStore.openForRead(options.homeDir);
71162
+ if (!snapshotStore) {
71163
+ return null;
71164
+ }
71165
+ try {
71166
+ return snapshotStore.readSnapshot();
71167
+ } finally {
71168
+ snapshotStore.close();
71169
+ }
71170
+ };
71171
+ const devkitDispatcher = new DevkitDeliveryDispatcher({
71172
+ homeDir: options.homeDir,
71173
+ readSnapshot: devkitReadSnapshot
71174
+ });
71175
+ const devkitRouter = createDevkitAutoRouter({
71176
+ homeDir: options.homeDir,
71177
+ commands,
71178
+ dispatcher: devkitDispatcher,
71179
+ readSnapshot: devkitReadSnapshot
71180
+ });
69643
71181
  await store.ensureReady();
69644
71182
  let userAttentionEvents = null;
69645
71183
  try {
@@ -69703,20 +71241,20 @@ async function runListenerWithLock(options, paths) {
69703
71241
  createInboundMiddleware: (deps) => createMiddlewareFromCoreDeps(store, deps, {
69704
71242
  sessionStore,
69705
71243
  onJobMessageStored: async (event) => {
69706
- await enqueueAiJobMessageDispatch({ commands, event });
71244
+ await devkitRouter.routeJob(event);
69707
71245
  },
69708
71246
  onSessionMessage: async (event) => {
69709
- await enqueueAiSessionMessageDispatch({ commands, event });
71247
+ await devkitRouter.routeSession(event);
69710
71248
  }
69711
71249
  }),
69712
71250
  processOfflineMessage: (ctx, deps, replayOptions) => processOfflineFromCoreDeps(store, ctx, deps, {
69713
71251
  ...replayOptions,
69714
71252
  sessionStore,
69715
71253
  onJobMessageStored: async (event) => {
69716
- await enqueueAiJobMessageDispatch({ commands, event });
71254
+ await devkitRouter.routeJob(event);
69717
71255
  },
69718
71256
  onSessionMessage: async (event) => {
69719
- await enqueueAiSessionMessageDispatch({ commands, event });
71257
+ await devkitRouter.routeSession(event);
69720
71258
  }
69721
71259
  }),
69722
71260
  notifySessionExpired: (command) => {
@@ -69748,12 +71286,12 @@ async function runListenerWithLock(options, paths) {
69748
71286
  });
69749
71287
  }
69750
71288
  });
69751
- service.setPluginVersion("0.2.16");
71289
+ service.setPluginVersion("0.2.17-beta-ab42219842-261020165552");
69752
71290
  await service.init();
69753
71291
  const pluginVersionStatus = service.pluginVersionStatus;
69754
71292
  if (pluginVersionStatus.unavailable) {
69755
71293
  throw new Error(
69756
- `@okxweb3/a2a-node v${"0.2.16"} is below the required minimum v${pluginVersionStatus.minVersion}`
71294
+ `@okxweb3/a2a-node v${"0.2.17-beta-ab42219842-261020165552"} is below the required minimum v${pluginVersionStatus.minVersion}`
69757
71295
  );
69758
71296
  }
69759
71297
  const systemConfig = service.getSystemConfig();
@@ -69781,7 +71319,7 @@ async function runListenerWithLock(options, paths) {
69781
71319
  onchainosAgentId: "*",
69782
71320
  reason: "system-config missing sentryDsn",
69783
71321
  pluginId: "@okxweb3/a2a-node",
69784
- pluginVersion: "0.2.16"
71322
+ pluginVersion: "0.2.17-beta-ab42219842-261020165552"
69785
71323
  });
69786
71324
  }
69787
71325
  logWithTimestamp(
@@ -70113,6 +71651,7 @@ async function runListenerWithLock(options, paths) {
70113
71651
  logWithTimestamp("[okx-agent-task] failed to close user_attention IPC wake:", err2);
70114
71652
  }
70115
71653
  stopClients(service);
71654
+ await devkitDispatcher.shutdown(SHUTDOWN_FORCE_RESOLVE_MS);
70116
71655
  sessionStore.close();
70117
71656
  clearTimeout(forceResolve);
70118
71657
  resolve14();
@@ -70131,13 +71670,14 @@ async function timeSettled(fn) {
70131
71670
  return { durationMs: Date.now() - startedAt, error };
70132
71671
  }
70133
71672
  }
70134
- var import_node_fs27, import_promises13, import_node_os10, import_node_path32, DEFAULT_OFFLINE_REPLAY_INTERVAL_SEC, DEFAULT_XMTP_CLIENT_RECYCLE_INTERVAL_SEC, XMTP_CLIENT_RECYCLE_INTERVAL_ENV, HEARTBEAT_GATEWAY_CHECK_TIMEOUT_MS, AUTH_RECOVERY_PROBE_INTERVAL_MS, AUTH_RECOVERY_REFRESH_BACKOFF_MS, AgentRefreshAuthGate, AgentRefreshCoordinator, ListenerDeferredTaskScheduler, ListenerMaintenanceGate, UPGRADE_RECOMMENDATION_IDEMPOTENCY_KEY, SHUTDOWN_FORCE_RESOLVE_MS;
71673
+ var import_node_fs28, import_promises14, import_node_os10, import_node_path32, DEFAULT_OFFLINE_REPLAY_INTERVAL_SEC, DEFAULT_XMTP_CLIENT_RECYCLE_INTERVAL_SEC, XMTP_CLIENT_RECYCLE_INTERVAL_ENV, HEARTBEAT_GATEWAY_CHECK_TIMEOUT_MS, AUTH_RECOVERY_PROBE_INTERVAL_MS, AUTH_RECOVERY_REFRESH_BACKOFF_MS, AgentRefreshAuthGate, AgentRefreshCoordinator, ListenerDeferredTaskScheduler, ListenerMaintenanceGate, UPGRADE_RECOMMENDATION_IDEMPOTENCY_KEY, SHUTDOWN_FORCE_RESOLVE_MS;
70135
71674
  var init_listener = __esm({
70136
71675
  "src/listener.ts"() {
70137
71676
  "use strict";
70138
71677
  init_log();
70139
- import_node_fs27 = require("node:fs");
70140
- import_promises13 = require("node:fs/promises");
71678
+ init_client_lifecycle();
71679
+ import_node_fs28 = require("node:fs");
71680
+ import_promises14 = require("node:fs/promises");
70141
71681
  import_node_os10 = require("node:os");
70142
71682
  import_node_path32 = require("node:path");
70143
71683
  init_onchainos();
@@ -70150,7 +71690,9 @@ var init_listener = __esm({
70150
71690
  init_session_store();
70151
71691
  init_command_processor();
70152
71692
  init_command_store();
70153
- init_ai_dispatch_queue();
71693
+ init_devkit_delivery();
71694
+ init_devkit_router();
71695
+ init_devkit_server_store();
70154
71696
  init_message_handler();
70155
71697
  init_agent_message_notice();
70156
71698
  init_paths();
@@ -70403,7 +71945,7 @@ async function startXmtpTest(args, releaseInfo) {
70403
71945
  const runId = requestedRunId ? validateRunId(requestedRunId) : createRunId(requestedName);
70404
71946
  const files = resolveRunFiles(testsDir, runId);
70405
71947
  try {
70406
- await (0, import_promises14.stat)(files.runDir);
71948
+ await (0, import_promises15.stat)(files.runDir);
70407
71949
  throw new Error(`XMTP test run already exists: ${runId}`);
70408
71950
  } catch (error) {
70409
71951
  if (error.code !== "ENOENT") {
@@ -70411,7 +71953,7 @@ async function startXmtpTest(args, releaseInfo) {
70411
71953
  }
70412
71954
  }
70413
71955
  await ensurePrivateDir(files.runDir);
70414
- await (0, import_promises14.writeFile)(files.eventsPath, "", { encoding: "utf8", mode: 384 });
71956
+ await (0, import_promises15.writeFile)(files.eventsPath, "", { encoding: "utf8", mode: 384 });
70415
71957
  const manifest = {
70416
71958
  runId,
70417
71959
  name: requestedName,
@@ -70455,7 +71997,7 @@ async function stopXmtpTest(args) {
70455
71997
  }
70456
71998
  const runId = validateRunId(active.runId);
70457
71999
  const files = resolveRunFiles(testsDir, runId);
70458
- await (0, import_promises14.unlink)(activePath);
72000
+ await (0, import_promises15.unlink)(activePath);
70459
72001
  const manifest = await readRequiredJson(files.manifestPath);
70460
72002
  const completed = {
70461
72003
  ...manifest,
@@ -70773,7 +72315,7 @@ async function resolveRequestedRunId(testsDir, args, preferActive = false) {
70773
72315
  async function findLatestRunId(testsDir) {
70774
72316
  let entries;
70775
72317
  try {
70776
- entries = await (0, import_promises14.readdir)(testsDir, { withFileTypes: true });
72318
+ entries = await (0, import_promises15.readdir)(testsDir, { withFileTypes: true });
70777
72319
  } catch (error) {
70778
72320
  if (error.code === "ENOENT") {
70779
72321
  return null;
@@ -70798,7 +72340,7 @@ async function findLatestRunId(testsDir) {
70798
72340
  async function readMetricEvents(path2) {
70799
72341
  let text;
70800
72342
  try {
70801
- text = await (0, import_promises14.readFile)(path2, "utf8");
72343
+ text = await (0, import_promises15.readFile)(path2, "utf8");
70802
72344
  } catch (error) {
70803
72345
  if (error.code === "ENOENT") {
70804
72346
  return [];
@@ -70822,9 +72364,9 @@ function parseMetricEvent(line) {
70822
72364
  }
70823
72365
  }
70824
72366
  async function ensurePrivateDir(path2) {
70825
- await (0, import_promises14.mkdir)(path2, { recursive: true, mode: 448 });
72367
+ await (0, import_promises15.mkdir)(path2, { recursive: true, mode: 448 });
70826
72368
  try {
70827
- await (0, import_promises14.chmod)(path2, 448);
72369
+ await (0, import_promises15.chmod)(path2, 448);
70828
72370
  } catch (error) {
70829
72371
  const code = error.code;
70830
72372
  if (code !== "EPERM" && code !== "EACCES") {
@@ -70834,12 +72376,12 @@ async function ensurePrivateDir(path2) {
70834
72376
  }
70835
72377
  async function writeJson(path2, value) {
70836
72378
  const temporary = `${path2}.${process.pid}.tmp`;
70837
- await (0, import_promises14.writeFile)(temporary, `${JSON.stringify(value, null, 2)}
72379
+ await (0, import_promises15.writeFile)(temporary, `${JSON.stringify(value, null, 2)}
70838
72380
  `, {
70839
72381
  encoding: "utf8",
70840
72382
  mode: 384
70841
72383
  });
70842
- await (0, import_promises14.rename)(temporary, path2);
72384
+ await (0, import_promises15.rename)(temporary, path2);
70843
72385
  }
70844
72386
  async function readRequiredJson(path2) {
70845
72387
  const value = await readJsonIfExists(path2);
@@ -70850,7 +72392,7 @@ async function readRequiredJson(path2) {
70850
72392
  }
70851
72393
  async function readJsonIfExists(path2) {
70852
72394
  try {
70853
- return JSON.parse(await (0, import_promises14.readFile)(path2, "utf8"));
72395
+ return JSON.parse(await (0, import_promises15.readFile)(path2, "utf8"));
70854
72396
  } catch (error) {
70855
72397
  if (error.code === "ENOENT") {
70856
72398
  return null;
@@ -71021,11 +72563,11 @@ function formatPercent(value) {
71021
72563
  function validTimestamp(value) {
71022
72564
  return typeof value === "string" && Number.isFinite(Date.parse(value));
71023
72565
  }
71024
- var import_promises14, import_node_path33, RUN_ID_PATTERN2, ACTIVE_FILE;
72566
+ var import_promises15, import_node_path33, RUN_ID_PATTERN2, ACTIVE_FILE;
71025
72567
  var init_xmtp_test_cli = __esm({
71026
72568
  "src/xmtp-test-cli.ts"() {
71027
72569
  "use strict";
71028
- import_promises14 = require("node:fs/promises");
72570
+ import_promises15 = require("node:fs/promises");
71029
72571
  import_node_path33 = require("node:path");
71030
72572
  init_daemon();
71031
72573
  init_log_tail();
@@ -114004,10 +115546,10 @@ var require_node4 = __commonJS({
114004
115546
 
114005
115547
  // ../../node_modules/@xmtp/content-type-remote-attachment/dist/index.js
114006
115548
  async function encrypt(plain, secret, additionalData) {
114007
- const salt = import_node_crypto16.webcrypto.getRandomValues(new Uint8Array(KDFSaltSize));
114008
- const nonce = import_node_crypto16.webcrypto.getRandomValues(new Uint8Array(AESGCMNonceSize));
115549
+ const salt = import_node_crypto17.webcrypto.getRandomValues(new Uint8Array(KDFSaltSize));
115550
+ const nonce = import_node_crypto17.webcrypto.getRandomValues(new Uint8Array(AESGCMNonceSize));
114009
115551
  const key = await hkdf(secret, salt);
114010
- const encrypted = await import_node_crypto16.webcrypto.subtle.encrypt(aesGcmParams(nonce), key, plain);
115552
+ const encrypted = await import_node_crypto17.webcrypto.subtle.encrypt(aesGcmParams(nonce), key, plain);
114011
115553
  return new Ciphertext({
114012
115554
  aes256GcmHkdfSha256: {
114013
115555
  payload: new Uint8Array(encrypted),
@@ -114021,7 +115563,7 @@ async function decrypt(encrypted, secret, additionalData) {
114021
115563
  throw new Error("invalid payload ciphertext");
114022
115564
  }
114023
115565
  const key = await hkdf(secret, encrypted.aes256GcmHkdfSha256.hkdfSalt);
114024
- const decrypted = await import_node_crypto16.webcrypto.subtle.decrypt(aesGcmParams(encrypted.aes256GcmHkdfSha256.gcmNonce), key, encrypted.aes256GcmHkdfSha256.payload);
115566
+ const decrypted = await import_node_crypto17.webcrypto.subtle.decrypt(aesGcmParams(encrypted.aes256GcmHkdfSha256.gcmNonce), key, encrypted.aes256GcmHkdfSha256.payload);
114025
115567
  return new Uint8Array(decrypted);
114026
115568
  }
114027
115569
  function aesGcmParams(nonce, additionalData) {
@@ -114032,18 +115574,18 @@ function aesGcmParams(nonce, additionalData) {
114032
115574
  return spec;
114033
115575
  }
114034
115576
  async function hkdf(secret, salt) {
114035
- const key = await import_node_crypto16.webcrypto.subtle.importKey("raw", secret, "HKDF", false, [
115577
+ const key = await import_node_crypto17.webcrypto.subtle.importKey("raw", secret, "HKDF", false, [
114036
115578
  "deriveKey"
114037
115579
  ]);
114038
- return import_node_crypto16.webcrypto.subtle.deriveKey({ name: "HKDF", hash: "SHA-256", salt, info: hkdfNoInfo }, key, { name: "AES-GCM", length: 256 }, false, ["encrypt", "decrypt"]);
115580
+ return import_node_crypto17.webcrypto.subtle.deriveKey({ name: "HKDF", hash: "SHA-256", salt, info: hkdfNoInfo }, key, { name: "AES-GCM", length: 256 }, false, ["encrypt", "decrypt"]);
114039
115581
  }
114040
- var import_proto, import_node_crypto16, ContentTypeAttachment, AttachmentCodec, KDFSaltSize, AESGCMNonceSize, AESGCMTagLength, Ciphertext, hkdfNoInfo, ContentTypeRemoteAttachment, RemoteAttachmentCodec;
115582
+ var import_proto, import_node_crypto17, ContentTypeAttachment, AttachmentCodec, KDFSaltSize, AESGCMNonceSize, AESGCMTagLength, Ciphertext, hkdfNoInfo, ContentTypeRemoteAttachment, RemoteAttachmentCodec;
114041
115583
  var init_dist6 = __esm({
114042
115584
  "../../node_modules/@xmtp/content-type-remote-attachment/dist/index.js"() {
114043
115585
  init_dist5();
114044
115586
  init_secp256k12();
114045
115587
  import_proto = __toESM(require_node4(), 1);
114046
- import_node_crypto16 = require("node:crypto");
115588
+ import_node_crypto17 = require("node:crypto");
114047
115589
  ContentTypeAttachment = new ContentTypeId({
114048
115590
  authorityId: "xmtp.org",
114049
115591
  typeId: "attachment",
@@ -114123,7 +115665,7 @@ var init_dist6 = __esm({
114123
115665
  if (payload.length === 0) {
114124
115666
  throw new Error(`no payload for remote attachment at ${remoteAttachment.url}`);
114125
115667
  }
114126
- const digestBytes = new Uint8Array(await import_node_crypto16.webcrypto.subtle.digest("SHA-256", payload));
115668
+ const digestBytes = new Uint8Array(await import_node_crypto17.webcrypto.subtle.digest("SHA-256", payload));
114127
115669
  const digest = etc.bytesToHex(digestBytes);
114128
115670
  if (digest !== remoteAttachment.contentDigest) {
114129
115671
  throw new Error("content digest does not match");
@@ -114147,7 +115689,7 @@ var init_dist6 = __esm({
114147
115689
  return codec.decode(encodedContent, codecRegistry);
114148
115690
  }
114149
115691
  static async encodeEncrypted(content$1, codec) {
114150
- const secret = import_node_crypto16.webcrypto.getRandomValues(new Uint8Array(32));
115692
+ const secret = import_node_crypto17.webcrypto.getRandomValues(new Uint8Array(32));
114151
115693
  const encodedContent = import_proto.content.EncodedContent.encode(codec.encode(content$1, {
114152
115694
  codecFor() {
114153
115695
  return void 0;
@@ -114160,7 +115702,7 @@ var init_dist6 = __esm({
114160
115702
  if (!salt || !nonce || !payload) {
114161
115703
  throw new Error("missing encryption key");
114162
115704
  }
114163
- const digestBytes = new Uint8Array(await import_node_crypto16.webcrypto.subtle.digest("SHA-256", payload));
115705
+ const digestBytes = new Uint8Array(await import_node_crypto17.webcrypto.subtle.digest("SHA-256", payload));
114164
115706
  const digest = etc.bytesToHex(digestBytes);
114165
115707
  return {
114166
115708
  digest,
@@ -114216,7 +115758,7 @@ var init_dist6 = __esm({
114216
115758
  // ../core/src/file-upload-safety.ts
114217
115759
  function getUnsafeFileUploadReason(filePath, sensitiveUploadReg = []) {
114218
115760
  const expanded = (0, import_node_path34.resolve)(expandHome(filePath));
114219
- const target = (0, import_node_fs28.realpathSync)(expanded);
115761
+ const target = (0, import_node_fs29.realpathSync)(expanded);
114220
115762
  const targetName = (0, import_node_path34.basename)(target);
114221
115763
  if (targetName === ".env" || targetName.startsWith(".env.")) {
114222
115764
  return ".env";
@@ -114270,19 +115812,19 @@ function expandHome(filePath) {
114270
115812
  return filePath;
114271
115813
  }
114272
115814
  function safeRealpath(path2) {
114273
- if (!(0, import_node_fs28.existsSync)(path2)) {
115815
+ if (!(0, import_node_fs29.existsSync)(path2)) {
114274
115816
  return null;
114275
115817
  }
114276
- return (0, import_node_fs28.realpathSync)(path2);
115818
+ return (0, import_node_fs29.realpathSync)(path2);
114277
115819
  }
114278
115820
  function isPathInside(target, dir) {
114279
115821
  return target === dir || target.startsWith(`${dir}${import_node_path34.sep}`);
114280
115822
  }
114281
- var import_node_fs28, import_node_os11, import_node_path34, SENSITIVE_HOME_DIRS, SENSITIVE_HOME_FILES, UNSAFE_FILE_UPLOAD_MESSAGE;
115823
+ var import_node_fs29, import_node_os11, import_node_path34, SENSITIVE_HOME_DIRS, SENSITIVE_HOME_FILES, UNSAFE_FILE_UPLOAD_MESSAGE;
114282
115824
  var init_file_upload_safety = __esm({
114283
115825
  "../core/src/file-upload-safety.ts"() {
114284
115826
  "use strict";
114285
- import_node_fs28 = require("node:fs");
115827
+ import_node_fs29 = require("node:fs");
114286
115828
  import_node_os11 = require("node:os");
114287
115829
  import_node_path34 = require("node:path");
114288
115830
  SENSITIVE_HOME_DIRS = [
@@ -114370,16 +115912,16 @@ async function uploadFile(params) {
114370
115912
  return;
114371
115913
  }
114372
115914
  const maxFileSizeBytes = uploadConfig.maxFileSizeBytes;
114373
- const fileSize = (0, import_node_fs29.statSync)(params.filePath).size;
115915
+ const fileSize = (0, import_node_fs30.statSync)(params.filePath).size;
114374
115916
  if (fileSize > maxFileSizeBytes) {
114375
115917
  throw new Error(formatFileTooLargeMessage(maxFileSizeBytes));
114376
115918
  }
114377
- const data = (0, import_node_fs29.readFileSync)(params.filePath);
115919
+ const data = (0, import_node_fs30.readFileSync)(params.filePath);
114378
115920
  const attachment = { filename, mimeType, data: new Uint8Array(data) };
114379
115921
  const encrypted = await RemoteAttachmentCodec.encodeEncrypted(attachment, new AttachmentCodec());
114380
115922
  ensureFileDirs();
114381
- const encryptedPath = (0, import_node_path35.resolve)(FILE_WORK_DIR, `${(0, import_node_crypto17.randomUUID)()}.enc`);
114382
- (0, import_node_fs29.writeFileSync)(encryptedPath, encrypted.payload);
115923
+ const encryptedPath = (0, import_node_path35.resolve)(FILE_WORK_DIR, `${(0, import_node_crypto18.randomUUID)()}.enc`);
115924
+ (0, import_node_fs30.writeFileSync)(encryptedPath, encrypted.payload);
114383
115925
  try {
114384
115926
  const stdout = runOnchainos([
114385
115927
  "agent",
@@ -114415,14 +115957,14 @@ async function uploadFile(params) {
114415
115957
  }, null, 2));
114416
115958
  } finally {
114417
115959
  try {
114418
- (0, import_node_fs29.unlinkSync)(encryptedPath);
115960
+ (0, import_node_fs30.unlinkSync)(encryptedPath);
114419
115961
  } catch {
114420
115962
  }
114421
115963
  }
114422
115964
  }
114423
115965
  async function downloadFile(params) {
114424
115966
  ensureFileDirs();
114425
- const encryptedPath = (0, import_node_path35.resolve)(FILE_WORK_DIR, `${(0, import_node_crypto17.randomUUID)()}.enc`);
115967
+ const encryptedPath = (0, import_node_path35.resolve)(FILE_WORK_DIR, `${(0, import_node_crypto18.randomUUID)()}.enc`);
114426
115968
  try {
114427
115969
  const stdout = runOnchainos([
114428
115970
  "agent",
@@ -114446,8 +115988,8 @@ async function downloadFile(params) {
114446
115988
  }));
114447
115989
  throw new Error(`file download failed: ${stdout}`);
114448
115990
  }
114449
- const payload = new Uint8Array((0, import_node_fs29.readFileSync)(encryptedPath));
114450
- const digestBytes = new Uint8Array(await import_node_crypto17.webcrypto.subtle.digest("SHA-256", payload));
115991
+ const payload = new Uint8Array((0, import_node_fs30.readFileSync)(encryptedPath));
115992
+ const digestBytes = new Uint8Array(await import_node_crypto18.webcrypto.subtle.digest("SHA-256", payload));
114451
115993
  const actualDigest = Array.from(digestBytes).map((byte) => byte.toString(16).padStart(2, "0")).join("");
114452
115994
  if (actualDigest !== params.digest) {
114453
115995
  throw new Error(`file download digest verification failed: expected=${params.digest}, actual=${actualDigest}`);
@@ -114455,15 +115997,15 @@ async function downloadFile(params) {
114455
115997
  const decryptedBytes = await decryptAttachmentPayload(payload, params);
114456
115998
  const encodedContent = import_proto2.content.EncodedContent.decode(decryptedBytes);
114457
115999
  const attachment = new AttachmentCodec().decode(encodedContent);
114458
- const outputFilename = params.filename || attachment.filename || `${(0, import_node_crypto17.randomUUID)()}.bin`;
116000
+ const outputFilename = params.filename || attachment.filename || `${(0, import_node_crypto18.randomUUID)()}.bin`;
114459
116001
  const outputDir = DOWNLOADS_DIR;
114460
116002
  ensureA2aTaskDir(outputDir);
114461
116003
  const outputPath = (0, import_node_path35.resolve)(outputDir, (0, import_node_path35.basename)(outputFilename));
114462
- (0, import_node_fs29.writeFileSync)(outputPath, attachment.data);
116004
+ (0, import_node_fs30.writeFileSync)(outputPath, attachment.data);
114463
116005
  console.log(outputPath);
114464
116006
  } finally {
114465
116007
  try {
114466
- (0, import_node_fs29.unlinkSync)(encryptedPath);
116008
+ (0, import_node_fs30.unlinkSync)(encryptedPath);
114467
116009
  } catch {
114468
116010
  }
114469
116011
  }
@@ -114472,15 +116014,15 @@ async function decryptAttachmentPayload(payload, params) {
114472
116014
  const secretBytes = new Uint8Array(Buffer.from(params.secret, "base64"));
114473
116015
  const saltBytes = new Uint8Array(Buffer.from(params.salt, "base64"));
114474
116016
  const nonceBytes = new Uint8Array(Buffer.from(params.nonce, "base64"));
114475
- const hkdfKey = await import_node_crypto17.webcrypto.subtle.importKey("raw", secretBytes, "HKDF", false, ["deriveKey"]);
114476
- const aesKey = await import_node_crypto17.webcrypto.subtle.deriveKey(
116017
+ const hkdfKey = await import_node_crypto18.webcrypto.subtle.importKey("raw", secretBytes, "HKDF", false, ["deriveKey"]);
116018
+ const aesKey = await import_node_crypto18.webcrypto.subtle.deriveKey(
114477
116019
  { name: "HKDF", hash: "SHA-256", salt: saltBytes, info: new Uint8Array().buffer },
114478
116020
  hkdfKey,
114479
116021
  { name: "AES-GCM", length: 256 },
114480
116022
  false,
114481
116023
  ["decrypt"]
114482
116024
  );
114483
- return new Uint8Array(await import_node_crypto17.webcrypto.subtle.decrypt({ name: "AES-GCM", iv: nonceBytes }, aesKey, toArrayBuffer(payload)));
116025
+ return new Uint8Array(await import_node_crypto18.webcrypto.subtle.decrypt({ name: "AES-GCM", iv: nonceBytes }, aesKey, toArrayBuffer(payload)));
114484
116026
  }
114485
116027
  function toArrayBuffer(bytes) {
114486
116028
  return bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
@@ -114560,7 +116102,7 @@ function readUploadSystemConfig() {
114560
116102
  const res = parseCliJson2(stdout, "system-config");
114561
116103
  if (res.data && typeof res.data === "object") {
114562
116104
  ensureA2aTaskDir(OKX_A2A_PATHS.xmtpDir);
114563
- (0, import_node_fs29.writeFileSync)(SYSTEM_CONFIG_PATH, JSON.stringify(res.data));
116105
+ (0, import_node_fs30.writeFileSync)(SYSTEM_CONFIG_PATH, JSON.stringify(res.data));
114564
116106
  }
114565
116107
  return parseUploadSystemConfig(res.data ?? {});
114566
116108
  } catch {
@@ -114583,10 +116125,10 @@ function fileCliSentryExtra(operation, reason, extra = {}) {
114583
116125
  }
114584
116126
  function readSystemConfigFromCache() {
114585
116127
  try {
114586
- if (!(0, import_node_fs29.existsSync)(SYSTEM_CONFIG_PATH)) {
116128
+ if (!(0, import_node_fs30.existsSync)(SYSTEM_CONFIG_PATH)) {
114587
116129
  return null;
114588
116130
  }
114589
- return JSON.parse((0, import_node_fs29.readFileSync)(SYSTEM_CONFIG_PATH, "utf8"));
116131
+ return JSON.parse((0, import_node_fs30.readFileSync)(SYSTEM_CONFIG_PATH, "utf8"));
114590
116132
  } catch {
114591
116133
  return null;
114592
116134
  }
@@ -114620,13 +116162,13 @@ function readRequiredOption(args, name) {
114620
116162
  }
114621
116163
  return value;
114622
116164
  }
114623
- var import_node_crypto17, import_node_fs29, import_node_path35, import_proto2, OKX_A2A_PATHS, OKX_A2A_HOME_DIR, FILE_WORK_DIR, DOWNLOADS_DIR, SYSTEM_CONFIG_PATH;
116165
+ var import_node_crypto18, import_node_fs30, import_node_path35, import_proto2, OKX_A2A_PATHS, OKX_A2A_HOME_DIR, FILE_WORK_DIR, DOWNLOADS_DIR, SYSTEM_CONFIG_PATH;
114624
116166
  var init_file_cli = __esm({
114625
116167
  "src/file-cli.ts"() {
114626
116168
  "use strict";
114627
116169
  init_win_spawn();
114628
- import_node_crypto17 = require("node:crypto");
114629
- import_node_fs29 = require("node:fs");
116170
+ import_node_crypto18 = require("node:crypto");
116171
+ import_node_fs30 = require("node:fs");
114630
116172
  import_node_path35 = require("node:path");
114631
116173
  init_dist6();
114632
116174
  import_proto2 = __toESM(require_node4());
@@ -114649,12 +116191,12 @@ __export(user_attention_cli_exports, {
114649
116191
  });
114650
116192
  async function handleUserCommand(args) {
114651
116193
  const subcommand = args[0];
114652
- if (!subcommand || args.every(isHelpArg2)) {
116194
+ if (!subcommand || args.every(isHelpArg3)) {
114653
116195
  printUserUsage();
114654
116196
  return;
114655
116197
  }
114656
116198
  if (subcommand === "help") {
114657
- const helpTarget = args.slice(1).find((arg) => !isHelpArg2(arg));
116199
+ const helpTarget = args.slice(1).find((arg) => !isHelpArg3(arg));
114658
116200
  if (!helpTarget) {
114659
116201
  printUserUsage();
114660
116202
  return;
@@ -114671,7 +116213,7 @@ async function handleUserCommand(args) {
114671
116213
  return;
114672
116214
  }
114673
116215
  const commandStartedAt = Date.now();
114674
- const parsed = parseArgs2(args.slice(1));
116216
+ const parsed = parseArgs3(args.slice(1));
114675
116217
  const json = parsed.flags.has("json");
114676
116218
  const storeInitStartedAt = Date.now();
114677
116219
  const store = new SessionStore();
@@ -114788,7 +116330,7 @@ async function handleUserCommand(args) {
114788
116330
  function hasHelpFlag2(args) {
114789
116331
  return args.some((arg) => arg === "-h" || arg === "--help");
114790
116332
  }
114791
- function isHelpArg2(arg) {
116333
+ function isHelpArg3(arg) {
114792
116334
  return arg === "-h" || arg === "--help" || arg === "help";
114793
116335
  }
114794
116336
  function printUserUsage() {
@@ -115120,7 +116662,7 @@ async function watchUserAttentionViaDaemon(store, parsed, json, options) {
115120
116662
  nextHeartbeatAt = Date.now() + Math.min(1e3, Math.max(100, pollMs));
115121
116663
  }
115122
116664
  const waitMs = deadline ? Math.max(0, Math.min(pollMs, USER_ATTENTION_WATCH_PARENT_CHECK_MS, deadline - Date.now())) : Math.min(pollMs, USER_ATTENTION_WATCH_PARENT_CHECK_MS);
115123
- await sleep4(waitMs);
116665
+ await sleep5(waitMs);
115124
116666
  }
115125
116667
  } finally {
115126
116668
  watcherCleanup.cleanup();
@@ -115140,7 +116682,7 @@ async function registerWatcherWithBusyRetry(options) {
115140
116682
  if (!isSqliteBusyError(err2) || attempt >= attempts) {
115141
116683
  throw err2;
115142
116684
  }
115143
- await sleep4(250 * attempt);
116685
+ await sleep5(250 * attempt);
115144
116686
  }
115145
116687
  }
115146
116688
  }
@@ -115266,7 +116808,7 @@ function createWakeSignal() {
115266
116808
  }
115267
116809
  };
115268
116810
  }
115269
- function sleep4(ms) {
116811
+ function sleep5(ms) {
115270
116812
  return new Promise((resolve14) => setTimeout(resolve14, ms));
115271
116813
  }
115272
116814
  function output(json, payload, human) {
@@ -115307,7 +116849,7 @@ function runSyncWithoutConsoleOutput(fn) {
115307
116849
  console.error = originalError;
115308
116850
  }
115309
116851
  }
115310
- function parseArgs2(args) {
116852
+ function parseArgs3(args) {
115311
116853
  const positional = [];
115312
116854
  const options = /* @__PURE__ */ new Map();
115313
116855
  const flags = /* @__PURE__ */ new Set();
@@ -115761,12 +117303,12 @@ __export(session_cli_exports, {
115761
117303
  });
115762
117304
  async function handleSessionCommand(args) {
115763
117305
  const subcommand = args[0];
115764
- if (!subcommand || args.every(isHelpArg3)) {
117306
+ if (!subcommand || args.every(isHelpArg4)) {
115765
117307
  printSessionUsage();
115766
117308
  return;
115767
117309
  }
115768
117310
  if (subcommand === "help") {
115769
- const helpTarget = args.slice(1).find((arg) => !isHelpArg3(arg));
117311
+ const helpTarget = args.slice(1).find((arg) => !isHelpArg4(arg));
115770
117312
  if (!helpTarget) {
115771
117313
  printSessionUsage();
115772
117314
  return;
@@ -115782,7 +117324,7 @@ async function handleSessionCommand(args) {
115782
117324
  }
115783
117325
  return;
115784
117326
  }
115785
- const parsed = parseArgs3(args.slice(1));
117327
+ const parsed = parseArgs4(args.slice(1));
115786
117328
  const json = parsed.flags.has("json");
115787
117329
  const store = new SessionStore();
115788
117330
  let usedOpenClawGateway = false;
@@ -115948,9 +117490,9 @@ async function handleSessionCommand(args) {
115948
117490
  }
115949
117491
  }
115950
117492
  function hasHelpFlag3(args) {
115951
- return args.some(isHelpArg3);
117493
+ return args.some(isHelpArg4);
115952
117494
  }
115953
- function isHelpArg3(arg) {
117495
+ function isHelpArg4(arg) {
115954
117496
  return arg === "-h" || arg === "--help" || arg === "help";
115955
117497
  }
115956
117498
  function printSessionUsage() {
@@ -116756,7 +118298,7 @@ function normalizeOptionalText4(value) {
116756
118298
  const normalized = value?.trim();
116757
118299
  return normalized ? normalized : null;
116758
118300
  }
116759
- function parseArgs3(args) {
118301
+ function parseArgs4(args) {
116760
118302
  const positional = [];
116761
118303
  const options = /* @__PURE__ */ new Map();
116762
118304
  const flags = /* @__PURE__ */ new Set();
@@ -116839,7 +118381,7 @@ async function handleXmtpDebugCli(args) {
116839
118381
  throw new Error(`Unknown xmtp-debug command: ${subcommand}`);
116840
118382
  }
116841
118383
  const action = subcommand;
116842
- const parsed = parseArgs4(args.slice(1));
118384
+ const parsed = parseArgs5(args.slice(1));
116843
118385
  rejectAccountOverride(parsed);
116844
118386
  const groupId = parsed.options.get("group-id");
116845
118387
  const jobId = parsed.options.get("job-id");
@@ -116933,7 +118475,7 @@ Options:
116933
118475
  --json Print machine-readable JSON.
116934
118476
  `);
116935
118477
  }
116936
- function parseArgs4(args) {
118478
+ function parseArgs5(args) {
116937
118479
  const options = /* @__PURE__ */ new Map();
116938
118480
  const flags = /* @__PURE__ */ new Set();
116939
118481
  for (let index2 = 0; index2 < args.length; index2 += 1) {
@@ -117021,7 +118563,7 @@ async function handleAiCommand(args) {
117021
118563
  return;
117022
118564
  }
117023
118565
  const subcommand = args[0] ?? "status";
117024
- const parsed = parseArgs5(args.slice(1));
118566
+ const parsed = parseArgs6(args.slice(1));
117025
118567
  const json = parsed.flags.has("json");
117026
118568
  const store = new SessionStore();
117027
118569
  try {
@@ -117145,7 +118687,7 @@ function output4(json, payload, human) {
117145
118687
  }
117146
118688
  console.log(human);
117147
118689
  }
117148
- function parseArgs5(args) {
118690
+ function parseArgs6(args) {
117149
118691
  const positional = [];
117150
118692
  const options = /* @__PURE__ */ new Map();
117151
118693
  const flags = /* @__PURE__ */ new Set();
@@ -117201,7 +118743,7 @@ function isPostjectRunnable() {
117201
118743
  function resolvePostjectCommand() {
117202
118744
  try {
117203
118745
  const cliPath = (0, import_node_module.createRequire)(__filename).resolve("postject/dist/cli.js");
117204
- if ((0, import_node_fs30.existsSync)(cliPath)) {
118746
+ if ((0, import_node_fs31.existsSync)(cliPath)) {
117205
118747
  return { command: process.execPath, prefixArgs: [cliPath] };
117206
118748
  }
117207
118749
  } catch {
@@ -117272,26 +118814,26 @@ function buildSeaConfig(entryPath, blobPath) {
117272
118814
  }
117273
118815
  async function installWindowsNativeLauncher(options) {
117274
118816
  const nodeExe = options.nodeExe ?? process.execPath;
117275
- if (!(0, import_node_fs30.existsSync)(options.cliPath)) {
118817
+ if (!(0, import_node_fs31.existsSync)(options.cliPath)) {
117276
118818
  throw new Error(`cannot build okx-a2a.exe: CLI entry not found at ${options.cliPath}`);
117277
118819
  }
117278
- if (!(0, import_node_fs30.existsSync)(nodeExe)) {
118820
+ if (!(0, import_node_fs31.existsSync)(nodeExe)) {
117279
118821
  throw new Error(`cannot build okx-a2a.exe: node executable not found at ${nodeExe}`);
117280
118822
  }
117281
118823
  const exePath = (0, import_node_path36.join)(options.targetDir, NATIVE_LAUNCHER_EXE_NAME);
117282
- (0, import_node_fs30.mkdirSync)(options.targetDir, { recursive: true });
117283
- const work = (0, import_node_fs30.mkdtempSync)((0, import_node_path36.join)((0, import_node_os12.tmpdir)(), "okx-a2a-sea-"));
118824
+ (0, import_node_fs31.mkdirSync)(options.targetDir, { recursive: true });
118825
+ const work = (0, import_node_fs31.mkdtempSync)((0, import_node_path36.join)((0, import_node_os12.tmpdir)(), "okx-a2a-sea-"));
117284
118826
  try {
117285
118827
  const entryPath = (0, import_node_path36.join)(work, "launcher-entry.js");
117286
118828
  const blobPath = (0, import_node_path36.join)(work, "okx-a2a.blob");
117287
118829
  const configPath = (0, import_node_path36.join)(work, "sea-config.json");
117288
- (0, import_node_fs30.writeFileSync)(entryPath, buildLauncherEntryJs(options.cliPath), "utf8");
117289
- (0, import_node_fs30.writeFileSync)(configPath, buildSeaConfig(entryPath, blobPath), "utf8");
118830
+ (0, import_node_fs31.writeFileSync)(entryPath, buildLauncherEntryJs(options.cliPath), "utf8");
118831
+ (0, import_node_fs31.writeFileSync)(configPath, buildSeaConfig(entryPath, blobPath), "utf8");
117290
118832
  (0, import_node_child_process9.execFileSync)(nodeExe, ["--experimental-sea-config", configPath], {
117291
118833
  stdio: "ignore",
117292
118834
  windowsHide: true
117293
118835
  });
117294
- (0, import_node_fs30.copyFileSync)(nodeExe, exePath);
118836
+ (0, import_node_fs31.copyFileSync)(nodeExe, exePath);
117295
118837
  const isMac = process.platform === "darwin";
117296
118838
  if (isMac) {
117297
118839
  try {
@@ -117311,10 +118853,10 @@ async function installWindowsNativeLauncher(options) {
117311
118853
  );
117312
118854
  return { exePath, cliPath: options.cliPath, nodeExe };
117313
118855
  } finally {
117314
- (0, import_node_fs30.rmSync)(work, { recursive: true, force: true });
118856
+ (0, import_node_fs31.rmSync)(work, { recursive: true, force: true });
117315
118857
  }
117316
118858
  }
117317
- function findWindowsNativeOkxA2aExe(pathValue, appData, userProfile, fileExists2 = import_node_fs30.existsSync) {
118859
+ function findWindowsNativeOkxA2aExe(pathValue, appData, userProfile, fileExists2 = import_node_fs31.existsSync) {
117318
118860
  const dirs = pathValue.split(";").map((d) => d.trim()).filter(Boolean);
117319
118861
  if (appData) {
117320
118862
  dirs.push((0, import_node_path36.join)(appData, "npm"));
@@ -117332,11 +118874,11 @@ function findWindowsNativeOkxA2aExe(pathValue, appData, userProfile, fileExists2
117332
118874
  }
117333
118875
  function resolveRunningCliPath() {
117334
118876
  const fromArgv = process.argv[1];
117335
- if (fromArgv && /(?:^|[\\/])cli\.js$/.test(fromArgv) && (0, import_node_fs30.existsSync)(fromArgv)) {
118877
+ if (fromArgv && /(?:^|[\\/])cli\.js$/.test(fromArgv) && (0, import_node_fs31.existsSync)(fromArgv)) {
117336
118878
  return fromArgv;
117337
118879
  }
117338
118880
  const beside = (0, import_node_path36.join)(__dirname, "cli.js");
117339
- if ((0, import_node_fs30.existsSync)(beside)) {
118881
+ if ((0, import_node_fs31.existsSync)(beside)) {
117340
118882
  return beside;
117341
118883
  }
117342
118884
  if (fromArgv) {
@@ -117358,12 +118900,12 @@ async function ensureWindowsNativeLauncher(options = {}) {
117358
118900
  const result = await installWindowsNativeLauncher({ cliPath: resolveRunningCliPath(), targetDir });
117359
118901
  return { exePath: result.exePath, installed: true };
117360
118902
  }
117361
- var import_node_child_process9, import_node_fs30, import_node_module, import_node_os12, import_node_path36, SEA_SENTINEL_FUSE, NATIVE_LAUNCHER_EXE_NAME, POSTJECT_SPEC, POSTJECT_BIN;
118903
+ var import_node_child_process9, import_node_fs31, import_node_module, import_node_os12, import_node_path36, SEA_SENTINEL_FUSE, NATIVE_LAUNCHER_EXE_NAME, POSTJECT_SPEC, POSTJECT_BIN;
117362
118904
  var init_win_native_launcher = __esm({
117363
118905
  "src/win-native-launcher.ts"() {
117364
118906
  "use strict";
117365
118907
  import_node_child_process9 = require("node:child_process");
117366
- import_node_fs30 = require("node:fs");
118908
+ import_node_fs31 = require("node:fs");
117367
118909
  import_node_module = require("node:module");
117368
118910
  import_node_os12 = require("node:os");
117369
118911
  import_node_path36 = require("node:path");
@@ -117505,7 +119047,7 @@ function buildProviderMismatchWarning(target, provider) {
117505
119047
  ].join("\n");
117506
119048
  }
117507
119049
  async function handleUpdateCommand(args) {
117508
- if (args.some(isHelpArg4)) {
119050
+ if (args.some(isHelpArg5)) {
117509
119051
  printUpdateUsage();
117510
119052
  return;
117511
119053
  }
@@ -117546,7 +119088,7 @@ function resolveUpdateTarget(target) {
117546
119088
  return detectGatewayInvocation() ?? "node";
117547
119089
  }
117548
119090
  async function handleSetupCommand(args) {
117549
- if (args.some(isHelpArg4)) {
119091
+ if (args.some(isHelpArg5)) {
117550
119092
  printSetupUsage();
117551
119093
  return;
117552
119094
  }
@@ -118123,7 +119665,7 @@ async function getCurrentNodeCliVersion() {
118123
119665
  return await getGlobalNpmPackageVersion(UPDATE_PACKAGES.node) ?? getBundledNodeCliVersion();
118124
119666
  }
118125
119667
  function getBundledNodeCliVersion() {
118126
- return true ? "0.2.16" : null;
119668
+ return true ? "0.2.17-beta-ab42219842-261020165552" : null;
118127
119669
  }
118128
119670
  function readConfiguredAiProvider() {
118129
119671
  const explicit = process.env.OKX_A2A_AI_PROVIDER || process.env.OKX_AGENT_TASK_AI_CLI;
@@ -118308,7 +119850,7 @@ async function updateHermes(release, options) {
118308
119850
  assertNotRunningInsideGateway("hermes");
118309
119851
  }
118310
119852
  const spec = buildNpmPackageSpec("hermes", release);
118311
- const workDir = await (0, import_promises15.mkdtemp)((0, import_node_path37.join)((0, import_node_os13.tmpdir)(), `okx-a2a-${label}-hermes-`));
119853
+ const workDir = await (0, import_promises16.mkdtemp)((0, import_node_path37.join)((0, import_node_os13.tmpdir)(), `okx-a2a-${label}-hermes-`));
118312
119854
  try {
118313
119855
  console.log(`[${label}] downloading ${spec}`);
118314
119856
  const npmTarball = await npmPack(spec, workDir);
@@ -118329,11 +119871,11 @@ async function updateHermes(release, options) {
118329
119871
  }
118330
119872
  console.log(`[${label}] hermes ${label} done`);
118331
119873
  } finally {
118332
- await (0, import_promises15.rm)(workDir, { recursive: true, force: true });
119874
+ await (0, import_promises16.rm)(workDir, { recursive: true, force: true });
118333
119875
  }
118334
119876
  }
118335
119877
  async function installGatewayPluginForDoctor(target) {
118336
- const release = isPrereleaseVersion("0.2.16") ? "beta" : "latest";
119878
+ const release = isPrereleaseVersion("0.2.17-beta-ab42219842-261020165552") ? "beta" : "latest";
118337
119879
  const insideTargetGateway = detectGatewayInvocation() === target;
118338
119880
  const options = {
118339
119881
  restart: !insideTargetGateway,
@@ -118360,7 +119902,7 @@ function setupReadyMessage(target) {
118360
119902
  async function normalizeHermesOkxA2aPluginConfig(configFile = resolveHermesConfigPath()) {
118361
119903
  let content2;
118362
119904
  try {
118363
- content2 = await (0, import_promises15.readFile)(configFile, "utf8");
119905
+ content2 = await (0, import_promises16.readFile)(configFile, "utf8");
118364
119906
  } catch (error) {
118365
119907
  if (isNodeError(error) && error.code === "ENOENT") {
118366
119908
  return false;
@@ -118371,21 +119913,21 @@ async function normalizeHermesOkxA2aPluginConfig(configFile = resolveHermesConfi
118371
119913
  if (!normalized.changed) {
118372
119914
  return false;
118373
119915
  }
118374
- await (0, import_promises15.writeFile)(configFile, normalized.content);
119916
+ await (0, import_promises16.writeFile)(configFile, normalized.content);
118375
119917
  console.log(`[update] normalized Hermes plugins.enabled okx-a2a entry in ${configFile}`);
118376
119918
  return true;
118377
119919
  }
118378
119920
  async function ensureHermesOkxA2aPluginConfig(configFile = resolveHermesConfigPath(), options = {}) {
118379
119921
  let content2;
118380
119922
  try {
118381
- content2 = await (0, import_promises15.readFile)(configFile, "utf8");
119923
+ content2 = await (0, import_promises16.readFile)(configFile, "utf8");
118382
119924
  } catch (error) {
118383
119925
  if (isNodeError(error) && error.code === "ENOENT") {
118384
119926
  if (options.dryRun) {
118385
119927
  return true;
118386
119928
  }
118387
- await (0, import_promises15.mkdir)((0, import_node_path37.resolve)(configFile, ".."), { recursive: true });
118388
- await (0, import_promises15.writeFile)(configFile, "plugins:\n enabled:\n - okx-a2a\n");
119929
+ await (0, import_promises16.mkdir)((0, import_node_path37.resolve)(configFile, ".."), { recursive: true });
119930
+ await (0, import_promises16.writeFile)(configFile, "plugins:\n enabled:\n - okx-a2a\n");
118389
119931
  console.log(`[update] added Hermes plugins.enabled okx-a2a entry in ${configFile}`);
118390
119932
  return true;
118391
119933
  }
@@ -118396,7 +119938,7 @@ async function ensureHermesOkxA2aPluginConfig(configFile = resolveHermesConfigPa
118396
119938
  if (options.dryRun) {
118397
119939
  return true;
118398
119940
  }
118399
- await (0, import_promises15.writeFile)(configFile, normalized.content);
119941
+ await (0, import_promises16.writeFile)(configFile, normalized.content);
118400
119942
  console.log(`[update] normalized Hermes plugins.enabled okx-a2a entry in ${configFile}`);
118401
119943
  return true;
118402
119944
  }
@@ -118407,7 +119949,7 @@ async function ensureHermesOkxA2aPluginConfig(configFile = resolveHermesConfigPa
118407
119949
  return true;
118408
119950
  }
118409
119951
  const updated = addHermesOkxA2aEnabled(content2);
118410
- await (0, import_promises15.writeFile)(configFile, updated);
119952
+ await (0, import_promises16.writeFile)(configFile, updated);
118411
119953
  console.log(`[update] added Hermes plugins.enabled okx-a2a entry in ${configFile}`);
118412
119954
  return true;
118413
119955
  }
@@ -118708,7 +120250,7 @@ async function isGatewayPluginInstalled(target) {
118708
120250
  if (target === "openclaw") {
118709
120251
  return (await getInstalledOpenClawPluginInfo()).installed;
118710
120252
  }
118711
- return (0, import_node_fs31.existsSync)(resolveHermesPluginYamlPath());
120253
+ return (0, import_node_fs32.existsSync)(resolveHermesPluginYamlPath());
118712
120254
  }
118713
120255
  async function getInstalledGatewayPluginVersion(target) {
118714
120256
  if (target === "hermes") {
@@ -118797,7 +120339,7 @@ function parsePackageVersionFromText(output5) {
118797
120339
  async function getInstalledHermesPluginVersion() {
118798
120340
  const pluginYaml = (0, import_node_path37.join)(process.env.HERMES_HOME ?? (0, import_node_path37.join)((0, import_node_os13.homedir)(), ".hermes"), "plugins", "platforms", "okx-a2a", "plugin.yaml");
118799
120341
  try {
118800
- const content2 = await (0, import_promises15.readFile)(pluginYaml, "utf8");
120342
+ const content2 = await (0, import_promises16.readFile)(pluginYaml, "utf8");
118801
120343
  return parsePluginYamlVersion(content2);
118802
120344
  } catch (error) {
118803
120345
  if (isNodeError(error) && error.code === "ENOENT") {
@@ -118856,7 +120398,7 @@ async function npmPack(spec, destination) {
118856
120398
  return (0, import_node_path37.resolve)(destination, (0, import_node_path37.basename)(tarballName));
118857
120399
  }
118858
120400
  async function findHermesPluginTarball(distDir) {
118859
- const entries = await (0, import_promises15.readdir)(distDir);
120401
+ const entries = await (0, import_promises16.readdir)(distDir);
118860
120402
  const tarball = entries.find((entry) => /^okx-a2a-hermes-plugin-.+\.tar\.gz$/.test(entry));
118861
120403
  if (!tarball) {
118862
120404
  throw new Error(`Hermes npm package did not contain dist/okx-a2a-hermes-plugin-*.tar.gz`);
@@ -118864,7 +120406,7 @@ async function findHermesPluginTarball(distDir) {
118864
120406
  return (0, import_node_path37.join)(distDir, tarball);
118865
120407
  }
118866
120408
  async function findFirstDirectory(parent) {
118867
- const entries = await (0, import_promises15.readdir)(parent, { withFileTypes: true });
120409
+ const entries = await (0, import_promises16.readdir)(parent, { withFileTypes: true });
118868
120410
  const dir = entries.find((entry) => entry.isDirectory());
118869
120411
  if (!dir) {
118870
120412
  throw new Error(`No unpacked plugin directory found under ${parent}`);
@@ -118881,7 +120423,7 @@ function readOption4(args, name) {
118881
120423
  function hasFlag(args, name) {
118882
120424
  return args.includes(name);
118883
120425
  }
118884
- function isHelpArg4(value) {
120426
+ function isHelpArg5(value) {
118885
120427
  return value === "-h" || value === "--help" || value === "help";
118886
120428
  }
118887
120429
  function isSupportedRelease(value) {
@@ -119090,13 +120632,13 @@ function buildExternalCommandInvocation(command, args, platform = process.platfo
119090
120632
  function formatExternalCommand(command, args) {
119091
120633
  return [command, ...args].join(" ");
119092
120634
  }
119093
- var import_node_child_process10, import_node_fs31, import_promises15, import_node_os13, import_node_path37, 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;
120635
+ var import_node_child_process10, import_node_fs32, import_promises16, import_node_os13, import_node_path37, 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;
119094
120636
  var init_update_cli = __esm({
119095
120637
  "src/update-cli.ts"() {
119096
120638
  "use strict";
119097
120639
  import_node_child_process10 = require("node:child_process");
119098
- import_node_fs31 = require("node:fs");
119099
- import_promises15 = require("node:fs/promises");
120640
+ import_node_fs32 = require("node:fs");
120641
+ import_promises16 = require("node:fs/promises");
119100
120642
  import_node_os13 = require("node:os");
119101
120643
  import_node_path37 = require("node:path");
119102
120644
  init_ai_command();
@@ -119386,7 +120928,7 @@ async function runDoctor(options = {}) {
119386
120928
  platform: options.platform ?? process.platform,
119387
120929
  env: options.env ?? process.env,
119388
120930
  target: options.target ?? resolveDoctorTarget(options.env ?? process.env),
119389
- cliVersion: options.cliVersion ?? (true ? "0.2.16" : "0.0.0"),
120931
+ cliVersion: options.cliVersion ?? (true ? "0.2.17-beta-ab42219842-261020165552" : "0.0.0"),
119390
120932
  fixMode: options.fix === true,
119391
120933
  nonInteractive: options.nonInteractive === true,
119392
120934
  packageChanged: false,
@@ -120423,7 +121965,7 @@ var init_doctor_cli = __esm({
120423
121965
  });
120424
121966
 
120425
121967
  // src/cli.ts
120426
- var import_node_fs32 = require("node:fs");
121968
+ var import_node_fs33 = require("node:fs");
120427
121969
  var import_node_os14 = require("node:os");
120428
121970
  var import_node_path39 = require("node:path");
120429
121971
  init_daemon();
@@ -120493,7 +122035,7 @@ init_sentry_config();
120493
122035
  init_runtime_metadata();
120494
122036
  var CURRENT_GATEWAY_SESSION_KEYS_ENV4 = "OKX_A2A_CURRENT_GATEWAY_SESSION_KEYS";
120495
122037
  function printUsage3() {
120496
- console.log(`okx-a2a ${"0.2.16"}
122038
+ console.log(`okx-a2a ${"0.2.17-beta-ab42219842-261020165552"}
120497
122039
 
120498
122040
  Usage:
120499
122041
  okx-a2a <command> [options]
@@ -120526,6 +122068,7 @@ Commands:
120526
122068
  trade-records
120527
122069
  Insert, query, and soft-delete local business trade records
120528
122070
  capabilities Print machine-readable A2A capability negotiation status (used by OnchainOS)
122071
+ devkit Register/unregister a local custom server for daemon message delivery
120529
122072
 
120530
122073
  Global options:
120531
122074
  -h, --help Show help
@@ -120535,7 +122078,7 @@ Run \`okx-a2a <command> -h\` for command-specific help.
120535
122078
  `);
120536
122079
  }
120537
122080
  function printVersion() {
120538
- console.log("0.2.16");
122081
+ console.log("0.2.17-beta-ab42219842-261020165552");
120539
122082
  }
120540
122083
  function printDaemonUsage() {
120541
122084
  console.log(`Usage: okx-a2a daemon <start|restart|stop|status|autostart> [options]
@@ -120803,11 +122346,11 @@ Commands:
120803
122346
  Print setup status JSON to stdout. Installer logs are written to stderr.
120804
122347
  `);
120805
122348
  }
120806
- function isHelpArg5(value) {
122349
+ function isHelpArg6(value) {
120807
122350
  return value === "-h" || value === "--help" || value === "help";
120808
122351
  }
120809
122352
  function hasHelpFlag5(args) {
120810
- return args.some(isHelpArg5);
122353
+ return args.some(isHelpArg6);
120811
122354
  }
120812
122355
  function isVersionArg(value) {
120813
122356
  return value === "-v" || value === "--version" || value === "version";
@@ -120834,14 +122377,14 @@ function maybeRedirectDaemonSelfLog() {
120834
122377
  }
120835
122378
  try {
120836
122379
  const logPath = resolveTaskPaths().listenerLogPath;
120837
- (0, import_node_fs32.mkdirSync)((0, import_node_path39.join)(logPath, ".."), { recursive: true });
120838
- const fd = (0, import_node_fs32.openSync)(logPath, "a");
122380
+ (0, import_node_fs33.mkdirSync)((0, import_node_path39.join)(logPath, ".."), { recursive: true });
122381
+ const fd = (0, import_node_fs33.openSync)(logPath, "a");
120839
122382
  const writeToLog = ((chunk, encoding, cb) => {
120840
122383
  try {
120841
122384
  if (typeof chunk === "string") {
120842
- (0, import_node_fs32.writeSync)(fd, chunk);
122385
+ (0, import_node_fs33.writeSync)(fd, chunk);
120843
122386
  } else {
120844
- (0, import_node_fs32.writeSync)(fd, chunk);
122387
+ (0, import_node_fs33.writeSync)(fd, chunk);
120845
122388
  }
120846
122389
  } catch {
120847
122390
  }
@@ -121191,12 +122734,12 @@ async function queueXmtpDaemonCommand(args, type) {
121191
122734
  }
121192
122735
  async function handleTaskCommand(args) {
121193
122736
  const subcommand = args[0];
121194
- if (!subcommand || args.every(isHelpArg5)) {
122737
+ if (!subcommand || args.every(isHelpArg6)) {
121195
122738
  printTaskUsage();
121196
122739
  return;
121197
122740
  }
121198
122741
  if (subcommand === "help") {
121199
- const helpTarget = args.slice(1).find((arg) => !isHelpArg5(arg));
122742
+ const helpTarget = args.slice(1).find((arg) => !isHelpArg6(arg));
121200
122743
  if (!helpTarget) {
121201
122744
  printTaskUsage();
121202
122745
  return;
@@ -121885,10 +123428,10 @@ async function initDirectCliSentry() {
121885
123428
  cliSentryInitAttempted = true;
121886
123429
  try {
121887
123430
  const configPath = (0, import_node_path39.join)(resolveTaskHomeForSentryConfig(), "xmtp", "system-config.json");
121888
- if (!(0, import_node_fs32.existsSync)(configPath)) {
123431
+ if (!(0, import_node_fs33.existsSync)(configPath)) {
121889
123432
  return;
121890
123433
  }
121891
- const config = JSON.parse((0, import_node_fs32.readFileSync)(configPath, "utf8"));
123434
+ const config = JSON.parse((0, import_node_fs33.readFileSync)(configPath, "utf8"));
121892
123435
  if (typeof config.sentryDsn !== "string" || !config.sentryDsn) {
121893
123436
  return;
121894
123437
  }
@@ -121950,7 +123493,7 @@ async function main() {
121950
123493
  assertSupportedNodeVersion();
121951
123494
  }
121952
123495
  const args = process.argv.slice(3);
121953
- if (isHelpArg5(command)) {
123496
+ if (isHelpArg6(command)) {
121954
123497
  printUsage3();
121955
123498
  return;
121956
123499
  }
@@ -121971,6 +123514,15 @@ async function main() {
121971
123514
  await handleTradeRecordsCommand2(args);
121972
123515
  return;
121973
123516
  }
123517
+ if (command === "devkit") {
123518
+ const { handleDevkitCommand: handleDevkitCommand2, printDevkitUsage: printDevkitUsage2 } = await Promise.resolve().then(() => (init_devkit_cli(), devkit_cli_exports));
123519
+ if (hasHelpFlag5(args)) {
123520
+ printDevkitUsage2();
123521
+ return;
123522
+ }
123523
+ await handleDevkitCommand2(args);
123524
+ return;
123525
+ }
121974
123526
  if (command === "daemon") {
121975
123527
  if (hasHelpFlag5(args)) {
121976
123528
  printDaemonUsage();
@@ -122030,7 +123582,7 @@ async function main() {
122030
123582
  if (command === "xmtp-test") {
122031
123583
  const { handleXmtpTestCommand: handleXmtpTestCommand2 } = await Promise.resolve().then(() => (init_xmtp_test_cli(), xmtp_test_cli_exports));
122032
123584
  await handleXmtpTestCommand2(process.argv.slice(3), {
122033
- packageVersion: "0.2.16",
123585
+ packageVersion: "0.2.17-beta-ab42219842-261020165552",
122034
123586
  agentSdkVersion: "2.3.0",
122035
123587
  nodeSdkVersion: "6.1.0",
122036
123588
  nodeBindingsVersion: "1.11.0"
@@ -122136,12 +123688,12 @@ function shouldDeferHelpToNestedHandler(command, args) {
122136
123688
  return true;
122137
123689
  }
122138
123690
  if (command === "trade-records") {
122139
- return args.some((arg) => !isHelpArg5(arg));
123691
+ return args.some((arg) => !isHelpArg6(arg));
122140
123692
  }
122141
123693
  if (command !== "session" && command !== "user" && command !== "task") {
122142
123694
  return false;
122143
123695
  }
122144
- return args.some((arg) => !isHelpArg5(arg));
123696
+ return args.some((arg) => !isHelpArg6(arg));
122145
123697
  }
122146
123698
  main().then(() => {
122147
123699
  if (cliSentryFlushTimedOut) {