@lark-apaas/openclaw-scripts-diagnose-cli 0.1.1-alpha.29 → 0.1.1-alpha.30
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 +77 -4
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1458,6 +1458,79 @@ function execCaptureErr(cmd) {
|
|
|
1458
1458
|
function shellQuote(s) {
|
|
1459
1459
|
return `'${s.replace(/'/g, `'\\''`)}'`;
|
|
1460
1460
|
}
|
|
1461
|
+
/**
|
|
1462
|
+
* Extract an npm-packed gzipped tarball.
|
|
1463
|
+
*
|
|
1464
|
+
* ## The problem this works around
|
|
1465
|
+
*
|
|
1466
|
+
* Some tarballs (openclaw's among them — they're not packed by vanilla
|
|
1467
|
+
* `npm pack`) include relative symlinks inside nested .bin/ dirs whose
|
|
1468
|
+
* targets contain `..`, e.g.
|
|
1469
|
+
* node_modules/<pkg>/node_modules/.bin/foo -> ../foo/bin/cli.js
|
|
1470
|
+
*
|
|
1471
|
+
* GNU tar classifies any symlink target with `..` or a leading `/` as
|
|
1472
|
+
* "dangerous" and defers its extraction to a post-files pass, while also
|
|
1473
|
+
* needing a post-files pass to restore directory permissions/mtimes. The
|
|
1474
|
+
* two passes race: the deferred-symlink handling mutates parent-dir inodes,
|
|
1475
|
+
* then the directory stat-restore pass does `fstatat()` and the recorded
|
|
1476
|
+
* inode doesn't match, firing
|
|
1477
|
+
*
|
|
1478
|
+
* tar: <path>: Directory renamed before its status could be extracted
|
|
1479
|
+
*
|
|
1480
|
+
* from `apply_nonancestor_delayed_set_stat()` in extract.c. This is an
|
|
1481
|
+
* `ERROR` (hard-fail, exit 2) — the `--warning=no-rename-directory`
|
|
1482
|
+
* keyword controls a different, incremental-archive code path and does
|
|
1483
|
+
* NOT silence this. Reference: Paul Eggert, bug-tar 2004-04:
|
|
1484
|
+
* https://lists.gnu.org/archive/html/bug-tar/2004-04/msg00021.html
|
|
1485
|
+
*
|
|
1486
|
+
* ## The fix
|
|
1487
|
+
*
|
|
1488
|
+
* Pass `--absolute-names` (aka `-P`). Per GNU tar docs, this disables the
|
|
1489
|
+
* "normalize dangerous names" logic — including the deferred-symlink pass
|
|
1490
|
+
* that's racing us. Also stops stripping leading `/`, but our tarballs
|
|
1491
|
+
* only contain relative (`./node_modules/...`) paths so there's nothing
|
|
1492
|
+
* to strip. Safe because:
|
|
1493
|
+
* - The tarball is sha512-verified upstream (downloadWithCache)
|
|
1494
|
+
* - All entry paths are relative, no absolute-path escape risk
|
|
1495
|
+
* - All dangerous symlink targets resolve within the extracted tree
|
|
1496
|
+
*
|
|
1497
|
+
* ## Belt-and-suspenders
|
|
1498
|
+
*
|
|
1499
|
+
* If some tar variant still emits the error despite -P, we fall through
|
|
1500
|
+
* to checking the stderr pattern: if every error line is the benign
|
|
1501
|
+
* "Directory renamed …" text (no real failures like ENOSPC/EACCES/gzip
|
|
1502
|
+
* CRC/etc.), swallow exit 2. Callers MUST still verify extraction
|
|
1503
|
+
* (e.g. `fs.existsSync(path.join(dest, 'package.json'))`) — tar's
|
|
1504
|
+
* `skip_this_one = 1` after the error means some dirs missed their
|
|
1505
|
+
* mtime/mode restore, but content was written.
|
|
1506
|
+
*/
|
|
1507
|
+
function extractTarballTolerant(tarball, destDir, opts = {}) {
|
|
1508
|
+
const strip = opts.stripComponents ?? 0;
|
|
1509
|
+
const stripFlag = strip > 0 ? ` --strip-components=${strip}` : "";
|
|
1510
|
+
const cmd = `tar -xzf ${shellQuote(tarball)} -C ${shellQuote(destDir)}${stripFlag} -P`;
|
|
1511
|
+
try {
|
|
1512
|
+
execCaptureErr(cmd);
|
|
1513
|
+
return;
|
|
1514
|
+
} catch (e) {
|
|
1515
|
+
const msg = e?.message ?? "";
|
|
1516
|
+
const hasFalseAlarm = msg.includes("Directory renamed before its status could be extracted");
|
|
1517
|
+
const hasFatal = [
|
|
1518
|
+
/Cannot open/i,
|
|
1519
|
+
/Cannot mkdir/i,
|
|
1520
|
+
/Cannot create/i,
|
|
1521
|
+
/No space left on device/i,
|
|
1522
|
+
/Disk quota exceeded/i,
|
|
1523
|
+
/Permission denied/i,
|
|
1524
|
+
/Read-only file system/i,
|
|
1525
|
+
/unrecognized option/i,
|
|
1526
|
+
/gzip:/i,
|
|
1527
|
+
/Unexpected EOF/i,
|
|
1528
|
+
/Invalid argument/i
|
|
1529
|
+
].some((r) => r.test(msg));
|
|
1530
|
+
if (!hasFalseAlarm || hasFatal) throw e;
|
|
1531
|
+
console.error(`[tar] -P did not suppress "Directory renamed" on ${tarball}; tolerating (content must be verified by caller)`);
|
|
1532
|
+
}
|
|
1533
|
+
}
|
|
1461
1534
|
//#endregion
|
|
1462
1535
|
//#region src/reset-async.ts
|
|
1463
1536
|
/**
|
|
@@ -1590,7 +1663,7 @@ async function installOpenclaw(openclawTag, ossFileMap, opts = {}) {
|
|
|
1590
1663
|
node_fs.default.mkdirSync(node_path.default.dirname(targetDir), { recursive: true });
|
|
1591
1664
|
const tmpStage = node_fs.default.mkdtempSync(node_path.default.join(opts.tmpRoot ?? node_os.default.tmpdir(), "openclaw-install-"));
|
|
1592
1665
|
try {
|
|
1593
|
-
|
|
1666
|
+
extractTarballTolerant(tarball, tmpStage, { stripComponents: 1 });
|
|
1594
1667
|
if (!node_fs.default.existsSync(node_path.default.join(tmpStage, "package.json"))) throw new Error("extracted tarball missing package.json");
|
|
1595
1668
|
moveSafe(tmpStage, newDir);
|
|
1596
1669
|
const hadExisting = node_fs.default.existsSync(targetDir);
|
|
@@ -1703,7 +1776,7 @@ function installOne(pkg, tarball, homeBase) {
|
|
|
1703
1776
|
});
|
|
1704
1777
|
node_fs.default.mkdirSync(stagingDir);
|
|
1705
1778
|
try {
|
|
1706
|
-
|
|
1779
|
+
extractTarballTolerant(tarball, stagingDir, { stripComponents: 1 });
|
|
1707
1780
|
if (!node_fs.default.existsSync(node_path.default.join(stagingDir, "package.json"))) throw new Error(`extension tarball missing package.json: ${pkg.name}`);
|
|
1708
1781
|
} catch (e) {
|
|
1709
1782
|
try {
|
|
@@ -1741,7 +1814,7 @@ async function downloadResource(tag, ossFileMap, opts) {
|
|
|
1741
1814
|
const format = (pkg.format ?? "").toLowerCase();
|
|
1742
1815
|
const lower = pkg.ossKey.toLowerCase();
|
|
1743
1816
|
if (format === "tgz" || lower.endsWith(".tgz") || lower.endsWith(".tar.gz")) {
|
|
1744
|
-
|
|
1817
|
+
extractTarballTolerant(file, extractDir);
|
|
1745
1818
|
console.error(`[download-resource] ${opts.role}/${opts.name}: extracted to ${extractDir}`);
|
|
1746
1819
|
} else {
|
|
1747
1820
|
const basename = node_path.default.posix.basename(pkg.ossKey);
|
|
@@ -2520,7 +2593,7 @@ async function runDoctor(rawCtx, opts) {
|
|
|
2520
2593
|
//#region src/help.ts
|
|
2521
2594
|
const BIN = "mclaw-diagnose";
|
|
2522
2595
|
function versionBanner() {
|
|
2523
|
-
return `v0.1.1-alpha.
|
|
2596
|
+
return `v0.1.1-alpha.30`;
|
|
2524
2597
|
}
|
|
2525
2598
|
const COMMANDS = [
|
|
2526
2599
|
{
|
package/package.json
CHANGED