clawdentity 0.0.17 → 0.0.19

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
@@ -17084,7 +17084,8 @@ var FILE_MODE = 384;
17084
17084
  var ENV_KEY_MAP = {
17085
17085
  registryUrl: "CLAWDENTITY_REGISTRY_URL",
17086
17086
  proxyUrl: "CLAWDENTITY_PROXY_URL",
17087
- apiKey: "CLAWDENTITY_API_KEY"
17087
+ apiKey: "CLAWDENTITY_API_KEY",
17088
+ humanName: "CLAWDENTITY_HUMAN_NAME"
17088
17089
  };
17089
17090
  var LEGACY_ENV_KEY_MAP = {
17090
17091
  registryUrl: ["CLAWDENTITY_REGISTRY"]
@@ -17111,6 +17112,9 @@ var normalizeConfig = (raw) => {
17111
17112
  if (typeof raw.apiKey === "string" && raw.apiKey.length > 0) {
17112
17113
  config2.apiKey = raw.apiKey;
17113
17114
  }
17115
+ if (typeof raw.humanName === "string" && raw.humanName.length > 0) {
17116
+ config2.humanName = raw.humanName;
17117
+ }
17114
17118
  return config2;
17115
17119
  };
17116
17120
  var getConfigDir = () => join2(homedir(), CONFIG_DIR);
@@ -18536,7 +18540,8 @@ var logger5 = createLogger({ service: "cli", module: "config" });
18536
18540
  var VALID_KEYS = [
18537
18541
  "registryUrl",
18538
18542
  "proxyUrl",
18539
- "apiKey"
18543
+ "apiKey",
18544
+ "humanName"
18540
18545
  ];
18541
18546
  var isValidConfigKey = (value) => {
18542
18547
  return VALID_KEYS.includes(value);
@@ -20862,11 +20867,20 @@ function parseInviteRedeemResponse(payload) {
20862
20867
  }
20863
20868
  const apiKeyId = parseNonEmptyString7(apiKeySource.id);
20864
20869
  const apiKeyName = parseNonEmptyString7(apiKeySource.name);
20870
+ const humanSource = isRecord7(payload.human) ? payload.human : void 0;
20871
+ const humanName = parseNonEmptyString7(humanSource?.displayName);
20865
20872
  const proxyUrl = parseNonEmptyString7(payload.proxyUrl);
20873
+ if (humanName.length === 0) {
20874
+ throw createCliError5(
20875
+ "CLI_INVITE_REDEEM_INVALID_RESPONSE",
20876
+ "Invite redeem response is invalid"
20877
+ );
20878
+ }
20866
20879
  return {
20867
20880
  apiKeyToken,
20868
20881
  apiKeyId: apiKeyId.length > 0 ? apiKeyId : void 0,
20869
20882
  apiKeyName: apiKeyName.length > 0 ? apiKeyName : void 0,
20883
+ humanName,
20870
20884
  proxyUrl
20871
20885
  };
20872
20886
  }
@@ -20921,6 +20935,14 @@ async function redeemInvite(code, options, dependencies = {}) {
20921
20935
  "Invite code is required"
20922
20936
  );
20923
20937
  }
20938
+ const displayName = parseNonEmptyString7(options.displayName);
20939
+ if (displayName.length === 0) {
20940
+ throw createCliError5(
20941
+ "CLI_INVITE_REDEEM_DISPLAY_NAME_REQUIRED",
20942
+ "Display name is required. Pass --display-name <name>."
20943
+ );
20944
+ }
20945
+ const apiKeyName = parseNonEmptyString7(options.apiKeyName);
20924
20946
  const runtime = await resolveInviteRuntime(options.registryUrl, dependencies);
20925
20947
  const response = await executeInviteRequest({
20926
20948
  fetchImpl: runtime.fetchImpl,
@@ -20930,7 +20952,11 @@ async function redeemInvite(code, options, dependencies = {}) {
20930
20952
  headers: {
20931
20953
  "content-type": "application/json"
20932
20954
  },
20933
- body: JSON.stringify({ code: inviteCode })
20955
+ body: JSON.stringify({
20956
+ code: inviteCode,
20957
+ displayName,
20958
+ apiKeyName: apiKeyName.length > 0 ? apiKeyName : void 0
20959
+ })
20934
20960
  }
20935
20961
  });
20936
20962
  const responseBody = await parseJsonResponse5(response);
@@ -20950,12 +20976,13 @@ async function redeemInvite(code, options, dependencies = {}) {
20950
20976
  registryUrl: runtime.registryUrl
20951
20977
  };
20952
20978
  }
