@lark-apaas/openclaw-scripts-diagnose-cli 0.1.1-alpha.25 → 0.1.1-alpha.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +176 -83
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -365,6 +365,74 @@ ConfigSyntaxRule = __decorate([Rule({
|
|
|
365
365
|
repairMode: "ai"
|
|
366
366
|
})], ConfigSyntaxRule);
|
|
367
367
|
//#endregion
|
|
368
|
+
//#region src/rules/template-vars-unreplaced.ts
|
|
369
|
+
/**
|
|
370
|
+
* Placeholder format used by miaoda-openclaw-template and Go-side templateVars,
|
|
371
|
+
* e.g. `$$__FEISHU_APP_ID__`. Double underscores on both sides act as a natural
|
|
372
|
+
* boundary so split-join replacement can't accidentally overlap between keys.
|
|
373
|
+
*/
|
|
374
|
+
const PLACEHOLDER_RE = /\$\$__[A-Z0-9_]+__/g;
|
|
375
|
+
let TemplateVarsUnreplacedRule = class TemplateVarsUnreplacedRule extends DiagnoseRule {
|
|
376
|
+
validate(ctx) {
|
|
377
|
+
const found = /* @__PURE__ */ new Set();
|
|
378
|
+
collectPlaceholders(ctx.config, found);
|
|
379
|
+
if (found.size === 0) return { pass: true };
|
|
380
|
+
return {
|
|
381
|
+
pass: false,
|
|
382
|
+
message: "存在未替换的模板占位符: " + [...found].sort().join(", ")
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
repair(ctx) {
|
|
386
|
+
const map = ctx.templateVars;
|
|
387
|
+
if (!map || Object.keys(map).length === 0) return;
|
|
388
|
+
replaceInPlace(ctx.config, Object.entries(map));
|
|
389
|
+
}
|
|
390
|
+
};
|
|
391
|
+
TemplateVarsUnreplacedRule = __decorate([Rule({
|
|
392
|
+
key: "template_vars_unreplaced",
|
|
393
|
+
dependsOn: ["config_syntax_check"],
|
|
394
|
+
repairMode: "standard"
|
|
395
|
+
})], TemplateVarsUnreplacedRule);
|
|
396
|
+
function collectPlaceholders(value, found) {
|
|
397
|
+
if (typeof value === "string") {
|
|
398
|
+
const matches = value.match(PLACEHOLDER_RE);
|
|
399
|
+
if (matches) for (const m of matches) found.add(m);
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
402
|
+
if (Array.isArray(value)) {
|
|
403
|
+
for (const v of value) collectPlaceholders(v, found);
|
|
404
|
+
return;
|
|
405
|
+
}
|
|
406
|
+
if (value && typeof value === "object") for (const v of Object.values(value)) collectPlaceholders(v, found);
|
|
407
|
+
}
|
|
408
|
+
function replaceInPlace(value, entries) {
|
|
409
|
+
if (Array.isArray(value)) {
|
|
410
|
+
for (let i = 0; i < value.length; i++) {
|
|
411
|
+
const el = value[i];
|
|
412
|
+
if (typeof el === "string") value[i] = applyVars(el, entries);
|
|
413
|
+
else replaceInPlace(el, entries);
|
|
414
|
+
}
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
if (value && typeof value === "object") {
|
|
418
|
+
const obj = value;
|
|
419
|
+
for (const key of Object.keys(obj)) {
|
|
420
|
+
const v = obj[key];
|
|
421
|
+
if (typeof v === "string") obj[key] = applyVars(v, entries);
|
|
422
|
+
else replaceInPlace(v, entries);
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
/** Split-join replacement — matches the algorithm in reset.ts:120 and avoids regex-escaping `$$`. */
|
|
427
|
+
function applyVars(str, entries) {
|
|
428
|
+
let out = str;
|
|
429
|
+
for (const [placeholder, value] of entries) {
|
|
430
|
+
if (!value) continue;
|
|
431
|
+
if (out.includes(placeholder)) out = out.split(placeholder).join(value);
|
|
432
|
+
}
|
|
433
|
+
return out;
|
|
434
|
+
}
|
|
435
|
+
//#endregion
|
|
368
436
|
//#region src/rules/model-provider.ts
|
|
369
437
|
var _ModelProviderRule;
|
|
370
438
|
let ModelProviderRule = class ModelProviderRule extends DiagnoseRule {
|
|
@@ -877,74 +945,6 @@ SecretsRule = __decorate([Rule({
|
|
|
877
945
|
skipWhen: ({ hasMiaoda, deps }) => !hasMiaoda || !deps.usesMiaodaSecretProvider
|
|
878
946
|
})], SecretsRule);
|
|
879
947
|
//#endregion
|
|
880
|
-
//#region src/rules/template-vars-unreplaced.ts
|
|
881
|
-
/**
|
|
882
|
-
* Placeholder format used by miaoda-openclaw-template and Go-side templateVars,
|
|
883
|
-
* e.g. `$$__FEISHU_APP_ID__`. Double underscores on both sides act as a natural
|
|
884
|
-
* boundary so split-join replacement can't accidentally overlap between keys.
|
|
885
|
-
*/
|
|
886
|
-
const PLACEHOLDER_RE = /\$\$__[A-Z0-9_]+__/g;
|
|
887
|
-
let TemplateVarsUnreplacedRule = class TemplateVarsUnreplacedRule extends DiagnoseRule {
|
|
888
|
-
validate(ctx) {
|
|
889
|
-
const found = /* @__PURE__ */ new Set();
|
|
890
|
-
collectPlaceholders(ctx.config, found);
|
|
891
|
-
if (found.size === 0) return { pass: true };
|
|
892
|
-
return {
|
|
893
|
-
pass: false,
|
|
894
|
-
message: "存在未替换的模板占位符: " + [...found].sort().join(", ")
|
|
895
|
-
};
|
|
896
|
-
}
|
|
897
|
-
repair(ctx) {
|
|
898
|
-
const map = ctx.templateVars;
|
|
899
|
-
if (!map || Object.keys(map).length === 0) return;
|
|
900
|
-
replaceInPlace(ctx.config, Object.entries(map));
|
|
901
|
-
}
|
|
902
|
-
};
|
|
903
|
-
TemplateVarsUnreplacedRule = __decorate([Rule({
|
|
904
|
-
key: "template_vars_unreplaced",
|
|
905
|
-
dependsOn: ["config_syntax_check"],
|
|
906
|
-
repairMode: "standard"
|
|
907
|
-
})], TemplateVarsUnreplacedRule);
|
|
908
|
-
function collectPlaceholders(value, found) {
|
|
909
|
-
if (typeof value === "string") {
|
|
910
|
-
const matches = value.match(PLACEHOLDER_RE);
|
|
911
|
-
if (matches) for (const m of matches) found.add(m);
|
|
912
|
-
return;
|
|
913
|
-
}
|
|
914
|
-
if (Array.isArray(value)) {
|
|
915
|
-
for (const v of value) collectPlaceholders(v, found);
|
|
916
|
-
return;
|
|
917
|
-
}
|
|
918
|
-
if (value && typeof value === "object") for (const v of Object.values(value)) collectPlaceholders(v, found);
|
|
919
|
-
}
|
|
920
|
-
function replaceInPlace(value, entries) {
|
|
921
|
-
if (Array.isArray(value)) {
|
|
922
|
-
for (let i = 0; i < value.length; i++) {
|
|
923
|
-
const el = value[i];
|
|
924
|
-
if (typeof el === "string") value[i] = applyVars(el, entries);
|
|
925
|
-
else replaceInPlace(el, entries);
|
|
926
|
-
}
|
|
927
|
-
return;
|
|
928
|
-
}
|
|
929
|
-
if (value && typeof value === "object") {
|
|
930
|
-
const obj = value;
|
|
931
|
-
for (const key of Object.keys(obj)) {
|
|
932
|
-
const v = obj[key];
|
|
933
|
-
if (typeof v === "string") obj[key] = applyVars(v, entries);
|
|
934
|
-
else replaceInPlace(v, entries);
|
|
935
|
-
}
|
|
936
|
-
}
|
|
937
|
-
}
|
|
938
|
-
/** Split-join replacement — matches the algorithm in reset.ts:120 and avoids regex-escaping `$$`. */
|
|
939
|
-
function applyVars(str, entries) {
|
|
940
|
-
let out = str;
|
|
941
|
-
for (const [placeholder, value] of entries) {
|
|
942
|
-
if (!value) continue;
|
|
943
|
-
if (out.includes(placeholder)) out = out.split(placeholder).join(value);
|
|
944
|
-
}
|
|
945
|
-
return out;
|
|
946
|
-
}
|
|
947
|
-
//#endregion
|
|
948
948
|
//#region src/rules/cleanup-install-backup-dirs.ts
|
|
949
949
|
const DIR_PREFIX = ".openclaw-install-";
|
|
950
950
|
function resolveExtensionsDir(configPath) {
|
|
@@ -962,7 +962,7 @@ function findLeftoverDirs(extensionsDir) {
|
|
|
962
962
|
}
|
|
963
963
|
let CleanupInstallBackupDirsRule = class CleanupInstallBackupDirsRule extends DiagnoseRule {
|
|
964
964
|
validate(ctx) {
|
|
965
|
-
const configPath = ctx
|
|
965
|
+
const { configPath } = ctx;
|
|
966
966
|
if (!configPath) return { pass: true };
|
|
967
967
|
const dirs = findLeftoverDirs(resolveExtensionsDir(configPath));
|
|
968
968
|
if (dirs.length === 0) return { pass: true };
|
|
@@ -972,7 +972,7 @@ let CleanupInstallBackupDirsRule = class CleanupInstallBackupDirsRule extends Di
|
|
|
972
972
|
};
|
|
973
973
|
}
|
|
974
974
|
repair(ctx) {
|
|
975
|
-
const configPath = ctx
|
|
975
|
+
const { configPath } = ctx;
|
|
976
976
|
if (!configPath) return;
|
|
977
977
|
const dirs = findLeftoverDirs(resolveExtensionsDir(configPath));
|
|
978
978
|
const failures = [];
|
|
@@ -1322,6 +1322,54 @@ const SECRETS_FILE_PATH = "/home/gem/workspace/.force/openclaw/miaoda-openclaw-s
|
|
|
1322
1322
|
const CONFIG_PATH = `${WORKSPACE_DIR}/openclaw.json`;
|
|
1323
1323
|
//#endregion
|
|
1324
1324
|
//#region src/logger.ts
|
|
1325
|
+
/**
|
|
1326
|
+
* Shared CLI log file. Every log line the CLI emits — whether through
|
|
1327
|
+
* `console.error` (rules, helpers, errors) or through the per-task
|
|
1328
|
+
* `makeLogger` (reset worker) — is tee'd here so operators have a single
|
|
1329
|
+
* file to tail when diagnosing a sandbox.
|
|
1330
|
+
*
|
|
1331
|
+
* `/tmp` is ephemeral on sandbox restart; we rely on that for rotation
|
|
1332
|
+
* (no size-based rotation implemented).
|
|
1333
|
+
*/
|
|
1334
|
+
const CLI_LOG_FILE = "/tmp/openclaw-diagnose/cli.log";
|
|
1335
|
+
/** Append one line to the shared cli.log. Swallows any fs error —
|
|
1336
|
+
* logging must never break the business flow. */
|
|
1337
|
+
function appendCliLog(line) {
|
|
1338
|
+
try {
|
|
1339
|
+
const dir = node_path.default.dirname(CLI_LOG_FILE);
|
|
1340
|
+
if (!node_fs.default.existsSync(dir)) node_fs.default.mkdirSync(dir, { recursive: true });
|
|
1341
|
+
node_fs.default.appendFileSync(CLI_LOG_FILE, line);
|
|
1342
|
+
} catch {}
|
|
1343
|
+
}
|
|
1344
|
+
let stderrMirrorInstalled = false;
|
|
1345
|
+
/**
|
|
1346
|
+
* Install a process-wide `console.error` interceptor that mirrors each
|
|
1347
|
+
* line to BOTH the original stderr AND cli.log. Call once at CLI entry
|
|
1348
|
+
* before any subcommand dispatch; idempotent.
|
|
1349
|
+
*
|
|
1350
|
+
* Why console.error and not console.log: the CLI's stdout carries the
|
|
1351
|
+
* structured JSON result protocol consumed by sandbox_console and other
|
|
1352
|
+
* callers — any log line on stdout would corrupt JSON parsing. Rules,
|
|
1353
|
+
* helpers, and error paths therefore must route debug output through
|
|
1354
|
+
* console.error (stderr).
|
|
1355
|
+
*/
|
|
1356
|
+
function installStderrMirror() {
|
|
1357
|
+
if (stderrMirrorInstalled) return;
|
|
1358
|
+
stderrMirrorInstalled = true;
|
|
1359
|
+
const original = console.error.bind(console);
|
|
1360
|
+
console.error = (...args) => {
|
|
1361
|
+
original(...args);
|
|
1362
|
+
const body = args.map((a) => typeof a === "string" ? a : safeStringify(a)).join(" ");
|
|
1363
|
+
appendCliLog(`[${(/* @__PURE__ */ new Date()).toISOString()}] ${body}\n`);
|
|
1364
|
+
};
|
|
1365
|
+
}
|
|
1366
|
+
function safeStringify(v) {
|
|
1367
|
+
try {
|
|
1368
|
+
return JSON.stringify(v);
|
|
1369
|
+
} catch {
|
|
1370
|
+
return String(v);
|
|
1371
|
+
}
|
|
1372
|
+
}
|
|
1325
1373
|
function makeLogger(logFile) {
|
|
1326
1374
|
try {
|
|
1327
1375
|
const dir = node_path.default.dirname(logFile);
|
|
@@ -1332,9 +1380,45 @@ function makeLogger(logFile) {
|
|
|
1332
1380
|
try {
|
|
1333
1381
|
node_fs.default.appendFileSync(logFile, line);
|
|
1334
1382
|
} catch {}
|
|
1383
|
+
appendCliLog(line);
|
|
1335
1384
|
};
|
|
1336
1385
|
}
|
|
1337
1386
|
//#endregion
|
|
1387
|
+
//#region src/fs-utils.ts
|
|
1388
|
+
/**
|
|
1389
|
+
* Rename src → dst, falling back to `mv` (which handles cross-device copy)
|
|
1390
|
+
* when the kernel returns EXDEV.
|
|
1391
|
+
*
|
|
1392
|
+
* Sandbox filesystems can put sibling paths on different "devices" from
|
|
1393
|
+
* rename(2)'s point of view: bind mounts, overlayfs copy-up, and
|
|
1394
|
+
* mount-point children inside a single directory all trip EXDEV. Seen in
|
|
1395
|
+
* production when reset's atomic swap did
|
|
1396
|
+
* /home/gem/.npm-global/lib/node_modules/openclaw → openclaw.bak
|
|
1397
|
+
* and the openclaw subdir was a bind-mounted volume.
|
|
1398
|
+
*
|
|
1399
|
+
* Behavior:
|
|
1400
|
+
* - Happy path hits rename(2) — atomic, single syscall, microseconds.
|
|
1401
|
+
* - EXDEV path shells out to `mv`, which does rename() then copy+unlink
|
|
1402
|
+
* on failure. Non-atomic but correct; callers already have rollback
|
|
1403
|
+
* logic (install-openclaw restores from .bak) so loss of atomicity
|
|
1404
|
+
* only matters if the process dies mid-copy, and that's survivable.
|
|
1405
|
+
* - Any other error (ENOENT, EACCES, EBUSY...) rethrows as-is so callers
|
|
1406
|
+
* see the real problem instead of a misleading `mv` fallback failure.
|
|
1407
|
+
*/
|
|
1408
|
+
function moveSafe(src, dst) {
|
|
1409
|
+
try {
|
|
1410
|
+
node_fs.default.renameSync(src, dst);
|
|
1411
|
+
} catch (e) {
|
|
1412
|
+
if (e?.code !== "EXDEV") throw e;
|
|
1413
|
+
(0, node_child_process.execSync)(`mv ${shellQuote(src)} ${shellQuote(dst)}`, { stdio: "ignore" });
|
|
1414
|
+
}
|
|
1415
|
+
}
|
|
1416
|
+
/** POSIX single-quote shell escape. Paths with embedded quotes are rare but
|
|
1417
|
+
* the token-file path conventions in sandboxes don't guarantee cleanliness. */
|
|
1418
|
+
function shellQuote(s) {
|
|
1419
|
+
return `'${s.replace(/'/g, `'\\''`)}'`;
|
|
1420
|
+
}
|
|
1421
|
+
//#endregion
|
|
1338
1422
|
//#region src/reset-async.ts
|
|
1339
1423
|
/**
|
|
1340
1424
|
* Start an async reset task: spawn a detached child process and return the taskId.
|
|
@@ -1357,7 +1441,7 @@ function startAsyncReset(ctxBase64) {
|
|
|
1357
1441
|
const dir = node_path.default.dirname(resultFile);
|
|
1358
1442
|
if (!node_fs.default.existsSync(dir)) node_fs.default.mkdirSync(dir, { recursive: true });
|
|
1359
1443
|
node_fs.default.writeFileSync(tmpPath, JSON.stringify(initial), "utf-8");
|
|
1360
|
-
|
|
1444
|
+
moveSafe(tmpPath, resultFile);
|
|
1361
1445
|
const child = (0, node_child_process.spawn)(process.execPath, [
|
|
1362
1446
|
process.argv[1],
|
|
1363
1447
|
"reset",
|
|
@@ -1381,7 +1465,7 @@ function startAsyncReset(ctxBase64) {
|
|
|
1381
1465
|
};
|
|
1382
1466
|
const errTmpPath = resultFile + ".tmp";
|
|
1383
1467
|
node_fs.default.writeFileSync(errTmpPath, JSON.stringify(failResult));
|
|
1384
|
-
|
|
1468
|
+
moveSafe(errTmpPath, resultFile);
|
|
1385
1469
|
});
|
|
1386
1470
|
child.unref();
|
|
1387
1471
|
log(`spawned worker pid=${child.pid}`);
|
|
@@ -1389,10 +1473,16 @@ function startAsyncReset(ctxBase64) {
|
|
|
1389
1473
|
}
|
|
1390
1474
|
//#endregion
|
|
1391
1475
|
//#region src/oss/fetchManifest.ts
|
|
1476
|
+
const MANIFEST_PREFIX = "builtin/manifests/openclaw/recommended/";
|
|
1477
|
+
const MANIFEST_SUFFIX = ".json";
|
|
1392
1478
|
async function fetchManifest(ossFileMap, tag) {
|
|
1393
|
-
const key =
|
|
1479
|
+
const key = `${MANIFEST_PREFIX}${tag}${MANIFEST_SUFFIX}`;
|
|
1394
1480
|
const url = ossFileMap[key];
|
|
1395
|
-
if (!url)
|
|
1481
|
+
if (!url) {
|
|
1482
|
+
const available = Object.keys(ossFileMap).filter((k) => k.startsWith(MANIFEST_PREFIX) && k.endsWith(MANIFEST_SUFFIX)).map((k) => k.slice(39, -5));
|
|
1483
|
+
const availStr = available.length ? available.join(", ") : "(none)";
|
|
1484
|
+
throw new Error(`manifest signed URL missing for tag "${tag}" (key ${key}). Available tags in ossFileMap: ${availStr}. Either pass an available tag or update the studio_server TCC openclaw_upgrade_config supported_versions.`);
|
|
1485
|
+
}
|
|
1396
1486
|
const res = await fetch(url);
|
|
1397
1487
|
if (!res.ok) throw new Error(`fetch manifest failed: HTTP ${res.status} ${res.statusText}`);
|
|
1398
1488
|
return await res.json();
|
|
@@ -1430,7 +1520,7 @@ async function downloadWithCache(pkg, ossFileMap, opts = {}) {
|
|
|
1430
1520
|
console.error(`⚠ [downloadWithCache] INTEGRITY BYPASS for ${pkg.ossKey}: expected ${expected.slice(0, 12)}… got ${actual.slice(0, 12)}… — ${sourceLabel}. DO NOT use this flag in production.`);
|
|
1431
1521
|
} else throw new Error(`integrity mismatch for ${pkg.ossKey}: expected ${expected} got ${actual}`);
|
|
1432
1522
|
}
|
|
1433
|
-
|
|
1523
|
+
moveSafe(tmpFile, destFile);
|
|
1434
1524
|
return destFile;
|
|
1435
1525
|
} catch (e) {
|
|
1436
1526
|
try {
|
|
@@ -1453,7 +1543,7 @@ async function installOpenclaw(openclawTag, ossFileMap, opts = {}) {
|
|
|
1453
1543
|
force: true
|
|
1454
1544
|
});
|
|
1455
1545
|
const hadExisting = node_fs.default.existsSync(targetDir);
|
|
1456
|
-
if (hadExisting)
|
|
1546
|
+
if (hadExisting) moveSafe(targetDir, bakDir);
|
|
1457
1547
|
try {
|
|
1458
1548
|
node_fs.default.mkdirSync(targetDir, { recursive: true });
|
|
1459
1549
|
(0, node_child_process.execSync)(`tar -xzf '${tarball}' -C '${targetDir}' --strip-components=1`, { stdio: "ignore" });
|
|
@@ -1465,7 +1555,7 @@ async function installOpenclaw(openclawTag, ossFileMap, opts = {}) {
|
|
|
1465
1555
|
force: true
|
|
1466
1556
|
});
|
|
1467
1557
|
} catch {}
|
|
1468
|
-
if (hadExisting && node_fs.default.existsSync(bakDir))
|
|
1558
|
+
if (hadExisting && node_fs.default.existsSync(bakDir)) moveSafe(bakDir, targetDir);
|
|
1469
1559
|
throw e;
|
|
1470
1560
|
}
|
|
1471
1561
|
if (node_fs.default.existsSync(bakDir)) node_fs.default.rmSync(bakDir, {
|
|
@@ -1540,7 +1630,7 @@ function updatePluginInstalls(configPath, installedPkgs) {
|
|
|
1540
1630
|
} else skipped++;
|
|
1541
1631
|
const tmpPath = configPath + ".installs-tmp";
|
|
1542
1632
|
node_fs.default.writeFileSync(tmpPath, JSON.stringify(config, null, 2), "utf-8");
|
|
1543
|
-
|
|
1633
|
+
moveSafe(tmpPath, configPath);
|
|
1544
1634
|
console.error(`[install-extension] plugins.installs updated: ${updated} entry(ies) in ${configPath}` + (skipped > 0 ? ` (${skipped} package(s) without installMetadata skipped)` : ""));
|
|
1545
1635
|
}
|
|
1546
1636
|
function installOne(pkg, tarball, homeBase) {
|
|
@@ -1566,8 +1656,8 @@ function installOne(pkg, tarball, homeBase) {
|
|
|
1566
1656
|
throw e;
|
|
1567
1657
|
}
|
|
1568
1658
|
const hadOld = node_fs.default.existsSync(destDir);
|
|
1569
|
-
if (hadOld)
|
|
1570
|
-
|
|
1659
|
+
if (hadOld) moveSafe(destDir, oldDir);
|
|
1660
|
+
moveSafe(stagingDir, destDir);
|
|
1571
1661
|
if (hadOld && node_fs.default.existsSync(oldDir)) node_fs.default.rmSync(oldDir, {
|
|
1572
1662
|
recursive: true,
|
|
1573
1663
|
force: true
|
|
@@ -1634,7 +1724,7 @@ function writeResultFile(resultFile, result) {
|
|
|
1634
1724
|
if (!node_fs.default.existsSync(dir)) node_fs.default.mkdirSync(dir, { recursive: true });
|
|
1635
1725
|
const tmpPath = resultFile + ".tmp";
|
|
1636
1726
|
node_fs.default.writeFileSync(tmpPath, JSON.stringify(result), "utf-8");
|
|
1637
|
-
|
|
1727
|
+
moveSafe(tmpPath, resultFile);
|
|
1638
1728
|
}
|
|
1639
1729
|
function updateProgress(resultFile, step, startedAt) {
|
|
1640
1730
|
writeResultFile(resultFile, {
|
|
@@ -1946,7 +2036,8 @@ async function runReset(input, taskId, resultFile) {
|
|
|
1946
2036
|
process.exit(1);
|
|
1947
2037
|
}
|
|
1948
2038
|
let openclawTag;
|
|
1949
|
-
|
|
2039
|
+
if (resetData.openclawTag) openclawTag = resetData.openclawTag;
|
|
2040
|
+
else try {
|
|
1950
2041
|
openclawTag = getOpenclawTagFromOssFileMap(ossFileMap);
|
|
1951
2042
|
} catch (e) {
|
|
1952
2043
|
const err = e.message;
|
|
@@ -2340,7 +2431,8 @@ function buildResetInput(raw, configPathOverride) {
|
|
|
2340
2431
|
secretsContent: ctx.secrets.secretsContent,
|
|
2341
2432
|
providerKeyContent: ctx.secrets.providerKeyContent,
|
|
2342
2433
|
coreBackup: ctx.reset.coreBackup,
|
|
2343
|
-
ossFileMap: ctx.install.ossFileMap
|
|
2434
|
+
ossFileMap: ctx.install.ossFileMap,
|
|
2435
|
+
openclawTag: ctx.install.openclawTag
|
|
2344
2436
|
}
|
|
2345
2437
|
};
|
|
2346
2438
|
}
|
|
@@ -2400,6 +2492,7 @@ function getMultiFlag(args, name) {
|
|
|
2400
2492
|
return args.filter((a) => a.startsWith(prefix)).map((a) => a.slice(prefix.length));
|
|
2401
2493
|
}
|
|
2402
2494
|
async function main() {
|
|
2495
|
+
installStderrMirror();
|
|
2403
2496
|
switch (mode) {
|
|
2404
2497
|
case "check":
|
|
2405
2498
|
case "repair": {
|
package/package.json
CHANGED