clawdentity 0.0.3 → 0.0.5
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 +481 -32
- package/dist/index.js +481 -32
- package/dist/postinstall.js +0 -0
- package/package.json +17 -15
- package/skill-bundle/AGENTS.md +2 -1
- package/skill-bundle/openclaw-skill/dist/relay-to-peer.mjs +165 -18
- package/skill-bundle/openclaw-skill/skill/SKILL.md +15 -2
- package/skill-bundle/openclaw-skill/skill/references/clawdentity-protocol.md +18 -7
package/dist/bin.js
CHANGED
|
@@ -19577,6 +19577,8 @@ var IDENTITY_FILE_NAME2 = "identity.json";
|
|
|
19577
19577
|
var AIT_FILE_NAME2 = "ait.jwt";
|
|
19578
19578
|
var SECRET_KEY_FILE_NAME = "secret.key";
|
|
19579
19579
|
var REGISTRY_AUTH_FILE_NAME2 = "registry-auth.json";
|
|
19580
|
+
var OPENCLAW_RELAY_RUNTIME_FILE_NAME = "openclaw-relay.json";
|
|
19581
|
+
var OPENCLAW_CONNECTORS_FILE_NAME = "openclaw-connectors.json";
|
|
19580
19582
|
var SERVICE_LOG_DIR_NAME = "logs";
|
|
19581
19583
|
var DEFAULT_CONNECTOR_BASE_URL2 = "http://127.0.0.1:19400";
|
|
19582
19584
|
var DEFAULT_CONNECTOR_OUTBOUND_PATH2 = "/v1/outbound";
|
|
@@ -19660,13 +19662,43 @@ function normalizeOutboundPath2(pathValue) {
|
|
|
19660
19662
|
}
|
|
19661
19663
|
return trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
|
|
19662
19664
|
}
|
|
19663
|
-
function
|
|
19665
|
+
function resolveConnectorBaseUrlFromEnv() {
|
|
19664
19666
|
const value = process.env.CLAWDENTITY_CONNECTOR_BASE_URL;
|
|
19665
19667
|
if (typeof value !== "string" || value.trim().length === 0) {
|
|
19666
|
-
return
|
|
19668
|
+
return void 0;
|
|
19667
19669
|
}
|
|
19668
19670
|
return parseConnectorBaseUrl(value.trim());
|
|
19669
19671
|
}
|
|
19672
|
+
async function readConnectorAssignedBaseUrl(configDir, agentName, readFileImpl) {
|
|
19673
|
+
const assignmentsPath = join5(configDir, OPENCLAW_CONNECTORS_FILE_NAME);
|
|
19674
|
+
let raw;
|
|
19675
|
+
try {
|
|
19676
|
+
raw = await readFileImpl(assignmentsPath, "utf8");
|
|
19677
|
+
} catch (error48) {
|
|
19678
|
+
if (getErrorCode(error48) === "ENOENT") {
|
|
19679
|
+
return void 0;
|
|
19680
|
+
}
|
|
19681
|
+
throw error48;
|
|
19682
|
+
}
|
|
19683
|
+
let parsed;
|
|
19684
|
+
try {
|
|
19685
|
+
parsed = JSON.parse(raw);
|
|
19686
|
+
} catch {
|
|
19687
|
+
throw createCliError3(
|
|
19688
|
+
"CLI_CONNECTOR_INVALID_ASSIGNMENTS",
|
|
19689
|
+
"Connector assignments config is invalid JSON",
|
|
19690
|
+
{ assignmentsPath }
|
|
19691
|
+
);
|
|
19692
|
+
}
|
|
19693
|
+
if (!isRecord5(parsed) || !isRecord5(parsed.agents)) {
|
|
19694
|
+
return void 0;
|
|
19695
|
+
}
|
|
19696
|
+
const entry = parsed.agents[agentName];
|
|
19697
|
+
if (!isRecord5(entry) || typeof entry.connectorBaseUrl !== "string") {
|
|
19698
|
+
return void 0;
|
|
19699
|
+
}
|
|
19700
|
+
return parseConnectorBaseUrl(entry.connectorBaseUrl);
|
|
19701
|
+
}
|
|
19670
19702
|
function resolveConnectorOutboundPath() {
|
|
19671
19703
|
const value = process.env.CLAWDENTITY_CONNECTOR_OUTBOUND_PATH;
|
|
19672
19704
|
if (typeof value !== "string" || value.trim().length === 0) {
|
|
@@ -19701,6 +19733,34 @@ async function readRequiredTrimmedFile(filePath, label, readFileImpl) {
|
|
|
19701
19733
|
}
|
|
19702
19734
|
return trimmed;
|
|
19703
19735
|
}
|
|
19736
|
+
async function readRelayRuntimeConfig(configDir, readFileImpl) {
|
|
19737
|
+
const filePath = join5(configDir, OPENCLAW_RELAY_RUNTIME_FILE_NAME);
|
|
19738
|
+
let raw;
|
|
19739
|
+
try {
|
|
19740
|
+
raw = await readFileImpl(filePath, "utf8");
|
|
19741
|
+
} catch (error48) {
|
|
19742
|
+
if (getErrorCode(error48) === "ENOENT") {
|
|
19743
|
+
return void 0;
|
|
19744
|
+
}
|
|
19745
|
+
throw error48;
|
|
19746
|
+
}
|
|
19747
|
+
let parsed;
|
|
19748
|
+
try {
|
|
19749
|
+
parsed = JSON.parse(raw);
|
|
19750
|
+
} catch {
|
|
19751
|
+
return void 0;
|
|
19752
|
+
}
|
|
19753
|
+
if (!isRecord5(parsed)) {
|
|
19754
|
+
return void 0;
|
|
19755
|
+
}
|
|
19756
|
+
const openclawHookToken = typeof parsed.openclawHookToken === "string" && parsed.openclawHookToken.trim().length > 0 ? parsed.openclawHookToken.trim() : void 0;
|
|
19757
|
+
if (!openclawHookToken) {
|
|
19758
|
+
return void 0;
|
|
19759
|
+
}
|
|
19760
|
+
return {
|
|
19761
|
+
openclawHookToken
|
|
19762
|
+
};
|
|
19763
|
+
}
|
|
19704
19764
|
function parseJsonRecord(value, code, message2) {
|
|
19705
19765
|
let parsed;
|
|
19706
19766
|
try {
|
|
@@ -20090,6 +20150,8 @@ async function startConnectorForAgent(agentName, commandOptions = {}, dependenci
|
|
|
20090
20150
|
rawSecretKey,
|
|
20091
20151
|
rawIdentity,
|
|
20092
20152
|
rawRegistryAuth,
|
|
20153
|
+
assignedConnectorBaseUrl,
|
|
20154
|
+
relayRuntimeConfig,
|
|
20093
20155
|
config2,
|
|
20094
20156
|
connectorModule
|
|
20095
20157
|
] = await Promise.all([
|
|
@@ -20113,6 +20175,8 @@ async function startConnectorForAgent(agentName, commandOptions = {}, dependenci
|
|
|
20113
20175
|
REGISTRY_AUTH_FILE_NAME2,
|
|
20114
20176
|
readFileImpl
|
|
20115
20177
|
),
|
|
20178
|
+
readConnectorAssignedBaseUrl(configDir, agentName, readFileImpl),
|
|
20179
|
+
readRelayRuntimeConfig(configDir, readFileImpl),
|
|
20116
20180
|
resolveConfigImpl(),
|
|
20117
20181
|
loadConnectorModule()
|
|
20118
20182
|
]);
|
|
@@ -20124,7 +20188,8 @@ async function startConnectorForAgent(agentName, commandOptions = {}, dependenci
|
|
|
20124
20188
|
}
|
|
20125
20189
|
const identity = parseAgentIdentity(rawIdentity);
|
|
20126
20190
|
const registryAuth = parseRegistryAuth(rawRegistryAuth);
|
|
20127
|
-
const
|
|
20191
|
+
const openclawHookToken = commandOptions.openclawHookToken ?? relayRuntimeConfig?.openclawHookToken;
|
|
20192
|
+
const outboundBaseUrl = resolveConnectorBaseUrlFromEnv() ?? assignedConnectorBaseUrl ?? DEFAULT_CONNECTOR_BASE_URL2;
|
|
20128
20193
|
const outboundPath = resolveConnectorOutboundPath();
|
|
20129
20194
|
const runtime = await connectorModule.startConnectorRuntime({
|
|
20130
20195
|
agentName,
|
|
@@ -20135,7 +20200,7 @@ async function startConnectorForAgent(agentName, commandOptions = {}, dependenci
|
|
|
20135
20200
|
proxyWebsocketUrl: commandOptions.proxyWsUrl,
|
|
20136
20201
|
openclawBaseUrl: commandOptions.openclawBaseUrl,
|
|
20137
20202
|
openclawHookPath: commandOptions.openclawHookPath,
|
|
20138
|
-
openclawHookToken
|
|
20203
|
+
openclawHookToken,
|
|
20139
20204
|
credentials: {
|
|
20140
20205
|
agentDid: identity.did,
|
|
20141
20206
|
ait: rawAit,
|
|
@@ -20602,9 +20667,11 @@ var createInviteCommand = (dependencies = {}) => {
|
|
|
20602
20667
|
};
|
|
20603
20668
|
|
|
20604
20669
|
// src/commands/openclaw.ts
|
|
20670
|
+
import { randomBytes as randomBytes3 } from "crypto";
|
|
20671
|
+
import { existsSync } from "fs";
|
|
20605
20672
|
import { chmod as chmod3, copyFile, mkdir as mkdir5, readFile as readFile4, writeFile as writeFile5 } from "fs/promises";
|
|
20606
20673
|
import { homedir as homedir3 } from "os";
|
|
20607
|
-
import { dirname as dirname4, join as join6 } from "path";
|
|
20674
|
+
import { dirname as dirname4, join as join6, resolve as resolvePath } from "path";
|
|
20608
20675
|
import { Command as Command7 } from "commander";
|
|
20609
20676
|
var logger8 = createLogger({ service: "cli", module: "openclaw" });
|
|
20610
20677
|
var CLAWDENTITY_DIR_NAME = ".clawdentity";
|
|
@@ -20614,17 +20681,29 @@ var SECRET_KEY_FILE_NAME2 = "secret.key";
|
|
|
20614
20681
|
var PEERS_FILE_NAME = "peers.json";
|
|
20615
20682
|
var OPENCLAW_DIR_NAME = ".openclaw";
|
|
20616
20683
|
var OPENCLAW_CONFIG_FILE_NAME = "openclaw.json";
|
|
20684
|
+
var LEGACY_OPENCLAW_STATE_DIR_NAMES = [".clawdbot", ".moldbot", ".moltbot"];
|
|
20685
|
+
var LEGACY_OPENCLAW_CONFIG_FILE_NAMES = ["clawdbot.json", "moldbot.json", "moltbot.json"];
|
|
20617
20686
|
var OPENCLAW_AGENT_FILE_NAME = "openclaw-agent-name";
|
|
20618
|
-
var
|
|
20687
|
+
var OPENCLAW_RELAY_RUNTIME_FILE_NAME2 = "openclaw-relay.json";
|
|
20688
|
+
var OPENCLAW_CONNECTORS_FILE_NAME2 = "openclaw-connectors.json";
|
|
20619
20689
|
var SKILL_DIR_NAME = "clawdentity-openclaw-relay";
|
|
20620
20690
|
var RELAY_MODULE_FILE_NAME = "relay-to-peer.mjs";
|
|
20691
|
+
var RELAY_RUNTIME_FILE_NAME = "clawdentity-relay.json";
|
|
20692
|
+
var RELAY_PEERS_FILE_NAME = "clawdentity-peers.json";
|
|
20621
20693
|
var HOOK_MAPPING_ID = "clawdentity-send-to-peer";
|
|
20622
20694
|
var HOOK_PATH_SEND_TO_PEER = "send-to-peer";
|
|
20623
20695
|
var OPENCLAW_SEND_TO_PEER_HOOK_PATH = "hooks/send-to-peer";
|
|
20624
20696
|
var DEFAULT_OPENCLAW_BASE_URL2 = "http://127.0.0.1:18789";
|
|
20697
|
+
var DEFAULT_CONNECTOR_PORT = 19400;
|
|
20698
|
+
var DEFAULT_CONNECTOR_OUTBOUND_PATH3 = "/v1/outbound";
|
|
20699
|
+
var CONNECTOR_HOST_LOOPBACK = "127.0.0.1";
|
|
20700
|
+
var CONNECTOR_HOST_DOCKER = "host.docker.internal";
|
|
20701
|
+
var CONNECTOR_HOST_DOCKER_GATEWAY = "gateway.docker.internal";
|
|
20702
|
+
var CONNECTOR_HOST_LINUX_BRIDGE = "172.17.0.1";
|
|
20625
20703
|
var INVITE_CODE_PREFIX = "clawd1_";
|
|
20626
20704
|
var PEER_ALIAS_PATTERN = /^[a-zA-Z0-9._-]+$/;
|
|
20627
20705
|
var FILE_MODE3 = 384;
|
|
20706
|
+
var OPENCLAW_HOOK_TOKEN_BYTES = 32;
|
|
20628
20707
|
var textEncoder2 = new TextEncoder();
|
|
20629
20708
|
var textDecoder = new TextDecoder();
|
|
20630
20709
|
function isRecord7(value) {
|
|
@@ -20783,11 +20862,56 @@ function resolveHomeDir(homeDir) {
|
|
|
20783
20862
|
}
|
|
20784
20863
|
return homedir3();
|
|
20785
20864
|
}
|
|
20865
|
+
function resolveHomePrefixedPath(input, homeDir) {
|
|
20866
|
+
const trimmed = input.trim();
|
|
20867
|
+
if (trimmed.startsWith("~")) {
|
|
20868
|
+
return resolvePath(trimmed.replace(/^~(?=$|[\\/])/, homeDir));
|
|
20869
|
+
}
|
|
20870
|
+
return resolvePath(trimmed);
|
|
20871
|
+
}
|
|
20872
|
+
function readNonEmptyEnvPath(value, homeDir) {
|
|
20873
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
20874
|
+
return void 0;
|
|
20875
|
+
}
|
|
20876
|
+
return resolveHomePrefixedPath(value, homeDir);
|
|
20877
|
+
}
|
|
20878
|
+
function resolveOpenclawHomeDir(homeDir) {
|
|
20879
|
+
const envOpenclawHome = readNonEmptyEnvPath(process.env.OPENCLAW_HOME, homeDir);
|
|
20880
|
+
return envOpenclawHome ?? homeDir;
|
|
20881
|
+
}
|
|
20882
|
+
function resolveDefaultOpenclawStateDir(openclawHomeDir) {
|
|
20883
|
+
const newStateDir = join6(openclawHomeDir, OPENCLAW_DIR_NAME);
|
|
20884
|
+
if (existsSync(newStateDir)) {
|
|
20885
|
+
return newStateDir;
|
|
20886
|
+
}
|
|
20887
|
+
for (const legacyDirName of LEGACY_OPENCLAW_STATE_DIR_NAMES) {
|
|
20888
|
+
const legacyStateDir = join6(openclawHomeDir, legacyDirName);
|
|
20889
|
+
if (existsSync(legacyStateDir)) {
|
|
20890
|
+
return legacyStateDir;
|
|
20891
|
+
}
|
|
20892
|
+
}
|
|
20893
|
+
return newStateDir;
|
|
20894
|
+
}
|
|
20786
20895
|
function resolveOpenclawDir(openclawDir, homeDir) {
|
|
20787
20896
|
if (typeof openclawDir === "string" && openclawDir.trim().length > 0) {
|
|
20788
|
-
return openclawDir
|
|
20897
|
+
return resolveHomePrefixedPath(openclawDir, homeDir);
|
|
20898
|
+
}
|
|
20899
|
+
const envStateDir = readNonEmptyEnvPath(
|
|
20900
|
+
process.env.OPENCLAW_STATE_DIR ?? process.env.CLAWDBOT_STATE_DIR,
|
|
20901
|
+
homeDir
|
|
20902
|
+
);
|
|
20903
|
+
if (envStateDir !== void 0) {
|
|
20904
|
+
return envStateDir;
|
|
20905
|
+
}
|
|
20906
|
+
const envConfigPath = readNonEmptyEnvPath(
|
|
20907
|
+
process.env.OPENCLAW_CONFIG_PATH ?? process.env.CLAWDBOT_CONFIG_PATH,
|
|
20908
|
+
homeDir
|
|
20909
|
+
);
|
|
20910
|
+
if (envConfigPath !== void 0) {
|
|
20911
|
+
return dirname4(envConfigPath);
|
|
20789
20912
|
}
|
|
20790
|
-
|
|
20913
|
+
const openclawHomeDir = resolveOpenclawHomeDir(homeDir);
|
|
20914
|
+
return resolveDefaultOpenclawStateDir(openclawHomeDir);
|
|
20791
20915
|
}
|
|
20792
20916
|
function resolveAgentDirectory(homeDir, agentName) {
|
|
20793
20917
|
return join6(homeDir, CLAWDENTITY_DIR_NAME, AGENTS_DIR_NAME4, agentName);
|
|
@@ -20795,8 +20919,26 @@ function resolveAgentDirectory(homeDir, agentName) {
|
|
|
20795
20919
|
function resolvePeersPath(homeDir) {
|
|
20796
20920
|
return join6(homeDir, CLAWDENTITY_DIR_NAME, PEERS_FILE_NAME);
|
|
20797
20921
|
}
|
|
20798
|
-
function resolveOpenclawConfigPath(openclawDir) {
|
|
20799
|
-
|
|
20922
|
+
function resolveOpenclawConfigPath(openclawDir, homeDir) {
|
|
20923
|
+
const envConfigPath = readNonEmptyEnvPath(
|
|
20924
|
+
process.env.OPENCLAW_CONFIG_PATH ?? process.env.CLAWDBOT_CONFIG_PATH,
|
|
20925
|
+
homeDir
|
|
20926
|
+
);
|
|
20927
|
+
if (envConfigPath !== void 0) {
|
|
20928
|
+
return envConfigPath;
|
|
20929
|
+
}
|
|
20930
|
+
const configCandidates = [
|
|
20931
|
+
join6(openclawDir, OPENCLAW_CONFIG_FILE_NAME),
|
|
20932
|
+
...LEGACY_OPENCLAW_CONFIG_FILE_NAMES.map(
|
|
20933
|
+
(fileName) => join6(openclawDir, fileName)
|
|
20934
|
+
)
|
|
20935
|
+
];
|
|
20936
|
+
for (const candidate of configCandidates) {
|
|
20937
|
+
if (existsSync(candidate)) {
|
|
20938
|
+
return candidate;
|
|
20939
|
+
}
|
|
20940
|
+
}
|
|
20941
|
+
return configCandidates[0];
|
|
20800
20942
|
}
|
|
20801
20943
|
function resolveDefaultTransformSource(openclawDir) {
|
|
20802
20944
|
return join6(
|
|
@@ -20814,7 +20956,16 @@ function resolveOpenclawAgentNamePath(homeDir) {
|
|
|
20814
20956
|
return join6(homeDir, CLAWDENTITY_DIR_NAME, OPENCLAW_AGENT_FILE_NAME);
|
|
20815
20957
|
}
|
|
20816
20958
|
function resolveRelayRuntimeConfigPath(homeDir) {
|
|
20817
|
-
return join6(homeDir, CLAWDENTITY_DIR_NAME,
|
|
20959
|
+
return join6(homeDir, CLAWDENTITY_DIR_NAME, OPENCLAW_RELAY_RUNTIME_FILE_NAME2);
|
|
20960
|
+
}
|
|
20961
|
+
function resolveConnectorAssignmentsPath(homeDir) {
|
|
20962
|
+
return join6(homeDir, CLAWDENTITY_DIR_NAME, OPENCLAW_CONNECTORS_FILE_NAME2);
|
|
20963
|
+
}
|
|
20964
|
+
function resolveTransformRuntimePath(openclawDir) {
|
|
20965
|
+
return join6(openclawDir, "hooks", "transforms", RELAY_RUNTIME_FILE_NAME);
|
|
20966
|
+
}
|
|
20967
|
+
function resolveTransformPeersPath(openclawDir) {
|
|
20968
|
+
return join6(openclawDir, "hooks", "transforms", RELAY_PEERS_FILE_NAME);
|
|
20818
20969
|
}
|
|
20819
20970
|
async function readJsonFile(filePath) {
|
|
20820
20971
|
const raw = await readFile4(filePath, "utf8");
|
|
@@ -20952,6 +21103,98 @@ async function savePeersConfig(peersPath, config2) {
|
|
|
20952
21103
|
await writeSecureFile3(peersPath, `${JSON.stringify(config2, null, 2)}
|
|
20953
21104
|
`);
|
|
20954
21105
|
}
|
|
21106
|
+
function parseConnectorBaseUrlForAssignment(value, label) {
|
|
21107
|
+
return parseHttpUrl(value, {
|
|
21108
|
+
label,
|
|
21109
|
+
code: "CLI_OPENCLAW_INVALID_CONNECTOR_BASE_URL",
|
|
21110
|
+
message: "Connector base URL must be a valid URL"
|
|
21111
|
+
});
|
|
21112
|
+
}
|
|
21113
|
+
function parseConnectorAssignments(value, connectorAssignmentsPath) {
|
|
21114
|
+
if (!isRecord7(value)) {
|
|
21115
|
+
throw createCliError5(
|
|
21116
|
+
"CLI_OPENCLAW_INVALID_CONNECTOR_ASSIGNMENTS",
|
|
21117
|
+
"Connector assignments config must be an object",
|
|
21118
|
+
{ connectorAssignmentsPath }
|
|
21119
|
+
);
|
|
21120
|
+
}
|
|
21121
|
+
const agentsRaw = value.agents;
|
|
21122
|
+
if (!isRecord7(agentsRaw)) {
|
|
21123
|
+
return { agents: {} };
|
|
21124
|
+
}
|
|
21125
|
+
const agents = {};
|
|
21126
|
+
for (const [agentName, entryValue] of Object.entries(agentsRaw)) {
|
|
21127
|
+
if (!isRecord7(entryValue)) {
|
|
21128
|
+
throw createCliError5(
|
|
21129
|
+
"CLI_OPENCLAW_INVALID_CONNECTOR_ASSIGNMENTS",
|
|
21130
|
+
"Connector assignment entry must be an object",
|
|
21131
|
+
{ connectorAssignmentsPath, agentName }
|
|
21132
|
+
);
|
|
21133
|
+
}
|
|
21134
|
+
const connectorBaseUrl = parseConnectorBaseUrlForAssignment(
|
|
21135
|
+
entryValue.connectorBaseUrl,
|
|
21136
|
+
"connectorBaseUrl"
|
|
21137
|
+
);
|
|
21138
|
+
const updatedAt = typeof entryValue.updatedAt === "string" && entryValue.updatedAt.trim().length > 0 ? entryValue.updatedAt.trim() : nowIso();
|
|
21139
|
+
agents[assertValidAgentName(agentName)] = {
|
|
21140
|
+
connectorBaseUrl,
|
|
21141
|
+
updatedAt
|
|
21142
|
+
};
|
|
21143
|
+
}
|
|
21144
|
+
return { agents };
|
|
21145
|
+
}
|
|
21146
|
+
async function loadConnectorAssignments(connectorAssignmentsPath) {
|
|
21147
|
+
let parsed;
|
|
21148
|
+
try {
|
|
21149
|
+
parsed = await readJsonFile(connectorAssignmentsPath);
|
|
21150
|
+
} catch (error48) {
|
|
21151
|
+
if (getErrorCode2(error48) === "ENOENT") {
|
|
21152
|
+
return { agents: {} };
|
|
21153
|
+
}
|
|
21154
|
+
throw error48;
|
|
21155
|
+
}
|
|
21156
|
+
return parseConnectorAssignments(parsed, connectorAssignmentsPath);
|
|
21157
|
+
}
|
|
21158
|
+
async function saveConnectorAssignments(connectorAssignmentsPath, config2) {
|
|
21159
|
+
await writeSecureFile3(
|
|
21160
|
+
connectorAssignmentsPath,
|
|
21161
|
+
`${JSON.stringify(config2, null, 2)}
|
|
21162
|
+
`
|
|
21163
|
+
);
|
|
21164
|
+
}
|
|
21165
|
+
function parseConnectorPortFromBaseUrl(baseUrl) {
|
|
21166
|
+
const parsed = new URL(baseUrl);
|
|
21167
|
+
if (parsed.port) {
|
|
21168
|
+
return Number(parsed.port);
|
|
21169
|
+
}
|
|
21170
|
+
return parsed.protocol === "https:" ? 443 : 80;
|
|
21171
|
+
}
|
|
21172
|
+
function allocateConnectorPort(assignments, agentName) {
|
|
21173
|
+
const existing = assignments.agents[agentName];
|
|
21174
|
+
if (existing) {
|
|
21175
|
+
return parseConnectorPortFromBaseUrl(existing.connectorBaseUrl);
|
|
21176
|
+
}
|
|
21177
|
+
const usedPorts = /* @__PURE__ */ new Set();
|
|
21178
|
+
for (const entry of Object.values(assignments.agents)) {
|
|
21179
|
+
usedPorts.add(parseConnectorPortFromBaseUrl(entry.connectorBaseUrl));
|
|
21180
|
+
}
|
|
21181
|
+
let nextPort = DEFAULT_CONNECTOR_PORT;
|
|
21182
|
+
while (usedPorts.has(nextPort)) {
|
|
21183
|
+
nextPort += 1;
|
|
21184
|
+
}
|
|
21185
|
+
return nextPort;
|
|
21186
|
+
}
|
|
21187
|
+
function buildConnectorBaseUrl(host, port) {
|
|
21188
|
+
return `http://${host}:${port}`;
|
|
21189
|
+
}
|
|
21190
|
+
function buildRelayConnectorBaseUrls(port) {
|
|
21191
|
+
return [
|
|
21192
|
+
buildConnectorBaseUrl(CONNECTOR_HOST_DOCKER, port),
|
|
21193
|
+
buildConnectorBaseUrl(CONNECTOR_HOST_DOCKER_GATEWAY, port),
|
|
21194
|
+
buildConnectorBaseUrl(CONNECTOR_HOST_LINUX_BRIDGE, port),
|
|
21195
|
+
buildConnectorBaseUrl(CONNECTOR_HOST_LOOPBACK, port)
|
|
21196
|
+
];
|
|
21197
|
+
}
|
|
20955
21198
|
function parseRelayRuntimeConfig(value, relayRuntimeConfigPath) {
|
|
20956
21199
|
if (!isRecord7(value)) {
|
|
20957
21200
|
throw createCliError5(
|
|
@@ -20961,8 +21204,10 @@ function parseRelayRuntimeConfig(value, relayRuntimeConfigPath) {
|
|
|
20961
21204
|
);
|
|
20962
21205
|
}
|
|
20963
21206
|
const updatedAt = typeof value.updatedAt === "string" && value.updatedAt.trim().length > 0 ? value.updatedAt.trim() : void 0;
|
|
21207
|
+
const openclawHookToken = typeof value.openclawHookToken === "string" && value.openclawHookToken.trim().length > 0 ? value.openclawHookToken.trim() : void 0;
|
|
20964
21208
|
return {
|
|
20965
21209
|
openclawBaseUrl: parseOpenclawBaseUrl(value.openclawBaseUrl),
|
|
21210
|
+
openclawHookToken,
|
|
20966
21211
|
updatedAt
|
|
20967
21212
|
};
|
|
20968
21213
|
}
|
|
@@ -20978,9 +21223,10 @@ async function loadRelayRuntimeConfig(relayRuntimeConfigPath) {
|
|
|
20978
21223
|
}
|
|
20979
21224
|
return parseRelayRuntimeConfig(parsed, relayRuntimeConfigPath);
|
|
20980
21225
|
}
|
|
20981
|
-
async function saveRelayRuntimeConfig(relayRuntimeConfigPath, openclawBaseUrl) {
|
|
21226
|
+
async function saveRelayRuntimeConfig(relayRuntimeConfigPath, openclawBaseUrl, openclawHookToken) {
|
|
20982
21227
|
const config2 = {
|
|
20983
21228
|
openclawBaseUrl,
|
|
21229
|
+
...openclawHookToken ? { openclawHookToken } : {},
|
|
20984
21230
|
updatedAt: nowIso()
|
|
20985
21231
|
};
|
|
20986
21232
|
await writeSecureFile3(
|
|
@@ -21021,6 +21267,9 @@ function normalizeStringArrayWithValue(value, requiredValue) {
|
|
|
21021
21267
|
normalized.add(requiredValue);
|
|
21022
21268
|
return Array.from(normalized);
|
|
21023
21269
|
}
|
|
21270
|
+
function generateOpenclawHookToken() {
|
|
21271
|
+
return randomBytes3(OPENCLAW_HOOK_TOKEN_BYTES).toString("hex");
|
|
21272
|
+
}
|
|
21024
21273
|
function upsertRelayHookMapping(mappingsValue) {
|
|
21025
21274
|
const mappings = Array.isArray(mappingsValue) ? mappingsValue.filter(isRecord7).map((mapping) => ({ ...mapping })) : [];
|
|
21026
21275
|
const existingIndex = mappings.findIndex((mapping) => {
|
|
@@ -21052,7 +21301,7 @@ function upsertRelayHookMapping(mappingsValue) {
|
|
|
21052
21301
|
mappings.push(relayMapping);
|
|
21053
21302
|
return mappings;
|
|
21054
21303
|
}
|
|
21055
|
-
async function patchOpenclawConfig(openclawConfigPath) {
|
|
21304
|
+
async function patchOpenclawConfig(openclawConfigPath, hookToken) {
|
|
21056
21305
|
let config2;
|
|
21057
21306
|
try {
|
|
21058
21307
|
config2 = await readJsonFile(openclawConfigPath);
|
|
@@ -21074,7 +21323,11 @@ async function patchOpenclawConfig(openclawConfigPath) {
|
|
|
21074
21323
|
);
|
|
21075
21324
|
}
|
|
21076
21325
|
const hooks = isRecord7(config2.hooks) ? { ...config2.hooks } : {};
|
|
21326
|
+
const existingHookToken = typeof hooks.token === "string" && hooks.token.trim().length > 0 ? hooks.token.trim() : void 0;
|
|
21327
|
+
const preferredHookToken = typeof hookToken === "string" && hookToken.trim().length > 0 ? hookToken.trim() : void 0;
|
|
21328
|
+
const resolvedHookToken = existingHookToken ?? preferredHookToken ?? generateOpenclawHookToken();
|
|
21077
21329
|
hooks.enabled = true;
|
|
21330
|
+
hooks.token = resolvedHookToken;
|
|
21078
21331
|
hooks.allowRequestSessionKey = false;
|
|
21079
21332
|
hooks.allowedSessionKeyPrefixes = normalizeStringArrayWithValue(
|
|
21080
21333
|
hooks.allowedSessionKeyPrefixes,
|
|
@@ -21091,6 +21344,9 @@ async function patchOpenclawConfig(openclawConfigPath) {
|
|
|
21091
21344
|
`,
|
|
21092
21345
|
"utf8"
|
|
21093
21346
|
);
|
|
21347
|
+
return {
|
|
21348
|
+
hookToken: resolvedHookToken
|
|
21349
|
+
};
|
|
21094
21350
|
}
|
|
21095
21351
|
function toDoctorCheck(input) {
|
|
21096
21352
|
return input;
|
|
@@ -21126,8 +21382,8 @@ function parseDoctorPeerAlias(peerAlias) {
|
|
|
21126
21382
|
}
|
|
21127
21383
|
return parsePeerAlias(peerAlias);
|
|
21128
21384
|
}
|
|
21129
|
-
function resolveHookToken(
|
|
21130
|
-
const trimmedOption = optionValue?.trim();
|
|
21385
|
+
async function resolveHookToken(input) {
|
|
21386
|
+
const trimmedOption = input.optionValue?.trim();
|
|
21131
21387
|
if (trimmedOption !== void 0 && trimmedOption.length > 0) {
|
|
21132
21388
|
return trimmedOption;
|
|
21133
21389
|
}
|
|
@@ -21135,6 +21391,12 @@ function resolveHookToken(optionValue) {
|
|
|
21135
21391
|
if (envValue !== void 0 && envValue.length > 0) {
|
|
21136
21392
|
return envValue;
|
|
21137
21393
|
}
|
|
21394
|
+
const existingConfig = await loadRelayRuntimeConfig(
|
|
21395
|
+
input.relayRuntimeConfigPath
|
|
21396
|
+
);
|
|
21397
|
+
if (existingConfig?.openclawHookToken) {
|
|
21398
|
+
return existingConfig.openclawHookToken;
|
|
21399
|
+
}
|
|
21138
21400
|
return void 0;
|
|
21139
21401
|
}
|
|
21140
21402
|
function resolveProbeMessage(optionValue) {
|
|
@@ -21353,17 +21615,28 @@ async function runOpenclawDoctor(options = {}) {
|
|
|
21353
21615
|
);
|
|
21354
21616
|
}
|
|
21355
21617
|
const transformTargetPath = resolveTransformTargetPath(openclawDir);
|
|
21618
|
+
const relayTransformRuntimePath = resolveTransformRuntimePath(openclawDir);
|
|
21619
|
+
const relayTransformPeersPath = resolveTransformPeersPath(openclawDir);
|
|
21356
21620
|
try {
|
|
21357
21621
|
const transformContents = await readFile4(transformTargetPath, "utf8");
|
|
21358
|
-
|
|
21622
|
+
const runtimeContents = await readFile4(relayTransformRuntimePath, "utf8");
|
|
21623
|
+
const peersSnapshotContents = await readFile4(
|
|
21624
|
+
relayTransformPeersPath,
|
|
21625
|
+
"utf8"
|
|
21626
|
+
);
|
|
21627
|
+
if (transformContents.trim().length === 0 || runtimeContents.trim().length === 0 || peersSnapshotContents.trim().length === 0) {
|
|
21359
21628
|
checks.push(
|
|
21360
21629
|
toDoctorCheck({
|
|
21361
21630
|
id: "state.transform",
|
|
21362
21631
|
label: "Relay transform",
|
|
21363
21632
|
status: "fail",
|
|
21364
|
-
message:
|
|
21633
|
+
message: "relay transform artifacts are missing or empty",
|
|
21365
21634
|
remediationHint: "Run: npm install clawdentity --skill",
|
|
21366
|
-
details: {
|
|
21635
|
+
details: {
|
|
21636
|
+
transformTargetPath,
|
|
21637
|
+
relayTransformRuntimePath,
|
|
21638
|
+
relayTransformPeersPath
|
|
21639
|
+
}
|
|
21367
21640
|
})
|
|
21368
21641
|
);
|
|
21369
21642
|
} else {
|
|
@@ -21372,8 +21645,12 @@ async function runOpenclawDoctor(options = {}) {
|
|
|
21372
21645
|
id: "state.transform",
|
|
21373
21646
|
label: "Relay transform",
|
|
21374
21647
|
status: "pass",
|
|
21375
|
-
message: "relay transform
|
|
21376
|
-
details: {
|
|
21648
|
+
message: "relay transform artifacts are present",
|
|
21649
|
+
details: {
|
|
21650
|
+
transformTargetPath,
|
|
21651
|
+
relayTransformRuntimePath,
|
|
21652
|
+
relayTransformPeersPath
|
|
21653
|
+
}
|
|
21377
21654
|
})
|
|
21378
21655
|
);
|
|
21379
21656
|
}
|
|
@@ -21383,19 +21660,25 @@ async function runOpenclawDoctor(options = {}) {
|
|
|
21383
21660
|
id: "state.transform",
|
|
21384
21661
|
label: "Relay transform",
|
|
21385
21662
|
status: "fail",
|
|
21386
|
-
message:
|
|
21663
|
+
message: "missing relay transform artifacts",
|
|
21387
21664
|
remediationHint: "Run: npm install clawdentity --skill",
|
|
21388
|
-
details: {
|
|
21665
|
+
details: {
|
|
21666
|
+
transformTargetPath,
|
|
21667
|
+
relayTransformRuntimePath,
|
|
21668
|
+
relayTransformPeersPath
|
|
21669
|
+
}
|
|
21389
21670
|
})
|
|
21390
21671
|
);
|
|
21391
21672
|
}
|
|
21392
|
-
const openclawConfigPath = resolveOpenclawConfigPath(openclawDir);
|
|
21673
|
+
const openclawConfigPath = resolveOpenclawConfigPath(openclawDir, homeDir);
|
|
21393
21674
|
try {
|
|
21394
21675
|
const openclawConfig = await readJsonFile(openclawConfigPath);
|
|
21395
21676
|
if (!isRecord7(openclawConfig)) {
|
|
21396
21677
|
throw new Error("root");
|
|
21397
21678
|
}
|
|
21398
21679
|
const hooks = isRecord7(openclawConfig.hooks) ? openclawConfig.hooks : {};
|
|
21680
|
+
const hooksEnabled = hooks.enabled === true;
|
|
21681
|
+
const hookToken = typeof hooks.token === "string" && hooks.token.trim().length > 0 ? hooks.token.trim() : void 0;
|
|
21399
21682
|
const mappings = Array.isArray(hooks.mappings) ? hooks.mappings.filter(isRecord7) : [];
|
|
21400
21683
|
const relayMapping = mappings.find(
|
|
21401
21684
|
(mapping) => isRelayHookMapping(mapping)
|
|
@@ -21422,6 +21705,39 @@ async function runOpenclawDoctor(options = {}) {
|
|
|
21422
21705
|
})
|
|
21423
21706
|
);
|
|
21424
21707
|
}
|
|
21708
|
+
if (!hooksEnabled) {
|
|
21709
|
+
checks.push(
|
|
21710
|
+
toDoctorCheck({
|
|
21711
|
+
id: "state.hookToken",
|
|
21712
|
+
label: "OpenClaw hook auth",
|
|
21713
|
+
status: "fail",
|
|
21714
|
+
message: `hooks.enabled is not true in ${openclawConfigPath}`,
|
|
21715
|
+
remediationHint: "Run: clawdentity openclaw setup <agentName> --invite-code <code> and restart OpenClaw",
|
|
21716
|
+
details: { openclawConfigPath }
|
|
21717
|
+
})
|
|
21718
|
+
);
|
|
21719
|
+
} else if (hookToken === void 0) {
|
|
21720
|
+
checks.push(
|
|
21721
|
+
toDoctorCheck({
|
|
21722
|
+
id: "state.hookToken",
|
|
21723
|
+
label: "OpenClaw hook auth",
|
|
21724
|
+
status: "fail",
|
|
21725
|
+
message: `hooks.token is missing in ${openclawConfigPath}`,
|
|
21726
|
+
remediationHint: "Run: clawdentity openclaw setup <agentName> --invite-code <code> and restart OpenClaw",
|
|
21727
|
+
details: { openclawConfigPath }
|
|
21728
|
+
})
|
|
21729
|
+
);
|
|
21730
|
+
} else {
|
|
21731
|
+
checks.push(
|
|
21732
|
+
toDoctorCheck({
|
|
21733
|
+
id: "state.hookToken",
|
|
21734
|
+
label: "OpenClaw hook auth",
|
|
21735
|
+
status: "pass",
|
|
21736
|
+
message: "hooks token is configured",
|
|
21737
|
+
details: { openclawConfigPath }
|
|
21738
|
+
})
|
|
21739
|
+
);
|
|
21740
|
+
}
|
|
21425
21741
|
} catch {
|
|
21426
21742
|
checks.push(
|
|
21427
21743
|
toDoctorCheck({
|
|
@@ -21429,7 +21745,17 @@ async function runOpenclawDoctor(options = {}) {
|
|
|
21429
21745
|
label: "OpenClaw hook mapping",
|
|
21430
21746
|
status: "fail",
|
|
21431
21747
|
message: `unable to read ${openclawConfigPath}`,
|
|
21432
|
-
remediationHint: "Ensure
|
|
21748
|
+
remediationHint: "Ensure the OpenClaw config file exists (OPENCLAW_CONFIG_PATH/CLAWDBOT_CONFIG_PATH, or state dir) and rerun openclaw setup",
|
|
21749
|
+
details: { openclawConfigPath }
|
|
21750
|
+
})
|
|
21751
|
+
);
|
|
21752
|
+
checks.push(
|
|
21753
|
+
toDoctorCheck({
|
|
21754
|
+
id: "state.hookToken",
|
|
21755
|
+
label: "OpenClaw hook auth",
|
|
21756
|
+
status: "fail",
|
|
21757
|
+
message: `unable to read ${openclawConfigPath}`,
|
|
21758
|
+
remediationHint: "Ensure the OpenClaw config file exists (OPENCLAW_CONFIG_PATH/CLAWDBOT_CONFIG_PATH, or state dir) and rerun openclaw setup",
|
|
21433
21759
|
details: { openclawConfigPath }
|
|
21434
21760
|
})
|
|
21435
21761
|
);
|
|
@@ -21473,6 +21799,12 @@ function parseRelayProbeFailure(input) {
|
|
|
21473
21799
|
remediationHint: "Run: clawdentity openclaw setup <agentName> --invite-code <code>"
|
|
21474
21800
|
};
|
|
21475
21801
|
}
|
|
21802
|
+
if (input.status === 405) {
|
|
21803
|
+
return {
|
|
21804
|
+
message: "OpenClaw send-to-peer hook is not enabled for POST requests",
|
|
21805
|
+
remediationHint: "Run: clawdentity openclaw setup <agentName> --invite-code <code>, then restart OpenClaw"
|
|
21806
|
+
};
|
|
21807
|
+
}
|
|
21476
21808
|
if (input.status === 500) {
|
|
21477
21809
|
return {
|
|
21478
21810
|
message: "Relay probe failed inside local relay pipeline",
|
|
@@ -21528,7 +21860,10 @@ async function runOpenclawRelayTest(options) {
|
|
|
21528
21860
|
preflight
|
|
21529
21861
|
};
|
|
21530
21862
|
}
|
|
21531
|
-
const hookToken = resolveHookToken(
|
|
21863
|
+
const hookToken = await resolveHookToken({
|
|
21864
|
+
optionValue: options.hookToken,
|
|
21865
|
+
relayRuntimeConfigPath
|
|
21866
|
+
});
|
|
21532
21867
|
const fetchImpl = options.fetchImpl ?? globalThis.fetch;
|
|
21533
21868
|
if (typeof fetchImpl !== "function") {
|
|
21534
21869
|
return {
|
|
@@ -21620,10 +21955,13 @@ async function setupOpenclawRelayFromInvite(agentName, options) {
|
|
|
21620
21955
|
const normalizedAgentName = assertValidAgentName(agentName);
|
|
21621
21956
|
const homeDir = resolveHomeDir(options.homeDir);
|
|
21622
21957
|
const openclawDir = resolveOpenclawDir(options.openclawDir, homeDir);
|
|
21623
|
-
const openclawConfigPath = resolveOpenclawConfigPath(openclawDir);
|
|
21958
|
+
const openclawConfigPath = resolveOpenclawConfigPath(openclawDir, homeDir);
|
|
21624
21959
|
const transformSource = typeof options.transformSource === "string" && options.transformSource.trim().length > 0 ? options.transformSource.trim() : resolveDefaultTransformSource(openclawDir);
|
|
21625
21960
|
const transformTargetPath = resolveTransformTargetPath(openclawDir);
|
|
21626
21961
|
const relayRuntimeConfigPath = resolveRelayRuntimeConfigPath(homeDir);
|
|
21962
|
+
const existingRelayRuntimeConfig = await loadRelayRuntimeConfig(
|
|
21963
|
+
relayRuntimeConfigPath
|
|
21964
|
+
);
|
|
21627
21965
|
const openclawBaseUrl = await resolveOpenclawBaseUrl2({
|
|
21628
21966
|
optionValue: options.openclawBaseUrl,
|
|
21629
21967
|
relayRuntimeConfigPath
|
|
@@ -21651,22 +21989,75 @@ async function setupOpenclawRelayFromInvite(agentName, options) {
|
|
|
21651
21989
|
}
|
|
21652
21990
|
throw error48;
|
|
21653
21991
|
}
|
|
21654
|
-
await patchOpenclawConfig(
|
|
21992
|
+
const patchedOpenclawConfig = await patchOpenclawConfig(
|
|
21993
|
+
openclawConfigPath,
|
|
21994
|
+
existingRelayRuntimeConfig?.openclawHookToken
|
|
21995
|
+
);
|
|
21655
21996
|
const peersPath = resolvePeersPath(homeDir);
|
|
21656
21997
|
const peers = await loadPeersConfig(peersPath);
|
|
21657
21998
|
peers.peers[peerAlias] = invite.name === void 0 ? { did: invite.did, proxyUrl: invite.proxyUrl } : { did: invite.did, proxyUrl: invite.proxyUrl, name: invite.name };
|
|
21658
21999
|
await savePeersConfig(peersPath, peers);
|
|
22000
|
+
const relayTransformPeersPath = resolveTransformPeersPath(openclawDir);
|
|
22001
|
+
await writeSecureFile3(
|
|
22002
|
+
relayTransformPeersPath,
|
|
22003
|
+
`${JSON.stringify(peers, null, 2)}
|
|
22004
|
+
`
|
|
22005
|
+
);
|
|
22006
|
+
const connectorAssignmentsPath = resolveConnectorAssignmentsPath(homeDir);
|
|
22007
|
+
const connectorAssignments = await loadConnectorAssignments(
|
|
22008
|
+
connectorAssignmentsPath
|
|
22009
|
+
);
|
|
22010
|
+
const connectorPort = allocateConnectorPort(
|
|
22011
|
+
connectorAssignments,
|
|
22012
|
+
normalizedAgentName
|
|
22013
|
+
);
|
|
22014
|
+
const connectorBaseUrl = buildConnectorBaseUrl(
|
|
22015
|
+
CONNECTOR_HOST_LOOPBACK,
|
|
22016
|
+
connectorPort
|
|
22017
|
+
);
|
|
22018
|
+
connectorAssignments.agents[normalizedAgentName] = {
|
|
22019
|
+
connectorBaseUrl,
|
|
22020
|
+
updatedAt: nowIso()
|
|
22021
|
+
};
|
|
22022
|
+
await saveConnectorAssignments(
|
|
22023
|
+
connectorAssignmentsPath,
|
|
22024
|
+
connectorAssignments
|
|
22025
|
+
);
|
|
22026
|
+
const relayTransformRuntimePath = resolveTransformRuntimePath(openclawDir);
|
|
22027
|
+
await writeSecureFile3(
|
|
22028
|
+
relayTransformRuntimePath,
|
|
22029
|
+
`${JSON.stringify(
|
|
22030
|
+
{
|
|
22031
|
+
version: 1,
|
|
22032
|
+
connectorBaseUrl: buildRelayConnectorBaseUrls(connectorPort)[0],
|
|
22033
|
+
connectorBaseUrls: buildRelayConnectorBaseUrls(connectorPort),
|
|
22034
|
+
connectorPath: DEFAULT_CONNECTOR_OUTBOUND_PATH3,
|
|
22035
|
+
peersConfigPath: RELAY_PEERS_FILE_NAME,
|
|
22036
|
+
updatedAt: nowIso()
|
|
22037
|
+
},
|
|
22038
|
+
null,
|
|
22039
|
+
2
|
|
22040
|
+
)}
|
|
22041
|
+
`
|
|
22042
|
+
);
|
|
21659
22043
|
const agentNamePath = resolveOpenclawAgentNamePath(homeDir);
|
|
21660
22044
|
await writeSecureFile3(agentNamePath, `${normalizedAgentName}
|
|
21661
22045
|
`);
|
|
21662
|
-
await saveRelayRuntimeConfig(
|
|
22046
|
+
await saveRelayRuntimeConfig(
|
|
22047
|
+
relayRuntimeConfigPath,
|
|
22048
|
+
openclawBaseUrl,
|
|
22049
|
+
patchedOpenclawConfig.hookToken
|
|
22050
|
+
);
|
|
21663
22051
|
logger8.info("cli.openclaw_setup_completed", {
|
|
21664
22052
|
agentName: normalizedAgentName,
|
|
21665
22053
|
peerAlias,
|
|
21666
22054
|
peerDid: invite.did,
|
|
21667
22055
|
openclawConfigPath,
|
|
21668
22056
|
transformTargetPath,
|
|
22057
|
+
relayTransformRuntimePath,
|
|
22058
|
+
relayTransformPeersPath,
|
|
21669
22059
|
openclawBaseUrl,
|
|
22060
|
+
connectorBaseUrl,
|
|
21670
22061
|
relayRuntimeConfigPath
|
|
21671
22062
|
});
|
|
21672
22063
|
return {
|
|
@@ -21675,7 +22066,10 @@ async function setupOpenclawRelayFromInvite(agentName, options) {
|
|
|
21675
22066
|
peerProxyUrl: invite.proxyUrl,
|
|
21676
22067
|
openclawConfigPath,
|
|
21677
22068
|
transformTargetPath,
|
|
22069
|
+
relayTransformRuntimePath,
|
|
22070
|
+
relayTransformPeersPath,
|
|
21678
22071
|
openclawBaseUrl,
|
|
22072
|
+
connectorBaseUrl,
|
|
21679
22073
|
relayRuntimeConfigPath
|
|
21680
22074
|
};
|
|
21681
22075
|
}
|
|
@@ -21724,6 +22118,13 @@ var createOpenclawCommand = () => {
|
|
|
21724
22118
|
`Updated OpenClaw config: ${result.openclawConfigPath}`
|
|
21725
22119
|
);
|
|
21726
22120
|
writeStdoutLine(`Installed transform: ${result.transformTargetPath}`);
|
|
22121
|
+
writeStdoutLine(
|
|
22122
|
+
`Transform runtime config: ${result.relayTransformRuntimePath}`
|
|
22123
|
+
);
|
|
22124
|
+
writeStdoutLine(
|
|
22125
|
+
`Transform peers snapshot: ${result.relayTransformPeersPath}`
|
|
22126
|
+
);
|
|
22127
|
+
writeStdoutLine(`Connector base URL: ${result.connectorBaseUrl}`);
|
|
21727
22128
|
writeStdoutLine(`OpenClaw base URL: ${result.openclawBaseUrl}`);
|
|
21728
22129
|
writeStdoutLine(
|
|
21729
22130
|
`Relay runtime config: ${result.relayRuntimeConfigPath}`
|
|
@@ -21795,8 +22196,8 @@ var createOpenclawCommand = () => {
|
|
|
21795
22196
|
};
|
|
21796
22197
|
|
|
21797
22198
|
// src/commands/pair.ts
|
|
21798
|
-
import { randomBytes as
|
|
21799
|
-
import { mkdir as mkdir6, readFile as readFile5, writeFile as writeFile6 } from "fs/promises";
|
|
22199
|
+
import { randomBytes as randomBytes4 } from "crypto";
|
|
22200
|
+
import { mkdir as mkdir6, readdir, readFile as readFile5, unlink as unlink2, writeFile as writeFile6 } from "fs/promises";
|
|
21800
22201
|
import { dirname as dirname5, join as join7, resolve } from "path";
|
|
21801
22202
|
import { Command as Command8 } from "commander";
|
|
21802
22203
|
import jsQR from "jsqr";
|
|
@@ -21812,6 +22213,8 @@ var PAIR_CONFIRM_PATH = "/pair/confirm";
|
|
|
21812
22213
|
var OWNER_PAT_HEADER = "x-claw-owner-pat";
|
|
21813
22214
|
var NONCE_SIZE2 = 24;
|
|
21814
22215
|
var PAIRING_TICKET_PREFIX = "clwpair1_";
|
|
22216
|
+
var PAIRING_QR_MAX_AGE_SECONDS = 900;
|
|
22217
|
+
var PAIRING_QR_FILENAME_PATTERN = /-pair-(\d+)\.png$/;
|
|
21815
22218
|
var isRecord8 = (value) => {
|
|
21816
22219
|
return typeof value === "object" && value !== null;
|
|
21817
22220
|
};
|
|
@@ -22120,6 +22523,8 @@ function decodeTicketFromPng(imageBytes) {
|
|
|
22120
22523
|
}
|
|
22121
22524
|
async function persistPairingQr(input) {
|
|
22122
22525
|
const mkdirImpl = input.dependencies.mkdirImpl ?? mkdir6;
|
|
22526
|
+
const readdirImpl = input.dependencies.readdirImpl ?? readdir;
|
|
22527
|
+
const unlinkImpl = input.dependencies.unlinkImpl ?? unlink2;
|
|
22123
22528
|
const writeFileImpl = input.dependencies.writeFileImpl ?? writeFile6;
|
|
22124
22529
|
const getConfigDirImpl = input.dependencies.getConfigDirImpl ?? getConfigDir;
|
|
22125
22530
|
const qrEncodeImpl = input.dependencies.qrEncodeImpl ?? encodeTicketQrPng;
|
|
@@ -22128,6 +22533,37 @@ async function persistPairingQr(input) {
|
|
|
22128
22533
|
baseDir,
|
|
22129
22534
|
`${assertValidAgentName(input.agentName)}-pair-${input.nowSeconds}.png`
|
|
22130
22535
|
);
|
|
22536
|
+
const existingFiles = await readdirImpl(baseDir).catch((error48) => {
|
|
22537
|
+
const nodeError = error48;
|
|
22538
|
+
if (nodeError.code === "ENOENT") {
|
|
22539
|
+
return [];
|
|
22540
|
+
}
|
|
22541
|
+
throw error48;
|
|
22542
|
+
});
|
|
22543
|
+
for (const fileName of existingFiles) {
|
|
22544
|
+
if (typeof fileName !== "string") {
|
|
22545
|
+
continue;
|
|
22546
|
+
}
|
|
22547
|
+
const match2 = PAIRING_QR_FILENAME_PATTERN.exec(fileName);
|
|
22548
|
+
if (!match2) {
|
|
22549
|
+
continue;
|
|
22550
|
+
}
|
|
22551
|
+
const issuedAtSeconds = Number.parseInt(match2[1] ?? "", 10);
|
|
22552
|
+
if (!Number.isInteger(issuedAtSeconds)) {
|
|
22553
|
+
continue;
|
|
22554
|
+
}
|
|
22555
|
+
if (issuedAtSeconds + PAIRING_QR_MAX_AGE_SECONDS > input.nowSeconds) {
|
|
22556
|
+
continue;
|
|
22557
|
+
}
|
|
22558
|
+
const stalePath = join7(baseDir, fileName);
|
|
22559
|
+
await unlinkImpl(stalePath).catch((error48) => {
|
|
22560
|
+
const nodeError = error48;
|
|
22561
|
+
if (nodeError.code === "ENOENT") {
|
|
22562
|
+
return;
|
|
22563
|
+
}
|
|
22564
|
+
throw error48;
|
|
22565
|
+
});
|
|
22566
|
+
}
|
|
22131
22567
|
await mkdirImpl(dirname5(outputPath), { recursive: true });
|
|
22132
22568
|
const imageBytes = await qrEncodeImpl(input.ticket);
|
|
22133
22569
|
await writeFileImpl(outputPath, imageBytes);
|
|
@@ -22164,7 +22600,7 @@ async function startPairing(agentName, options, dependencies = {}) {
|
|
|
22164
22600
|
const fetchImpl = dependencies.fetchImpl ?? fetch;
|
|
22165
22601
|
const resolveConfigImpl = dependencies.resolveConfigImpl ?? resolveConfig;
|
|
22166
22602
|
const nowSecondsImpl = dependencies.nowSecondsImpl ?? (() => Math.floor(Date.now() / 1e3));
|
|
22167
|
-
const nonceFactoryImpl = dependencies.nonceFactoryImpl ?? (() =>
|
|
22603
|
+
const nonceFactoryImpl = dependencies.nonceFactoryImpl ?? (() => randomBytes4(NONCE_SIZE2).toString("base64url"));
|
|
22168
22604
|
const ttlSeconds = parseTtlSeconds(options.ttlSeconds);
|
|
22169
22605
|
const proxyUrl = resolveProxyUrl(options.proxyUrl);
|
|
22170
22606
|
const config2 = await resolveConfigImpl();
|
|
@@ -22231,7 +22667,7 @@ async function startPairing(agentName, options, dependencies = {}) {
|
|
|
22231
22667
|
async function confirmPairing(agentName, options, dependencies = {}) {
|
|
22232
22668
|
const fetchImpl = dependencies.fetchImpl ?? fetch;
|
|
22233
22669
|
const nowSecondsImpl = dependencies.nowSecondsImpl ?? (() => Math.floor(Date.now() / 1e3));
|
|
22234
|
-
const nonceFactoryImpl = dependencies.nonceFactoryImpl ?? (() =>
|
|
22670
|
+
const nonceFactoryImpl = dependencies.nonceFactoryImpl ?? (() => randomBytes4(NONCE_SIZE2).toString("base64url"));
|
|
22235
22671
|
const readFileImpl = dependencies.readFileImpl ?? readFile5;
|
|
22236
22672
|
const qrDecodeImpl = dependencies.qrDecodeImpl ?? decodeTicketFromPng;
|
|
22237
22673
|
const ticketSource = resolveConfirmTicketSource(options);
|
|
@@ -22297,6 +22733,19 @@ async function confirmPairing(agentName, options, dependencies = {}) {
|
|
|
22297
22733
|
);
|
|
22298
22734
|
}
|
|
22299
22735
|
const parsed = parsePairConfirmResponse(responseBody);
|
|
22736
|
+
if (ticketSource.source === "qr-file" && ticketSource.qrFilePath) {
|
|
22737
|
+
const unlinkImpl = dependencies.unlinkImpl ?? unlink2;
|
|
22738
|
+
await unlinkImpl(ticketSource.qrFilePath).catch((error48) => {
|
|
22739
|
+
const nodeError = error48;
|
|
22740
|
+
if (nodeError.code === "ENOENT") {
|
|
22741
|
+
return;
|
|
22742
|
+
}
|
|
22743
|
+
logger9.warn("cli.pair.confirm.qr_cleanup_failed", {
|
|
22744
|
+
path: ticketSource.qrFilePath,
|
|
22745
|
+
reason: error48 instanceof Error && error48.message.length > 0 ? error48.message : "unknown"
|
|
22746
|
+
});
|
|
22747
|
+
});
|
|
22748
|
+
}
|
|
22300
22749
|
return {
|
|
22301
22750
|
...parsed,
|
|
22302
22751
|
proxyUrl
|