20953
- async function persistRedeemConfig(registryUrl, apiKeyToken, proxyUrl, dependencies = {}) {
20979
+ async function persistRedeemConfig(registryUrl, apiKeyToken, proxyUrl, humanName, dependencies = {}) {
20954
20980
  const setConfigValueImpl = dependencies.setConfigValueImpl ?? setConfigValue;
20955
20981
  try {
20956
20982
  await setConfigValueImpl("registryUrl", registryUrl);
20957
20983
  await setConfigValueImpl("apiKey", apiKeyToken);
20958
20984
  await setConfigValueImpl("proxyUrl", proxyUrl);
20985
+ await setConfigValueImpl("humanName", humanName);
20959
20986
  } catch (error48) {
20960
20987
  logger7.warn("cli.invite_redeem_config_persist_failed", {
20961
20988
  errorName: error48 instanceof Error ? error48.name : "unknown"
@@ -20989,7 +21016,10 @@ var createInviteCommand = (dependencies = {}) => {
20989
21016
  }
20990
21017
  )
20991
21018
  );
20992
- inviteCommand.command("redeem <code>").description("Redeem a registry invite code and store PAT locally").option("--registry-url <url>", "Override registry URL").action(
21019
+ inviteCommand.command("redeem <code>").description("Redeem a registry invite code and store PAT locally").requiredOption(
21020
+ "--display-name <name>",
21021
+ "Human display name used for onboarding"
21022
+ ).option("--api-key-name <name>", "Optional API key label").option("--registry-url <url>", "Override registry URL").action(
20993
21023
  withErrorHandling(
20994
21024
  "invite redeem",
20995
21025
  async (code, options) => {
@@ -20997,9 +21027,11 @@ var createInviteCommand = (dependencies = {}) => {
20997
21027
  logger7.info("cli.invite_redeemed", {
20998
21028
  apiKeyId: result.apiKeyId,
20999
21029
  apiKeyName: result.apiKeyName,
21030
+ humanName: result.humanName,
21000
21031
  registryUrl: result.registryUrl
21001
21032
  });
21002
21033
  writeStdoutLine("Invite redeemed");
21034
+ writeStdoutLine(`Human name: ${result.humanName}`);
21003
21035
  if (result.apiKeyName) {
21004
21036
  writeStdoutLine(`API key name: ${result.apiKeyName}`);
21005
21037
  }
@@ -21009,6 +21041,7 @@ var createInviteCommand = (dependencies = {}) => {
21009
21041
  result.registryUrl,
21010
21042
  result.apiKeyToken,
21011
21043
  result.proxyUrl,
21044
+ result.humanName,
21012
21045
  dependencies
21013
21046
  );
21014
21047
  writeStdoutLine("API key saved to local config");
@@ -21057,7 +21090,6 @@ var HOOK_PATH_SEND_TO_PEER = "send-to-peer";
21057
21090
  var OPENCLAW_SEND_TO_PEER_HOOK_PATH = "hooks/send-to-peer";
21058
21091
  var DEFAULT_OPENCLAW_BASE_URL2 = "http://127.0.0.1:18789";
21059
21092
  var DEFAULT_OPENCLAW_MAIN_SESSION_KEY = "main";
21060
- var DEFAULT_OPENCLAW_AGENT_ID = "main";
21061
21093
  var DEFAULT_CONNECTOR_PORT = 19400;
21062
21094
  var DEFAULT_CONNECTOR_OUTBOUND_PATH3 = "/v1/outbound";
21063
21095
  var DEFAULT_CONNECTOR_STATUS_PATH2 = "/v1/status";
@@ -21074,6 +21106,7 @@ var OPENCLAW_SETUP_COMMAND_HINT = "Run: clawdentity openclaw setup <agentName>";
21074
21106
  var OPENCLAW_SETUP_RESTART_COMMAND_HINT = `${OPENCLAW_SETUP_COMMAND_HINT} and restart OpenClaw`;
21075
21107
  var OPENCLAW_SETUP_WITH_BASE_URL_HINT = `${OPENCLAW_SETUP_COMMAND_HINT} --openclaw-base-url <url>`;
21076
21108
  var OPENCLAW_PAIRING_COMMAND_HINT = "Run QR pairing first: clawdentity pair start <agentName> --qr and clawdentity pair confirm <agentName> --qr-file <path>";
21109
+ var OPENCLAW_DEVICE_APPROVAL_COMMAND_HINT = "Run: openclaw devices list and openclaw devices approve <requestId>";
21077
21110
  var textEncoder2 = new TextEncoder();
21078
21111
  var textDecoder = new TextDecoder();
21079
21112
  function isRecord8(value) {
@@ -21113,11 +21146,11 @@ function parseNonEmptyString8(value, label) {
21113
21146
  }
21114
21147
  return trimmed;
21115
21148
  }
21116
- function parseOptionalName(value) {
21149
+ function parseOptionalProfileName(value, label) {
21117
21150
  if (value === void 0) {
21118
21151
  return void 0;
21119
21152
  }
21120
- return parseNonEmptyString8(value, "name");
21153
+ return parseNonEmptyString8(value, label);
21121
21154
  }
21122
21155
  function parsePeerAlias(value) {
21123
21156
  const alias = parseNonEmptyString8(value, "peer alias");
@@ -21374,12 +21407,13 @@ async function loadPeersConfig(peersPath) {
21374
21407
  }
21375
21408
  const did = parseAgentDid2(value.did, `Peer ${normalizedAlias} did`);
21376
21409
  const proxyUrl = parseProxyUrl(value.proxyUrl);
21377
- const name = parseOptionalName(value.name);
21378
- if (name === void 0) {
21410
+ const agentName = parseOptionalProfileName(value.agentName, "agentName");
21411
+ const humanName = parseOptionalProfileName(value.humanName, "humanName");
21412
+ if (agentName === void 0 && humanName === void 0) {
21379
21413
  peers[normalizedAlias] = { did, proxyUrl };
21380
21414
  continue;
21381
21415
  }
21382
- peers[normalizedAlias] = { did, proxyUrl, name };
21416
+ peers[normalizedAlias] = { did, proxyUrl, agentName, humanName };
21383
21417
  }
21384
21418
  return { peers };
21385
21419
  }
@@ -21739,9 +21773,11 @@ function parseRelayRuntimeConfig(value, relayRuntimeConfigPath) {
21739
21773
  }
21740
21774
  const updatedAt = typeof value.updatedAt === "string" && value.updatedAt.trim().length > 0 ? value.updatedAt.trim() : void 0;
21741
21775
  const openclawHookToken = typeof value.openclawHookToken === "string" && value.openclawHookToken.trim().length > 0 ? value.openclawHookToken.trim() : void 0;
21776
+ const relayTransformPeersPath = typeof value.relayTransformPeersPath === "string" && value.relayTransformPeersPath.trim().length > 0 ? value.relayTransformPeersPath.trim() : void 0;
21742
21777
  return {
21743
21778
  openclawBaseUrl: parseOpenclawBaseUrl(value.openclawBaseUrl),
21744
21779
  openclawHookToken,
21780
+ relayTransformPeersPath,
21745
21781
  updatedAt
21746
21782
  };
21747
21783
  }
@@ -21757,10 +21793,11 @@ async function loadRelayRuntimeConfig(relayRuntimeConfigPath) {
21757
21793
  }
21758
21794
  return parseRelayRuntimeConfig(parsed, relayRuntimeConfigPath);
21759
21795
  }
21760
- async function saveRelayRuntimeConfig(relayRuntimeConfigPath, openclawBaseUrl, openclawHookToken) {
21796
+ async function saveRelayRuntimeConfig(relayRuntimeConfigPath, openclawBaseUrl, openclawHookToken, relayTransformPeersPath) {
21761
21797
  const config2 = {
21762
21798
  openclawBaseUrl,
21763
21799
  ...openclawHookToken ? { openclawHookToken } : {},
21800
+ ...relayTransformPeersPath ? { relayTransformPeersPath } : {},
21764
21801
  updatedAt: nowIso()
21765
21802
  };
21766
21803
  await writeSecureFile3(
@@ -21807,33 +21844,40 @@ function normalizeStringArrayWithValues(value, requiredValues) {
21807
21844
  return Array.from(normalized);
21808
21845
  }
21809
21846
  function resolveHookDefaultSessionKey(config2, hooks) {
21810
- if (typeof hooks.defaultSessionKey === "string" && hooks.defaultSessionKey.trim().length > 0) {
21811
- return hooks.defaultSessionKey.trim();
21812
- }
21813
21847
  const session = isRecord8(config2.session) ? config2.session : {};
21814
21848
  const scope = typeof session.scope === "string" ? session.scope.trim().toLowerCase() : "";
21849
+ const configuredMainSessionKey = resolveConfiguredOpenclawMainSessionKey(session);
21850
+ if (typeof hooks.defaultSessionKey === "string" && hooks.defaultSessionKey.trim().length > 0) {
21851
+ return normalizeLegacyHookDefaultSessionKey(
21852
+ hooks.defaultSessionKey,
21853
+ configuredMainSessionKey
21854
+ );
21855
+ }
21815
21856
  if (scope === "global") {
21816
21857
  return "global";
21817
21858
  }
21818
- const agents = isRecord8(config2.agents) ? config2.agents : {};
21819
- const agentList = Array.isArray(agents.list) ? agents.list : [];
21820
- const defaultAgentId = resolveDefaultOpenclawAgentId(agentList);
21821
- return `agent:${defaultAgentId}:${DEFAULT_OPENCLAW_MAIN_SESSION_KEY}`;
21859
+ return configuredMainSessionKey;
21822
21860
  }
21823
- function resolveDefaultOpenclawAgentId(agentList) {
21824
- const preferred = agentList.find(
21825
- (agent) => isRecord8(agent) && agent.default === true && typeof agent.id === "string" && agent.id.trim().length > 0
21826
- ) ?? agentList.find(
21827
- (agent) => isRecord8(agent) && typeof agent.id === "string" && agent.id.trim().length > 0
21828
- );
21829
- if (isRecord8(preferred) && typeof preferred.id === "string" && preferred.id.trim().length > 0) {
21830
- return normalizeOpenclawIdToken(preferred.id, DEFAULT_OPENCLAW_AGENT_ID);
21861
+ function resolveConfiguredOpenclawMainSessionKey(session) {
21862
+ if (typeof session.mainKey === "string" && session.mainKey.trim().length > 0) {
21863
+ return session.mainKey.trim();
21864
+ }
21865
+ return DEFAULT_OPENCLAW_MAIN_SESSION_KEY;
21866
+ }
21867
+ function normalizeLegacyHookDefaultSessionKey(value, fallbackSessionKey) {
21868
+ const trimmed = value.trim();
21869
+ const legacyMatch = /^agent:[^:]+:(.+)$/i.exec(trimmed);
21870
+ if (!legacyMatch) {
21871
+ return trimmed;
21872
+ }
21873
+ const routedSessionKey = legacyMatch[1]?.trim();
21874
+ if (typeof routedSessionKey === "string" && routedSessionKey.length > 0) {
21875
+ return routedSessionKey;
21831
21876
  }
21832
- return DEFAULT_OPENCLAW_AGENT_ID;
21877
+ return fallbackSessionKey;
21833
21878
  }
21834
- function normalizeOpenclawIdToken(value, fallback) {
21835
- const normalized = value.trim().toLowerCase().replace(/[^a-z0-9_-]+/g, "-").replace(/^-+/g, "").replace(/-+$/g, "").slice(0, 64);
21836
- return normalized.length > 0 ? normalized : fallback;
21879
+ function isCanonicalAgentSessionKey(value) {
21880
+ return /^agent:[^:]+:.+/i.test(value.trim());
21837
21881
  }
21838
21882
  function generateOpenclawHookToken() {
21839
21883
  return randomBytes3(OPENCLAW_HOOK_TOKEN_BYTES).toString("hex");
@@ -22017,103 +22061,105 @@ async function runOpenclawDoctor(options = {}) {
22017
22061
  const openclawDir = resolveOpenclawDir(options.openclawDir, homeDir);
22018
22062
  const peerAlias = parseDoctorPeerAlias(options.peerAlias);
22019
22063
  const checks = [];
22020
- const resolveConfigImpl = options.resolveConfigImpl ?? resolveConfig;
22021
- try {
22022
- const resolvedConfig = await resolveConfigImpl();
22023
- const envProxyUrl = typeof process.env.CLAWDENTITY_PROXY_URL === "string" ? process.env.CLAWDENTITY_PROXY_URL.trim() : "";
22024
- if (typeof resolvedConfig.registryUrl !== "string" || resolvedConfig.registryUrl.trim().length === 0) {
22025
- checks.push(
22026
- toDoctorCheck({
22027
- id: "config.registry",
22028
- label: "CLI config",
22029
- status: "fail",
22030
- message: "registryUrl is missing",
22031
- remediationHint: "Run: clawdentity config set registryUrl <REGISTRY_URL>"
22032
- })
22033
- );
22034
- } else if (typeof resolvedConfig.apiKey !== "string" || resolvedConfig.apiKey.trim().length === 0) {
22035
- checks.push(
22036
- toDoctorCheck({
22037
- id: "config.registry",
22038
- label: "CLI config",
22039
- status: "fail",
22040
- message: "apiKey is missing",
22041
- remediationHint: "Run: clawdentity config set apiKey <API_KEY>"
22042
- })
22043
- );
22044
- } else if (envProxyUrl.length > 0) {
22045
- let hasValidEnvProxyUrl = true;
22046
- try {
22047
- parseProxyUrl(envProxyUrl);
22048
- } catch {
22049
- hasValidEnvProxyUrl = false;
22064
+ if (options.includeConfigCheck !== false) {
22065
+ const resolveConfigImpl = options.resolveConfigImpl ?? resolveConfig;
22066
+ try {
22067
+ const resolvedConfig = await resolveConfigImpl();
22068
+ const envProxyUrl = typeof process.env.CLAWDENTITY_PROXY_URL === "string" ? process.env.CLAWDENTITY_PROXY_URL.trim() : "";
22069
+ if (typeof resolvedConfig.registryUrl !== "string" || resolvedConfig.registryUrl.trim().length === 0) {
22050
22070
  checks.push(
22051
22071
  toDoctorCheck({
22052
22072
  id: "config.registry",
22053
22073
  label: "CLI config",
22054
22074
  status: "fail",
22055
- message: "CLAWDENTITY_PROXY_URL is invalid",
22056
- remediationHint: "Set CLAWDENTITY_PROXY_URL to a valid http(s) URL or unset it"
22075
+ message: "registryUrl is missing",
22076
+ remediationHint: "Run: clawdentity config set registryUrl <REGISTRY_URL>"
22057
22077
  })
22058
22078
  );
22059
- }
22060
- if (hasValidEnvProxyUrl) {
22079
+ } else if (typeof resolvedConfig.apiKey !== "string" || resolvedConfig.apiKey.trim().length === 0) {
22061
22080
  checks.push(
22062
22081
  toDoctorCheck({
22063
22082
  id: "config.registry",
22064
22083
  label: "CLI config",
22065
- status: "pass",
22066
- message: "registryUrl and apiKey are configured (proxy URL override is active via CLAWDENTITY_PROXY_URL)"
22084
+ status: "fail",
22085
+ message: "apiKey is missing",
22086
+ remediationHint: "Run: clawdentity config set apiKey <API_KEY>"
22067
22087
  })
22068
22088
  );
22069
- }
22070
- } else if (typeof resolvedConfig.proxyUrl !== "string" || resolvedConfig.proxyUrl.trim().length === 0) {
22071
- checks.push(
22072
- toDoctorCheck({
22073
- id: "config.registry",
22074
- label: "CLI config",
22075
- status: "fail",
22076
- message: "proxyUrl is missing",
22077
- remediationHint: "Run: clawdentity invite redeem <clw_inv_...> or clawdentity config init"
22078
- })
22079
- );
22080
- } else {
22081
- let hasValidConfigProxyUrl = true;
22082
- try {
22083
- parseProxyUrl(resolvedConfig.proxyUrl);
22084
- } catch {
22085
- hasValidConfigProxyUrl = false;
22089
+ } else if (envProxyUrl.length > 0) {
22090
+ let hasValidEnvProxyUrl = true;
22091
+ try {
22092
+ parseProxyUrl(envProxyUrl);
22093
+ } catch {
22094
+ hasValidEnvProxyUrl = false;
22095
+ checks.push(
22096
+ toDoctorCheck({
22097
+ id: "config.registry",
22098
+ label: "CLI config",
22099
+ status: "fail",
22100
+ message: "CLAWDENTITY_PROXY_URL is invalid",
22101
+ remediationHint: "Set CLAWDENTITY_PROXY_URL to a valid http(s) URL or unset it"
22102
+ })
22103
+ );
22104
+ }
22105
+ if (hasValidEnvProxyUrl) {
22106
+ checks.push(
22107
+ toDoctorCheck({
22108
+ id: "config.registry",
22109
+ label: "CLI config",
22110
+ status: "pass",
22111
+ message: "registryUrl and apiKey are configured (proxy URL override is active via CLAWDENTITY_PROXY_URL)"
22112
+ })
22113
+ );
22114
+ }
22115
+ } else if (typeof resolvedConfig.proxyUrl !== "string" || resolvedConfig.proxyUrl.trim().length === 0) {
22086
22116
  checks.push(
22087
22117
  toDoctorCheck({
22088
22118
  id: "config.registry",
22089
22119
  label: "CLI config",
22090
22120
  status: "fail",
22091
- message: "proxyUrl is invalid",
22121
+ message: "proxyUrl is missing",
22092
22122
  remediationHint: "Run: clawdentity invite redeem <clw_inv_...> or clawdentity config init"
22093
22123
  })
22094
22124
  );
22125
+ } else {
22126
+ let hasValidConfigProxyUrl = true;
22127
+ try {
22128
+ parseProxyUrl(resolvedConfig.proxyUrl);
22129
+ } catch {
22130
+ hasValidConfigProxyUrl = false;
22131
+ checks.push(
22132
+ toDoctorCheck({
22133
+ id: "config.registry",
22134
+ label: "CLI config",
22135
+ status: "fail",
22136
+ message: "proxyUrl is invalid",
22137
+ remediationHint: "Run: clawdentity invite redeem <clw_inv_...> or clawdentity config init"
22138
+ })
22139
+ );
22140
+ }
22141
+ if (hasValidConfigProxyUrl) {
22142
+ checks.push(
22143
+ toDoctorCheck({
22144
+ id: "config.registry",
22145
+ label: "CLI config",
22146
+ status: "pass",
22147
+ message: "registryUrl, apiKey, and proxyUrl are configured"
22148
+ })
22149
+ );
22150
+ }
22095
22151
  }
22096
- if (hasValidConfigProxyUrl) {
22097
- checks.push(
22098
- toDoctorCheck({
22099
- id: "config.registry",
22100
- label: "CLI config",
22101
- status: "pass",
22102
- message: "registryUrl, apiKey, and proxyUrl are configured"
22103
- })
22104
- );
22105
- }
22152
+ } catch {
22153
+ checks.push(
22154
+ toDoctorCheck({
22155
+ id: "config.registry",
22156
+ label: "CLI config",
22157
+ status: "fail",
22158
+ message: "unable to resolve CLI config",
22159
+ remediationHint: "Fix ~/.clawdentity/config.json or rerun: clawdentity config init"
22160
+ })
22161
+ );
22106
22162
  }
22107
- } catch {
22108
- checks.push(
22109
- toDoctorCheck({
22110
- id: "config.registry",
22111
- label: "CLI config",
22112
- status: "fail",
22113
- message: "unable to resolve CLI config",
22114
- remediationHint: "Fix ~/.clawdentity/config.json or rerun: clawdentity config init"
22115
- })
22116
- );
22117
22163
  }
22118
22164
  const selectedAgentPath = resolveOpenclawAgentNamePath(homeDir);
22119
22165
  let selectedAgentName;
@@ -22302,6 +22348,15 @@ async function runOpenclawDoctor(options = {}) {
22302
22348
  const hooks = isRecord8(openclawConfig.hooks) ? openclawConfig.hooks : {};
22303
22349
  const hooksEnabled = hooks.enabled === true;
22304
22350
  const hookToken = typeof hooks.token === "string" && hooks.token.trim().length > 0 ? hooks.token.trim() : void 0;
22351
+ const defaultSessionKey = typeof hooks.defaultSessionKey === "string" && hooks.defaultSessionKey.trim().length > 0 ? hooks.defaultSessionKey.trim() : void 0;
22352
+ const allowRequestSessionKey = hooks.allowRequestSessionKey === false;
22353
+ const allowedSessionKeyPrefixes = normalizeStringArrayWithValues(
22354
+ hooks.allowedSessionKeyPrefixes,
22355
+ []
22356
+ );
22357
+ const missingRequiredSessionPrefixes = defaultSessionKey === void 0 ? ["hook:"] : ["hook:", defaultSessionKey].filter(
22358
+ (prefix) => !allowedSessionKeyPrefixes.includes(prefix)
22359
+ );
22305
22360
  const mappings = Array.isArray(hooks.mappings) ? hooks.mappings.filter(isRecord8) : [];
22306
22361
  const relayMapping = mappings.find(
22307
22362
  (mapping) => isRelayHookMapping(mapping)
@@ -22361,6 +22416,45 @@ async function runOpenclawDoctor(options = {}) {
22361
22416
  })
22362
22417
  );
22363
22418
  }
22419
+ const sessionRoutingIssues = [];
22420
+ if (defaultSessionKey === void 0) {
22421
+ sessionRoutingIssues.push("hooks.defaultSessionKey is missing");
22422
+ }
22423
+ if (!allowRequestSessionKey) {
22424
+ sessionRoutingIssues.push("hooks.allowRequestSessionKey is not false");
22425
+ }
22426
+ if (missingRequiredSessionPrefixes.length > 0) {
22427
+ sessionRoutingIssues.push(
22428
+ `hooks.allowedSessionKeyPrefixes is missing: ${missingRequiredSessionPrefixes.join(", ")}`
22429
+ );
22430
+ }
22431
+ if (defaultSessionKey !== void 0 && isCanonicalAgentSessionKey(defaultSessionKey)) {
22432
+ sessionRoutingIssues.push(
22433
+ "hooks.defaultSessionKey uses canonical agent format (agent:<id>:...); use OpenClaw request session keys like main, global, or subagent:*"
22434
+ );
22435
+ }
22436
+ if (sessionRoutingIssues.length > 0) {
22437
+ checks.push(
22438
+ toDoctorCheck({
22439
+ id: "state.hookSessionRouting",
22440
+ label: "OpenClaw hook session routing",
22441
+ status: "fail",
22442
+ message: sessionRoutingIssues.join("; "),
22443
+ remediationHint: OPENCLAW_SETUP_RESTART_COMMAND_HINT,
22444
+ details: { openclawConfigPath }
22445
+ })
22446
+ );
22447
+ } else {
22448
+ checks.push(
22449
+ toDoctorCheck({
22450
+ id: "state.hookSessionRouting",
22451
+ label: "OpenClaw hook session routing",
22452
+ status: "pass",
22453
+ message: "hooks default session and allowed session prefixes are configured",
22454
+ details: { openclawConfigPath }
22455
+ })
22456
+ );
22457
+ }
22364
22458
  } catch {
22365
22459
  checks.push(
22366
22460
  toDoctorCheck({
@@ -22382,6 +22476,16 @@ async function runOpenclawDoctor(options = {}) {
22382
22476
  details: { openclawConfigPath }
22383
22477
  })
22384
22478
  );
22479
+ checks.push(
22480
+ toDoctorCheck({
22481
+ id: "state.hookSessionRouting",
22482
+ label: "OpenClaw hook session routing",
22483
+ status: "fail",
22484
+ message: `unable to read ${openclawConfigPath}`,
22485
+ remediationHint: "Ensure the OpenClaw config file exists (OPENCLAW_CONFIG_PATH/CLAWDBOT_CONFIG_PATH, or state dir) and rerun openclaw setup",
22486
+ details: { openclawConfigPath }
22487
+ })
22488
+ );
22385
22489
  }
22386
22490
  const relayRuntimeConfigPath = resolveRelayRuntimeConfigPath(homeDir);
22387
22491
  try {
@@ -22407,6 +22511,72 @@ async function runOpenclawDoctor(options = {}) {
22407
22511
  })
22408
22512
  );
22409
22513
  }
22514
+ const gatewayDevicePendingPath = join6(openclawDir, "devices", "pending.json");
22515
+ try {
22516
+ const pendingPayload = await readJsonFile(gatewayDevicePendingPath);
22517
+ if (!isRecord8(pendingPayload)) {
22518
+ checks.push(
22519
+ toDoctorCheck({
22520
+ id: "state.gatewayDevicePairing",
22521
+ label: "OpenClaw gateway device pairing",
22522
+ status: "fail",
22523
+ message: `invalid pending device approvals file: ${gatewayDevicePendingPath}`,
22524
+ remediationHint: OPENCLAW_DEVICE_APPROVAL_COMMAND_HINT,
22525
+ details: { gatewayDevicePendingPath }
22526
+ })
22527
+ );
22528
+ } else {
22529
+ const pendingRequestIds = Object.keys(pendingPayload);
22530
+ if (pendingRequestIds.length === 0) {
22531
+ checks.push(
22532
+ toDoctorCheck({
22533
+ id: "state.gatewayDevicePairing",
22534
+ label: "OpenClaw gateway device pairing",
22535
+ status: "pass",
22536
+ message: "no pending gateway device approvals",
22537
+ details: { gatewayDevicePendingPath }
22538
+ })
22539
+ );
22540
+ } else {
22541
+ checks.push(
22542
+ toDoctorCheck({
22543
+ id: "state.gatewayDevicePairing",
22544
+ label: "OpenClaw gateway device pairing",
22545
+ status: "fail",
22546
+ message: `pending gateway device approvals: ${pendingRequestIds.length}`,
22547
+ remediationHint: OPENCLAW_DEVICE_APPROVAL_COMMAND_HINT,
22548
+ details: {
22549
+ gatewayDevicePendingPath,
22550
+ pendingRequestIds
22551
+ }
22552
+ })
22553
+ );
22554
+ }
22555
+ }
22556
+ } catch (error48) {
22557
+ if (getErrorCode2(error48) === "ENOENT") {
22558
+ checks.push(
22559
+ toDoctorCheck({
22560
+ id: "state.gatewayDevicePairing",
22561
+ label: "OpenClaw gateway device pairing",
22562
+ status: "pass",
22563
+ message: "no pending gateway device approvals file was found",
22564
+ details: { gatewayDevicePendingPath }
22565
+ })
22566
+ );
22567
+ } else {
22568
+ checks.push(
22569
+ toDoctorCheck({
22570
+ id: "state.gatewayDevicePairing",
22571
+ label: "OpenClaw gateway device pairing",
22572
+ status: "fail",
22573
+ message: `unable to read pending device approvals at ${gatewayDevicePendingPath}`,
22574
+ remediationHint: OPENCLAW_DEVICE_APPROVAL_COMMAND_HINT,
22575
+ details: { gatewayDevicePendingPath }
22576
+ })
22577
+ );
22578
+ }
22579
+ }
22410
22580
  if (options.includeConnectorRuntimeCheck !== false) {
22411
22581
  if (selectedAgentName === void 0) {
22412
22582
  checks.push(
@@ -22769,7 +22939,8 @@ async function setupOpenclawRelay(agentName, options) {
22769
22939
  await saveRelayRuntimeConfig(
22770
22940
  relayRuntimeConfigPath,
22771
22941
  openclawBaseUrl,
22772
- patchedOpenclawConfig.hookToken
22942
+ patchedOpenclawConfig.hookToken,
22943
+ relayTransformPeersPath
22773
22944
  );
22774
22945
  logger8.info("cli.openclaw_setup_completed", {
22775
22946
  agentName: normalizedAgentName,
@@ -22791,9 +22962,45 @@ async function setupOpenclawRelay(agentName, options) {
22791
22962
  relayRuntimeConfigPath
22792
22963
  };
22793
22964
  }
22965
+ async function assertSetupChecklistHealthy(input) {
22966
+ const checklist = await runOpenclawDoctor({
22967
+ homeDir: input.homeDir,
22968
+ openclawDir: input.openclawDir,
22969
+ includeConfigCheck: false,
22970
+ includeConnectorRuntimeCheck: input.includeConnectorRuntimeCheck
22971
+ });
22972
+ if (checklist.status === "healthy") {
22973
+ return;
22974
+ }
22975
+ const firstFailure = checklist.checks.find((check2) => check2.status === "fail");
22976
+ throw createCliError6(
22977
+ "CLI_OPENCLAW_SETUP_CHECKLIST_FAILED",
22978
+ "OpenClaw setup checklist failed",
22979
+ {
22980
+ firstFailedCheckId: firstFailure?.id,
22981
+ firstFailedCheckMessage: firstFailure?.message,
22982
+ remediationHint: firstFailure?.remediationHint,
22983
+ checks: checklist.checks
22984
+ }
22985
+ );
22986
+ }
22794
22987
  async function setupOpenclawSelfReady(agentName, options) {
22795
- const setup = await setupOpenclawRelay(agentName, options);
22988
+ const resolvedHomeDir = resolveHomeDir(options.homeDir);
22989
+ const resolvedOpenclawDir = resolveOpenclawDir(
22990
+ options.openclawDir,
22991
+ resolvedHomeDir
22992
+ );
22993
+ const setup = await setupOpenclawRelay(agentName, {
22994
+ ...options,
22995
+ homeDir: resolvedHomeDir,
22996
+ openclawDir: resolvedOpenclawDir
22997
+ });
22796
22998
  if (options.noRuntimeStart === true) {
22999
+ await assertSetupChecklistHealthy({
23000
+ homeDir: resolvedHomeDir,
23001
+ openclawDir: resolvedOpenclawDir,
23002
+ includeConnectorRuntimeCheck: false
23003
+ });
22797
23004
  return {
22798
23005
  ...setup,
22799
23006
  runtimeMode: "none",
@@ -22812,7 +23019,6 @@ async function setupOpenclawSelfReady(agentName, options) {
22812
23019
  const waitTimeoutSeconds = parseWaitTimeoutSeconds(
22813
23020
  options.waitTimeoutSeconds
22814
23021
  );
22815
- const resolvedHomeDir = resolveHomeDir(options.homeDir);
22816
23022
  const runtime = await startSetupConnectorRuntime({
22817
23023
  agentName: assertValidAgentName(agentName),
22818
23024
  homeDir: resolvedHomeDir,
@@ -22822,6 +23028,11 @@ async function setupOpenclawSelfReady(agentName, options) {
22822
23028
  waitTimeoutSeconds,
22823
23029
  fetchImpl
22824
23030
  });
23031
+ await assertSetupChecklistHealthy({
23032
+ homeDir: resolvedHomeDir,
23033
+ openclawDir: resolvedOpenclawDir,
23034
+ includeConnectorRuntimeCheck: true
23035
+ });
22825
23036
  return {
22826
23037
  ...setup,
22827
23038
  ...runtime
@@ -22967,6 +23178,7 @@ var AIT_FILE_NAME4 = "ait.jwt";
22967
23178
  var SECRET_KEY_FILE_NAME3 = "secret.key";
22968
23179
  var PAIRING_QR_DIR_NAME = "pairing";
22969
23180
  var PEERS_FILE_NAME2 = "peers.json";
23181
+ var OPENCLAW_RELAY_RUNTIME_FILE_NAME3 = "openclaw-relay.json";
22970
23182
  var PAIR_START_PATH = "/pair/start";
22971
23183
  var PAIR_CONFIRM_PATH = "/pair/confirm";
22972
23184
  var PAIR_STATUS_PATH = "/pair/status";
@@ -22978,6 +23190,7 @@ var FILE_MODE4 = 384;
22978
23190
  var PEER_ALIAS_PATTERN2 = /^[a-zA-Z0-9._-]+$/;
22979
23191
  var DEFAULT_STATUS_WAIT_SECONDS = 300;
22980
23192
  var DEFAULT_STATUS_POLL_INTERVAL_SECONDS = 3;
23193
+ var MAX_PROFILE_NAME_LENGTH = 64;
22981
23194
  var isRecord9 = (value) => {
22982
23195
  return typeof value === "object" && value !== null;
22983
23196
  };
@@ -22994,6 +23207,49 @@ function parseNonEmptyString9(value) {
22994
23207
  }
22995
23208
  return value.trim();
22996
23209
  }
23210
+ function hasControlChars2(value) {
23211
+ for (let index = 0; index < value.length; index += 1) {
23212
+ const code = value.charCodeAt(index);
23213
+ if (code <= 31 || code === 127) {
23214
+ return true;
23215
+ }
23216
+ }
23217
+ return false;
23218
+ }
23219
+ function parseProfileName(value, label) {
23220
+ const candidate = parseNonEmptyString9(value);
23221
+ if (candidate.length === 0) {
23222
+ throw createCliError7(
23223
+ "CLI_PAIR_PROFILE_INVALID",
23224
+ `${label} is required for pairing`
23225
+ );
23226
+ }
23227
+ if (candidate.length > MAX_PROFILE_NAME_LENGTH) {
23228
+ throw createCliError7(
23229
+ "CLI_PAIR_PROFILE_INVALID",
23230
+ `${label} must be at most ${MAX_PROFILE_NAME_LENGTH} characters`
23231
+ );
23232
+ }
23233
+ if (hasControlChars2(candidate)) {
23234
+ throw createCliError7(
23235
+ "CLI_PAIR_PROFILE_INVALID",
23236
+ `${label} contains control characters`
23237
+ );
23238
+ }
23239
+ return candidate;
23240
+ }
23241
+ function parsePeerProfile(payload) {
23242
+ if (!isRecord9(payload)) {
23243
+ throw createCliError7(
23244
+ "CLI_PAIR_PROFILE_INVALID",
23245
+ "Pair profile must be an object"
23246
+ );
23247
+ }
23248
+ return {
23249
+ agentName: parseProfileName(payload.agentName, "agentName"),
23250
+ humanName: parseProfileName(payload.humanName, "humanName")
23251
+ };
23252
+ }
22997
23253
  function parsePairingTicket(value) {
22998
23254
  const ticket = parseNonEmptyString9(value);
22999
23255
  if (!ticket.startsWith(PAIRING_TICKET_PREFIX)) {
@@ -23158,10 +23414,19 @@ function parsePeerEntry(value) {
23158
23414
  "Peer entry is invalid"
23159
23415
  );
23160
23416
  }
23161
- return {
23417
+ const agentNameRaw = parseNonEmptyString9(value.agentName);
23418
+ const humanNameRaw = parseNonEmptyString9(value.humanName);
23419
+ const entry = {
23162
23420
  did,
23163
23421
  proxyUrl
23164
23422
  };
23423
+ if (agentNameRaw.length > 0) {
23424
+ entry.agentName = parseProfileName(agentNameRaw, "agentName");
23425
+ }
23426
+ if (humanNameRaw.length > 0) {
23427
+ entry.humanName = parseProfileName(humanNameRaw, "humanName");
23428
+ }
23429
+ return entry;
23165
23430
  }
23166
23431
  async function loadPeersConfig2(input) {
23167
23432
  const peersPath = resolvePeersConfigPath(input.getConfigDirImpl);
@@ -23216,6 +23481,86 @@ async function savePeersConfig2(input) {
23216
23481
  );
23217
23482
  await input.chmodImpl(peersPath, FILE_MODE4);
23218
23483
  }
23484
+ function resolveRelayRuntimeConfigPath2(getConfigDirImpl) {
23485
+ return join7(getConfigDirImpl(), OPENCLAW_RELAY_RUNTIME_FILE_NAME3);
23486
+ }
23487
+ async function loadRelayTransformPeersPath(input) {
23488
+ const relayRuntimeConfigPath = resolveRelayRuntimeConfigPath2(
23489
+ input.getConfigDirImpl
23490
+ );
23491
+ let raw;
23492
+ try {
23493
+ raw = await input.readFileImpl(relayRuntimeConfigPath, "utf8");
23494
+ } catch (error48) {
23495
+ const nodeError = error48;
23496
+ if (nodeError.code === "ENOENT") {
23497
+ return void 0;
23498
+ }
23499
+ logger9.warn("cli.pair.relay_runtime_read_failed", {
23500
+ relayRuntimeConfigPath,
23501
+ reason: error48 instanceof Error && error48.message.length > 0 ? error48.message : "unknown"
23502
+ });
23503
+ return void 0;
23504
+ }
23505
+ let parsed;
23506
+ try {
23507
+ parsed = JSON.parse(raw);
23508
+ } catch {
23509
+ logger9.warn("cli.pair.relay_runtime_invalid_json", {
23510
+ relayRuntimeConfigPath
23511
+ });
23512
+ return void 0;
23513
+ }
23514
+ if (!isRecord9(parsed)) {
23515
+ return void 0;
23516
+ }
23517
+ const relayTransformPeersPath = parseNonEmptyString9(
23518
+ parsed.relayTransformPeersPath
23519
+ );
23520
+ if (relayTransformPeersPath.length === 0) {
23521
+ return void 0;
23522
+ }
23523
+ return resolve(relayTransformPeersPath);
23524
+ }
23525
+ async function syncOpenclawRelayPeersSnapshot(input) {
23526
+ const relayTransformPeersPath = await loadRelayTransformPeersPath({
23527
+ getConfigDirImpl: input.getConfigDirImpl,
23528
+ readFileImpl: input.readFileImpl
23529
+ });
23530
+ if (relayTransformPeersPath === void 0) {
23531
+ return;
23532
+ }
23533
+ try {
23534
+ await input.readFileImpl(relayTransformPeersPath, "utf8");
23535
+ } catch (error48) {
23536
+ const nodeError = error48;
23537
+ if (nodeError.code === "ENOENT") {
23538
+ return;
23539
+ }
23540
+ logger9.warn("cli.pair.relay_peers_snapshot_probe_failed", {
23541
+ relayTransformPeersPath,
23542
+ reason: error48 instanceof Error && error48.message.length > 0 ? error48.message : "unknown"
23543
+ });
23544
+ return;
23545
+ }
23546
+ try {
23547
+ await input.mkdirImpl(dirname5(relayTransformPeersPath), {
23548
+ recursive: true
23549
+ });
23550
+ await input.writeFileImpl(
23551
+ relayTransformPeersPath,
23552
+ `${JSON.stringify(input.config, null, 2)}
23553
+ `,
23554
+ "utf8"
23555
+ );
23556
+ await input.chmodImpl(relayTransformPeersPath, FILE_MODE4);
23557
+ } catch (error48) {
23558
+ logger9.warn("cli.pair.relay_peers_snapshot_write_failed", {
23559
+ relayTransformPeersPath,
23560
+ reason: error48 instanceof Error && error48.message.length > 0 ? error48.message : "unknown"
23561
+ });
23562
+ }
23563
+ }
23219
23564
  function parseTtlSeconds(value) {
23220
23565
  const raw = parseNonEmptyString9(value);
23221
23566
  if (raw.length === 0) {
@@ -23244,6 +23589,19 @@ function parsePositiveIntegerOption(input) {
23244
23589
  }
23245
23590
  return parsed;
23246
23591
  }
23592
+ function resolveLocalPairProfile(input) {
23593
+ const humanName = parseNonEmptyString9(input.config.humanName);
23594
+ if (humanName.length === 0) {
23595
+ throw createCliError7(
23596
+ "CLI_PAIR_HUMAN_NAME_MISSING",
23597
+ "Human name is missing. Run `clawdentity invite redeem <clw_inv_...> --display-name <name>` or `clawdentity config set humanName <name>`."
23598
+ );
23599
+ }
23600
+ return {
23601
+ agentName: parseProfileName(input.agentName, "agentName"),
23602
+ humanName: parseProfileName(humanName, "humanName")
23603
+ };
23604
+ }
23247
23605
  function parseProxyUrl2(candidate) {
23248
23606
  try {
23249
23607
  const parsed = new URL(candidate);
@@ -23394,15 +23752,25 @@ function parsePairStartResponse(payload) {
23394
23752
  const ticket = parsePairingTicket(payload.ticket);
23395
23753
  const initiatorAgentDid = parseNonEmptyString9(payload.initiatorAgentDid);
23396
23754
  const expiresAt = parseNonEmptyString9(payload.expiresAt);
23755
+ let initiatorProfile;
23397
23756
  if (initiatorAgentDid.length === 0 || expiresAt.length === 0) {
23398
23757
  throw createCliError7(
23399
23758
  "CLI_PAIR_START_INVALID_RESPONSE",
23400
23759
  "Pair start response is invalid"
23401
23760
  );
23402
23761
  }
23762
+ try {
23763
+ initiatorProfile = parsePeerProfile(payload.initiatorProfile);
23764
+ } catch {
23765
+ throw createCliError7(
23766
+ "CLI_PAIR_START_INVALID_RESPONSE",
23767
+ "Pair start response is invalid"
23768
+ );
23769
+ }
23403
23770
  return {
23404
23771
  ticket,
23405
23772
  initiatorAgentDid,
23773
+ initiatorProfile,
23406
23774
  expiresAt
23407
23775
  };
23408
23776
  }
@@ -23416,16 +23784,29 @@ function parsePairConfirmResponse(payload) {
23416
23784
  const paired = payload.paired === true;
23417
23785
  const initiatorAgentDid = parseNonEmptyString9(payload.initiatorAgentDid);
23418
23786
  const responderAgentDid = parseNonEmptyString9(payload.responderAgentDid);
23787
+ let initiatorProfile;
23788
+ let responderProfile;
23419
23789
  if (!paired || initiatorAgentDid.length === 0 || responderAgentDid.length === 0) {
23420
23790
  throw createCliError7(
23421
23791
  "CLI_PAIR_CONFIRM_INVALID_RESPONSE",
23422
23792
  "Pair confirm response is invalid"
23423
23793
  );
23424
23794
  }
23795
+ try {
23796
+ initiatorProfile = parsePeerProfile(payload.initiatorProfile);
23797
+ responderProfile = parsePeerProfile(payload.responderProfile);
23798
+ } catch {
23799
+ throw createCliError7(
23800
+ "CLI_PAIR_CONFIRM_INVALID_RESPONSE",
23801
+ "Pair confirm response is invalid"
23802
+ );
23803
+ }
23425
23804
  return {
23426
23805
  paired,
23427
23806
  initiatorAgentDid,
23428
- responderAgentDid
23807
+ responderAgentDid,
23808
+ initiatorProfile,
23809
+ responderProfile
23429
23810
  };
23430
23811
  }
23431
23812
  function parsePairStatusResponse(payload) {
@@ -23446,6 +23827,7 @@ function parsePairStatusResponse(payload) {
23446
23827
  const responderAgentDid = parseNonEmptyString9(payload.responderAgentDid);
23447
23828
  const expiresAt = parseNonEmptyString9(payload.expiresAt);
23448
23829
  const confirmedAt = parseNonEmptyString9(payload.confirmedAt);
23830
+ let initiatorProfile;
23449
23831
  if (initiatorAgentDid.length === 0 || expiresAt.length === 0) {
23450
23832
  throw createCliError7(
23451
23833
  "CLI_PAIR_STATUS_INVALID_RESPONSE",
@@ -23458,10 +23840,37 @@ function parsePairStatusResponse(payload) {
23458
23840
  "Pair status response is invalid"
23459
23841
  );
23460
23842
  }
23843
+ try {
23844
+ initiatorProfile = parsePeerProfile(payload.initiatorProfile);
23845
+ } catch {
23846
+ throw createCliError7(
23847
+ "CLI_PAIR_STATUS_INVALID_RESPONSE",
23848
+ "Pair status response is invalid"
23849
+ );
23850
+ }
23851
+ let responderProfile;
23852
+ if (payload.responderProfile !== void 0) {
23853
+ try {
23854
+ responderProfile = parsePeerProfile(payload.responderProfile);
23855
+ } catch {
23856
+ throw createCliError7(
23857
+ "CLI_PAIR_STATUS_INVALID_RESPONSE",
23858
+ "Pair status response is invalid"
23859
+ );
23860
+ }
23861
+ }
23862
+ if (statusRaw === "confirmed" && responderProfile === void 0) {
23863
+ throw createCliError7(
23864
+ "CLI_PAIR_STATUS_INVALID_RESPONSE",
23865
+ "Pair status response is invalid"
23866
+ );
23867
+ }
23461
23868
  return {
23462
23869
  status: statusRaw,
23463
23870
  initiatorAgentDid,
23871
+ initiatorProfile,
23464
23872
  responderAgentDid: responderAgentDid.length > 0 ? responderAgentDid : void 0,
23873
+ responderProfile,
23465
23874
  expiresAt,
23466
23875
  confirmedAt: confirmedAt.length > 0 ? confirmedAt : void 0
23467
23876
  };
@@ -23666,7 +24075,9 @@ async function persistPairedPeer(input) {
23666
24075
  });
23667
24076
  peersConfig.peers[alias] = {
23668
24077
  did: input.peerDid,
23669
- proxyUrl: peerProxyUrl
24078
+ proxyUrl: peerProxyUrl,
24079
+ agentName: input.peerProfile.agentName,
24080
+ humanName: input.peerProfile.humanName
23670
24081
  };
23671
24082
  await savePeersConfig2({
23672
24083
  config: peersConfig,
@@ -23675,6 +24086,14 @@ async function persistPairedPeer(input) {
23675
24086
  writeFileImpl,
23676
24087
  chmodImpl
23677
24088
  });
24089
+ await syncOpenclawRelayPeersSnapshot({
24090
+ config: peersConfig,
24091
+ getConfigDirImpl,
24092
+ readFileImpl,
24093
+ mkdirImpl,
24094
+ writeFileImpl,
24095
+ chmodImpl
24096
+ });
23678
24097
  return alias;
23679
24098
  }
23680
24099
  async function startPairing(agentName, options, dependencies = {}) {
@@ -23688,13 +24107,19 @@ async function startPairing(agentName, options, dependencies = {}) {
23688
24107
  config: config2,
23689
24108
  fetchImpl
23690
24109
  });
24110
+ const normalizedAgentName = assertValidAgentName(agentName);
24111
+ const initiatorProfile = resolveLocalPairProfile({
24112
+ config: config2,
24113
+ agentName: normalizedAgentName
24114
+ });
23691
24115
  const { ait, secretKey } = await readAgentProofMaterial(
23692
- agentName,
24116
+ normalizedAgentName,
23693
24117
  dependencies
23694
24118
  );
23695
24119
  const requestUrl = toProxyRequestUrl(proxyUrl, PAIR_START_PATH);
23696
24120
  const requestBody = JSON.stringify({
23697
- ttlSeconds
24121
+ ttlSeconds,
24122
+ initiatorProfile
23698
24123
  });
23699
24124
  const bodyBytes = new TextEncoder().encode(requestBody);
23700
24125
  const timestampSeconds = nowSecondsImpl();
@@ -23751,6 +24176,11 @@ async function confirmPairing(agentName, options, dependencies = {}) {
23751
24176
  const readFileImpl = dependencies.readFileImpl ?? readFile6;
23752
24177
  const qrDecodeImpl = dependencies.qrDecodeImpl ?? decodeTicketFromPng;
23753
24178
  const config2 = await resolveConfigImpl();
24179
+ const normalizedAgentName = assertValidAgentName(agentName);
24180
+ const responderProfile = resolveLocalPairProfile({
24181
+ config: config2,
24182
+ agentName: normalizedAgentName
24183
+ });
23754
24184
  const ticketSource = resolveConfirmTicketSource(options);
23755
24185
  const proxyUrl = await resolveProxyUrl({
23756
24186
  config: config2,
@@ -23780,11 +24210,14 @@ async function confirmPairing(agentName, options, dependencies = {}) {
23780
24210
  ticket = parsePairingTicket(qrDecodeImpl(new Uint8Array(imageBytes)));
23781
24211
  }
23782
24212
  const { ait, secretKey } = await readAgentProofMaterial(
23783
- agentName,
24213
+ normalizedAgentName,
23784
24214
  dependencies
23785
24215
  );
23786
24216
  const requestUrl = toProxyRequestUrl(proxyUrl, PAIR_CONFIRM_PATH);
23787
- const requestBody = JSON.stringify({ ticket });
24217
+ const requestBody = JSON.stringify({
24218
+ ticket,
24219
+ responderProfile
24220
+ });
23788
24221
  const bodyBytes = new TextEncoder().encode(requestBody);
23789
24222
  const timestampSeconds = nowSecondsImpl();
23790
24223
  const nonce = nonceFactoryImpl();
@@ -23820,6 +24253,7 @@ async function confirmPairing(agentName, options, dependencies = {}) {
23820
24253
  const peerAlias = await persistPairedPeer({
23821
24254
  ticket,
23822
24255
  peerDid: parsed.initiatorAgentDid,
24256
+ peerProfile: parsed.initiatorProfile,
23823
24257
  dependencies
23824
24258
  });
23825
24259
  if (ticketSource.source === "qr-file" && ticketSource.qrFilePath) {
@@ -23901,15 +24335,23 @@ async function getPairingStatusOnce(agentName, options, dependencies = {}) {
23901
24335
  );
23902
24336
  }
23903
24337
  const peerDid = callerAgentDid === parsed.initiatorAgentDid ? responderAgentDid : callerAgentDid === responderAgentDid ? parsed.initiatorAgentDid : void 0;
24338
+ const peerProfile = callerAgentDid === parsed.initiatorAgentDid ? parsed.responderProfile : callerAgentDid === responderAgentDid ? parsed.initiatorProfile : void 0;
23904
24339
  if (!peerDid) {
23905
24340
  throw createCliError7(
23906
24341
  "CLI_PAIR_STATUS_FORBIDDEN",
23907
24342
  "Local agent is not a participant in the pairing ticket"
23908
24343
  );
23909
24344
  }
24345
+ if (!peerProfile) {
24346
+ throw createCliError7(
24347
+ "CLI_PAIR_STATUS_INVALID_RESPONSE",
24348
+ "Pair status response is invalid"
24349
+ );
24350
+ }
23910
24351
  peerAlias = await persistPairedPeer({
23911
24352
  ticket,
23912
24353
  peerDid,
24354
+ peerProfile,
23913
24355
  dependencies
23914
24356
  });
23915
24357
  }
@@ -24005,6 +24447,12 @@ var createPairCommand = (dependencies = {}) => {
24005
24447
  writeStdoutLine("Pairing ticket created");
24006
24448
  writeStdoutLine(`Ticket: ${result.ticket}`);
24007
24449
  writeStdoutLine(`Initiator Agent DID: ${result.initiatorAgentDid}`);
24450
+ writeStdoutLine(
24451
+ `Initiator Agent Name: ${result.initiatorProfile.agentName}`
24452
+ );
24453
+ writeStdoutLine(
24454
+ `Initiator Human Name: ${result.initiatorProfile.humanName}`
24455
+ );
24008
24456
  writeStdoutLine(`Expires At: ${result.expiresAt}`);
24009
24457
  if (result.qrPath) {
24010
24458
  writeStdoutLine(`QR File: ${result.qrPath}`);
@@ -24047,6 +24495,14 @@ var createPairCommand = (dependencies = {}) => {
24047
24495
  `Responder Agent DID: ${status.responderAgentDid}`
24048
24496
  );
24049
24497
  }
24498
+ if (status.responderProfile) {
24499
+ writeStdoutLine(
24500
+ `Responder Agent Name: ${status.responderProfile.agentName}`
24501
+ );
24502
+ writeStdoutLine(
24503
+ `Responder Human Name: ${status.responderProfile.humanName}`
24504
+ );
24505
+ }
24050
24506
  if (status.peerAlias) {
24051
24507
  writeStdoutLine(`Peer alias saved: ${status.peerAlias}`);
24052
24508
  }
@@ -24067,7 +24523,19 @@ var createPairCommand = (dependencies = {}) => {
24067
24523
  });
24068
24524
  writeStdoutLine("Pairing confirmed");
24069
24525
  writeStdoutLine(`Initiator Agent DID: ${result.initiatorAgentDid}`);
24526
+ writeStdoutLine(
24527
+ `Initiator Agent Name: ${result.initiatorProfile.agentName}`
24528
+ );
24529
+ writeStdoutLine(
24530
+ `Initiator Human Name: ${result.initiatorProfile.humanName}`
24531
+ );
24070
24532
  writeStdoutLine(`Responder Agent DID: ${result.responderAgentDid}`);
24533
+ writeStdoutLine(
24534
+ `Responder Agent Name: ${result.responderProfile.agentName}`
24535
+ );
24536
+ writeStdoutLine(
24537
+ `Responder Human Name: ${result.responderProfile.humanName}`
24538
+ );
24071
24539
  writeStdoutLine(`Paired: ${result.paired ? "true" : "false"}`);
24072
24540
  if (result.peerAlias) {
24073
24541
  writeStdoutLine(`Peer alias saved: ${result.peerAlias}`);
@@ -24099,9 +24567,23 @@ var createPairCommand = (dependencies = {}) => {
24099
24567
  });
24100
24568
  writeStdoutLine(`Status: ${result.status}`);
24101
24569
  writeStdoutLine(`Initiator Agent DID: ${result.initiatorAgentDid}`);
24570
+ writeStdoutLine(
24571
+ `Initiator Agent Name: ${result.initiatorProfile.agentName}`
24572
+ );
24573
+ writeStdoutLine(
24574
+ `Initiator Human Name: ${result.initiatorProfile.humanName}`
24575
+ );
24102
24576
  if (result.responderAgentDid) {
24103
24577
  writeStdoutLine(`Responder Agent DID: ${result.responderAgentDid}`);
24104
24578
  }
24579
+ if (result.responderProfile) {
24580
+ writeStdoutLine(
24581
+ `Responder Agent Name: ${result.responderProfile.agentName}`
24582
+ );
24583
+ writeStdoutLine(
24584
+ `Responder Human Name: ${result.responderProfile.humanName}`
24585
+ );
24586
+ }
24105
24587
  writeStdoutLine(`Expires At: ${result.expiresAt}`);
24106
24588
  if (result.confirmedAt) {
24107
24589
  writeStdoutLine(`Confirmed At: ${result.confirmedAt}`);