clawdentity 0.0.17 → 0.0.18

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");
@@ -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
  }
@@ -22978,6 +23012,7 @@ var FILE_MODE4 = 384;
22978
23012
  var PEER_ALIAS_PATTERN2 = /^[a-zA-Z0-9._-]+$/;
22979
23013
  var DEFAULT_STATUS_WAIT_SECONDS = 300;
22980
23014
  var DEFAULT_STATUS_POLL_INTERVAL_SECONDS = 3;
23015
+ var MAX_PROFILE_NAME_LENGTH = 64;
22981
23016
  var isRecord9 = (value) => {
22982
23017
  return typeof value === "object" && value !== null;
22983
23018
  };
@@ -22994,6 +23029,49 @@ function parseNonEmptyString9(value) {
22994
23029
  }
22995
23030
  return value.trim();
22996
23031
  }
23032
+ function hasControlChars2(value) {
23033
+ for (let index = 0; index < value.length; index += 1) {
23034
+ const code = value.charCodeAt(index);
23035
+ if (code <= 31 || code === 127) {
23036
+ return true;
23037
+ }
23038
+ }
23039
+ return false;
23040
+ }
23041
+ function parseProfileName(value, label) {
23042
+ const candidate = parseNonEmptyString9(value);
23043
+ if (candidate.length === 0) {
23044
+ throw createCliError7(
23045
+ "CLI_PAIR_PROFILE_INVALID",
23046
+ `${label} is required for pairing`
23047
+ );
23048
+ }
23049
+ if (candidate.length > MAX_PROFILE_NAME_LENGTH) {
23050
+ throw createCliError7(
23051
+ "CLI_PAIR_PROFILE_INVALID",
23052
+ `${label} must be at most ${MAX_PROFILE_NAME_LENGTH} characters`
23053
+ );
23054
+ }
23055
+ if (hasControlChars2(candidate)) {
23056
+ throw createCliError7(
23057
+ "CLI_PAIR_PROFILE_INVALID",
23058
+ `${label} contains control characters`
23059
+ );
23060
+ }
23061
+ return candidate;
23062
+ }
23063
+ function parsePeerProfile(payload) {
23064
+ if (!isRecord9(payload)) {
23065
+ throw createCliError7(
23066
+ "CLI_PAIR_PROFILE_INVALID",
23067
+ "Pair profile must be an object"
23068
+ );
23069
+ }
23070
+ return {
23071
+ agentName: parseProfileName(payload.agentName, "agentName"),
23072
+ humanName: parseProfileName(payload.humanName, "humanName")
23073
+ };
23074
+ }
22997
23075
  function parsePairingTicket(value) {
22998
23076
  const ticket = parseNonEmptyString9(value);
22999
23077
  if (!ticket.startsWith(PAIRING_TICKET_PREFIX)) {
@@ -23158,10 +23236,19 @@ function parsePeerEntry(value) {
23158
23236
  "Peer entry is invalid"
23159
23237
  );
23160
23238
  }
23161
- return {
23239
+ const agentNameRaw = parseNonEmptyString9(value.agentName);
23240
+ const humanNameRaw = parseNonEmptyString9(value.humanName);
23241
+ const entry = {
23162
23242
  did,
23163
23243
  proxyUrl
23164
23244
  };
23245
+ if (agentNameRaw.length > 0) {
23246
+ entry.agentName = parseProfileName(agentNameRaw, "agentName");
23247
+ }
23248
+ if (humanNameRaw.length > 0) {
23249
+ entry.humanName = parseProfileName(humanNameRaw, "humanName");
23250
+ }
23251
+ return entry;
23165
23252
  }
23166
23253
  async function loadPeersConfig2(input) {
23167
23254
  const peersPath = resolvePeersConfigPath(input.getConfigDirImpl);
@@ -23244,6 +23331,19 @@ function parsePositiveIntegerOption(input) {
23244
23331
  }
23245
23332
  return parsed;
23246
23333
  }
23334
+ function resolveLocalPairProfile(input) {
23335
+ const humanName = parseNonEmptyString9(input.config.humanName);
23336
+ if (humanName.length === 0) {
23337
+ throw createCliError7(
23338
+ "CLI_PAIR_HUMAN_NAME_MISSING",
23339
+ "Human name is missing. Run `clawdentity invite redeem <clw_inv_...> --display-name <name>` or `clawdentity config set humanName <name>`."
23340
+ );
23341
+ }
23342
+ return {
23343
+ agentName: parseProfileName(input.agentName, "agentName"),
23344
+ humanName: parseProfileName(humanName, "humanName")
23345
+ };
23346
+ }
23247
23347
  function parseProxyUrl2(candidate) {
23248
23348
  try {
23249
23349
  const parsed = new URL(candidate);
@@ -23394,15 +23494,25 @@ function parsePairStartResponse(payload) {
23394
23494
  const ticket = parsePairingTicket(payload.ticket);
23395
23495
  const initiatorAgentDid = parseNonEmptyString9(payload.initiatorAgentDid);
23396
23496
  const expiresAt = parseNonEmptyString9(payload.expiresAt);
23497
+ let initiatorProfile;
23397
23498
  if (initiatorAgentDid.length === 0 || expiresAt.length === 0) {
23398
23499
  throw createCliError7(
23399
23500
  "CLI_PAIR_START_INVALID_RESPONSE",
23400
23501
  "Pair start response is invalid"
23401
23502
  );
23402
23503
  }
23504
+ try {
23505
+ initiatorProfile = parsePeerProfile(payload.initiatorProfile);
23506
+ } catch {
23507
+ throw createCliError7(
23508
+ "CLI_PAIR_START_INVALID_RESPONSE",
23509
+ "Pair start response is invalid"
23510
+ );
23511
+ }
23403
23512
  return {
23404
23513
  ticket,
23405
23514
  initiatorAgentDid,
23515
+ initiatorProfile,
23406
23516
  expiresAt
23407
23517
  };
23408
23518
  }
@@ -23416,16 +23526,29 @@ function parsePairConfirmResponse(payload) {
23416
23526
  const paired = payload.paired === true;
23417
23527
  const initiatorAgentDid = parseNonEmptyString9(payload.initiatorAgentDid);
23418
23528
  const responderAgentDid = parseNonEmptyString9(payload.responderAgentDid);
23529
+ let initiatorProfile;
23530
+ let responderProfile;
23419
23531
  if (!paired || initiatorAgentDid.length === 0 || responderAgentDid.length === 0) {
23420
23532
  throw createCliError7(
23421
23533
  "CLI_PAIR_CONFIRM_INVALID_RESPONSE",
23422
23534
  "Pair confirm response is invalid"
23423
23535
  );
23424
23536
  }
23537
+ try {
23538
+ initiatorProfile = parsePeerProfile(payload.initiatorProfile);
23539
+ responderProfile = parsePeerProfile(payload.responderProfile);
23540
+ } catch {
23541
+ throw createCliError7(
23542
+ "CLI_PAIR_CONFIRM_INVALID_RESPONSE",
23543
+ "Pair confirm response is invalid"
23544
+ );
23545
+ }
23425
23546
  return {
23426
23547
  paired,
23427
23548
  initiatorAgentDid,
23428
- responderAgentDid
23549
+ responderAgentDid,
23550
+ initiatorProfile,
23551
+ responderProfile
23429
23552
  };
23430
23553
  }
23431
23554
  function parsePairStatusResponse(payload) {
@@ -23446,6 +23569,7 @@ function parsePairStatusResponse(payload) {
23446
23569
  const responderAgentDid = parseNonEmptyString9(payload.responderAgentDid);
23447
23570
  const expiresAt = parseNonEmptyString9(payload.expiresAt);
23448
23571
  const confirmedAt = parseNonEmptyString9(payload.confirmedAt);
23572
+ let initiatorProfile;
23449
23573
  if (initiatorAgentDid.length === 0 || expiresAt.length === 0) {
23450
23574
  throw createCliError7(
23451
23575
  "CLI_PAIR_STATUS_INVALID_RESPONSE",
@@ -23458,10 +23582,37 @@ function parsePairStatusResponse(payload) {
23458
23582
  "Pair status response is invalid"
23459
23583
  );
23460
23584
  }
23585
+ try {
23586
+ initiatorProfile = parsePeerProfile(payload.initiatorProfile);
23587
+ } catch {
23588
+ throw createCliError7(
23589
+ "CLI_PAIR_STATUS_INVALID_RESPONSE",
23590
+ "Pair status response is invalid"
23591
+ );
23592
+ }
23593
+ let responderProfile;
23594
+ if (payload.responderProfile !== void 0) {
23595
+ try {
23596
+ responderProfile = parsePeerProfile(payload.responderProfile);
23597
+ } catch {
23598
+ throw createCliError7(
23599
+ "CLI_PAIR_STATUS_INVALID_RESPONSE",
23600
+ "Pair status response is invalid"
23601
+ );
23602
+ }
23603
+ }
23604
+ if (statusRaw === "confirmed" && responderProfile === void 0) {
23605
+ throw createCliError7(
23606
+ "CLI_PAIR_STATUS_INVALID_RESPONSE",
23607
+ "Pair status response is invalid"
23608
+ );
23609
+ }
23461
23610
  return {
23462
23611
  status: statusRaw,
23463
23612
  initiatorAgentDid,
23613
+ initiatorProfile,
23464
23614
  responderAgentDid: responderAgentDid.length > 0 ? responderAgentDid : void 0,
23615
+ responderProfile,
23465
23616
  expiresAt,
23466
23617
  confirmedAt: confirmedAt.length > 0 ? confirmedAt : void 0
23467
23618
  };
@@ -23666,7 +23817,9 @@ async function persistPairedPeer(input) {
23666
23817
  });
23667
23818
  peersConfig.peers[alias] = {
23668
23819
  did: input.peerDid,
23669
- proxyUrl: peerProxyUrl
23820
+ proxyUrl: peerProxyUrl,
23821
+ agentName: input.peerProfile.agentName,
23822
+ humanName: input.peerProfile.humanName
23670
23823
  };
23671
23824
  await savePeersConfig2({
23672
23825
  config: peersConfig,
@@ -23688,13 +23841,19 @@ async function startPairing(agentName, options, dependencies = {}) {
23688
23841
  config: config2,
23689
23842
  fetchImpl
23690
23843
  });
23844
+ const normalizedAgentName = assertValidAgentName(agentName);
23845
+ const initiatorProfile = resolveLocalPairProfile({
23846
+ config: config2,
23847
+ agentName: normalizedAgentName
23848
+ });
23691
23849
  const { ait, secretKey } = await readAgentProofMaterial(
23692
- agentName,
23850
+ normalizedAgentName,
23693
23851
  dependencies
23694
23852
  );
23695
23853
  const requestUrl = toProxyRequestUrl(proxyUrl, PAIR_START_PATH);
23696
23854
  const requestBody = JSON.stringify({
23697
- ttlSeconds
23855
+ ttlSeconds,
23856
+ initiatorProfile
23698
23857
  });
23699
23858
  const bodyBytes = new TextEncoder().encode(requestBody);
23700
23859
  const timestampSeconds = nowSecondsImpl();
@@ -23751,6 +23910,11 @@ async function confirmPairing(agentName, options, dependencies = {}) {
23751
23910
  const readFileImpl = dependencies.readFileImpl ?? readFile6;
23752
23911
  const qrDecodeImpl = dependencies.qrDecodeImpl ?? decodeTicketFromPng;
23753
23912
  const config2 = await resolveConfigImpl();
23913
+ const normalizedAgentName = assertValidAgentName(agentName);
23914
+ const responderProfile = resolveLocalPairProfile({
23915
+ config: config2,
23916
+ agentName: normalizedAgentName
23917
+ });
23754
23918
  const ticketSource = resolveConfirmTicketSource(options);
23755
23919
  const proxyUrl = await resolveProxyUrl({
23756
23920
  config: config2,
@@ -23780,11 +23944,14 @@ async function confirmPairing(agentName, options, dependencies = {}) {
23780
23944
  ticket = parsePairingTicket(qrDecodeImpl(new Uint8Array(imageBytes)));
23781
23945
  }
23782
23946
  const { ait, secretKey } = await readAgentProofMaterial(
23783
- agentName,
23947
+ normalizedAgentName,
23784
23948
  dependencies
23785
23949
  );
23786
23950
  const requestUrl = toProxyRequestUrl(proxyUrl, PAIR_CONFIRM_PATH);
23787
- const requestBody = JSON.stringify({ ticket });
23951
+ const requestBody = JSON.stringify({
23952
+ ticket,
23953
+ responderProfile
23954
+ });
23788
23955
  const bodyBytes = new TextEncoder().encode(requestBody);
23789
23956
  const timestampSeconds = nowSecondsImpl();
23790
23957
  const nonce = nonceFactoryImpl();
@@ -23820,6 +23987,7 @@ async function confirmPairing(agentName, options, dependencies = {}) {
23820
23987
  const peerAlias = await persistPairedPeer({
23821
23988
  ticket,
23822
23989
  peerDid: parsed.initiatorAgentDid,
23990
+ peerProfile: parsed.initiatorProfile,
23823
23991
  dependencies
23824
23992
  });
23825
23993
  if (ticketSource.source === "qr-file" && ticketSource.qrFilePath) {
@@ -23901,15 +24069,23 @@ async function getPairingStatusOnce(agentName, options, dependencies = {}) {
23901
24069
  );
23902
24070
  }
23903
24071
  const peerDid = callerAgentDid === parsed.initiatorAgentDid ? responderAgentDid : callerAgentDid === responderAgentDid ? parsed.initiatorAgentDid : void 0;
24072
+ const peerProfile = callerAgentDid === parsed.initiatorAgentDid ? parsed.responderProfile : callerAgentDid === responderAgentDid ? parsed.initiatorProfile : void 0;
23904
24073
  if (!peerDid) {
23905
24074
  throw createCliError7(
23906
24075
  "CLI_PAIR_STATUS_FORBIDDEN",
23907
24076
  "Local agent is not a participant in the pairing ticket"
23908
24077
  );
23909
24078
  }
24079
+ if (!peerProfile) {
24080
+ throw createCliError7(
24081
+ "CLI_PAIR_STATUS_INVALID_RESPONSE",
24082
+ "Pair status response is invalid"
24083
+ );
24084
+ }
23910
24085
  peerAlias = await persistPairedPeer({
23911
24086
  ticket,
23912
24087
  peerDid,
24088
+ peerProfile,
23913
24089
  dependencies
23914
24090
  });
23915
24091
  }
@@ -24005,6 +24181,12 @@ var createPairCommand = (dependencies = {}) => {
24005
24181
  writeStdoutLine("Pairing ticket created");
24006
24182
  writeStdoutLine(`Ticket: ${result.ticket}`);
24007
24183
  writeStdoutLine(`Initiator Agent DID: ${result.initiatorAgentDid}`);
24184
+ writeStdoutLine(
24185
+ `Initiator Agent Name: ${result.initiatorProfile.agentName}`
24186
+ );
24187
+ writeStdoutLine(
24188
+ `Initiator Human Name: ${result.initiatorProfile.humanName}`
24189
+ );
24008
24190
  writeStdoutLine(`Expires At: ${result.expiresAt}`);
24009
24191
  if (result.qrPath) {
24010
24192
  writeStdoutLine(`QR File: ${result.qrPath}`);
@@ -24047,6 +24229,14 @@ var createPairCommand = (dependencies = {}) => {
24047
24229
  `Responder Agent DID: ${status.responderAgentDid}`
24048
24230
  );
24049
24231
  }
24232
+ if (status.responderProfile) {
24233
+ writeStdoutLine(
24234
+ `Responder Agent Name: ${status.responderProfile.agentName}`
24235
+ );
24236
+ writeStdoutLine(
24237
+ `Responder Human Name: ${status.responderProfile.humanName}`
24238
+ );
24239
+ }
24050
24240
  if (status.peerAlias) {
24051
24241
  writeStdoutLine(`Peer alias saved: ${status.peerAlias}`);
24052
24242
  }
@@ -24067,7 +24257,19 @@ var createPairCommand = (dependencies = {}) => {
24067
24257
  });
24068
24258
  writeStdoutLine("Pairing confirmed");
24069
24259
  writeStdoutLine(`Initiator Agent DID: ${result.initiatorAgentDid}`);
24260
+ writeStdoutLine(
24261
+ `Initiator Agent Name: ${result.initiatorProfile.agentName}`
24262
+ );
24263
+ writeStdoutLine(
24264
+ `Initiator Human Name: ${result.initiatorProfile.humanName}`
24265
+ );
24070
24266
  writeStdoutLine(`Responder Agent DID: ${result.responderAgentDid}`);
24267
+ writeStdoutLine(
24268
+ `Responder Agent Name: ${result.responderProfile.agentName}`
24269
+ );
24270
+ writeStdoutLine(
24271
+ `Responder Human Name: ${result.responderProfile.humanName}`
24272
+ );
24071
24273
  writeStdoutLine(`Paired: ${result.paired ? "true" : "false"}`);
24072
24274
  if (result.peerAlias) {
24073
24275
  writeStdoutLine(`Peer alias saved: ${result.peerAlias}`);
@@ -24099,9 +24301,23 @@ var createPairCommand = (dependencies = {}) => {
24099
24301
  });
24100
24302
  writeStdoutLine(`Status: ${result.status}`);
24101
24303
  writeStdoutLine(`Initiator Agent DID: ${result.initiatorAgentDid}`);
24304
+ writeStdoutLine(
24305
+ `Initiator Agent Name: ${result.initiatorProfile.agentName}`
24306
+ );
24307
+ writeStdoutLine(
24308
+ `Initiator Human Name: ${result.initiatorProfile.humanName}`
24309
+ );
24102
24310
  if (result.responderAgentDid) {
24103
24311
  writeStdoutLine(`Responder Agent DID: ${result.responderAgentDid}`);
24104
24312
  }
24313
+ if (result.responderProfile) {
24314
+ writeStdoutLine(
24315
+ `Responder Agent Name: ${result.responderProfile.agentName}`
24316
+ );
24317
+ writeStdoutLine(
24318
+ `Responder Human Name: ${result.responderProfile.humanName}`
24319
+ );
24320
+ }
24105
24321
  writeStdoutLine(`Expires At: ${result.expiresAt}`);
24106
24322
  if (result.confirmedAt) {
24107
24323
  writeStdoutLine(`Confirmed At: ${result.confirmedAt}`);
package/dist/index.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");
@@ -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
  }
@@ -22978,6 +23012,7 @@ var FILE_MODE4 = 384;
22978
23012
  var PEER_ALIAS_PATTERN2 = /^[a-zA-Z0-9._-]+$/;
22979
23013
  var DEFAULT_STATUS_WAIT_SECONDS = 300;
22980
23014
  var DEFAULT_STATUS_POLL_INTERVAL_SECONDS = 3;
23015
+ var MAX_PROFILE_NAME_LENGTH = 64;
22981
23016
  var isRecord9 = (value) => {
22982
23017
  return typeof value === "object" && value !== null;
22983
23018
  };
@@ -22994,6 +23029,49 @@ function parseNonEmptyString9(value) {
22994
23029
  }
22995
23030
  return value.trim();
22996
23031
  }
23032
+ function hasControlChars2(value) {
23033
+ for (let index = 0; index < value.length; index += 1) {
23034
+ const code = value.charCodeAt(index);
23035
+ if (code <= 31 || code === 127) {
23036
+ return true;
23037
+ }
23038
+ }
23039
+ return false;
23040
+ }
23041
+ function parseProfileName(value, label) {
23042
+ const candidate = parseNonEmptyString9(value);
23043
+ if (candidate.length === 0) {
23044
+ throw createCliError7(
23045
+ "CLI_PAIR_PROFILE_INVALID",
23046
+ `${label} is required for pairing`
23047
+ );
23048
+ }
23049
+ if (candidate.length > MAX_PROFILE_NAME_LENGTH) {
23050
+ throw createCliError7(
23051
+ "CLI_PAIR_PROFILE_INVALID",
23052
+ `${label} must be at most ${MAX_PROFILE_NAME_LENGTH} characters`
23053
+ );
23054
+ }
23055
+ if (hasControlChars2(candidate)) {
23056
+ throw createCliError7(
23057
+ "CLI_PAIR_PROFILE_INVALID",
23058
+ `${label} contains control characters`
23059
+ );
23060
+ }
23061
+ return candidate;
23062
+ }
23063
+ function parsePeerProfile(payload) {
23064
+ if (!isRecord9(payload)) {
23065
+ throw createCliError7(
23066
+ "CLI_PAIR_PROFILE_INVALID",
23067
+ "Pair profile must be an object"
23068
+ );
23069
+ }
23070
+ return {
23071
+ agentName: parseProfileName(payload.agentName, "agentName"),
23072
+ humanName: parseProfileName(payload.humanName, "humanName")
23073
+ };
23074
+ }
22997
23075
  function parsePairingTicket(value) {
22998
23076
  const ticket = parseNonEmptyString9(value);
22999
23077
  if (!ticket.startsWith(PAIRING_TICKET_PREFIX)) {
@@ -23158,10 +23236,19 @@ function parsePeerEntry(value) {
23158
23236
  "Peer entry is invalid"
23159
23237
  );
23160
23238
  }
23161
- return {
23239
+ const agentNameRaw = parseNonEmptyString9(value.agentName);
23240
+ const humanNameRaw = parseNonEmptyString9(value.humanName);
23241
+ const entry = {
23162
23242
  did,
23163
23243
  proxyUrl
23164
23244
  };
23245
+ if (agentNameRaw.length > 0) {
23246
+ entry.agentName = parseProfileName(agentNameRaw, "agentName");
23247
+ }
23248
+ if (humanNameRaw.length > 0) {
23249
+ entry.humanName = parseProfileName(humanNameRaw, "humanName");
23250
+ }
23251
+ return entry;
23165
23252
  }
23166
23253
  async function loadPeersConfig2(input) {
23167
23254
  const peersPath = resolvePeersConfigPath(input.getConfigDirImpl);
@@ -23244,6 +23331,19 @@ function parsePositiveIntegerOption(input) {
23244
23331
  }
23245
23332
  return parsed;
23246
23333
  }
23334
+ function resolveLocalPairProfile(input) {
23335
+ const humanName = parseNonEmptyString9(input.config.humanName);
23336
+ if (humanName.length === 0) {
23337
+ throw createCliError7(
23338
+ "CLI_PAIR_HUMAN_NAME_MISSING",
23339
+ "Human name is missing. Run `clawdentity invite redeem <clw_inv_...> --display-name <name>` or `clawdentity config set humanName <name>`."
23340
+ );
23341
+ }
23342
+ return {
23343
+ agentName: parseProfileName(input.agentName, "agentName"),
23344
+ humanName: parseProfileName(humanName, "humanName")
23345
+ };
23346
+ }
23247
23347
  function parseProxyUrl2(candidate) {
23248
23348
  try {
23249
23349
  const parsed = new URL(candidate);
@@ -23394,15 +23494,25 @@ function parsePairStartResponse(payload) {
23394
23494
  const ticket = parsePairingTicket(payload.ticket);
23395
23495
  const initiatorAgentDid = parseNonEmptyString9(payload.initiatorAgentDid);
23396
23496
  const expiresAt = parseNonEmptyString9(payload.expiresAt);
23497
+ let initiatorProfile;
23397
23498
  if (initiatorAgentDid.length === 0 || expiresAt.length === 0) {
23398
23499
  throw createCliError7(
23399
23500
  "CLI_PAIR_START_INVALID_RESPONSE",
23400
23501
  "Pair start response is invalid"
23401
23502
  );
23402
23503
  }
23504
+ try {
23505
+ initiatorProfile = parsePeerProfile(payload.initiatorProfile);
23506
+ } catch {
23507
+ throw createCliError7(
23508
+ "CLI_PAIR_START_INVALID_RESPONSE",
23509
+ "Pair start response is invalid"
23510
+ );
23511
+ }
23403
23512
  return {
23404
23513
  ticket,
23405
23514
  initiatorAgentDid,
23515
+ initiatorProfile,
23406
23516
  expiresAt
23407
23517
  };
23408
23518
  }
@@ -23416,16 +23526,29 @@ function parsePairConfirmResponse(payload) {
23416
23526
  const paired = payload.paired === true;
23417
23527
  const initiatorAgentDid = parseNonEmptyString9(payload.initiatorAgentDid);
23418
23528
  const responderAgentDid = parseNonEmptyString9(payload.responderAgentDid);
23529
+ let initiatorProfile;
23530
+ let responderProfile;
23419
23531
  if (!paired || initiatorAgentDid.length === 0 || responderAgentDid.length === 0) {
23420
23532
  throw createCliError7(
23421
23533
  "CLI_PAIR_CONFIRM_INVALID_RESPONSE",
23422
23534
  "Pair confirm response is invalid"
23423
23535
  );
23424
23536
  }
23537
+ try {
23538
+ initiatorProfile = parsePeerProfile(payload.initiatorProfile);
23539
+ responderProfile = parsePeerProfile(payload.responderProfile);
23540
+ } catch {
23541
+ throw createCliError7(
23542
+ "CLI_PAIR_CONFIRM_INVALID_RESPONSE",
23543
+ "Pair confirm response is invalid"
23544
+ );
23545
+ }
23425
23546
  return {
23426
23547
  paired,
23427
23548
  initiatorAgentDid,
23428
- responderAgentDid
23549
+ responderAgentDid,
23550
+ initiatorProfile,
23551
+ responderProfile
23429
23552
  };
23430
23553
  }
23431
23554
  function parsePairStatusResponse(payload) {
@@ -23446,6 +23569,7 @@ function parsePairStatusResponse(payload) {
23446
23569
  const responderAgentDid = parseNonEmptyString9(payload.responderAgentDid);
23447
23570
  const expiresAt = parseNonEmptyString9(payload.expiresAt);
23448
23571
  const confirmedAt = parseNonEmptyString9(payload.confirmedAt);
23572
+ let initiatorProfile;
23449
23573
  if (initiatorAgentDid.length === 0 || expiresAt.length === 0) {
23450
23574
  throw createCliError7(
23451
23575
  "CLI_PAIR_STATUS_INVALID_RESPONSE",
@@ -23458,10 +23582,37 @@ function parsePairStatusResponse(payload) {
23458
23582
  "Pair status response is invalid"
23459
23583
  );
23460
23584
  }
23585
+ try {
23586
+ initiatorProfile = parsePeerProfile(payload.initiatorProfile);
23587
+ } catch {
23588
+ throw createCliError7(
23589
+ "CLI_PAIR_STATUS_INVALID_RESPONSE",
23590
+ "Pair status response is invalid"
23591
+ );
23592
+ }
23593
+ let responderProfile;
23594
+ if (payload.responderProfile !== void 0) {
23595
+ try {
23596
+ responderProfile = parsePeerProfile(payload.responderProfile);
23597
+ } catch {
23598
+ throw createCliError7(
23599
+ "CLI_PAIR_STATUS_INVALID_RESPONSE",
23600
+ "Pair status response is invalid"
23601
+ );
23602
+ }
23603
+ }
23604
+ if (statusRaw === "confirmed" && responderProfile === void 0) {
23605
+ throw createCliError7(
23606
+ "CLI_PAIR_STATUS_INVALID_RESPONSE",
23607
+ "Pair status response is invalid"
23608
+ );
23609
+ }
23461
23610
  return {
23462
23611
  status: statusRaw,
23463
23612
  initiatorAgentDid,
23613
+ initiatorProfile,
23464
23614
  responderAgentDid: responderAgentDid.length > 0 ? responderAgentDid : void 0,
23615
+ responderProfile,
23465
23616
  expiresAt,
23466
23617
  confirmedAt: confirmedAt.length > 0 ? confirmedAt : void 0
23467
23618
  };
@@ -23666,7 +23817,9 @@ async function persistPairedPeer(input) {
23666
23817
  });
23667
23818
  peersConfig.peers[alias] = {
23668
23819
  did: input.peerDid,
23669
- proxyUrl: peerProxyUrl
23820
+ proxyUrl: peerProxyUrl,
23821
+ agentName: input.peerProfile.agentName,
23822
+ humanName: input.peerProfile.humanName
23670
23823
  };
23671
23824
  await savePeersConfig2({
23672
23825
  config: peersConfig,
@@ -23688,13 +23841,19 @@ async function startPairing(agentName, options, dependencies = {}) {
23688
23841
  config: config2,
23689
23842
  fetchImpl
23690
23843
  });
23844
+ const normalizedAgentName = assertValidAgentName(agentName);
23845
+ const initiatorProfile = resolveLocalPairProfile({
23846
+ config: config2,
23847
+ agentName: normalizedAgentName
23848
+ });
23691
23849
  const { ait, secretKey } = await readAgentProofMaterial(
23692
- agentName,
23850
+ normalizedAgentName,
23693
23851
  dependencies
23694
23852
  );
23695
23853
  const requestUrl = toProxyRequestUrl(proxyUrl, PAIR_START_PATH);
23696
23854
  const requestBody = JSON.stringify({
23697
- ttlSeconds
23855
+ ttlSeconds,
23856
+ initiatorProfile
23698
23857
  });
23699
23858
  const bodyBytes = new TextEncoder().encode(requestBody);
23700
23859
  const timestampSeconds = nowSecondsImpl();
@@ -23751,6 +23910,11 @@ async function confirmPairing(agentName, options, dependencies = {}) {
23751
23910
  const readFileImpl = dependencies.readFileImpl ?? readFile6;
23752
23911
  const qrDecodeImpl = dependencies.qrDecodeImpl ?? decodeTicketFromPng;
23753
23912
  const config2 = await resolveConfigImpl();
23913
+ const normalizedAgentName = assertValidAgentName(agentName);
23914
+ const responderProfile = resolveLocalPairProfile({
23915
+ config: config2,
23916
+ agentName: normalizedAgentName
23917
+ });
23754
23918
  const ticketSource = resolveConfirmTicketSource(options);
23755
23919
  const proxyUrl = await resolveProxyUrl({
23756
23920
  config: config2,
@@ -23780,11 +23944,14 @@ async function confirmPairing(agentName, options, dependencies = {}) {
23780
23944
  ticket = parsePairingTicket(qrDecodeImpl(new Uint8Array(imageBytes)));
23781
23945
  }
23782
23946
  const { ait, secretKey } = await readAgentProofMaterial(
23783
- agentName,
23947
+ normalizedAgentName,
23784
23948
  dependencies
23785
23949
  );
23786
23950
  const requestUrl = toProxyRequestUrl(proxyUrl, PAIR_CONFIRM_PATH);
23787
- const requestBody = JSON.stringify({ ticket });
23951
+ const requestBody = JSON.stringify({
23952
+ ticket,
23953
+ responderProfile
23954
+ });
23788
23955
  const bodyBytes = new TextEncoder().encode(requestBody);
23789
23956
  const timestampSeconds = nowSecondsImpl();
23790
23957
  const nonce = nonceFactoryImpl();
@@ -23820,6 +23987,7 @@ async function confirmPairing(agentName, options, dependencies = {}) {
23820
23987
  const peerAlias = await persistPairedPeer({
23821
23988
  ticket,
23822
23989
  peerDid: parsed.initiatorAgentDid,
23990
+ peerProfile: parsed.initiatorProfile,
23823
23991
  dependencies
23824
23992
  });
23825
23993
  if (ticketSource.source === "qr-file" && ticketSource.qrFilePath) {
@@ -23901,15 +24069,23 @@ async function getPairingStatusOnce(agentName, options, dependencies = {}) {
23901
24069
  );
23902
24070
  }
23903
24071
  const peerDid = callerAgentDid === parsed.initiatorAgentDid ? responderAgentDid : callerAgentDid === responderAgentDid ? parsed.initiatorAgentDid : void 0;
24072
+ const peerProfile = callerAgentDid === parsed.initiatorAgentDid ? parsed.responderProfile : callerAgentDid === responderAgentDid ? parsed.initiatorProfile : void 0;
23904
24073
  if (!peerDid) {
23905
24074
  throw createCliError7(
23906
24075
  "CLI_PAIR_STATUS_FORBIDDEN",
23907
24076
  "Local agent is not a participant in the pairing ticket"
23908
24077
  );
23909
24078
  }
24079
+ if (!peerProfile) {
24080
+ throw createCliError7(
24081
+ "CLI_PAIR_STATUS_INVALID_RESPONSE",
24082
+ "Pair status response is invalid"
24083
+ );
24084
+ }
23910
24085
  peerAlias = await persistPairedPeer({
23911
24086
  ticket,
23912
24087
  peerDid,
24088
+ peerProfile,
23913
24089
  dependencies
23914
24090
  });
23915
24091
  }
@@ -24005,6 +24181,12 @@ var createPairCommand = (dependencies = {}) => {
24005
24181
  writeStdoutLine("Pairing ticket created");
24006
24182
  writeStdoutLine(`Ticket: ${result.ticket}`);
24007
24183
  writeStdoutLine(`Initiator Agent DID: ${result.initiatorAgentDid}`);
24184
+ writeStdoutLine(
24185
+ `Initiator Agent Name: ${result.initiatorProfile.agentName}`
24186
+ );
24187
+ writeStdoutLine(
24188
+ `Initiator Human Name: ${result.initiatorProfile.humanName}`
24189
+ );
24008
24190
  writeStdoutLine(`Expires At: ${result.expiresAt}`);
24009
24191
  if (result.qrPath) {
24010
24192
  writeStdoutLine(`QR File: ${result.qrPath}`);
@@ -24047,6 +24229,14 @@ var createPairCommand = (dependencies = {}) => {
24047
24229
  `Responder Agent DID: ${status.responderAgentDid}`
24048
24230
  );
24049
24231
  }
24232
+ if (status.responderProfile) {
24233
+ writeStdoutLine(
24234
+ `Responder Agent Name: ${status.responderProfile.agentName}`
24235
+ );
24236
+ writeStdoutLine(
24237
+ `Responder Human Name: ${status.responderProfile.humanName}`
24238
+ );
24239
+ }
24050
24240
  if (status.peerAlias) {
24051
24241
  writeStdoutLine(`Peer alias saved: ${status.peerAlias}`);
24052
24242
  }
@@ -24067,7 +24257,19 @@ var createPairCommand = (dependencies = {}) => {
24067
24257
  });
24068
24258
  writeStdoutLine("Pairing confirmed");
24069
24259
  writeStdoutLine(`Initiator Agent DID: ${result.initiatorAgentDid}`);
24260
+ writeStdoutLine(
24261
+ `Initiator Agent Name: ${result.initiatorProfile.agentName}`
24262
+ );
24263
+ writeStdoutLine(
24264
+ `Initiator Human Name: ${result.initiatorProfile.humanName}`
24265
+ );
24070
24266
  writeStdoutLine(`Responder Agent DID: ${result.responderAgentDid}`);
24267
+ writeStdoutLine(
24268
+ `Responder Agent Name: ${result.responderProfile.agentName}`
24269
+ );
24270
+ writeStdoutLine(
24271
+ `Responder Human Name: ${result.responderProfile.humanName}`
24272
+ );
24071
24273
  writeStdoutLine(`Paired: ${result.paired ? "true" : "false"}`);
24072
24274
  if (result.peerAlias) {
24073
24275
  writeStdoutLine(`Peer alias saved: ${result.peerAlias}`);
@@ -24099,9 +24301,23 @@ var createPairCommand = (dependencies = {}) => {
24099
24301
  });
24100
24302
  writeStdoutLine(`Status: ${result.status}`);
24101
24303
  writeStdoutLine(`Initiator Agent DID: ${result.initiatorAgentDid}`);
24304
+ writeStdoutLine(
24305
+ `Initiator Agent Name: ${result.initiatorProfile.agentName}`
24306
+ );
24307
+ writeStdoutLine(
24308
+ `Initiator Human Name: ${result.initiatorProfile.humanName}`
24309
+ );
24102
24310
  if (result.responderAgentDid) {
24103
24311
  writeStdoutLine(`Responder Agent DID: ${result.responderAgentDid}`);
24104
24312
  }
24313
+ if (result.responderProfile) {
24314
+ writeStdoutLine(
24315
+ `Responder Agent Name: ${result.responderProfile.agentName}`
24316
+ );
24317
+ writeStdoutLine(
24318
+ `Responder Human Name: ${result.responderProfile.humanName}`
24319
+ );
24320
+ }
24105
24321
  writeStdoutLine(`Expires At: ${result.expiresAt}`);
24106
24322
  if (result.confirmedAt) {
24107
24323
  writeStdoutLine(`Confirmed At: ${result.confirmedAt}`);
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clawdentity",
3
- "version": "0.0.17",
3
+ "version": "0.0.18",
4
4
  "type": "module",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -21,17 +21,6 @@
21
21
  "postinstall.mjs",
22
22
  "skill-bundle"
23
23
  ],
24
- "scripts": {
25
- "build": "pnpm -F @clawdentity/openclaw-skill build && pnpm run sync:skill-bundle && pnpm run verify:skill-bundle && tsup",
26
- "format": "biome format .",
27
- "lint": "biome lint .",
28
- "prepack": "pnpm run build",
29
- "postinstall": "node ./postinstall.mjs",
30
- "sync:skill-bundle": "node ./scripts/sync-skill-bundle.mjs",
31
- "verify:skill-bundle": "node ./scripts/verify-skill-bundle.mjs",
32
- "test": "vitest run",
33
- "typecheck": "tsc --noEmit"
34
- },
35
24
  "dependencies": {
36
25
  "commander": "^13.1.0",
37
26
  "jsqr": "^1.4.0",
@@ -40,11 +29,21 @@
40
29
  "ws": "^8.19.0"
41
30
  },
42
31
  "devDependencies": {
43
- "@clawdentity/connector": "workspace:*",
44
- "@clawdentity/protocol": "workspace:*",
45
- "@clawdentity/sdk": "workspace:*",
46
32
  "@types/node": "^22.18.11",
47
33
  "@types/pngjs": "^6.0.5",
48
- "@types/qrcode": "^1.5.6"
34
+ "@types/qrcode": "^1.5.6",
35
+ "@clawdentity/connector": "0.0.0",
36
+ "@clawdentity/protocol": "0.0.0",
37
+ "@clawdentity/sdk": "0.0.0"
38
+ },
39
+ "scripts": {
40
+ "build": "pnpm -F @clawdentity/openclaw-skill build && pnpm run sync:skill-bundle && pnpm run verify:skill-bundle && tsup",
41
+ "format": "biome format .",
42
+ "lint": "biome lint .",
43
+ "postinstall": "node ./postinstall.mjs",
44
+ "sync:skill-bundle": "node ./scripts/sync-skill-bundle.mjs",
45
+ "verify:skill-bundle": "node ./scripts/verify-skill-bundle.mjs",
46
+ "test": "vitest run",
47
+ "typecheck": "tsc --noEmit"
49
48
  }
50
- }
49
+ }
@@ -56,11 +56,11 @@ function parseProxyUrl(value) {
56
56
  throw new Error("proxyUrl must be a valid URL");
57
57
  }
58
58
  }
59
- function parsePeerName(value) {
59
+ function parseProfileName(value, label) {
60
60
  if (value === void 0) {
61
61
  return void 0;
62
62
  }
63
- return parseNonEmptyString(value, "name");
63
+ return parseNonEmptyString(value, label);
64
64
  }
65
65
  function parsePeerEntry(value) {
66
66
  if (!isRecord(value)) {
@@ -68,11 +68,12 @@ function parsePeerEntry(value) {
68
68
  }
69
69
  const did = parseDid(value.did);
70
70
  const proxyUrl = parseProxyUrl(value.proxyUrl);
71
- const name = parsePeerName(value.name);
72
- if (name === void 0) {
71
+ const agentName = parseProfileName(value.agentName, "agentName");
72
+ const humanName = parseProfileName(value.humanName, "humanName");
73
+ if (agentName === void 0 && humanName === void 0) {
73
74
  return { did, proxyUrl };
74
75
  }
75
- return { did, proxyUrl, name };
76
+ return { did, proxyUrl, agentName, humanName };
76
77
  }
77
78
  function parsePeersConfig(value, source) {
78
79
  if (!isRecord(value)) {
@@ -57,6 +57,7 @@ Relay invite codes are not part of this flow.
57
57
  Required for onboarding:
58
58
  - Registry onboarding invite code: `clw_inv_...` (default onboarding path)
59
59
  - Local agent name
60
+ - Human display name (used by invite redeem and pairing profile metadata)
60
61
 
61
62
  Optional only for recovery/advanced operator flows:
62
63
  - Existing API key (only when user explicitly says no invite is available)
@@ -84,8 +85,8 @@ Note: Registry operators must run `admin bootstrap` before creating invites. See
84
85
  - `clawdentity config show`
85
86
 
86
87
  ### Invite management
87
- - `clawdentity invite redeem <registry-invite-code>`
88
- - `clawdentity invite redeem <registry-invite-code> --registry-url <registry-url>`
88
+ - `clawdentity invite redeem <registry-invite-code> --display-name <human-name>`
89
+ - `clawdentity invite redeem <registry-invite-code> --display-name <human-name> --registry-url <registry-url>`
89
90
  - `clawdentity invite create` (admin only, see registry reference)
90
91
  - `clawdentity invite create --expires-at <iso-8601>` (admin only)
91
92
 
@@ -152,6 +153,7 @@ Note: Registry operators must run `admin bootstrap` before creating invites. See
152
153
  - If `--invite-code` appears, treat CLI as outdated and upgrade before continuing:
153
154
  - `npm install -g clawdentity@latest`
154
155
  - Confirm local agent name.
156
+ - Confirm local human display name for onboarding.
155
157
  - Check local API key status with `clawdentity config get apiKey`.
156
158
  - If API key is missing, ask for onboarding invite `clw_inv_...` and continue with invite redeem.
157
159
  - Do not ask for raw API key unless the user explicitly says invite is unavailable.
@@ -167,13 +169,14 @@ Note: Registry operators must run `admin bootstrap` before creating invites. See
167
169
  - If needed, run with `--registry-url`.
168
170
 
169
171
  4. Finish onboarding and generate API key.
170
- - Preferred path: run `clawdentity invite redeem <clw_inv_...>`.
172
+ - Preferred path: run `clawdentity invite redeem <clw_inv_...> --display-name <human-name>`.
171
173
  - If local API key already exists and user explicitly wants to reuse it, continue without redeem.
172
174
  - Use `config set apiKey` only as a manual recovery path when user cannot provide invite.
173
175
  - Confirm output shows:
174
176
  - `Invite redeemed`
175
177
  - API key token printed once
176
178
  - `API key saved to local config`
179
+ - `Human name: <human-name>`
177
180
  - Stop and fix if this step fails. Do not proceed to pairing.
178
181
 
179
182
  5. Create local OpenClaw agent identity.
@@ -226,6 +229,14 @@ Note: Registry operators must run `admin bootstrap` before creating invites. See
226
229
  - Inline ticket path: `clawdentity pair confirm <agent-name> --ticket <clwpair1_...>`
227
230
  - Cannot provide both `--qr-file` and `--ticket` simultaneously.
228
231
  - Pair confirm auto-saves peer DID/proxy mapping locally from QR ticket metadata.
232
+ - Pair start/confirm/status exchange profile metadata:
233
+ - `initiatorProfile = { agentName, humanName }`
234
+ - `responderProfile = { agentName, humanName }`
235
+ - Local peer entries in `~/.clawdentity/peers.json` should include:
236
+ - `did`
237
+ - `proxyUrl`
238
+ - `agentName`
239
+ - `humanName`
229
240
  - If initiator started without `--wait`, initiator must run:
230
241
  - `clawdentity pair status <agent-name> --ticket <clwpair1_...> --wait`
231
242
  - This persists the peer on initiator after responder confirmation.
@@ -236,6 +247,8 @@ Note: Registry operators must run `admin bootstrap` before creating invites. See
236
247
  - Verify output shows token status, expiry, and no revocation.
237
248
  - Run `clawdentity openclaw doctor --peer <alias>` to confirm the new peer is visible.
238
249
  - Run `clawdentity openclaw relay test` to confirm end-to-end message delivery.
250
+ - Relay delivery is asynchronous: proxy accepts deliveries with `202`, and `state=queued` is expected when the recipient connector is temporarily offline.
251
+ - `state=queued` is not a pairing failure. The proxy retries delivery automatically while the message is within queue TTL/retry limits.
239
252
  - Note: `relay test` runs preflight doctor checks before sending the probe.
240
253
 
241
254
  ## Lifecycle Management
@@ -51,7 +51,8 @@ Rules:
51
51
  "beta": {
52
52
  "did": "did:claw:agent:01H...",
53
53
  "proxyUrl": "https://beta-proxy.example.com/hooks/agent",
54
- "name": "Beta Agent"
54
+ "agentName": "beta",
55
+ "humanName": "Ira"
55
56
  }
56
57
  }
57
58
  }
@@ -61,7 +62,8 @@ Rules:
61
62
  - peer alias key uses `[a-zA-Z0-9._-]`
62
63
  - `did` required and must begin with `did:`
63
64
  - `proxyUrl` required and must be a valid absolute URL
64
- - `name` optional
65
+ - `agentName` optional
66
+ - `humanName` optional
65
67
 
66
68
  ## Proxy Pairing Prerequisite
67
69
 
@@ -75,11 +77,15 @@ Current pairing contract is ticket-based with CLI support:
75
77
  - headers:
76
78
  - `Authorization: Claw <AIT>`
77
79
  - ownership validation is handled internally by proxy-to-registry service auth
78
- - body (optional):
80
+ - body:
79
81
 
80
82
  ```json
81
83
  {
82
- "ttlSeconds": 300
84
+ "ttlSeconds": 300,
85
+ "initiatorProfile": {
86
+ "agentName": "alpha",
87
+ "humanName": "Ravi"
88
+ }
83
89
  }
84
90
  ```
85
91
 
@@ -92,7 +98,11 @@ Current pairing contract is ticket-based with CLI support:
92
98
 
93
99
  ```json
94
100
  {
95
- "ticket": "clwpair1_..."
101
+ "ticket": "clwpair1_...",
102
+ "responderProfile": {
103
+ "agentName": "beta",
104
+ "humanName": "Ira"
105
+ }
96
106
  }
97
107
  ```
98
108
 
@@ -202,7 +212,7 @@ Known defaults:
202
212
  | `https://registry.clawdentity.com` | `https://proxy.clawdentity.com` |
203
213
  | `https://dev.registry.clawdentity.com` | `https://dev.proxy.clawdentity.com` |
204
214
 
205
- Recovery: rerun onboarding (`clawdentity invite redeem <clw_inv_...>`) so local config aligns to registry metadata.
215
+ Recovery: rerun onboarding (`clawdentity invite redeem <clw_inv_...> --display-name <human-name>`) so local config aligns to registry metadata.
206
216
 
207
217
  ## Pairing Error Codes
208
218
 
@@ -213,6 +223,7 @@ Recovery: rerun onboarding (`clawdentity invite redeem <clw_inv_...>`) so local
213
223
  | 403 | `PROXY_PAIR_OWNERSHIP_FORBIDDEN` | Initiator ownership check failed |
214
224
  | 503 | `PROXY_PAIR_OWNERSHIP_UNAVAILABLE` | Registry ownership lookup unavailable |
215
225
  | — | `CLI_PAIR_AGENT_NOT_FOUND` | Agent ait.jwt or secret.key missing/empty |
226
+ | — | `CLI_PAIR_HUMAN_NAME_MISSING` | Local config is missing `humanName`; set via invite redeem or config |
216
227
  | — | `CLI_PAIR_PROXY_URL_REQUIRED` | Proxy URL could not be resolved |
217
228
  | — | `CLI_PAIR_START_INVALID_TTL` | ttlSeconds must be a positive integer |
218
229
  | — | `CLI_PAIR_INVALID_PROXY_URL` | Proxy URL is invalid |