clawdentity 0.0.11 → 0.0.13
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 +953 -364
- package/dist/index.js +953 -364
- package/dist/postinstall.js +0 -357
- package/package.json +16 -17
- package/postinstall.mjs +1 -34
- package/skill-bundle/AGENTS.md +1 -1
- package/skill-bundle/openclaw-skill/skill/SKILL.md +9 -11
- package/skill-bundle/openclaw-skill/skill/references/clawdentity-protocol.md +1 -1
package/dist/index.js
CHANGED
|
@@ -6,8 +6,8 @@ var __export = (target, all) => {
|
|
|
6
6
|
};
|
|
7
7
|
|
|
8
8
|
// src/index.ts
|
|
9
|
-
import { createRequire } from "module";
|
|
10
|
-
import { Command as
|
|
9
|
+
import { createRequire as createRequire2 } from "module";
|
|
10
|
+
import { Command as Command11 } from "commander";
|
|
11
11
|
|
|
12
12
|
// ../../packages/protocol/src/agent-registration-proof.ts
|
|
13
13
|
var AGENT_REGISTRATION_PROOF_VERSION = "clawdentity.register.v1";
|
|
@@ -14359,6 +14359,8 @@ var AGENT_AUTH_REFRESH_PATH = "/v1/agents/auth/refresh";
|
|
|
14359
14359
|
var INVITES_PATH = "/v1/invites";
|
|
14360
14360
|
var INVITES_REDEEM_PATH = "/v1/invites/redeem";
|
|
14361
14361
|
var ME_API_KEYS_PATH = "/v1/me/api-keys";
|
|
14362
|
+
var REGISTRY_METADATA_PATH = "/v1/metadata";
|
|
14363
|
+
var RELAY_CONNECT_PATH = "/v1/relay/connect";
|
|
14362
14364
|
var RELAY_RECIPIENT_AGENT_DID_HEADER = "x-claw-recipient-agent-did";
|
|
14363
14365
|
|
|
14364
14366
|
// ../../packages/protocol/src/http-signing.ts
|
|
@@ -18395,6 +18397,139 @@ var createApiKeyCommand = (dependencies = {}) => {
|
|
|
18395
18397
|
// src/commands/config.ts
|
|
18396
18398
|
import { access as access2 } from "fs/promises";
|
|
18397
18399
|
import { Command as Command4 } from "commander";
|
|
18400
|
+
|
|
18401
|
+
// src/config/registry-metadata.ts
|
|
18402
|
+
function isRecord4(value) {
|
|
18403
|
+
return typeof value === "object" && value !== null;
|
|
18404
|
+
}
|
|
18405
|
+
function parseNonEmptyString5(value) {
|
|
18406
|
+
if (typeof value !== "string") {
|
|
18407
|
+
return "";
|
|
18408
|
+
}
|
|
18409
|
+
return value.trim();
|
|
18410
|
+
}
|
|
18411
|
+
function createCliError3(code, message2) {
|
|
18412
|
+
return new AppError({
|
|
18413
|
+
code,
|
|
18414
|
+
message: message2,
|
|
18415
|
+
status: 400
|
|
18416
|
+
});
|
|
18417
|
+
}
|
|
18418
|
+
function parseUrl(candidate, label) {
|
|
18419
|
+
let parsed;
|
|
18420
|
+
try {
|
|
18421
|
+
parsed = new URL(candidate);
|
|
18422
|
+
} catch {
|
|
18423
|
+
throw createCliError3("CLI_REGISTRY_URL_INVALID", `${label} is invalid`);
|
|
18424
|
+
}
|
|
18425
|
+
if (parsed.protocol !== "https:" && parsed.protocol !== "http:") {
|
|
18426
|
+
throw createCliError3("CLI_REGISTRY_URL_INVALID", `${label} is invalid`);
|
|
18427
|
+
}
|
|
18428
|
+
return parsed;
|
|
18429
|
+
}
|
|
18430
|
+
function normalizeRegistryUrl(registryUrl) {
|
|
18431
|
+
return parseUrl(registryUrl, "Registry URL").toString();
|
|
18432
|
+
}
|
|
18433
|
+
function toRegistryRequestUrl(registryUrl, path) {
|
|
18434
|
+
const normalizedRegistryUrl = normalizeRegistryUrl(registryUrl);
|
|
18435
|
+
const base = normalizedRegistryUrl.endsWith("/") ? normalizedRegistryUrl : `${normalizedRegistryUrl}/`;
|
|
18436
|
+
return new URL(path.slice(1), base).toString();
|
|
18437
|
+
}
|
|
18438
|
+
function extractRegistryErrorMessage3(payload) {
|
|
18439
|
+
if (!isRecord4(payload)) {
|
|
18440
|
+
return void 0;
|
|
18441
|
+
}
|
|
18442
|
+
const envelope = payload;
|
|
18443
|
+
if (!envelope.error || typeof envelope.error.message !== "string") {
|
|
18444
|
+
return void 0;
|
|
18445
|
+
}
|
|
18446
|
+
const trimmed = envelope.error.message.trim();
|
|
18447
|
+
return trimmed.length > 0 ? trimmed : void 0;
|
|
18448
|
+
}
|
|
18449
|
+
async function parseJsonResponse4(response) {
|
|
18450
|
+
try {
|
|
18451
|
+
return await response.json();
|
|
18452
|
+
} catch {
|
|
18453
|
+
return void 0;
|
|
18454
|
+
}
|
|
18455
|
+
}
|
|
18456
|
+
function parseMetadataPayload(payload, fallbackRegistryUrl) {
|
|
18457
|
+
if (!isRecord4(payload)) {
|
|
18458
|
+
throw createCliError3(
|
|
18459
|
+
"CLI_REGISTRY_METADATA_INVALID_RESPONSE",
|
|
18460
|
+
"Registry metadata response is invalid"
|
|
18461
|
+
);
|
|
18462
|
+
}
|
|
18463
|
+
const proxyUrlRaw = parseNonEmptyString5(payload.proxyUrl);
|
|
18464
|
+
if (proxyUrlRaw.length === 0) {
|
|
18465
|
+
throw createCliError3(
|
|
18466
|
+
"CLI_REGISTRY_METADATA_INVALID_RESPONSE",
|
|
18467
|
+
"Registry metadata response is invalid"
|
|
18468
|
+
);
|
|
18469
|
+
}
|
|
18470
|
+
const proxyUrl = parseUrl(proxyUrlRaw, "Proxy URL").toString();
|
|
18471
|
+
const registryUrlRaw = parseNonEmptyString5(payload.registryUrl);
|
|
18472
|
+
const registryUrl = registryUrlRaw.length > 0 ? parseUrl(registryUrlRaw, "Registry URL").toString() : normalizeRegistryUrl(fallbackRegistryUrl);
|
|
18473
|
+
const environment = parseNonEmptyString5(payload.environment);
|
|
18474
|
+
const version2 = parseNonEmptyString5(payload.version);
|
|
18475
|
+
return {
|
|
18476
|
+
proxyUrl,
|
|
18477
|
+
registryUrl,
|
|
18478
|
+
environment: environment.length > 0 ? environment : void 0,
|
|
18479
|
+
version: version2.length > 0 ? version2 : void 0
|
|
18480
|
+
};
|
|
18481
|
+
}
|
|
18482
|
+
function mapMetadataError(status, payload) {
|
|
18483
|
+
const registryMessage = extractRegistryErrorMessage3(payload);
|
|
18484
|
+
if (status === 404) {
|
|
18485
|
+
return "Registry metadata endpoint is unavailable (404).";
|
|
18486
|
+
}
|
|
18487
|
+
if (status >= 500) {
|
|
18488
|
+
return `Registry metadata request failed (${status}). Try again later.`;
|
|
18489
|
+
}
|
|
18490
|
+
if (registryMessage) {
|
|
18491
|
+
return `Registry metadata request failed (${status}): ${registryMessage}`;
|
|
18492
|
+
}
|
|
18493
|
+
return `Registry metadata request failed (${status}).`;
|
|
18494
|
+
}
|
|
18495
|
+
async function fetchRegistryMetadata(registryUrl, dependencies = {}) {
|
|
18496
|
+
const fetchImpl = dependencies.fetchImpl ?? globalThis.fetch;
|
|
18497
|
+
if (typeof fetchImpl !== "function") {
|
|
18498
|
+
throw createCliError3(
|
|
18499
|
+
"CLI_REGISTRY_METADATA_FETCH_UNAVAILABLE",
|
|
18500
|
+
"Runtime fetch is unavailable for registry metadata lookup"
|
|
18501
|
+
);
|
|
18502
|
+
}
|
|
18503
|
+
const normalizedRegistryUrl = normalizeRegistryUrl(registryUrl);
|
|
18504
|
+
const requestUrl = toRegistryRequestUrl(
|
|
18505
|
+
normalizedRegistryUrl,
|
|
18506
|
+
REGISTRY_METADATA_PATH
|
|
18507
|
+
);
|
|
18508
|
+
let response;
|
|
18509
|
+
try {
|
|
18510
|
+
response = await fetchImpl(requestUrl, {
|
|
18511
|
+
method: "GET",
|
|
18512
|
+
headers: {
|
|
18513
|
+
accept: "application/json"
|
|
18514
|
+
}
|
|
18515
|
+
});
|
|
18516
|
+
} catch {
|
|
18517
|
+
throw createCliError3(
|
|
18518
|
+
"CLI_REGISTRY_METADATA_REQUEST_FAILED",
|
|
18519
|
+
"Unable to reach registry metadata endpoint. Check registryUrl and network access."
|
|
18520
|
+
);
|
|
18521
|
+
}
|
|
18522
|
+
const payload = await parseJsonResponse4(response);
|
|
18523
|
+
if (!response.ok) {
|
|
18524
|
+
throw createCliError3(
|
|
18525
|
+
"CLI_REGISTRY_METADATA_FETCH_FAILED",
|
|
18526
|
+
mapMetadataError(response.status, payload)
|
|
18527
|
+
);
|
|
18528
|
+
}
|
|
18529
|
+
return parseMetadataPayload(payload, normalizedRegistryUrl);
|
|
18530
|
+
}
|
|
18531
|
+
|
|
18532
|
+
// src/commands/config.ts
|
|
18398
18533
|
var logger5 = createLogger({ service: "cli", module: "config" });
|
|
18399
18534
|
var VALID_KEYS = [
|
|
18400
18535
|
"registryUrl",
|
|
@@ -18437,7 +18572,7 @@ var getEnvRegistryUrlOverride = () => {
|
|
|
18437
18572
|
return typeof value === "string" && value.length > 0;
|
|
18438
18573
|
});
|
|
18439
18574
|
};
|
|
18440
|
-
var createConfigCommand = () => {
|
|
18575
|
+
var createConfigCommand = (dependencies = {}) => {
|
|
18441
18576
|
const configCommand = new Command4("config").description(
|
|
18442
18577
|
"Manage local CLI configuration"
|
|
18443
18578
|
);
|
|
@@ -18454,14 +18589,27 @@ var createConfigCommand = () => {
|
|
|
18454
18589
|
}
|
|
18455
18590
|
}
|
|
18456
18591
|
const config2 = await readConfig();
|
|
18457
|
-
const
|
|
18592
|
+
const requestedRegistryUrl = options.registryUrl ?? getEnvRegistryUrlOverride() ?? config2.registryUrl;
|
|
18593
|
+
const normalizedRegistryUrl = normalizeRegistryUrl(requestedRegistryUrl);
|
|
18594
|
+
const metadata = await fetchRegistryMetadata(normalizedRegistryUrl, {
|
|
18595
|
+
fetchImpl: dependencies.fetchImpl
|
|
18596
|
+
});
|
|
18458
18597
|
await writeConfig({
|
|
18459
18598
|
...config2,
|
|
18460
|
-
registryUrl
|
|
18599
|
+
registryUrl: metadata.registryUrl,
|
|
18600
|
+
proxyUrl: metadata.proxyUrl
|
|
18461
18601
|
});
|
|
18462
18602
|
writeStdoutLine(`Initialized config at ${configFilePath}`);
|
|
18463
18603
|
writeStdoutLine(
|
|
18464
|
-
JSON.stringify(
|
|
18604
|
+
JSON.stringify(
|
|
18605
|
+
maskApiKey({
|
|
18606
|
+
...config2,
|
|
18607
|
+
registryUrl: metadata.registryUrl,
|
|
18608
|
+
proxyUrl: metadata.proxyUrl
|
|
18609
|
+
}),
|
|
18610
|
+
null,
|
|
18611
|
+
2
|
|
18612
|
+
)
|
|
18465
18613
|
);
|
|
18466
18614
|
})
|
|
18467
18615
|
);
|
|
@@ -18768,6 +18916,7 @@ function normalizeConnectionHeaders(headers) {
|
|
|
18768
18916
|
var ConnectorClient = class {
|
|
18769
18917
|
connectorUrl;
|
|
18770
18918
|
connectionHeaders;
|
|
18919
|
+
connectionHeadersProvider;
|
|
18771
18920
|
openclawHookUrl;
|
|
18772
18921
|
openclawHookToken;
|
|
18773
18922
|
heartbeatIntervalMs;
|
|
@@ -18799,6 +18948,7 @@ var ConnectorClient = class {
|
|
|
18799
18948
|
this.connectionHeaders = normalizeConnectionHeaders(
|
|
18800
18949
|
options.connectionHeaders
|
|
18801
18950
|
);
|
|
18951
|
+
this.connectionHeadersProvider = options.connectionHeadersProvider;
|
|
18802
18952
|
this.openclawHookToken = options.openclawHookToken;
|
|
18803
18953
|
this.heartbeatIntervalMs = options.heartbeatIntervalMs ?? DEFAULT_HEARTBEAT_INTERVAL_MS;
|
|
18804
18954
|
this.reconnectMinDelayMs = options.reconnectMinDelayMs ?? DEFAULT_RECONNECT_MIN_DELAY_MS;
|
|
@@ -18851,7 +19001,7 @@ var ConnectorClient = class {
|
|
|
18851
19001
|
return;
|
|
18852
19002
|
}
|
|
18853
19003
|
this.started = true;
|
|
18854
|
-
this.connectSocket();
|
|
19004
|
+
void this.connectSocket();
|
|
18855
19005
|
}
|
|
18856
19006
|
disconnect() {
|
|
18857
19007
|
this.started = false;
|
|
@@ -18884,13 +19034,27 @@ var ConnectorClient = class {
|
|
|
18884
19034
|
this.flushOutboundQueue();
|
|
18885
19035
|
return frame;
|
|
18886
19036
|
}
|
|
18887
|
-
connectSocket() {
|
|
19037
|
+
async connectSocket() {
|
|
18888
19038
|
this.clearReconnectTimeout();
|
|
19039
|
+
let connectionHeaders = this.connectionHeaders;
|
|
19040
|
+
if (this.connectionHeadersProvider) {
|
|
19041
|
+
try {
|
|
19042
|
+
connectionHeaders = normalizeConnectionHeaders(
|
|
19043
|
+
await this.connectionHeadersProvider()
|
|
19044
|
+
);
|
|
19045
|
+
} catch (error48) {
|
|
19046
|
+
this.logger.warn("connector.websocket.create_failed", {
|
|
19047
|
+
reason: sanitizeErrorReason(error48)
|
|
19048
|
+
});
|
|
19049
|
+
this.scheduleReconnect();
|
|
19050
|
+
return;
|
|
19051
|
+
}
|
|
19052
|
+
}
|
|
19053
|
+
if (!this.started) {
|
|
19054
|
+
return;
|
|
19055
|
+
}
|
|
18889
19056
|
try {
|
|
18890
|
-
this.socket = this.webSocketFactory(
|
|
18891
|
-
this.connectorUrl,
|
|
18892
|
-
this.connectionHeaders
|
|
18893
|
-
);
|
|
19057
|
+
this.socket = this.webSocketFactory(this.connectorUrl, connectionHeaders);
|
|
18894
19058
|
} catch (error48) {
|
|
18895
19059
|
this.logger.warn("connector.websocket.create_failed", {
|
|
18896
19060
|
reason: sanitizeErrorReason(error48)
|
|
@@ -18945,7 +19109,7 @@ var ConnectorClient = class {
|
|
|
18945
19109
|
const delayMs = Math.max(0, Math.floor(boundedDelay + jitterOffset));
|
|
18946
19110
|
this.reconnectAttempt += 1;
|
|
18947
19111
|
this.reconnectTimeout = setTimeout(() => {
|
|
18948
|
-
this.connectSocket();
|
|
19112
|
+
void this.connectSocket();
|
|
18949
19113
|
}, delayMs);
|
|
18950
19114
|
}
|
|
18951
19115
|
clearReconnectTimeout() {
|
|
@@ -19165,7 +19329,7 @@ var REFRESH_SINGLE_FLIGHT_PREFIX = "connector-runtime";
|
|
|
19165
19329
|
var NONCE_SIZE = 16;
|
|
19166
19330
|
var MAX_OUTBOUND_BODY_BYTES = 1024 * 1024;
|
|
19167
19331
|
var ACCESS_TOKEN_REFRESH_SKEW_MS = 3e4;
|
|
19168
|
-
function
|
|
19332
|
+
function isRecord5(value) {
|
|
19169
19333
|
return typeof value === "object" && value !== null;
|
|
19170
19334
|
}
|
|
19171
19335
|
function toPathWithQuery2(url2) {
|
|
@@ -19213,6 +19377,9 @@ function normalizeWebSocketUrl(urlInput) {
|
|
|
19213
19377
|
if (parsed.protocol !== "wss:" && parsed.protocol !== "ws:") {
|
|
19214
19378
|
throw new Error("Proxy websocket URL must use ws:// or wss://");
|
|
19215
19379
|
}
|
|
19380
|
+
if (parsed.pathname === "/") {
|
|
19381
|
+
parsed.pathname = RELAY_CONNECT_PATH;
|
|
19382
|
+
}
|
|
19216
19383
|
return parsed.toString();
|
|
19217
19384
|
}
|
|
19218
19385
|
function resolveOpenclawBaseUrl(input) {
|
|
@@ -19257,7 +19424,7 @@ function shouldRefreshAccessToken(auth, nowMs) {
|
|
|
19257
19424
|
return expiresAtMs <= nowMs + ACCESS_TOKEN_REFRESH_SKEW_MS;
|
|
19258
19425
|
}
|
|
19259
19426
|
function parseOutboundRelayRequest(payload) {
|
|
19260
|
-
if (!
|
|
19427
|
+
if (!isRecord5(payload)) {
|
|
19261
19428
|
throw new AppError({
|
|
19262
19429
|
code: "CONNECTOR_OUTBOUND_INVALID_REQUEST",
|
|
19263
19430
|
message: "Outbound relay request must be an object",
|
|
@@ -19390,7 +19557,10 @@ async function startConnectorRuntime(input) {
|
|
|
19390
19557
|
parseRequiredString(input.credentials.secretKey, "secretKey")
|
|
19391
19558
|
);
|
|
19392
19559
|
let currentAuth = toInitialAuthBundle(input.credentials);
|
|
19393
|
-
|
|
19560
|
+
const refreshCurrentAuthIfNeeded = async () => {
|
|
19561
|
+
if (!shouldRefreshAccessToken(currentAuth, Date.now())) {
|
|
19562
|
+
return;
|
|
19563
|
+
}
|
|
19394
19564
|
currentAuth = await refreshAgentAuthWithClawProof({
|
|
19395
19565
|
registryUrl: input.registryUrl,
|
|
19396
19566
|
ait: input.credentials.ait,
|
|
@@ -19403,18 +19573,22 @@ async function startConnectorRuntime(input) {
|
|
|
19403
19573
|
agentName: input.agentName,
|
|
19404
19574
|
auth: currentAuth
|
|
19405
19575
|
});
|
|
19406
|
-
}
|
|
19576
|
+
};
|
|
19577
|
+
await refreshCurrentAuthIfNeeded();
|
|
19407
19578
|
const wsUrl = normalizeWebSocketUrl(input.proxyWebsocketUrl);
|
|
19408
19579
|
const wsParsed = new URL(wsUrl);
|
|
19409
|
-
const
|
|
19410
|
-
|
|
19411
|
-
|
|
19412
|
-
|
|
19413
|
-
|
|
19414
|
-
|
|
19580
|
+
const resolveUpgradeHeaders = async () => {
|
|
19581
|
+
await refreshCurrentAuthIfNeeded();
|
|
19582
|
+
return buildUpgradeHeaders({
|
|
19583
|
+
wsUrl: wsParsed,
|
|
19584
|
+
ait: input.credentials.ait,
|
|
19585
|
+
accessToken: currentAuth.accessToken,
|
|
19586
|
+
secretKey
|
|
19587
|
+
});
|
|
19588
|
+
};
|
|
19415
19589
|
const connectorClient = new ConnectorClient({
|
|
19416
19590
|
connectorUrl: wsParsed.toString(),
|
|
19417
|
-
|
|
19591
|
+
connectionHeadersProvider: resolveUpgradeHeaders,
|
|
19418
19592
|
openclawBaseUrl: resolveOpenclawBaseUrl(input.openclawBaseUrl),
|
|
19419
19593
|
openclawHookPath: resolveOpenclawHookPath(input.openclawHookPath),
|
|
19420
19594
|
openclawHookToken: resolveOpenclawHookToken(input.openclawHookToken),
|
|
@@ -19588,16 +19762,16 @@ var OPENCLAW_CONNECTORS_FILE_NAME = "openclaw-connectors.json";
|
|
|
19588
19762
|
var SERVICE_LOG_DIR_NAME = "logs";
|
|
19589
19763
|
var DEFAULT_CONNECTOR_BASE_URL2 = "http://127.0.0.1:19400";
|
|
19590
19764
|
var DEFAULT_CONNECTOR_OUTBOUND_PATH2 = "/v1/outbound";
|
|
19591
|
-
function
|
|
19765
|
+
function isRecord6(value) {
|
|
19592
19766
|
return typeof value === "object" && value !== null;
|
|
19593
19767
|
}
|
|
19594
19768
|
function getErrorCode(error48) {
|
|
19595
|
-
if (!
|
|
19769
|
+
if (!isRecord6(error48)) {
|
|
19596
19770
|
return void 0;
|
|
19597
19771
|
}
|
|
19598
19772
|
return typeof error48.code === "string" ? error48.code : void 0;
|
|
19599
19773
|
}
|
|
19600
|
-
function
|
|
19774
|
+
function createCliError4(code, message2, details) {
|
|
19601
19775
|
return new AppError({
|
|
19602
19776
|
code,
|
|
19603
19777
|
message: message2,
|
|
@@ -19605,9 +19779,9 @@ function createCliError3(code, message2, details) {
|
|
|
19605
19779
|
details
|
|
19606
19780
|
});
|
|
19607
19781
|
}
|
|
19608
|
-
function
|
|
19782
|
+
function parseNonEmptyString6(value, label) {
|
|
19609
19783
|
if (typeof value !== "string") {
|
|
19610
|
-
throw
|
|
19784
|
+
throw createCliError4(
|
|
19611
19785
|
"CLI_CONNECTOR_INVALID_INPUT",
|
|
19612
19786
|
"Connector input is invalid",
|
|
19613
19787
|
{
|
|
@@ -19617,7 +19791,7 @@ function parseNonEmptyString5(value, label) {
|
|
|
19617
19791
|
}
|
|
19618
19792
|
const trimmed = value.trim();
|
|
19619
19793
|
if (trimmed.length === 0) {
|
|
19620
|
-
throw
|
|
19794
|
+
throw createCliError4(
|
|
19621
19795
|
"CLI_CONNECTOR_INVALID_INPUT",
|
|
19622
19796
|
"Connector input is invalid",
|
|
19623
19797
|
{
|
|
@@ -19628,9 +19802,9 @@ function parseNonEmptyString5(value, label) {
|
|
|
19628
19802
|
return trimmed;
|
|
19629
19803
|
}
|
|
19630
19804
|
function parseAgentDid(value) {
|
|
19631
|
-
const did =
|
|
19805
|
+
const did = parseNonEmptyString6(value, "agent did");
|
|
19632
19806
|
if (!did.startsWith("did:claw:agent:")) {
|
|
19633
|
-
throw
|
|
19807
|
+
throw createCliError4(
|
|
19634
19808
|
"CLI_CONNECTOR_INVALID_AGENT_IDENTITY",
|
|
19635
19809
|
"Agent identity is invalid for connector startup"
|
|
19636
19810
|
);
|
|
@@ -19642,13 +19816,13 @@ function parseConnectorBaseUrl(value) {
|
|
|
19642
19816
|
try {
|
|
19643
19817
|
parsed = new URL(value);
|
|
19644
19818
|
} catch {
|
|
19645
|
-
throw
|
|
19819
|
+
throw createCliError4(
|
|
19646
19820
|
"CLI_CONNECTOR_INVALID_BASE_URL",
|
|
19647
19821
|
"Connector base URL is invalid"
|
|
19648
19822
|
);
|
|
19649
19823
|
}
|
|
19650
19824
|
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
19651
|
-
throw
|
|
19825
|
+
throw createCliError4(
|
|
19652
19826
|
"CLI_CONNECTOR_INVALID_BASE_URL",
|
|
19653
19827
|
"Connector base URL is invalid"
|
|
19654
19828
|
);
|
|
@@ -19658,10 +19832,65 @@ function parseConnectorBaseUrl(value) {
|
|
|
19658
19832
|
}
|
|
19659
19833
|
return parsed.toString();
|
|
19660
19834
|
}
|
|
19835
|
+
function parseProxyWebsocketUrl(value) {
|
|
19836
|
+
let parsed;
|
|
19837
|
+
try {
|
|
19838
|
+
parsed = new URL(value);
|
|
19839
|
+
} catch {
|
|
19840
|
+
throw createCliError4(
|
|
19841
|
+
"CLI_CONNECTOR_INVALID_PROXY_URL",
|
|
19842
|
+
"Proxy websocket URL is invalid"
|
|
19843
|
+
);
|
|
19844
|
+
}
|
|
19845
|
+
if (parsed.protocol !== "ws:" && parsed.protocol !== "wss:" && parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
19846
|
+
throw createCliError4(
|
|
19847
|
+
"CLI_CONNECTOR_INVALID_PROXY_URL",
|
|
19848
|
+
"Proxy websocket URL is invalid"
|
|
19849
|
+
);
|
|
19850
|
+
}
|
|
19851
|
+
return parsed.toString();
|
|
19852
|
+
}
|
|
19853
|
+
function resolveProxyWebsocketUrlFromEnv() {
|
|
19854
|
+
const explicitProxyWsUrl = process.env.CLAWDENTITY_PROXY_WS_URL;
|
|
19855
|
+
if (typeof explicitProxyWsUrl === "string" && explicitProxyWsUrl.trim().length > 0) {
|
|
19856
|
+
return parseProxyWebsocketUrl(explicitProxyWsUrl.trim());
|
|
19857
|
+
}
|
|
19858
|
+
const proxyUrl = process.env.CLAWDENTITY_PROXY_URL;
|
|
19859
|
+
if (typeof proxyUrl === "string" && proxyUrl.trim().length > 0) {
|
|
19860
|
+
return parseProxyWebsocketUrl(proxyUrl.trim());
|
|
19861
|
+
}
|
|
19862
|
+
return void 0;
|
|
19863
|
+
}
|
|
19864
|
+
async function resolveProxyWebsocketUrl(input) {
|
|
19865
|
+
if (typeof input.explicitProxyWsUrl === "string" && input.explicitProxyWsUrl.trim().length > 0) {
|
|
19866
|
+
return parseProxyWebsocketUrl(input.explicitProxyWsUrl.trim());
|
|
19867
|
+
}
|
|
19868
|
+
const fromEnv = resolveProxyWebsocketUrlFromEnv();
|
|
19869
|
+
if (fromEnv !== void 0) {
|
|
19870
|
+
return fromEnv;
|
|
19871
|
+
}
|
|
19872
|
+
if (typeof input.configProxyUrl === "string" && input.configProxyUrl.trim().length > 0) {
|
|
19873
|
+
return parseProxyWebsocketUrl(input.configProxyUrl.trim());
|
|
19874
|
+
}
|
|
19875
|
+
const fetchImpl = input.fetchImpl ?? globalThis.fetch;
|
|
19876
|
+
if (typeof fetchImpl === "function") {
|
|
19877
|
+
try {
|
|
19878
|
+
const metadata = await fetchRegistryMetadata(input.registryUrl, {
|
|
19879
|
+
fetchImpl
|
|
19880
|
+
});
|
|
19881
|
+
return parseProxyWebsocketUrl(metadata.proxyUrl);
|
|
19882
|
+
} catch {
|
|
19883
|
+
}
|
|
19884
|
+
}
|
|
19885
|
+
throw createCliError4(
|
|
19886
|
+
"CLI_CONNECTOR_PROXY_URL_REQUIRED",
|
|
19887
|
+
"Proxy URL is required for connector startup. Run `clawdentity invite redeem <clw_inv_...>` or set CLAWDENTITY_PROXY_URL / CLAWDENTITY_PROXY_WS_URL."
|
|
19888
|
+
);
|
|
19889
|
+
}
|
|
19661
19890
|
function normalizeOutboundPath2(pathValue) {
|
|
19662
19891
|
const trimmed = pathValue.trim();
|
|
19663
19892
|
if (trimmed.length === 0) {
|
|
19664
|
-
throw
|
|
19893
|
+
throw createCliError4(
|
|
19665
19894
|
"CLI_CONNECTOR_INVALID_OUTBOUND_PATH",
|
|
19666
19895
|
"Connector outbound path is invalid"
|
|
19667
19896
|
);
|
|
@@ -19690,17 +19919,17 @@ async function readConnectorAssignedBaseUrl(configDir, agentName, readFileImpl)
|
|
|
19690
19919
|
try {
|
|
19691
19920
|
parsed = JSON.parse(raw);
|
|
19692
19921
|
} catch {
|
|
19693
|
-
throw
|
|
19922
|
+
throw createCliError4(
|
|
19694
19923
|
"CLI_CONNECTOR_INVALID_ASSIGNMENTS",
|
|
19695
19924
|
"Connector assignments config is invalid JSON",
|
|
19696
19925
|
{ assignmentsPath }
|
|
19697
19926
|
);
|
|
19698
19927
|
}
|
|
19699
|
-
if (!
|
|
19928
|
+
if (!isRecord6(parsed) || !isRecord6(parsed.agents)) {
|
|
19700
19929
|
return void 0;
|
|
19701
19930
|
}
|
|
19702
19931
|
const entry = parsed.agents[agentName];
|
|
19703
|
-
if (!
|
|
19932
|
+
if (!isRecord6(entry) || typeof entry.connectorBaseUrl !== "string") {
|
|
19704
19933
|
return void 0;
|
|
19705
19934
|
}
|
|
19706
19935
|
return parseConnectorBaseUrl(entry.connectorBaseUrl);
|
|
@@ -19721,7 +19950,7 @@ async function readRequiredTrimmedFile(filePath, label, readFileImpl) {
|
|
|
19721
19950
|
raw = await readFileImpl(filePath, "utf8");
|
|
19722
19951
|
} catch (error48) {
|
|
19723
19952
|
if (getErrorCode(error48) === "ENOENT") {
|
|
19724
|
-
throw
|
|
19953
|
+
throw createCliError4(
|
|
19725
19954
|
"CLI_CONNECTOR_MISSING_AGENT_MATERIAL",
|
|
19726
19955
|
"Local agent credentials are missing for connector startup",
|
|
19727
19956
|
{ label }
|
|
@@ -19731,7 +19960,7 @@ async function readRequiredTrimmedFile(filePath, label, readFileImpl) {
|
|
|
19731
19960
|
}
|
|
19732
19961
|
const trimmed = raw.trim();
|
|
19733
19962
|
if (trimmed.length === 0) {
|
|
19734
|
-
throw
|
|
19963
|
+
throw createCliError4(
|
|
19735
19964
|
"CLI_CONNECTOR_MISSING_AGENT_MATERIAL",
|
|
19736
19965
|
"Local agent credentials are missing for connector startup",
|
|
19737
19966
|
{ label }
|
|
@@ -19756,7 +19985,7 @@ async function readRelayRuntimeConfig(configDir, readFileImpl) {
|
|
|
19756
19985
|
} catch {
|
|
19757
19986
|
return void 0;
|
|
19758
19987
|
}
|
|
19759
|
-
if (!
|
|
19988
|
+
if (!isRecord6(parsed)) {
|
|
19760
19989
|
return void 0;
|
|
19761
19990
|
}
|
|
19762
19991
|
const openclawHookToken = typeof parsed.openclawHookToken === "string" && parsed.openclawHookToken.trim().length > 0 ? parsed.openclawHookToken.trim() : void 0;
|
|
@@ -19772,10 +20001,10 @@ function parseJsonRecord(value, code, message2) {
|
|
|
19772
20001
|
try {
|
|
19773
20002
|
parsed = JSON.parse(value);
|
|
19774
20003
|
} catch {
|
|
19775
|
-
throw
|
|
20004
|
+
throw createCliError4(code, message2);
|
|
19776
20005
|
}
|
|
19777
|
-
if (!
|
|
19778
|
-
throw
|
|
20006
|
+
if (!isRecord6(parsed)) {
|
|
20007
|
+
throw createCliError4(code, message2);
|
|
19779
20008
|
}
|
|
19780
20009
|
return parsed;
|
|
19781
20010
|
}
|
|
@@ -19785,7 +20014,7 @@ function parseRegistryAuth(rawRegistryAuth) {
|
|
|
19785
20014
|
"CLI_CONNECTOR_INVALID_REGISTRY_AUTH",
|
|
19786
20015
|
"Agent registry auth is invalid for connector startup"
|
|
19787
20016
|
);
|
|
19788
|
-
const refreshToken =
|
|
20017
|
+
const refreshToken = parseNonEmptyString6(parsed.refreshToken, "refreshToken");
|
|
19789
20018
|
const accessToken = typeof parsed.accessToken === "string" && parsed.accessToken.trim().length > 0 ? parsed.accessToken.trim() : void 0;
|
|
19790
20019
|
const accessExpiresAt = typeof parsed.accessExpiresAt === "string" && parsed.accessExpiresAt.trim().length > 0 ? parsed.accessExpiresAt.trim() : void 0;
|
|
19791
20020
|
const refreshExpiresAt = typeof parsed.refreshExpiresAt === "string" && parsed.refreshExpiresAt.trim().length > 0 ? parsed.refreshExpiresAt.trim() : void 0;
|
|
@@ -19814,7 +20043,7 @@ async function loadDefaultConnectorModule() {
|
|
|
19814
20043
|
};
|
|
19815
20044
|
}
|
|
19816
20045
|
function resolveWaitPromise(runtime) {
|
|
19817
|
-
if (!runtime || !
|
|
20046
|
+
if (!runtime || !isRecord6(runtime)) {
|
|
19818
20047
|
return void 0;
|
|
19819
20048
|
}
|
|
19820
20049
|
if (typeof runtime.waitUntilStopped === "function") {
|
|
@@ -19838,7 +20067,7 @@ function parseConnectorServicePlatformOption(value) {
|
|
|
19838
20067
|
if (value === "auto" || value === "launchd" || value === "systemd") {
|
|
19839
20068
|
return value;
|
|
19840
20069
|
}
|
|
19841
|
-
throw
|
|
20070
|
+
throw createCliError4(
|
|
19842
20071
|
"CLI_CONNECTOR_SERVICE_PLATFORM_INVALID",
|
|
19843
20072
|
"Connector service platform must be one of: auto, launchd, systemd"
|
|
19844
20073
|
);
|
|
@@ -19853,7 +20082,7 @@ function resolveConnectorServicePlatform(inputPlatform, currentPlatform) {
|
|
|
19853
20082
|
if (currentPlatform === "linux") {
|
|
19854
20083
|
return "systemd";
|
|
19855
20084
|
}
|
|
19856
|
-
throw
|
|
20085
|
+
throw createCliError4(
|
|
19857
20086
|
"CLI_CONNECTOR_SERVICE_PLATFORM_UNSUPPORTED",
|
|
19858
20087
|
"Connector service install is supported only on macOS (launchd) and Linux (systemd)",
|
|
19859
20088
|
{
|
|
@@ -19955,7 +20184,7 @@ function resolveServiceDependencies(dependencies) {
|
|
|
19955
20184
|
resolveCurrentPlatformImpl: dependencies.resolveCurrentPlatformImpl ?? (() => process.platform),
|
|
19956
20185
|
resolveCurrentUidImpl: dependencies.resolveCurrentUidImpl ?? (() => {
|
|
19957
20186
|
if (typeof process.getuid !== "function") {
|
|
19958
|
-
throw
|
|
20187
|
+
throw createCliError4(
|
|
19959
20188
|
"CLI_CONNECTOR_SERVICE_UID_UNAVAILABLE",
|
|
19960
20189
|
"Current user id is unavailable in this runtime"
|
|
19961
20190
|
);
|
|
@@ -20017,7 +20246,7 @@ async function installConnectorServiceForAgent(agentName, commandOptions = {}, d
|
|
|
20017
20246
|
`${serviceName}.service`
|
|
20018
20247
|
]);
|
|
20019
20248
|
} catch (error48) {
|
|
20020
|
-
throw
|
|
20249
|
+
throw createCliError4(
|
|
20021
20250
|
"CLI_CONNECTOR_SERVICE_INSTALL_FAILED",
|
|
20022
20251
|
"Failed to install systemd connector service",
|
|
20023
20252
|
{
|
|
@@ -20064,7 +20293,7 @@ async function installConnectorServiceForAgent(agentName, commandOptions = {}, d
|
|
|
20064
20293
|
serviceFilePath
|
|
20065
20294
|
]);
|
|
20066
20295
|
} catch (error48) {
|
|
20067
|
-
throw
|
|
20296
|
+
throw createCliError4(
|
|
20068
20297
|
"CLI_CONNECTOR_SERVICE_INSTALL_FAILED",
|
|
20069
20298
|
"Failed to install launchd connector service",
|
|
20070
20299
|
{
|
|
@@ -20148,6 +20377,7 @@ async function startConnectorForAgent(agentName, commandOptions = {}, dependenci
|
|
|
20148
20377
|
const resolveConfigImpl = dependencies.resolveConfigImpl ?? resolveConfig;
|
|
20149
20378
|
const getConfigDirImpl = dependencies.getConfigDirImpl ?? getConfigDir;
|
|
20150
20379
|
const readFileImpl = dependencies.readFileImpl ?? ((path, encoding) => readFile3(path, encoding));
|
|
20380
|
+
const fetchImpl = dependencies.fetchImpl ?? globalThis.fetch;
|
|
20151
20381
|
const loadConnectorModule = dependencies.loadConnectorModule ?? loadDefaultConnectorModule;
|
|
20152
20382
|
const configDir = getConfigDirImpl();
|
|
20153
20383
|
const agentDirectory = join5(configDir, AGENTS_DIR_NAME3, agentName);
|
|
@@ -20187,13 +20417,19 @@ async function startConnectorForAgent(agentName, commandOptions = {}, dependenci
|
|
|
20187
20417
|
loadConnectorModule()
|
|
20188
20418
|
]);
|
|
20189
20419
|
if (typeof connectorModule.startConnectorRuntime !== "function") {
|
|
20190
|
-
throw
|
|
20420
|
+
throw createCliError4(
|
|
20191
20421
|
"CLI_CONNECTOR_INVALID_PACKAGE_API",
|
|
20192
20422
|
"Connector package does not expose startConnectorRuntime"
|
|
20193
20423
|
);
|
|
20194
20424
|
}
|
|
20195
20425
|
const identity = parseAgentIdentity(rawIdentity);
|
|
20196
20426
|
const registryAuth = parseRegistryAuth(rawRegistryAuth);
|
|
20427
|
+
const resolvedProxyWebsocketUrl = await resolveProxyWebsocketUrl({
|
|
20428
|
+
explicitProxyWsUrl: commandOptions.proxyWsUrl,
|
|
20429
|
+
configProxyUrl: config2.proxyUrl,
|
|
20430
|
+
registryUrl: config2.registryUrl,
|
|
20431
|
+
fetchImpl
|
|
20432
|
+
});
|
|
20197
20433
|
const openclawHookToken = commandOptions.openclawHookToken ?? relayRuntimeConfig?.openclawHookToken;
|
|
20198
20434
|
const outboundBaseUrl = resolveConnectorBaseUrlFromEnv() ?? assignedConnectorBaseUrl ?? DEFAULT_CONNECTOR_BASE_URL2;
|
|
20199
20435
|
const outboundPath = resolveConnectorOutboundPath();
|
|
@@ -20203,7 +20439,7 @@ async function startConnectorForAgent(agentName, commandOptions = {}, dependenci
|
|
|
20203
20439
|
registryUrl: config2.registryUrl,
|
|
20204
20440
|
outboundBaseUrl,
|
|
20205
20441
|
outboundPath,
|
|
20206
|
-
proxyWebsocketUrl:
|
|
20442
|
+
proxyWebsocketUrl: resolvedProxyWebsocketUrl,
|
|
20207
20443
|
openclawBaseUrl: commandOptions.openclawBaseUrl,
|
|
20208
20444
|
openclawHookPath: commandOptions.openclawHookPath,
|
|
20209
20445
|
openclawHookToken,
|
|
@@ -20218,8 +20454,8 @@ async function startConnectorForAgent(agentName, commandOptions = {}, dependenci
|
|
|
20218
20454
|
tokenType: registryAuth.tokenType
|
|
20219
20455
|
}
|
|
20220
20456
|
});
|
|
20221
|
-
const outboundUrl = runtime &&
|
|
20222
|
-
const proxyWebsocketUrl = runtime &&
|
|
20457
|
+
const outboundUrl = runtime && isRecord6(runtime) && typeof runtime.outboundUrl === "string" ? runtime.outboundUrl : resolveOutboundUrl(outboundBaseUrl, outboundPath);
|
|
20458
|
+
const proxyWebsocketUrl = runtime && isRecord6(runtime) ? typeof runtime.websocketUrl === "string" ? runtime.websocketUrl : typeof runtime.proxyWebsocketUrl === "string" ? runtime.proxyWebsocketUrl : resolvedProxyWebsocketUrl : void 0;
|
|
20223
20459
|
return {
|
|
20224
20460
|
outboundUrl,
|
|
20225
20461
|
proxyWebsocketUrl,
|
|
@@ -20349,107 +20585,52 @@ function createConnectorCommand(dependencies = {}) {
|
|
|
20349
20585
|
|
|
20350
20586
|
// src/commands/invite.ts
|
|
20351
20587
|
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
|
|
20410
20588
|
var logger7 = createLogger({ service: "cli", module: "invite" });
|
|
20411
|
-
var
|
|
20589
|
+
var isRecord7 = (value) => {
|
|
20412
20590
|
return typeof value === "object" && value !== null;
|
|
20413
20591
|
};
|
|
20414
|
-
function
|
|
20592
|
+
function parseNonEmptyString7(value) {
|
|
20415
20593
|
if (typeof value !== "string") {
|
|
20416
20594
|
return "";
|
|
20417
20595
|
}
|
|
20418
20596
|
return value.trim();
|
|
20419
20597
|
}
|
|
20420
|
-
function
|
|
20598
|
+
function createCliError5(code, message2) {
|
|
20421
20599
|
return new AppError({
|
|
20422
20600
|
code,
|
|
20423
20601
|
message: message2,
|
|
20424
20602
|
status: 400
|
|
20425
20603
|
});
|
|
20426
20604
|
}
|
|
20427
|
-
function
|
|
20428
|
-
const candidate = parseNonEmptyString6(input.overrideRegistryUrl) || input.configRegistryUrl;
|
|
20605
|
+
function normalizeProxyUrl(value) {
|
|
20429
20606
|
try {
|
|
20430
|
-
|
|
20607
|
+
const parsed = new URL(value);
|
|
20608
|
+
if (parsed.protocol !== "https:" && parsed.protocol !== "http:") {
|
|
20609
|
+
throw new Error("invalid protocol");
|
|
20610
|
+
}
|
|
20611
|
+
return parsed.toString();
|
|
20431
20612
|
} catch {
|
|
20432
|
-
throw
|
|
20433
|
-
"
|
|
20434
|
-
"
|
|
20613
|
+
throw createCliError5(
|
|
20614
|
+
"CLI_INVITE_REDEEM_INVALID_RESPONSE",
|
|
20615
|
+
"Invite redeem response is invalid"
|
|
20435
20616
|
);
|
|
20436
20617
|
}
|
|
20437
20618
|
}
|
|
20619
|
+
function resolveRegistryUrl2(input) {
|
|
20620
|
+
const candidate = parseNonEmptyString7(input.overrideRegistryUrl) || input.configRegistryUrl;
|
|
20621
|
+
return normalizeRegistryUrl(candidate);
|
|
20622
|
+
}
|
|
20438
20623
|
function requireApiKey2(config2) {
|
|
20439
20624
|
if (typeof config2.apiKey === "string" && config2.apiKey.trim().length > 0) {
|
|
20440
20625
|
return config2.apiKey;
|
|
20441
20626
|
}
|
|
20442
|
-
throw
|
|
20627
|
+
throw createCliError5(
|
|
20443
20628
|
"CLI_INVITE_MISSING_LOCAL_CREDENTIALS",
|
|
20444
20629
|
"API key is not configured. Run `clawdentity config set apiKey <token>` or set CLAWDENTITY_API_KEY."
|
|
20445
20630
|
);
|
|
20446
20631
|
}
|
|
20447
|
-
function toRegistryRequestUrl(registryUrl, path) {
|
|
20448
|
-
const normalizedBaseUrl = registryUrl.endsWith("/") ? registryUrl : `${registryUrl}/`;
|
|
20449
|
-
return new URL(path.slice(1), normalizedBaseUrl).toString();
|
|
20450
|
-
}
|
|
20451
20632
|
function extractRegistryErrorCode(payload) {
|
|
20452
|
-
if (!
|
|
20633
|
+
if (!isRecord7(payload)) {
|
|
20453
20634
|
return void 0;
|
|
20454
20635
|
}
|
|
20455
20636
|
const envelope = payload;
|
|
@@ -20459,8 +20640,8 @@ function extractRegistryErrorCode(payload) {
|
|
|
20459
20640
|
const trimmed = envelope.error.code.trim();
|
|
20460
20641
|
return trimmed.length > 0 ? trimmed : void 0;
|
|
20461
20642
|
}
|
|
20462
|
-
function
|
|
20463
|
-
if (!
|
|
20643
|
+
function extractRegistryErrorMessage4(payload) {
|
|
20644
|
+
if (!isRecord7(payload)) {
|
|
20464
20645
|
return void 0;
|
|
20465
20646
|
}
|
|
20466
20647
|
const envelope = payload;
|
|
@@ -20470,7 +20651,7 @@ function extractRegistryErrorMessage3(payload) {
|
|
|
20470
20651
|
const trimmed = envelope.error.message.trim();
|
|
20471
20652
|
return trimmed.length > 0 ? trimmed : void 0;
|
|
20472
20653
|
}
|
|
20473
|
-
async function
|
|
20654
|
+
async function parseJsonResponse5(response) {
|
|
20474
20655
|
try {
|
|
20475
20656
|
return await response.json();
|
|
20476
20657
|
} catch {
|
|
@@ -20481,7 +20662,7 @@ async function executeInviteRequest(input) {
|
|
|
20481
20662
|
try {
|
|
20482
20663
|
return await input.fetchImpl(input.url, input.init);
|
|
20483
20664
|
} catch {
|
|
20484
|
-
throw
|
|
20665
|
+
throw createCliError5(
|
|
20485
20666
|
"CLI_INVITE_REQUEST_FAILED",
|
|
20486
20667
|
"Unable to connect to the registry. Check network access and registryUrl."
|
|
20487
20668
|
);
|
|
@@ -20489,7 +20670,7 @@ async function executeInviteRequest(input) {
|
|
|
20489
20670
|
}
|
|
20490
20671
|
function mapCreateInviteError(status, payload) {
|
|
20491
20672
|
const errorCode = extractRegistryErrorCode(payload);
|
|
20492
|
-
const registryMessage =
|
|
20673
|
+
const registryMessage = extractRegistryErrorMessage4(payload);
|
|
20493
20674
|
if (status === 401) {
|
|
20494
20675
|
return registryMessage ? `Registry authentication failed (401): ${registryMessage}` : "Registry authentication failed (401). Check your API key.";
|
|
20495
20676
|
}
|
|
@@ -20512,7 +20693,7 @@ function mapCreateInviteError(status, payload) {
|
|
|
20512
20693
|
}
|
|
20513
20694
|
function mapRedeemInviteError(status, payload) {
|
|
20514
20695
|
const errorCode = extractRegistryErrorCode(payload);
|
|
20515
|
-
const registryMessage =
|
|
20696
|
+
const registryMessage = extractRegistryErrorMessage4(payload);
|
|
20516
20697
|
if (errorCode === "INVITE_REDEEM_ALREADY_USED" || errorCode === "INVITE_REDEEM_ALREADY_REDEEMED") {
|
|
20517
20698
|
return "Invite code has already been redeemed";
|
|
20518
20699
|
}
|
|
@@ -20534,16 +20715,16 @@ function mapRedeemInviteError(status, payload) {
|
|
|
20534
20715
|
return `Invite redeem failed (${status})`;
|
|
20535
20716
|
}
|
|
20536
20717
|
function parseInviteRecord(payload) {
|
|
20537
|
-
if (!
|
|
20538
|
-
throw
|
|
20718
|
+
if (!isRecord7(payload)) {
|
|
20719
|
+
throw createCliError5(
|
|
20539
20720
|
"CLI_INVITE_CREATE_INVALID_RESPONSE",
|
|
20540
20721
|
"Invite response is invalid"
|
|
20541
20722
|
);
|
|
20542
20723
|
}
|
|
20543
|
-
const source =
|
|
20544
|
-
const code =
|
|
20724
|
+
const source = isRecord7(payload.invite) ? payload.invite : payload;
|
|
20725
|
+
const code = parseNonEmptyString7(source.code);
|
|
20545
20726
|
if (code.length === 0) {
|
|
20546
|
-
throw
|
|
20727
|
+
throw createCliError5(
|
|
20547
20728
|
"CLI_INVITE_CREATE_INVALID_RESPONSE",
|
|
20548
20729
|
"Invite response is invalid"
|
|
20549
20730
|
);
|
|
@@ -20551,11 +20732,11 @@ function parseInviteRecord(payload) {
|
|
|
20551
20732
|
const invite = {
|
|
20552
20733
|
code
|
|
20553
20734
|
};
|
|
20554
|
-
const id =
|
|
20735
|
+
const id = parseNonEmptyString7(source.id);
|
|
20555
20736
|
if (id.length > 0) {
|
|
20556
20737
|
invite.id = id;
|
|
20557
20738
|
}
|
|
20558
|
-
const createdAt =
|
|
20739
|
+
const createdAt = parseNonEmptyString7(source.createdAt);
|
|
20559
20740
|
if (createdAt.length > 0) {
|
|
20560
20741
|
invite.createdAt = createdAt;
|
|
20561
20742
|
}
|
|
@@ -20565,36 +20746,25 @@ function parseInviteRecord(payload) {
|
|
|
20565
20746
|
return invite;
|
|
20566
20747
|
}
|
|
20567
20748
|
function parseInviteRedeemResponse(payload) {
|
|
20568
|
-
if (!
|
|
20569
|
-
throw
|
|
20749
|
+
if (!isRecord7(payload)) {
|
|
20750
|
+
throw createCliError5(
|
|
20570
20751
|
"CLI_INVITE_REDEEM_INVALID_RESPONSE",
|
|
20571
20752
|
"Invite redeem response is invalid"
|
|
20572
20753
|
);
|
|
20573
20754
|
}
|
|
20574
|
-
const apiKeySource =
|
|
20575
|
-
const apiKeyToken =
|
|
20576
|
-
|
|
20755
|
+
const apiKeySource = isRecord7(payload.apiKey) ? payload.apiKey : payload;
|
|
20756
|
+
const apiKeyToken = parseNonEmptyString7(
|
|
20757
|
+
isRecord7(payload.apiKey) ? payload.apiKey.token : payload.token
|
|
20577
20758
|
);
|
|
20578
20759
|
if (apiKeyToken.length === 0) {
|
|
20579
|
-
throw
|
|
20760
|
+
throw createCliError5(
|
|
20580
20761
|
"CLI_INVITE_REDEEM_INVALID_RESPONSE",
|
|
20581
20762
|
"Invite redeem response is invalid"
|
|
20582
20763
|
);
|
|
20583
20764
|
}
|
|
20584
|
-
const apiKeyId =
|
|
20585
|
-
const apiKeyName =
|
|
20586
|
-
const
|
|
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
|
-
}
|
|
20765
|
+
const apiKeyId = parseNonEmptyString7(apiKeySource.id);
|
|
20766
|
+
const apiKeyName = parseNonEmptyString7(apiKeySource.name);
|
|
20767
|
+
const proxyUrl = parseNonEmptyString7(payload.proxyUrl);
|
|
20598
20768
|
return {
|
|
20599
20769
|
apiKeyToken,
|
|
20600
20770
|
apiKeyId: apiKeyId.length > 0 ? apiKeyId : void 0,
|
|
@@ -20629,13 +20799,13 @@ async function createInvite(options, dependencies = {}) {
|
|
|
20629
20799
|
"content-type": "application/json"
|
|
20630
20800
|
},
|
|
20631
20801
|
body: JSON.stringify({
|
|
20632
|
-
expiresAt:
|
|
20802
|
+
expiresAt: parseNonEmptyString7(options.expiresAt) || void 0
|
|
20633
20803
|
})
|
|
20634
20804
|
}
|
|
20635
20805
|
});
|
|
20636
|
-
const responseBody = await
|
|
20806
|
+
const responseBody = await parseJsonResponse5(response);
|
|
20637
20807
|
if (!response.ok) {
|
|
20638
|
-
throw
|
|
20808
|
+
throw createCliError5(
|
|
20639
20809
|
"CLI_INVITE_CREATE_FAILED",
|
|
20640
20810
|
mapCreateInviteError(response.status, responseBody)
|
|
20641
20811
|
);
|
|
@@ -20646,9 +20816,9 @@ async function createInvite(options, dependencies = {}) {
|
|
|
20646
20816
|
};
|
|
20647
20817
|
}
|
|
20648
20818
|
async function redeemInvite(code, options, dependencies = {}) {
|
|
20649
|
-
const inviteCode =
|
|
20819
|
+
const inviteCode = parseNonEmptyString7(code);
|
|
20650
20820
|
if (inviteCode.length === 0) {
|
|
20651
|
-
throw
|
|
20821
|
+
throw createCliError5(
|
|
20652
20822
|
"CLI_INVITE_REDEEM_CODE_REQUIRED",
|
|
20653
20823
|
"Invite code is required"
|
|
20654
20824
|
);
|
|
@@ -20665,36 +20835,34 @@ async function redeemInvite(code, options, dependencies = {}) {
|
|
|
20665
20835
|
body: JSON.stringify({ code: inviteCode })
|
|
20666
20836
|
}
|
|
20667
20837
|
});
|
|
20668
|
-
const responseBody = await
|
|
20838
|
+
const responseBody = await parseJsonResponse5(response);
|
|
20669
20839
|
if (!response.ok) {
|
|
20670
|
-
throw
|
|
20840
|
+
throw createCliError5(
|
|
20671
20841
|
"CLI_INVITE_REDEEM_FAILED",
|
|
20672
20842
|
mapRedeemInviteError(response.status, responseBody)
|
|
20673
20843
|
);
|
|
20674
20844
|
}
|
|
20845
|
+
const parsedRedeem = parseInviteRedeemResponse(responseBody);
|
|
20846
|
+
const proxyUrl = parsedRedeem.proxyUrl.length > 0 ? parsedRedeem.proxyUrl : (await fetchRegistryMetadata(runtime.registryUrl, {
|
|
20847
|
+
fetchImpl: runtime.fetchImpl
|
|
20848
|
+
})).proxyUrl;
|
|
20675
20849
|
return {
|
|
20676
|
-
...
|
|
20850
|
+
...parsedRedeem,
|
|
20851
|
+
proxyUrl: normalizeProxyUrl(proxyUrl),
|
|
20677
20852
|
registryUrl: runtime.registryUrl
|
|
20678
20853
|
};
|
|
20679
20854
|
}
|
|
20680
|
-
async function persistRedeemConfig(
|
|
20855
|
+
async function persistRedeemConfig(registryUrl, apiKeyToken, proxyUrl, dependencies = {}) {
|
|
20681
20856
|
const setConfigValueImpl = dependencies.setConfigValueImpl ?? setConfigValue;
|
|
20682
20857
|
try {
|
|
20683
|
-
await setConfigValueImpl("registryUrl",
|
|
20684
|
-
await setConfigValueImpl("apiKey",
|
|
20685
|
-
|
|
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);
|
|
20858
|
+
await setConfigValueImpl("registryUrl", registryUrl);
|
|
20859
|
+
await setConfigValueImpl("apiKey", apiKeyToken);
|
|
20860
|
+
await setConfigValueImpl("proxyUrl", proxyUrl);
|
|
20693
20861
|
} catch (error48) {
|
|
20694
20862
|
logger7.warn("cli.invite_redeem_config_persist_failed", {
|
|
20695
20863
|
errorName: error48 instanceof Error ? error48.name : "unknown"
|
|
20696
20864
|
});
|
|
20697
|
-
throw
|
|
20865
|
+
throw createCliError5(
|
|
20698
20866
|
"CLI_INVITE_REDEEM_CONFIG_PERSISTENCE_FAILED",
|
|
20699
20867
|
"Failed to save redeemed API key locally"
|
|
20700
20868
|
);
|
|
@@ -20702,7 +20870,7 @@ async function persistRedeemConfig(input, dependencies = {}) {
|
|
|
20702
20870
|
}
|
|
20703
20871
|
var createInviteCommand = (dependencies = {}) => {
|
|
20704
20872
|
const inviteCommand = new Command6("invite").description(
|
|
20705
|
-
"Manage registry onboarding invites"
|
|
20873
|
+
"Manage registry onboarding invites (not OpenClaw peer relay invites)"
|
|
20706
20874
|
);
|
|
20707
20875
|
inviteCommand.command("create").description("Create a registry invite code (admin only)").option("--expires-at <timestamp>", "Optional invite expiry (ISO-8601)").option("--registry-url <url>", "Override registry URL").action(
|
|
20708
20876
|
withErrorHandling(
|
|
@@ -20740,15 +20908,12 @@ var createInviteCommand = (dependencies = {}) => {
|
|
|
20740
20908
|
writeStdoutLine("API key token (shown once):");
|
|
20741
20909
|
writeStdoutLine(result.apiKeyToken);
|
|
20742
20910
|
await persistRedeemConfig(
|
|
20743
|
-
|
|
20744
|
-
|
|
20745
|
-
|
|
20746
|
-
proxyUrl: result.proxyUrl
|
|
20747
|
-
},
|
|
20911
|
+
result.registryUrl,
|
|
20912
|
+
result.apiKeyToken,
|
|
20913
|
+
result.proxyUrl,
|
|
20748
20914
|
dependencies
|
|
20749
20915
|
);
|
|
20750
20916
|
writeStdoutLine("API key saved to local config");
|
|
20751
|
-
writeStdoutLine("Onboarding auth complete");
|
|
20752
20917
|
}
|
|
20753
20918
|
)
|
|
20754
20919
|
);
|
|
@@ -20770,8 +20935,16 @@ var SECRET_KEY_FILE_NAME2 = "secret.key";
|
|
|
20770
20935
|
var PEERS_FILE_NAME = "peers.json";
|
|
20771
20936
|
var OPENCLAW_DIR_NAME = ".openclaw";
|
|
20772
20937
|
var OPENCLAW_CONFIG_FILE_NAME = "openclaw.json";
|
|
20773
|
-
var LEGACY_OPENCLAW_STATE_DIR_NAMES = [
|
|
20774
|
-
|
|
20938
|
+
var LEGACY_OPENCLAW_STATE_DIR_NAMES = [
|
|
20939
|
+
".clawdbot",
|
|
20940
|
+
".moldbot",
|
|
20941
|
+
".moltbot"
|
|
20942
|
+
];
|
|
20943
|
+
var LEGACY_OPENCLAW_CONFIG_FILE_NAMES = [
|
|
20944
|
+
"clawdbot.json",
|
|
20945
|
+
"moldbot.json",
|
|
20946
|
+
"moltbot.json"
|
|
20947
|
+
];
|
|
20775
20948
|
var OPENCLAW_AGENT_FILE_NAME = "openclaw-agent-name";
|
|
20776
20949
|
var OPENCLAW_RELAY_RUNTIME_FILE_NAME2 = "openclaw-relay.json";
|
|
20777
20950
|
var OPENCLAW_CONNECTORS_FILE_NAME2 = "openclaw-connectors.json";
|
|
@@ -20783,6 +20956,8 @@ var HOOK_MAPPING_ID = "clawdentity-send-to-peer";
|
|
|
20783
20956
|
var HOOK_PATH_SEND_TO_PEER = "send-to-peer";
|
|
20784
20957
|
var OPENCLAW_SEND_TO_PEER_HOOK_PATH = "hooks/send-to-peer";
|
|
20785
20958
|
var DEFAULT_OPENCLAW_BASE_URL2 = "http://127.0.0.1:18789";
|
|
20959
|
+
var DEFAULT_OPENCLAW_MAIN_SESSION_KEY = "main";
|
|
20960
|
+
var DEFAULT_OPENCLAW_AGENT_ID = "main";
|
|
20786
20961
|
var DEFAULT_CONNECTOR_PORT = 19400;
|
|
20787
20962
|
var DEFAULT_CONNECTOR_OUTBOUND_PATH3 = "/v1/outbound";
|
|
20788
20963
|
var CONNECTOR_HOST_LOOPBACK = "127.0.0.1";
|
|
@@ -20798,10 +20973,10 @@ var OPENCLAW_SETUP_WITH_BASE_URL_HINT = `${OPENCLAW_SETUP_COMMAND_HINT} --opencl
|
|
|
20798
20973
|
var OPENCLAW_PAIRING_COMMAND_HINT = "Run QR pairing first: clawdentity pair start <agentName> --qr and clawdentity pair confirm <agentName> --qr-file <path>";
|
|
20799
20974
|
var textEncoder2 = new TextEncoder();
|
|
20800
20975
|
var textDecoder = new TextDecoder();
|
|
20801
|
-
function
|
|
20976
|
+
function isRecord8(value) {
|
|
20802
20977
|
return typeof value === "object" && value !== null;
|
|
20803
20978
|
}
|
|
20804
|
-
function
|
|
20979
|
+
function createCliError6(code, message2, details) {
|
|
20805
20980
|
return new AppError({
|
|
20806
20981
|
code,
|
|
20807
20982
|
message: message2,
|
|
@@ -20810,14 +20985,14 @@ function createCliError5(code, message2, details) {
|
|
|
20810
20985
|
});
|
|
20811
20986
|
}
|
|
20812
20987
|
function getErrorCode2(error48) {
|
|
20813
|
-
if (!
|
|
20988
|
+
if (!isRecord8(error48)) {
|
|
20814
20989
|
return void 0;
|
|
20815
20990
|
}
|
|
20816
20991
|
return typeof error48.code === "string" ? error48.code : void 0;
|
|
20817
20992
|
}
|
|
20818
|
-
function
|
|
20993
|
+
function parseNonEmptyString8(value, label) {
|
|
20819
20994
|
if (typeof value !== "string") {
|
|
20820
|
-
throw
|
|
20995
|
+
throw createCliError6(
|
|
20821
20996
|
"CLI_OPENCLAW_INVALID_INPUT",
|
|
20822
20997
|
"Input must be a string",
|
|
20823
20998
|
{
|
|
@@ -20827,7 +21002,7 @@ function parseNonEmptyString7(value, label) {
|
|
|
20827
21002
|
}
|
|
20828
21003
|
const trimmed = value.trim();
|
|
20829
21004
|
if (trimmed.length === 0) {
|
|
20830
|
-
throw
|
|
21005
|
+
throw createCliError6(
|
|
20831
21006
|
"CLI_OPENCLAW_INVALID_INPUT",
|
|
20832
21007
|
"Input must not be empty",
|
|
20833
21008
|
{ label }
|
|
@@ -20839,18 +21014,18 @@ function parseOptionalName(value) {
|
|
|
20839
21014
|
if (value === void 0) {
|
|
20840
21015
|
return void 0;
|
|
20841
21016
|
}
|
|
20842
|
-
return
|
|
21017
|
+
return parseNonEmptyString8(value, "name");
|
|
20843
21018
|
}
|
|
20844
21019
|
function parsePeerAlias(value) {
|
|
20845
|
-
const alias =
|
|
21020
|
+
const alias = parseNonEmptyString8(value, "peer alias");
|
|
20846
21021
|
if (alias.length > 128) {
|
|
20847
|
-
throw
|
|
21022
|
+
throw createCliError6(
|
|
20848
21023
|
"CLI_OPENCLAW_INVALID_PEER_ALIAS",
|
|
20849
21024
|
"peer alias must be at most 128 characters"
|
|
20850
21025
|
);
|
|
20851
21026
|
}
|
|
20852
21027
|
if (!PEER_ALIAS_PATTERN.test(alias)) {
|
|
20853
|
-
throw
|
|
21028
|
+
throw createCliError6(
|
|
20854
21029
|
"CLI_OPENCLAW_INVALID_PEER_ALIAS",
|
|
20855
21030
|
"peer alias must use only letters, numbers, dot, underscore, or hyphen"
|
|
20856
21031
|
);
|
|
@@ -20865,15 +21040,15 @@ function parseProxyUrl(value) {
|
|
|
20865
21040
|
});
|
|
20866
21041
|
}
|
|
20867
21042
|
function parseHttpUrl(value, input) {
|
|
20868
|
-
const candidate =
|
|
21043
|
+
const candidate = parseNonEmptyString8(value, input.label);
|
|
20869
21044
|
let parsedUrl;
|
|
20870
21045
|
try {
|
|
20871
21046
|
parsedUrl = new URL(candidate);
|
|
20872
21047
|
} catch {
|
|
20873
|
-
throw
|
|
21048
|
+
throw createCliError6(input.code, input.message);
|
|
20874
21049
|
}
|
|
20875
21050
|
if (parsedUrl.protocol !== "http:" && parsedUrl.protocol !== "https:") {
|
|
20876
|
-
throw
|
|
21051
|
+
throw createCliError6(input.code, `${input.label} must use http or https`);
|
|
20877
21052
|
}
|
|
20878
21053
|
if (parsedUrl.pathname === "/" && parsedUrl.search.length === 0 && parsedUrl.hash.length === 0) {
|
|
20879
21054
|
return parsedUrl.origin;
|
|
@@ -20888,17 +21063,17 @@ function parseOpenclawBaseUrl(value) {
|
|
|
20888
21063
|
});
|
|
20889
21064
|
}
|
|
20890
21065
|
function parseAgentDid2(value, label) {
|
|
20891
|
-
const did =
|
|
21066
|
+
const did = parseNonEmptyString8(value, label);
|
|
20892
21067
|
try {
|
|
20893
21068
|
const parsed = parseDid(did);
|
|
20894
21069
|
if (parsed.kind !== "agent") {
|
|
20895
|
-
throw
|
|
21070
|
+
throw createCliError6(
|
|
20896
21071
|
"CLI_OPENCLAW_INVALID_DID",
|
|
20897
21072
|
"DID is not an agent DID"
|
|
20898
21073
|
);
|
|
20899
21074
|
}
|
|
20900
21075
|
} catch {
|
|
20901
|
-
throw
|
|
21076
|
+
throw createCliError6("CLI_OPENCLAW_INVALID_DID", "Agent DID is invalid", {
|
|
20902
21077
|
label
|
|
20903
21078
|
});
|
|
20904
21079
|
}
|
|
@@ -20924,7 +21099,10 @@ function readNonEmptyEnvPath(value, homeDir) {
|
|
|
20924
21099
|
return resolveHomePrefixedPath(value, homeDir);
|
|
20925
21100
|
}
|
|
20926
21101
|
function resolveOpenclawHomeDir(homeDir) {
|
|
20927
|
-
const envOpenclawHome = readNonEmptyEnvPath(
|
|
21102
|
+
const envOpenclawHome = readNonEmptyEnvPath(
|
|
21103
|
+
process.env.OPENCLAW_HOME,
|
|
21104
|
+
homeDir
|
|
21105
|
+
);
|
|
20928
21106
|
return envOpenclawHome ?? homeDir;
|
|
20929
21107
|
}
|
|
20930
21108
|
function resolveDefaultOpenclawStateDir(openclawHomeDir) {
|
|
@@ -20989,13 +21167,7 @@ function resolveOpenclawConfigPath(openclawDir, homeDir) {
|
|
|
20989
21167
|
return configCandidates[0];
|
|
20990
21168
|
}
|
|
20991
21169
|
function resolveDefaultTransformSource(openclawDir) {
|
|
20992
|
-
return join6(
|
|
20993
|
-
openclawDir,
|
|
20994
|
-
"workspace",
|
|
20995
|
-
"skills",
|
|
20996
|
-
SKILL_DIR_NAME,
|
|
20997
|
-
RELAY_MODULE_FILE_NAME
|
|
20998
|
-
);
|
|
21170
|
+
return join6(openclawDir, "skills", SKILL_DIR_NAME, RELAY_MODULE_FILE_NAME);
|
|
20999
21171
|
}
|
|
21000
21172
|
function resolveTransformTargetPath(openclawDir) {
|
|
21001
21173
|
return join6(openclawDir, "hooks", "transforms", RELAY_MODULE_FILE_NAME);
|
|
@@ -21020,7 +21192,7 @@ async function readJsonFile(filePath) {
|
|
|
21020
21192
|
try {
|
|
21021
21193
|
return JSON.parse(raw);
|
|
21022
21194
|
} catch {
|
|
21023
|
-
throw
|
|
21195
|
+
throw createCliError6("CLI_OPENCLAW_INVALID_JSON", "JSON file is invalid", {
|
|
21024
21196
|
filePath
|
|
21025
21197
|
});
|
|
21026
21198
|
}
|
|
@@ -21037,7 +21209,7 @@ async function ensureLocalAgentCredentials(homeDir, agentName) {
|
|
|
21037
21209
|
content = await readFile4(filePath, "utf8");
|
|
21038
21210
|
} catch (error48) {
|
|
21039
21211
|
if (getErrorCode2(error48) === "ENOENT") {
|
|
21040
|
-
throw
|
|
21212
|
+
throw createCliError6(
|
|
21041
21213
|
"CLI_OPENCLAW_MISSING_AGENT_CREDENTIALS",
|
|
21042
21214
|
"Local agent credentials are missing",
|
|
21043
21215
|
{ agentName, filePath }
|
|
@@ -21046,7 +21218,7 @@ async function ensureLocalAgentCredentials(homeDir, agentName) {
|
|
|
21046
21218
|
throw error48;
|
|
21047
21219
|
}
|
|
21048
21220
|
if (content.trim().length === 0) {
|
|
21049
|
-
throw
|
|
21221
|
+
throw createCliError6(
|
|
21050
21222
|
"CLI_OPENCLAW_EMPTY_AGENT_CREDENTIALS",
|
|
21051
21223
|
"Agent credential file is empty",
|
|
21052
21224
|
{ filePath }
|
|
@@ -21069,8 +21241,8 @@ async function loadPeersConfig(peersPath) {
|
|
|
21069
21241
|
}
|
|
21070
21242
|
throw error48;
|
|
21071
21243
|
}
|
|
21072
|
-
if (!
|
|
21073
|
-
throw
|
|
21244
|
+
if (!isRecord8(parsed)) {
|
|
21245
|
+
throw createCliError6(
|
|
21074
21246
|
"CLI_OPENCLAW_INVALID_PEERS_CONFIG",
|
|
21075
21247
|
"Peer config root must be a JSON object",
|
|
21076
21248
|
{ peersPath }
|
|
@@ -21080,8 +21252,8 @@ async function loadPeersConfig(peersPath) {
|
|
|
21080
21252
|
if (peersValue === void 0) {
|
|
21081
21253
|
return { peers: {} };
|
|
21082
21254
|
}
|
|
21083
|
-
if (!
|
|
21084
|
-
throw
|
|
21255
|
+
if (!isRecord8(peersValue)) {
|
|
21256
|
+
throw createCliError6(
|
|
21085
21257
|
"CLI_OPENCLAW_INVALID_PEERS_CONFIG",
|
|
21086
21258
|
"Peer config peers field must be an object",
|
|
21087
21259
|
{ peersPath }
|
|
@@ -21090,8 +21262,8 @@ async function loadPeersConfig(peersPath) {
|
|
|
21090
21262
|
const peers = {};
|
|
21091
21263
|
for (const [alias, value] of Object.entries(peersValue)) {
|
|
21092
21264
|
const normalizedAlias = parsePeerAlias(alias);
|
|
21093
|
-
if (!
|
|
21094
|
-
throw
|
|
21265
|
+
if (!isRecord8(value)) {
|
|
21266
|
+
throw createCliError6(
|
|
21095
21267
|
"CLI_OPENCLAW_INVALID_PEERS_CONFIG",
|
|
21096
21268
|
"Peer entry must be an object",
|
|
21097
21269
|
{ alias: normalizedAlias }
|
|
@@ -21120,21 +21292,21 @@ function parseConnectorBaseUrlForAssignment(value, label) {
|
|
|
21120
21292
|
});
|
|
21121
21293
|
}
|
|
21122
21294
|
function parseConnectorAssignments(value, connectorAssignmentsPath) {
|
|
21123
|
-
if (!
|
|
21124
|
-
throw
|
|
21295
|
+
if (!isRecord8(value)) {
|
|
21296
|
+
throw createCliError6(
|
|
21125
21297
|
"CLI_OPENCLAW_INVALID_CONNECTOR_ASSIGNMENTS",
|
|
21126
21298
|
"Connector assignments config must be an object",
|
|
21127
21299
|
{ connectorAssignmentsPath }
|
|
21128
21300
|
);
|
|
21129
21301
|
}
|
|
21130
21302
|
const agentsRaw = value.agents;
|
|
21131
|
-
if (!
|
|
21303
|
+
if (!isRecord8(agentsRaw)) {
|
|
21132
21304
|
return { agents: {} };
|
|
21133
21305
|
}
|
|
21134
21306
|
const agents = {};
|
|
21135
21307
|
for (const [agentName, entryValue] of Object.entries(agentsRaw)) {
|
|
21136
|
-
if (!
|
|
21137
|
-
throw
|
|
21308
|
+
if (!isRecord8(entryValue)) {
|
|
21309
|
+
throw createCliError6(
|
|
21138
21310
|
"CLI_OPENCLAW_INVALID_CONNECTOR_ASSIGNMENTS",
|
|
21139
21311
|
"Connector assignment entry must be an object",
|
|
21140
21312
|
{ connectorAssignmentsPath, agentName }
|
|
@@ -21205,8 +21377,8 @@ function buildRelayConnectorBaseUrls(port) {
|
|
|
21205
21377
|
];
|
|
21206
21378
|
}
|
|
21207
21379
|
function parseRelayRuntimeConfig(value, relayRuntimeConfigPath) {
|
|
21208
|
-
if (!
|
|
21209
|
-
throw
|
|
21380
|
+
if (!isRecord8(value)) {
|
|
21381
|
+
throw createCliError6(
|
|
21210
21382
|
"CLI_OPENCLAW_INVALID_RELAY_RUNTIME_CONFIG",
|
|
21211
21383
|
"Relay runtime config must be an object",
|
|
21212
21384
|
{ relayRuntimeConfigPath }
|
|
@@ -21260,7 +21432,7 @@ async function resolveOpenclawBaseUrl2(input) {
|
|
|
21260
21432
|
}
|
|
21261
21433
|
return DEFAULT_OPENCLAW_BASE_URL2;
|
|
21262
21434
|
}
|
|
21263
|
-
function
|
|
21435
|
+
function normalizeStringArrayWithValues(value, requiredValues) {
|
|
21264
21436
|
const normalized = /* @__PURE__ */ new Set();
|
|
21265
21437
|
if (Array.isArray(value)) {
|
|
21266
21438
|
for (const item of value) {
|
|
@@ -21273,27 +21445,61 @@ function normalizeStringArrayWithValue(value, requiredValue) {
|
|
|
21273
21445
|
}
|
|
21274
21446
|
}
|
|
21275
21447
|
}
|
|
21276
|
-
|
|
21448
|
+
for (const requiredValue of requiredValues) {
|
|
21449
|
+
const trimmed = requiredValue.trim();
|
|
21450
|
+
if (trimmed.length > 0) {
|
|
21451
|
+
normalized.add(trimmed);
|
|
21452
|
+
}
|
|
21453
|
+
}
|
|
21277
21454
|
return Array.from(normalized);
|
|
21278
21455
|
}
|
|
21456
|
+
function resolveHookDefaultSessionKey(config2, hooks) {
|
|
21457
|
+
if (typeof hooks.defaultSessionKey === "string" && hooks.defaultSessionKey.trim().length > 0) {
|
|
21458
|
+
return hooks.defaultSessionKey.trim();
|
|
21459
|
+
}
|
|
21460
|
+
const session = isRecord8(config2.session) ? config2.session : {};
|
|
21461
|
+
const scope = typeof session.scope === "string" ? session.scope.trim().toLowerCase() : "";
|
|
21462
|
+
if (scope === "global") {
|
|
21463
|
+
return "global";
|
|
21464
|
+
}
|
|
21465
|
+
const agents = isRecord8(config2.agents) ? config2.agents : {};
|
|
21466
|
+
const agentList = Array.isArray(agents.list) ? agents.list : [];
|
|
21467
|
+
const defaultAgentId = resolveDefaultOpenclawAgentId(agentList);
|
|
21468
|
+
return `agent:${defaultAgentId}:${DEFAULT_OPENCLAW_MAIN_SESSION_KEY}`;
|
|
21469
|
+
}
|
|
21470
|
+
function resolveDefaultOpenclawAgentId(agentList) {
|
|
21471
|
+
const preferred = agentList.find(
|
|
21472
|
+
(agent) => isRecord8(agent) && agent.default === true && typeof agent.id === "string" && agent.id.trim().length > 0
|
|
21473
|
+
) ?? agentList.find(
|
|
21474
|
+
(agent) => isRecord8(agent) && typeof agent.id === "string" && agent.id.trim().length > 0
|
|
21475
|
+
);
|
|
21476
|
+
if (isRecord8(preferred) && typeof preferred.id === "string" && preferred.id.trim().length > 0) {
|
|
21477
|
+
return normalizeOpenclawIdToken(preferred.id, DEFAULT_OPENCLAW_AGENT_ID);
|
|
21478
|
+
}
|
|
21479
|
+
return DEFAULT_OPENCLAW_AGENT_ID;
|
|
21480
|
+
}
|
|
21481
|
+
function normalizeOpenclawIdToken(value, fallback) {
|
|
21482
|
+
const normalized = value.trim().toLowerCase().replace(/[^a-z0-9_-]+/g, "-").replace(/^-+/g, "").replace(/-+$/g, "").slice(0, 64);
|
|
21483
|
+
return normalized.length > 0 ? normalized : fallback;
|
|
21484
|
+
}
|
|
21279
21485
|
function generateOpenclawHookToken() {
|
|
21280
21486
|
return randomBytes3(OPENCLAW_HOOK_TOKEN_BYTES).toString("hex");
|
|
21281
21487
|
}
|
|
21282
21488
|
function upsertRelayHookMapping(mappingsValue) {
|
|
21283
|
-
const mappings = Array.isArray(mappingsValue) ? mappingsValue.filter(
|
|
21489
|
+
const mappings = Array.isArray(mappingsValue) ? mappingsValue.filter(isRecord8).map((mapping) => ({ ...mapping })) : [];
|
|
21284
21490
|
const existingIndex = mappings.findIndex((mapping) => {
|
|
21285
21491
|
if (mapping.id === HOOK_MAPPING_ID) {
|
|
21286
21492
|
return true;
|
|
21287
21493
|
}
|
|
21288
|
-
if (!
|
|
21494
|
+
if (!isRecord8(mapping.match)) {
|
|
21289
21495
|
return false;
|
|
21290
21496
|
}
|
|
21291
21497
|
return mapping.match.path === HOOK_PATH_SEND_TO_PEER;
|
|
21292
21498
|
});
|
|
21293
|
-
const baseMapping = existingIndex >= 0 &&
|
|
21294
|
-
const nextMatch =
|
|
21499
|
+
const baseMapping = existingIndex >= 0 && isRecord8(mappings[existingIndex]) ? mappings[existingIndex] : {};
|
|
21500
|
+
const nextMatch = isRecord8(baseMapping.match) ? { ...baseMapping.match } : {};
|
|
21295
21501
|
nextMatch.path = HOOK_PATH_SEND_TO_PEER;
|
|
21296
|
-
const nextTransform =
|
|
21502
|
+
const nextTransform = isRecord8(baseMapping.transform) ? { ...baseMapping.transform } : {};
|
|
21297
21503
|
nextTransform.module = RELAY_MODULE_FILE_NAME;
|
|
21298
21504
|
const relayMapping = {
|
|
21299
21505
|
...baseMapping,
|
|
@@ -21316,7 +21522,7 @@ async function patchOpenclawConfig(openclawConfigPath, hookToken) {
|
|
|
21316
21522
|
config2 = await readJsonFile(openclawConfigPath);
|
|
21317
21523
|
} catch (error48) {
|
|
21318
21524
|
if (getErrorCode2(error48) === "ENOENT") {
|
|
21319
|
-
throw
|
|
21525
|
+
throw createCliError6(
|
|
21320
21526
|
"CLI_OPENCLAW_CONFIG_NOT_FOUND",
|
|
21321
21527
|
"OpenClaw config file was not found",
|
|
21322
21528
|
{ openclawConfigPath }
|
|
@@ -21324,23 +21530,25 @@ async function patchOpenclawConfig(openclawConfigPath, hookToken) {
|
|
|
21324
21530
|
}
|
|
21325
21531
|
throw error48;
|
|
21326
21532
|
}
|
|
21327
|
-
if (!
|
|
21328
|
-
throw
|
|
21533
|
+
if (!isRecord8(config2)) {
|
|
21534
|
+
throw createCliError6(
|
|
21329
21535
|
"CLI_OPENCLAW_INVALID_CONFIG",
|
|
21330
21536
|
"OpenClaw config root must be an object",
|
|
21331
21537
|
{ openclawConfigPath }
|
|
21332
21538
|
);
|
|
21333
21539
|
}
|
|
21334
|
-
const hooks =
|
|
21540
|
+
const hooks = isRecord8(config2.hooks) ? { ...config2.hooks } : {};
|
|
21335
21541
|
const existingHookToken = typeof hooks.token === "string" && hooks.token.trim().length > 0 ? hooks.token.trim() : void 0;
|
|
21336
21542
|
const preferredHookToken = typeof hookToken === "string" && hookToken.trim().length > 0 ? hookToken.trim() : void 0;
|
|
21337
21543
|
const resolvedHookToken = existingHookToken ?? preferredHookToken ?? generateOpenclawHookToken();
|
|
21544
|
+
const defaultSessionKey = resolveHookDefaultSessionKey(config2, hooks);
|
|
21338
21545
|
hooks.enabled = true;
|
|
21339
21546
|
hooks.token = resolvedHookToken;
|
|
21547
|
+
hooks.defaultSessionKey = defaultSessionKey;
|
|
21340
21548
|
hooks.allowRequestSessionKey = false;
|
|
21341
|
-
hooks.allowedSessionKeyPrefixes =
|
|
21549
|
+
hooks.allowedSessionKeyPrefixes = normalizeStringArrayWithValues(
|
|
21342
21550
|
hooks.allowedSessionKeyPrefixes,
|
|
21343
|
-
"hook:"
|
|
21551
|
+
["hook:", defaultSessionKey]
|
|
21344
21552
|
);
|
|
21345
21553
|
hooks.mappings = upsertRelayHookMapping(hooks.mappings);
|
|
21346
21554
|
const nextConfig = {
|
|
@@ -21368,10 +21576,10 @@ function toDoctorResult(checks) {
|
|
|
21368
21576
|
};
|
|
21369
21577
|
}
|
|
21370
21578
|
function isRelayHookMapping(value) {
|
|
21371
|
-
if (!
|
|
21579
|
+
if (!isRecord8(value)) {
|
|
21372
21580
|
return false;
|
|
21373
21581
|
}
|
|
21374
|
-
if (!
|
|
21582
|
+
if (!isRecord8(value.match) || value.match.path !== HOOK_PATH_SEND_TO_PEER) {
|
|
21375
21583
|
return false;
|
|
21376
21584
|
}
|
|
21377
21585
|
if (typeof value.id === "string" && value.id !== HOOK_MAPPING_ID) {
|
|
@@ -21380,7 +21588,7 @@ function isRelayHookMapping(value) {
|
|
|
21380
21588
|
return true;
|
|
21381
21589
|
}
|
|
21382
21590
|
function hasRelayTransformModule(value) {
|
|
21383
|
-
if (!
|
|
21591
|
+
if (!isRecord8(value) || !isRecord8(value.transform)) {
|
|
21384
21592
|
return false;
|
|
21385
21593
|
}
|
|
21386
21594
|
return value.transform.module === RELAY_MODULE_FILE_NAME;
|
|
@@ -21459,6 +21667,7 @@ async function runOpenclawDoctor(options = {}) {
|
|
|
21459
21667
|
const resolveConfigImpl = options.resolveConfigImpl ?? resolveConfig;
|
|
21460
21668
|
try {
|
|
21461
21669
|
const resolvedConfig = await resolveConfigImpl();
|
|
21670
|
+
const envProxyUrl = typeof process.env.CLAWDENTITY_PROXY_URL === "string" ? process.env.CLAWDENTITY_PROXY_URL.trim() : "";
|
|
21462
21671
|
if (typeof resolvedConfig.registryUrl !== "string" || resolvedConfig.registryUrl.trim().length === 0) {
|
|
21463
21672
|
checks.push(
|
|
21464
21673
|
toDoctorCheck({
|
|
@@ -21479,15 +21688,68 @@ async function runOpenclawDoctor(options = {}) {
|
|
|
21479
21688
|
remediationHint: "Run: clawdentity config set apiKey <API_KEY>"
|
|
21480
21689
|
})
|
|
21481
21690
|
);
|
|
21482
|
-
} else {
|
|
21691
|
+
} else if (envProxyUrl.length > 0) {
|
|
21692
|
+
let hasValidEnvProxyUrl = true;
|
|
21693
|
+
try {
|
|
21694
|
+
parseProxyUrl(envProxyUrl);
|
|
21695
|
+
} catch {
|
|
21696
|
+
hasValidEnvProxyUrl = false;
|
|
21697
|
+
checks.push(
|
|
21698
|
+
toDoctorCheck({
|
|
21699
|
+
id: "config.registry",
|
|
21700
|
+
label: "CLI config",
|
|
21701
|
+
status: "fail",
|
|
21702
|
+
message: "CLAWDENTITY_PROXY_URL is invalid",
|
|
21703
|
+
remediationHint: "Set CLAWDENTITY_PROXY_URL to a valid http(s) URL or unset it"
|
|
21704
|
+
})
|
|
21705
|
+
);
|
|
21706
|
+
}
|
|
21707
|
+
if (hasValidEnvProxyUrl) {
|
|
21708
|
+
checks.push(
|
|
21709
|
+
toDoctorCheck({
|
|
21710
|
+
id: "config.registry",
|
|
21711
|
+
label: "CLI config",
|
|
21712
|
+
status: "pass",
|
|
21713
|
+
message: "registryUrl and apiKey are configured (proxy URL override is active via CLAWDENTITY_PROXY_URL)"
|
|
21714
|
+
})
|
|
21715
|
+
);
|
|
21716
|
+
}
|
|
21717
|
+
} else if (typeof resolvedConfig.proxyUrl !== "string" || resolvedConfig.proxyUrl.trim().length === 0) {
|
|
21483
21718
|
checks.push(
|
|
21484
21719
|
toDoctorCheck({
|
|
21485
21720
|
id: "config.registry",
|
|
21486
21721
|
label: "CLI config",
|
|
21487
|
-
status: "
|
|
21488
|
-
message: "
|
|
21722
|
+
status: "fail",
|
|
21723
|
+
message: "proxyUrl is missing",
|
|
21724
|
+
remediationHint: "Run: clawdentity invite redeem <clw_inv_...> or clawdentity config init"
|
|
21489
21725
|
})
|
|
21490
21726
|
);
|
|
21727
|
+
} else {
|
|
21728
|
+
let hasValidConfigProxyUrl = true;
|
|
21729
|
+
try {
|
|
21730
|
+
parseProxyUrl(resolvedConfig.proxyUrl);
|
|
21731
|
+
} catch {
|
|
21732
|
+
hasValidConfigProxyUrl = false;
|
|
21733
|
+
checks.push(
|
|
21734
|
+
toDoctorCheck({
|
|
21735
|
+
id: "config.registry",
|
|
21736
|
+
label: "CLI config",
|
|
21737
|
+
status: "fail",
|
|
21738
|
+
message: "proxyUrl is invalid",
|
|
21739
|
+
remediationHint: "Run: clawdentity invite redeem <clw_inv_...> or clawdentity config init"
|
|
21740
|
+
})
|
|
21741
|
+
);
|
|
21742
|
+
}
|
|
21743
|
+
if (hasValidConfigProxyUrl) {
|
|
21744
|
+
checks.push(
|
|
21745
|
+
toDoctorCheck({
|
|
21746
|
+
id: "config.registry",
|
|
21747
|
+
label: "CLI config",
|
|
21748
|
+
status: "pass",
|
|
21749
|
+
message: "registryUrl, apiKey, and proxyUrl are configured"
|
|
21750
|
+
})
|
|
21751
|
+
);
|
|
21752
|
+
}
|
|
21491
21753
|
}
|
|
21492
21754
|
} catch {
|
|
21493
21755
|
checks.push(
|
|
@@ -21639,7 +21901,7 @@ async function runOpenclawDoctor(options = {}) {
|
|
|
21639
21901
|
label: "Relay transform",
|
|
21640
21902
|
status: "fail",
|
|
21641
21903
|
message: "relay transform artifacts are missing or empty",
|
|
21642
|
-
remediationHint: "Run:
|
|
21904
|
+
remediationHint: "Run: clawdentity skill install",
|
|
21643
21905
|
details: {
|
|
21644
21906
|
transformTargetPath,
|
|
21645
21907
|
relayTransformRuntimePath,
|
|
@@ -21669,7 +21931,7 @@ async function runOpenclawDoctor(options = {}) {
|
|
|
21669
21931
|
label: "Relay transform",
|
|
21670
21932
|
status: "fail",
|
|
21671
21933
|
message: "missing relay transform artifacts",
|
|
21672
|
-
remediationHint: "Run:
|
|
21934
|
+
remediationHint: "Run: clawdentity skill install",
|
|
21673
21935
|
details: {
|
|
21674
21936
|
transformTargetPath,
|
|
21675
21937
|
relayTransformRuntimePath,
|
|
@@ -21681,13 +21943,13 @@ async function runOpenclawDoctor(options = {}) {
|
|
|
21681
21943
|
const openclawConfigPath = resolveOpenclawConfigPath(openclawDir, homeDir);
|
|
21682
21944
|
try {
|
|
21683
21945
|
const openclawConfig = await readJsonFile(openclawConfigPath);
|
|
21684
|
-
if (!
|
|
21946
|
+
if (!isRecord8(openclawConfig)) {
|
|
21685
21947
|
throw new Error("root");
|
|
21686
21948
|
}
|
|
21687
|
-
const hooks =
|
|
21949
|
+
const hooks = isRecord8(openclawConfig.hooks) ? openclawConfig.hooks : {};
|
|
21688
21950
|
const hooksEnabled = hooks.enabled === true;
|
|
21689
21951
|
const hookToken = typeof hooks.token === "string" && hooks.token.trim().length > 0 ? hooks.token.trim() : void 0;
|
|
21690
|
-
const mappings = Array.isArray(hooks.mappings) ? hooks.mappings.filter(
|
|
21952
|
+
const mappings = Array.isArray(hooks.mappings) ? hooks.mappings.filter(isRecord8) : [];
|
|
21691
21953
|
const relayMapping = mappings.find(
|
|
21692
21954
|
(mapping) => isRelayHookMapping(mapping)
|
|
21693
21955
|
);
|
|
@@ -21835,13 +22097,13 @@ async function resolveRelayProbePeerAlias(input) {
|
|
|
21835
22097
|
return peerAliases[0];
|
|
21836
22098
|
}
|
|
21837
22099
|
if (peerAliases.length === 0) {
|
|
21838
|
-
throw
|
|
22100
|
+
throw createCliError6(
|
|
21839
22101
|
"CLI_OPENCLAW_RELAY_TEST_PEER_REQUIRED",
|
|
21840
22102
|
"No paired peer is configured yet. Complete QR pairing first.",
|
|
21841
22103
|
{ peersPath }
|
|
21842
22104
|
);
|
|
21843
22105
|
}
|
|
21844
|
-
throw
|
|
22106
|
+
throw createCliError6(
|
|
21845
22107
|
"CLI_OPENCLAW_RELAY_TEST_PEER_REQUIRED",
|
|
21846
22108
|
"Multiple peers are configured. Pass --peer <alias> to choose one.",
|
|
21847
22109
|
{ peersPath, peerAliases }
|
|
@@ -21998,7 +22260,7 @@ async function setupOpenclawRelay(agentName, options) {
|
|
|
21998
22260
|
await copyFile(transformSource, transformTargetPath);
|
|
21999
22261
|
} catch (error48) {
|
|
22000
22262
|
if (getErrorCode2(error48) === "ENOENT") {
|
|
22001
|
-
throw
|
|
22263
|
+
throw createCliError6(
|
|
22002
22264
|
"CLI_OPENCLAW_TRANSFORM_NOT_FOUND",
|
|
22003
22265
|
"Relay transform source file was not found",
|
|
22004
22266
|
{ transformSource }
|
|
@@ -22093,7 +22355,7 @@ var createOpenclawCommand = () => {
|
|
|
22093
22355
|
"OpenClaw state directory (default ~/.openclaw)"
|
|
22094
22356
|
).option(
|
|
22095
22357
|
"--transform-source <path>",
|
|
22096
|
-
"Path to relay-to-peer.mjs (default <openclaw-dir>/
|
|
22358
|
+
"Path to relay-to-peer.mjs (default <openclaw-dir>/skills/clawdentity-openclaw-relay/relay-to-peer.mjs)"
|
|
22097
22359
|
).option(
|
|
22098
22360
|
"--openclaw-base-url <url>",
|
|
22099
22361
|
"Base URL for local OpenClaw hook API (default http://127.0.0.1:18789)"
|
|
@@ -22216,26 +22478,26 @@ var PAIRING_QR_MAX_AGE_SECONDS = 900;
|
|
|
22216
22478
|
var PAIRING_QR_FILENAME_PATTERN = /-pair-(\d+)\.png$/;
|
|
22217
22479
|
var FILE_MODE4 = 384;
|
|
22218
22480
|
var PEER_ALIAS_PATTERN2 = /^[a-zA-Z0-9._-]+$/;
|
|
22219
|
-
var
|
|
22481
|
+
var isRecord9 = (value) => {
|
|
22220
22482
|
return typeof value === "object" && value !== null;
|
|
22221
22483
|
};
|
|
22222
|
-
function
|
|
22484
|
+
function createCliError7(code, message2) {
|
|
22223
22485
|
return new AppError({
|
|
22224
22486
|
code,
|
|
22225
22487
|
message: message2,
|
|
22226
22488
|
status: 400
|
|
22227
22489
|
});
|
|
22228
22490
|
}
|
|
22229
|
-
function
|
|
22491
|
+
function parseNonEmptyString9(value) {
|
|
22230
22492
|
if (typeof value !== "string") {
|
|
22231
22493
|
return "";
|
|
22232
22494
|
}
|
|
22233
22495
|
return value.trim();
|
|
22234
22496
|
}
|
|
22235
22497
|
function parsePairingTicket(value) {
|
|
22236
|
-
const ticket =
|
|
22498
|
+
const ticket = parseNonEmptyString9(value);
|
|
22237
22499
|
if (!ticket.startsWith(PAIRING_TICKET_PREFIX)) {
|
|
22238
|
-
throw
|
|
22500
|
+
throw createCliError7(
|
|
22239
22501
|
"CLI_PAIR_CONFIRM_TICKET_INVALID",
|
|
22240
22502
|
"Pairing ticket is invalid"
|
|
22241
22503
|
);
|
|
@@ -22245,7 +22507,7 @@ function parsePairingTicket(value) {
|
|
|
22245
22507
|
function parsePairingTicketIssuerOrigin(ticket) {
|
|
22246
22508
|
const encodedPayload = ticket.slice(PAIRING_TICKET_PREFIX.length);
|
|
22247
22509
|
if (encodedPayload.length === 0) {
|
|
22248
|
-
throw
|
|
22510
|
+
throw createCliError7(
|
|
22249
22511
|
"CLI_PAIR_CONFIRM_TICKET_INVALID",
|
|
22250
22512
|
"Pairing ticket is invalid"
|
|
22251
22513
|
);
|
|
@@ -22254,7 +22516,7 @@ function parsePairingTicketIssuerOrigin(ticket) {
|
|
|
22254
22516
|
try {
|
|
22255
22517
|
payloadRaw = new TextDecoder().decode(decodeBase64url(encodedPayload));
|
|
22256
22518
|
} catch {
|
|
22257
|
-
throw
|
|
22519
|
+
throw createCliError7(
|
|
22258
22520
|
"CLI_PAIR_CONFIRM_TICKET_INVALID",
|
|
22259
22521
|
"Pairing ticket is invalid"
|
|
22260
22522
|
);
|
|
@@ -22263,13 +22525,13 @@ function parsePairingTicketIssuerOrigin(ticket) {
|
|
|
22263
22525
|
try {
|
|
22264
22526
|
payload = JSON.parse(payloadRaw);
|
|
22265
22527
|
} catch {
|
|
22266
|
-
throw
|
|
22528
|
+
throw createCliError7(
|
|
22267
22529
|
"CLI_PAIR_CONFIRM_TICKET_INVALID",
|
|
22268
22530
|
"Pairing ticket is invalid"
|
|
22269
22531
|
);
|
|
22270
22532
|
}
|
|
22271
|
-
if (!
|
|
22272
|
-
throw
|
|
22533
|
+
if (!isRecord9(payload) || typeof payload.iss !== "string") {
|
|
22534
|
+
throw createCliError7(
|
|
22273
22535
|
"CLI_PAIR_CONFIRM_TICKET_INVALID",
|
|
22274
22536
|
"Pairing ticket is invalid"
|
|
22275
22537
|
);
|
|
@@ -22278,13 +22540,13 @@ function parsePairingTicketIssuerOrigin(ticket) {
|
|
|
22278
22540
|
try {
|
|
22279
22541
|
issuerUrl = new URL(payload.iss);
|
|
22280
22542
|
} catch {
|
|
22281
|
-
throw
|
|
22543
|
+
throw createCliError7(
|
|
22282
22544
|
"CLI_PAIR_CONFIRM_TICKET_INVALID",
|
|
22283
22545
|
"Pairing ticket is invalid"
|
|
22284
22546
|
);
|
|
22285
22547
|
}
|
|
22286
22548
|
if (issuerUrl.protocol !== "https:" && issuerUrl.protocol !== "http:") {
|
|
22287
|
-
throw
|
|
22549
|
+
throw createCliError7(
|
|
22288
22550
|
"CLI_PAIR_CONFIRM_TICKET_INVALID",
|
|
22289
22551
|
"Pairing ticket is invalid"
|
|
22290
22552
|
);
|
|
@@ -22293,13 +22555,13 @@ function parsePairingTicketIssuerOrigin(ticket) {
|
|
|
22293
22555
|
}
|
|
22294
22556
|
function parsePeerAlias2(value) {
|
|
22295
22557
|
if (value.length === 0 || value.length > 128) {
|
|
22296
|
-
throw
|
|
22558
|
+
throw createCliError7(
|
|
22297
22559
|
"CLI_PAIR_PEER_ALIAS_INVALID",
|
|
22298
22560
|
"Generated peer alias is invalid"
|
|
22299
22561
|
);
|
|
22300
22562
|
}
|
|
22301
22563
|
if (!PEER_ALIAS_PATTERN2.test(value)) {
|
|
22302
|
-
throw
|
|
22564
|
+
throw createCliError7(
|
|
22303
22565
|
"CLI_PAIR_PEER_ALIAS_INVALID",
|
|
22304
22566
|
"Generated peer alias is invalid"
|
|
22305
22567
|
);
|
|
@@ -22336,16 +22598,16 @@ function resolvePeersConfigPath(getConfigDirImpl) {
|
|
|
22336
22598
|
return join7(getConfigDirImpl(), PEERS_FILE_NAME2);
|
|
22337
22599
|
}
|
|
22338
22600
|
function parsePeerEntry(value) {
|
|
22339
|
-
if (!
|
|
22340
|
-
throw
|
|
22601
|
+
if (!isRecord9(value)) {
|
|
22602
|
+
throw createCliError7(
|
|
22341
22603
|
"CLI_PAIR_PEERS_CONFIG_INVALID",
|
|
22342
22604
|
"Peer entry must be an object"
|
|
22343
22605
|
);
|
|
22344
22606
|
}
|
|
22345
|
-
const did =
|
|
22346
|
-
const proxyUrl =
|
|
22607
|
+
const did = parseNonEmptyString9(value.did);
|
|
22608
|
+
const proxyUrl = parseNonEmptyString9(value.proxyUrl);
|
|
22347
22609
|
if (did.length === 0 || proxyUrl.length === 0) {
|
|
22348
|
-
throw
|
|
22610
|
+
throw createCliError7(
|
|
22349
22611
|
"CLI_PAIR_PEERS_CONFIG_INVALID",
|
|
22350
22612
|
"Peer entry is invalid"
|
|
22351
22613
|
);
|
|
@@ -22371,13 +22633,13 @@ async function loadPeersConfig2(input) {
|
|
|
22371
22633
|
try {
|
|
22372
22634
|
parsed = JSON.parse(raw);
|
|
22373
22635
|
} catch {
|
|
22374
|
-
throw
|
|
22636
|
+
throw createCliError7(
|
|
22375
22637
|
"CLI_PAIR_PEERS_CONFIG_INVALID",
|
|
22376
22638
|
"Peer config is not valid JSON"
|
|
22377
22639
|
);
|
|
22378
22640
|
}
|
|
22379
|
-
if (!
|
|
22380
|
-
throw
|
|
22641
|
+
if (!isRecord9(parsed)) {
|
|
22642
|
+
throw createCliError7(
|
|
22381
22643
|
"CLI_PAIR_PEERS_CONFIG_INVALID",
|
|
22382
22644
|
"Peer config must be a JSON object"
|
|
22383
22645
|
);
|
|
@@ -22385,8 +22647,8 @@ async function loadPeersConfig2(input) {
|
|
|
22385
22647
|
if (parsed.peers === void 0) {
|
|
22386
22648
|
return { peers: {} };
|
|
22387
22649
|
}
|
|
22388
|
-
if (!
|
|
22389
|
-
throw
|
|
22650
|
+
if (!isRecord9(parsed.peers)) {
|
|
22651
|
+
throw createCliError7(
|
|
22390
22652
|
"CLI_PAIR_PEERS_CONFIG_INVALID",
|
|
22391
22653
|
"Peer config peers field must be an object"
|
|
22392
22654
|
);
|
|
@@ -22409,13 +22671,13 @@ async function savePeersConfig2(input) {
|
|
|
22409
22671
|
await input.chmodImpl(peersPath, FILE_MODE4);
|
|
22410
22672
|
}
|
|
22411
22673
|
function parseTtlSeconds(value) {
|
|
22412
|
-
const raw =
|
|
22674
|
+
const raw = parseNonEmptyString9(value);
|
|
22413
22675
|
if (raw.length === 0) {
|
|
22414
22676
|
return void 0;
|
|
22415
22677
|
}
|
|
22416
22678
|
const parsed = Number.parseInt(raw, 10);
|
|
22417
22679
|
if (!Number.isInteger(parsed) || parsed < 1) {
|
|
22418
|
-
throw
|
|
22680
|
+
throw createCliError7(
|
|
22419
22681
|
"CLI_PAIR_START_INVALID_TTL",
|
|
22420
22682
|
"ttlSeconds must be a positive integer"
|
|
22421
22683
|
);
|
|
@@ -22430,36 +22692,31 @@ function parseProxyUrl2(candidate) {
|
|
|
22430
22692
|
}
|
|
22431
22693
|
return parsed.toString();
|
|
22432
22694
|
} catch {
|
|
22433
|
-
throw
|
|
22695
|
+
throw createCliError7("CLI_PAIR_INVALID_PROXY_URL", "Proxy URL is invalid");
|
|
22434
22696
|
}
|
|
22435
22697
|
}
|
|
22436
|
-
function
|
|
22437
|
-
const
|
|
22438
|
-
if (explicit.length > 0) {
|
|
22439
|
-
return [parseProxyUrl2(explicit)];
|
|
22440
|
-
}
|
|
22441
|
-
const fromEnv = parseNonEmptyString8(process.env.CLAWDENTITY_PROXY_URL);
|
|
22698
|
+
async function resolveProxyUrl(input) {
|
|
22699
|
+
const fromEnv = parseNonEmptyString9(process.env.CLAWDENTITY_PROXY_URL);
|
|
22442
22700
|
if (fromEnv.length > 0) {
|
|
22443
|
-
return
|
|
22701
|
+
return parseProxyUrl2(fromEnv);
|
|
22444
22702
|
}
|
|
22445
|
-
const
|
|
22446
|
-
|
|
22447
|
-
|
|
22703
|
+
const metadata = await fetchRegistryMetadata(input.config.registryUrl, {
|
|
22704
|
+
fetchImpl: input.fetchImpl
|
|
22705
|
+
});
|
|
22706
|
+
const metadataProxyUrl = parseProxyUrl2(metadata.proxyUrl);
|
|
22707
|
+
const configuredProxyUrl = parseNonEmptyString9(input.config.proxyUrl);
|
|
22708
|
+
if (configuredProxyUrl.length === 0) {
|
|
22709
|
+
return metadataProxyUrl;
|
|
22448
22710
|
}
|
|
22449
|
-
const
|
|
22450
|
-
|
|
22451
|
-
|
|
22452
|
-
if (typeof derivedFromRegistry === "string" && derivedFromRegistry.length > 0) {
|
|
22453
|
-
return [parseProxyUrl2(derivedFromRegistry)];
|
|
22711
|
+
const normalizedConfiguredProxyUrl = parseProxyUrl2(configuredProxyUrl);
|
|
22712
|
+
if (normalizedConfiguredProxyUrl === metadataProxyUrl) {
|
|
22713
|
+
return metadataProxyUrl;
|
|
22454
22714
|
}
|
|
22455
|
-
throw
|
|
22456
|
-
"
|
|
22457
|
-
|
|
22715
|
+
throw createCliError7(
|
|
22716
|
+
"CLI_PAIR_PROXY_URL_MISMATCH",
|
|
22717
|
+
`Configured proxy URL does not match registry metadata. config=${normalizedConfiguredProxyUrl} metadata=${metadataProxyUrl}. Rerun onboarding invite redeem to refresh config.`
|
|
22458
22718
|
);
|
|
22459
22719
|
}
|
|
22460
|
-
function resolveProxyUrl(input) {
|
|
22461
|
-
return resolveProxyUrlCandidates(input)[0];
|
|
22462
|
-
}
|
|
22463
22720
|
function toProxyRequestUrl(proxyUrl, path) {
|
|
22464
22721
|
const normalizedBase = proxyUrl.endsWith("/") ? proxyUrl : `${proxyUrl}/`;
|
|
22465
22722
|
return new URL(path.slice(1), normalizedBase).toString();
|
|
@@ -22469,7 +22726,7 @@ function toPathWithQuery3(url2) {
|
|
|
22469
22726
|
return `${parsed.pathname}${parsed.search}`;
|
|
22470
22727
|
}
|
|
22471
22728
|
function extractErrorCode(payload) {
|
|
22472
|
-
if (!
|
|
22729
|
+
if (!isRecord9(payload)) {
|
|
22473
22730
|
return void 0;
|
|
22474
22731
|
}
|
|
22475
22732
|
const envelope = payload;
|
|
@@ -22480,7 +22737,7 @@ function extractErrorCode(payload) {
|
|
|
22480
22737
|
return code.length > 0 ? code : void 0;
|
|
22481
22738
|
}
|
|
22482
22739
|
function extractErrorMessage(payload) {
|
|
22483
|
-
if (!
|
|
22740
|
+
if (!isRecord9(payload)) {
|
|
22484
22741
|
return void 0;
|
|
22485
22742
|
}
|
|
22486
22743
|
const envelope = payload;
|
|
@@ -22490,7 +22747,7 @@ function extractErrorMessage(payload) {
|
|
|
22490
22747
|
const message2 = envelope.error.message.trim();
|
|
22491
22748
|
return message2.length > 0 ? message2 : void 0;
|
|
22492
22749
|
}
|
|
22493
|
-
async function
|
|
22750
|
+
async function parseJsonResponse6(response) {
|
|
22494
22751
|
try {
|
|
22495
22752
|
return await response.json();
|
|
22496
22753
|
} catch {
|
|
@@ -22501,7 +22758,7 @@ async function executePairRequest(input) {
|
|
|
22501
22758
|
try {
|
|
22502
22759
|
return await input.fetchImpl(input.url, input.init);
|
|
22503
22760
|
} catch {
|
|
22504
|
-
throw
|
|
22761
|
+
throw createCliError7(
|
|
22505
22762
|
"CLI_PAIR_REQUEST_FAILED",
|
|
22506
22763
|
"Unable to connect to proxy URL. Check network access and proxyUrl."
|
|
22507
22764
|
);
|
|
@@ -22548,17 +22805,17 @@ function mapConfirmPairError(status, payload) {
|
|
|
22548
22805
|
return `Pair confirm failed (${status})`;
|
|
22549
22806
|
}
|
|
22550
22807
|
function parsePairStartResponse(payload) {
|
|
22551
|
-
if (!
|
|
22552
|
-
throw
|
|
22808
|
+
if (!isRecord9(payload)) {
|
|
22809
|
+
throw createCliError7(
|
|
22553
22810
|
"CLI_PAIR_START_INVALID_RESPONSE",
|
|
22554
22811
|
"Pair start response is invalid"
|
|
22555
22812
|
);
|
|
22556
22813
|
}
|
|
22557
22814
|
const ticket = parsePairingTicket(payload.ticket);
|
|
22558
|
-
const initiatorAgentDid =
|
|
22559
|
-
const expiresAt =
|
|
22815
|
+
const initiatorAgentDid = parseNonEmptyString9(payload.initiatorAgentDid);
|
|
22816
|
+
const expiresAt = parseNonEmptyString9(payload.expiresAt);
|
|
22560
22817
|
if (initiatorAgentDid.length === 0 || expiresAt.length === 0) {
|
|
22561
|
-
throw
|
|
22818
|
+
throw createCliError7(
|
|
22562
22819
|
"CLI_PAIR_START_INVALID_RESPONSE",
|
|
22563
22820
|
"Pair start response is invalid"
|
|
22564
22821
|
);
|
|
@@ -22570,17 +22827,17 @@ function parsePairStartResponse(payload) {
|
|
|
22570
22827
|
};
|
|
22571
22828
|
}
|
|
22572
22829
|
function parsePairConfirmResponse(payload) {
|
|
22573
|
-
if (!
|
|
22574
|
-
throw
|
|
22830
|
+
if (!isRecord9(payload)) {
|
|
22831
|
+
throw createCliError7(
|
|
22575
22832
|
"CLI_PAIR_CONFIRM_INVALID_RESPONSE",
|
|
22576
22833
|
"Pair confirm response is invalid"
|
|
22577
22834
|
);
|
|
22578
22835
|
}
|
|
22579
22836
|
const paired = payload.paired === true;
|
|
22580
|
-
const initiatorAgentDid =
|
|
22581
|
-
const responderAgentDid =
|
|
22837
|
+
const initiatorAgentDid = parseNonEmptyString9(payload.initiatorAgentDid);
|
|
22838
|
+
const responderAgentDid = parseNonEmptyString9(payload.responderAgentDid);
|
|
22582
22839
|
if (!paired || initiatorAgentDid.length === 0 || responderAgentDid.length === 0) {
|
|
22583
|
-
throw
|
|
22840
|
+
throw createCliError7(
|
|
22584
22841
|
"CLI_PAIR_CONFIRM_INVALID_RESPONSE",
|
|
22585
22842
|
"Pair confirm response is invalid"
|
|
22586
22843
|
);
|
|
@@ -22608,7 +22865,7 @@ async function readAgentProofMaterial(agentName, dependencies) {
|
|
|
22608
22865
|
} catch (error48) {
|
|
22609
22866
|
const nodeError = error48;
|
|
22610
22867
|
if (nodeError.code === "ENOENT") {
|
|
22611
|
-
throw
|
|
22868
|
+
throw createCliError7(
|
|
22612
22869
|
"CLI_PAIR_AGENT_NOT_FOUND",
|
|
22613
22870
|
`Agent "${normalizedAgentName}" is missing ${AIT_FILE_NAME4}. Run agent create first.`
|
|
22614
22871
|
);
|
|
@@ -22616,7 +22873,7 @@ async function readAgentProofMaterial(agentName, dependencies) {
|
|
|
22616
22873
|
throw error48;
|
|
22617
22874
|
}
|
|
22618
22875
|
if (ait.length === 0) {
|
|
22619
|
-
throw
|
|
22876
|
+
throw createCliError7(
|
|
22620
22877
|
"CLI_PAIR_AGENT_NOT_FOUND",
|
|
22621
22878
|
`Agent "${normalizedAgentName}" has an empty ${AIT_FILE_NAME4}`
|
|
22622
22879
|
);
|
|
@@ -22627,7 +22884,7 @@ async function readAgentProofMaterial(agentName, dependencies) {
|
|
|
22627
22884
|
} catch (error48) {
|
|
22628
22885
|
const nodeError = error48;
|
|
22629
22886
|
if (nodeError.code === "ENOENT") {
|
|
22630
|
-
throw
|
|
22887
|
+
throw createCliError7(
|
|
22631
22888
|
"CLI_PAIR_AGENT_NOT_FOUND",
|
|
22632
22889
|
`Agent "${normalizedAgentName}" is missing ${SECRET_KEY_FILE_NAME3}. Run agent create first.`
|
|
22633
22890
|
);
|
|
@@ -22635,7 +22892,7 @@ async function readAgentProofMaterial(agentName, dependencies) {
|
|
|
22635
22892
|
throw error48;
|
|
22636
22893
|
}
|
|
22637
22894
|
if (encodedSecretKey.length === 0) {
|
|
22638
|
-
throw
|
|
22895
|
+
throw createCliError7(
|
|
22639
22896
|
"CLI_PAIR_AGENT_NOT_FOUND",
|
|
22640
22897
|
`Agent "${normalizedAgentName}" has an empty ${SECRET_KEY_FILE_NAME3}`
|
|
22641
22898
|
);
|
|
@@ -22644,7 +22901,7 @@ async function readAgentProofMaterial(agentName, dependencies) {
|
|
|
22644
22901
|
try {
|
|
22645
22902
|
secretKey = decodeBase64url(encodedSecretKey);
|
|
22646
22903
|
} catch {
|
|
22647
|
-
throw
|
|
22904
|
+
throw createCliError7(
|
|
22648
22905
|
"CLI_PAIR_AGENT_NOT_FOUND",
|
|
22649
22906
|
`Agent "${normalizedAgentName}" has invalid ${SECRET_KEY_FILE_NAME3}`
|
|
22650
22907
|
);
|
|
@@ -22655,11 +22912,11 @@ async function readAgentProofMaterial(agentName, dependencies) {
|
|
|
22655
22912
|
};
|
|
22656
22913
|
}
|
|
22657
22914
|
function resolveOwnerPat(options) {
|
|
22658
|
-
const ownerPat =
|
|
22915
|
+
const ownerPat = parseNonEmptyString9(options.explicitOwnerPat) || parseNonEmptyString9(options.config.apiKey);
|
|
22659
22916
|
if (ownerPat.length > 0) {
|
|
22660
22917
|
return ownerPat;
|
|
22661
22918
|
}
|
|
22662
|
-
throw
|
|
22919
|
+
throw createCliError7(
|
|
22663
22920
|
"CLI_PAIR_START_OWNER_PAT_REQUIRED",
|
|
22664
22921
|
"Owner PAT is required. Pass --owner-pat <token> or configure API key with `clawdentity invite redeem` / `clawdentity config set apiKey <token>`."
|
|
22665
22922
|
);
|
|
@@ -22689,7 +22946,7 @@ function decodeTicketFromPng(imageBytes) {
|
|
|
22689
22946
|
try {
|
|
22690
22947
|
decodedPng = PNG.sync.read(Buffer.from(imageBytes));
|
|
22691
22948
|
} catch {
|
|
22692
|
-
throw
|
|
22949
|
+
throw createCliError7(
|
|
22693
22950
|
"CLI_PAIR_CONFIRM_QR_FILE_INVALID",
|
|
22694
22951
|
"QR image file is invalid or unsupported"
|
|
22695
22952
|
);
|
|
@@ -22700,8 +22957,8 @@ function decodeTicketFromPng(imageBytes) {
|
|
|
22700
22957
|
decodedPng.data.byteLength
|
|
22701
22958
|
);
|
|
22702
22959
|
const decoded = jsQR(imageData, decodedPng.width, decodedPng.height);
|
|
22703
|
-
if (!decoded ||
|
|
22704
|
-
throw
|
|
22960
|
+
if (!decoded || parseNonEmptyString9(decoded.data).length === 0) {
|
|
22961
|
+
throw createCliError7(
|
|
22705
22962
|
"CLI_PAIR_CONFIRM_QR_NOT_FOUND",
|
|
22706
22963
|
"No pairing QR code was found in the image"
|
|
22707
22964
|
);
|
|
@@ -22716,7 +22973,7 @@ async function persistPairingQr(input) {
|
|
|
22716
22973
|
const getConfigDirImpl = input.dependencies.getConfigDirImpl ?? getConfigDir;
|
|
22717
22974
|
const qrEncodeImpl = input.dependencies.qrEncodeImpl ?? encodeTicketQrPng;
|
|
22718
22975
|
const baseDir = join7(getConfigDirImpl(), PAIRING_QR_DIR_NAME);
|
|
22719
|
-
const outputPath =
|
|
22976
|
+
const outputPath = parseNonEmptyString9(input.qrOutput) ? resolve(input.qrOutput ?? "") : join7(
|
|
22720
22977
|
baseDir,
|
|
22721
22978
|
`${assertValidAgentName(input.agentName)}-pair-${input.nowSeconds}.png`
|
|
22722
22979
|
);
|
|
@@ -22757,10 +23014,10 @@ async function persistPairingQr(input) {
|
|
|
22757
23014
|
return outputPath;
|
|
22758
23015
|
}
|
|
22759
23016
|
function resolveConfirmTicketSource(options) {
|
|
22760
|
-
const inlineTicket =
|
|
22761
|
-
const qrFile =
|
|
23017
|
+
const inlineTicket = parseNonEmptyString9(options.ticket);
|
|
23018
|
+
const qrFile = parseNonEmptyString9(options.qrFile);
|
|
22762
23019
|
if (inlineTicket.length > 0 && qrFile.length > 0) {
|
|
22763
|
-
throw
|
|
23020
|
+
throw createCliError7(
|
|
22764
23021
|
"CLI_PAIR_CONFIRM_INPUT_CONFLICT",
|
|
22765
23022
|
"Provide either --ticket or --qr-file, not both"
|
|
22766
23023
|
);
|
|
@@ -22778,7 +23035,7 @@ function resolveConfirmTicketSource(options) {
|
|
|
22778
23035
|
qrFilePath: resolve(qrFile)
|
|
22779
23036
|
};
|
|
22780
23037
|
}
|
|
22781
|
-
throw
|
|
23038
|
+
throw createCliError7(
|
|
22782
23039
|
"CLI_PAIR_CONFIRM_TICKET_REQUIRED",
|
|
22783
23040
|
"Pairing ticket is required. Pass --ticket <clwpair1_...> or --qr-file <path>."
|
|
22784
23041
|
);
|
|
@@ -22819,14 +23076,14 @@ async function startPairing(agentName, options, dependencies = {}) {
|
|
|
22819
23076
|
const nonceFactoryImpl = dependencies.nonceFactoryImpl ?? (() => randomBytes4(NONCE_SIZE2).toString("base64url"));
|
|
22820
23077
|
const ttlSeconds = parseTtlSeconds(options.ttlSeconds);
|
|
22821
23078
|
const config2 = await resolveConfigImpl();
|
|
22822
|
-
const proxyUrl = resolveProxyUrl({
|
|
22823
|
-
overrideProxyUrl: options.proxyUrl,
|
|
22824
|
-
config: config2
|
|
22825
|
-
});
|
|
22826
23079
|
const ownerPat = resolveOwnerPat({
|
|
22827
23080
|
explicitOwnerPat: options.ownerPat,
|
|
22828
23081
|
config: config2
|
|
22829
23082
|
});
|
|
23083
|
+
const proxyUrl = await resolveProxyUrl({
|
|
23084
|
+
config: config2,
|
|
23085
|
+
fetchImpl
|
|
23086
|
+
});
|
|
22830
23087
|
const { ait, secretKey } = await readAgentProofMaterial(
|
|
22831
23088
|
agentName,
|
|
22832
23089
|
dependencies
|
|
@@ -22860,9 +23117,9 @@ async function startPairing(agentName, options, dependencies = {}) {
|
|
|
22860
23117
|
body: requestBody
|
|
22861
23118
|
}
|
|
22862
23119
|
});
|
|
22863
|
-
const responseBody = await
|
|
23120
|
+
const responseBody = await parseJsonResponse6(response);
|
|
22864
23121
|
if (!response.ok) {
|
|
22865
|
-
throw
|
|
23122
|
+
throw createCliError7(
|
|
22866
23123
|
"CLI_PAIR_START_FAILED",
|
|
22867
23124
|
mapStartPairError(response.status, responseBody)
|
|
22868
23125
|
);
|
|
@@ -22892,14 +23149,14 @@ async function confirmPairing(agentName, options, dependencies = {}) {
|
|
|
22892
23149
|
const qrDecodeImpl = dependencies.qrDecodeImpl ?? decodeTicketFromPng;
|
|
22893
23150
|
const config2 = await resolveConfigImpl();
|
|
22894
23151
|
const ticketSource = resolveConfirmTicketSource(options);
|
|
22895
|
-
const proxyUrl = resolveProxyUrl({
|
|
22896
|
-
|
|
22897
|
-
|
|
23152
|
+
const proxyUrl = await resolveProxyUrl({
|
|
23153
|
+
config: config2,
|
|
23154
|
+
fetchImpl
|
|
22898
23155
|
});
|
|
22899
23156
|
let ticket = ticketSource.ticket;
|
|
22900
23157
|
if (ticketSource.source === "qr-file") {
|
|
22901
23158
|
if (!ticketSource.qrFilePath) {
|
|
22902
|
-
throw
|
|
23159
|
+
throw createCliError7(
|
|
22903
23160
|
"CLI_PAIR_CONFIRM_QR_FILE_REQUIRED",
|
|
22904
23161
|
"QR file path is required"
|
|
22905
23162
|
);
|
|
@@ -22910,7 +23167,7 @@ async function confirmPairing(agentName, options, dependencies = {}) {
|
|
|
22910
23167
|
} catch (error48) {
|
|
22911
23168
|
const nodeError = error48;
|
|
22912
23169
|
if (nodeError.code === "ENOENT") {
|
|
22913
|
-
throw
|
|
23170
|
+
throw createCliError7(
|
|
22914
23171
|
"CLI_PAIR_CONFIRM_QR_FILE_NOT_FOUND",
|
|
22915
23172
|
`QR file not found: ${ticketSource.qrFilePath}`
|
|
22916
23173
|
);
|
|
@@ -22949,9 +23206,9 @@ async function confirmPairing(agentName, options, dependencies = {}) {
|
|
|
22949
23206
|
body: requestBody
|
|
22950
23207
|
}
|
|
22951
23208
|
});
|
|
22952
|
-
const responseBody = await
|
|
23209
|
+
const responseBody = await parseJsonResponse6(response);
|
|
22953
23210
|
if (!response.ok) {
|
|
22954
|
-
throw
|
|
23211
|
+
throw createCliError7(
|
|
22955
23212
|
"CLI_PAIR_CONFIRM_FAILED",
|
|
22956
23213
|
mapConfirmPairError(response.status, responseBody)
|
|
22957
23214
|
);
|
|
@@ -22985,7 +23242,7 @@ var createPairCommand = (dependencies = {}) => {
|
|
|
22985
23242
|
const pairCommand = new Command8("pair").description(
|
|
22986
23243
|
"Manage proxy trust pairing between agents"
|
|
22987
23244
|
);
|
|
22988
|
-
pairCommand.command("start <agentName>").description("Start pairing and issue one-time pairing ticket").option(
|
|
23245
|
+
pairCommand.command("start <agentName>").description("Start pairing and issue one-time pairing ticket").option(
|
|
22989
23246
|
"--owner-pat <token>",
|
|
22990
23247
|
"Owner PAT override (defaults to configured API key)"
|
|
22991
23248
|
).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(
|
|
@@ -23009,7 +23266,7 @@ var createPairCommand = (dependencies = {}) => {
|
|
|
23009
23266
|
}
|
|
23010
23267
|
)
|
|
23011
23268
|
);
|
|
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").
|
|
23269
|
+
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").action(
|
|
23013
23270
|
withErrorHandling(
|
|
23014
23271
|
"pair confirm",
|
|
23015
23272
|
async (agentName, options) => {
|
|
@@ -23033,9 +23290,341 @@ var createPairCommand = (dependencies = {}) => {
|
|
|
23033
23290
|
return pairCommand;
|
|
23034
23291
|
};
|
|
23035
23292
|
|
|
23036
|
-
// src/commands/
|
|
23037
|
-
import { readFile as readFile6 } from "fs/promises";
|
|
23293
|
+
// src/commands/skill.ts
|
|
23038
23294
|
import { Command as Command9 } from "commander";
|
|
23295
|
+
|
|
23296
|
+
// src/install-skill-mode.ts
|
|
23297
|
+
import { constants, existsSync as existsSync2 } from "fs";
|
|
23298
|
+
import { access as access3, copyFile as copyFile2, mkdir as mkdir7, readdir as readdir2, readFile as readFile6 } from "fs/promises";
|
|
23299
|
+
import { createRequire } from "module";
|
|
23300
|
+
import { homedir as homedir4 } from "os";
|
|
23301
|
+
import { dirname as dirname6, join as join8, relative } from "path";
|
|
23302
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
23303
|
+
var OPENCLAW_DIR_NAME2 = ".openclaw";
|
|
23304
|
+
var SKILL_PACKAGE_NAME = "@clawdentity/openclaw-skill";
|
|
23305
|
+
var SKILL_DIR_NAME2 = "clawdentity-openclaw-relay";
|
|
23306
|
+
var RELAY_MODULE_FILE_NAME2 = "relay-to-peer.mjs";
|
|
23307
|
+
function isRecord10(value) {
|
|
23308
|
+
return typeof value === "object" && value !== null;
|
|
23309
|
+
}
|
|
23310
|
+
var SkillInstallError = class extends Error {
|
|
23311
|
+
code;
|
|
23312
|
+
details;
|
|
23313
|
+
constructor(input) {
|
|
23314
|
+
super(input.message);
|
|
23315
|
+
this.name = "SkillInstallError";
|
|
23316
|
+
this.code = input.code;
|
|
23317
|
+
this.details = input.details ?? {};
|
|
23318
|
+
}
|
|
23319
|
+
};
|
|
23320
|
+
function getErrorCode3(error48) {
|
|
23321
|
+
if (!isRecord10(error48)) {
|
|
23322
|
+
return void 0;
|
|
23323
|
+
}
|
|
23324
|
+
return typeof error48.code === "string" ? error48.code : void 0;
|
|
23325
|
+
}
|
|
23326
|
+
function resolveHomeDir2(inputHomeDir) {
|
|
23327
|
+
if (typeof inputHomeDir === "string" && inputHomeDir.trim().length > 0) {
|
|
23328
|
+
return inputHomeDir.trim();
|
|
23329
|
+
}
|
|
23330
|
+
return homedir4();
|
|
23331
|
+
}
|
|
23332
|
+
function resolveOpenclawDir2(homeDir, inputOpenclawDir) {
|
|
23333
|
+
if (typeof inputOpenclawDir === "string" && inputOpenclawDir.trim().length > 0) {
|
|
23334
|
+
return inputOpenclawDir.trim();
|
|
23335
|
+
}
|
|
23336
|
+
return join8(homeDir, OPENCLAW_DIR_NAME2);
|
|
23337
|
+
}
|
|
23338
|
+
function resolveSkillPackageRoot(input) {
|
|
23339
|
+
if (typeof input.skillPackageRoot === "string" && input.skillPackageRoot.trim().length > 0) {
|
|
23340
|
+
return input.skillPackageRoot.trim();
|
|
23341
|
+
}
|
|
23342
|
+
const overriddenRoot = input.env.CLAWDENTITY_SKILL_PACKAGE_ROOT;
|
|
23343
|
+
if (typeof overriddenRoot === "string" && overriddenRoot.trim().length > 0) {
|
|
23344
|
+
return overriddenRoot.trim();
|
|
23345
|
+
}
|
|
23346
|
+
const bundledSkillRoot = join8(
|
|
23347
|
+
dirname6(fileURLToPath2(import.meta.url)),
|
|
23348
|
+
"..",
|
|
23349
|
+
"skill-bundle",
|
|
23350
|
+
"openclaw-skill"
|
|
23351
|
+
);
|
|
23352
|
+
if (existsSync2(bundledSkillRoot)) {
|
|
23353
|
+
return bundledSkillRoot;
|
|
23354
|
+
}
|
|
23355
|
+
const require3 = createRequire(import.meta.url);
|
|
23356
|
+
let packageJsonPath;
|
|
23357
|
+
try {
|
|
23358
|
+
packageJsonPath = require3.resolve(`${SKILL_PACKAGE_NAME}/package.json`);
|
|
23359
|
+
return dirname6(packageJsonPath);
|
|
23360
|
+
} catch {
|
|
23361
|
+
const workspaceFallbackRoot = join8(
|
|
23362
|
+
dirname6(fileURLToPath2(import.meta.url)),
|
|
23363
|
+
"..",
|
|
23364
|
+
"..",
|
|
23365
|
+
"openclaw-skill"
|
|
23366
|
+
);
|
|
23367
|
+
if (existsSync2(workspaceFallbackRoot)) {
|
|
23368
|
+
return workspaceFallbackRoot;
|
|
23369
|
+
}
|
|
23370
|
+
throw new SkillInstallError({
|
|
23371
|
+
code: "CLI_SKILL_PACKAGE_NOT_FOUND",
|
|
23372
|
+
message: "Skill artifacts are unavailable. Set CLAWDENTITY_SKILL_PACKAGE_ROOT or provide bundled skill assets before running skill install.",
|
|
23373
|
+
details: {
|
|
23374
|
+
packageName: SKILL_PACKAGE_NAME,
|
|
23375
|
+
bundledSkillRoot,
|
|
23376
|
+
workspaceFallbackRoot
|
|
23377
|
+
}
|
|
23378
|
+
});
|
|
23379
|
+
}
|
|
23380
|
+
}
|
|
23381
|
+
async function assertReadableFile(filePath, details) {
|
|
23382
|
+
try {
|
|
23383
|
+
await access3(filePath, constants.R_OK);
|
|
23384
|
+
} catch (error48) {
|
|
23385
|
+
if (getErrorCode3(error48) === "ENOENT") {
|
|
23386
|
+
throw new SkillInstallError({
|
|
23387
|
+
code: "CLI_SKILL_ARTIFACT_MISSING",
|
|
23388
|
+
message: "Required skill artifact is missing",
|
|
23389
|
+
details: {
|
|
23390
|
+
...details,
|
|
23391
|
+
sourcePath: filePath
|
|
23392
|
+
}
|
|
23393
|
+
});
|
|
23394
|
+
}
|
|
23395
|
+
throw error48;
|
|
23396
|
+
}
|
|
23397
|
+
}
|
|
23398
|
+
async function listFilesRecursively(directoryPath) {
|
|
23399
|
+
const entries = await readdir2(directoryPath, { withFileTypes: true });
|
|
23400
|
+
const files = [];
|
|
23401
|
+
for (const entry of entries.sort(
|
|
23402
|
+
(left, right) => left.name.localeCompare(right.name)
|
|
23403
|
+
)) {
|
|
23404
|
+
const entryPath = join8(directoryPath, entry.name);
|
|
23405
|
+
if (entry.isDirectory()) {
|
|
23406
|
+
files.push(...await listFilesRecursively(entryPath));
|
|
23407
|
+
continue;
|
|
23408
|
+
}
|
|
23409
|
+
if (entry.isFile()) {
|
|
23410
|
+
files.push(entryPath);
|
|
23411
|
+
}
|
|
23412
|
+
}
|
|
23413
|
+
return files;
|
|
23414
|
+
}
|
|
23415
|
+
async function resolveArtifacts(input) {
|
|
23416
|
+
const skillRoot = join8(input.skillPackageRoot, "skill");
|
|
23417
|
+
const skillDocSource = join8(skillRoot, "SKILL.md");
|
|
23418
|
+
const referencesRoot = join8(skillRoot, "references");
|
|
23419
|
+
const relaySource = join8(
|
|
23420
|
+
input.skillPackageRoot,
|
|
23421
|
+
"dist",
|
|
23422
|
+
RELAY_MODULE_FILE_NAME2
|
|
23423
|
+
);
|
|
23424
|
+
await assertReadableFile(skillDocSource, {
|
|
23425
|
+
artifact: "SKILL.md"
|
|
23426
|
+
});
|
|
23427
|
+
await assertReadableFile(relaySource, {
|
|
23428
|
+
artifact: RELAY_MODULE_FILE_NAME2
|
|
23429
|
+
});
|
|
23430
|
+
let referenceFiles;
|
|
23431
|
+
try {
|
|
23432
|
+
referenceFiles = await listFilesRecursively(referencesRoot);
|
|
23433
|
+
} catch (error48) {
|
|
23434
|
+
if (getErrorCode3(error48) === "ENOENT") {
|
|
23435
|
+
throw new SkillInstallError({
|
|
23436
|
+
code: "CLI_SKILL_ARTIFACT_MISSING",
|
|
23437
|
+
message: "Required skill references directory is missing",
|
|
23438
|
+
details: {
|
|
23439
|
+
sourcePath: referencesRoot,
|
|
23440
|
+
artifact: "references"
|
|
23441
|
+
}
|
|
23442
|
+
});
|
|
23443
|
+
}
|
|
23444
|
+
throw error48;
|
|
23445
|
+
}
|
|
23446
|
+
if (referenceFiles.length === 0) {
|
|
23447
|
+
throw new SkillInstallError({
|
|
23448
|
+
code: "CLI_SKILL_REFERENCE_DIR_EMPTY",
|
|
23449
|
+
message: "Required skill references directory is empty",
|
|
23450
|
+
details: {
|
|
23451
|
+
sourcePath: referencesRoot
|
|
23452
|
+
}
|
|
23453
|
+
});
|
|
23454
|
+
}
|
|
23455
|
+
const targetSkillRoot = join8(
|
|
23456
|
+
input.openclawDir,
|
|
23457
|
+
"skills",
|
|
23458
|
+
SKILL_DIR_NAME2
|
|
23459
|
+
);
|
|
23460
|
+
const artifacts = [
|
|
23461
|
+
{
|
|
23462
|
+
sourcePath: skillDocSource,
|
|
23463
|
+
targetPath: join8(targetSkillRoot, "SKILL.md")
|
|
23464
|
+
},
|
|
23465
|
+
{
|
|
23466
|
+
sourcePath: relaySource,
|
|
23467
|
+
targetPath: join8(targetSkillRoot, RELAY_MODULE_FILE_NAME2)
|
|
23468
|
+
},
|
|
23469
|
+
{
|
|
23470
|
+
sourcePath: relaySource,
|
|
23471
|
+
targetPath: join8(
|
|
23472
|
+
input.openclawDir,
|
|
23473
|
+
"hooks",
|
|
23474
|
+
"transforms",
|
|
23475
|
+
RELAY_MODULE_FILE_NAME2
|
|
23476
|
+
)
|
|
23477
|
+
}
|
|
23478
|
+
];
|
|
23479
|
+
for (const referenceFile of referenceFiles) {
|
|
23480
|
+
const relativePath = relative(referencesRoot, referenceFile);
|
|
23481
|
+
artifacts.push({
|
|
23482
|
+
sourcePath: referenceFile,
|
|
23483
|
+
targetPath: join8(targetSkillRoot, "references", relativePath)
|
|
23484
|
+
});
|
|
23485
|
+
}
|
|
23486
|
+
return artifacts.sort(
|
|
23487
|
+
(left, right) => left.targetPath.localeCompare(right.targetPath)
|
|
23488
|
+
);
|
|
23489
|
+
}
|
|
23490
|
+
async function copyArtifact(input) {
|
|
23491
|
+
const sourceContent = await readFile6(input.sourcePath);
|
|
23492
|
+
let existingContent;
|
|
23493
|
+
try {
|
|
23494
|
+
existingContent = await readFile6(input.targetPath);
|
|
23495
|
+
} catch (error48) {
|
|
23496
|
+
if (getErrorCode3(error48) !== "ENOENT") {
|
|
23497
|
+
throw error48;
|
|
23498
|
+
}
|
|
23499
|
+
}
|
|
23500
|
+
if (existingContent !== void 0 && sourceContent.equals(existingContent)) {
|
|
23501
|
+
return "unchanged";
|
|
23502
|
+
}
|
|
23503
|
+
await mkdir7(dirname6(input.targetPath), { recursive: true });
|
|
23504
|
+
await copyFile2(input.sourcePath, input.targetPath);
|
|
23505
|
+
if (existingContent !== void 0) {
|
|
23506
|
+
return "updated";
|
|
23507
|
+
}
|
|
23508
|
+
return "installed";
|
|
23509
|
+
}
|
|
23510
|
+
async function installOpenclawSkillArtifacts(options = {}) {
|
|
23511
|
+
const env = options.env ?? process.env;
|
|
23512
|
+
const homeDir = resolveHomeDir2(options.homeDir);
|
|
23513
|
+
const openclawDir = resolveOpenclawDir2(homeDir, options.openclawDir);
|
|
23514
|
+
const skillPackageRoot = resolveSkillPackageRoot({
|
|
23515
|
+
skillPackageRoot: options.skillPackageRoot,
|
|
23516
|
+
env
|
|
23517
|
+
});
|
|
23518
|
+
const artifacts = await resolveArtifacts({
|
|
23519
|
+
skillPackageRoot,
|
|
23520
|
+
openclawDir
|
|
23521
|
+
});
|
|
23522
|
+
const records = [];
|
|
23523
|
+
for (const artifact of artifacts) {
|
|
23524
|
+
const action = await copyArtifact(artifact);
|
|
23525
|
+
records.push({
|
|
23526
|
+
action,
|
|
23527
|
+
sourcePath: artifact.sourcePath,
|
|
23528
|
+
targetPath: artifact.targetPath
|
|
23529
|
+
});
|
|
23530
|
+
}
|
|
23531
|
+
return {
|
|
23532
|
+
homeDir,
|
|
23533
|
+
openclawDir,
|
|
23534
|
+
skillPackageRoot,
|
|
23535
|
+
targetSkillDirectory: join8(openclawDir, "skills", SKILL_DIR_NAME2),
|
|
23536
|
+
records
|
|
23537
|
+
};
|
|
23538
|
+
}
|
|
23539
|
+
function formatSkillInstallError(error48) {
|
|
23540
|
+
if (error48 instanceof SkillInstallError) {
|
|
23541
|
+
const details = Object.entries(error48.details).map(([key, value]) => `${key}=${value}`).join(" ");
|
|
23542
|
+
if (details.length === 0) {
|
|
23543
|
+
return `${error48.code}: ${error48.message}`;
|
|
23544
|
+
}
|
|
23545
|
+
return `${error48.code}: ${error48.message} (${details})`;
|
|
23546
|
+
}
|
|
23547
|
+
if (error48 instanceof Error) {
|
|
23548
|
+
return error48.message;
|
|
23549
|
+
}
|
|
23550
|
+
return String(error48);
|
|
23551
|
+
}
|
|
23552
|
+
|
|
23553
|
+
// src/commands/skill.ts
|
|
23554
|
+
function collectStringOption(value, previous) {
|
|
23555
|
+
const trimmed = value.trim();
|
|
23556
|
+
if (trimmed.length === 0) {
|
|
23557
|
+
return previous;
|
|
23558
|
+
}
|
|
23559
|
+
return [...previous, trimmed];
|
|
23560
|
+
}
|
|
23561
|
+
function toInstallSummary(records) {
|
|
23562
|
+
const installed = records.filter((record2) => record2.action === "installed");
|
|
23563
|
+
const updated = records.filter((record2) => record2.action === "updated");
|
|
23564
|
+
const unchanged = records.filter((record2) => record2.action === "unchanged");
|
|
23565
|
+
return `installed=${installed.length} updated=${updated.length} unchanged=${unchanged.length}`;
|
|
23566
|
+
}
|
|
23567
|
+
async function runSkillInstall(options) {
|
|
23568
|
+
const requestedDirs = (options.openclawDir ?? []).filter(
|
|
23569
|
+
(dir) => dir.trim().length > 0
|
|
23570
|
+
);
|
|
23571
|
+
const dirs = requestedDirs.length > 0 ? requestedDirs : [void 0];
|
|
23572
|
+
const results = [];
|
|
23573
|
+
for (const openclawDir of dirs) {
|
|
23574
|
+
const result = await installOpenclawSkillArtifacts({
|
|
23575
|
+
openclawDir,
|
|
23576
|
+
skillPackageRoot: options.skillPackageRoot
|
|
23577
|
+
});
|
|
23578
|
+
results.push(result);
|
|
23579
|
+
}
|
|
23580
|
+
return results;
|
|
23581
|
+
}
|
|
23582
|
+
var createSkillCommand = () => {
|
|
23583
|
+
const skillCommand = new Command9("skill").description(
|
|
23584
|
+
"Install and manage Clawdentity skill artifacts"
|
|
23585
|
+
);
|
|
23586
|
+
skillCommand.command("install").description("Install Clawdentity OpenClaw skill artifacts").option(
|
|
23587
|
+
"--openclaw-dir <path>",
|
|
23588
|
+
"OpenClaw state directory target (repeat for multiple profiles)",
|
|
23589
|
+
collectStringOption,
|
|
23590
|
+
[]
|
|
23591
|
+
).option(
|
|
23592
|
+
"--skill-package-root <path>",
|
|
23593
|
+
"Override skill package root (defaults to bundled assets)"
|
|
23594
|
+
).option("--json", "Print machine-readable JSON output").action(
|
|
23595
|
+
withErrorHandling(
|
|
23596
|
+
"skill install",
|
|
23597
|
+
async (options) => {
|
|
23598
|
+
let results;
|
|
23599
|
+
try {
|
|
23600
|
+
results = await runSkillInstall(options);
|
|
23601
|
+
} catch (error48) {
|
|
23602
|
+
throw new Error(formatSkillInstallError(error48));
|
|
23603
|
+
}
|
|
23604
|
+
if (options.json) {
|
|
23605
|
+
writeStdoutLine(JSON.stringify({ installs: results }, null, 2));
|
|
23606
|
+
return;
|
|
23607
|
+
}
|
|
23608
|
+
for (const result of results) {
|
|
23609
|
+
writeStdoutLine(`OpenClaw dir: ${result.openclawDir}`);
|
|
23610
|
+
writeStdoutLine(`Skill source: ${result.skillPackageRoot}`);
|
|
23611
|
+
writeStdoutLine(`Target skill dir: ${result.targetSkillDirectory}`);
|
|
23612
|
+
for (const record2 of result.records) {
|
|
23613
|
+
writeStdoutLine(
|
|
23614
|
+
`${record2.action}: ${record2.targetPath} (source: ${record2.sourcePath})`
|
|
23615
|
+
);
|
|
23616
|
+
}
|
|
23617
|
+
writeStdoutLine(toInstallSummary(result.records));
|
|
23618
|
+
}
|
|
23619
|
+
}
|
|
23620
|
+
)
|
|
23621
|
+
);
|
|
23622
|
+
return skillCommand;
|
|
23623
|
+
};
|
|
23624
|
+
|
|
23625
|
+
// src/commands/verify.ts
|
|
23626
|
+
import { readFile as readFile7 } from "fs/promises";
|
|
23627
|
+
import { Command as Command10 } from "commander";
|
|
23039
23628
|
var logger10 = createLogger({ service: "cli", module: "verify" });
|
|
23040
23629
|
var REGISTRY_KEYS_CACHE_FILE = "registry-keys.json";
|
|
23041
23630
|
var CRL_CLAIMS_CACHE_FILE = "crl-claims.json";
|
|
@@ -23047,10 +23636,10 @@ var VerifyCommandError = class extends Error {
|
|
|
23047
23636
|
this.name = "VerifyCommandError";
|
|
23048
23637
|
}
|
|
23049
23638
|
};
|
|
23050
|
-
var
|
|
23639
|
+
var isRecord11 = (value) => {
|
|
23051
23640
|
return typeof value === "object" && value !== null;
|
|
23052
23641
|
};
|
|
23053
|
-
var
|
|
23642
|
+
var normalizeRegistryUrl2 = (registryUrl) => {
|
|
23054
23643
|
try {
|
|
23055
23644
|
return new URL(registryUrl).toString();
|
|
23056
23645
|
} catch {
|
|
@@ -23083,7 +23672,7 @@ var resolveToken = async (tokenOrFile) => {
|
|
|
23083
23672
|
throw new VerifyCommandError("invalid token (value is empty)");
|
|
23084
23673
|
}
|
|
23085
23674
|
try {
|
|
23086
|
-
const fileContents = await
|
|
23675
|
+
const fileContents = await readFile7(input, "utf-8");
|
|
23087
23676
|
const token = fileContents.trim();
|
|
23088
23677
|
if (token.length === 0) {
|
|
23089
23678
|
throw new VerifyCommandError(`invalid token (${input} is empty)`);
|
|
@@ -23115,7 +23704,7 @@ var parseResponseJson = async (response) => {
|
|
|
23115
23704
|
}
|
|
23116
23705
|
};
|
|
23117
23706
|
var parseSigningKeys = (payload) => {
|
|
23118
|
-
if (!
|
|
23707
|
+
if (!isRecord11(payload) || !Array.isArray(payload.keys)) {
|
|
23119
23708
|
throw new VerifyCommandError(
|
|
23120
23709
|
"verification keys unavailable (response payload is invalid)"
|
|
23121
23710
|
);
|
|
@@ -23134,7 +23723,7 @@ var parseSigningKeys = (payload) => {
|
|
|
23134
23723
|
};
|
|
23135
23724
|
var parseRegistryKeysCache = (rawCache) => {
|
|
23136
23725
|
const parsed = parseJson(rawCache);
|
|
23137
|
-
if (!
|
|
23726
|
+
if (!isRecord11(parsed)) {
|
|
23138
23727
|
return void 0;
|
|
23139
23728
|
}
|
|
23140
23729
|
const { registryUrl, fetchedAtMs, keys } = parsed;
|
|
@@ -23160,7 +23749,7 @@ var parseRegistryKeysCache = (rawCache) => {
|
|
|
23160
23749
|
};
|
|
23161
23750
|
var parseCrlCache = (rawCache) => {
|
|
23162
23751
|
const parsed = parseJson(rawCache);
|
|
23163
|
-
if (!
|
|
23752
|
+
if (!isRecord11(parsed)) {
|
|
23164
23753
|
return void 0;
|
|
23165
23754
|
}
|
|
23166
23755
|
const { registryUrl, fetchedAtMs, claims } = parsed;
|
|
@@ -23258,7 +23847,7 @@ var fetchCrlClaims = async (input) => {
|
|
|
23258
23847
|
);
|
|
23259
23848
|
}
|
|
23260
23849
|
const payload = await parseResponseJson(response);
|
|
23261
|
-
if (!
|
|
23850
|
+
if (!isRecord11(payload) || typeof payload.crl !== "string") {
|
|
23262
23851
|
throw new VerifyCommandError(
|
|
23263
23852
|
"revocation check unavailable (response payload is invalid)"
|
|
23264
23853
|
);
|
|
@@ -23303,7 +23892,7 @@ var loadCrlClaims = async (input) => {
|
|
|
23303
23892
|
return claims;
|
|
23304
23893
|
};
|
|
23305
23894
|
var toInvalidTokenReason = (error48) => {
|
|
23306
|
-
if (
|
|
23895
|
+
if (isRecord11(error48) && typeof error48.message === "string") {
|
|
23307
23896
|
return `invalid token (${error48.message})`;
|
|
23308
23897
|
}
|
|
23309
23898
|
if (error48 instanceof Error && error48.message.length > 0) {
|
|
@@ -23321,7 +23910,7 @@ var printResult = (passed, reason) => {
|
|
|
23321
23910
|
};
|
|
23322
23911
|
var runVerify = async (tokenOrFile) => {
|
|
23323
23912
|
const config2 = await resolveConfig();
|
|
23324
|
-
const registryUrl =
|
|
23913
|
+
const registryUrl = normalizeRegistryUrl2(config2.registryUrl);
|
|
23325
23914
|
const expectedIssuer = toExpectedIssuer(registryUrl);
|
|
23326
23915
|
const token = await resolveToken(tokenOrFile);
|
|
23327
23916
|
let keys;
|
|
@@ -23379,7 +23968,7 @@ var runVerify = async (tokenOrFile) => {
|
|
|
23379
23968
|
printResult(true, `token verified (${claims.sub})`);
|
|
23380
23969
|
};
|
|
23381
23970
|
var createVerifyCommand = () => {
|
|
23382
|
-
return new
|
|
23971
|
+
return new Command10("verify").description("Verify an AIT using registry keys and CRL state").argument(
|
|
23383
23972
|
"<tokenOrFile>",
|
|
23384
23973
|
"Raw AIT token or file path containing the token"
|
|
23385
23974
|
).action(
|
|
@@ -23390,7 +23979,7 @@ var createVerifyCommand = () => {
|
|
|
23390
23979
|
};
|
|
23391
23980
|
|
|
23392
23981
|
// src/index.ts
|
|
23393
|
-
var require2 =
|
|
23982
|
+
var require2 = createRequire2(import.meta.url);
|
|
23394
23983
|
var resolveCliVersion = () => {
|
|
23395
23984
|
const packageJson = require2("../package.json");
|
|
23396
23985
|
if (typeof packageJson.version === "string" && packageJson.version.length > 0) {
|
|
@@ -23400,7 +23989,7 @@ var resolveCliVersion = () => {
|
|
|
23400
23989
|
};
|
|
23401
23990
|
var CLI_VERSION = resolveCliVersion();
|
|
23402
23991
|
var createProgram = () => {
|
|
23403
|
-
return new
|
|
23992
|
+
return new Command11("clawdentity").description("Clawdentity CLI - Agent identity management").version(CLI_VERSION).addCommand(createAdminCommand()).addCommand(createAgentCommand()).addCommand(createApiKeyCommand()).addCommand(createConnectorCommand()).addCommand(createConfigCommand()).addCommand(createInviteCommand()).addCommand(createOpenclawCommand()).addCommand(createPairCommand()).addCommand(createSkillCommand()).addCommand(createVerifyCommand());
|
|
23404
23993
|
};
|
|
23405
23994
|
export {
|
|
23406
23995
|
CLI_VERSION,
|