@newlandnpt/pep-cli 0.9.2 → 0.9.3
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/pep.cjs +96 -4
- package/package.json +1 -1
package/dist/pep.cjs
CHANGED
|
@@ -684,6 +684,7 @@ public static class PepCredential {
|
|
|
684
684
|
function encodedPowerShell(script) {
|
|
685
685
|
return Buffer.from(script, "utf16le").toString("base64");
|
|
686
686
|
}
|
|
687
|
+
var CREDENTIAL_TOOL_TIMEOUT_MS = 6e4;
|
|
687
688
|
async function runPowerShell(script, input) {
|
|
688
689
|
return new Promise((resolve5, reject) => {
|
|
689
690
|
const child = (0, import_node_child_process2.spawn)(
|
|
@@ -699,7 +700,11 @@ async function runPowerShell(script, input) {
|
|
|
699
700
|
);
|
|
700
701
|
let stdout = "";
|
|
701
702
|
let stderr = "";
|
|
702
|
-
|
|
703
|
+
let killed = false;
|
|
704
|
+
const timeout = setTimeout(() => {
|
|
705
|
+
killed = true;
|
|
706
|
+
child.kill();
|
|
707
|
+
}, CREDENTIAL_TOOL_TIMEOUT_MS);
|
|
703
708
|
child.stdout.setEncoding("utf8").on("data", (chunk) => stdout += chunk);
|
|
704
709
|
child.stderr.setEncoding("utf8").on("data", (chunk) => stderr += chunk);
|
|
705
710
|
child.once(
|
|
@@ -708,6 +713,14 @@ async function runPowerShell(script, input) {
|
|
|
708
713
|
);
|
|
709
714
|
child.once("close", (code) => {
|
|
710
715
|
clearTimeout(timeout);
|
|
716
|
+
if (killed) {
|
|
717
|
+
reject(
|
|
718
|
+
new Error(
|
|
719
|
+
`Windows Credential Manager did not answer within ${CREDENTIAL_TOOL_TIMEOUT_MS / 1e3}s. The machine may be heavily loaded \u2014 try again.`
|
|
720
|
+
)
|
|
721
|
+
);
|
|
722
|
+
return;
|
|
723
|
+
}
|
|
711
724
|
if (code === 0) resolve5(stdout.trim());
|
|
712
725
|
else
|
|
713
726
|
reject(
|
|
@@ -768,7 +781,11 @@ async function runSecurity(args) {
|
|
|
768
781
|
});
|
|
769
782
|
let stdout = "";
|
|
770
783
|
let stderr = "";
|
|
771
|
-
|
|
784
|
+
let killed = false;
|
|
785
|
+
const timeout = setTimeout(() => {
|
|
786
|
+
killed = true;
|
|
787
|
+
child.kill();
|
|
788
|
+
}, CREDENTIAL_TOOL_TIMEOUT_MS);
|
|
772
789
|
child.stdout.setEncoding("utf8").on("data", (chunk) => stdout += chunk);
|
|
773
790
|
child.stderr.setEncoding("utf8").on("data", (chunk) => stderr += chunk);
|
|
774
791
|
child.once(
|
|
@@ -777,6 +794,14 @@ async function runSecurity(args) {
|
|
|
777
794
|
);
|
|
778
795
|
child.once("close", (code) => {
|
|
779
796
|
clearTimeout(timeout);
|
|
797
|
+
if (killed) {
|
|
798
|
+
reject(
|
|
799
|
+
new Error(
|
|
800
|
+
`macOS Keychain did not answer within ${CREDENTIAL_TOOL_TIMEOUT_MS / 1e3}s. The machine may be heavily loaded \u2014 try again.`
|
|
801
|
+
)
|
|
802
|
+
);
|
|
803
|
+
return;
|
|
804
|
+
}
|
|
780
805
|
resolve5({ code: code ?? -1, stdout, stderr });
|
|
781
806
|
});
|
|
782
807
|
});
|
|
@@ -1117,6 +1142,30 @@ async function blobShaOfFile(path) {
|
|
|
1117
1142
|
});
|
|
1118
1143
|
return digest.digest("hex");
|
|
1119
1144
|
}
|
|
1145
|
+
function humanBytes(n) {
|
|
1146
|
+
if (n < 1024) return `${n} B`;
|
|
1147
|
+
const units = ["KB", "MB", "GB"];
|
|
1148
|
+
let value = n / 1024;
|
|
1149
|
+
let unit = 0;
|
|
1150
|
+
while (value >= 1024 && unit < units.length - 1) {
|
|
1151
|
+
value /= 1024;
|
|
1152
|
+
unit += 1;
|
|
1153
|
+
}
|
|
1154
|
+
return `${value.toFixed(value < 10 ? 1 : 0)} ${units[unit]}`;
|
|
1155
|
+
}
|
|
1156
|
+
function formatProgress(progress, width = 24) {
|
|
1157
|
+
if (progress.phase === "verifying") return " verifying\u2026";
|
|
1158
|
+
const { bytes, total, elapsedMs } = progress;
|
|
1159
|
+
const speed = elapsedMs > 0 && bytes > 0 ? ` \xB7 ${humanBytes(bytes / elapsedMs * 1e3)}/s` : "";
|
|
1160
|
+
if (total === void 0 || total <= 0) {
|
|
1161
|
+
return ` ${humanBytes(bytes)}${speed}`;
|
|
1162
|
+
}
|
|
1163
|
+
const ratio = Math.min(1, bytes / total);
|
|
1164
|
+
const filled = Math.round(ratio * width);
|
|
1165
|
+
const bar = `${"\u2588".repeat(filled)}${"\u2591".repeat(width - filled)}`;
|
|
1166
|
+
const pct = `${Math.floor(ratio * 100)}`.padStart(3);
|
|
1167
|
+
return ` ${bar} ${pct}% ${humanBytes(bytes)} / ${humanBytes(total)}${speed}`;
|
|
1168
|
+
}
|
|
1120
1169
|
async function downloadResource(dependencies, resource, options) {
|
|
1121
1170
|
const file = (0, import_node_path3.basename)(resource.file);
|
|
1122
1171
|
if (file !== resource.file || file === "." || file === "..") {
|
|
@@ -1149,8 +1198,26 @@ async function downloadResource(dependencies, resource, options) {
|
|
|
1149
1198
|
await (0, import_promises3.mkdir)(directory, { recursive: true });
|
|
1150
1199
|
const temporary = `${target}.${process.pid}.part`;
|
|
1151
1200
|
try {
|
|
1201
|
+
const report = options.onProgress;
|
|
1202
|
+
const startedAt = Date.now();
|
|
1203
|
+
let seen = 0;
|
|
1152
1204
|
await (0, import_promises4.pipeline)(
|
|
1153
1205
|
import_node_stream.Readable.fromWeb(response.body),
|
|
1206
|
+
// ⚠ 这一层**无条件**插着,没有回调时它只是加一个数。本来想「没人听就不插」,
|
|
1207
|
+
// 但那要往 `pipeline(...)` 里展开一个数组,TS 的重载当场推不出来;为省一层
|
|
1208
|
+
// generator 去跟类型较劲不划算。
|
|
1209
|
+
async function* (source) {
|
|
1210
|
+
for await (const chunk of source) {
|
|
1211
|
+
seen += chunk.length;
|
|
1212
|
+
report?.({
|
|
1213
|
+
phase: "downloading",
|
|
1214
|
+
bytes: seen,
|
|
1215
|
+
...Number.isFinite(declared) && declared > 0 ? { total: declared } : {},
|
|
1216
|
+
elapsedMs: Date.now() - startedAt
|
|
1217
|
+
});
|
|
1218
|
+
yield chunk;
|
|
1219
|
+
}
|
|
1220
|
+
},
|
|
1154
1221
|
(0, import_node_fs.createWriteStream)(temporary)
|
|
1155
1222
|
);
|
|
1156
1223
|
const bytes = (await (0, import_promises3.stat)(temporary)).size;
|
|
@@ -1161,6 +1228,7 @@ async function downloadResource(dependencies, resource, options) {
|
|
|
1161
1228
|
}
|
|
1162
1229
|
let verified = "none";
|
|
1163
1230
|
if (expected !== void 0) {
|
|
1231
|
+
options.onProgress?.({ phase: "verifying" });
|
|
1164
1232
|
const actual = (await blobShaOfFile(temporary)).slice(0, 12);
|
|
1165
1233
|
if (actual !== expected) {
|
|
1166
1234
|
throw new Error(
|
|
@@ -2484,8 +2552,29 @@ async function planSetup(dependencies) {
|
|
|
2484
2552
|
}
|
|
2485
2553
|
|
|
2486
2554
|
// src/cli.ts
|
|
2487
|
-
var VERSION = false ? "0.0.0-dev" : "0.9.
|
|
2555
|
+
var VERSION = false ? "0.0.0-dev" : "0.9.3";
|
|
2488
2556
|
var SKILLS_ADD_DEPRECATION = "\u26A0 `pep skills add` will be removed in a future release.";
|
|
2557
|
+
function createProgressReporter(stream = process.stderr) {
|
|
2558
|
+
if (!stream.isTTY) return void 0;
|
|
2559
|
+
const INTERVAL_MS = 100;
|
|
2560
|
+
let lastAt = 0;
|
|
2561
|
+
let painted = false;
|
|
2562
|
+
const paint = (line) => {
|
|
2563
|
+
stream.write(`\r${" ".repeat(78)}\r${line}`);
|
|
2564
|
+
painted = true;
|
|
2565
|
+
};
|
|
2566
|
+
return {
|
|
2567
|
+
report(progress) {
|
|
2568
|
+
const now = Date.now();
|
|
2569
|
+
if (progress.phase === "downloading" && now - lastAt < INTERVAL_MS) return;
|
|
2570
|
+
lastAt = now;
|
|
2571
|
+
paint(formatProgress(progress));
|
|
2572
|
+
},
|
|
2573
|
+
done() {
|
|
2574
|
+
if (painted) stream.write(`\r${" ".repeat(78)}\r`);
|
|
2575
|
+
}
|
|
2576
|
+
};
|
|
2577
|
+
}
|
|
2489
2578
|
function reportUpdate(result) {
|
|
2490
2579
|
const conflicts = () => {
|
|
2491
2580
|
for (const { skill, owner } of result.conflicts) {
|
|
@@ -2922,11 +3011,14 @@ ${usage(VERSION, [group])}`);
|
|
|
2922
3011
|
return;
|
|
2923
3012
|
}
|
|
2924
3013
|
const target = pickResource(all, wantedFile);
|
|
3014
|
+
const progress = createProgressReporter();
|
|
2925
3015
|
const result = await downloadResource(dependencies, target, {
|
|
2926
3016
|
// 默认落在**执行命令时的当前目录**,不是 CLI 装在哪儿。
|
|
2927
3017
|
directory: intoDirectory ?? process.cwd(),
|
|
2928
|
-
force
|
|
3018
|
+
force,
|
|
3019
|
+
...progress ? { onProgress: progress.report } : {}
|
|
2929
3020
|
});
|
|
3021
|
+
progress?.done();
|
|
2930
3022
|
console.error(
|
|
2931
3023
|
result.verified === "blob-sha" ? ` ${result.bytes} bytes, content hash verified` : result.verified === "content-length" ? ` ${result.bytes} bytes, length verified (no content hash in the address)` : ` ${result.bytes} bytes \u2014 the server declared neither length nor content hash`
|
|
2932
3024
|
);
|