clawdentity 0.0.4 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bin.js CHANGED
@@ -18495,9 +18495,9 @@ var createConfigCommand = () => {
18495
18495
 
18496
18496
  // src/commands/connector.ts
18497
18497
  import { execFile as execFileCallback } from "child_process";
18498
- import { mkdir as mkdir4, readFile as readFile4, rm, writeFile as writeFile4 } from "fs/promises";
18498
+ import { mkdir as mkdir4, readFile as readFile3, rm, writeFile as writeFile4 } from "fs/promises";
18499
18499
  import { homedir as homedir2 } from "os";
18500
- import { dirname as dirname3, join as join6 } from "path";
18500
+ import { dirname as dirname3, join as join5 } from "path";
18501
18501
  import { fileURLToPath } from "url";
18502
18502
  import { promisify } from "util";
18503
18503
 
@@ -19151,271 +19151,15 @@ import { mkdir as mkdir3, rename as rename2, writeFile as writeFile3 } from "fs/
19151
19151
  import {
19152
19152
  createServer
19153
19153
  } from "http";
19154
- import { dirname as dirname2, join as join5 } from "path";
19154
+ import { dirname as dirname2, join as join4 } from "path";
19155
19155
  import { WebSocket as NodeWebSocket } from "ws";
19156
-
19157
- // ../../packages/connector/src/relay-echo.ts
19158
- import { readFile as readFile3 } from "fs/promises";
19159
- import { join as join4 } from "path";
19160
- var OPENCLAW_RELAY_RUNTIME_CONFIG_FILENAME = "openclaw-relay.json";
19161
- var PEERS_CONFIG_FILENAME = "peers.json";
19162
- var ECHO_EMPTY_MESSAGE_FALLBACK = "(no message content)";
19163
- var MIN_ECHO_MAX_LENGTH = 50;
19164
- var MAX_ECHO_MAX_LENGTH = 2e3;
19165
- var DEFAULT_RELAY_ECHO_ENABLED = true;
19166
- var DEFAULT_RELAY_ECHO_CHANNEL = "last";
19167
- var DEFAULT_RELAY_ECHO_MAX_LENGTH = 500;
19168
- function isRecord4(value) {
19169
- return typeof value === "object" && value !== null;
19170
- }
19171
- function parseAbsoluteHttpUrl(value, field) {
19172
- if (typeof value !== "string" || value.trim().length === 0) {
19173
- throw new Error(`${field} must be a non-empty string`);
19174
- }
19175
- let parsed;
19176
- try {
19177
- parsed = new URL(value.trim());
19178
- } catch {
19179
- throw new Error(`${field} must be a valid absolute URL`);
19180
- }
19181
- if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
19182
- throw new Error(`${field} must use http or https`);
19183
- }
19184
- if (parsed.pathname === "/" && parsed.search.length === 0 && parsed.hash.length === 0) {
19185
- return parsed.origin;
19186
- }
19187
- return parsed.toString();
19188
- }
19189
- function parseBoolean(value, field) {
19190
- if (typeof value !== "boolean") {
19191
- throw new Error(`${field} must be a boolean`);
19192
- }
19193
- return value;
19194
- }
19195
- function parsePositiveInt(value, field, min, max) {
19196
- const parsed = typeof value === "number" ? value : typeof value === "string" ? Number(value) : Number.NaN;
19197
- if (!Number.isInteger(parsed) || parsed < min || parsed > max) {
19198
- throw new Error(`${field} must be an integer between ${min} and ${max}`);
19199
- }
19200
- return parsed;
19201
- }
19202
- function parseOptionalString(value, field) {
19203
- if (value === void 0) {
19204
- return void 0;
19205
- }
19206
- if (typeof value !== "string") {
19207
- throw new Error(`${field} must be a string`);
19208
- }
19209
- const trimmed = value.trim();
19210
- if (trimmed.length === 0) {
19211
- return void 0;
19212
- }
19213
- return trimmed;
19214
- }
19215
- function parseEchoConfig(value) {
19216
- if (value === void 0) {
19217
- return {
19218
- enabled: DEFAULT_RELAY_ECHO_ENABLED,
19219
- channel: DEFAULT_RELAY_ECHO_CHANNEL,
19220
- maxLength: DEFAULT_RELAY_ECHO_MAX_LENGTH
19221
- };
19222
- }
19223
- if (!isRecord4(value)) {
19224
- throw new Error("echo config must be an object");
19225
- }
19226
- return {
19227
- enabled: value.enabled === void 0 ? DEFAULT_RELAY_ECHO_ENABLED : parseBoolean(value.enabled, "echo.enabled"),
19228
- channel: parseOptionalString(value.channel, "echo.channel") ?? DEFAULT_RELAY_ECHO_CHANNEL,
19229
- to: parseOptionalString(value.to, "echo.to"),
19230
- maxLength: value.maxLength === void 0 ? DEFAULT_RELAY_ECHO_MAX_LENGTH : parsePositiveInt(
19231
- value.maxLength,
19232
- "echo.maxLength",
19233
- MIN_ECHO_MAX_LENGTH,
19234
- MAX_ECHO_MAX_LENGTH
19235
- )
19236
- };
19237
- }
19238
- async function loadRelayRuntimeConfigFile(input) {
19239
- const relayRuntimeConfigPath = join4(
19240
- input.configDir,
19241
- OPENCLAW_RELAY_RUNTIME_CONFIG_FILENAME
19242
- );
19243
- let raw;
19244
- try {
19245
- raw = await readFile3(relayRuntimeConfigPath, "utf8");
19246
- } catch (error48) {
19247
- if (typeof error48 === "object" && error48 !== null && "code" in error48 && error48.code === "ENOENT") {
19248
- return void 0;
19249
- }
19250
- throw new Error(
19251
- `Unable to read relay runtime config at ${relayRuntimeConfigPath}`
19252
- );
19253
- }
19254
- let parsed;
19255
- try {
19256
- parsed = JSON.parse(raw);
19257
- } catch {
19258
- throw new Error(
19259
- `Unable to parse relay runtime config at ${relayRuntimeConfigPath}`
19260
- );
19261
- }
19262
- if (!isRecord4(parsed)) {
19263
- throw new Error("Relay runtime config root must be a JSON object");
19264
- }
19265
- const config2 = parsed;
19266
- const openclawBaseUrl = config2.openclawBaseUrl === void 0 ? void 0 : parseAbsoluteHttpUrl(config2.openclawBaseUrl, "openclawBaseUrl");
19267
- return {
19268
- openclawBaseUrl,
19269
- echo: parseEchoConfig(config2.echo)
19270
- };
19271
- }
19272
- function compactString(value) {
19273
- return value.replaceAll(/\s+/g, " ").trim();
19274
- }
19275
- function toCompactJson(value) {
19276
- try {
19277
- const raw = JSON.stringify(value);
19278
- if (typeof raw !== "string" || raw.length === 0) {
19279
- return ECHO_EMPTY_MESSAGE_FALLBACK;
19280
- }
19281
- return raw;
19282
- } catch {
19283
- return ECHO_EMPTY_MESSAGE_FALLBACK;
19284
- }
19285
- }
19286
- function truncateMessage(value, maxLength) {
19287
- if (value.length <= maxLength) {
19288
- return value;
19289
- }
19290
- return `${value.slice(0, maxLength)}...`;
19291
- }
19292
- function extractRelayMessageContent(payload) {
19293
- if (typeof payload === "string") {
19294
- const compact = compactString(payload);
19295
- return compact.length > 0 ? compact : ECHO_EMPTY_MESSAGE_FALLBACK;
19296
- }
19297
- if (isRecord4(payload)) {
19298
- for (const candidateKey of ["message", "text", "content"]) {
19299
- const candidateValue = payload[candidateKey];
19300
- if (typeof candidateValue === "string") {
19301
- const compact = compactString(candidateValue);
19302
- if (compact.length > 0) {
19303
- return compact;
19304
- }
19305
- }
19306
- }
19307
- }
19308
- return toCompactJson(payload);
19309
- }
19310
- function formatInboundRelayEcho(input) {
19311
- const content = truncateMessage(
19312
- extractRelayMessageContent(input.payload),
19313
- input.maxLength
19314
- );
19315
- return `\u{1F517} [${input.fromLabel}]: ${content}`;
19316
- }
19317
- function formatOutboundRelayEcho(input) {
19318
- const content = truncateMessage(
19319
- extractRelayMessageContent(input.payload),
19320
- input.maxLength
19321
- );
19322
- return `\u21A9\uFE0F Reply to [${input.toLabel}]: ${content}`;
19323
- }
19324
- async function loadPeerLabelsByDid(input) {
19325
- const peersPath = join4(input.configDir, PEERS_CONFIG_FILENAME);
19326
- let raw;
19327
- try {
19328
- raw = await readFile3(peersPath, "utf8");
19329
- } catch (error48) {
19330
- if (typeof error48 === "object" && error48 !== null && "code" in error48 && error48.code === "ENOENT") {
19331
- return /* @__PURE__ */ new Map();
19332
- }
19333
- throw new Error(`Unable to read peers config at ${peersPath}`);
19334
- }
19335
- let parsed;
19336
- try {
19337
- parsed = JSON.parse(raw);
19338
- } catch {
19339
- throw new Error(`Unable to parse peers config at ${peersPath}`);
19340
- }
19341
- if (!isRecord4(parsed) || !isRecord4(parsed.peers)) {
19342
- return /* @__PURE__ */ new Map();
19343
- }
19344
- const labels = /* @__PURE__ */ new Map();
19345
- for (const [alias, entry] of Object.entries(parsed.peers)) {
19346
- if (!isRecord4(entry) || typeof entry.did !== "string") {
19347
- continue;
19348
- }
19349
- const did = entry.did.trim();
19350
- if (did.length === 0) {
19351
- continue;
19352
- }
19353
- const name = typeof entry.name === "string" && entry.name.trim().length > 0 ? entry.name.trim() : alias.trim();
19354
- if (name.length === 0) {
19355
- continue;
19356
- }
19357
- labels.set(did, name);
19358
- }
19359
- return labels;
19360
- }
19361
- function resolvePeerLabel(input) {
19362
- if (input.peerDid !== void 0) {
19363
- const byDid = input.peerLabelsByDid.get(input.peerDid);
19364
- if (typeof byDid === "string" && byDid.length > 0) {
19365
- return byDid;
19366
- }
19367
- }
19368
- const fallback = input.fallbackLabel.trim();
19369
- if (fallback.length > 0) {
19370
- return fallback;
19371
- }
19372
- return input.peerDid?.trim() || "Unknown peer";
19373
- }
19374
- async function sendRelayEchoToOpenclaw(input) {
19375
- if (!input.echoConfig.enabled) {
19376
- return;
19377
- }
19378
- const payload = {
19379
- message: input.message,
19380
- name: "Clawdentity Relay",
19381
- wakeMode: "now",
19382
- deliver: true,
19383
- channel: input.echoConfig.channel
19384
- };
19385
- if (input.echoConfig.to !== void 0) {
19386
- payload.to = input.echoConfig.to;
19387
- }
19388
- const headers = {
19389
- "content-type": "application/json"
19390
- };
19391
- if (input.requestId !== void 0 && input.requestId.trim().length > 0) {
19392
- headers["x-request-id"] = input.requestId.trim();
19393
- }
19394
- if (input.hookToken !== void 0 && input.hookToken.trim().length > 0) {
19395
- headers["x-openclaw-token"] = input.hookToken.trim();
19396
- }
19397
- const response = await input.fetchImpl(input.endpoint, {
19398
- method: "POST",
19399
- headers,
19400
- body: JSON.stringify(payload)
19401
- });
19402
- if (!response.ok) {
19403
- input.logger.warn("connector.relay_echo.rejected", {
19404
- status: response.status,
19405
- requestId: input.requestId
19406
- });
19407
- throw new Error(`Relay echo rejected with status ${response.status}`);
19408
- }
19409
- }
19410
-
19411
- // ../../packages/connector/src/runtime.ts
19412
19156
  var REGISTRY_AUTH_FILENAME = "registry-auth.json";
19413
19157
  var AGENTS_DIR_NAME2 = "agents";
19414
19158
  var REFRESH_SINGLE_FLIGHT_PREFIX = "connector-runtime";
19415
19159
  var NONCE_SIZE = 16;
19416
19160
  var MAX_OUTBOUND_BODY_BYTES = 1024 * 1024;
19417
19161
  var ACCESS_TOKEN_REFRESH_SKEW_MS = 3e4;
