clawdentity 0.0.8 → 0.0.10
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
|
@@ -15709,6 +15709,7 @@ var registrySigningKeysEnvSchema = external_exports.string().min(1).transform((v
|
|
|
15709
15709
|
var registryConfigSchema = external_exports.object({
|
|
15710
15710
|
ENVIRONMENT: environmentSchema,
|
|
15711
15711
|
APP_VERSION: external_exports.string().min(1).optional(),
|
|
15712
|
+
PROXY_URL: external_exports.string().url().optional(),
|
|
15712
15713
|
BOOTSTRAP_SECRET: external_exports.string().min(1).optional(),
|
|
15713
15714
|
REGISTRY_SIGNING_KEY: external_exports.string().min(1).optional(),
|
|
15714
15715
|
REGISTRY_SIGNING_KEYS: registrySigningKeysEnvSchema.optional()
|
|
@@ -17071,13 +17072,14 @@ import { Command } from "commander";
|
|
|
17071
17072
|
import { chmod, mkdir, readFile, writeFile } from "fs/promises";
|
|
17072
17073
|
import { homedir } from "os";
|
|
17073
17074
|
import { dirname, join as join2 } from "path";
|
|
17074
|
-
var DEFAULT_REGISTRY_URL = "https://
|
|
17075
|
+
var DEFAULT_REGISTRY_URL = "https://registry.clawdentity.com";
|
|
17075
17076
|
var CONFIG_DIR = ".clawdentity";
|
|
17076
17077
|
var CONFIG_FILE = "config.json";
|
|
17077
17078
|
var CACHE_DIR = "cache";
|
|
17078
17079
|
var FILE_MODE = 384;
|
|
17079
17080
|
var ENV_KEY_MAP = {
|
|
17080
17081
|
registryUrl: "CLAWDENTITY_REGISTRY_URL",
|
|
17082
|
+
proxyUrl: "CLAWDENTITY_PROXY_URL",
|
|
17081
17083
|
apiKey: "CLAWDENTITY_API_KEY"
|
|
17082
17084
|
};
|
|
17083
17085
|
var LEGACY_ENV_KEY_MAP = {
|
|
@@ -17099,6 +17101,9 @@ var normalizeConfig = (raw) => {
|
|
|
17099
17101
|
if (typeof raw.registryUrl === "string" && raw.registryUrl.length > 0) {
|
|
17100
17102
|
config2.registryUrl = raw.registryUrl;
|
|
17101
17103
|
}
|
|
17104
|
+
if (typeof raw.proxyUrl === "string" && raw.proxyUrl.length > 0) {
|
|
17105
|
+
config2.proxyUrl = raw.proxyUrl;
|
|
17106
|
+
}
|
|
17102
17107
|
if (typeof raw.apiKey === "string" && raw.apiKey.length > 0) {
|
|
17103
17108
|
config2.apiKey = raw.apiKey;
|
|
17104
17109
|
}
|
|
@@ -18393,6 +18398,7 @@ import { Command as Command4 } from "commander";
|
|
|
18393
18398
|
var logger5 = createLogger({ service: "cli", module: "config" });
|
|
18394
18399
|
var VALID_KEYS = [
|
|
18395
18400
|
"registryUrl",
|
|
18401
|
+
"proxyUrl",
|
|
18396
18402
|
"apiKey"
|
|
18397
18403
|
];
|
|
18398
18404
|
var isValidConfigKey = (value) => {
|
|
@@ -20343,6 +20349,64 @@ function createConnectorCommand(dependencies = {}) {
|
|
|
20343
20349
|
|
|
20344
20350
|
// src/commands/invite.ts
|
|
20345
20351
|
import { Command as Command6 } from "commander";
|
|
20352
|
+
|
|
20353
|
+
// src/config/endpoints.ts
|
|
20354
|
+
var PRODUCTION_REGISTRY_HOST = "registry.clawdentity.com";
|
|
20355
|
+
var DEVELOPMENT_REGISTRY_HOST = "dev.registry.clawdentity.com";
|
|
20356
|
+
var PRODUCTION_PROXY_HOST = "proxy.clawdentity.com";
|
|
20357
|
+
var DEVELOPMENT_PROXY_HOST = "dev.proxy.clawdentity.com";
|
|
20358
|
+
var LOCAL_REGISTRY_PORT = "8788";
|
|
20359
|
+
var LOCAL_PROXY_PORT = "8787";
|
|
20360
|
+
var LOCAL_HOSTNAMES = /* @__PURE__ */ new Set([
|
|
20361
|
+
"localhost",
|
|
20362
|
+
"127.0.0.1",
|
|
20363
|
+
"host.docker.internal",
|
|
20364
|
+
"gateway.docker.internal"
|
|
20365
|
+
]);
|
|
20366
|
+
var normalizeUrl = (candidate) => {
|
|
20367
|
+
try {
|
|
20368
|
+
const parsed = new URL(candidate);
|
|
20369
|
+
if (parsed.protocol !== "https:" && parsed.protocol !== "http:") {
|
|
20370
|
+
return void 0;
|
|
20371
|
+
}
|
|
20372
|
+
return parsed;
|
|
20373
|
+
} catch {
|
|
20374
|
+
return void 0;
|
|
20375
|
+
}
|
|
20376
|
+
};
|
|
20377
|
+
var toProxyHostname = (registryHostname) => {
|
|
20378
|
+
if (registryHostname === PRODUCTION_REGISTRY_HOST) {
|
|
20379
|
+
return PRODUCTION_PROXY_HOST;
|
|
20380
|
+
}
|
|
20381
|
+
if (registryHostname === DEVELOPMENT_REGISTRY_HOST) {
|
|
20382
|
+
return DEVELOPMENT_PROXY_HOST;
|
|
20383
|
+
}
|
|
20384
|
+
if (registryHostname.startsWith("dev.registry.")) {
|
|
20385
|
+
return `dev.proxy.${registryHostname.slice("dev.registry.".length)}`;
|
|
20386
|
+
}
|
|
20387
|
+
if (registryHostname.startsWith("registry.")) {
|
|
20388
|
+
return `proxy.${registryHostname.slice("registry.".length)}`;
|
|
20389
|
+
}
|
|
20390
|
+
return void 0;
|
|
20391
|
+
};
|
|
20392
|
+
var deriveProxyUrlFromRegistryUrl = (registryUrl) => {
|
|
20393
|
+
const parsedRegistryUrl = normalizeUrl(registryUrl);
|
|
20394
|
+
if (!parsedRegistryUrl) {
|
|
20395
|
+
return void 0;
|
|
20396
|
+
}
|
|
20397
|
+
const hostname3 = parsedRegistryUrl.hostname.toLowerCase();
|
|
20398
|
+
if (LOCAL_HOSTNAMES.has(hostname3) && parsedRegistryUrl.port === LOCAL_REGISTRY_PORT) {
|
|
20399
|
+
return `${parsedRegistryUrl.protocol}//${hostname3}:${LOCAL_PROXY_PORT}/`;
|
|
20400
|
+
}
|
|
20401
|
+
const mappedHostname = toProxyHostname(hostname3);
|
|
20402
|
+
if (!mappedHostname) {
|
|
20403
|
+
return void 0;
|
|
20404
|
+
}
|
|
20405
|
+
const port = parsedRegistryUrl.port.length > 0 ? `:${parsedRegistryUrl.port}` : "";
|
|
20406
|
+
return `${parsedRegistryUrl.protocol}//${mappedHostname}${port}/`;
|
|
20407
|
+
};
|
|
20408
|
+
|
|
20409
|
+
// src/commands/invite.ts
|
|
20346
20410
|
var logger7 = createLogger({ service: "cli", module: "invite" });
|
|
20347
20411
|
var isRecord6 = (value) => {
|
|
20348
20412
|
return typeof value === "object" && value !== null;
|
|
@@ -20519,10 +20583,23 @@ function parseInviteRedeemResponse(payload) {
|
|
|
20519
20583
|
}
|
|
20520
20584
|
const apiKeyId = parseNonEmptyString6(apiKeySource.id);
|
|
20521
20585
|
const apiKeyName = parseNonEmptyString6(apiKeySource.name);
|
|
20586
|
+
const proxyUrlCandidate = parseNonEmptyString6(payload.proxyUrl);
|
|
20587
|
+
let proxyUrl;
|
|
20588
|
+
if (proxyUrlCandidate.length > 0) {
|
|
20589
|
+
try {
|
|
20590
|
+
const parsed = new URL(proxyUrlCandidate);
|
|
20591
|
+
if (parsed.protocol === "https:" || parsed.protocol === "http:") {
|
|
20592
|
+
proxyUrl = parsed.toString();
|
|
20593
|
+
}
|
|
20594
|
+
} catch {
|
|
20595
|
+
proxyUrl = void 0;
|
|
20596
|
+
}
|
|
20597
|
+
}
|
|
20522
20598
|
return {
|
|
20523
20599
|
apiKeyToken,
|
|
20524
20600
|
apiKeyId: apiKeyId.length > 0 ? apiKeyId : void 0,
|
|
20525
|
-
apiKeyName: apiKeyName.length > 0 ? apiKeyName : void 0
|
|
20601
|
+
apiKeyName: apiKeyName.length > 0 ? apiKeyName : void 0,
|
|
20602
|
+
proxyUrl
|
|
20526
20603
|
};
|
|
20527
20604
|
}
|
|
20528
20605
|
async function resolveInviteRuntime(overrideRegistryUrl, dependencies) {
|
|
@@ -20600,11 +20677,19 @@ async function redeemInvite(code, options, dependencies = {}) {
|
|
|
20600
20677
|
registryUrl: runtime.registryUrl
|
|
20601
20678
|
};
|
|
20602
20679
|
}
|
|
20603
|
-
async function persistRedeemConfig(
|
|
20680
|
+
async function persistRedeemConfig(input, dependencies = {}) {
|
|
20604
20681
|
const setConfigValueImpl = dependencies.setConfigValueImpl ?? setConfigValue;
|
|
20605
20682
|
try {
|
|
20606
|
-
await setConfigValueImpl("registryUrl", registryUrl);
|
|
20607
|
-
await setConfigValueImpl("apiKey", apiKeyToken);
|
|
20683
|
+
await setConfigValueImpl("registryUrl", input.registryUrl);
|
|
20684
|
+
await setConfigValueImpl("apiKey", input.apiKeyToken);
|
|
20685
|
+
const resolvedProxyUrl = parseNonEmptyString6(input.proxyUrl) || deriveProxyUrlFromRegistryUrl(input.registryUrl);
|
|
20686
|
+
if (!resolvedProxyUrl) {
|
|
20687
|
+
throw createCliError4(
|
|
20688
|
+
"CLI_INVITE_REDEEM_PROXY_URL_MISSING",
|
|
20689
|
+
"Proxy URL is missing from onboarding response and could not be derived from registry URL."
|
|
20690
|
+
);
|
|
20691
|
+
}
|
|
20692
|
+
await setConfigValueImpl("proxyUrl", resolvedProxyUrl);
|
|
20608
20693
|
} catch (error48) {
|
|
20609
20694
|
logger7.warn("cli.invite_redeem_config_persist_failed", {
|
|
20610
20695
|
errorName: error48 instanceof Error ? error48.name : "unknown"
|
|
@@ -20655,8 +20740,11 @@ var createInviteCommand = (dependencies = {}) => {
|
|
|
20655
20740
|
writeStdoutLine("API key token (shown once):");
|
|
20656
20741
|
writeStdoutLine(result.apiKeyToken);
|
|
20657
20742
|
await persistRedeemConfig(
|
|
20658
|
-
|
|
20659
|
-
|
|
20743
|
+
{
|
|
20744
|
+
registryUrl: result.registryUrl,
|
|
20745
|
+
apiKeyToken: result.apiKeyToken,
|
|
20746
|
+
proxyUrl: result.proxyUrl
|
|
20747
|
+
},
|
|
20660
20748
|
dependencies
|
|
20661
20749
|
);
|
|
20662
20750
|
writeStdoutLine("API key saved to local config");
|
|
@@ -20701,13 +20789,13 @@ var CONNECTOR_HOST_LOOPBACK = "127.0.0.1";
|
|
|
20701
20789
|
var CONNECTOR_HOST_DOCKER = "host.docker.internal";
|
|
20702
20790
|
var CONNECTOR_HOST_DOCKER_GATEWAY = "gateway.docker.internal";
|
|
20703
20791
|
var CONNECTOR_HOST_LINUX_BRIDGE = "172.17.0.1";
|
|
20704
|
-
var INVITE_CODE_PREFIX = "clawd1_";
|
|
20705
20792
|
var PEER_ALIAS_PATTERN = /^[a-zA-Z0-9._-]+$/;
|
|
20706
20793
|
var FILE_MODE3 = 384;
|
|
20707
20794
|
var OPENCLAW_HOOK_TOKEN_BYTES = 32;
|
|
20708
|
-
var OPENCLAW_SETUP_COMMAND_HINT = "Run: clawdentity openclaw setup <agentName>
|
|
20795
|
+
var OPENCLAW_SETUP_COMMAND_HINT = "Run: clawdentity openclaw setup <agentName>";
|
|
20709
20796
|
var OPENCLAW_SETUP_RESTART_COMMAND_HINT = `${OPENCLAW_SETUP_COMMAND_HINT} and restart OpenClaw`;
|
|
20710
20797
|
var OPENCLAW_SETUP_WITH_BASE_URL_HINT = `${OPENCLAW_SETUP_COMMAND_HINT} --openclaw-base-url <url>`;
|
|
20798
|
+
var OPENCLAW_PAIRING_COMMAND_HINT = "Run QR pairing first: clawdentity pair start <agentName> --qr and clawdentity pair confirm <agentName> --qr-file <path>";
|
|
20711
20799
|
var textEncoder2 = new TextEncoder();
|
|
20712
20800
|
var textDecoder = new TextDecoder();
|
|
20713
20801
|
function isRecord7(value) {
|
|
@@ -20816,50 +20904,6 @@ function parseAgentDid2(value, label) {
|
|
|
20816
20904
|
}
|
|
20817
20905
|
return did;
|
|
20818
20906
|
}
|
|
20819
|
-
function parseInvitePayload(value) {
|
|
20820
|
-
if (!isRecord7(value)) {
|
|
20821
|
-
throw createCliError5(
|
|
20822
|
-
"CLI_OPENCLAW_INVALID_INVITE",
|
|
20823
|
-
"invite payload must be an object"
|
|
20824
|
-
);
|
|
20825
|
-
}
|
|
20826
|
-
if (value.v !== 1) {
|
|
20827
|
-
throw createCliError5(
|
|
20828
|
-
"CLI_OPENCLAW_INVALID_INVITE",
|
|
20829
|
-
"invite payload version is unsupported"
|
|
20830
|
-
);
|
|
20831
|
-
}
|
|
20832
|
-
const issuedAt = parseNonEmptyString7(value.issuedAt, "invite issuedAt");
|
|
20833
|
-
const did = parseAgentDid2(value.did, "invite did");
|
|
20834
|
-
const proxyUrl = parseProxyUrl(value.proxyUrl);
|
|
20835
|
-
const alias = value.alias === void 0 ? void 0 : parsePeerAlias(value.alias);
|
|
20836
|
-
const name = parseOptionalName(value.name);
|
|
20837
|
-
if (alias === void 0 && name === void 0) {
|
|
20838
|
-
return {
|
|
20839
|
-
v: 1,
|
|
20840
|
-
issuedAt,
|
|
20841
|
-
did,
|
|
20842
|
-
proxyUrl
|
|
20843
|
-
};
|
|
20844
|
-
}
|
|
20845
|
-
if (name === void 0) {
|
|
20846
|
-
return {
|
|
20847
|
-
v: 1,
|
|
20848
|
-
issuedAt,
|
|
20849
|
-
did,
|
|
20850
|
-
proxyUrl,
|
|
20851
|
-
alias
|
|
20852
|
-
};
|
|
20853
|
-
}
|
|
20854
|
-
return {
|
|
20855
|
-
v: 1,
|
|
20856
|
-
issuedAt,
|
|
20857
|
-
did,
|
|
20858
|
-
proxyUrl,
|
|
20859
|
-
alias,
|
|
20860
|
-
name
|
|
20861
|
-
};
|
|
20862
|
-
}
|
|
20863
20907
|
function resolveHomeDir(homeDir) {
|
|
20864
20908
|
if (typeof homeDir === "string" && homeDir.trim().length > 0) {
|
|
20865
20909
|
return homeDir.trim();
|
|
@@ -21010,41 +21054,6 @@ async function ensureLocalAgentCredentials(homeDir, agentName) {
|
|
|
21010
21054
|
}
|
|
21011
21055
|
}
|
|
21012
21056
|
}
|
|
21013
|
-
function decodeInvitePayload(code) {
|
|
21014
|
-
const rawCode = parseNonEmptyString7(code, "invite code");
|
|
21015
|
-
if (!rawCode.startsWith(INVITE_CODE_PREFIX)) {
|
|
21016
|
-
throw createCliError5(
|
|
21017
|
-
"CLI_OPENCLAW_INVALID_INVITE",
|
|
21018
|
-
"Invite code has invalid prefix"
|
|
21019
|
-
);
|
|
21020
|
-
}
|
|
21021
|
-
const encoded = rawCode.slice(INVITE_CODE_PREFIX.length);
|
|
21022
|
-
if (encoded.length === 0) {
|
|
21023
|
-
throw createCliError5(
|
|
21024
|
-
"CLI_OPENCLAW_INVALID_INVITE",
|
|
21025
|
-
"invite code payload is empty"
|
|
21026
|
-
);
|
|
21027
|
-
}
|
|
21028
|
-
let decodedJson;
|
|
21029
|
-
try {
|
|
21030
|
-
decodedJson = textDecoder.decode(decodeBase64url(encoded));
|
|
21031
|
-
} catch {
|
|
21032
|
-
throw createCliError5(
|
|
21033
|
-
"CLI_OPENCLAW_INVALID_INVITE",
|
|
21034
|
-
"invite code payload is not valid base64url"
|
|
21035
|
-
);
|
|
21036
|
-
}
|
|
21037
|
-
let parsedPayload;
|
|
21038
|
-
try {
|
|
21039
|
-
parsedPayload = JSON.parse(decodedJson);
|
|
21040
|
-
} catch {
|
|
21041
|
-
throw createCliError5(
|
|
21042
|
-
"CLI_OPENCLAW_INVALID_INVITE",
|
|
21043
|
-
"invite code payload is not valid JSON"
|
|
21044
|
-
);
|
|
21045
|
-
}
|
|
21046
|
-
return parseInvitePayload(parsedPayload);
|
|
21047
|
-
}
|
|
21048
21057
|
async function writeSecureFile3(filePath, content) {
|
|
21049
21058
|
await mkdir5(dirname4(filePath), { recursive: true });
|
|
21050
21059
|
await writeFile5(filePath, content, "utf8");
|
|
@@ -21565,7 +21574,7 @@ async function runOpenclawDoctor(options = {}) {
|
|
|
21565
21574
|
label: "Peers map",
|
|
21566
21575
|
status: "fail",
|
|
21567
21576
|
message: `peer alias is missing: ${peerAlias}`,
|
|
21568
|
-
remediationHint:
|
|
21577
|
+
remediationHint: OPENCLAW_PAIRING_COMMAND_HINT,
|
|
21569
21578
|
details: { peersPath, peerAlias }
|
|
21570
21579
|
})
|
|
21571
21580
|
);
|
|
@@ -21585,9 +21594,8 @@ async function runOpenclawDoctor(options = {}) {
|
|
|
21585
21594
|
toDoctorCheck({
|
|
21586
21595
|
id: "state.peers",
|
|
21587
21596
|
label: "Peers map",
|
|
21588
|
-
status: "
|
|
21589
|
-
message: "no peers are configured",
|
|
21590
|
-
remediationHint: OPENCLAW_SETUP_COMMAND_HINT,
|
|
21597
|
+
status: "pass",
|
|
21598
|
+
message: "no peers are configured yet (optional until pairing)",
|
|
21591
21599
|
details: { peersPath }
|
|
21592
21600
|
})
|
|
21593
21601
|
);
|
|
@@ -21808,7 +21816,7 @@ function parseRelayProbeFailure(input) {
|
|
|
21808
21816
|
if (input.status === 500) {
|
|
21809
21817
|
return {
|
|
21810
21818
|
message: "Relay probe failed inside local relay pipeline",
|
|
21811
|
-
remediationHint: "Check connector runtime and peer
|
|
21819
|
+
remediationHint: "Check connector runtime and peer pairing; rerun clawdentity openclaw doctor"
|
|
21812
21820
|
};
|
|
21813
21821
|
}
|
|
21814
21822
|
return {
|
|
@@ -21816,17 +21824,57 @@ function parseRelayProbeFailure(input) {
|
|
|
21816
21824
|
remediationHint: input.responseBody.trim().length > 0 ? `Inspect response body: ${input.responseBody.trim()}` : "Check local OpenClaw and connector logs"
|
|
21817
21825
|
};
|
|
21818
21826
|
}
|
|
21827
|
+
async function resolveRelayProbePeerAlias(input) {
|
|
21828
|
+
if (typeof input.peerAliasOption === "string" && input.peerAliasOption.trim().length > 0) {
|
|
21829
|
+
return parsePeerAlias(input.peerAliasOption);
|
|
21830
|
+
}
|
|
21831
|
+
const peersPath = resolvePeersPath(input.homeDir);
|
|
21832
|
+
const peersConfig = await loadPeersConfig(peersPath);
|
|
21833
|
+
const peerAliases = Object.keys(peersConfig.peers);
|
|
21834
|
+
if (peerAliases.length === 1) {
|
|
21835
|
+
return peerAliases[0];
|
|
21836
|
+
}
|
|
21837
|
+
if (peerAliases.length === 0) {
|
|
21838
|
+
throw createCliError5(
|
|
21839
|
+
"CLI_OPENCLAW_RELAY_TEST_PEER_REQUIRED",
|
|
21840
|
+
"No paired peer is configured yet. Complete QR pairing first.",
|
|
21841
|
+
{ peersPath }
|
|
21842
|
+
);
|
|
21843
|
+
}
|
|
21844
|
+
throw createCliError5(
|
|
21845
|
+
"CLI_OPENCLAW_RELAY_TEST_PEER_REQUIRED",
|
|
21846
|
+
"Multiple peers are configured. Pass --peer <alias> to choose one.",
|
|
21847
|
+
{ peersPath, peerAliases }
|
|
21848
|
+
);
|
|
21849
|
+
}
|
|
21819
21850
|
async function runOpenclawRelayTest(options) {
|
|
21820
21851
|
const homeDir = resolveHomeDir(options.homeDir);
|
|
21821
21852
|
const openclawDir = resolveOpenclawDir(options.openclawDir, homeDir);
|
|
21822
|
-
const
|
|
21853
|
+
const checkedAt = nowIso();
|
|
21854
|
+
let peerAlias;
|
|
21855
|
+
try {
|
|
21856
|
+
peerAlias = await resolveRelayProbePeerAlias({
|
|
21857
|
+
homeDir,
|
|
21858
|
+
peerAliasOption: options.peer
|
|
21859
|
+
});
|
|
21860
|
+
} catch (error48) {
|
|
21861
|
+
const appError = error48 instanceof AppError ? error48 : void 0;
|
|
21862
|
+
return {
|
|
21863
|
+
status: "failure",
|
|
21864
|
+
checkedAt,
|
|
21865
|
+
peerAlias: "unresolved",
|
|
21866
|
+
endpoint: toSendToPeerEndpoint(DEFAULT_OPENCLAW_BASE_URL2),
|
|
21867
|
+
message: appError?.message ?? "Unable to resolve relay peer alias",
|
|
21868
|
+
remediationHint: OPENCLAW_PAIRING_COMMAND_HINT,
|
|
21869
|
+
details: appError?.details
|
|
21870
|
+
};
|
|
21871
|
+
}
|
|
21823
21872
|
const preflight = await runOpenclawDoctor({
|
|
21824
21873
|
homeDir,
|
|
21825
21874
|
openclawDir,
|
|
21826
21875
|
peerAlias,
|
|
21827
21876
|
resolveConfigImpl: options.resolveConfigImpl
|
|
21828
21877
|
});
|
|
21829
|
-
const checkedAt = nowIso();
|
|
21830
21878
|
const relayRuntimeConfigPath = resolveRelayRuntimeConfigPath(homeDir);
|
|
21831
21879
|
let openclawBaseUrl = DEFAULT_OPENCLAW_BASE_URL2;
|
|
21832
21880
|
try {
|
|
@@ -21929,37 +21977,6 @@ async function runOpenclawRelayTest(options) {
|
|
|
21929
21977
|
preflight
|
|
21930
21978
|
};
|
|
21931
21979
|
}
|
|
21932
|
-
function resolveOpenclawSetupPeerInput(options) {
|
|
21933
|
-
const inviteCode = options.inviteCode?.trim();
|
|
21934
|
-
const invite = inviteCode !== void 0 && inviteCode.length > 0 ? decodeInvitePayload(inviteCode) : void 0;
|
|
21935
|
-
const peerAliasCandidate = options.peerAlias ?? invite?.alias;
|
|
21936
|
-
const peerDidCandidate = options.peerDid ?? invite?.did;
|
|
21937
|
-
const peerProxyUrlCandidate = options.peerProxyUrl ?? invite?.proxyUrl;
|
|
21938
|
-
const peerNameCandidate = options.peerName ?? invite?.name;
|
|
21939
|
-
const missingFields = [];
|
|
21940
|
-
if (peerAliasCandidate === void 0 || peerAliasCandidate.trim().length === 0) {
|
|
21941
|
-
missingFields.push("peerAlias");
|
|
21942
|
-
}
|
|
21943
|
-
if (peerDidCandidate === void 0 || peerDidCandidate.trim().length === 0) {
|
|
21944
|
-
missingFields.push("peerDid");
|
|
21945
|
-
}
|
|
21946
|
-
if (peerProxyUrlCandidate === void 0 || peerProxyUrlCandidate.trim().length === 0) {
|
|
21947
|
-
missingFields.push("peerProxyUrl");
|
|
21948
|
-
}
|
|
21949
|
-
if (missingFields.length > 0) {
|
|
21950
|
-
throw createCliError5(
|
|
21951
|
-
"CLI_OPENCLAW_PEER_INPUT_REQUIRED",
|
|
21952
|
-
"Peer routing details are required. Provide --peer-alias, --peer-did, and --peer-proxy-url.",
|
|
21953
|
-
{ missingFields }
|
|
21954
|
-
);
|
|
21955
|
-
}
|
|
21956
|
-
return {
|
|
21957
|
-
peerAlias: parsePeerAlias(peerAliasCandidate),
|
|
21958
|
-
peerDid: parseAgentDid2(peerDidCandidate, "peer DID"),
|
|
21959
|
-
peerProxyUrl: parseProxyUrl(peerProxyUrlCandidate),
|
|
21960
|
-
peerName: parseOptionalName(peerNameCandidate)
|
|
21961
|
-
};
|
|
21962
|
-
}
|
|
21963
21980
|
async function setupOpenclawRelay(agentName, options) {
|
|
21964
21981
|
const normalizedAgentName = assertValidAgentName(agentName);
|
|
21965
21982
|
const homeDir = resolveHomeDir(options.homeDir);
|
|
@@ -21975,7 +21992,6 @@ async function setupOpenclawRelay(agentName, options) {
|
|
|
21975
21992
|
optionValue: options.openclawBaseUrl,
|
|
21976
21993
|
relayRuntimeConfigPath
|
|
21977
21994
|
});
|
|
21978
|
-
const peerInput = resolveOpenclawSetupPeerInput(options);
|
|
21979
21995
|
await ensureLocalAgentCredentials(homeDir, normalizedAgentName);
|
|
21980
21996
|
await mkdir5(dirname4(transformTargetPath), { recursive: true });
|
|
21981
21997
|
try {
|
|
@@ -21996,11 +22012,6 @@ async function setupOpenclawRelay(agentName, options) {
|
|
|
21996
22012
|
);
|
|
21997
22013
|
const peersPath = resolvePeersPath(homeDir);
|
|
21998
22014
|
const peers = await loadPeersConfig(peersPath);
|
|
21999
|
-
peers.peers[peerInput.peerAlias] = peerInput.peerName === void 0 ? { did: peerInput.peerDid, proxyUrl: peerInput.peerProxyUrl } : {
|
|
22000
|
-
did: peerInput.peerDid,
|
|
22001
|
-
proxyUrl: peerInput.peerProxyUrl,
|
|
22002
|
-
name: peerInput.peerName
|
|
22003
|
-
};
|
|
22004
22015
|
await savePeersConfig(peersPath, peers);
|
|
22005
22016
|
const relayTransformPeersPath = resolveTransformPeersPath(openclawDir);
|
|
22006
22017
|
await writeSecureFile3(
|
|
@@ -22055,9 +22066,6 @@ async function setupOpenclawRelay(agentName, options) {
|
|
|
22055
22066
|
);
|
|
22056
22067
|
logger8.info("cli.openclaw_setup_completed", {
|
|
22057
22068
|
agentName: normalizedAgentName,
|
|
22058
|
-
peerAlias: peerInput.peerAlias,
|
|
22059
|
-
peerDid: peerInput.peerDid,
|
|
22060
|
-
peerProxyUrl: peerInput.peerProxyUrl,
|
|
22061
22069
|
openclawConfigPath,
|
|
22062
22070
|
transformTargetPath,
|
|
22063
22071
|
relayTransformRuntimePath,
|
|
@@ -22067,9 +22075,6 @@ async function setupOpenclawRelay(agentName, options) {
|
|
|
22067
22075
|
relayRuntimeConfigPath
|
|
22068
22076
|
});
|
|
22069
22077
|
return {
|
|
22070
|
-
peerAlias: peerInput.peerAlias,
|
|
22071
|
-
peerDid: peerInput.peerDid,
|
|
22072
|
-
peerProxyUrl: peerInput.peerProxyUrl,
|
|
22073
22078
|
openclawConfigPath,
|
|
22074
22079
|
transformTargetPath,
|
|
22075
22080
|
relayTransformRuntimePath,
|
|
@@ -22083,10 +22088,7 @@ var createOpenclawCommand = () => {
|
|
|
22083
22088
|
const openclawCommand = new Command7("openclaw").description(
|
|
22084
22089
|
"Manage OpenClaw relay setup"
|
|
22085
22090
|
);
|
|
22086
|
-
openclawCommand.command("setup <agentName>").description("Apply OpenClaw relay setup
|
|
22087
|
-
"--peer-proxy-url <url>",
|
|
22088
|
-
"Peer proxy URL ending in /hooks/agent"
|
|
22089
|
-
).option("--peer-name <displayName>", "Human-friendly peer display name").option(
|
|
22091
|
+
openclawCommand.command("setup <agentName>").description("Apply OpenClaw relay setup").option(
|
|
22090
22092
|
"--openclaw-dir <path>",
|
|
22091
22093
|
"OpenClaw state directory (default ~/.openclaw)"
|
|
22092
22094
|
).option(
|
|
@@ -22100,9 +22102,7 @@ var createOpenclawCommand = () => {
|
|
|
22100
22102
|
"openclaw setup",
|
|
22101
22103
|
async (agentName, options) => {
|
|
22102
22104
|
const result = await setupOpenclawRelay(agentName, options);
|
|
22103
|
-
writeStdoutLine(
|
|
22104
|
-
writeStdoutLine(`Peer DID: ${result.peerDid}`);
|
|
22105
|
-
writeStdoutLine(`Peer proxy URL: ${result.peerProxyUrl}`);
|
|
22105
|
+
writeStdoutLine("Self setup complete");
|
|
22106
22106
|
writeStdoutLine(
|
|
22107
22107
|
`Updated OpenClaw config: ${result.openclawConfigPath}`
|
|
22108
22108
|
);
|
|
@@ -22145,7 +22145,9 @@ var createOpenclawCommand = () => {
|
|
|
22145
22145
|
)
|
|
22146
22146
|
);
|
|
22147
22147
|
const relayCommand = openclawCommand.command("relay").description("Run OpenClaw relay diagnostics");
|
|
22148
|
-
relayCommand.command("test").description(
|
|
22148
|
+
relayCommand.command("test").description(
|
|
22149
|
+
"Send a relay probe to a configured peer (auto-selects when one peer exists)"
|
|
22150
|
+
).option("--peer <alias>", "Peer alias in ~/.clawdentity/peers.json").option(
|
|
22149
22151
|
"--openclaw-base-url <url>",
|
|
22150
22152
|
"Base URL for local OpenClaw hook API (default OPENCLAW_BASE_URL or relay runtime config)"
|
|
22151
22153
|
).option(
|
|
@@ -22186,7 +22188,14 @@ var createOpenclawCommand = () => {
|
|
|
22186
22188
|
|
|
22187
22189
|
// src/commands/pair.ts
|
|
22188
22190
|
import { randomBytes as randomBytes4 } from "crypto";
|
|
22189
|
-
import {
|
|
22191
|
+
import {
|
|
22192
|
+
chmod as chmod4,
|
|
22193
|
+
mkdir as mkdir6,
|
|
22194
|
+
readdir,
|
|
22195
|
+
readFile as readFile5,
|
|
22196
|
+
unlink as unlink2,
|
|
22197
|
+
writeFile as writeFile6
|
|
22198
|
+
} from "fs/promises";
|
|
22190
22199
|
import { dirname as dirname5, join as join7, resolve } from "path";
|
|
22191
22200
|
import { Command as Command8 } from "commander";
|
|
22192
22201
|
import jsQR from "jsqr";
|
|
@@ -22197,6 +22206,7 @@ var AGENTS_DIR_NAME5 = "agents";
|
|
|
22197
22206
|
var AIT_FILE_NAME4 = "ait.jwt";
|
|
22198
22207
|
var SECRET_KEY_FILE_NAME3 = "secret.key";
|
|
22199
22208
|
var PAIRING_QR_DIR_NAME = "pairing";
|
|
22209
|
+
var PEERS_FILE_NAME2 = "peers.json";
|
|
22200
22210
|
var PAIR_START_PATH = "/pair/start";
|
|
22201
22211
|
var PAIR_CONFIRM_PATH = "/pair/confirm";
|
|
22202
22212
|
var OWNER_PAT_HEADER = "x-claw-owner-pat";
|
|
@@ -22204,6 +22214,8 @@ var NONCE_SIZE2 = 24;
|
|
|
22204
22214
|
var PAIRING_TICKET_PREFIX = "clwpair1_";
|
|
22205
22215
|
var PAIRING_QR_MAX_AGE_SECONDS = 900;
|
|
22206
22216
|
var PAIRING_QR_FILENAME_PATTERN = /-pair-(\d+)\.png$/;
|
|
22217
|
+
var FILE_MODE4 = 384;
|
|
22218
|
+
var PEER_ALIAS_PATTERN2 = /^[a-zA-Z0-9._-]+$/;
|
|
22207
22219
|
var isRecord8 = (value) => {
|
|
22208
22220
|
return typeof value === "object" && value !== null;
|
|
22209
22221
|
};
|
|
@@ -22230,6 +22242,172 @@ function parsePairingTicket(value) {
|
|
|
22230
22242
|
}
|
|
22231
22243
|
return ticket;
|
|
22232
22244
|
}
|
|
22245
|
+
function parsePairingTicketIssuerOrigin(ticket) {
|
|
22246
|
+
const encodedPayload = ticket.slice(PAIRING_TICKET_PREFIX.length);
|
|
22247
|
+
if (encodedPayload.length === 0) {
|
|
22248
|
+
throw createCliError6(
|
|
22249
|
+
"CLI_PAIR_CONFIRM_TICKET_INVALID",
|
|
22250
|
+
"Pairing ticket is invalid"
|
|
22251
|
+
);
|
|
22252
|
+
}
|
|
22253
|
+
let payloadRaw;
|
|
22254
|
+
try {
|
|
22255
|
+
payloadRaw = new TextDecoder().decode(decodeBase64url(encodedPayload));
|
|
22256
|
+
} catch {
|
|
22257
|
+
throw createCliError6(
|
|
22258
|
+
"CLI_PAIR_CONFIRM_TICKET_INVALID",
|
|
22259
|
+
"Pairing ticket is invalid"
|
|
22260
|
+
);
|
|
22261
|
+
}
|
|
22262
|
+
let payload;
|
|
22263
|
+
try {
|
|
22264
|
+
payload = JSON.parse(payloadRaw);
|
|
22265
|
+
} catch {
|
|
22266
|
+
throw createCliError6(
|
|
22267
|
+
"CLI_PAIR_CONFIRM_TICKET_INVALID",
|
|
22268
|
+
"Pairing ticket is invalid"
|
|
22269
|
+
);
|
|
22270
|
+
}
|
|
22271
|
+
if (!isRecord8(payload) || typeof payload.iss !== "string") {
|
|
22272
|
+
throw createCliError6(
|
|
22273
|
+
"CLI_PAIR_CONFIRM_TICKET_INVALID",
|
|
22274
|
+
"Pairing ticket is invalid"
|
|
22275
|
+
);
|
|
22276
|
+
}
|
|
22277
|
+
let issuerUrl;
|
|
22278
|
+
try {
|
|
22279
|
+
issuerUrl = new URL(payload.iss);
|
|
22280
|
+
} catch {
|
|
22281
|
+
throw createCliError6(
|
|
22282
|
+
"CLI_PAIR_CONFIRM_TICKET_INVALID",
|
|
22283
|
+
"Pairing ticket is invalid"
|
|
22284
|
+
);
|
|
22285
|
+
}
|
|
22286
|
+
if (issuerUrl.protocol !== "https:" && issuerUrl.protocol !== "http:") {
|
|
22287
|
+
throw createCliError6(
|
|
22288
|
+
"CLI_PAIR_CONFIRM_TICKET_INVALID",
|
|
22289
|
+
"Pairing ticket is invalid"
|
|
22290
|
+
);
|
|
22291
|
+
}
|
|
22292
|
+
return issuerUrl.origin;
|
|
22293
|
+
}
|
|
22294
|
+
function parsePeerAlias2(value) {
|
|
22295
|
+
if (value.length === 0 || value.length > 128) {
|
|
22296
|
+
throw createCliError6(
|
|
22297
|
+
"CLI_PAIR_PEER_ALIAS_INVALID",
|
|
22298
|
+
"Generated peer alias is invalid"
|
|
22299
|
+
);
|
|
22300
|
+
}
|
|
22301
|
+
if (!PEER_ALIAS_PATTERN2.test(value)) {
|
|
22302
|
+
throw createCliError6(
|
|
22303
|
+
"CLI_PAIR_PEER_ALIAS_INVALID",
|
|
22304
|
+
"Generated peer alias is invalid"
|
|
22305
|
+
);
|
|
22306
|
+
}
|
|
22307
|
+
return value;
|
|
22308
|
+
}
|
|
22309
|
+
function derivePeerAliasBase(peerDid) {
|
|
22310
|
+
try {
|
|
22311
|
+
const parsed = parseDid(peerDid);
|
|
22312
|
+
if (parsed.kind === "agent") {
|
|
22313
|
+
return parsePeerAlias2(`peer-${parsed.ulid.slice(-8).toLowerCase()}`);
|
|
22314
|
+
}
|
|
22315
|
+
} catch {
|
|
22316
|
+
}
|
|
22317
|
+
return "peer";
|
|
22318
|
+
}
|
|
22319
|
+
function resolvePeerAlias(input) {
|
|
22320
|
+
for (const [alias, entry] of Object.entries(input.peers)) {
|
|
22321
|
+
if (entry.did === input.peerDid) {
|
|
22322
|
+
return alias;
|
|
22323
|
+
}
|
|
22324
|
+
}
|
|
22325
|
+
const baseAlias = derivePeerAliasBase(input.peerDid);
|
|
22326
|
+
if (input.peers[baseAlias] === void 0) {
|
|
22327
|
+
return baseAlias;
|
|
22328
|
+
}
|
|
22329
|
+
let index = 2;
|
|
22330
|
+
while (input.peers[`${baseAlias}-${index}`] !== void 0) {
|
|
22331
|
+
index += 1;
|
|
22332
|
+
}
|
|
22333
|
+
return `${baseAlias}-${index}`;
|
|
22334
|
+
}
|
|
22335
|
+
function resolvePeersConfigPath(getConfigDirImpl) {
|
|
22336
|
+
return join7(getConfigDirImpl(), PEERS_FILE_NAME2);
|
|
22337
|
+
}
|
|
22338
|
+
function parsePeerEntry(value) {
|
|
22339
|
+
if (!isRecord8(value)) {
|
|
22340
|
+
throw createCliError6(
|
|
22341
|
+
"CLI_PAIR_PEERS_CONFIG_INVALID",
|
|
22342
|
+
"Peer entry must be an object"
|
|
22343
|
+
);
|
|
22344
|
+
}
|
|
22345
|
+
const did = parseNonEmptyString8(value.did);
|
|
22346
|
+
const proxyUrl = parseNonEmptyString8(value.proxyUrl);
|
|
22347
|
+
if (did.length === 0 || proxyUrl.length === 0) {
|
|
22348
|
+
throw createCliError6(
|
|
22349
|
+
"CLI_PAIR_PEERS_CONFIG_INVALID",
|
|
22350
|
+
"Peer entry is invalid"
|
|
22351
|
+
);
|
|
22352
|
+
}
|
|
22353
|
+
return {
|
|
22354
|
+
did,
|
|
22355
|
+
proxyUrl
|
|
22356
|
+
};
|
|
22357
|
+
}
|
|
22358
|
+
async function loadPeersConfig2(input) {
|
|
22359
|
+
const peersPath = resolvePeersConfigPath(input.getConfigDirImpl);
|
|
22360
|
+
let raw;
|
|
22361
|
+
try {
|
|
22362
|
+
raw = await input.readFileImpl(peersPath, "utf8");
|
|
22363
|
+
} catch (error48) {
|
|
22364
|
+
const nodeError = error48;
|
|
22365
|
+
if (nodeError.code === "ENOENT") {
|
|
22366
|
+
return { peers: {} };
|
|
22367
|
+
}
|
|
22368
|
+
throw error48;
|
|
22369
|
+
}
|
|
22370
|
+
let parsed;
|
|
22371
|
+
try {
|
|
22372
|
+
parsed = JSON.parse(raw);
|
|
22373
|
+
} catch {
|
|
22374
|
+
throw createCliError6(
|
|
22375
|
+
"CLI_PAIR_PEERS_CONFIG_INVALID",
|
|
22376
|
+
"Peer config is not valid JSON"
|
|
22377
|
+
);
|
|
22378
|
+
}
|
|
22379
|
+
if (!isRecord8(parsed)) {
|
|
22380
|
+
throw createCliError6(
|
|
22381
|
+
"CLI_PAIR_PEERS_CONFIG_INVALID",
|
|
22382
|
+
"Peer config must be a JSON object"
|
|
22383
|
+
);
|
|
22384
|
+
}
|
|
22385
|
+
if (parsed.peers === void 0) {
|
|
22386
|
+
return { peers: {} };
|
|
22387
|
+
}
|
|
22388
|
+
if (!isRecord8(parsed.peers)) {
|
|
22389
|
+
throw createCliError6(
|
|
22390
|
+
"CLI_PAIR_PEERS_CONFIG_INVALID",
|
|
22391
|
+
"Peer config peers field must be an object"
|
|
22392
|
+
);
|
|
22393
|
+
}
|
|
22394
|
+
const peers = {};
|
|
22395
|
+
for (const [alias, value] of Object.entries(parsed.peers)) {
|
|
22396
|
+
peers[parsePeerAlias2(alias)] = parsePeerEntry(value);
|
|
22397
|
+
}
|
|
22398
|
+
return { peers };
|
|
22399
|
+
}
|
|
22400
|
+
async function savePeersConfig2(input) {
|
|
22401
|
+
const peersPath = resolvePeersConfigPath(input.getConfigDirImpl);
|
|
22402
|
+
await input.mkdirImpl(dirname5(peersPath), { recursive: true });
|
|
22403
|
+
await input.writeFileImpl(
|
|
22404
|
+
peersPath,
|
|
22405
|
+
`${JSON.stringify(input.config, null, 2)}
|
|
22406
|
+
`,
|
|
22407
|
+
"utf8"
|
|
22408
|
+
);
|
|
22409
|
+
await input.chmodImpl(peersPath, FILE_MODE4);
|
|
22410
|
+
}
|
|
22233
22411
|
function parseTtlSeconds(value) {
|
|
22234
22412
|
const raw = parseNonEmptyString8(value);
|
|
22235
22413
|
if (raw.length === 0) {
|
|
@@ -22244,14 +22422,7 @@ function parseTtlSeconds(value) {
|
|
|
22244
22422
|
}
|
|
22245
22423
|
return parsed;
|
|
22246
22424
|
}
|
|
22247
|
-
function
|
|
22248
|
-
const candidate = parseNonEmptyString8(overrideProxyUrl) || parseNonEmptyString8(process.env.CLAWDENTITY_PROXY_URL);
|
|
22249
|
-
if (candidate.length === 0) {
|
|
22250
|
-
throw createCliError6(
|
|
22251
|
-
"CLI_PAIR_PROXY_URL_REQUIRED",
|
|
22252
|
-
"Proxy URL is required. Pass --proxy-url <url> or set CLAWDENTITY_PROXY_URL."
|
|
22253
|
-
);
|
|
22254
|
-
}
|
|
22425
|
+
function parseProxyUrl2(candidate) {
|
|
22255
22426
|
try {
|
|
22256
22427
|
const parsed = new URL(candidate);
|
|
22257
22428
|
if (parsed.protocol !== "https:" && parsed.protocol !== "http:") {
|
|
@@ -22262,6 +22433,33 @@ function resolveProxyUrl(overrideProxyUrl) {
|
|
|
22262
22433
|
throw createCliError6("CLI_PAIR_INVALID_PROXY_URL", "Proxy URL is invalid");
|
|
22263
22434
|
}
|
|
22264
22435
|
}
|
|
22436
|
+
function resolveProxyUrlCandidates(input) {
|
|
22437
|
+
const explicit = parseNonEmptyString8(input.overrideProxyUrl);
|
|
22438
|
+
if (explicit.length > 0) {
|
|
22439
|
+
return [parseProxyUrl2(explicit)];
|
|
22440
|
+
}
|
|
22441
|
+
const fromEnv = parseNonEmptyString8(process.env.CLAWDENTITY_PROXY_URL);
|
|
22442
|
+
if (fromEnv.length > 0) {
|
|
22443
|
+
return [parseProxyUrl2(fromEnv)];
|
|
22444
|
+
}
|
|
22445
|
+
const fromConfig = parseNonEmptyString8(input.config.proxyUrl);
|
|
22446
|
+
if (fromConfig.length > 0) {
|
|
22447
|
+
return [parseProxyUrl2(fromConfig)];
|
|
22448
|
+
}
|
|
22449
|
+
const derivedFromRegistry = deriveProxyUrlFromRegistryUrl(
|
|
22450
|
+
input.config.registryUrl || DEFAULT_REGISTRY_URL
|
|
22451
|
+
);
|
|
22452
|
+
if (typeof derivedFromRegistry === "string" && derivedFromRegistry.length > 0) {
|
|
22453
|
+
return [parseProxyUrl2(derivedFromRegistry)];
|
|
22454
|
+
}
|
|
22455
|
+
throw createCliError6(
|
|
22456
|
+
"CLI_PAIR_PROXY_URL_REQUIRED",
|
|
22457
|
+
"Proxy URL could not be resolved. Run onboarding invite redeem again or set proxyUrl via `clawdentity config set proxyUrl <url>`."
|
|
22458
|
+
);
|
|
22459
|
+
}
|
|
22460
|
+
function resolveProxyUrl(input) {
|
|
22461
|
+
return resolveProxyUrlCandidates(input)[0];
|
|
22462
|
+
}
|
|
22265
22463
|
function toProxyRequestUrl(proxyUrl, path) {
|
|
22266
22464
|
const normalizedBase = proxyUrl.endsWith("/") ? proxyUrl : `${proxyUrl}/`;
|
|
22267
22465
|
return new URL(path.slice(1), normalizedBase).toString();
|
|
@@ -22585,14 +22783,46 @@ function resolveConfirmTicketSource(options) {
|
|
|
22585
22783
|
"Pairing ticket is required. Pass --ticket <clwpair1_...> or --qr-file <path>."
|
|
22586
22784
|
);
|
|
22587
22785
|
}
|
|
22786
|
+
async function persistPairedPeer(input) {
|
|
22787
|
+
const getConfigDirImpl = input.dependencies.getConfigDirImpl ?? getConfigDir;
|
|
22788
|
+
const readFileImpl = input.dependencies.readFileImpl ?? readFile5;
|
|
22789
|
+
const mkdirImpl = input.dependencies.mkdirImpl ?? mkdir6;
|
|
22790
|
+
const writeFileImpl = input.dependencies.writeFileImpl ?? writeFile6;
|
|
22791
|
+
const chmodImpl = input.dependencies.chmodImpl ?? chmod4;
|
|
22792
|
+
const issuerOrigin = parsePairingTicketIssuerOrigin(input.ticket);
|
|
22793
|
+
const peerProxyUrl = new URL("/hooks/agent", `${issuerOrigin}/`).toString();
|
|
22794
|
+
const peersConfig = await loadPeersConfig2({
|
|
22795
|
+
getConfigDirImpl,
|
|
22796
|
+
readFileImpl
|
|
22797
|
+
});
|
|
22798
|
+
const alias = resolvePeerAlias({
|
|
22799
|
+
peers: peersConfig.peers,
|
|
22800
|
+
peerDid: input.peerDid
|
|
22801
|
+
});
|
|
22802
|
+
peersConfig.peers[alias] = {
|
|
22803
|
+
did: input.peerDid,
|
|
22804
|
+
proxyUrl: peerProxyUrl
|
|
22805
|
+
};
|
|
22806
|
+
await savePeersConfig2({
|
|
22807
|
+
config: peersConfig,
|
|
22808
|
+
getConfigDirImpl,
|
|
22809
|
+
mkdirImpl,
|
|
22810
|
+
writeFileImpl,
|
|
22811
|
+
chmodImpl
|
|
22812
|
+
});
|
|
22813
|
+
return alias;
|
|
22814
|
+
}
|
|
22588
22815
|
async function startPairing(agentName, options, dependencies = {}) {
|
|
22589
22816
|
const fetchImpl = dependencies.fetchImpl ?? fetch;
|
|
22590
22817
|
const resolveConfigImpl = dependencies.resolveConfigImpl ?? resolveConfig;
|
|
22591
22818
|
const nowSecondsImpl = dependencies.nowSecondsImpl ?? (() => Math.floor(Date.now() / 1e3));
|
|
22592
22819
|
const nonceFactoryImpl = dependencies.nonceFactoryImpl ?? (() => randomBytes4(NONCE_SIZE2).toString("base64url"));
|
|
22593
22820
|
const ttlSeconds = parseTtlSeconds(options.ttlSeconds);
|
|
22594
|
-
const proxyUrl = resolveProxyUrl(options.proxyUrl);
|
|
22595
22821
|
const config2 = await resolveConfigImpl();
|
|
22822
|
+
const proxyUrl = resolveProxyUrl({
|
|
22823
|
+
overrideProxyUrl: options.proxyUrl,
|
|
22824
|
+
config: config2
|
|
22825
|
+
});
|
|
22596
22826
|
const ownerPat = resolveOwnerPat({
|
|
22597
22827
|
explicitOwnerPat: options.ownerPat,
|
|
22598
22828
|
config: config2
|
|
@@ -22655,12 +22885,17 @@ async function startPairing(agentName, options, dependencies = {}) {
|
|
|
22655
22885
|
}
|
|
22656
22886
|
async function confirmPairing(agentName, options, dependencies = {}) {
|
|
22657
22887
|
const fetchImpl = dependencies.fetchImpl ?? fetch;
|
|
22888
|
+
const resolveConfigImpl = dependencies.resolveConfigImpl ?? resolveConfig;
|
|
22658
22889
|
const nowSecondsImpl = dependencies.nowSecondsImpl ?? (() => Math.floor(Date.now() / 1e3));
|
|
22659
22890
|
const nonceFactoryImpl = dependencies.nonceFactoryImpl ?? (() => randomBytes4(NONCE_SIZE2).toString("base64url"));
|
|
22660
22891
|
const readFileImpl = dependencies.readFileImpl ?? readFile5;
|
|
22661
22892
|
const qrDecodeImpl = dependencies.qrDecodeImpl ?? decodeTicketFromPng;
|
|
22893
|
+
const config2 = await resolveConfigImpl();
|
|
22662
22894
|
const ticketSource = resolveConfirmTicketSource(options);
|
|
22663
|
-
const proxyUrl = resolveProxyUrl(
|
|
22895
|
+
const proxyUrl = resolveProxyUrl({
|
|
22896
|
+
overrideProxyUrl: options.proxyUrl,
|
|
22897
|
+
config: config2
|
|
22898
|
+
});
|
|
22664
22899
|
let ticket = ticketSource.ticket;
|
|
22665
22900
|
if (ticketSource.source === "qr-file") {
|
|
22666
22901
|
if (!ticketSource.qrFilePath) {
|
|
@@ -22722,6 +22957,11 @@ async function confirmPairing(agentName, options, dependencies = {}) {
|
|
|
22722
22957
|
);
|
|
22723
22958
|
}
|
|
22724
22959
|
const parsed = parsePairConfirmResponse(responseBody);
|
|
22960
|
+
const peerAlias = await persistPairedPeer({
|
|
22961
|
+
ticket,
|
|
22962
|
+
peerDid: parsed.initiatorAgentDid,
|
|
22963
|
+
dependencies
|
|
22964
|
+
});
|
|
22725
22965
|
if (ticketSource.source === "qr-file" && ticketSource.qrFilePath) {
|
|
22726
22966
|
const unlinkImpl = dependencies.unlinkImpl ?? unlink2;
|
|
22727
22967
|
await unlinkImpl(ticketSource.qrFilePath).catch((error48) => {
|
|
@@ -22737,17 +22977,15 @@ async function confirmPairing(agentName, options, dependencies = {}) {
|
|
|
22737
22977
|
}
|
|
22738
22978
|
return {
|
|
22739
22979
|
...parsed,
|
|
22740
|
-
proxyUrl
|
|
22980
|
+
proxyUrl,
|
|
22981
|
+
peerAlias
|
|
22741
22982
|
};
|
|
22742
22983
|
}
|
|
22743
22984
|
var createPairCommand = (dependencies = {}) => {
|
|
22744
22985
|
const pairCommand = new Command8("pair").description(
|
|
22745
22986
|
"Manage proxy trust pairing between agents"
|
|
22746
22987
|
);
|
|
22747
|
-
pairCommand.command("start <agentName>").description("Start pairing and issue one-time pairing ticket").option(
|
|
22748
|
-
"--proxy-url <url>",
|
|
22749
|
-
"Initiator proxy base URL (or set CLAWDENTITY_PROXY_URL)"
|
|
22750
|
-
).option(
|
|
22988
|
+
pairCommand.command("start <agentName>").description("Start pairing and issue one-time pairing ticket").option("--proxy-url <url>", "Optional initiator proxy base URL override").option(
|
|
22751
22989
|
"--owner-pat <token>",
|
|
22752
22990
|
"Owner PAT override (defaults to configured API key)"
|
|
22753
22991
|
).option("--ttl-seconds <seconds>", "Pairing ticket expiry in seconds").option("--qr", "Generate a local QR file for sharing").option("--qr-output <path>", "Write QR PNG to a specific file path").action(
|
|
@@ -22771,10 +23009,7 @@ var createPairCommand = (dependencies = {}) => {
|
|
|
22771
23009
|
}
|
|
22772
23010
|
)
|
|
22773
23011
|
);
|
|
22774
|
-
pairCommand.command("confirm <agentName>").description("Confirm pairing using one-time pairing ticket").option("--ticket <ticket>", "One-time pairing ticket (clwpair1_...)").option("--qr-file <path>", "Path to pairing QR PNG file").option(
|
|
22775
|
-
"--proxy-url <url>",
|
|
22776
|
-
"Responder proxy base URL (or set CLAWDENTITY_PROXY_URL)"
|
|
22777
|
-
).action(
|
|
23012
|
+
pairCommand.command("confirm <agentName>").description("Confirm pairing using one-time pairing ticket").option("--ticket <ticket>", "One-time pairing ticket (clwpair1_...)").option("--qr-file <path>", "Path to pairing QR PNG file").option("--proxy-url <url>", "Optional responder proxy base URL override").action(
|
|
22778
23013
|
withErrorHandling(
|
|
22779
23014
|
"pair confirm",
|
|
22780
23015
|
async (agentName, options) => {
|
|
@@ -22782,12 +23017,16 @@ var createPairCommand = (dependencies = {}) => {
|
|
|
22782
23017
|
logger9.info("cli.pair_confirmed", {
|
|
22783
23018
|
initiatorAgentDid: result.initiatorAgentDid,
|
|
22784
23019
|
responderAgentDid: result.responderAgentDid,
|
|
22785
|
-
proxyUrl: result.proxyUrl
|
|
23020
|
+
proxyUrl: result.proxyUrl,
|
|
23021
|
+
peerAlias: result.peerAlias
|
|
22786
23022
|
});
|
|
22787
23023
|
writeStdoutLine("Pairing confirmed");
|
|
22788
23024
|
writeStdoutLine(`Initiator Agent DID: ${result.initiatorAgentDid}`);
|
|
22789
23025
|
writeStdoutLine(`Responder Agent DID: ${result.responderAgentDid}`);
|
|
22790
23026
|
writeStdoutLine(`Paired: ${result.paired ? "true" : "false"}`);
|
|
23027
|
+
if (result.peerAlias) {
|
|
23028
|
+
writeStdoutLine(`Peer alias saved: ${result.peerAlias}`);
|
|
23029
|
+
}
|
|
22791
23030
|
}
|
|
22792
23031
|
)
|
|
22793
23032
|
);
|
|
@@ -22827,11 +23066,11 @@ var toRegistryUrl = (registryUrl, path) => {
|
|
|
22827
23066
|
var toExpectedIssuer = (registryUrl) => {
|
|
22828
23067
|
try {
|
|
22829
23068
|
const hostname3 = new URL(registryUrl).hostname;
|
|
22830
|
-
if (hostname3 === "
|
|
22831
|
-
return "https://
|
|
23069
|
+
if (hostname3 === "registry.clawdentity.com") {
|
|
23070
|
+
return "https://registry.clawdentity.com";
|
|
22832
23071
|
}
|
|
22833
|
-
if (hostname3 === "dev.
|
|
22834
|
-
return "https://dev.
|
|
23072
|
+
if (hostname3 === "dev.registry.clawdentity.com") {
|
|
23073
|
+
return "https://dev.registry.clawdentity.com";
|
|
22835
23074
|
}
|
|
22836
23075
|
return void 0;
|
|
22837
23076
|
} catch {
|