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