19418
- function isRecord5(value) {
19162
+ function isRecord4(value) {
19419
19163
  return typeof value === "object" && value !== null;
19420
19164
  }
19421
19165
  function toPathWithQuery2(url2) {
@@ -19465,38 +19209,9 @@ function normalizeWebSocketUrl(urlInput) {
19465
19209
  }
19466
19210
  return parsed.toString();
19467
19211
  }
19468
- function parseOpenclawBaseUrl(value) {
19469
- let parsed;
19470
- try {
19471
- parsed = new URL(value);
19472
- } catch {
19473
- throw new Error("OpenClaw base URL is invalid");
19474
- }
19475
- if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
19476
- throw new Error("OpenClaw base URL is invalid");
19477
- }
19478
- if (parsed.pathname === "/" && parsed.search.length === 0 && parsed.hash.length === 0) {
19479
- return parsed.origin;
19480
- }
19481
- return parsed.toString();
19482
- }
19483
- async function resolveOpenclawRuntimeSettings(input) {
19484
- const fileConfig = await loadRelayRuntimeConfigFile({
19485
- configDir: input.configDir
19486
- });
19487
- const baseUrlFromOption = input.openclawBaseUrlOption?.trim();
19488
- const baseUrlFromEnv = process.env.OPENCLAW_BASE_URL?.trim();
19489
- const openclawBaseUrl = parseOpenclawBaseUrl(
19490
- baseUrlFromOption || baseUrlFromEnv || fileConfig?.openclawBaseUrl || DEFAULT_OPENCLAW_BASE_URL
19491
- );
19492
- return {
19493
- openclawBaseUrl,
19494
- echoConfig: fileConfig?.echo ?? {
19495
- enabled: DEFAULT_RELAY_ECHO_ENABLED,
19496
- channel: DEFAULT_RELAY_ECHO_CHANNEL,
19497
- maxLength: DEFAULT_RELAY_ECHO_MAX_LENGTH
19498
- }
19499
- };
19212
+ function resolveOpenclawBaseUrl(input) {
19213
+ const value = input?.trim() || process.env.OPENCLAW_BASE_URL?.trim() || DEFAULT_OPENCLAW_BASE_URL;
19214
+ return value;
19500
19215
  }
19501
19216
  function resolveOpenclawHookPath(input) {
19502
19217
  const value = input?.trim() || process.env.OPENCLAW_HOOK_PATH?.trim() || DEFAULT_OPENCLAW_HOOK_PATH;
@@ -19536,7 +19251,7 @@ function shouldRefreshAccessToken(auth, nowMs) {
19536
19251
  return expiresAtMs <= nowMs + ACCESS_TOKEN_REFRESH_SKEW_MS;
19537
19252
  }
19538
19253
  function parseOutboundRelayRequest(payload) {
19539
- if (!isRecord5(payload)) {
19254
+ if (!isRecord4(payload)) {
19540
19255
  throw new AppError({
19541
19256
  code: "CONNECTOR_OUTBOUND_INVALID_REQUEST",
19542
19257
  message: "Outbound relay request must be an object",
@@ -19594,7 +19309,7 @@ function createWebSocketFactory() {
19594
19309
  };
19595
19310
  }
19596
19311
  async function writeRegistryAuthAtomic(input) {
19597
- const targetPath = join5(
19312
+ const targetPath = join4(
19598
19313
  input.configDir,
19599
19314
  AGENTS_DIR_NAME2,
19600
19315
  input.agentName,
@@ -19691,63 +19406,14 @@ async function startConnectorRuntime(input) {
19691
19406
  accessToken: currentAuth.accessToken,
19692
19407
  secretKey
19693
19408
  });
19694
- const openclawRuntimeSettings = await resolveOpenclawRuntimeSettings({
19695
- configDir: input.configDir,
19696
- openclawBaseUrlOption: input.openclawBaseUrl
19697
- });
19698
- const peerLabelsByDid = await loadPeerLabelsByDid({
19699
- configDir: input.configDir
19700
- });
19701
- const openclawHookPath = resolveOpenclawHookPath(input.openclawHookPath);
19702
- const openclawHookToken = resolveOpenclawHookToken(input.openclawHookToken);
19703
- const openclawHookUrl = new URL(
19704
- openclawHookPath,
19705
- openclawRuntimeSettings.openclawBaseUrl
19706
- ).toString();
19707
- const queueRelayEcho = (echoInput) => {
19708
- void sendRelayEchoToOpenclaw({
19709
- endpoint: openclawHookUrl,
19710
- echoConfig: openclawRuntimeSettings.echoConfig,
19711
- fetchImpl,
19712
- hookToken: openclawHookToken,
19713
- logger: logger12,
19714
- message: echoInput.message,
19715
- requestId: echoInput.requestId
19716
- }).catch((error48) => {
19717
- logger12.warn("connector.relay_echo.failed", {
19718
- direction: echoInput.direction,
19719
- errorName: error48 instanceof Error ? error48.name : "unknown",
19720
- requestId: echoInput.requestId
19721
- });
19722
- });
19723
- };
19724
19409
  const connectorClient = new ConnectorClient({
19725
19410
  connectorUrl: wsParsed.toString(),
19726
19411
  connectionHeaders: upgradeHeaders,
19727
- openclawBaseUrl: openclawRuntimeSettings.openclawBaseUrl,
19728
- openclawHookPath,
19729
- openclawHookToken,
19412
+ openclawBaseUrl: resolveOpenclawBaseUrl(input.openclawBaseUrl),
19413
+ openclawHookPath: resolveOpenclawHookPath(input.openclawHookPath),
19414
+ openclawHookToken: resolveOpenclawHookToken(input.openclawHookToken),
19730
19415
  fetchImpl,
19731
19416
  logger: logger12,
19732
- hooks: {
19733
- onDeliverSucceeded: (frame) => {
19734
- const fromLabel = resolvePeerLabel({
19735
- peerLabelsByDid,
19736
- peerDid: frame.fromAgentDid,
19737
- fallbackLabel: frame.fromAgentDid
19738
- });
19739
- const echoMessage = formatInboundRelayEcho({
19740
- fromLabel,
19741
- payload: frame.payload,
19742
- maxLength: openclawRuntimeSettings.echoConfig.maxLength
19743
- });
19744
- queueRelayEcho({
19745
- direction: "inbound",
19746
- message: echoMessage,
19747
- requestId: frame.id
19748
- });
19749
- }
19750
- },
19751
19417
  webSocketFactory: createWebSocketFactory()
19752
19418
  });
19753
19419
  const outboundBaseUrl = normalizeOutboundBaseUrl(input.outboundBaseUrl);
@@ -19833,22 +19499,6 @@ async function startConnectorRuntime(input) {
19833
19499
  const requestBody = await readRequestJson(req);
19834
19500
  const relayRequest = parseOutboundRelayRequest(requestBody);
19835
19501
  await relayToPeer(relayRequest);
19836
- const toLabel = resolvePeerLabel({
19837
- peerLabelsByDid,
19838
- peerDid: relayRequest.peerDid,
19839
- fallbackLabel: relayRequest.peer
19840
- });
19841
- const requestId = typeof req.headers["x-request-id"] === "string" ? req.headers["x-request-id"] : void 0;
19842
- const echoMessage = formatOutboundRelayEcho({
19843
- toLabel,
19844
- payload: relayRequest.payload,
19845
- maxLength: openclawRuntimeSettings.echoConfig.maxLength
19846
- });
19847
- queueRelayEcho({
19848
- direction: "outbound",
19849
- message: echoMessage,
19850
- requestId
19851
- });
19852
19502
  writeJson(res, 202, { accepted: true, peer: relayRequest.peer });
19853
19503
  } catch (error48) {
19854
19504
  if (error48 instanceof AppError) {
@@ -19927,14 +19577,16 @@ var IDENTITY_FILE_NAME2 = "identity.json";
19927
19577
  var AIT_FILE_NAME2 = "ait.jwt";
19928
19578
  var SECRET_KEY_FILE_NAME = "secret.key";
19929
19579
  var REGISTRY_AUTH_FILE_NAME2 = "registry-auth.json";
19580
+ var OPENCLAW_RELAY_RUNTIME_FILE_NAME = "openclaw-relay.json";
19581
+ var OPENCLAW_CONNECTORS_FILE_NAME = "openclaw-connectors.json";
19930
19582
  var SERVICE_LOG_DIR_NAME = "logs";
19931
19583
  var DEFAULT_CONNECTOR_BASE_URL2 = "http://127.0.0.1:19400";
19932
19584
  var DEFAULT_CONNECTOR_OUTBOUND_PATH2 = "/v1/outbound";
19933
- function isRecord6(value) {
19585
+ function isRecord5(value) {
19934
19586
  return typeof value === "object" && value !== null;
19935
19587
  }
19936
19588
  function getErrorCode(error48) {
19937
- if (!isRecord6(error48)) {
19589
+ if (!isRecord5(error48)) {
19938
19590
  return void 0;
19939
19591
  }
19940
19592
  return typeof error48.code === "string" ? error48.code : void 0;
@@ -20010,13 +19662,43 @@ function normalizeOutboundPath2(pathValue) {
20010
19662
  }
20011
19663
  return trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
20012
19664
  }
20013
- function resolveConnectorBaseUrl() {
19665
+ function resolveConnectorBaseUrlFromEnv() {
20014
19666
  const value = process.env.CLAWDENTITY_CONNECTOR_BASE_URL;
20015
19667
  if (typeof value !== "string" || value.trim().length === 0) {
20016
- return DEFAULT_CONNECTOR_BASE_URL2;
19668
+ return void 0;
20017
19669
  }
20018
19670
  return parseConnectorBaseUrl(value.trim());
20019
19671
  }
19672
+ async function readConnectorAssignedBaseUrl(configDir, agentName, readFileImpl) {
19673
+ const assignmentsPath = join5(configDir, OPENCLAW_CONNECTORS_FILE_NAME);
19674
+ let raw;
19675
+ try {
19676
+ raw = await readFileImpl(assignmentsPath, "utf8");
19677
+ } catch (error48) {
19678
+ if (getErrorCode(error48) === "ENOENT") {
19679
+ return void 0;
19680
+ }
19681
+ throw error48;
19682
+ }
19683
+ let parsed;
19684
+ try {
19685
+ parsed = JSON.parse(raw);
19686
+ } catch {
19687
+ throw createCliError3(
19688
+ "CLI_CONNECTOR_INVALID_ASSIGNMENTS",
19689
+ "Connector assignments config is invalid JSON",
19690
+ { assignmentsPath }
19691
+ );
19692
+ }
19693
+ if (!isRecord5(parsed) || !isRecord5(parsed.agents)) {
19694
+ return void 0;
19695
+ }
19696
+ const entry = parsed.agents[agentName];
19697
+ if (!isRecord5(entry) || typeof entry.connectorBaseUrl !== "string") {
19698
+ return void 0;
19699
+ }
19700
+ return parseConnectorBaseUrl(entry.connectorBaseUrl);
19701
+ }
20020
19702
  function resolveConnectorOutboundPath() {
20021
19703
  const value = process.env.CLAWDENTITY_CONNECTOR_OUTBOUND_PATH;
20022
19704
  if (typeof value !== "string" || value.trim().length === 0) {
@@ -20051,6 +19733,34 @@ async function readRequiredTrimmedFile(filePath, label, readFileImpl) {
20051
19733
  }
20052
19734
  return trimmed;
20053
19735
  }
19736
+ async function readRelayRuntimeConfig(configDir, readFileImpl) {
19737
+ const filePath = join5(configDir, OPENCLAW_RELAY_RUNTIME_FILE_NAME);
19738
+ let raw;
19739
+ try {
19740
+ raw = await readFileImpl(filePath, "utf8");
19741
+ } catch (error48) {
19742
+ if (getErrorCode(error48) === "ENOENT") {
19743
+ return void 0;
19744
+ }
19745
+ throw error48;
19746
+ }
19747
+ let parsed;
19748
+ try {
19749
+ parsed = JSON.parse(raw);
19750
+ } catch {
19751
+ return void 0;
19752
+ }
19753
+ if (!isRecord5(parsed)) {
19754
+ return void 0;
19755
+ }
19756
+ const openclawHookToken = typeof parsed.openclawHookToken === "string" && parsed.openclawHookToken.trim().length > 0 ? parsed.openclawHookToken.trim() : void 0;
19757
+ if (!openclawHookToken) {
19758
+ return void 0;
19759
+ }
19760
+ return {
19761
+ openclawHookToken
19762
+ };
19763
+ }
20054
19764
  function parseJsonRecord(value, code, message2) {
20055
19765
  let parsed;
20056
19766
  try {
@@ -20058,7 +19768,7 @@ function parseJsonRecord(value, code, message2) {
20058
19768
  } catch {
20059
19769
  throw createCliError3(code, message2);
20060
19770
  }
20061
- if (!isRecord6(parsed)) {
19771
+ if (!isRecord5(parsed)) {
20062
19772
  throw createCliError3(code, message2);
20063
19773
  }
20064
19774
  return parsed;
@@ -20098,7 +19808,7 @@ async function loadDefaultConnectorModule() {
20098
19808
  };
20099
19809
  }
20100
19810
  function resolveWaitPromise(runtime) {
20101
- if (!runtime || !isRecord6(runtime)) {
19811
+ if (!runtime || !isRecord5(runtime)) {
20102
19812
  return void 0;
20103
19813
  }
20104
19814
  if (typeof runtime.waitUntilStopped === "function") {
@@ -20163,7 +19873,7 @@ function buildConnectorStartArgs(agentName, commandOptions) {
20163
19873
  }
20164
19874
  function resolveCliEntryPath(resolveCurrentModulePathImpl) {
20165
19875
  const modulePath = resolveCurrentModulePathImpl?.() ?? fileURLToPath(import.meta.url);
20166
- return join6(dirname3(modulePath), "..", "bin.js");
19876
+ return join5(dirname3(modulePath), "..", "bin.js");
20167
19877
  }
20168
19878
  function escapeXml(value) {
20169
19879
  return value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&apos;");
@@ -20261,7 +19971,7 @@ async function installConnectorServiceForAgent(agentName, commandOptions = {}, d
20261
19971
  );
20262
19972
  const configDir = serviceDependencies.getConfigDirImpl();
20263
19973
  const homeDir = serviceDependencies.getHomeDirImpl();
20264
- const logsDir = join6(configDir, SERVICE_LOG_DIR_NAME);
19974
+ const logsDir = join5(configDir, SERVICE_LOG_DIR_NAME);
20265
19975
  const serviceName = sanitizeServiceSegment(
20266
19976
  `clawdentity-connector-${agentName}`
20267
19977
  );
@@ -20271,12 +19981,12 @@ async function installConnectorServiceForAgent(agentName, commandOptions = {}, d
20271
19981
  resolveCliEntryPath(serviceDependencies.resolveCurrentModulePathImpl),
20272
19982
  ...startArgs
20273
19983
  ];
20274
- const outputLogPath = join6(logsDir, `${serviceName}.out.log`);
20275
- const errorLogPath = join6(logsDir, `${serviceName}.err.log`);
19984
+ const outputLogPath = join5(logsDir, `${serviceName}.out.log`);
19985
+ const errorLogPath = join5(logsDir, `${serviceName}.err.log`);
20276
19986
  await serviceDependencies.mkdirImpl(logsDir, { recursive: true });
20277
19987
  if (platform === "systemd") {
20278
- const serviceDir = join6(homeDir, ".config", "systemd", "user");
20279
- const serviceFilePath2 = join6(serviceDir, `${serviceName}.service`);
19988
+ const serviceDir = join5(homeDir, ".config", "systemd", "user");
19989
+ const serviceFilePath2 = join5(serviceDir, `${serviceName}.service`);
20280
19990
  await serviceDependencies.mkdirImpl(serviceDir, { recursive: true });
20281
19991
  await serviceDependencies.writeFileImpl(
20282
19992
  serviceFilePath2,
@@ -20315,9 +20025,9 @@ async function installConnectorServiceForAgent(agentName, commandOptions = {}, d
20315
20025
  serviceFilePath: serviceFilePath2
20316
20026
  };
20317
20027
  }
20318
- const launchAgentsDir = join6(homeDir, "Library", "LaunchAgents");
20028
+ const launchAgentsDir = join5(homeDir, "Library", "LaunchAgents");
20319
20029
  const serviceNameWithDomain = `com.clawdentity.${serviceName}`;
20320
- const serviceFilePath = join6(
20030
+ const serviceFilePath = join5(
20321
20031
  launchAgentsDir,
20322
20032
  `${serviceNameWithDomain}.plist`
20323
20033
  );
@@ -20376,7 +20086,7 @@ async function uninstallConnectorServiceForAgent(agentName, commandOptions = {},
20376
20086
  `clawdentity-connector-${agentName}`
20377
20087
  );
20378
20088
  if (platform === "systemd") {
20379
- const serviceFilePath2 = join6(
20089
+ const serviceFilePath2 = join5(
20380
20090
  homeDir,
20381
20091
  ".config",
20382
20092
  "systemd",
@@ -20407,7 +20117,7 @@ async function uninstallConnectorServiceForAgent(agentName, commandOptions = {},
20407
20117
  };
20408
20118
  }
20409
20119
  const serviceNameWithDomain = `com.clawdentity.${serviceName}`;
20410
- const serviceFilePath = join6(
20120
+ const serviceFilePath = join5(
20411
20121
  homeDir,
20412
20122
  "Library",
20413
20123
  "LaunchAgents",
@@ -20431,38 +20141,42 @@ async function uninstallConnectorServiceForAgent(agentName, commandOptions = {},
20431
20141
  async function startConnectorForAgent(agentName, commandOptions = {}, dependencies = {}) {
20432
20142
  const resolveConfigImpl = dependencies.resolveConfigImpl ?? resolveConfig;
20433
20143
  const getConfigDirImpl = dependencies.getConfigDirImpl ?? getConfigDir;
20434
- const readFileImpl = dependencies.readFileImpl ?? ((path, encoding) => readFile4(path, encoding));
20144
+ const readFileImpl = dependencies.readFileImpl ?? ((path, encoding) => readFile3(path, encoding));
20435
20145
  const loadConnectorModule = dependencies.loadConnectorModule ?? loadDefaultConnectorModule;
20436
20146
  const configDir = getConfigDirImpl();
20437
- const agentDirectory = join6(configDir, AGENTS_DIR_NAME3, agentName);
20147
+ const agentDirectory = join5(configDir, AGENTS_DIR_NAME3, agentName);
20438
20148
  const [
20439
20149
  rawAit,
20440
20150
  rawSecretKey,
20441
20151
  rawIdentity,
20442
20152
  rawRegistryAuth,
20153
+ assignedConnectorBaseUrl,
20154
+ relayRuntimeConfig,
20443
20155
  config2,
20444
20156
  connectorModule
20445
20157
  ] = await Promise.all([
20446
20158
  readRequiredTrimmedFile(
20447
- join6(agentDirectory, AIT_FILE_NAME2),
20159
+ join5(agentDirectory, AIT_FILE_NAME2),
20448
20160
  AIT_FILE_NAME2,
20449
20161
  readFileImpl
20450
20162
  ),
20451
20163
  readRequiredTrimmedFile(
20452
- join6(agentDirectory, SECRET_KEY_FILE_NAME),
20164
+ join5(agentDirectory, SECRET_KEY_FILE_NAME),
20453
20165
  SECRET_KEY_FILE_NAME,
20454
20166
  readFileImpl
20455
20167
  ),
20456
20168
  readRequiredTrimmedFile(
20457
- join6(agentDirectory, IDENTITY_FILE_NAME2),
20169
+ join5(agentDirectory, IDENTITY_FILE_NAME2),
20458
20170
  IDENTITY_FILE_NAME2,
20459
20171
  readFileImpl
20460
20172
  ),
20461
20173
  readRequiredTrimmedFile(
20462
- join6(agentDirectory, REGISTRY_AUTH_FILE_NAME2),
20174
+ join5(agentDirectory, REGISTRY_AUTH_FILE_NAME2),
20463
20175
  REGISTRY_AUTH_FILE_NAME2,
20464
20176
  readFileImpl
20465
20177
  ),
20178
+ readConnectorAssignedBaseUrl(configDir, agentName, readFileImpl),
20179
+ readRelayRuntimeConfig(configDir, readFileImpl),
20466
20180
  resolveConfigImpl(),
20467
20181
  loadConnectorModule()
20468
20182
  ]);
@@ -20474,7 +20188,8 @@ async function startConnectorForAgent(agentName, commandOptions = {}, dependenci
20474
20188
  }
20475
20189
  const identity = parseAgentIdentity(rawIdentity);
20476
20190
  const registryAuth = parseRegistryAuth(rawRegistryAuth);
20477
- const outboundBaseUrl = resolveConnectorBaseUrl();
20191
+ const openclawHookToken = commandOptions.openclawHookToken ?? relayRuntimeConfig?.openclawHookToken;
20192
+ const outboundBaseUrl = resolveConnectorBaseUrlFromEnv() ?? assignedConnectorBaseUrl ?? DEFAULT_CONNECTOR_BASE_URL2;
20478
20193
  const outboundPath = resolveConnectorOutboundPath();
20479
20194
  const runtime = await connectorModule.startConnectorRuntime({
20480
20195
  agentName,
@@ -20485,7 +20200,7 @@ async function startConnectorForAgent(agentName, commandOptions = {}, dependenci
20485
20200
  proxyWebsocketUrl: commandOptions.proxyWsUrl,
20486
20201
  openclawBaseUrl: commandOptions.openclawBaseUrl,
20487
20202
  openclawHookPath: commandOptions.openclawHookPath,
20488
- openclawHookToken: commandOptions.openclawHookToken,
20203
+ openclawHookToken,
20489
20204
  credentials: {
20490
20205
  agentDid: identity.did,
20491
20206
  ait: rawAit,
@@ -20497,8 +20212,8 @@ async function startConnectorForAgent(agentName, commandOptions = {}, dependenci
20497
20212
  tokenType: registryAuth.tokenType
20498
20213
  }
20499
20214
  });
20500
- const outboundUrl = runtime && isRecord6(runtime) && typeof runtime.outboundUrl === "string" ? runtime.outboundUrl : resolveOutboundUrl(outboundBaseUrl, outboundPath);
20501
- const proxyWebsocketUrl = runtime && isRecord6(runtime) ? typeof runtime.websocketUrl === "string" ? runtime.websocketUrl : typeof runtime.proxyWebsocketUrl === "string" ? runtime.proxyWebsocketUrl : void 0 : void 0;
20215
+ const outboundUrl = runtime && isRecord5(runtime) && typeof runtime.outboundUrl === "string" ? runtime.outboundUrl : resolveOutboundUrl(outboundBaseUrl, outboundPath);
20216
+ const proxyWebsocketUrl = runtime && isRecord5(runtime) ? typeof runtime.websocketUrl === "string" ? runtime.websocketUrl : typeof runtime.proxyWebsocketUrl === "string" ? runtime.proxyWebsocketUrl : void 0 : void 0;
20502
20217
  return {
20503
20218
  outboundUrl,
20504
20219
  proxyWebsocketUrl,
@@ -20629,7 +20344,7 @@ function createConnectorCommand(dependencies = {}) {
20629
20344
  // src/commands/invite.ts
20630
20345
  import { Command as Command6 } from "commander";
20631
20346
  var logger7 = createLogger({ service: "cli", module: "invite" });
20632
- var isRecord7 = (value) => {
20347
+ var isRecord6 = (value) => {
20633
20348
  return typeof value === "object" && value !== null;
20634
20349
  };
20635
20350
  function parseNonEmptyString6(value) {
@@ -20670,7 +20385,7 @@ function toRegistryRequestUrl(registryUrl, path) {
20670
20385
  return new URL(path.slice(1), normalizedBaseUrl).toString();
20671
20386
  }
20672
20387
  function extractRegistryErrorCode(payload) {
20673
- if (!isRecord7(payload)) {
20388
+ if (!isRecord6(payload)) {
20674
20389
  return void 0;
20675
20390
  }
20676
20391
  const envelope = payload;
@@ -20681,7 +20396,7 @@ function extractRegistryErrorCode(payload) {
20681
20396
  return trimmed.length > 0 ? trimmed : void 0;
20682
20397
  }
20683
20398
  function extractRegistryErrorMessage3(payload) {
20684
- if (!isRecord7(payload)) {
20399
+ if (!isRecord6(payload)) {
20685
20400
  return void 0;
20686
20401
  }
20687
20402
  const envelope = payload;
@@ -20755,13 +20470,13 @@ function mapRedeemInviteError(status, payload) {
20755
20470
  return `Invite redeem failed (${status})`;
20756
20471
  }
20757
20472
  function parseInviteRecord(payload) {
20758
- if (!isRecord7(payload)) {
20473
+ if (!isRecord6(payload)) {
20759
20474
  throw createCliError4(
20760
20475
  "CLI_INVITE_CREATE_INVALID_RESPONSE",
20761
20476
  "Invite response is invalid"
20762
20477
  );
20763
20478
  }
20764
- const source = isRecord7(payload.invite) ? payload.invite : payload;
20479
+ const source = isRecord6(payload.invite) ? payload.invite : payload;
20765
20480
  const code = parseNonEmptyString6(source.code);
20766
20481
  if (code.length === 0) {
20767
20482
  throw createCliError4(
@@ -20786,15 +20501,15 @@ function parseInviteRecord(payload) {
20786
20501
  return invite;
20787
20502
  }
20788
20503
  function parseInviteRedeemResponse(payload) {
20789
- if (!isRecord7(payload)) {
20504
+ if (!isRecord6(payload)) {
20790
20505
  throw createCliError4(
20791
20506
  "CLI_INVITE_REDEEM_INVALID_RESPONSE",
20792
20507
  "Invite redeem response is invalid"
20793
20508
  );
20794
20509
  }
20795
- const apiKeySource = isRecord7(payload.apiKey) ? payload.apiKey : payload;
20510
+ const apiKeySource = isRecord6(payload.apiKey) ? payload.apiKey : payload;
20796
20511
  const apiKeyToken = parseNonEmptyString6(
20797
- isRecord7(payload.apiKey) ? payload.apiKey.token : payload.token
20512
+ isRecord6(payload.apiKey) ? payload.apiKey.token : payload.token
20798
20513
  );
20799
20514
  if (apiKeyToken.length === 0) {
20800
20515
  throw createCliError4(
@@ -20952,9 +20667,11 @@ var createInviteCommand = (dependencies = {}) => {
20952
20667
  };
20953
20668
 
20954
20669
  // src/commands/openclaw.ts
20955
- import { chmod as chmod3, copyFile, mkdir as mkdir5, readFile as readFile5, writeFile as writeFile5 } from "fs/promises";
20670
+ import { randomBytes as randomBytes3 } from "crypto";
20671
+ import { existsSync } from "fs";
20672
+ import { chmod as chmod3, copyFile, mkdir as mkdir5, readFile as readFile4, writeFile as writeFile5 } from "fs/promises";
20956
20673
  import { homedir as homedir3 } from "os";
20957
- import { dirname as dirname4, join as join7 } from "path";
20674
+ import { dirname as dirname4, join as join6, resolve as resolvePath } from "path";
20958
20675
  import { Command as Command7 } from "commander";
20959
20676
  var logger8 = createLogger({ service: "cli", module: "openclaw" });
20960
20677
  var CLAWDENTITY_DIR_NAME = ".clawdentity";
@@ -20964,25 +20681,32 @@ var SECRET_KEY_FILE_NAME2 = "secret.key";
20964
20681
  var PEERS_FILE_NAME = "peers.json";
20965
20682
  var OPENCLAW_DIR_NAME = ".openclaw";
20966
20683
  var OPENCLAW_CONFIG_FILE_NAME = "openclaw.json";
20684
+ var LEGACY_OPENCLAW_STATE_DIR_NAMES = [".clawdbot", ".moldbot", ".moltbot"];
20685
+ var LEGACY_OPENCLAW_CONFIG_FILE_NAMES = ["clawdbot.json", "moldbot.json", "moltbot.json"];
20967
20686
  var OPENCLAW_AGENT_FILE_NAME = "openclaw-agent-name";
20968
- var OPENCLAW_RELAY_RUNTIME_FILE_NAME = "openclaw-relay.json";
20687
+ var OPENCLAW_RELAY_RUNTIME_FILE_NAME2 = "openclaw-relay.json";
20688
+ var OPENCLAW_CONNECTORS_FILE_NAME2 = "openclaw-connectors.json";
20969
20689
  var SKILL_DIR_NAME = "clawdentity-openclaw-relay";
20970
20690
  var RELAY_MODULE_FILE_NAME = "relay-to-peer.mjs";
20691
+ var RELAY_RUNTIME_FILE_NAME = "clawdentity-relay.json";
20692
+ var RELAY_PEERS_FILE_NAME = "clawdentity-peers.json";
20971
20693
  var HOOK_MAPPING_ID = "clawdentity-send-to-peer";
20972
20694
  var HOOK_PATH_SEND_TO_PEER = "send-to-peer";
20973
20695
  var OPENCLAW_SEND_TO_PEER_HOOK_PATH = "hooks/send-to-peer";
20974
20696
  var DEFAULT_OPENCLAW_BASE_URL2 = "http://127.0.0.1:18789";
20975
- var DEFAULT_RELAY_ECHO_ENABLED2 = true;
20976
- var DEFAULT_RELAY_ECHO_CHANNEL2 = "last";
20977
- var DEFAULT_RELAY_ECHO_MAX_LENGTH2 = 500;
20978
- var MIN_RELAY_ECHO_MAX_LENGTH = 50;
20979
- var MAX_RELAY_ECHO_MAX_LENGTH = 2e3;
20697
+ var DEFAULT_CONNECTOR_PORT = 19400;
20698
+ var DEFAULT_CONNECTOR_OUTBOUND_PATH3 = "/v1/outbound";
20699
+ var CONNECTOR_HOST_LOOPBACK = "127.0.0.1";
20700
+ var CONNECTOR_HOST_DOCKER = "host.docker.internal";
20701
+ var CONNECTOR_HOST_DOCKER_GATEWAY = "gateway.docker.internal";
20702
+ var CONNECTOR_HOST_LINUX_BRIDGE = "172.17.0.1";
20980
20703
  var INVITE_CODE_PREFIX = "clawd1_";
20981
20704
  var PEER_ALIAS_PATTERN = /^[a-zA-Z0-9._-]+$/;
20982
20705
  var FILE_MODE3 = 384;
20706
+ var OPENCLAW_HOOK_TOKEN_BYTES = 32;
20983
20707
  var textEncoder2 = new TextEncoder();
20984
20708
  var textDecoder = new TextDecoder();
20985
- function isRecord8(value) {
20709
+ function isRecord7(value) {
20986
20710
  return typeof value === "object" && value !== null;
20987
20711
  }
20988
20712
  function createCliError5(code, message2, details) {
@@ -20994,7 +20718,7 @@ function createCliError5(code, message2, details) {
20994
20718
  });
20995
20719
  }
20996
20720
  function getErrorCode2(error48) {
20997
- if (!isRecord8(error48)) {
20721
+ if (!isRecord7(error48)) {
20998
20722
  return void 0;
20999
20723
  }
21000
20724
  return typeof error48.code === "string" ? error48.code : void 0;
@@ -21064,82 +20788,13 @@ function parseHttpUrl(value, input) {
21064
20788
  }
21065
20789
  return parsedUrl.toString();
21066
20790
  }
21067
- function parseOpenclawBaseUrl2(value) {
20791
+ function parseOpenclawBaseUrl(value) {
21068
20792
  return parseHttpUrl(value, {
21069
20793
  label: "OpenClaw base URL",
21070
20794
  code: "CLI_OPENCLAW_INVALID_OPENCLAW_BASE_URL",
21071
20795
  message: "OpenClaw base URL must be a valid URL"
21072
20796
  });
21073
20797
  }
21074
- function parseBooleanValue(value, label) {
21075
- if (typeof value === "boolean") {
21076
- return value;
21077
- }
21078
- if (typeof value === "string") {
21079
- const normalized = value.trim().toLowerCase();
21080
- if (normalized === "true" || normalized === "1" || normalized === "yes" || normalized === "on") {
21081
- return true;
21082
- }
21083
- if (normalized === "false" || normalized === "0" || normalized === "no" || normalized === "off") {
21084
- return false;
21085
- }
21086
- }
21087
- throw createCliError5(
21088
- "CLI_OPENCLAW_INVALID_INPUT",
21089
- `${label} must be true or false`,
21090
- { label }
21091
- );
21092
- }
21093
- function parseRelayEchoChannel(value) {
21094
- return parseNonEmptyString7(value, "relay echo channel");
21095
- }
21096
- function parseRelayEchoMaxLength(value) {
21097
- const parsed = typeof value === "number" ? value : typeof value === "string" ? Number(value) : Number.NaN;
21098
- if (!Number.isInteger(parsed) || parsed < MIN_RELAY_ECHO_MAX_LENGTH || parsed > MAX_RELAY_ECHO_MAX_LENGTH) {
21099
- throw createCliError5(
21100
- "CLI_OPENCLAW_INVALID_ECHO_MAX_LENGTH",
21101
- `echo max length must be an integer between ${MIN_RELAY_ECHO_MAX_LENGTH} and ${MAX_RELAY_ECHO_MAX_LENGTH}`
21102
- );
21103
- }
21104
- return parsed;
21105
- }
21106
- function parseRelayEchoEnabled(value) {
21107
- return parseBooleanValue(value, "relay echo enabled");
21108
- }
21109
- function parseRelayEchoTo(value) {
21110
- if (value === void 0) {
21111
- return void 0;
21112
- }
21113
- if (typeof value !== "string") {
21114
- throw createCliError5(
21115
- "CLI_OPENCLAW_INVALID_INPUT",
21116
- "relay echo target must be a string",
21117
- { label: "relay echo target" }
21118
- );
21119
- }
21120
- const trimmed = value.trim();
21121
- if (trimmed.length === 0) {
21122
- return void 0;
21123
- }
21124
- return trimmed;
21125
- }
21126
- function defaultRelayEchoConfig() {
21127
- return {
21128
- enabled: DEFAULT_RELAY_ECHO_ENABLED2,
21129
- channel: DEFAULT_RELAY_ECHO_CHANNEL2,
21130
- maxLength: DEFAULT_RELAY_ECHO_MAX_LENGTH2
21131
- };
21132
- }
21133
- function resolveSetupRelayEchoConfig(input) {
21134
- const current = input.existingConfig?.echo ?? defaultRelayEchoConfig();
21135
- const options = input.options;
21136
- return {
21137
- enabled: options.echoEnabled === void 0 ? current.enabled : parseRelayEchoEnabled(options.echoEnabled),
21138
- channel: options.echoChannel === void 0 ? current.channel : parseRelayEchoChannel(options.echoChannel),
21139
- to: options.echoTo === void 0 ? current.to : parseRelayEchoTo(options.echoTo),
21140
- maxLength: options.echoMaxLength === void 0 ? current.maxLength : parseRelayEchoMaxLength(options.echoMaxLength)
21141
- };
21142
- }
21143
20798
  function parseAgentDid2(value, label) {
21144
20799
  const did = parseNonEmptyString7(value, label);
21145
20800
  try {
@@ -21158,7 +20813,7 @@ function parseAgentDid2(value, label) {
21158
20813
  return did;
21159
20814
  }
21160
20815
  function parseInvitePayload(value) {
21161
- if (!isRecord8(value)) {
20816
+ if (!isRecord7(value)) {
21162
20817
  throw createCliError5(
21163
20818
  "CLI_OPENCLAW_INVALID_INVITE",
21164
20819
  "invite payload must be an object"
@@ -21207,23 +20862,86 @@ function resolveHomeDir(homeDir) {
21207
20862
  }
21208
20863
  return homedir3();
21209
20864
  }
20865
+ function resolveHomePrefixedPath(input, homeDir) {
20866
+ const trimmed = input.trim();
20867
+ if (trimmed.startsWith("~")) {
20868
+ return resolvePath(trimmed.replace(/^~(?=$|[\\/])/, homeDir));
20869
+ }
20870
+ return resolvePath(trimmed);
20871
+ }
20872
+ function readNonEmptyEnvPath(value, homeDir) {
20873
+ if (typeof value !== "string" || value.trim().length === 0) {
20874
+ return void 0;
20875
+ }
20876
+ return resolveHomePrefixedPath(value, homeDir);
20877
+ }
20878
+ function resolveOpenclawHomeDir(homeDir) {
20879
+ const envOpenclawHome = readNonEmptyEnvPath(process.env.OPENCLAW_HOME, homeDir);
20880
+ return envOpenclawHome ?? homeDir;
20881
+ }
20882
+ function resolveDefaultOpenclawStateDir(openclawHomeDir) {
20883
+ const newStateDir = join6(openclawHomeDir, OPENCLAW_DIR_NAME);
20884
+ if (existsSync(newStateDir)) {
20885
+ return newStateDir;
20886
+ }
20887
+ for (const legacyDirName of LEGACY_OPENCLAW_STATE_DIR_NAMES) {
20888
+ const legacyStateDir = join6(openclawHomeDir, legacyDirName);
20889
+ if (existsSync(legacyStateDir)) {
20890
+ return legacyStateDir;
20891
+ }
20892
+ }
20893
+ return newStateDir;
20894
+ }
21210
20895
  function resolveOpenclawDir(openclawDir, homeDir) {
21211
20896
  if (typeof openclawDir === "string" && openclawDir.trim().length > 0) {
21212
- return openclawDir.trim();
20897
+ return resolveHomePrefixedPath(openclawDir, homeDir);
20898
+ }
20899
+ const envStateDir = readNonEmptyEnvPath(
20900
+ process.env.OPENCLAW_STATE_DIR ?? process.env.CLAWDBOT_STATE_DIR,
20901
+ homeDir
20902
+ );
20903
+ if (envStateDir !== void 0) {
20904
+ return envStateDir;
21213
20905
  }
21214
- return join7(homeDir, OPENCLAW_DIR_NAME);
20906
+ const envConfigPath = readNonEmptyEnvPath(
20907
+ process.env.OPENCLAW_CONFIG_PATH ?? process.env.CLAWDBOT_CONFIG_PATH,
20908
+ homeDir
20909
+ );
20910
+ if (envConfigPath !== void 0) {
20911
+ return dirname4(envConfigPath);
20912
+ }
20913
+ const openclawHomeDir = resolveOpenclawHomeDir(homeDir);
20914
+ return resolveDefaultOpenclawStateDir(openclawHomeDir);
21215
20915
  }
21216
20916
  function resolveAgentDirectory(homeDir, agentName) {
21217
- return join7(homeDir, CLAWDENTITY_DIR_NAME, AGENTS_DIR_NAME4, agentName);
20917
+ return join6(homeDir, CLAWDENTITY_DIR_NAME, AGENTS_DIR_NAME4, agentName);
21218
20918
  }
21219
20919
  function resolvePeersPath(homeDir) {
21220
- return join7(homeDir, CLAWDENTITY_DIR_NAME, PEERS_FILE_NAME);
20920
+ return join6(homeDir, CLAWDENTITY_DIR_NAME, PEERS_FILE_NAME);
21221
20921
  }
21222
- function resolveOpenclawConfigPath(openclawDir) {
21223
- return join7(openclawDir, OPENCLAW_CONFIG_FILE_NAME);
20922
+ function resolveOpenclawConfigPath(openclawDir, homeDir) {
20923
+ const envConfigPath = readNonEmptyEnvPath(
20924
+ process.env.OPENCLAW_CONFIG_PATH ?? process.env.CLAWDBOT_CONFIG_PATH,
20925
+ homeDir
20926
+ );
20927
+ if (envConfigPath !== void 0) {
20928
+ return envConfigPath;
20929
+ }
20930
+ const configCandidates = [
20931
+ join6(openclawDir, OPENCLAW_CONFIG_FILE_NAME),
20932
+ ...LEGACY_OPENCLAW_CONFIG_FILE_NAMES.map(
20933
+ (fileName) => join6(openclawDir, fileName)
20934
+ )
20935
+ ];
20936
+ for (const candidate of configCandidates) {
20937
+ if (existsSync(candidate)) {
20938
+ return candidate;
20939
+ }
20940
+ }
20941
+ return configCandidates[0];
21224
20942
  }
21225
20943
  function resolveDefaultTransformSource(openclawDir) {
21226
- return join7(
20944
+ return join6(
21227
20945
  openclawDir,
21228
20946
  "workspace",
21229
20947
  "skills",
@@ -21232,16 +20950,25 @@ function resolveDefaultTransformSource(openclawDir) {
21232
20950
  );
21233
20951
  }
21234
20952
  function resolveTransformTargetPath(openclawDir) {
21235
- return join7(openclawDir, "hooks", "transforms", RELAY_MODULE_FILE_NAME);
20953
+ return join6(openclawDir, "hooks", "transforms", RELAY_MODULE_FILE_NAME);
21236
20954
  }
21237
20955
  function resolveOpenclawAgentNamePath(homeDir) {
21238
- return join7(homeDir, CLAWDENTITY_DIR_NAME, OPENCLAW_AGENT_FILE_NAME);
20956
+ return join6(homeDir, CLAWDENTITY_DIR_NAME, OPENCLAW_AGENT_FILE_NAME);
21239
20957
  }
21240
20958
  function resolveRelayRuntimeConfigPath(homeDir) {
21241
- return join7(homeDir, CLAWDENTITY_DIR_NAME, OPENCLAW_RELAY_RUNTIME_FILE_NAME);
20959
+ return join6(homeDir, CLAWDENTITY_DIR_NAME, OPENCLAW_RELAY_RUNTIME_FILE_NAME2);
20960
+ }
20961
+ function resolveConnectorAssignmentsPath(homeDir) {
20962
+ return join6(homeDir, CLAWDENTITY_DIR_NAME, OPENCLAW_CONNECTORS_FILE_NAME2);
20963
+ }
20964
+ function resolveTransformRuntimePath(openclawDir) {
20965
+ return join6(openclawDir, "hooks", "transforms", RELAY_RUNTIME_FILE_NAME);
20966
+ }
20967
+ function resolveTransformPeersPath(openclawDir) {
20968
+ return join6(openclawDir, "hooks", "transforms", RELAY_PEERS_FILE_NAME);
21242
20969
  }
21243
20970
  async function readJsonFile(filePath) {
21244
- const raw = await readFile5(filePath, "utf8");
20971
+ const raw = await readFile4(filePath, "utf8");
21245
20972
  try {
21246
20973
  return JSON.parse(raw);
21247
20974
  } catch {
@@ -21253,13 +20980,13 @@ async function readJsonFile(filePath) {
21253
20980
  async function ensureLocalAgentCredentials(homeDir, agentName) {
21254
20981
  const agentDir = resolveAgentDirectory(homeDir, agentName);
21255
20982
  const requiredFiles = [
21256
- join7(agentDir, SECRET_KEY_FILE_NAME2),
21257
- join7(agentDir, AIT_FILE_NAME3)
20983
+ join6(agentDir, SECRET_KEY_FILE_NAME2),
20984
+ join6(agentDir, AIT_FILE_NAME3)
21258
20985
  ];
21259
20986
  for (const filePath of requiredFiles) {
21260
20987
  let content;
21261
20988
  try {
21262
- content = await readFile5(filePath, "utf8");
20989
+ content = await readFile4(filePath, "utf8");
21263
20990
  } catch (error48) {
21264
20991
  if (getErrorCode2(error48) === "ENOENT") {
21265
20992
  throw createCliError5(
@@ -21333,7 +21060,7 @@ async function loadPeersConfig(peersPath) {
21333
21060
  }
21334
21061
  throw error48;
21335
21062
  }
21336
- if (!isRecord8(parsed)) {
21063
+ if (!isRecord7(parsed)) {
21337
21064
  throw createCliError5(
21338
21065
  "CLI_OPENCLAW_INVALID_PEERS_CONFIG",
21339
21066
  "Peer config root must be a JSON object",
@@ -21344,7 +21071,7 @@ async function loadPeersConfig(peersPath) {
21344
21071
  if (peersValue === void 0) {
21345
21072
  return { peers: {} };
21346
21073
  }
21347
- if (!isRecord8(peersValue)) {
21074
+ if (!isRecord7(peersValue)) {
21348
21075
  throw createCliError5(
21349
21076
  "CLI_OPENCLAW_INVALID_PEERS_CONFIG",
21350
21077
  "Peer config peers field must be an object",
@@ -21354,7 +21081,7 @@ async function loadPeersConfig(peersPath) {
21354
21081
  const peers = {};
21355
21082
  for (const [alias, value] of Object.entries(peersValue)) {
21356
21083
  const normalizedAlias = parsePeerAlias(alias);
21357
- if (!isRecord8(value)) {
21084
+ if (!isRecord7(value)) {
21358
21085
  throw createCliError5(
21359
21086
  "CLI_OPENCLAW_INVALID_PEERS_CONFIG",
21360
21087
  "Peer entry must be an object",
@@ -21376,35 +21103,100 @@ async function savePeersConfig(peersPath, config2) {
21376
21103
  await writeSecureFile3(peersPath, `${JSON.stringify(config2, null, 2)}
21377
21104
  `);
21378
21105
  }
21379
- function parseRelayRuntimeEchoConfig(value, relayRuntimeConfigPath) {
21380
- if (value === void 0) {
21381
- return defaultRelayEchoConfig();
21382
- }
21383
- if (!isRecord8(value)) {
21106
+ function parseConnectorBaseUrlForAssignment(value, label) {
21107
+ return parseHttpUrl(value, {
21108
+ label,
21109
+ code: "CLI_OPENCLAW_INVALID_CONNECTOR_BASE_URL",
21110
+ message: "Connector base URL must be a valid URL"
21111
+ });
21112
+ }
21113
+ function parseConnectorAssignments(value, connectorAssignmentsPath) {
21114
+ if (!isRecord7(value)) {
21384
21115
  throw createCliError5(
21385
- "CLI_OPENCLAW_INVALID_RELAY_RUNTIME_CONFIG",
21386
- "Relay runtime echo config must be an object",
21387
- { relayRuntimeConfigPath }
21116
+ "CLI_OPENCLAW_INVALID_CONNECTOR_ASSIGNMENTS",
21117
+ "Connector assignments config must be an object",
21118
+ { connectorAssignmentsPath }
21388
21119
  );
21389
21120
  }
21390
- const defaults = defaultRelayEchoConfig();
21391
- try {
21392
- return {
21393
- enabled: value.enabled === void 0 ? defaults.enabled : parseRelayEchoEnabled(value.enabled),
21394
- channel: value.channel === void 0 ? defaults.channel : parseRelayEchoChannel(value.channel),
21395
- to: parseRelayEchoTo(value.to),
21396
- maxLength: value.maxLength === void 0 ? defaults.maxLength : parseRelayEchoMaxLength(value.maxLength)
21121
+ const agentsRaw = value.agents;
21122
+ if (!isRecord7(agentsRaw)) {
21123
+ return { agents: {} };
21124
+ }
21125
+ const agents = {};
21126
+ for (const [agentName, entryValue] of Object.entries(agentsRaw)) {
21127
+ if (!isRecord7(entryValue)) {
21128
+ throw createCliError5(
21129
+ "CLI_OPENCLAW_INVALID_CONNECTOR_ASSIGNMENTS",
21130
+ "Connector assignment entry must be an object",
21131
+ { connectorAssignmentsPath, agentName }
21132
+ );
21133
+ }
21134
+ const connectorBaseUrl = parseConnectorBaseUrlForAssignment(
21135
+ entryValue.connectorBaseUrl,
21136
+ "connectorBaseUrl"
21137
+ );
21138
+ const updatedAt = typeof entryValue.updatedAt === "string" && entryValue.updatedAt.trim().length > 0 ? entryValue.updatedAt.trim() : nowIso();
21139
+ agents[assertValidAgentName(agentName)] = {
21140
+ connectorBaseUrl,
21141
+ updatedAt
21397
21142
  };
21143
+ }
21144
+ return { agents };
21145
+ }
21146
+ async function loadConnectorAssignments(connectorAssignmentsPath) {
21147
+ let parsed;
21148
+ try {
21149
+ parsed = await readJsonFile(connectorAssignmentsPath);
21398
21150
  } catch (error48) {
21399
- throw createCliError5(
21400
- "CLI_OPENCLAW_INVALID_RELAY_RUNTIME_CONFIG",
21401
- error48 instanceof Error ? error48.message : "Relay runtime echo config is invalid",
21402
- { relayRuntimeConfigPath }
21403
- );
21151
+ if (getErrorCode2(error48) === "ENOENT") {
21152
+ return { agents: {} };
21153
+ }
21154
+ throw error48;
21404
21155
  }
21156
+ return parseConnectorAssignments(parsed, connectorAssignmentsPath);
21157
+ }
21158
+ async function saveConnectorAssignments(connectorAssignmentsPath, config2) {
21159
+ await writeSecureFile3(
21160
+ connectorAssignmentsPath,
21161
+ `${JSON.stringify(config2, null, 2)}
21162
+ `
21163
+ );
21164
+ }
21165
+ function parseConnectorPortFromBaseUrl(baseUrl) {
21166
+ const parsed = new URL(baseUrl);
21167
+ if (parsed.port) {
21168
+ return Number(parsed.port);
21169
+ }
21170
+ return parsed.protocol === "https:" ? 443 : 80;
21171
+ }
21172
+ function allocateConnectorPort(assignments, agentName) {
21173
+ const existing = assignments.agents[agentName];
21174
+ if (existing) {
21175
+ return parseConnectorPortFromBaseUrl(existing.connectorBaseUrl);
21176
+ }
21177
+ const usedPorts = /* @__PURE__ */ new Set();
21178
+ for (const entry of Object.values(assignments.agents)) {
21179
+ usedPorts.add(parseConnectorPortFromBaseUrl(entry.connectorBaseUrl));
21180
+ }
21181
+ let nextPort = DEFAULT_CONNECTOR_PORT;
21182
+ while (usedPorts.has(nextPort)) {
21183
+ nextPort += 1;
21184
+ }
21185
+ return nextPort;
21186
+ }
21187
+ function buildConnectorBaseUrl(host, port) {
21188
+ return `http://${host}:${port}`;
21189
+ }
21190
+ function buildRelayConnectorBaseUrls(port) {
21191
+ return [
21192
+ buildConnectorBaseUrl(CONNECTOR_HOST_DOCKER, port),
21193
+ buildConnectorBaseUrl(CONNECTOR_HOST_DOCKER_GATEWAY, port),
21194
+ buildConnectorBaseUrl(CONNECTOR_HOST_LINUX_BRIDGE, port),
21195
+ buildConnectorBaseUrl(CONNECTOR_HOST_LOOPBACK, port)
21196
+ ];
21405
21197
  }
21406
21198
  function parseRelayRuntimeConfig(value, relayRuntimeConfigPath) {
21407
- if (!isRecord8(value)) {
21199
+ if (!isRecord7(value)) {
21408
21200
  throw createCliError5(
21409
21201
  "CLI_OPENCLAW_INVALID_RELAY_RUNTIME_CONFIG",
21410
21202
  "Relay runtime config must be an object",
@@ -21412,11 +21204,11 @@ function parseRelayRuntimeConfig(value, relayRuntimeConfigPath) {
21412
21204
  );
21413
21205
  }
21414
21206
  const updatedAt = typeof value.updatedAt === "string" && value.updatedAt.trim().length > 0 ? value.updatedAt.trim() : void 0;
21415
- const echo = parseRelayRuntimeEchoConfig(value.echo, relayRuntimeConfigPath);
21207
+ const openclawHookToken = typeof value.openclawHookToken === "string" && value.openclawHookToken.trim().length > 0 ? value.openclawHookToken.trim() : void 0;
21416
21208
  return {
21417
- openclawBaseUrl: parseOpenclawBaseUrl2(value.openclawBaseUrl),
21418
- updatedAt,
21419
- echo
21209
+ openclawBaseUrl: parseOpenclawBaseUrl(value.openclawBaseUrl),
21210
+ openclawHookToken,
21211
+ updatedAt
21420
21212
  };
21421
21213
  }
21422
21214
  async function loadRelayRuntimeConfig(relayRuntimeConfigPath) {
@@ -21431,11 +21223,11 @@ async function loadRelayRuntimeConfig(relayRuntimeConfigPath) {
21431
21223
  }
21432
21224
  return parseRelayRuntimeConfig(parsed, relayRuntimeConfigPath);
21433
21225
  }
21434
- async function saveRelayRuntimeConfig(relayRuntimeConfigPath, openclawBaseUrl, relayEchoConfig) {
21226
+ async function saveRelayRuntimeConfig(relayRuntimeConfigPath, openclawBaseUrl, openclawHookToken) {
21435
21227
  const config2 = {
21436
21228
  openclawBaseUrl,
21437
- updatedAt: nowIso(),
21438
- echo: relayEchoConfig
21229
+ ...openclawHookToken ? { openclawHookToken } : {},
21230
+ updatedAt: nowIso()
21439
21231
  };
21440
21232
  await writeSecureFile3(
21441
21233
  relayRuntimeConfigPath,
@@ -21443,13 +21235,13 @@ async function saveRelayRuntimeConfig(relayRuntimeConfigPath, openclawBaseUrl, r
21443
21235
  `
21444
21236
  );
21445
21237
  }
21446
- async function resolveOpenclawBaseUrl(input) {
21238
+ async function resolveOpenclawBaseUrl2(input) {
21447
21239
  if (typeof input.optionValue === "string" && input.optionValue.trim().length > 0) {
21448
- return parseOpenclawBaseUrl2(input.optionValue);
21240
+ return parseOpenclawBaseUrl(input.optionValue);
21449
21241
  }
21450
21242
  const envOpenclawBaseUrl = process.env.OPENCLAW_BASE_URL;
21451
21243
  if (typeof envOpenclawBaseUrl === "string" && envOpenclawBaseUrl.trim().length > 0) {
21452
- return parseOpenclawBaseUrl2(envOpenclawBaseUrl);
21244
+ return parseOpenclawBaseUrl(envOpenclawBaseUrl);
21453
21245
  }
21454
21246
  const existingConfig = await loadRelayRuntimeConfig(
21455
21247
  input.relayRuntimeConfigPath
@@ -21475,21 +21267,24 @@ function normalizeStringArrayWithValue(value, requiredValue) {
21475
21267
  normalized.add(requiredValue);
21476
21268
  return Array.from(normalized);
21477
21269
  }
21270
+ function generateOpenclawHookToken() {
21271
+ return randomBytes3(OPENCLAW_HOOK_TOKEN_BYTES).toString("hex");
21272
+ }
21478
21273
  function upsertRelayHookMapping(mappingsValue) {
21479
- const mappings = Array.isArray(mappingsValue) ? mappingsValue.filter(isRecord8).map((mapping) => ({ ...mapping })) : [];
21274
+ const mappings = Array.isArray(mappingsValue) ? mappingsValue.filter(isRecord7).map((mapping) => ({ ...mapping })) : [];
21480
21275
  const existingIndex = mappings.findIndex((mapping) => {
21481
21276
  if (mapping.id === HOOK_MAPPING_ID) {
21482
21277
  return true;
21483
21278
  }
21484
- if (!isRecord8(mapping.match)) {
21279
+ if (!isRecord7(mapping.match)) {
21485
21280
  return false;
21486
21281
  }
21487
21282
  return mapping.match.path === HOOK_PATH_SEND_TO_PEER;
21488
21283
  });
21489
- const baseMapping = existingIndex >= 0 && isRecord8(mappings[existingIndex]) ? mappings[existingIndex] : {};
21490
- const nextMatch = isRecord8(baseMapping.match) ? { ...baseMapping.match } : {};
21284
+ const baseMapping = existingIndex >= 0 && isRecord7(mappings[existingIndex]) ? mappings[existingIndex] : {};
21285
+ const nextMatch = isRecord7(baseMapping.match) ? { ...baseMapping.match } : {};
21491
21286
  nextMatch.path = HOOK_PATH_SEND_TO_PEER;
21492
- const nextTransform = isRecord8(baseMapping.transform) ? { ...baseMapping.transform } : {};
21287
+ const nextTransform = isRecord7(baseMapping.transform) ? { ...baseMapping.transform } : {};
21493
21288
  nextTransform.module = RELAY_MODULE_FILE_NAME;
21494
21289
  const relayMapping = {
21495
21290
  ...baseMapping,
@@ -21506,7 +21301,7 @@ function upsertRelayHookMapping(mappingsValue) {
21506
21301
  mappings.push(relayMapping);
21507
21302
  return mappings;
21508
21303
  }
21509
- async function patchOpenclawConfig(openclawConfigPath) {
21304
+ async function patchOpenclawConfig(openclawConfigPath, hookToken) {
21510
21305
  let config2;
21511
21306
  try {
21512
21307
  config2 = await readJsonFile(openclawConfigPath);
@@ -21520,15 +21315,19 @@ async function patchOpenclawConfig(openclawConfigPath) {
21520
21315
  }
21521
21316
  throw error48;
21522
21317
  }
21523
- if (!isRecord8(config2)) {
21318
+ if (!isRecord7(config2)) {
21524
21319
  throw createCliError5(
21525
21320
  "CLI_OPENCLAW_INVALID_CONFIG",
21526
21321
  "OpenClaw config root must be an object",
21527
21322
  { openclawConfigPath }
21528
21323
  );
21529
21324
  }
21530
- const hooks = isRecord8(config2.hooks) ? { ...config2.hooks } : {};
21325
+ const hooks = isRecord7(config2.hooks) ? { ...config2.hooks } : {};
21326
+ const existingHookToken = typeof hooks.token === "string" && hooks.token.trim().length > 0 ? hooks.token.trim() : void 0;
21327
+ const preferredHookToken = typeof hookToken === "string" && hookToken.trim().length > 0 ? hookToken.trim() : void 0;
21328
+ const resolvedHookToken = existingHookToken ?? preferredHookToken ?? generateOpenclawHookToken();
21531
21329
  hooks.enabled = true;
21330
+ hooks.token = resolvedHookToken;
21532
21331
  hooks.allowRequestSessionKey = false;
21533
21332
  hooks.allowedSessionKeyPrefixes = normalizeStringArrayWithValue(
21534
21333
  hooks.allowedSessionKeyPrefixes,
@@ -21545,6 +21344,9 @@ async function patchOpenclawConfig(openclawConfigPath) {
21545
21344
  `,
21546
21345
  "utf8"
21547
21346
  );
21347
+ return {
21348
+ hookToken: resolvedHookToken
21349
+ };
21548
21350
  }
21549
21351
  function toDoctorCheck(input) {
21550
21352
  return input;
@@ -21557,10 +21359,10 @@ function toDoctorResult(checks) {
21557
21359
  };
21558
21360
  }
21559
21361
  function isRelayHookMapping(value) {
21560
- if (!isRecord8(value)) {
21362
+ if (!isRecord7(value)) {
21561
21363
  return false;
21562
21364
  }
21563
- if (!isRecord8(value.match) || value.match.path !== HOOK_PATH_SEND_TO_PEER) {
21365
+ if (!isRecord7(value.match) || value.match.path !== HOOK_PATH_SEND_TO_PEER) {
21564
21366
  return false;
21565
21367
  }
21566
21368
  if (typeof value.id === "string" && value.id !== HOOK_MAPPING_ID) {
@@ -21569,7 +21371,7 @@ function isRelayHookMapping(value) {
21569
21371
  return true;
21570
21372
  }
21571
21373
  function hasRelayTransformModule(value) {
21572
- if (!isRecord8(value) || !isRecord8(value.transform)) {
21374
+ if (!isRecord7(value) || !isRecord7(value.transform)) {
21573
21375
  return false;
21574
21376
  }
21575
21377
  return value.transform.module === RELAY_MODULE_FILE_NAME;
@@ -21580,8 +21382,8 @@ function parseDoctorPeerAlias(peerAlias) {
21580
21382
  }
21581
21383
  return parsePeerAlias(peerAlias);
21582
21384
  }
21583
- function resolveHookToken(optionValue) {
21584
- const trimmedOption = optionValue?.trim();
21385
+ async function resolveHookToken(input) {
21386
+ const trimmedOption = input.optionValue?.trim();
21585
21387
  if (trimmedOption !== void 0 && trimmedOption.length > 0) {
21586
21388
  return trimmedOption;
21587
21389
  }
@@ -21589,6 +21391,12 @@ function resolveHookToken(optionValue) {
21589
21391
  if (envValue !== void 0 && envValue.length > 0) {
21590
21392
  return envValue;
21591
21393
  }
21394
+ const existingConfig = await loadRelayRuntimeConfig(
21395
+ input.relayRuntimeConfigPath
21396
+ );
21397
+ if (existingConfig?.openclawHookToken) {
21398
+ return existingConfig.openclawHookToken;
21399
+ }
21592
21400
  return void 0;
21593
21401
  }
21594
21402
  function resolveProbeMessage(optionValue) {
@@ -21686,7 +21494,7 @@ async function runOpenclawDoctor(options = {}) {
21686
21494
  const selectedAgentPath = resolveOpenclawAgentNamePath(homeDir);
21687
21495
  let selectedAgentName;
21688
21496
  try {
21689
- const selectedAgentRaw = await readFile5(selectedAgentPath, "utf8");
21497
+ const selectedAgentRaw = await readFile4(selectedAgentPath, "utf8");
21690
21498
  selectedAgentName = assertValidAgentName(selectedAgentRaw.trim());
21691
21499
  checks.push(
21692
21500
  toDoctorCheck({
@@ -21807,17 +21615,28 @@ async function runOpenclawDoctor(options = {}) {
21807
21615
  );
21808
21616
  }
21809
21617
  const transformTargetPath = resolveTransformTargetPath(openclawDir);
21618
+ const relayTransformRuntimePath = resolveTransformRuntimePath(openclawDir);
21619
+ const relayTransformPeersPath = resolveTransformPeersPath(openclawDir);
21810
21620
  try {
21811
- const transformContents = await readFile5(transformTargetPath, "utf8");
21812
- if (transformContents.trim().length === 0) {
21621
+ const transformContents = await readFile4(transformTargetPath, "utf8");
21622
+ const runtimeContents = await readFile4(relayTransformRuntimePath, "utf8");
21623
+ const peersSnapshotContents = await readFile4(
21624
+ relayTransformPeersPath,
21625
+ "utf8"
21626
+ );
21627
+ if (transformContents.trim().length === 0 || runtimeContents.trim().length === 0 || peersSnapshotContents.trim().length === 0) {
21813
21628
  checks.push(
21814
21629
  toDoctorCheck({
21815
21630
  id: "state.transform",
21816
21631
  label: "Relay transform",
21817
21632
  status: "fail",
21818
- message: `transform file is empty: ${transformTargetPath}`,
21633
+ message: "relay transform artifacts are missing or empty",
21819
21634
  remediationHint: "Run: npm install clawdentity --skill",
21820
- details: { transformTargetPath }
21635
+ details: {
21636
+ transformTargetPath,
21637
+ relayTransformRuntimePath,
21638
+ relayTransformPeersPath
21639
+ }
21821
21640
  })
21822
21641
  );
21823
21642
  } else {
@@ -21826,8 +21645,12 @@ async function runOpenclawDoctor(options = {}) {
21826
21645
  id: "state.transform",
21827
21646
  label: "Relay transform",
21828
21647
  status: "pass",
21829
- message: "relay transform file exists",
21830
- details: { transformTargetPath }
21648
+ message: "relay transform artifacts are present",
21649
+ details: {
21650
+ transformTargetPath,
21651
+ relayTransformRuntimePath,
21652
+ relayTransformPeersPath
21653
+ }
21831
21654
  })
21832
21655
  );
21833
21656
  }
@@ -21837,20 +21660,26 @@ async function runOpenclawDoctor(options = {}) {
21837
21660
  id: "state.transform",
21838
21661
  label: "Relay transform",
21839
21662
  status: "fail",
21840
- message: `missing transform file: ${transformTargetPath}`,
21663
+ message: "missing relay transform artifacts",
21841
21664
  remediationHint: "Run: npm install clawdentity --skill",
21842
- details: { transformTargetPath }
21665
+ details: {
21666
+ transformTargetPath,
21667
+ relayTransformRuntimePath,
21668
+ relayTransformPeersPath
21669
+ }
21843
21670
  })
21844
21671
  );
21845
21672
  }
21846
- const openclawConfigPath = resolveOpenclawConfigPath(openclawDir);
21673
+ const openclawConfigPath = resolveOpenclawConfigPath(openclawDir, homeDir);
21847
21674
  try {
21848
21675
  const openclawConfig = await readJsonFile(openclawConfigPath);
21849
- if (!isRecord8(openclawConfig)) {
21676
+ if (!isRecord7(openclawConfig)) {
21850
21677
  throw new Error("root");
21851
21678
  }
21852
- const hooks = isRecord8(openclawConfig.hooks) ? openclawConfig.hooks : {};
21853
- const mappings = Array.isArray(hooks.mappings) ? hooks.mappings.filter(isRecord8) : [];
21679
+ const hooks = isRecord7(openclawConfig.hooks) ? openclawConfig.hooks : {};
21680
+ const hooksEnabled = hooks.enabled === true;
21681
+ const hookToken = typeof hooks.token === "string" && hooks.token.trim().length > 0 ? hooks.token.trim() : void 0;
21682
+ const mappings = Array.isArray(hooks.mappings) ? hooks.mappings.filter(isRecord7) : [];
21854
21683
  const relayMapping = mappings.find(
21855
21684
  (mapping) => isRelayHookMapping(mapping)
21856
21685
  );
@@ -21876,6 +21705,39 @@ async function runOpenclawDoctor(options = {}) {
21876
21705
  })
21877
21706
  );
21878
21707
  }
21708
+ if (!hooksEnabled) {
21709
+ checks.push(
21710
+ toDoctorCheck({
21711
+ id: "state.hookToken",
21712
+ label: "OpenClaw hook auth",
21713
+ status: "fail",
21714
+ message: `hooks.enabled is not true in ${openclawConfigPath}`,
21715
+ remediationHint: "Run: clawdentity openclaw setup <agentName> --invite-code <code> and restart OpenClaw",
21716
+ details: { openclawConfigPath }
21717
+ })
21718
+ );
21719
+ } else if (hookToken === void 0) {
21720
+ checks.push(
21721
+ toDoctorCheck({
21722
+ id: "state.hookToken",
21723
+ label: "OpenClaw hook auth",
21724
+ status: "fail",
21725
+ message: `hooks.token is missing in ${openclawConfigPath}`,
21726
+ remediationHint: "Run: clawdentity openclaw setup <agentName> --invite-code <code> and restart OpenClaw",
21727
+ details: { openclawConfigPath }
21728
+ })
21729
+ );
21730
+ } else {
21731
+ checks.push(
21732
+ toDoctorCheck({
21733
+ id: "state.hookToken",
21734
+ label: "OpenClaw hook auth",
21735
+ status: "pass",
21736
+ message: "hooks token is configured",
21737
+ details: { openclawConfigPath }
21738
+ })
21739
+ );
21740
+ }
21879
21741
  } catch {
21880
21742
  checks.push(
21881
21743
  toDoctorCheck({
@@ -21883,14 +21745,24 @@ async function runOpenclawDoctor(options = {}) {
21883
21745
  label: "OpenClaw hook mapping",
21884
21746
  status: "fail",
21885
21747
  message: `unable to read ${openclawConfigPath}`,
21886
- remediationHint: "Ensure ~/.openclaw/openclaw.json exists and rerun openclaw setup",
21748
+ remediationHint: "Ensure the OpenClaw config file exists (OPENCLAW_CONFIG_PATH/CLAWDBOT_CONFIG_PATH, or state dir) and rerun openclaw setup",
21749
+ details: { openclawConfigPath }
21750
+ })
21751
+ );
21752
+ checks.push(
21753
+ toDoctorCheck({
21754
+ id: "state.hookToken",
21755
+ label: "OpenClaw hook auth",
21756
+ status: "fail",
21757
+ message: `unable to read ${openclawConfigPath}`,
21758
+ remediationHint: "Ensure the OpenClaw config file exists (OPENCLAW_CONFIG_PATH/CLAWDBOT_CONFIG_PATH, or state dir) and rerun openclaw setup",
21887
21759
  details: { openclawConfigPath }
21888
21760
  })
21889
21761
  );
21890
21762
  }
21891
21763
  const relayRuntimeConfigPath = resolveRelayRuntimeConfigPath(homeDir);
21892
21764
  try {
21893
- const openclawBaseUrl = await resolveOpenclawBaseUrl({
21765
+ const openclawBaseUrl = await resolveOpenclawBaseUrl2({
21894
21766
  relayRuntimeConfigPath
21895
21767
  });
21896
21768
  checks.push(
@@ -21927,6 +21799,12 @@ function parseRelayProbeFailure(input) {
21927
21799
  remediationHint: "Run: clawdentity openclaw setup <agentName> --invite-code <code>"
21928
21800
  };
21929
21801
  }
21802
+ if (input.status === 405) {
21803
+ return {
21804
+ message: "OpenClaw send-to-peer hook is not enabled for POST requests",
21805
+ remediationHint: "Run: clawdentity openclaw setup <agentName> --invite-code <code>, then restart OpenClaw"
21806
+ };
21807
+ }
21930
21808
  if (input.status === 500) {
21931
21809
  return {
21932
21810
  message: "Relay probe failed inside local relay pipeline",
@@ -21952,7 +21830,7 @@ async function runOpenclawRelayTest(options) {
21952
21830
  const relayRuntimeConfigPath = resolveRelayRuntimeConfigPath(homeDir);
21953
21831
  let openclawBaseUrl = DEFAULT_OPENCLAW_BASE_URL2;
21954
21832
  try {
21955
- openclawBaseUrl = await resolveOpenclawBaseUrl({
21833
+ openclawBaseUrl = await resolveOpenclawBaseUrl2({
21956
21834
  optionValue: options.openclawBaseUrl,
21957
21835
  relayRuntimeConfigPath
21958
21836
  });
@@ -21982,7 +21860,10 @@ async function runOpenclawRelayTest(options) {
21982
21860
  preflight
21983
21861
  };
21984
21862
  }
21985
- const hookToken = resolveHookToken(options.hookToken);
21863
+ const hookToken = await resolveHookToken({
21864
+ optionValue: options.hookToken,
21865
+ relayRuntimeConfigPath
21866
+ });
21986
21867
  const fetchImpl = options.fetchImpl ?? globalThis.fetch;
21987
21868
  if (typeof fetchImpl !== "function") {
21988
21869
  return {
@@ -22074,21 +21955,17 @@ async function setupOpenclawRelayFromInvite(agentName, options) {
22074
21955
  const normalizedAgentName = assertValidAgentName(agentName);
22075
21956
  const homeDir = resolveHomeDir(options.homeDir);
22076
21957
  const openclawDir = resolveOpenclawDir(options.openclawDir, homeDir);
22077
- const openclawConfigPath = resolveOpenclawConfigPath(openclawDir);
21958
+ const openclawConfigPath = resolveOpenclawConfigPath(openclawDir, homeDir);
22078
21959
  const transformSource = typeof options.transformSource === "string" && options.transformSource.trim().length > 0 ? options.transformSource.trim() : resolveDefaultTransformSource(openclawDir);
22079
21960
  const transformTargetPath = resolveTransformTargetPath(openclawDir);
22080
21961
  const relayRuntimeConfigPath = resolveRelayRuntimeConfigPath(homeDir);
22081
21962
  const existingRelayRuntimeConfig = await loadRelayRuntimeConfig(
22082
21963
  relayRuntimeConfigPath
22083
21964
  );
22084
- const openclawBaseUrl = await resolveOpenclawBaseUrl({
21965
+ const openclawBaseUrl = await resolveOpenclawBaseUrl2({
22085
21966
  optionValue: options.openclawBaseUrl,
22086
21967
  relayRuntimeConfigPath
22087
21968
  });
22088
- const relayEchoConfig = resolveSetupRelayEchoConfig({
22089
- existingConfig: existingRelayRuntimeConfig,
22090
- options
22091
- });
22092
21969
  const invite = decodeInvitePayload(options.inviteCode);
22093
21970
  const peerAliasCandidate = options.peerAlias ?? invite.alias;
22094
21971
  if (!peerAliasCandidate) {
@@ -22112,18 +21989,64 @@ async function setupOpenclawRelayFromInvite(agentName, options) {
22112
21989
  }
22113
21990
  throw error48;
22114
21991
  }
22115
- await patchOpenclawConfig(openclawConfigPath);
21992
+ const patchedOpenclawConfig = await patchOpenclawConfig(
21993
+ openclawConfigPath,
21994
+ existingRelayRuntimeConfig?.openclawHookToken
21995
+ );
22116
21996
  const peersPath = resolvePeersPath(homeDir);
22117
21997
  const peers = await loadPeersConfig(peersPath);
22118
21998
  peers.peers[peerAlias] = invite.name === void 0 ? { did: invite.did, proxyUrl: invite.proxyUrl } : { did: invite.did, proxyUrl: invite.proxyUrl, name: invite.name };
22119
21999
  await savePeersConfig(peersPath, peers);
22000
+ const relayTransformPeersPath = resolveTransformPeersPath(openclawDir);
22001
+ await writeSecureFile3(
22002
+ relayTransformPeersPath,
22003
+ `${JSON.stringify(peers, null, 2)}
22004
+ `
22005
+ );
22006
+ const connectorAssignmentsPath = resolveConnectorAssignmentsPath(homeDir);
22007
+ const connectorAssignments = await loadConnectorAssignments(
22008
+ connectorAssignmentsPath
22009
+ );
22010
+ const connectorPort = allocateConnectorPort(
22011
+ connectorAssignments,
22012
+ normalizedAgentName
22013
+ );
22014
+ const connectorBaseUrl = buildConnectorBaseUrl(
22015
+ CONNECTOR_HOST_LOOPBACK,
22016
+ connectorPort
22017
+ );
22018
+ connectorAssignments.agents[normalizedAgentName] = {
22019
+ connectorBaseUrl,
22020
+ updatedAt: nowIso()
22021
+ };
22022
+ await saveConnectorAssignments(
22023
+ connectorAssignmentsPath,
22024
+ connectorAssignments
22025
+ );
22026
+ const relayTransformRuntimePath = resolveTransformRuntimePath(openclawDir);
22027
+ await writeSecureFile3(
22028
+ relayTransformRuntimePath,
22029
+ `${JSON.stringify(
22030
+ {
22031
+ version: 1,
22032
+ connectorBaseUrl: buildRelayConnectorBaseUrls(connectorPort)[0],
22033
+ connectorBaseUrls: buildRelayConnectorBaseUrls(connectorPort),
22034
+ connectorPath: DEFAULT_CONNECTOR_OUTBOUND_PATH3,
22035
+ peersConfigPath: RELAY_PEERS_FILE_NAME,
22036
+ updatedAt: nowIso()
22037
+ },
22038
+ null,
22039
+ 2
22040
+ )}
22041
+ `
22042
+ );
22120
22043
  const agentNamePath = resolveOpenclawAgentNamePath(homeDir);
22121
22044
  await writeSecureFile3(agentNamePath, `${normalizedAgentName}
22122
22045
  `);
22123
22046
  await saveRelayRuntimeConfig(
22124
22047
  relayRuntimeConfigPath,
22125
22048
  openclawBaseUrl,
22126
- relayEchoConfig
22049
+ patchedOpenclawConfig.hookToken
22127
22050
  );
22128
22051
  logger8.info("cli.openclaw_setup_completed", {
22129
22052
  agentName: normalizedAgentName,
@@ -22131,9 +22054,11 @@ async function setupOpenclawRelayFromInvite(agentName, options) {
22131
22054
  peerDid: invite.did,
22132
22055
  openclawConfigPath,
22133
22056
  transformTargetPath,
22057
+ relayTransformRuntimePath,
22058
+ relayTransformPeersPath,
22134
22059
  openclawBaseUrl,
22135
- relayRuntimeConfigPath,
22136
- relayEchoConfig
22060
+ connectorBaseUrl,
22061
+ relayRuntimeConfigPath
22137
22062
  });
22138
22063
  return {
22139
22064
  peerAlias,
@@ -22141,9 +22066,11 @@ async function setupOpenclawRelayFromInvite(agentName, options) {
22141
22066
  peerProxyUrl: invite.proxyUrl,
22142
22067
  openclawConfigPath,
22143
22068
  transformTargetPath,
22069
+ relayTransformRuntimePath,
22070
+ relayTransformPeersPath,
22144
22071
  openclawBaseUrl,
22145
- relayRuntimeConfigPath,
22146
- relayEcho: relayEchoConfig
22072
+ connectorBaseUrl,
22073
+ relayRuntimeConfigPath
22147
22074
  };
22148
22075
  }
22149
22076
  var createOpenclawCommand = () => {
@@ -22179,20 +22106,6 @@ var createOpenclawCommand = () => {
22179
22106
  ).option(
22180
22107
  "--openclaw-base-url <url>",
22181
22108
  "Base URL for local OpenClaw hook API (default http://127.0.0.1:18789)"
22182
- ).option(
22183
- "--echo-enabled <true|false>",
22184
- "Enable or disable relay echo to the operator chat channel (default true)",
22185
- parseRelayEchoEnabled
22186
- ).option(
22187
- "--echo-channel <channel>",
22188
- "Relay echo delivery channel (default last)"
22189
- ).option(
22190
- "--echo-to <target>",
22191
- "Relay echo delivery target id/recipient (optional)"
22192
- ).option(
22193
- "--echo-max-length <number>",
22194
- `Relay echo message truncation limit (${MIN_RELAY_ECHO_MAX_LENGTH}-${MAX_RELAY_ECHO_MAX_LENGTH}, default ${DEFAULT_RELAY_ECHO_MAX_LENGTH2})`,
22195
- parseRelayEchoMaxLength
22196
22109
  ).action(
22197
22110
  withErrorHandling(
22198
22111
  "openclaw setup",
@@ -22205,17 +22118,14 @@ var createOpenclawCommand = () => {
22205
22118
  `Updated OpenClaw config: ${result.openclawConfigPath}`
22206
22119
  );
22207
22120
  writeStdoutLine(`Installed transform: ${result.transformTargetPath}`);
22208
- writeStdoutLine(`OpenClaw base URL: ${result.openclawBaseUrl}`);
22209
22121
  writeStdoutLine(
22210
- `Relay echo enabled: ${result.relayEcho.enabled ? "true" : "false"}`
22122
+ `Transform runtime config: ${result.relayTransformRuntimePath}`
22211
22123
  );
22212
- writeStdoutLine(`Relay echo channel: ${result.relayEcho.channel}`);
22213
22124
  writeStdoutLine(
22214
- `Relay echo target: ${result.relayEcho.to ?? "(last route default)"}`
22215
- );
22216
- writeStdoutLine(
22217
- `Relay echo max length: ${result.relayEcho.maxLength}`
22125
+ `Transform peers snapshot: ${result.relayTransformPeersPath}`
22218
22126
  );
22127
+ writeStdoutLine(`Connector base URL: ${result.connectorBaseUrl}`);
22128
+ writeStdoutLine(`OpenClaw base URL: ${result.openclawBaseUrl}`);
22219
22129
  writeStdoutLine(
22220
22130
  `Relay runtime config: ${result.relayRuntimeConfigPath}`
22221
22131
  );
@@ -22286,9 +22196,9 @@ var createOpenclawCommand = () => {
22286
22196
  };
22287
22197
 
22288
22198
  // src/commands/pair.ts
22289
- import { randomBytes as randomBytes3 } from "crypto";
22290
- import { mkdir as mkdir6, readdir, readFile as readFile6, unlink as unlink2, writeFile as writeFile6 } from "fs/promises";
22291
- import { dirname as dirname5, join as join8, resolve } from "path";
22199
+ import { randomBytes as randomBytes4 } from "crypto";
22200
+ import { mkdir as mkdir6, readdir, readFile as readFile5, unlink as unlink2, writeFile as writeFile6 } from "fs/promises";
22201
+ import { dirname as dirname5, join as join7, resolve } from "path";
22292
22202
  import { Command as Command8 } from "commander";
22293
22203
  import jsQR from "jsqr";
22294
22204
  import { PNG } from "pngjs";
@@ -22305,7 +22215,7 @@ var NONCE_SIZE2 = 24;
22305
22215
  var PAIRING_TICKET_PREFIX = "clwpair1_";
22306
22216
  var PAIRING_QR_MAX_AGE_SECONDS = 900;
22307
22217
  var PAIRING_QR_FILENAME_PATTERN = /-pair-(\d+)\.png$/;
22308
- var isRecord9 = (value) => {
22218
+ var isRecord8 = (value) => {
22309
22219
  return typeof value === "object" && value !== null;
22310
22220
  };
22311
22221
  function createCliError6(code, message2) {
@@ -22372,7 +22282,7 @@ function toPathWithQuery3(url2) {
22372
22282
  return `${parsed.pathname}${parsed.search}`;
22373
22283
  }
22374
22284
  function extractErrorCode(payload) {
22375
- if (!isRecord9(payload)) {
22285
+ if (!isRecord8(payload)) {
22376
22286
  return void 0;
22377
22287
  }
22378
22288
  const envelope = payload;
@@ -22383,7 +22293,7 @@ function extractErrorCode(payload) {
22383
22293
  return code.length > 0 ? code : void 0;
22384
22294
  }
22385
22295
  function extractErrorMessage(payload) {
22386
- if (!isRecord9(payload)) {
22296
+ if (!isRecord8(payload)) {
22387
22297
  return void 0;
22388
22298
  }
22389
22299
  const envelope = payload;
@@ -22451,7 +22361,7 @@ function mapConfirmPairError(status, payload) {
22451
22361
  return `Pair confirm failed (${status})`;
22452
22362
  }
22453
22363
  function parsePairStartResponse(payload) {
22454
- if (!isRecord9(payload)) {
22364
+ if (!isRecord8(payload)) {
22455
22365
  throw createCliError6(
22456
22366
  "CLI_PAIR_START_INVALID_RESPONSE",
22457
22367
  "Pair start response is invalid"
@@ -22473,7 +22383,7 @@ function parsePairStartResponse(payload) {
22473
22383
  };
22474
22384
  }
22475
22385
  function parsePairConfirmResponse(payload) {
22476
- if (!isRecord9(payload)) {
22386
+ if (!isRecord8(payload)) {
22477
22387
  throw createCliError6(
22478
22388
  "CLI_PAIR_CONFIRM_INVALID_RESPONSE",
22479
22389
  "Pair confirm response is invalid"
@@ -22495,16 +22405,16 @@ function parsePairConfirmResponse(payload) {
22495
22405
  };
22496
22406
  }
22497
22407
  async function readAgentProofMaterial(agentName, dependencies) {
22498
- const readFileImpl = dependencies.readFileImpl ?? readFile6;
22408
+ const readFileImpl = dependencies.readFileImpl ?? readFile5;
22499
22409
  const getConfigDirImpl = dependencies.getConfigDirImpl ?? getConfigDir;
22500
22410
  const normalizedAgentName = assertValidAgentName(agentName);
22501
- const agentDir = join8(
22411
+ const agentDir = join7(
22502
22412
  getConfigDirImpl(),
22503
22413
  AGENTS_DIR_NAME5,
22504
22414
  normalizedAgentName
22505
22415
  );
22506
- const aitPath = join8(agentDir, AIT_FILE_NAME4);
22507
- const secretKeyPath = join8(agentDir, SECRET_KEY_FILE_NAME3);
22416
+ const aitPath = join7(agentDir, AIT_FILE_NAME4);
22417
+ const secretKeyPath = join7(agentDir, SECRET_KEY_FILE_NAME3);
22508
22418
  let ait;
22509
22419
  try {
22510
22420
  ait = (await readFileImpl(aitPath, "utf-8")).trim();
@@ -22618,8 +22528,8 @@ async function persistPairingQr(input) {
22618
22528
  const writeFileImpl = input.dependencies.writeFileImpl ?? writeFile6;
22619
22529
  const getConfigDirImpl = input.dependencies.getConfigDirImpl ?? getConfigDir;
22620
22530
  const qrEncodeImpl = input.dependencies.qrEncodeImpl ?? encodeTicketQrPng;
22621
- const baseDir = join8(getConfigDirImpl(), PAIRING_QR_DIR_NAME);
22622
- const outputPath = parseNonEmptyString8(input.qrOutput) ? resolve(input.qrOutput ?? "") : join8(
22531
+ const baseDir = join7(getConfigDirImpl(), PAIRING_QR_DIR_NAME);
22532
+ const outputPath = parseNonEmptyString8(input.qrOutput) ? resolve(input.qrOutput ?? "") : join7(
22623
22533
  baseDir,
22624
22534
  `${assertValidAgentName(input.agentName)}-pair-${input.nowSeconds}.png`
22625
22535
  );
@@ -22645,7 +22555,7 @@ async function persistPairingQr(input) {
22645
22555
  if (issuedAtSeconds + PAIRING_QR_MAX_AGE_SECONDS > input.nowSeconds) {
22646
22556
  continue;
22647
22557
  }
22648
- const stalePath = join8(baseDir, fileName);
22558
+ const stalePath = join7(baseDir, fileName);
22649
22559
  await unlinkImpl(stalePath).catch((error48) => {
22650
22560
  const nodeError = error48;
22651
22561
  if (nodeError.code === "ENOENT") {
@@ -22690,7 +22600,7 @@ async function startPairing(agentName, options, dependencies = {}) {
22690
22600
  const fetchImpl = dependencies.fetchImpl ?? fetch;
22691
22601
  const resolveConfigImpl = dependencies.resolveConfigImpl ?? resolveConfig;
22692
22602
  const nowSecondsImpl = dependencies.nowSecondsImpl ?? (() => Math.floor(Date.now() / 1e3));
22693
- const nonceFactoryImpl = dependencies.nonceFactoryImpl ?? (() => randomBytes3(NONCE_SIZE2).toString("base64url"));
22603
+ const nonceFactoryImpl = dependencies.nonceFactoryImpl ?? (() => randomBytes4(NONCE_SIZE2).toString("base64url"));
22694
22604
  const ttlSeconds = parseTtlSeconds(options.ttlSeconds);
22695
22605
  const proxyUrl = resolveProxyUrl(options.proxyUrl);
22696
22606
  const config2 = await resolveConfigImpl();
@@ -22757,8 +22667,8 @@ async function startPairing(agentName, options, dependencies = {}) {
22757
22667
  async function confirmPairing(agentName, options, dependencies = {}) {
22758
22668
  const fetchImpl = dependencies.fetchImpl ?? fetch;
22759
22669
  const nowSecondsImpl = dependencies.nowSecondsImpl ?? (() => Math.floor(Date.now() / 1e3));
22760
- const nonceFactoryImpl = dependencies.nonceFactoryImpl ?? (() => randomBytes3(NONCE_SIZE2).toString("base64url"));
22761
- const readFileImpl = dependencies.readFileImpl ?? readFile6;
22670
+ const nonceFactoryImpl = dependencies.nonceFactoryImpl ?? (() => randomBytes4(NONCE_SIZE2).toString("base64url"));
22671
+ const readFileImpl = dependencies.readFileImpl ?? readFile5;
22762
22672
  const qrDecodeImpl = dependencies.qrDecodeImpl ?? decodeTicketFromPng;
22763
22673
  const ticketSource = resolveConfirmTicketSource(options);
22764
22674
  const proxyUrl = resolveProxyUrl(options.proxyUrl);
@@ -22896,7 +22806,7 @@ var createPairCommand = (dependencies = {}) => {
22896
22806
  };
22897
22807
 
22898
22808
  // src/commands/verify.ts
22899
- import { readFile as readFile7 } from "fs/promises";
22809
+ import { readFile as readFile6 } from "fs/promises";
22900
22810
  import { Command as Command9 } from "commander";
22901
22811
  var logger10 = createLogger({ service: "cli", module: "verify" });
22902
22812
  var REGISTRY_KEYS_CACHE_FILE = "registry-keys.json";
@@ -22909,7 +22819,7 @@ var VerifyCommandError = class extends Error {
22909
22819
  this.name = "VerifyCommandError";
22910
22820
  }
22911
22821
  };
22912
- var isRecord10 = (value) => {
22822
+ var isRecord9 = (value) => {
22913
22823
  return typeof value === "object" && value !== null;
22914
22824
  };
22915
22825
  var normalizeRegistryUrl = (registryUrl) => {
@@ -22945,7 +22855,7 @@ var resolveToken = async (tokenOrFile) => {
22945
22855
  throw new VerifyCommandError("invalid token (value is empty)");
22946
22856
  }
22947
22857
  try {
22948
- const fileContents = await readFile7(input, "utf-8");
22858
+ const fileContents = await readFile6(input, "utf-8");
22949
22859
  const token = fileContents.trim();
22950
22860
  if (token.length === 0) {
22951
22861
  throw new VerifyCommandError(`invalid token (${input} is empty)`);
@@ -22977,7 +22887,7 @@ var parseResponseJson = async (response) => {
22977
22887
  }
22978
22888
  };
22979
22889
  var parseSigningKeys = (payload) => {
22980
- if (!isRecord10(payload) || !Array.isArray(payload.keys)) {
22890
+ if (!isRecord9(payload) || !Array.isArray(payload.keys)) {
22981
22891
  throw new VerifyCommandError(
22982
22892
  "verification keys unavailable (response payload is invalid)"
22983
22893
  );
@@ -22996,7 +22906,7 @@ var parseSigningKeys = (payload) => {
22996
22906
  };
22997
22907
  var parseRegistryKeysCache = (rawCache) => {
22998
22908
  const parsed = parseJson(rawCache);
22999
- if (!isRecord10(parsed)) {
22909
+ if (!isRecord9(parsed)) {
23000
22910
  return void 0;
23001
22911
  }
23002
22912
  const { registryUrl, fetchedAtMs, keys } = parsed;
@@ -23022,7 +22932,7 @@ var parseRegistryKeysCache = (rawCache) => {
23022
22932
  };
23023
22933
  var parseCrlCache = (rawCache) => {
23024
22934
  const parsed = parseJson(rawCache);
23025
- if (!isRecord10(parsed)) {
22935
+ if (!isRecord9(parsed)) {
23026
22936
  return void 0;
23027
22937
  }
23028
22938
  const { registryUrl, fetchedAtMs, claims } = parsed;
@@ -23120,7 +23030,7 @@ var fetchCrlClaims = async (input) => {
23120
23030
  );
23121
23031
  }
23122
23032
  const payload = await parseResponseJson(response);
23123
- if (!isRecord10(payload) || typeof payload.crl !== "string") {
23033
+ if (!isRecord9(payload) || typeof payload.crl !== "string") {
23124
23034
  throw new VerifyCommandError(
23125
23035
  "revocation check unavailable (response payload is invalid)"
23126
23036
  );
@@ -23165,7 +23075,7 @@ var loadCrlClaims = async (input) => {
23165
23075
  return claims;
23166
23076
  };
23167
23077
  var toInvalidTokenReason = (error48) => {
23168
- if (isRecord10(error48) && typeof error48.message === "string") {
23078
+ if (isRecord9(error48) && typeof error48.message === "string") {
23169
23079
  return `invalid token (${error48.message})`;
23170
23080
  }
23171
23081
  if (error48 instanceof Error && error48.message.length > 0) {