harnessed 2.0.0 → 2.0.1
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/cli.mjs +151 -146
- package/dist/cli.mjs.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/cli.mjs
CHANGED
|
@@ -785,7 +785,7 @@ var init_resume = __esm({
|
|
|
785
785
|
|
|
786
786
|
// package.json
|
|
787
787
|
var package_default = {
|
|
788
|
-
version: "2.0.
|
|
788
|
+
version: "2.0.1"};
|
|
789
789
|
|
|
790
790
|
// src/manifest/errors.ts
|
|
791
791
|
function instancePathToKeyPath(instancePath) {
|
|
@@ -1566,7 +1566,7 @@ function renderHumanTable(records) {
|
|
|
1566
1566
|
}
|
|
1567
1567
|
}
|
|
1568
1568
|
function pipeToJq(filterExpr, lines) {
|
|
1569
|
-
return new Promise((
|
|
1569
|
+
return new Promise((resolve8, reject) => {
|
|
1570
1570
|
const child = spawn("jq", [filterExpr], {
|
|
1571
1571
|
stdio: ["pipe", "inherit", "inherit"],
|
|
1572
1572
|
windowsHide: true
|
|
@@ -1575,12 +1575,12 @@ function pipeToJq(filterExpr, lines) {
|
|
|
1575
1575
|
const e = err2;
|
|
1576
1576
|
if (e.code === "ENOENT") {
|
|
1577
1577
|
console.error("\u2717 jq not found in PATH \u2014 run: harnessed doctor");
|
|
1578
|
-
|
|
1578
|
+
resolve8(1);
|
|
1579
1579
|
} else {
|
|
1580
1580
|
reject(err2);
|
|
1581
1581
|
}
|
|
1582
1582
|
});
|
|
1583
|
-
child.on("close", (code) =>
|
|
1583
|
+
child.on("close", (code) => resolve8(code ?? 0));
|
|
1584
1584
|
child.stdin.write(lines.join("\n"));
|
|
1585
1585
|
child.stdin.end();
|
|
1586
1586
|
});
|
|
@@ -1638,19 +1638,132 @@ function registerAuditLog(program2) {
|
|
|
1638
1638
|
}
|
|
1639
1639
|
);
|
|
1640
1640
|
}
|
|
1641
|
+
function getBackupRoot() {
|
|
1642
|
+
return join(homedir(), ".harnessed", "backups");
|
|
1643
|
+
}
|
|
1644
|
+
var HOME_DIR = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
1645
|
+
function mirrorPath(target, scope, backupDir) {
|
|
1646
|
+
const root = scope === "HOME" ? HOME_DIR : ".";
|
|
1647
|
+
const rel = root ? relative(root, target) : target;
|
|
1648
|
+
if (!rel || rel.startsWith("..")) {
|
|
1649
|
+
const flat = createHash("sha1").update(target).digest("hex").slice(0, 16);
|
|
1650
|
+
return join(backupDir, scope, flat);
|
|
1651
|
+
}
|
|
1652
|
+
return join(backupDir, scope, rel);
|
|
1653
|
+
}
|
|
1654
|
+
function detectEol(buf) {
|
|
1655
|
+
return buf.includes("\r\n") ? "crlf" : "lf";
|
|
1656
|
+
}
|
|
1657
|
+
async function backup(plan, ctx) {
|
|
1658
|
+
const filename = ctx.manifest.metadata.name;
|
|
1659
|
+
const backupId = (/* @__PURE__ */ new Date()).toISOString().replace(/:/g, "-");
|
|
1660
|
+
const backupDir = join(getBackupRoot(), backupId);
|
|
1661
|
+
try {
|
|
1662
|
+
await mkdir(backupDir, { recursive: true });
|
|
1663
|
+
} catch (err2) {
|
|
1664
|
+
return {
|
|
1665
|
+
ok: false,
|
|
1666
|
+
error: {
|
|
1667
|
+
file: filename,
|
|
1668
|
+
path: "/",
|
|
1669
|
+
message: `failed to create backup dir ${backupDir}: ${err2.message}`,
|
|
1670
|
+
line: null,
|
|
1671
|
+
column: null,
|
|
1672
|
+
keyword: "backup-mkdir-failed"
|
|
1673
|
+
}
|
|
1674
|
+
};
|
|
1675
|
+
}
|
|
1676
|
+
const entries = [];
|
|
1677
|
+
for (const file of plan.files) {
|
|
1678
|
+
let buf;
|
|
1679
|
+
try {
|
|
1680
|
+
buf = await readFile(file.target);
|
|
1681
|
+
} catch (err2) {
|
|
1682
|
+
const code = err2.code;
|
|
1683
|
+
if (code === "ENOENT" && file.oldText === "") {
|
|
1684
|
+
entries.push({
|
|
1685
|
+
target: file.target,
|
|
1686
|
+
backup: "",
|
|
1687
|
+
// sentinel: no backup written; rollback should unlink target
|
|
1688
|
+
sha1: "",
|
|
1689
|
+
eol: "lf"
|
|
1690
|
+
// moot for non-existent file; default to lf
|
|
1691
|
+
});
|
|
1692
|
+
continue;
|
|
1693
|
+
}
|
|
1694
|
+
return {
|
|
1695
|
+
ok: false,
|
|
1696
|
+
error: {
|
|
1697
|
+
file: filename,
|
|
1698
|
+
path: file.target,
|
|
1699
|
+
message: `failed to read original file for backup: ${err2.message}`,
|
|
1700
|
+
line: null,
|
|
1701
|
+
column: null,
|
|
1702
|
+
keyword: "backup-read-failed"
|
|
1703
|
+
}
|
|
1704
|
+
};
|
|
1705
|
+
}
|
|
1706
|
+
const sha1 = createHash("sha1").update(buf).digest("hex");
|
|
1707
|
+
const eol = detectEol(buf);
|
|
1708
|
+
const dest = mirrorPath(file.target, file.scope, backupDir);
|
|
1709
|
+
try {
|
|
1710
|
+
await mkdir(dirname(dest), { recursive: true });
|
|
1711
|
+
await writeFile(dest, buf);
|
|
1712
|
+
} catch (err2) {
|
|
1713
|
+
return {
|
|
1714
|
+
ok: false,
|
|
1715
|
+
error: {
|
|
1716
|
+
file: filename,
|
|
1717
|
+
path: dest,
|
|
1718
|
+
message: `failed to write backup copy: ${err2.message}`,
|
|
1719
|
+
line: null,
|
|
1720
|
+
column: null,
|
|
1721
|
+
keyword: "backup-write-failed"
|
|
1722
|
+
}
|
|
1723
|
+
};
|
|
1724
|
+
}
|
|
1725
|
+
entries.push({ target: file.target, backup: dest, sha1, eol });
|
|
1726
|
+
}
|
|
1727
|
+
const metadata = {
|
|
1728
|
+
installer: filename,
|
|
1729
|
+
manifest: filename,
|
|
1730
|
+
timestamp: backupId,
|
|
1731
|
+
files: entries
|
|
1732
|
+
};
|
|
1733
|
+
const metadataPath = join(backupDir, "metadata.json");
|
|
1734
|
+
try {
|
|
1735
|
+
await writeFile(metadataPath, `${JSON.stringify(metadata, null, 2)}
|
|
1736
|
+
`, "utf8");
|
|
1737
|
+
} catch (err2) {
|
|
1738
|
+
return {
|
|
1739
|
+
ok: false,
|
|
1740
|
+
error: {
|
|
1741
|
+
file: filename,
|
|
1742
|
+
path: metadataPath,
|
|
1743
|
+
message: `failed to write metadata.json: ${err2.message}`,
|
|
1744
|
+
line: null,
|
|
1745
|
+
column: null,
|
|
1746
|
+
keyword: "backup-metadata-failed"
|
|
1747
|
+
}
|
|
1748
|
+
};
|
|
1749
|
+
}
|
|
1750
|
+
return { ok: true, backupId, backupDir };
|
|
1751
|
+
}
|
|
1752
|
+
|
|
1753
|
+
// src/cli/backup-list.ts
|
|
1641
1754
|
function registerBackupList(program2) {
|
|
1642
1755
|
const backup2 = program2.command("backup").description("Backup snapshot operations");
|
|
1643
1756
|
backup2.command("list").description("List backup snapshots under .harnessed-backup/").action(async () => {
|
|
1644
|
-
const root =
|
|
1757
|
+
const root = getBackupRoot();
|
|
1645
1758
|
let dirs;
|
|
1646
1759
|
try {
|
|
1647
1760
|
dirs = (await readdir(root, { withFileTypes: true })).filter((e) => e.isDirectory()).map((e) => e.name).sort();
|
|
1648
1761
|
} catch {
|
|
1649
|
-
console.log(
|
|
1762
|
+
console.log(`no backups found (${root} absent)`);
|
|
1650
1763
|
return;
|
|
1651
1764
|
}
|
|
1652
1765
|
if (dirs.length === 0) {
|
|
1653
|
-
console.log(
|
|
1766
|
+
console.log(`no backups found (${root} empty)`);
|
|
1654
1767
|
return;
|
|
1655
1768
|
}
|
|
1656
1769
|
for (const ts of dirs) {
|
|
@@ -2721,12 +2834,12 @@ function registerGc(program2) {
|
|
|
2721
2834
|
return;
|
|
2722
2835
|
}
|
|
2723
2836
|
const keepLast = Number.parseInt(opts.keepLast ?? "0", 10);
|
|
2724
|
-
const root =
|
|
2837
|
+
const root = getBackupRoot();
|
|
2725
2838
|
let dirs;
|
|
2726
2839
|
try {
|
|
2727
2840
|
dirs = (await readdir(root, { withFileTypes: true })).filter((e) => e.isDirectory()).map((e) => e.name).sort();
|
|
2728
2841
|
} catch {
|
|
2729
|
-
console.log(
|
|
2842
|
+
console.log(`no backups found (${root} absent) \u2014 nothing to gc`);
|
|
2730
2843
|
return;
|
|
2731
2844
|
}
|
|
2732
2845
|
const cutoff = Date.now() - olderMs;
|
|
@@ -2763,114 +2876,6 @@ function registerGc(program2) {
|
|
|
2763
2876
|
if (dryRun) console.log("\n(dry-run \u2014 re-run with --apply to actually delete)");
|
|
2764
2877
|
});
|
|
2765
2878
|
}
|
|
2766
|
-
var HOME_DIR = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
2767
|
-
function mirrorPath(target, scope, backupDir) {
|
|
2768
|
-
const root = scope === "HOME" ? HOME_DIR : ".";
|
|
2769
|
-
const rel = root ? relative(root, target) : target;
|
|
2770
|
-
if (!rel || rel.startsWith("..")) {
|
|
2771
|
-
const flat = createHash("sha1").update(target).digest("hex").slice(0, 16);
|
|
2772
|
-
return join(backupDir, scope, flat);
|
|
2773
|
-
}
|
|
2774
|
-
return join(backupDir, scope, rel);
|
|
2775
|
-
}
|
|
2776
|
-
function detectEol(buf) {
|
|
2777
|
-
return buf.includes("\r\n") ? "crlf" : "lf";
|
|
2778
|
-
}
|
|
2779
|
-
async function backup(plan, ctx) {
|
|
2780
|
-
const filename = ctx.manifest.metadata.name;
|
|
2781
|
-
const backupId = (/* @__PURE__ */ new Date()).toISOString().replace(/:/g, "-");
|
|
2782
|
-
const backupDir = join(ctx.cwd, ".harnessed-backup", backupId);
|
|
2783
|
-
try {
|
|
2784
|
-
await mkdir(backupDir, { recursive: true });
|
|
2785
|
-
} catch (err2) {
|
|
2786
|
-
return {
|
|
2787
|
-
ok: false,
|
|
2788
|
-
error: {
|
|
2789
|
-
file: filename,
|
|
2790
|
-
path: "/",
|
|
2791
|
-
message: `failed to create backup dir ${backupDir}: ${err2.message}`,
|
|
2792
|
-
line: null,
|
|
2793
|
-
column: null,
|
|
2794
|
-
keyword: "backup-mkdir-failed"
|
|
2795
|
-
}
|
|
2796
|
-
};
|
|
2797
|
-
}
|
|
2798
|
-
const entries = [];
|
|
2799
|
-
for (const file of plan.files) {
|
|
2800
|
-
let buf;
|
|
2801
|
-
try {
|
|
2802
|
-
buf = await readFile(file.target);
|
|
2803
|
-
} catch (err2) {
|
|
2804
|
-
const code = err2.code;
|
|
2805
|
-
if (code === "ENOENT" && file.oldText === "") {
|
|
2806
|
-
entries.push({
|
|
2807
|
-
target: file.target,
|
|
2808
|
-
backup: "",
|
|
2809
|
-
// sentinel: no backup written; rollback should unlink target
|
|
2810
|
-
sha1: "",
|
|
2811
|
-
eol: "lf"
|
|
2812
|
-
// moot for non-existent file; default to lf
|
|
2813
|
-
});
|
|
2814
|
-
continue;
|
|
2815
|
-
}
|
|
2816
|
-
return {
|
|
2817
|
-
ok: false,
|
|
2818
|
-
error: {
|
|
2819
|
-
file: filename,
|
|
2820
|
-
path: file.target,
|
|
2821
|
-
message: `failed to read original file for backup: ${err2.message}`,
|
|
2822
|
-
line: null,
|
|
2823
|
-
column: null,
|
|
2824
|
-
keyword: "backup-read-failed"
|
|
2825
|
-
}
|
|
2826
|
-
};
|
|
2827
|
-
}
|
|
2828
|
-
const sha1 = createHash("sha1").update(buf).digest("hex");
|
|
2829
|
-
const eol = detectEol(buf);
|
|
2830
|
-
const dest = mirrorPath(file.target, file.scope, backupDir);
|
|
2831
|
-
try {
|
|
2832
|
-
await mkdir(dirname(dest), { recursive: true });
|
|
2833
|
-
await writeFile(dest, buf);
|
|
2834
|
-
} catch (err2) {
|
|
2835
|
-
return {
|
|
2836
|
-
ok: false,
|
|
2837
|
-
error: {
|
|
2838
|
-
file: filename,
|
|
2839
|
-
path: dest,
|
|
2840
|
-
message: `failed to write backup copy: ${err2.message}`,
|
|
2841
|
-
line: null,
|
|
2842
|
-
column: null,
|
|
2843
|
-
keyword: "backup-write-failed"
|
|
2844
|
-
}
|
|
2845
|
-
};
|
|
2846
|
-
}
|
|
2847
|
-
entries.push({ target: file.target, backup: dest, sha1, eol });
|
|
2848
|
-
}
|
|
2849
|
-
const metadata = {
|
|
2850
|
-
installer: filename,
|
|
2851
|
-
manifest: filename,
|
|
2852
|
-
timestamp: backupId,
|
|
2853
|
-
files: entries
|
|
2854
|
-
};
|
|
2855
|
-
const metadataPath = join(backupDir, "metadata.json");
|
|
2856
|
-
try {
|
|
2857
|
-
await writeFile(metadataPath, `${JSON.stringify(metadata, null, 2)}
|
|
2858
|
-
`, "utf8");
|
|
2859
|
-
} catch (err2) {
|
|
2860
|
-
return {
|
|
2861
|
-
ok: false,
|
|
2862
|
-
error: {
|
|
2863
|
-
file: filename,
|
|
2864
|
-
path: metadataPath,
|
|
2865
|
-
message: `failed to write metadata.json: ${err2.message}`,
|
|
2866
|
-
line: null,
|
|
2867
|
-
column: null,
|
|
2868
|
-
keyword: "backup-metadata-failed"
|
|
2869
|
-
}
|
|
2870
|
-
};
|
|
2871
|
-
}
|
|
2872
|
-
return { ok: true, backupId, backupDir };
|
|
2873
|
-
}
|
|
2874
2879
|
async function confirmAt(level, ctx) {
|
|
2875
2880
|
if (level === "L4" && !ctx.opts.system) {
|
|
2876
2881
|
if (!ctx.opts.nonInteractive) {
|
|
@@ -3152,7 +3157,7 @@ var installCcHookAdd = async (ctx) => {
|
|
|
3152
3157
|
return { ok: true, backupId: bk.backupId, appliedFiles: [settingsPath] };
|
|
3153
3158
|
};
|
|
3154
3159
|
function runArgs(claudeArgs, cwd, timeoutMs = 15e3) {
|
|
3155
|
-
return new Promise((
|
|
3160
|
+
return new Promise((resolve8) => {
|
|
3156
3161
|
const isWin = process.platform === "win32";
|
|
3157
3162
|
const child = isWin ? spawn("cmd.exe", ["/c", "claude", ...claudeArgs], { cwd, windowsHide: true }) : spawn("claude", claudeArgs, { cwd, shell: false });
|
|
3158
3163
|
let stderr = "";
|
|
@@ -3161,15 +3166,15 @@ function runArgs(claudeArgs, cwd, timeoutMs = 15e3) {
|
|
|
3161
3166
|
});
|
|
3162
3167
|
const timer = setTimeout(() => {
|
|
3163
3168
|
child.kill("SIGKILL");
|
|
3164
|
-
|
|
3169
|
+
resolve8({ exitCode: -1, stderr: `${stderr}[timeout after ${timeoutMs}ms]` });
|
|
3165
3170
|
}, timeoutMs);
|
|
3166
3171
|
child.on("error", (e) => {
|
|
3167
3172
|
clearTimeout(timer);
|
|
3168
|
-
|
|
3173
|
+
resolve8({ exitCode: -1, stderr: `${stderr}${e.message}` });
|
|
3169
3174
|
});
|
|
3170
3175
|
child.on("close", (code) => {
|
|
3171
3176
|
clearTimeout(timer);
|
|
3172
|
-
|
|
3177
|
+
resolve8({ exitCode: code ?? -1, stderr });
|
|
3173
3178
|
});
|
|
3174
3179
|
});
|
|
3175
3180
|
}
|
|
@@ -3310,7 +3315,7 @@ ${newEntry}
|
|
|
3310
3315
|
)
|
|
3311
3316
|
};
|
|
3312
3317
|
}
|
|
3313
|
-
const vr = await new Promise((
|
|
3318
|
+
const vr = await new Promise((resolve8) => {
|
|
3314
3319
|
const child = spawn(verifyShell, [verifyFlag, verifyLine], { cwd: ctx.cwd, windowsHide: true });
|
|
3315
3320
|
let stderr = "";
|
|
3316
3321
|
child.stderr?.setEncoding("utf8").on("data", (c) => {
|
|
@@ -3318,15 +3323,15 @@ ${newEntry}
|
|
|
3318
3323
|
});
|
|
3319
3324
|
const timer = setTimeout(() => {
|
|
3320
3325
|
child.kill("SIGKILL");
|
|
3321
|
-
|
|
3326
|
+
resolve8({ exitCode: -1, stderr: `${stderr}[timeout]` });
|
|
3322
3327
|
}, 15e3);
|
|
3323
3328
|
child.on("error", (e) => {
|
|
3324
3329
|
clearTimeout(timer);
|
|
3325
|
-
|
|
3330
|
+
resolve8({ exitCode: -1, stderr: e.message });
|
|
3326
3331
|
});
|
|
3327
3332
|
child.on("close", (code) => {
|
|
3328
3333
|
clearTimeout(timer);
|
|
3329
|
-
|
|
3334
|
+
resolve8({ exitCode: code ?? -1, stderr });
|
|
3330
3335
|
});
|
|
3331
3336
|
});
|
|
3332
3337
|
if (vr.exitCode !== 0) {
|
|
@@ -3382,10 +3387,10 @@ async function spawnCmd(ctx, cmd, args) {
|
|
|
3382
3387
|
child.stderr?.setEncoding("utf8").on("data", (chunk) => {
|
|
3383
3388
|
stderr += chunk;
|
|
3384
3389
|
});
|
|
3385
|
-
return await new Promise((
|
|
3390
|
+
return await new Promise((resolve8) => {
|
|
3386
3391
|
const timer = setTimeout(() => {
|
|
3387
3392
|
child.kill("SIGKILL");
|
|
3388
|
-
|
|
3393
|
+
resolve8({
|
|
3389
3394
|
ok: false,
|
|
3390
3395
|
phase: "spawn",
|
|
3391
3396
|
error: {
|
|
@@ -3400,7 +3405,7 @@ async function spawnCmd(ctx, cmd, args) {
|
|
|
3400
3405
|
}, timeoutMs);
|
|
3401
3406
|
child.on("error", (err2) => {
|
|
3402
3407
|
clearTimeout(timer);
|
|
3403
|
-
|
|
3408
|
+
resolve8({
|
|
3404
3409
|
ok: false,
|
|
3405
3410
|
phase: "spawn",
|
|
3406
3411
|
error: {
|
|
@@ -3415,14 +3420,14 @@ async function spawnCmd(ctx, cmd, args) {
|
|
|
3415
3420
|
});
|
|
3416
3421
|
child.on("close", (code) => {
|
|
3417
3422
|
clearTimeout(timer);
|
|
3418
|
-
|
|
3423
|
+
resolve8({ ok: true, exitCode: code ?? -1, stdout: stdout2, stderr });
|
|
3419
3424
|
});
|
|
3420
3425
|
});
|
|
3421
3426
|
}
|
|
3422
3427
|
|
|
3423
3428
|
// src/installers/gitCloneWithSetup.ts
|
|
3424
3429
|
function gitRevParseHead(cwd, timeoutMs = 1e4) {
|
|
3425
|
-
return new Promise((
|
|
3430
|
+
return new Promise((resolve8) => {
|
|
3426
3431
|
const isWin = process.platform === "win32";
|
|
3427
3432
|
const child = isWin ? spawn("cmd.exe", ["/c", "git", "rev-parse", "HEAD"], { cwd, windowsHide: true }) : spawn("git", ["rev-parse", "HEAD"], { cwd, shell: false });
|
|
3428
3433
|
let stdout2 = "";
|
|
@@ -3431,15 +3436,15 @@ function gitRevParseHead(cwd, timeoutMs = 1e4) {
|
|
|
3431
3436
|
});
|
|
3432
3437
|
const timer = setTimeout(() => {
|
|
3433
3438
|
child.kill("SIGKILL");
|
|
3434
|
-
|
|
3439
|
+
resolve8({ sha: "", exit: -1 });
|
|
3435
3440
|
}, timeoutMs);
|
|
3436
3441
|
child.on("error", () => {
|
|
3437
3442
|
clearTimeout(timer);
|
|
3438
|
-
|
|
3443
|
+
resolve8({ sha: "", exit: -1 });
|
|
3439
3444
|
});
|
|
3440
3445
|
child.on("close", (code) => {
|
|
3441
3446
|
clearTimeout(timer);
|
|
3442
|
-
|
|
3447
|
+
resolve8({ sha: stdout2.trim(), exit: code ?? -1 });
|
|
3443
3448
|
});
|
|
3444
3449
|
});
|
|
3445
3450
|
}
|
|
@@ -3779,7 +3784,7 @@ ${newEntry}
|
|
|
3779
3784
|
)
|
|
3780
3785
|
};
|
|
3781
3786
|
}
|
|
3782
|
-
const vr = await new Promise((
|
|
3787
|
+
const vr = await new Promise((resolve8) => {
|
|
3783
3788
|
const child = spawn(verifyShell, [verifyFlag, verifyLine], { cwd: ctx.cwd, windowsHide: true });
|
|
3784
3789
|
let stderr = "";
|
|
3785
3790
|
child.stderr?.setEncoding("utf8").on("data", (c) => {
|
|
@@ -3787,15 +3792,15 @@ ${newEntry}
|
|
|
3787
3792
|
});
|
|
3788
3793
|
const timer = setTimeout(() => {
|
|
3789
3794
|
child.kill("SIGKILL");
|
|
3790
|
-
|
|
3795
|
+
resolve8({ exitCode: -1, stderr: `${stderr}[timeout]` });
|
|
3791
3796
|
}, 15e3);
|
|
3792
3797
|
child.on("error", (e) => {
|
|
3793
3798
|
clearTimeout(timer);
|
|
3794
|
-
|
|
3799
|
+
resolve8({ exitCode: -1, stderr: e.message });
|
|
3795
3800
|
});
|
|
3796
3801
|
child.on("close", (code) => {
|
|
3797
3802
|
clearTimeout(timer);
|
|
3798
|
-
|
|
3803
|
+
resolve8({ exitCode: code ?? -1, stderr });
|
|
3799
3804
|
});
|
|
3800
3805
|
});
|
|
3801
3806
|
if (vr.exitCode !== 0) {
|
|
@@ -3927,7 +3932,7 @@ ${newEntry}
|
|
|
3927
3932
|
)
|
|
3928
3933
|
};
|
|
3929
3934
|
}
|
|
3930
|
-
const vr = await new Promise((
|
|
3935
|
+
const vr = await new Promise((resolve8) => {
|
|
3931
3936
|
const child = spawn(verifyShell, [verifyFlag, verifyLine], { cwd: ctx.cwd, windowsHide: true });
|
|
3932
3937
|
let stderr = "";
|
|
3933
3938
|
child.stderr?.setEncoding("utf8").on("data", (c) => {
|
|
@@ -3935,15 +3940,15 @@ ${newEntry}
|
|
|
3935
3940
|
});
|
|
3936
3941
|
const timer = setTimeout(() => {
|
|
3937
3942
|
child.kill("SIGKILL");
|
|
3938
|
-
|
|
3943
|
+
resolve8({ exitCode: -1, stderr: `${stderr}[timeout]` });
|
|
3939
3944
|
}, 15e3);
|
|
3940
3945
|
child.on("error", (e) => {
|
|
3941
3946
|
clearTimeout(timer);
|
|
3942
|
-
|
|
3947
|
+
resolve8({ exitCode: -1, stderr: e.message });
|
|
3943
3948
|
});
|
|
3944
3949
|
child.on("close", (code) => {
|
|
3945
3950
|
clearTimeout(timer);
|
|
3946
|
-
|
|
3951
|
+
resolve8({ exitCode: code ?? -1, stderr });
|
|
3947
3952
|
});
|
|
3948
3953
|
});
|
|
3949
3954
|
if (vr.exitCode !== 0) {
|
|
@@ -4515,7 +4520,7 @@ function normalizeEol(buf, eol) {
|
|
|
4515
4520
|
}
|
|
4516
4521
|
function registerRollback(program2) {
|
|
4517
4522
|
program2.command("rollback <timestamp>").description("Restore files from a backup snapshot (preserves original LF/CRLF)").action(async (timestamp) => {
|
|
4518
|
-
const dir =
|
|
4523
|
+
const dir = join(getBackupRoot(), timestamp);
|
|
4519
4524
|
const metaPath = join(dir, "metadata.json");
|
|
4520
4525
|
let meta;
|
|
4521
4526
|
try {
|
|
@@ -4958,7 +4963,7 @@ var uninstallNpmCli = async (ctx) => {
|
|
|
4958
4963
|
const m = install.cmd.match(/npm\s+(?:install|i)\s+(?:-g\s+)?(\S+)/);
|
|
4959
4964
|
const pkg = m?.[1] ?? ctx.manifest.metadata.upstream.source;
|
|
4960
4965
|
const isWin = process.platform === "win32";
|
|
4961
|
-
const result = await new Promise((
|
|
4966
|
+
const result = await new Promise((resolve8) => {
|
|
4962
4967
|
const child = isWin ? spawn("cmd.exe", ["/c", "npm", "uninstall", "-g", pkg], { windowsHide: true }) : spawn("npm", ["uninstall", "-g", pkg], { shell: false });
|
|
4963
4968
|
let stderr = "";
|
|
4964
4969
|
child.stderr?.setEncoding("utf8").on("data", (c) => {
|
|
@@ -4966,15 +4971,15 @@ var uninstallNpmCli = async (ctx) => {
|
|
|
4966
4971
|
});
|
|
4967
4972
|
const timer = setTimeout(() => {
|
|
4968
4973
|
child.kill("SIGKILL");
|
|
4969
|
-
|
|
4974
|
+
resolve8({ exitCode: -1, stderr: `${stderr}[timeout]` });
|
|
4970
4975
|
}, 3e4);
|
|
4971
4976
|
child.on("error", (e) => {
|
|
4972
4977
|
clearTimeout(timer);
|
|
4973
|
-
|
|
4978
|
+
resolve8({ exitCode: -1, stderr: e.message });
|
|
4974
4979
|
});
|
|
4975
4980
|
child.on("close", (code) => {
|
|
4976
4981
|
clearTimeout(timer);
|
|
4977
|
-
|
|
4982
|
+
resolve8({ exitCode: code ?? -1, stderr });
|
|
4978
4983
|
});
|
|
4979
4984
|
});
|
|
4980
4985
|
if (result.exitCode !== 0) {
|