clawdentity 0.0.22 → 0.0.24
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/README.md +97 -0
- package/dist/bin.js +531 -136
- package/dist/index.js +531 -136
- package/dist/postinstall.js +0 -0
- package/package.json +17 -16
- package/postinstall.mjs +16 -7
- package/skill-bundle/openclaw-skill/skill/SKILL.md +44 -7
- package/skill-bundle/openclaw-skill/skill/references/clawdentity-environment.md +13 -0
package/dist/bin.js
CHANGED
|
@@ -17110,11 +17110,24 @@ import { Command as Command11 } from "commander";
|
|
|
17110
17110
|
import { Command } from "commander";
|
|
17111
17111
|
|
|
17112
17112
|
// src/config/manager.ts
|
|
17113
|
-
import {
|
|
17113
|
+
import { readFileSync } from "fs";
|
|
17114
|
+
import {
|
|
17115
|
+
chmod,
|
|
17116
|
+
cp,
|
|
17117
|
+
mkdir,
|
|
17118
|
+
readdir,
|
|
17119
|
+
readFile,
|
|
17120
|
+
stat,
|
|
17121
|
+
writeFile
|
|
17122
|
+
} from "fs/promises";
|
|
17114
17123
|
import { homedir } from "os";
|
|
17115
17124
|
import { dirname, join as join2 } from "path";
|
|
17116
17125
|
var DEFAULT_REGISTRY_URL = "https://registry.clawdentity.com";
|
|
17117
|
-
var
|
|
17126
|
+
var DEFAULT_DEV_REGISTRY_URL = "https://dev.registry.clawdentity.com";
|
|
17127
|
+
var DEFAULT_LOCAL_REGISTRY_URL = "http://127.0.0.1:8788";
|
|
17128
|
+
var CONFIG_ROOT_DIR = ".clawdentity";
|
|
17129
|
+
var CONFIG_STATES_DIR = "states";
|
|
17130
|
+
var CONFIG_ROUTER_FILE = "router.json";
|
|
17118
17131
|
var CONFIG_FILE = "config.json";
|
|
17119
17132
|
var CACHE_DIR = "cache";
|
|
17120
17133
|
var FILE_MODE = 384;
|
|
@@ -17130,9 +17143,26 @@ var LEGACY_ENV_KEY_MAP = {
|
|
|
17130
17143
|
var DEFAULT_CONFIG = {
|
|
17131
17144
|
registryUrl: DEFAULT_REGISTRY_URL
|
|
17132
17145
|
};
|
|
17146
|
+
var STATE_KIND_BY_REGISTRY_HOST = {
|
|
17147
|
+
"registry.clawdentity.com": "prod",
|
|
17148
|
+
"dev.registry.clawdentity.com": "dev"
|
|
17149
|
+
};
|
|
17150
|
+
var LOCAL_REGISTRY_HOSTS = /* @__PURE__ */ new Set([
|
|
17151
|
+
"localhost",
|
|
17152
|
+
"127.0.0.1",
|
|
17153
|
+
"host.docker.internal"
|
|
17154
|
+
]);
|
|
17155
|
+
var LEGACY_ROOT_ENTRIES = /* @__PURE__ */ new Set([CONFIG_STATES_DIR, CONFIG_ROUTER_FILE]);
|
|
17133
17156
|
var isConfigObject = (value) => {
|
|
17134
17157
|
return typeof value === "object" && value !== null;
|
|
17135
17158
|
};
|
|
17159
|
+
var parseNonEmptyString2 = (value) => {
|
|
17160
|
+
if (typeof value !== "string") {
|
|
17161
|
+
return void 0;
|
|
17162
|
+
}
|
|
17163
|
+
const trimmed = value.trim();
|
|
17164
|
+
return trimmed.length > 0 ? trimmed : void 0;
|
|
17165
|
+
};
|
|
17136
17166
|
var normalizeConfig = (raw) => {
|
|
17137
17167
|
if (!isConfigObject(raw)) {
|
|
17138
17168
|
return { ...DEFAULT_CONFIG };
|
|
@@ -17154,17 +17184,196 @@ var normalizeConfig = (raw) => {
|
|
|
17154
17184
|
}
|
|
17155
17185
|
return config2;
|
|
17156
17186
|
};
|
|
17157
|
-
var
|
|
17158
|
-
|
|
17159
|
-
|
|
17160
|
-
var
|
|
17187
|
+
var isCliStateKind = (value) => {
|
|
17188
|
+
return value === "prod" || value === "dev" || value === "local";
|
|
17189
|
+
};
|
|
17190
|
+
var resolveHomeDir = (options) => {
|
|
17191
|
+
const configured = parseNonEmptyString2(options?.homeDir);
|
|
17192
|
+
return configured ?? homedir();
|
|
17193
|
+
};
|
|
17194
|
+
var getConfigRootDir = (options) => {
|
|
17195
|
+
return join2(resolveHomeDir(options), CONFIG_ROOT_DIR);
|
|
17196
|
+
};
|
|
17197
|
+
var getConfigStatesDir = (options) => {
|
|
17198
|
+
return join2(getConfigRootDir(options), CONFIG_STATES_DIR);
|
|
17199
|
+
};
|
|
17200
|
+
var getRouterFilePath = (options) => {
|
|
17201
|
+
return join2(getConfigRootDir(options), CONFIG_ROUTER_FILE);
|
|
17202
|
+
};
|
|
17203
|
+
var readRouterSync = (options) => {
|
|
17204
|
+
try {
|
|
17205
|
+
const raw = readFileSync(getRouterFilePath(options), "utf-8");
|
|
17206
|
+
const parsed = JSON.parse(raw);
|
|
17207
|
+
if (!isConfigObject(parsed)) {
|
|
17208
|
+
return {};
|
|
17209
|
+
}
|
|
17210
|
+
const lastRegistryUrl = parseNonEmptyString2(parsed.lastRegistryUrl);
|
|
17211
|
+
const lastState = isCliStateKind(parsed.lastState) ? parsed.lastState : void 0;
|
|
17212
|
+
const migratedLegacyState = parsed.migratedLegacyState === true;
|
|
17213
|
+
return {
|
|
17214
|
+
lastRegistryUrl,
|
|
17215
|
+
lastState,
|
|
17216
|
+
migratedLegacyState
|
|
17217
|
+
};
|
|
17218
|
+
} catch {
|
|
17219
|
+
return {};
|
|
17220
|
+
}
|
|
17221
|
+
};
|
|
17222
|
+
var getRegistryUrlOverrideFromEnv = () => {
|
|
17223
|
+
const envCandidates = [
|
|
17224
|
+
process.env.CLAWDENTITY_REGISTRY_URL,
|
|
17225
|
+
process.env.CLAWDENTITY_REGISTRY
|
|
17226
|
+
];
|
|
17227
|
+
return envCandidates.find((value) => {
|
|
17228
|
+
return typeof value === "string" && value.trim().length > 0;
|
|
17229
|
+
});
|
|
17230
|
+
};
|
|
17231
|
+
var resolveStateKindFromRegistryUrl = (registryUrl) => {
|
|
17232
|
+
try {
|
|
17233
|
+
const host = new URL(registryUrl).hostname.trim().toLowerCase();
|
|
17234
|
+
const mapped = STATE_KIND_BY_REGISTRY_HOST[host];
|
|
17235
|
+
if (mapped) {
|
|
17236
|
+
return mapped;
|
|
17237
|
+
}
|
|
17238
|
+
if (LOCAL_REGISTRY_HOSTS.has(host)) {
|
|
17239
|
+
return "local";
|
|
17240
|
+
}
|
|
17241
|
+
return "prod";
|
|
17242
|
+
} catch {
|
|
17243
|
+
return "prod";
|
|
17244
|
+
}
|
|
17245
|
+
};
|
|
17246
|
+
var defaultRegistryUrlForState = (state) => {
|
|
17247
|
+
switch (state) {
|
|
17248
|
+
case "dev":
|
|
17249
|
+
return DEFAULT_DEV_REGISTRY_URL;
|
|
17250
|
+
case "local":
|
|
17251
|
+
return DEFAULT_LOCAL_REGISTRY_URL;
|
|
17252
|
+
default:
|
|
17253
|
+
return DEFAULT_REGISTRY_URL;
|
|
17254
|
+
}
|
|
17255
|
+
};
|
|
17256
|
+
var resolveStateSelection = (options) => {
|
|
17257
|
+
const hintedRegistryUrl = parseNonEmptyString2(options?.registryUrlHint);
|
|
17258
|
+
if (hintedRegistryUrl) {
|
|
17259
|
+
return {
|
|
17260
|
+
stateKind: resolveStateKindFromRegistryUrl(hintedRegistryUrl),
|
|
17261
|
+
registryUrl: hintedRegistryUrl
|
|
17262
|
+
};
|
|
17263
|
+
}
|
|
17264
|
+
const envRegistryUrl = getRegistryUrlOverrideFromEnv();
|
|
17265
|
+
if (envRegistryUrl) {
|
|
17266
|
+
return {
|
|
17267
|
+
stateKind: resolveStateKindFromRegistryUrl(envRegistryUrl),
|
|
17268
|
+
registryUrl: envRegistryUrl
|
|
17269
|
+
};
|
|
17270
|
+
}
|
|
17271
|
+
const router = readRouterSync(options);
|
|
17272
|
+
if (router.lastRegistryUrl) {
|
|
17273
|
+
return {
|
|
17274
|
+
stateKind: resolveStateKindFromRegistryUrl(router.lastRegistryUrl),
|
|
17275
|
+
registryUrl: router.lastRegistryUrl
|
|
17276
|
+
};
|
|
17277
|
+
}
|
|
17278
|
+
if (router.lastState) {
|
|
17279
|
+
return {
|
|
17280
|
+
stateKind: router.lastState,
|
|
17281
|
+
registryUrl: defaultRegistryUrlForState(router.lastState)
|
|
17282
|
+
};
|
|
17283
|
+
}
|
|
17284
|
+
return {
|
|
17285
|
+
stateKind: "prod",
|
|
17286
|
+
registryUrl: DEFAULT_REGISTRY_URL
|
|
17287
|
+
};
|
|
17288
|
+
};
|
|
17289
|
+
var pathExists = async (path) => {
|
|
17290
|
+
try {
|
|
17291
|
+
await stat(path);
|
|
17292
|
+
return true;
|
|
17293
|
+
} catch (error48) {
|
|
17294
|
+
const nodeError = error48;
|
|
17295
|
+
if (nodeError.code === "ENOENT") {
|
|
17296
|
+
return false;
|
|
17297
|
+
}
|
|
17298
|
+
throw error48;
|
|
17299
|
+
}
|
|
17300
|
+
};
|
|
17161
17301
|
var writeSecureFile = async (filePath, value) => {
|
|
17162
17302
|
const targetDirectory = dirname(filePath);
|
|
17163
17303
|
await mkdir(targetDirectory, { recursive: true });
|
|
17164
17304
|
await writeFile(filePath, value, "utf-8");
|
|
17165
17305
|
await chmod(filePath, FILE_MODE);
|
|
17166
17306
|
};
|
|
17307
|
+
var writeRouter = async (router, options) => {
|
|
17308
|
+
const payload = {};
|
|
17309
|
+
if (router.lastRegistryUrl) {
|
|
17310
|
+
payload.lastRegistryUrl = router.lastRegistryUrl;
|
|
17311
|
+
}
|
|
17312
|
+
if (router.lastState) {
|
|
17313
|
+
payload.lastState = router.lastState;
|
|
17314
|
+
}
|
|
17315
|
+
if (router.migratedLegacyState === true) {
|
|
17316
|
+
payload.migratedLegacyState = true;
|
|
17317
|
+
}
|
|
17318
|
+
await writeSecureFile(
|
|
17319
|
+
getRouterFilePath(options),
|
|
17320
|
+
`${JSON.stringify(payload)}
|
|
17321
|
+
`
|
|
17322
|
+
);
|
|
17323
|
+
};
|
|
17324
|
+
var ensureStateLayoutMigrated = async (options) => {
|
|
17325
|
+
const router = readRouterSync(options);
|
|
17326
|
+
if (router.migratedLegacyState === true) {
|
|
17327
|
+
return;
|
|
17328
|
+
}
|
|
17329
|
+
let entries;
|
|
17330
|
+
try {
|
|
17331
|
+
entries = await readdir(getConfigRootDir(options), {
|
|
17332
|
+
withFileTypes: true
|
|
17333
|
+
});
|
|
17334
|
+
} catch (error48) {
|
|
17335
|
+
const nodeError = error48;
|
|
17336
|
+
if (nodeError.code === "ENOENT") {
|
|
17337
|
+
return;
|
|
17338
|
+
}
|
|
17339
|
+
throw error48;
|
|
17340
|
+
}
|
|
17341
|
+
const legacyEntries = entries.filter((entry) => {
|
|
17342
|
+
return !LEGACY_ROOT_ENTRIES.has(entry.name);
|
|
17343
|
+
});
|
|
17344
|
+
if (legacyEntries.length > 0) {
|
|
17345
|
+
const prodStateDir = join2(getConfigStatesDir(options), "prod");
|
|
17346
|
+
await mkdir(prodStateDir, { recursive: true });
|
|
17347
|
+
for (const entry of legacyEntries) {
|
|
17348
|
+
const sourcePath = join2(getConfigRootDir(options), entry.name);
|
|
17349
|
+
const targetPath = join2(prodStateDir, entry.name);
|
|
17350
|
+
if (await pathExists(targetPath)) {
|
|
17351
|
+
continue;
|
|
17352
|
+
}
|
|
17353
|
+
await cp(sourcePath, targetPath, {
|
|
17354
|
+
recursive: true,
|
|
17355
|
+
errorOnExist: false
|
|
17356
|
+
});
|
|
17357
|
+
}
|
|
17358
|
+
}
|
|
17359
|
+
await writeRouter(
|
|
17360
|
+
{
|
|
17361
|
+
lastRegistryUrl: router.lastRegistryUrl ?? DEFAULT_REGISTRY_URL,
|
|
17362
|
+
lastState: router.lastState ?? "prod",
|
|
17363
|
+
migratedLegacyState: true
|
|
17364
|
+
},
|
|
17365
|
+
options
|
|
17366
|
+
);
|
|
17367
|
+
};
|
|
17368
|
+
var getConfigDir = (options) => {
|
|
17369
|
+
const selection = resolveStateSelection(options);
|
|
17370
|
+
return join2(getConfigStatesDir(options), selection.stateKind);
|
|
17371
|
+
};
|
|
17372
|
+
var getConfigFilePath = (options) => join2(getConfigDir(options), CONFIG_FILE);
|
|
17373
|
+
var getCacheDir = (options) => join2(getConfigDir(options), CACHE_DIR);
|
|
17374
|
+
var getCacheFilePath = (fileName, options) => join2(getCacheDir(options), fileName);
|
|
17167
17375
|
var readConfig = async () => {
|
|
17376
|
+
await ensureStateLayoutMigrated();
|
|
17168
17377
|
try {
|
|
17169
17378
|
const configContents = await readFile(getConfigFilePath(), "utf-8");
|
|
17170
17379
|
return normalizeConfig(JSON.parse(configContents));
|
|
@@ -17190,11 +17399,21 @@ var resolveConfig = async () => {
|
|
|
17190
17399
|
return config2;
|
|
17191
17400
|
};
|
|
17192
17401
|
var writeConfig = async (config2) => {
|
|
17402
|
+
await ensureStateLayoutMigrated();
|
|
17403
|
+
const selection = resolveStateSelection({
|
|
17404
|
+
registryUrlHint: config2.registryUrl
|
|
17405
|
+
});
|
|
17193
17406
|
await writeSecureFile(
|
|
17194
|
-
getConfigFilePath(),
|
|
17407
|
+
getConfigFilePath({ registryUrlHint: config2.registryUrl }),
|
|
17195
17408
|
`${JSON.stringify(config2, null, 2)}
|
|
17196
17409
|
`
|
|
17197
17410
|
);
|
|
17411
|
+
const currentRouter = readRouterSync();
|
|
17412
|
+
await writeRouter({
|
|
17413
|
+
lastRegistryUrl: selection.registryUrl,
|
|
17414
|
+
lastState: selection.stateKind,
|
|
17415
|
+
migratedLegacyState: currentRouter.migratedLegacyState === true
|
|
17416
|
+
});
|
|
17198
17417
|
};
|
|
17199
17418
|
var getConfigValue = async (key) => {
|
|
17200
17419
|
const config2 = await resolveConfig();
|
|
@@ -17208,6 +17427,7 @@ var setConfigValue = async (key, value) => {
|
|
|
17208
17427
|
});
|
|
17209
17428
|
};
|
|
17210
17429
|
var readCacheFile = async (fileName) => {
|
|
17430
|
+
await ensureStateLayoutMigrated();
|
|
17211
17431
|
try {
|
|
17212
17432
|
return await readFile(getCacheFilePath(fileName), "utf-8");
|
|
17213
17433
|
} catch (error48) {
|
|
@@ -17219,6 +17439,7 @@ var readCacheFile = async (fileName) => {
|
|
|
17219
17439
|
}
|
|
17220
17440
|
};
|
|
17221
17441
|
var writeCacheFile = async (fileName, value) => {
|
|
17442
|
+
await ensureStateLayoutMigrated();
|
|
17222
17443
|
await writeSecureFile(getCacheFilePath(fileName), value);
|
|
17223
17444
|
};
|
|
17224
17445
|
|
|
@@ -17259,14 +17480,14 @@ function createCliError(code, message2) {
|
|
|
17259
17480
|
status: 400
|
|
17260
17481
|
});
|
|
17261
17482
|
}
|
|
17262
|
-
function
|
|
17483
|
+
function parseNonEmptyString3(value) {
|
|
17263
17484
|
if (typeof value !== "string") {
|
|
17264
17485
|
return "";
|
|
17265
17486
|
}
|
|
17266
17487
|
return value.trim();
|
|
17267
17488
|
}
|
|
17268
17489
|
function resolveBootstrapRegistryUrl(input) {
|
|
17269
|
-
const candidate =
|
|
17490
|
+
const candidate = parseNonEmptyString3(input.overrideRegistryUrl) || input.configRegistryUrl;
|
|
17270
17491
|
try {
|
|
17271
17492
|
return new URL(candidate).toString();
|
|
17272
17493
|
} catch {
|
|
@@ -17292,12 +17513,12 @@ function parseBootstrapResponse(payload) {
|
|
|
17292
17513
|
"Bootstrap response is invalid"
|
|
17293
17514
|
);
|
|
17294
17515
|
}
|
|
17295
|
-
const humanId =
|
|
17296
|
-
const humanDid =
|
|
17297
|
-
const humanDisplayName =
|
|
17298
|
-
const apiKeyId =
|
|
17299
|
-
const apiKeyName =
|
|
17300
|
-
const apiKeyToken =
|
|
17516
|
+
const humanId = parseNonEmptyString3(human.id);
|
|
17517
|
+
const humanDid = parseNonEmptyString3(human.did);
|
|
17518
|
+
const humanDisplayName = parseNonEmptyString3(human.displayName);
|
|
17519
|
+
const apiKeyId = parseNonEmptyString3(apiKey.id);
|
|
17520
|
+
const apiKeyName = parseNonEmptyString3(apiKey.name);
|
|
17521
|
+
const apiKeyToken = parseNonEmptyString3(apiKey.token);
|
|
17301
17522
|
if (humanId.length === 0 || humanDid.length === 0 || humanDisplayName.length === 0 || apiKeyId.length === 0 || apiKeyName.length === 0 || apiKeyToken.length === 0) {
|
|
17302
17523
|
throw createCliError(
|
|
17303
17524
|
"CLI_ADMIN_BOOTSTRAP_INVALID_RESPONSE",
|
|
@@ -17335,7 +17556,7 @@ function mapBootstrapFailureMessage(payload) {
|
|
|
17335
17556
|
return "Admin bootstrap request failed";
|
|
17336
17557
|
}
|
|
17337
17558
|
async function bootstrapAdmin(options, dependencies = {}) {
|
|
17338
|
-
const bootstrapSecret =
|
|
17559
|
+
const bootstrapSecret = parseNonEmptyString3(options.bootstrapSecret);
|
|
17339
17560
|
if (bootstrapSecret.length === 0) {
|
|
17340
17561
|
throw createCliError(
|
|
17341
17562
|
"CLI_ADMIN_BOOTSTRAP_SECRET_REQUIRED",
|
|
@@ -17358,8 +17579,8 @@ async function bootstrapAdmin(options, dependencies = {}) {
|
|
|
17358
17579
|
"x-bootstrap-secret": bootstrapSecret
|
|
17359
17580
|
},
|
|
17360
17581
|
body: JSON.stringify({
|
|
17361
|
-
displayName:
|
|
17362
|
-
apiKeyName:
|
|
17582
|
+
displayName: parseNonEmptyString3(options.displayName) || void 0,
|
|
17583
|
+
apiKeyName: parseNonEmptyString3(options.apiKeyName) || void 0
|
|
17363
17584
|
})
|
|
17364
17585
|
});
|
|
17365
17586
|
} catch (error48) {
|
|
@@ -17470,7 +17691,7 @@ var FILE_MODE2 = 384;
|
|
|
17470
17691
|
var isRecord2 = (value) => {
|
|
17471
17692
|
return typeof value === "object" && value !== null;
|
|
17472
17693
|
};
|
|
17473
|
-
var
|
|
17694
|
+
var parseNonEmptyString4 = (value) => {
|
|
17474
17695
|
if (typeof value !== "string") {
|
|
17475
17696
|
return "";
|
|
17476
17697
|
}
|
|
@@ -17540,7 +17761,7 @@ var readAgentIdentity = async (agentName) => {
|
|
|
17540
17761
|
`Agent "${agentName}" has invalid ${IDENTITY_FILE_NAME} (missing did)`
|
|
17541
17762
|
);
|
|
17542
17763
|
}
|
|
17543
|
-
const registryUrl =
|
|
17764
|
+
const registryUrl = parseNonEmptyString4(parsed.registryUrl);
|
|
17544
17765
|
return {
|
|
17545
17766
|
did,
|
|
17546
17767
|
registryUrl: registryUrl.length > 0 ? registryUrl : void 0
|
|
@@ -17595,7 +17816,7 @@ var readAgentRegistryAuth = async (agentName) => {
|
|
|
17595
17816
|
`Agent "${agentName}" has invalid ${REGISTRY_AUTH_FILE_NAME}`
|
|
17596
17817
|
);
|
|
17597
17818
|
}
|
|
17598
|
-
const refreshToken =
|
|
17819
|
+
const refreshToken = parseNonEmptyString4(parsed.refreshToken);
|
|
17599
17820
|
if (refreshToken.length === 0) {
|
|
17600
17821
|
throw new Error(
|
|
17601
17822
|
`Agent "${agentName}" has invalid ${REGISTRY_AUTH_FILE_NAME} (missing refreshToken)`
|
|
@@ -18120,7 +18341,7 @@ var logger4 = createLogger({ service: "cli", module: "api-key" });
|
|
|
18120
18341
|
var isRecord3 = (value) => {
|
|
18121
18342
|
return typeof value === "object" && value !== null;
|
|
18122
18343
|
};
|
|
18123
|
-
function
|
|
18344
|
+
function parseNonEmptyString5(value) {
|
|
18124
18345
|
if (typeof value !== "string") {
|
|
18125
18346
|
return "";
|
|
18126
18347
|
}
|
|
@@ -18134,7 +18355,7 @@ function createCliError2(code, message2) {
|
|
|
18134
18355
|
});
|
|
18135
18356
|
}
|
|
18136
18357
|
function resolveRegistryUrl(input) {
|
|
18137
|
-
const candidate =
|
|
18358
|
+
const candidate = parseNonEmptyString5(input.overrideRegistryUrl) || input.configRegistryUrl;
|
|
18138
18359
|
try {
|
|
18139
18360
|
return new URL(candidate).toString();
|
|
18140
18361
|
} catch {
|
|
@@ -18202,10 +18423,10 @@ function parseApiKeyMetadata(payload) {
|
|
|
18202
18423
|
"API key response is invalid"
|
|
18203
18424
|
);
|
|
18204
18425
|
}
|
|
18205
|
-
const id =
|
|
18206
|
-
const name =
|
|
18426
|
+
const id = parseNonEmptyString5(payload.id);
|
|
18427
|
+
const name = parseNonEmptyString5(payload.name);
|
|
18207
18428
|
const status = payload.status;
|
|
18208
|
-
const createdAt =
|
|
18429
|
+
const createdAt = parseNonEmptyString5(payload.createdAt);
|
|
18209
18430
|
const lastUsedAt = payload.lastUsedAt;
|
|
18210
18431
|
if (id.length === 0 || name.length === 0 || status !== "active" && status !== "revoked" || createdAt.length === 0 || lastUsedAt !== null && typeof lastUsedAt !== "string") {
|
|
18211
18432
|
throw createCliError2(
|
|
@@ -18229,7 +18450,7 @@ function parseApiKeyCreateResponse(payload) {
|
|
|
18229
18450
|
);
|
|
18230
18451
|
}
|
|
18231
18452
|
const metadata = parseApiKeyMetadata(payload.apiKey);
|
|
18232
|
-
const token =
|
|
18453
|
+
const token = parseNonEmptyString5(payload.apiKey.token);
|
|
18233
18454
|
if (token.length === 0) {
|
|
18234
18455
|
throw createCliError2(
|
|
18235
18456
|
"CLI_API_KEY_INVALID_RESPONSE",
|
|
@@ -18301,7 +18522,7 @@ async function createApiKey(options, dependencies = {}) {
|
|
|
18301
18522
|
"content-type": "application/json"
|
|
18302
18523
|
},
|
|
18303
18524
|
body: JSON.stringify({
|
|
18304
|
-
name:
|
|
18525
|
+
name: parseNonEmptyString5(options.name) || void 0
|
|
18305
18526
|
})
|
|
18306
18527
|
}
|
|
18307
18528
|
});
|
|
@@ -18445,7 +18666,7 @@ import { Command as Command4 } from "commander";
|
|
|
18445
18666
|
function isRecord4(value) {
|
|
18446
18667
|
return typeof value === "object" && value !== null;
|
|
18447
18668
|
}
|
|
18448
|
-
function
|
|
18669
|
+
function parseNonEmptyString6(value) {
|
|
18449
18670
|
if (typeof value !== "string") {
|
|
18450
18671
|
return "";
|
|
18451
18672
|
}
|
|
@@ -18503,7 +18724,7 @@ function parseMetadataPayload(payload, fallbackRegistryUrl) {
|
|
|
18503
18724
|
"Registry metadata response is invalid"
|
|
18504
18725
|
);
|
|
18505
18726
|
}
|
|
18506
|
-
const proxyUrlRaw =
|
|
18727
|
+
const proxyUrlRaw = parseNonEmptyString6(payload.proxyUrl);
|
|
18507
18728
|
if (proxyUrlRaw.length === 0) {
|
|
18508
18729
|
throw createCliError3(
|
|
18509
18730
|
"CLI_REGISTRY_METADATA_INVALID_RESPONSE",
|
|
@@ -18511,10 +18732,10 @@ function parseMetadataPayload(payload, fallbackRegistryUrl) {
|
|
|
18511
18732
|
);
|
|
18512
18733
|
}
|
|
18513
18734
|
const proxyUrl = parseUrl(proxyUrlRaw, "Proxy URL").toString();
|
|
18514
|
-
const registryUrlRaw =
|
|
18735
|
+
const registryUrlRaw = parseNonEmptyString6(payload.registryUrl);
|
|
18515
18736
|
const registryUrl = registryUrlRaw.length > 0 ? parseUrl(registryUrlRaw, "Registry URL").toString() : normalizeRegistryUrl(fallbackRegistryUrl);
|
|
18516
|
-
const environment =
|
|
18517
|
-
const version2 =
|
|
18737
|
+
const environment = parseNonEmptyString6(payload.environment);
|
|
18738
|
+
const version2 = parseNonEmptyString6(payload.version);
|
|
18518
18739
|
return {
|
|
18519
18740
|
proxyUrl,
|
|
18520
18741
|
registryUrl,
|
|
@@ -18622,28 +18843,35 @@ var createConfigCommand = (dependencies = {}) => {
|
|
|
18622
18843
|
);
|
|
18623
18844
|
configCommand.command("init").description("Initialize local config file").option("--registry-url <url>", "Initialize config with registry URL").action(
|
|
18624
18845
|
withErrorHandling("config init", async (options) => {
|
|
18625
|
-
const
|
|
18846
|
+
const config2 = await readConfig();
|
|
18847
|
+
const requestedRegistryUrl = options.registryUrl ?? getEnvRegistryUrlOverride() ?? config2.registryUrl;
|
|
18848
|
+
const normalizedRegistryUrl = normalizeRegistryUrl(requestedRegistryUrl);
|
|
18849
|
+
const requestedConfigFilePath = getConfigFilePath({
|
|
18850
|
+
registryUrlHint: normalizedRegistryUrl
|
|
18851
|
+
});
|
|
18626
18852
|
try {
|
|
18627
|
-
await access2(
|
|
18628
|
-
writeStdoutLine(
|
|
18853
|
+
await access2(requestedConfigFilePath);
|
|
18854
|
+
writeStdoutLine(
|
|
18855
|
+
`Config already exists at ${requestedConfigFilePath}`
|
|
18856
|
+
);
|
|
18629
18857
|
return;
|
|
18630
18858
|
} catch (error48) {
|
|
18631
18859
|
if (!isNotFoundError(error48)) {
|
|
18632
18860
|
throw error48;
|
|
18633
18861
|
}
|
|
18634
18862
|
}
|
|
18635
|
-
const config2 = await readConfig();
|
|
18636
|
-
const requestedRegistryUrl = options.registryUrl ?? getEnvRegistryUrlOverride() ?? config2.registryUrl;
|
|
18637
|
-
const normalizedRegistryUrl = normalizeRegistryUrl(requestedRegistryUrl);
|
|
18638
18863
|
const metadata = await fetchRegistryMetadata(normalizedRegistryUrl, {
|
|
18639
18864
|
fetchImpl: dependencies.fetchImpl
|
|
18640
18865
|
});
|
|
18866
|
+
const targetConfigFilePath = getConfigFilePath({
|
|
18867
|
+
registryUrlHint: metadata.registryUrl
|
|
18868
|
+
});
|
|
18641
18869
|
await writeConfig({
|
|
18642
18870
|
...config2,
|
|
18643
18871
|
registryUrl: metadata.registryUrl,
|
|
18644
18872
|
proxyUrl: metadata.proxyUrl
|
|
18645
18873
|
});
|
|
18646
|
-
writeStdoutLine(`Initialized config at ${
|
|
18874
|
+
writeStdoutLine(`Initialized config at ${targetConfigFilePath}`);
|
|
18647
18875
|
writeStdoutLine(
|
|
18648
18876
|
JSON.stringify(
|
|
18649
18877
|
maskApiKey({
|
|
@@ -20571,7 +20799,7 @@ function createCliError4(code, message2, details) {
|
|
|
20571
20799
|
details
|
|
20572
20800
|
});
|
|
20573
20801
|
}
|
|
20574
|
-
function
|
|
20802
|
+
function parseNonEmptyString7(value, label) {
|
|
20575
20803
|
if (typeof value !== "string") {
|
|
20576
20804
|
throw createCliError4(
|
|
20577
20805
|
"CLI_CONNECTOR_INVALID_INPUT",
|
|
@@ -20594,7 +20822,7 @@ function parseNonEmptyString6(value, label) {
|
|
|
20594
20822
|
return trimmed;
|
|
20595
20823
|
}
|
|
20596
20824
|
function parseAgentDid(value) {
|
|
20597
|
-
const did =
|
|
20825
|
+
const did = parseNonEmptyString7(value, "agent did");
|
|
20598
20826
|
if (!did.startsWith("did:claw:agent:")) {
|
|
20599
20827
|
throw createCliError4(
|
|
20600
20828
|
"CLI_CONNECTOR_INVALID_AGENT_IDENTITY",
|
|
@@ -20806,7 +21034,7 @@ function parseRegistryAuth(rawRegistryAuth) {
|
|
|
20806
21034
|
"CLI_CONNECTOR_INVALID_REGISTRY_AUTH",
|
|
20807
21035
|
"Agent registry auth is invalid for connector startup"
|
|
20808
21036
|
);
|
|
20809
|
-
const refreshToken =
|
|
21037
|
+
const refreshToken = parseNonEmptyString7(parsed.refreshToken, "refreshToken");
|
|
20810
21038
|
const accessToken = typeof parsed.accessToken === "string" && parsed.accessToken.trim().length > 0 ? parsed.accessToken.trim() : void 0;
|
|
20811
21039
|
const accessExpiresAt = typeof parsed.accessExpiresAt === "string" && parsed.accessExpiresAt.trim().length > 0 ? parsed.accessExpiresAt.trim() : void 0;
|
|
20812
21040
|
const refreshExpiresAt = typeof parsed.refreshExpiresAt === "string" && parsed.refreshExpiresAt.trim().length > 0 ? parsed.refreshExpiresAt.trim() : void 0;
|
|
@@ -21381,7 +21609,7 @@ var logger7 = createLogger({ service: "cli", module: "invite" });
|
|
|
21381
21609
|
var isRecord8 = (value) => {
|
|
21382
21610
|
return typeof value === "object" && value !== null;
|
|
21383
21611
|
};
|
|
21384
|
-
function
|
|
21612
|
+
function parseNonEmptyString8(value) {
|
|
21385
21613
|
if (typeof value !== "string") {
|
|
21386
21614
|
return "";
|
|
21387
21615
|
}
|
|
@@ -21409,7 +21637,7 @@ function normalizeProxyUrl(value) {
|
|
|
21409
21637
|
}
|
|
21410
21638
|
}
|
|
21411
21639
|
function resolveRegistryUrl2(input) {
|
|
21412
|
-
const candidate =
|
|
21640
|
+
const candidate = parseNonEmptyString8(input.overrideRegistryUrl) || input.configRegistryUrl;
|
|
21413
21641
|
return normalizeRegistryUrl(candidate);
|
|
21414
21642
|
}
|
|
21415
21643
|
function requireApiKey2(config2) {
|
|
@@ -21514,7 +21742,7 @@ function parseInviteRecord(payload) {
|
|
|
21514
21742
|
);
|
|
21515
21743
|
}
|
|
21516
21744
|
const source = isRecord8(payload.invite) ? payload.invite : payload;
|
|
21517
|
-
const code =
|
|
21745
|
+
const code = parseNonEmptyString8(source.code);
|
|
21518
21746
|
if (code.length === 0) {
|
|
21519
21747
|
throw createCliError5(
|
|
21520
21748
|
"CLI_INVITE_CREATE_INVALID_RESPONSE",
|
|
@@ -21524,11 +21752,11 @@ function parseInviteRecord(payload) {
|
|
|
21524
21752
|
const invite = {
|
|
21525
21753
|
code
|
|
21526
21754
|
};
|
|
21527
|
-
const id =
|
|
21755
|
+
const id = parseNonEmptyString8(source.id);
|
|
21528
21756
|
if (id.length > 0) {
|
|
21529
21757
|
invite.id = id;
|
|
21530
21758
|
}
|
|
21531
|
-
const createdAt =
|
|
21759
|
+
const createdAt = parseNonEmptyString8(source.createdAt);
|
|
21532
21760
|
if (createdAt.length > 0) {
|
|
21533
21761
|
invite.createdAt = createdAt;
|
|
21534
21762
|
}
|
|
@@ -21545,7 +21773,7 @@ function parseInviteRedeemResponse(payload) {
|
|
|
21545
21773
|
);
|
|
21546
21774
|
}
|
|
21547
21775
|
const apiKeySource = isRecord8(payload.apiKey) ? payload.apiKey : payload;
|
|
21548
|
-
const apiKeyToken =
|
|
21776
|
+
const apiKeyToken = parseNonEmptyString8(
|
|
21549
21777
|
isRecord8(payload.apiKey) ? payload.apiKey.token : payload.token
|
|
21550
21778
|
);
|
|
21551
21779
|
if (apiKeyToken.length === 0) {
|
|
@@ -21554,11 +21782,11 @@ function parseInviteRedeemResponse(payload) {
|
|
|
21554
21782
|
"Invite redeem response is invalid"
|
|
21555
21783
|
);
|
|
21556
21784
|
}
|
|
21557
|
-
const apiKeyId =
|
|
21558
|
-
const apiKeyName =
|
|
21785
|
+
const apiKeyId = parseNonEmptyString8(apiKeySource.id);
|
|
21786
|
+
const apiKeyName = parseNonEmptyString8(apiKeySource.name);
|
|
21559
21787
|
const humanSource = isRecord8(payload.human) ? payload.human : void 0;
|
|
21560
|
-
const humanName =
|
|
21561
|
-
const proxyUrl =
|
|
21788
|
+
const humanName = parseNonEmptyString8(humanSource?.displayName);
|
|
21789
|
+
const proxyUrl = parseNonEmptyString8(payload.proxyUrl);
|
|
21562
21790
|
if (humanName.length === 0) {
|
|
21563
21791
|
throw createCliError5(
|
|
21564
21792
|
"CLI_INVITE_REDEEM_INVALID_RESPONSE",
|
|
@@ -21600,7 +21828,7 @@ async function createInvite(options, dependencies = {}) {
|
|
|
21600
21828
|
"content-type": "application/json"
|
|
21601
21829
|
},
|
|
21602
21830
|
body: JSON.stringify({
|
|
21603
|
-
expiresAt:
|
|
21831
|
+
expiresAt: parseNonEmptyString8(options.expiresAt) || void 0
|
|
21604
21832
|
})
|
|
21605
21833
|
}
|
|
21606
21834
|
});
|
|
@@ -21617,21 +21845,21 @@ async function createInvite(options, dependencies = {}) {
|
|
|
21617
21845
|
};
|
|
21618
21846
|
}
|
|
21619
21847
|
async function redeemInvite(code, options, dependencies = {}) {
|
|
21620
|
-
const inviteCode =
|
|
21848
|
+
const inviteCode = parseNonEmptyString8(code);
|
|
21621
21849
|
if (inviteCode.length === 0) {
|
|
21622
21850
|
throw createCliError5(
|
|
21623
21851
|
"CLI_INVITE_REDEEM_CODE_REQUIRED",
|
|
21624
21852
|
"Invite code is required"
|
|
21625
21853
|
);
|
|
21626
21854
|
}
|
|
21627
|
-
const displayName =
|
|
21855
|
+
const displayName = parseNonEmptyString8(options.displayName);
|
|
21628
21856
|
if (displayName.length === 0) {
|
|
21629
21857
|
throw createCliError5(
|
|
21630
21858
|
"CLI_INVITE_REDEEM_DISPLAY_NAME_REQUIRED",
|
|
21631
21859
|
"Display name is required. Pass --display-name <name>."
|
|
21632
21860
|
);
|
|
21633
21861
|
}
|
|
21634
|
-
const apiKeyName =
|
|
21862
|
+
const apiKeyName = parseNonEmptyString8(options.apiKeyName);
|
|
21635
21863
|
const runtime = await resolveInviteRuntime(options.registryUrl, dependencies);
|
|
21636
21864
|
const response = await executeInviteRequest({
|
|
21637
21865
|
fetchImpl: runtime.fetchImpl,
|
|
@@ -21743,14 +21971,13 @@ var createInviteCommand = (dependencies = {}) => {
|
|
|
21743
21971
|
// src/commands/openclaw.ts
|
|
21744
21972
|
import { spawn } from "child_process";
|
|
21745
21973
|
import { randomBytes as randomBytes3 } from "crypto";
|
|
21746
|
-
import { existsSync } from "fs";
|
|
21974
|
+
import { closeSync, existsSync, openSync } from "fs";
|
|
21747
21975
|
import { chmod as chmod3, copyFile, mkdir as mkdir6, readFile as readFile6, writeFile as writeFile6 } from "fs/promises";
|
|
21748
21976
|
import { homedir as homedir3 } from "os";
|
|
21749
21977
|
import { dirname as dirname5, join as join7, resolve as resolvePath } from "path";
|
|
21750
21978
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
21751
21979
|
import { Command as Command7 } from "commander";
|
|
21752
21980
|
var logger8 = createLogger({ service: "cli", module: "openclaw" });
|
|
21753
|
-
var CLAWDENTITY_DIR_NAME = ".clawdentity";
|
|
21754
21981
|
var AGENTS_DIR_NAME4 = "agents";
|
|
21755
21982
|
var AIT_FILE_NAME3 = "ait.jwt";
|
|
21756
21983
|
var SECRET_KEY_FILE_NAME2 = "secret.key";
|
|
@@ -21788,6 +22015,8 @@ var CONNECTOR_HOST_DOCKER = "host.docker.internal";
|
|
|
21788
22015
|
var CONNECTOR_HOST_DOCKER_GATEWAY = "gateway.docker.internal";
|
|
21789
22016
|
var CONNECTOR_HOST_LINUX_BRIDGE = "172.17.0.1";
|
|
21790
22017
|
var CONNECTOR_RUN_DIR_NAME = "run";
|
|
22018
|
+
var CONNECTOR_DETACHED_STDOUT_FILE_SUFFIX = "stdout.log";
|
|
22019
|
+
var CONNECTOR_DETACHED_STDERR_FILE_SUFFIX = "stderr.log";
|
|
21791
22020
|
var PEER_ALIAS_PATTERN = /^[a-zA-Z0-9._-]+$/;
|
|
21792
22021
|
var FILE_MODE3 = 384;
|
|
21793
22022
|
var OPENCLAW_HOOK_TOKEN_BYTES = 32;
|
|
@@ -21799,6 +22028,8 @@ var OPENCLAW_DEVICE_APPROVAL_RECOVERY_HINT = "Run: clawdentity openclaw setup <a
|
|
|
21799
22028
|
var OPENCLAW_GATEWAY_AUTH_RECOVERY_HINT = "Run: clawdentity openclaw setup <agentName> (ensures gateway auth mode/token are configured)";
|
|
21800
22029
|
var OPENCLAW_GATEWAY_APPROVAL_COMMAND = "openclaw";
|
|
21801
22030
|
var OPENCLAW_GATEWAY_APPROVAL_TIMEOUT_MS = 1e4;
|
|
22031
|
+
var OPENCLAW_SETUP_STABILITY_WINDOW_SECONDS = 20;
|
|
22032
|
+
var OPENCLAW_SETUP_STABILITY_POLL_INTERVAL_MS = 1e3;
|
|
21802
22033
|
var textEncoder2 = new TextEncoder();
|
|
21803
22034
|
var textDecoder = new TextDecoder();
|
|
21804
22035
|
function isRecord9(value) {
|
|
@@ -21818,7 +22049,7 @@ function getErrorCode2(error48) {
|
|
|
21818
22049
|
}
|
|
21819
22050
|
return typeof error48.code === "string" ? error48.code : void 0;
|
|
21820
22051
|
}
|
|
21821
|
-
function
|
|
22052
|
+
function parseNonEmptyString9(value, label) {
|
|
21822
22053
|
if (typeof value !== "string") {
|
|
21823
22054
|
throw createCliError6(
|
|
21824
22055
|
"CLI_OPENCLAW_INVALID_INPUT",
|
|
@@ -21842,10 +22073,10 @@ function parseOptionalProfileName(value, label) {
|
|
|
21842
22073
|
if (value === void 0) {
|
|
21843
22074
|
return void 0;
|
|
21844
22075
|
}
|
|
21845
|
-
return
|
|
22076
|
+
return parseNonEmptyString9(value, label);
|
|
21846
22077
|
}
|
|
21847
22078
|
function parsePeerAlias(value) {
|
|
21848
|
-
const alias =
|
|
22079
|
+
const alias = parseNonEmptyString9(value, "peer alias");
|
|
21849
22080
|
if (alias.length > 128) {
|
|
21850
22081
|
throw createCliError6(
|
|
21851
22082
|
"CLI_OPENCLAW_INVALID_PEER_ALIAS",
|
|
@@ -21868,7 +22099,7 @@ function parseProxyUrl(value) {
|
|
|
21868
22099
|
});
|
|
21869
22100
|
}
|
|
21870
22101
|
function parseHttpUrl(value, input) {
|
|
21871
|
-
const candidate =
|
|
22102
|
+
const candidate = parseNonEmptyString9(value, input.label);
|
|
21872
22103
|
let parsedUrl;
|
|
21873
22104
|
try {
|
|
21874
22105
|
parsedUrl = new URL(candidate);
|
|
@@ -21891,7 +22122,7 @@ function parseOpenclawBaseUrl(value) {
|
|
|
21891
22122
|
});
|
|
21892
22123
|
}
|
|
21893
22124
|
function parseAgentDid2(value, label) {
|
|
21894
|
-
const did =
|
|
22125
|
+
const did = parseNonEmptyString9(value, label);
|
|
21895
22126
|
try {
|
|
21896
22127
|
const parsed = parseDid(did);
|
|
21897
22128
|
if (parsed.kind !== "agent") {
|
|
@@ -21907,7 +22138,7 @@ function parseAgentDid2(value, label) {
|
|
|
21907
22138
|
}
|
|
21908
22139
|
return did;
|
|
21909
22140
|
}
|
|
21910
|
-
function
|
|
22141
|
+
function resolveHomeDir2(homeDir) {
|
|
21911
22142
|
if (typeof homeDir === "string" && homeDir.trim().length > 0) {
|
|
21912
22143
|
return homeDir.trim();
|
|
21913
22144
|
}
|
|
@@ -21968,10 +22199,10 @@ function resolveOpenclawDir(openclawDir, homeDir) {
|
|
|
21968
22199
|
return resolveDefaultOpenclawStateDir(openclawHomeDir);
|
|
21969
22200
|
}
|
|
21970
22201
|
function resolveAgentDirectory(homeDir, agentName) {
|
|
21971
|
-
return join7(homeDir
|
|
22202
|
+
return join7(getConfigDir({ homeDir }), AGENTS_DIR_NAME4, agentName);
|
|
21972
22203
|
}
|
|
21973
22204
|
function resolvePeersPath(homeDir) {
|
|
21974
|
-
return join7(homeDir
|
|
22205
|
+
return join7(getConfigDir({ homeDir }), PEERS_FILE_NAME);
|
|
21975
22206
|
}
|
|
21976
22207
|
function resolveOpenclawConfigPath(openclawDir, homeDir) {
|
|
21977
22208
|
const envConfigPath = readNonEmptyEnvPath(
|
|
@@ -22001,13 +22232,13 @@ function resolveTransformTargetPath(openclawDir) {
|
|
|
22001
22232
|
return join7(openclawDir, "hooks", "transforms", RELAY_MODULE_FILE_NAME);
|
|
22002
22233
|
}
|
|
22003
22234
|
function resolveOpenclawAgentNamePath(homeDir) {
|
|
22004
|
-
return join7(homeDir
|
|
22235
|
+
return join7(getConfigDir({ homeDir }), OPENCLAW_AGENT_FILE_NAME);
|
|
22005
22236
|
}
|
|
22006
22237
|
function resolveRelayRuntimeConfigPath(homeDir) {
|
|
22007
|
-
return join7(homeDir
|
|
22238
|
+
return join7(getConfigDir({ homeDir }), OPENCLAW_RELAY_RUNTIME_FILE_NAME2);
|
|
22008
22239
|
}
|
|
22009
22240
|
function resolveConnectorAssignmentsPath(homeDir) {
|
|
22010
|
-
return join7(homeDir
|
|
22241
|
+
return join7(getConfigDir({ homeDir }), OPENCLAW_CONNECTORS_FILE_NAME2);
|
|
22011
22242
|
}
|
|
22012
22243
|
function resolveTransformRuntimePath(openclawDir) {
|
|
22013
22244
|
return join7(openclawDir, "hooks", "transforms", RELAY_RUNTIME_FILE_NAME);
|
|
@@ -22475,12 +22706,51 @@ async function waitForConnectorConnected(input) {
|
|
|
22475
22706
|
}
|
|
22476
22707
|
return latest;
|
|
22477
22708
|
}
|
|
22709
|
+
function sleepMilliseconds(durationMs) {
|
|
22710
|
+
return new Promise((resolve2) => {
|
|
22711
|
+
setTimeout(resolve2, durationMs);
|
|
22712
|
+
});
|
|
22713
|
+
}
|
|
22714
|
+
async function monitorConnectorStabilityWindow(input) {
|
|
22715
|
+
if (input.durationSeconds <= 0) {
|
|
22716
|
+
return fetchConnectorHealthStatus({
|
|
22717
|
+
connectorBaseUrl: input.connectorBaseUrl,
|
|
22718
|
+
fetchImpl: input.fetchImpl
|
|
22719
|
+
});
|
|
22720
|
+
}
|
|
22721
|
+
const deadline = Date.now() + input.durationSeconds * 1e3;
|
|
22722
|
+
let latest = await fetchConnectorHealthStatus({
|
|
22723
|
+
connectorBaseUrl: input.connectorBaseUrl,
|
|
22724
|
+
fetchImpl: input.fetchImpl
|
|
22725
|
+
});
|
|
22726
|
+
if (!latest.connected) {
|
|
22727
|
+
return latest;
|
|
22728
|
+
}
|
|
22729
|
+
while (Date.now() < deadline) {
|
|
22730
|
+
await sleepMilliseconds(input.pollIntervalMs);
|
|
22731
|
+
latest = await fetchConnectorHealthStatus({
|
|
22732
|
+
connectorBaseUrl: input.connectorBaseUrl,
|
|
22733
|
+
fetchImpl: input.fetchImpl
|
|
22734
|
+
});
|
|
22735
|
+
if (!latest.connected) {
|
|
22736
|
+
return latest;
|
|
22737
|
+
}
|
|
22738
|
+
}
|
|
22739
|
+
return latest;
|
|
22740
|
+
}
|
|
22478
22741
|
function resolveConnectorRunDir(homeDir) {
|
|
22479
|
-
return join7(homeDir
|
|
22742
|
+
return join7(getConfigDir({ homeDir }), CONNECTOR_RUN_DIR_NAME);
|
|
22480
22743
|
}
|
|
22481
22744
|
function resolveConnectorPidPath(homeDir, agentName) {
|
|
22482
22745
|
return join7(resolveConnectorRunDir(homeDir), `connector-${agentName}.pid`);
|
|
22483
22746
|
}
|
|
22747
|
+
function resolveDetachedConnectorLogPath(homeDir, agentName, stream) {
|
|
22748
|
+
const suffix = stream === "stdout" ? CONNECTOR_DETACHED_STDOUT_FILE_SUFFIX : CONNECTOR_DETACHED_STDERR_FILE_SUFFIX;
|
|
22749
|
+
return join7(
|
|
22750
|
+
resolveConnectorRunDir(homeDir),
|
|
22751
|
+
`connector-${agentName}.${suffix}`
|
|
22752
|
+
);
|
|
22753
|
+
}
|
|
22484
22754
|
async function readConnectorPidFile(pidPath) {
|
|
22485
22755
|
try {
|
|
22486
22756
|
const raw = (await readFile6(pidPath, "utf8")).trim();
|
|
@@ -22542,17 +22812,40 @@ async function startDetachedConnectorRuntime(input) {
|
|
|
22542
22812
|
"--openclaw-base-url",
|
|
22543
22813
|
input.openclawBaseUrl
|
|
22544
22814
|
];
|
|
22545
|
-
const
|
|
22546
|
-
|
|
22547
|
-
|
|
22548
|
-
|
|
22549
|
-
});
|
|
22550
|
-
child.unref();
|
|
22551
|
-
await writeSecureFile3(
|
|
22552
|
-
resolveConnectorPidPath(input.homeDir, input.agentName),
|
|
22553
|
-
`${child.pid}
|
|
22554
|
-
`
|
|
22815
|
+
const stdoutLogPath = resolveDetachedConnectorLogPath(
|
|
22816
|
+
input.homeDir,
|
|
22817
|
+
input.agentName,
|
|
22818
|
+
"stdout"
|
|
22555
22819
|
);
|
|
22820
|
+
const stderrLogPath = resolveDetachedConnectorLogPath(
|
|
22821
|
+
input.homeDir,
|
|
22822
|
+
input.agentName,
|
|
22823
|
+
"stderr"
|
|
22824
|
+
);
|
|
22825
|
+
const stdoutFd = openSync(stdoutLogPath, "a");
|
|
22826
|
+
const stderrFd = openSync(stderrLogPath, "a");
|
|
22827
|
+
try {
|
|
22828
|
+
const child = spawn(process.execPath, args, {
|
|
22829
|
+
detached: true,
|
|
22830
|
+
stdio: ["ignore", stdoutFd, stderrFd],
|
|
22831
|
+
env: process.env
|
|
22832
|
+
});
|
|
22833
|
+
child.unref();
|
|
22834
|
+
await writeSecureFile3(
|
|
22835
|
+
resolveConnectorPidPath(input.homeDir, input.agentName),
|
|
22836
|
+
`${child.pid}
|
|
22837
|
+
`
|
|
22838
|
+
);
|
|
22839
|
+
logger8.info("cli.openclaw.setup.detached_runtime_started", {
|
|
22840
|
+
agentName: input.agentName,
|
|
22841
|
+
pid: child.pid,
|
|
22842
|
+
stdoutLogPath,
|
|
22843
|
+
stderrLogPath
|
|
22844
|
+
});
|
|
22845
|
+
} finally {
|
|
22846
|
+
closeSync(stdoutFd);
|
|
22847
|
+
closeSync(stderrFd);
|
|
22848
|
+
}
|
|
22556
22849
|
}
|
|
22557
22850
|
async function startSetupConnectorRuntime(input) {
|
|
22558
22851
|
if (input.mode !== "service") {
|
|
@@ -22833,14 +23126,18 @@ async function patchOpenclawConfig(openclawConfigPath, hookToken) {
|
|
|
22833
23126
|
hooks,
|
|
22834
23127
|
gateway
|
|
22835
23128
|
};
|
|
22836
|
-
|
|
22837
|
-
|
|
22838
|
-
|
|
23129
|
+
const configChanged = JSON.stringify(config2) !== JSON.stringify(nextConfig);
|
|
23130
|
+
if (configChanged) {
|
|
23131
|
+
await writeFile6(
|
|
23132
|
+
openclawConfigPath,
|
|
23133
|
+
`${JSON.stringify(nextConfig, null, 2)}
|
|
22839
23134
|
`,
|
|
22840
|
-
|
|
22841
|
-
|
|
23135
|
+
"utf8"
|
|
23136
|
+
);
|
|
23137
|
+
}
|
|
22842
23138
|
return {
|
|
22843
|
-
hookToken: resolvedHookToken
|
|
23139
|
+
hookToken: resolvedHookToken,
|
|
23140
|
+
configChanged
|
|
22844
23141
|
};
|
|
22845
23142
|
}
|
|
22846
23143
|
function toDoctorCheck(input) {
|
|
@@ -22938,7 +23235,7 @@ function toSendToPeerEndpoint(openclawBaseUrl) {
|
|
|
22938
23235
|
return new URL(OPENCLAW_SEND_TO_PEER_HOOK_PATH, normalizedBase).toString();
|
|
22939
23236
|
}
|
|
22940
23237
|
async function runOpenclawDoctor(options = {}) {
|
|
22941
|
-
const homeDir =
|
|
23238
|
+
const homeDir = resolveHomeDir2(options.homeDir);
|
|
22942
23239
|
const openclawDir = resolveOpenclawDir(options.openclawDir, homeDir);
|
|
22943
23240
|
const peerAlias = parseDoctorPeerAlias(options.peerAlias);
|
|
22944
23241
|
const checks = [];
|
|
@@ -23037,7 +23334,7 @@ async function runOpenclawDoctor(options = {}) {
|
|
|
23037
23334
|
label: "CLI config",
|
|
23038
23335
|
status: "fail",
|
|
23039
23336
|
message: "unable to resolve CLI config",
|
|
23040
|
-
remediationHint: "
|
|
23337
|
+
remediationHint: "Run: clawdentity config init (or fix your CLI state config file)"
|
|
23041
23338
|
})
|
|
23042
23339
|
);
|
|
23043
23340
|
}
|
|
@@ -23159,7 +23456,7 @@ async function runOpenclawDoctor(options = {}) {
|
|
|
23159
23456
|
label: "Peers map",
|
|
23160
23457
|
status: "fail",
|
|
23161
23458
|
message: `invalid peers config at ${peersPath}`,
|
|
23162
|
-
remediationHint:
|
|
23459
|
+
remediationHint: `Fix JSON in ${peersPath} or rerun openclaw setup`,
|
|
23163
23460
|
details: { peersPath }
|
|
23164
23461
|
})
|
|
23165
23462
|
);
|
|
@@ -23818,7 +24115,7 @@ async function resolveRelayProbePeerAlias(input) {
|
|
|
23818
24115
|
);
|
|
23819
24116
|
}
|
|
23820
24117
|
async function runOpenclawRelayTest(options) {
|
|
23821
|
-
const homeDir =
|
|
24118
|
+
const homeDir = resolveHomeDir2(options.homeDir);
|
|
23822
24119
|
const openclawDir = resolveOpenclawDir(options.openclawDir, homeDir);
|
|
23823
24120
|
const checkedAt = nowIso();
|
|
23824
24121
|
let peerAlias;
|
|
@@ -23950,7 +24247,7 @@ async function runOpenclawRelayTest(options) {
|
|
|
23950
24247
|
}
|
|
23951
24248
|
async function setupOpenclawRelay(agentName, options) {
|
|
23952
24249
|
const normalizedAgentName = assertValidAgentName(agentName);
|
|
23953
|
-
const homeDir =
|
|
24250
|
+
const homeDir = resolveHomeDir2(options.homeDir);
|
|
23954
24251
|
const openclawDir = resolveOpenclawDir(options.openclawDir, homeDir);
|
|
23955
24252
|
const openclawConfigPath = resolveOpenclawConfigPath(openclawDir, homeDir);
|
|
23956
24253
|
const transformSource = typeof options.transformSource === "string" && options.transformSource.trim().length > 0 ? options.transformSource.trim() : resolveDefaultTransformSource(openclawDir);
|
|
@@ -24053,7 +24350,8 @@ async function setupOpenclawRelay(agentName, options) {
|
|
|
24053
24350
|
relayTransformPeersPath,
|
|
24054
24351
|
openclawBaseUrl,
|
|
24055
24352
|
connectorBaseUrl,
|
|
24056
|
-
relayRuntimeConfigPath
|
|
24353
|
+
relayRuntimeConfigPath,
|
|
24354
|
+
openclawConfigChanged: patchedOpenclawConfig.configChanged
|
|
24057
24355
|
};
|
|
24058
24356
|
}
|
|
24059
24357
|
async function assertSetupChecklistHealthy(input) {
|
|
@@ -24121,12 +24419,13 @@ async function assertSetupChecklistHealthy(input) {
|
|
|
24121
24419
|
);
|
|
24122
24420
|
}
|
|
24123
24421
|
async function setupOpenclawSelfReady(agentName, options) {
|
|
24124
|
-
const
|
|
24422
|
+
const normalizedAgentName = assertValidAgentName(agentName);
|
|
24423
|
+
const resolvedHomeDir = resolveHomeDir2(options.homeDir);
|
|
24125
24424
|
const resolvedOpenclawDir = resolveOpenclawDir(
|
|
24126
24425
|
options.openclawDir,
|
|
24127
24426
|
resolvedHomeDir
|
|
24128
24427
|
);
|
|
24129
|
-
const setup = await setupOpenclawRelay(
|
|
24428
|
+
const setup = await setupOpenclawRelay(normalizedAgentName, {
|
|
24130
24429
|
...options,
|
|
24131
24430
|
homeDir: resolvedHomeDir,
|
|
24132
24431
|
openclawDir: resolvedOpenclawDir
|
|
@@ -24156,8 +24455,8 @@ async function setupOpenclawSelfReady(agentName, options) {
|
|
|
24156
24455
|
const waitTimeoutSeconds = parseWaitTimeoutSeconds(
|
|
24157
24456
|
options.waitTimeoutSeconds
|
|
24158
24457
|
);
|
|
24159
|
-
|
|
24160
|
-
agentName:
|
|
24458
|
+
let runtime = await startSetupConnectorRuntime({
|
|
24459
|
+
agentName: normalizedAgentName,
|
|
24161
24460
|
homeDir: resolvedHomeDir,
|
|
24162
24461
|
openclawBaseUrl: setup.openclawBaseUrl,
|
|
24163
24462
|
connectorBaseUrl: setup.connectorBaseUrl,
|
|
@@ -24171,6 +24470,44 @@ async function setupOpenclawSelfReady(agentName, options) {
|
|
|
24171
24470
|
includeConnectorRuntimeCheck: true,
|
|
24172
24471
|
gatewayDeviceApprovalRunner: options.gatewayDeviceApprovalRunner
|
|
24173
24472
|
});
|
|
24473
|
+
const requiresStabilityGuard = setup.openclawConfigChanged && (runtime.runtimeMode === "existing" || runtime.runtimeMode === "detached");
|
|
24474
|
+
if (requiresStabilityGuard) {
|
|
24475
|
+
const stabilityWindowSeconds = Math.min(
|
|
24476
|
+
waitTimeoutSeconds,
|
|
24477
|
+
OPENCLAW_SETUP_STABILITY_WINDOW_SECONDS
|
|
24478
|
+
);
|
|
24479
|
+
const stableStatus = await monitorConnectorStabilityWindow({
|
|
24480
|
+
connectorBaseUrl: setup.connectorBaseUrl,
|
|
24481
|
+
fetchImpl,
|
|
24482
|
+
durationSeconds: stabilityWindowSeconds,
|
|
24483
|
+
pollIntervalMs: OPENCLAW_SETUP_STABILITY_POLL_INTERVAL_MS
|
|
24484
|
+
});
|
|
24485
|
+
if (!stableStatus.connected) {
|
|
24486
|
+
logger8.warn("cli.openclaw.setup.connector_dropped_post_config_change", {
|
|
24487
|
+
agentName: normalizedAgentName,
|
|
24488
|
+
connectorBaseUrl: setup.connectorBaseUrl,
|
|
24489
|
+
connectorStatusUrl: stableStatus.statusUrl,
|
|
24490
|
+
reason: stableStatus.reason,
|
|
24491
|
+
previousRuntimeMode: runtime.runtimeMode,
|
|
24492
|
+
stabilityWindowSeconds
|
|
24493
|
+
});
|
|
24494
|
+
runtime = await startSetupConnectorRuntime({
|
|
24495
|
+
agentName: normalizedAgentName,
|
|
24496
|
+
homeDir: resolvedHomeDir,
|
|
24497
|
+
openclawBaseUrl: setup.openclawBaseUrl,
|
|
24498
|
+
connectorBaseUrl: setup.connectorBaseUrl,
|
|
24499
|
+
mode: resolvedMode,
|
|
24500
|
+
waitTimeoutSeconds,
|
|
24501
|
+
fetchImpl
|
|
24502
|
+
});
|
|
24503
|
+
await assertSetupChecklistHealthy({
|
|
24504
|
+
homeDir: resolvedHomeDir,
|
|
24505
|
+
openclawDir: resolvedOpenclawDir,
|
|
24506
|
+
includeConnectorRuntimeCheck: true,
|
|
24507
|
+
gatewayDeviceApprovalRunner: options.gatewayDeviceApprovalRunner
|
|
24508
|
+
});
|
|
24509
|
+
}
|
|
24510
|
+
}
|
|
24174
24511
|
return {
|
|
24175
24512
|
...setup,
|
|
24176
24513
|
...runtime
|
|
@@ -24256,7 +24593,7 @@ var createOpenclawCommand = () => {
|
|
|
24256
24593
|
const relayCommand = openclawCommand.command("relay").description("Run OpenClaw relay diagnostics");
|
|
24257
24594
|
relayCommand.command("test").description(
|
|
24258
24595
|
"Send a relay probe to a configured peer (auto-selects when one peer exists)"
|
|
24259
|
-
).option("--peer <alias>", "Peer alias in
|
|
24596
|
+
).option("--peer <alias>", "Peer alias in local peers map").option(
|
|
24260
24597
|
"--openclaw-base-url <url>",
|
|
24261
24598
|
"Base URL for local OpenClaw hook API (default OPENCLAW_BASE_URL or relay runtime config)"
|
|
24262
24599
|
).option(
|
|
@@ -24300,7 +24637,7 @@ import { randomBytes as randomBytes4 } from "crypto";
|
|
|
24300
24637
|
import {
|
|
24301
24638
|
chmod as chmod4,
|
|
24302
24639
|
mkdir as mkdir7,
|
|
24303
|
-
readdir,
|
|
24640
|
+
readdir as readdir2,
|
|
24304
24641
|
readFile as readFile7,
|
|
24305
24642
|
unlink as unlink2,
|
|
24306
24643
|
writeFile as writeFile7
|
|
@@ -24339,7 +24676,7 @@ function createCliError7(code, message2) {
|
|
|
24339
24676
|
status: 400
|
|
24340
24677
|
});
|
|
24341
24678
|
}
|
|
24342
|
-
function
|
|
24679
|
+
function parseNonEmptyString10(value) {
|
|
24343
24680
|
if (typeof value !== "string") {
|
|
24344
24681
|
return "";
|
|
24345
24682
|
}
|
|
@@ -24355,7 +24692,7 @@ function hasControlChars2(value) {
|
|
|
24355
24692
|
return false;
|
|
24356
24693
|
}
|
|
24357
24694
|
function parseProfileName(value, label) {
|
|
24358
|
-
const candidate =
|
|
24695
|
+
const candidate = parseNonEmptyString10(value);
|
|
24359
24696
|
if (candidate.length === 0) {
|
|
24360
24697
|
throw createCliError7(
|
|
24361
24698
|
"CLI_PAIR_PROFILE_INVALID",
|
|
@@ -24389,16 +24726,20 @@ function parsePeerProfile(payload) {
|
|
|
24389
24726
|
};
|
|
24390
24727
|
}
|
|
24391
24728
|
function parsePairingTicket(value) {
|
|
24392
|
-
|
|
24729
|
+
let ticket = parseNonEmptyString10(value);
|
|
24730
|
+
while (ticket.startsWith("`")) {
|
|
24731
|
+
ticket = ticket.slice(1);
|
|
24732
|
+
}
|
|
24733
|
+
while (ticket.endsWith("`")) {
|
|
24734
|
+
ticket = ticket.slice(0, -1);
|
|
24735
|
+
}
|
|
24736
|
+
ticket = ticket.trim().replace(/\s+/gu, "");
|
|
24393
24737
|
if (!ticket.startsWith(PAIRING_TICKET_PREFIX)) {
|
|
24394
24738
|
throw createCliError7(
|
|
24395
24739
|
"CLI_PAIR_CONFIRM_TICKET_INVALID",
|
|
24396
24740
|
"Pairing ticket is invalid"
|
|
24397
24741
|
);
|
|
24398
24742
|
}
|
|
24399
|
-
return ticket;
|
|
24400
|
-
}
|
|
24401
|
-
function parsePairingTicketIssuerOrigin(ticket) {
|
|
24402
24743
|
const encodedPayload = ticket.slice(PAIRING_TICKET_PREFIX.length);
|
|
24403
24744
|
if (encodedPayload.length === 0) {
|
|
24404
24745
|
throw createCliError7(
|
|
@@ -24406,15 +24747,26 @@ function parsePairingTicketIssuerOrigin(ticket) {
|
|
|
24406
24747
|
"Pairing ticket is invalid"
|
|
24407
24748
|
);
|
|
24408
24749
|
}
|
|
24409
|
-
let payloadRaw;
|
|
24410
24750
|
try {
|
|
24411
|
-
payloadRaw = new TextDecoder().decode(
|
|
24751
|
+
const payloadRaw = new TextDecoder().decode(
|
|
24752
|
+
decodeBase64url(encodedPayload)
|
|
24753
|
+
);
|
|
24754
|
+
const payload = JSON.parse(payloadRaw);
|
|
24755
|
+
if (!isRecord10(payload)) {
|
|
24756
|
+
throw new Error("invalid payload");
|
|
24757
|
+
}
|
|
24412
24758
|
} catch {
|
|
24413
24759
|
throw createCliError7(
|
|
24414
24760
|
"CLI_PAIR_CONFIRM_TICKET_INVALID",
|
|
24415
24761
|
"Pairing ticket is invalid"
|
|
24416
24762
|
);
|
|
24417
24763
|
}
|
|
24764
|
+
return ticket;
|
|
24765
|
+
}
|
|
24766
|
+
function parsePairingTicketIssuerOrigin(ticket) {
|
|
24767
|
+
const normalizedTicket = parsePairingTicket(ticket);
|
|
24768
|
+
const encodedPayload = normalizedTicket.slice(PAIRING_TICKET_PREFIX.length);
|
|
24769
|
+
const payloadRaw = new TextDecoder().decode(decodeBase64url(encodedPayload));
|
|
24418
24770
|
let payload;
|
|
24419
24771
|
try {
|
|
24420
24772
|
payload = JSON.parse(payloadRaw);
|
|
@@ -24447,6 +24799,26 @@ function parsePairingTicketIssuerOrigin(ticket) {
|
|
|
24447
24799
|
}
|
|
24448
24800
|
return issuerUrl.origin;
|
|
24449
24801
|
}
|
|
24802
|
+
function assertTicketIssuerMatchesProxy(input) {
|
|
24803
|
+
const issuerOrigin = parsePairingTicketIssuerOrigin(input.ticket);
|
|
24804
|
+
let proxyOrigin;
|
|
24805
|
+
try {
|
|
24806
|
+
proxyOrigin = new URL(input.proxyUrl).origin;
|
|
24807
|
+
} catch {
|
|
24808
|
+
throw createCliError7(
|
|
24809
|
+
"CLI_PAIR_PROXY_URL_INVALID",
|
|
24810
|
+
"Configured proxyUrl is invalid. Run `clawdentity config set proxyUrl <url>` and retry."
|
|
24811
|
+
);
|
|
24812
|
+
}
|
|
24813
|
+
if (issuerOrigin === proxyOrigin) {
|
|
24814
|
+
return;
|
|
24815
|
+
}
|
|
24816
|
+
const command = input.context === "confirm" ? "pair confirm" : "pair status";
|
|
24817
|
+
throw createCliError7(
|
|
24818
|
+
"CLI_PAIR_TICKET_ISSUER_MISMATCH",
|
|
24819
|
+
`Pairing ticket was issued by ${issuerOrigin}, but current proxy URL is ${proxyOrigin}. Run \`clawdentity config set proxyUrl ${issuerOrigin}\` and retry \`${command}\`.`
|
|
24820
|
+
);
|
|
24821
|
+
}
|
|
24450
24822
|
function parseAitAgentDid(ait) {
|
|
24451
24823
|
const parts = ait.split(".");
|
|
24452
24824
|
if (parts.length < 2) {
|
|
@@ -24544,16 +24916,16 @@ function parsePeerEntry(value) {
|
|
|
24544
24916
|
"Peer entry must be an object"
|
|
24545
24917
|
);
|
|
24546
24918
|
}
|
|
24547
|
-
const did =
|
|
24548
|
-
const proxyUrl =
|
|
24919
|
+
const did = parseNonEmptyString10(value.did);
|
|
24920
|
+
const proxyUrl = parseNonEmptyString10(value.proxyUrl);
|
|
24549
24921
|
if (did.length === 0 || proxyUrl.length === 0) {
|
|
24550
24922
|
throw createCliError7(
|
|
24551
24923
|
"CLI_PAIR_PEERS_CONFIG_INVALID",
|
|
24552
24924
|
"Peer entry is invalid"
|
|
24553
24925
|
);
|
|
24554
24926
|
}
|
|
24555
|
-
const agentNameRaw =
|
|
24556
|
-
const humanNameRaw =
|
|
24927
|
+
const agentNameRaw = parseNonEmptyString10(value.agentName);
|
|
24928
|
+
const humanNameRaw = parseNonEmptyString10(value.humanName);
|
|
24557
24929
|
const entry = {
|
|
24558
24930
|
did,
|
|
24559
24931
|
proxyUrl
|
|
@@ -24652,7 +25024,7 @@ async function loadRelayTransformPeersPath(input) {
|
|
|
24652
25024
|
if (!isRecord10(parsed)) {
|
|
24653
25025
|
return void 0;
|
|
24654
25026
|
}
|
|
24655
|
-
const relayTransformPeersPath =
|
|
25027
|
+
const relayTransformPeersPath = parseNonEmptyString10(
|
|
24656
25028
|
parsed.relayTransformPeersPath
|
|
24657
25029
|
);
|
|
24658
25030
|
if (relayTransformPeersPath.length === 0) {
|
|
@@ -24700,7 +25072,7 @@ async function syncOpenclawRelayPeersSnapshot(input) {
|
|
|
24700
25072
|
}
|
|
24701
25073
|
}
|
|
24702
25074
|
function parseTtlSeconds(value) {
|
|
24703
|
-
const raw =
|
|
25075
|
+
const raw = parseNonEmptyString10(value);
|
|
24704
25076
|
if (raw.length === 0) {
|
|
24705
25077
|
return void 0;
|
|
24706
25078
|
}
|
|
@@ -24714,7 +25086,7 @@ function parseTtlSeconds(value) {
|
|
|
24714
25086
|
return parsed;
|
|
24715
25087
|
}
|
|
24716
25088
|
function parsePositiveIntegerOption(input) {
|
|
24717
|
-
const raw =
|
|
25089
|
+
const raw = parseNonEmptyString10(input.value);
|
|
24718
25090
|
if (raw.length === 0) {
|
|
24719
25091
|
return input.defaultValue;
|
|
24720
25092
|
}
|
|
@@ -24728,7 +25100,7 @@ function parsePositiveIntegerOption(input) {
|
|
|
24728
25100
|
return parsed;
|
|
24729
25101
|
}
|
|
24730
25102
|
function resolveLocalPairProfile(input) {
|
|
24731
|
-
const humanName =
|
|
25103
|
+
const humanName = parseNonEmptyString10(input.config.humanName);
|
|
24732
25104
|
if (humanName.length === 0) {
|
|
24733
25105
|
throw createCliError7(
|
|
24734
25106
|
"CLI_PAIR_HUMAN_NAME_MISSING",
|
|
@@ -24752,7 +25124,7 @@ function parseProxyUrl2(candidate) {
|
|
|
24752
25124
|
}
|
|
24753
25125
|
}
|
|
24754
25126
|
async function resolveProxyUrl(input) {
|
|
24755
|
-
const fromEnv =
|
|
25127
|
+
const fromEnv = parseNonEmptyString10(process.env.CLAWDENTITY_PROXY_URL);
|
|
24756
25128
|
if (fromEnv.length > 0) {
|
|
24757
25129
|
return parseProxyUrl2(fromEnv);
|
|
24758
25130
|
}
|
|
@@ -24760,7 +25132,7 @@ async function resolveProxyUrl(input) {
|
|
|
24760
25132
|
fetchImpl: input.fetchImpl
|
|
24761
25133
|
});
|
|
24762
25134
|
const metadataProxyUrl = parseProxyUrl2(metadata.proxyUrl);
|
|
24763
|
-
const configuredProxyUrl =
|
|
25135
|
+
const configuredProxyUrl = parseNonEmptyString10(input.config.proxyUrl);
|
|
24764
25136
|
if (configuredProxyUrl.length === 0) {
|
|
24765
25137
|
return metadataProxyUrl;
|
|
24766
25138
|
}
|
|
@@ -24846,6 +25218,12 @@ function mapConfirmPairError(status, payload) {
|
|
|
24846
25218
|
if (code === "PROXY_PAIR_TICKET_EXPIRED" || status === 410) {
|
|
24847
25219
|
return "Pairing ticket has expired";
|
|
24848
25220
|
}
|
|
25221
|
+
if (code === "PROXY_PAIR_TICKET_INVALID_ISSUER") {
|
|
25222
|
+
return message2 ? `Pair confirm failed: ticket issuer does not match this proxy (${message2}). Use the same proxy URL where the ticket was issued.` : "Pair confirm failed: ticket issuer does not match this proxy. Use the same proxy URL where the ticket was issued.";
|
|
25223
|
+
}
|
|
25224
|
+
if (code === "PROXY_PAIR_TICKET_INVALID_FORMAT" || code === "PROXY_PAIR_TICKET_UNSUPPORTED_VERSION") {
|
|
25225
|
+
return message2 ? `Pair confirm request is invalid (400): ${message2}. Re-copy the full ticket/QR without truncation.` : "Pair confirm request is invalid (400): pairing ticket is malformed. Re-copy the full ticket/QR without truncation.";
|
|
25226
|
+
}
|
|
24849
25227
|
if (status === 400) {
|
|
24850
25228
|
return message2 ? `Pair confirm request is invalid (400): ${message2}` : "Pair confirm request is invalid (400).";
|
|
24851
25229
|
}
|
|
@@ -24869,6 +25247,12 @@ function mapStatusPairError(status, payload) {
|
|
|
24869
25247
|
if (code === "PROXY_PAIR_STATUS_FORBIDDEN" || status === 403) {
|
|
24870
25248
|
return message2 ? `Pair status request is forbidden (403): ${message2}` : "Pair status request is forbidden (403).";
|
|
24871
25249
|
}
|
|
25250
|
+
if (code === "PROXY_PAIR_TICKET_INVALID_ISSUER") {
|
|
25251
|
+
return message2 ? `Pair status failed: ticket issuer does not match this proxy (${message2}). Use the same proxy URL where the ticket was issued.` : "Pair status failed: ticket issuer does not match this proxy. Use the same proxy URL where the ticket was issued.";
|
|
25252
|
+
}
|
|
25253
|
+
if (code === "PROXY_PAIR_TICKET_INVALID_FORMAT" || code === "PROXY_PAIR_TICKET_UNSUPPORTED_VERSION") {
|
|
25254
|
+
return message2 ? `Pair status request is invalid (400): ${message2}. Re-copy the full ticket/QR without truncation.` : "Pair status request is invalid (400): pairing ticket is malformed. Re-copy the full ticket/QR without truncation.";
|
|
25255
|
+
}
|
|
24872
25256
|
if (status === 400) {
|
|
24873
25257
|
return message2 ? `Pair status request is invalid (400): ${message2}` : "Pair status request is invalid (400).";
|
|
24874
25258
|
}
|
|
@@ -24888,8 +25272,8 @@ function parsePairStartResponse(payload) {
|
|
|
24888
25272
|
);
|
|
24889
25273
|
}
|
|
24890
25274
|
const ticket = parsePairingTicket(payload.ticket);
|
|
24891
|
-
const initiatorAgentDid =
|
|
24892
|
-
const expiresAt =
|
|
25275
|
+
const initiatorAgentDid = parseNonEmptyString10(payload.initiatorAgentDid);
|
|
25276
|
+
const expiresAt = parseNonEmptyString10(payload.expiresAt);
|
|
24893
25277
|
let initiatorProfile;
|
|
24894
25278
|
if (initiatorAgentDid.length === 0 || expiresAt.length === 0) {
|
|
24895
25279
|
throw createCliError7(
|
|
@@ -24920,8 +25304,8 @@ function parsePairConfirmResponse(payload) {
|
|
|
24920
25304
|
);
|
|
24921
25305
|
}
|
|
24922
25306
|
const paired = payload.paired === true;
|
|
24923
|
-
const initiatorAgentDid =
|
|
24924
|
-
const responderAgentDid =
|
|
25307
|
+
const initiatorAgentDid = parseNonEmptyString10(payload.initiatorAgentDid);
|
|
25308
|
+
const responderAgentDid = parseNonEmptyString10(payload.responderAgentDid);
|
|
24925
25309
|
let initiatorProfile;
|
|
24926
25310
|
let responderProfile;
|
|
24927
25311
|
if (!paired || initiatorAgentDid.length === 0 || responderAgentDid.length === 0) {
|
|
@@ -24954,17 +25338,17 @@ function parsePairStatusResponse(payload) {
|
|
|
24954
25338
|
"Pair status response is invalid"
|
|
24955
25339
|
);
|
|
24956
25340
|
}
|
|
24957
|
-
const statusRaw =
|
|
25341
|
+
const statusRaw = parseNonEmptyString10(payload.status);
|
|
24958
25342
|
if (statusRaw !== "pending" && statusRaw !== "confirmed") {
|
|
24959
25343
|
throw createCliError7(
|
|
24960
25344
|
"CLI_PAIR_STATUS_INVALID_RESPONSE",
|
|
24961
25345
|
"Pair status response is invalid"
|
|
24962
25346
|
);
|
|
24963
25347
|
}
|
|
24964
|
-
const initiatorAgentDid =
|
|
24965
|
-
const responderAgentDid =
|
|
24966
|
-
const expiresAt =
|
|
24967
|
-
const confirmedAt =
|
|
25348
|
+
const initiatorAgentDid = parseNonEmptyString10(payload.initiatorAgentDid);
|
|
25349
|
+
const responderAgentDid = parseNonEmptyString10(payload.responderAgentDid);
|
|
25350
|
+
const expiresAt = parseNonEmptyString10(payload.expiresAt);
|
|
25351
|
+
const confirmedAt = parseNonEmptyString10(payload.confirmedAt);
|
|
24968
25352
|
let initiatorProfile;
|
|
24969
25353
|
if (initiatorAgentDid.length === 0 || expiresAt.length === 0) {
|
|
24970
25354
|
throw createCliError7(
|
|
@@ -25112,7 +25496,7 @@ function decodeTicketFromPng(imageBytes) {
|
|
|
25112
25496
|
decodedPng.data.byteLength
|
|
25113
25497
|
);
|
|
25114
25498
|
const decoded = jsQR(imageData, decodedPng.width, decodedPng.height);
|
|
25115
|
-
if (!decoded ||
|
|
25499
|
+
if (!decoded || parseNonEmptyString10(decoded.data).length === 0) {
|
|
25116
25500
|
throw createCliError7(
|
|
25117
25501
|
"CLI_PAIR_CONFIRM_QR_NOT_FOUND",
|
|
25118
25502
|
"No pairing QR code was found in the image"
|
|
@@ -25122,13 +25506,13 @@ function decodeTicketFromPng(imageBytes) {
|
|
|
25122
25506
|
}
|
|
25123
25507
|
async function persistPairingQr(input) {
|
|
25124
25508
|
const mkdirImpl = input.dependencies.mkdirImpl ?? mkdir7;
|
|
25125
|
-
const readdirImpl = input.dependencies.readdirImpl ??
|
|
25509
|
+
const readdirImpl = input.dependencies.readdirImpl ?? readdir2;
|
|
25126
25510
|
const unlinkImpl = input.dependencies.unlinkImpl ?? unlink2;
|
|
25127
25511
|
const writeFileImpl = input.dependencies.writeFileImpl ?? writeFile7;
|
|
25128
25512
|
const getConfigDirImpl = input.dependencies.getConfigDirImpl ?? getConfigDir;
|
|
25129
25513
|
const qrEncodeImpl = input.dependencies.qrEncodeImpl ?? encodeTicketQrPng;
|
|
25130
25514
|
const baseDir = join8(getConfigDirImpl(), PAIRING_QR_DIR_NAME);
|
|
25131
|
-
const outputPath =
|
|
25515
|
+
const outputPath = parseNonEmptyString10(input.qrOutput) ? resolve(input.qrOutput ?? "") : join8(
|
|
25132
25516
|
baseDir,
|
|
25133
25517
|
`${assertValidAgentName(input.agentName)}-pair-${input.nowSeconds}.png`
|
|
25134
25518
|
);
|
|
@@ -25169,8 +25553,8 @@ async function persistPairingQr(input) {
|
|
|
25169
25553
|
return outputPath;
|
|
25170
25554
|
}
|
|
25171
25555
|
function resolveConfirmTicketSource(options) {
|
|
25172
|
-
const inlineTicket =
|
|
25173
|
-
const qrFile =
|
|
25556
|
+
const inlineTicket = parseNonEmptyString10(options.ticket);
|
|
25557
|
+
const qrFile = parseNonEmptyString10(options.qrFile);
|
|
25174
25558
|
if (inlineTicket.length > 0 && qrFile.length > 0) {
|
|
25175
25559
|
throw createCliError7(
|
|
25176
25560
|
"CLI_PAIR_CONFIRM_INPUT_CONFLICT",
|
|
@@ -25347,6 +25731,12 @@ async function confirmPairing(agentName, options, dependencies = {}) {
|
|
|
25347
25731
|
}
|
|
25348
25732
|
ticket = parsePairingTicket(qrDecodeImpl(new Uint8Array(imageBytes)));
|
|
25349
25733
|
}
|
|
25734
|
+
ticket = parsePairingTicket(ticket);
|
|
25735
|
+
assertTicketIssuerMatchesProxy({
|
|
25736
|
+
ticket,
|
|
25737
|
+
proxyUrl,
|
|
25738
|
+
context: "confirm"
|
|
25739
|
+
});
|
|
25350
25740
|
const { ait, secretKey } = await readAgentProofMaterial(
|
|
25351
25741
|
normalizedAgentName,
|
|
25352
25742
|
dependencies
|
|
@@ -25424,6 +25814,11 @@ async function getPairingStatusOnce(agentName, options, dependencies = {}) {
|
|
|
25424
25814
|
fetchImpl
|
|
25425
25815
|
});
|
|
25426
25816
|
const ticket = parsePairingTicket(options.ticket);
|
|
25817
|
+
assertTicketIssuerMatchesProxy({
|
|
25818
|
+
ticket,
|
|
25819
|
+
proxyUrl,
|
|
25820
|
+
context: "status"
|
|
25821
|
+
});
|
|
25427
25822
|
const { ait, secretKey } = await readAgentProofMaterial(
|
|
25428
25823
|
agentName,
|
|
25429
25824
|
dependencies
|
|
@@ -25529,7 +25924,7 @@ async function waitForPairingStatus(input) {
|
|
|
25529
25924
|
}
|
|
25530
25925
|
}
|
|
25531
25926
|
async function getPairingStatus(agentName, options, dependencies = {}) {
|
|
25532
|
-
const ticketRaw =
|
|
25927
|
+
const ticketRaw = parseNonEmptyString10(options.ticket);
|
|
25533
25928
|
if (ticketRaw.length === 0) {
|
|
25534
25929
|
throw createCliError7(
|
|
25535
25930
|
"CLI_PAIR_STATUS_TICKET_REQUIRED",
|
|
@@ -25740,7 +26135,7 @@ import { Command as Command9 } from "commander";
|
|
|
25740
26135
|
|
|
25741
26136
|
// src/install-skill-mode.ts
|
|
25742
26137
|
import { constants, existsSync as existsSync2 } from "fs";
|
|
25743
|
-
import { access as access3, copyFile as copyFile2, mkdir as mkdir8, readdir as
|
|
26138
|
+
import { access as access3, copyFile as copyFile2, mkdir as mkdir8, readdir as readdir3, readFile as readFile8 } from "fs/promises";
|
|
25744
26139
|
import { createRequire } from "module";
|
|
25745
26140
|
import { homedir as homedir4 } from "os";
|
|
25746
26141
|
import { dirname as dirname7, join as join9, relative } from "path";
|
|
@@ -25768,7 +26163,7 @@ function getErrorCode3(error48) {
|
|
|
25768
26163
|
}
|
|
25769
26164
|
return typeof error48.code === "string" ? error48.code : void 0;
|
|
25770
26165
|
}
|
|
25771
|
-
function
|
|
26166
|
+
function resolveHomeDir3(inputHomeDir) {
|
|
25772
26167
|
if (typeof inputHomeDir === "string" && inputHomeDir.trim().length > 0) {
|
|
25773
26168
|
return inputHomeDir.trim();
|
|
25774
26169
|
}
|
|
@@ -25841,7 +26236,7 @@ async function assertReadableFile(filePath, details) {
|
|
|
25841
26236
|
}
|
|
25842
26237
|
}
|
|
25843
26238
|
async function listFilesRecursively(directoryPath) {
|
|
25844
|
-
const entries = await
|
|
26239
|
+
const entries = await readdir3(directoryPath, { withFileTypes: true });
|
|
25845
26240
|
const files = [];
|
|
25846
26241
|
for (const entry of entries.sort(
|
|
25847
26242
|
(left, right) => left.name.localeCompare(right.name)
|
|
@@ -25950,7 +26345,7 @@ async function copyArtifact(input) {
|
|
|
25950
26345
|
}
|
|
25951
26346
|
async function installOpenclawSkillArtifacts(options = {}) {
|
|
25952
26347
|
const env = options.env ?? process.env;
|
|
25953
|
-
const homeDir =
|
|
26348
|
+
const homeDir = resolveHomeDir3(options.homeDir);
|
|
25954
26349
|
const openclawDir = resolveOpenclawDir2(homeDir, options.openclawDir);
|
|
25955
26350
|
const skillPackageRoot = resolveSkillPackageRoot({
|
|
25956
26351
|
skillPackageRoot: options.skillPackageRoot,
|