@serviceme/devtools-core 0.4.5 → 0.4.7
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.d.mts +14 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +99 -13
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +95 -9
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.d.mts
CHANGED
|
@@ -266,9 +266,17 @@ declare class EnvironmentInspector {
|
|
|
266
266
|
private readonly runCommandFn;
|
|
267
267
|
private readonly platform;
|
|
268
268
|
private readonly shell;
|
|
269
|
+
/**
|
|
270
|
+
* Per-check-cycle result cache. `checkEnvironment()` clears it before
|
|
271
|
+
* probing so a fresh cycle never returns stale results, while concurrent
|
|
272
|
+
* or repeated `checkTool()` calls within the same cycle share one probe
|
|
273
|
+
* (deduplicating expensive login-shell fallbacks).
|
|
274
|
+
*/
|
|
275
|
+
private readonly toolCheckCache;
|
|
269
276
|
constructor(options?: EnvironmentInspectorOptions);
|
|
270
277
|
checkEnvironment(): Promise<EnvironmentCheckResult>;
|
|
271
278
|
checkTool(toolName: KnownEnvironmentTool): Promise<ToolCheckResult>;
|
|
279
|
+
private performToolCheck;
|
|
272
280
|
private getToolPath;
|
|
273
281
|
private getToolPathFromLoginShell;
|
|
274
282
|
/**
|
|
@@ -281,6 +289,12 @@ declare class EnvironmentInspector {
|
|
|
281
289
|
private getToolVersion;
|
|
282
290
|
private shouldUsePosixLoginShellFallback;
|
|
283
291
|
private checkNvm;
|
|
292
|
+
/**
|
|
293
|
+
* Resolve `nvm.sh` from `$NVM_DIR` and the known install roots without
|
|
294
|
+
* spawning a shell. Returns undefined when nvm is not installed in any
|
|
295
|
+
* well-known location, letting callers skip a login-shell probe.
|
|
296
|
+
*/
|
|
297
|
+
private resolveNvmShPath;
|
|
284
298
|
private checkNuget;
|
|
285
299
|
private getVersionInvocation;
|
|
286
300
|
private getToolTimeout;
|
package/dist/index.d.ts
CHANGED
|
@@ -266,9 +266,17 @@ declare class EnvironmentInspector {
|
|
|
266
266
|
private readonly runCommandFn;
|
|
267
267
|
private readonly platform;
|
|
268
268
|
private readonly shell;
|
|
269
|
+
/**
|
|
270
|
+
* Per-check-cycle result cache. `checkEnvironment()` clears it before
|
|
271
|
+
* probing so a fresh cycle never returns stale results, while concurrent
|
|
272
|
+
* or repeated `checkTool()` calls within the same cycle share one probe
|
|
273
|
+
* (deduplicating expensive login-shell fallbacks).
|
|
274
|
+
*/
|
|
275
|
+
private readonly toolCheckCache;
|
|
269
276
|
constructor(options?: EnvironmentInspectorOptions);
|
|
270
277
|
checkEnvironment(): Promise<EnvironmentCheckResult>;
|
|
271
278
|
checkTool(toolName: KnownEnvironmentTool): Promise<ToolCheckResult>;
|
|
279
|
+
private performToolCheck;
|
|
272
280
|
private getToolPath;
|
|
273
281
|
private getToolPathFromLoginShell;
|
|
274
282
|
/**
|
|
@@ -281,6 +289,12 @@ declare class EnvironmentInspector {
|
|
|
281
289
|
private getToolVersion;
|
|
282
290
|
private shouldUsePosixLoginShellFallback;
|
|
283
291
|
private checkNvm;
|
|
292
|
+
/**
|
|
293
|
+
* Resolve `nvm.sh` from `$NVM_DIR` and the known install roots without
|
|
294
|
+
* spawning a shell. Returns undefined when nvm is not installed in any
|
|
295
|
+
* well-known location, letting callers skip a login-shell probe.
|
|
296
|
+
*/
|
|
297
|
+
private resolveNvmShPath;
|
|
284
298
|
private checkNuget;
|
|
285
299
|
private getVersionInvocation;
|
|
286
300
|
private getToolTimeout;
|
package/dist/index.js
CHANGED
|
@@ -1519,7 +1519,8 @@ var import_devtools_protocol2 = require("@serviceme/devtools-protocol");
|
|
|
1519
1519
|
|
|
1520
1520
|
// src/process/runCommand.ts
|
|
1521
1521
|
var import_node_child_process = require("child_process");
|
|
1522
|
-
|
|
1522
|
+
var FORCE_KILL_DELAY_MS = 2e3;
|
|
1523
|
+
function terminateCommandProcess(child, signal = "SIGTERM") {
|
|
1523
1524
|
if (child.killed) {
|
|
1524
1525
|
return;
|
|
1525
1526
|
}
|
|
@@ -1533,7 +1534,32 @@ function terminateCommandProcess(child) {
|
|
|
1533
1534
|
});
|
|
1534
1535
|
return;
|
|
1535
1536
|
}
|
|
1536
|
-
child.
|
|
1537
|
+
const pid = child.pid;
|
|
1538
|
+
if (pid) {
|
|
1539
|
+
try {
|
|
1540
|
+
process.kill(-pid, signal);
|
|
1541
|
+
return;
|
|
1542
|
+
} catch {
|
|
1543
|
+
}
|
|
1544
|
+
}
|
|
1545
|
+
child.kill(signal);
|
|
1546
|
+
}
|
|
1547
|
+
function scheduleForceKill(child) {
|
|
1548
|
+
if (process.platform === "win32") {
|
|
1549
|
+
return void 0;
|
|
1550
|
+
}
|
|
1551
|
+
const pid = child.pid;
|
|
1552
|
+
if (pid === void 0) {
|
|
1553
|
+
return void 0;
|
|
1554
|
+
}
|
|
1555
|
+
const timer = setTimeout(() => {
|
|
1556
|
+
try {
|
|
1557
|
+
process.kill(-pid, "SIGKILL");
|
|
1558
|
+
} catch {
|
|
1559
|
+
}
|
|
1560
|
+
}, FORCE_KILL_DELAY_MS);
|
|
1561
|
+
timer.unref?.();
|
|
1562
|
+
return timer;
|
|
1537
1563
|
}
|
|
1538
1564
|
async function runCommand(command, options = {}) {
|
|
1539
1565
|
return new Promise((resolve3, reject) => {
|
|
@@ -1542,12 +1568,16 @@ async function runCommand(command, options = {}) {
|
|
|
1542
1568
|
env: options.env,
|
|
1543
1569
|
shell: options.shell,
|
|
1544
1570
|
stdio: "pipe",
|
|
1545
|
-
windowsHide: true
|
|
1571
|
+
windowsHide: true,
|
|
1572
|
+
// POSIX: run the command in its own process group so a timeout can
|
|
1573
|
+
// terminate the whole tree (login shell + its children) at once.
|
|
1574
|
+
detached: process.platform !== "win32"
|
|
1546
1575
|
});
|
|
1547
1576
|
let stdout = "";
|
|
1548
1577
|
let stderr = "";
|
|
1549
1578
|
let finished = false;
|
|
1550
1579
|
let timeoutId;
|
|
1580
|
+
let forceKillTimer;
|
|
1551
1581
|
const finish = (handler) => {
|
|
1552
1582
|
if (finished) {
|
|
1553
1583
|
return;
|
|
@@ -1556,6 +1586,9 @@ async function runCommand(command, options = {}) {
|
|
|
1556
1586
|
if (timeoutId) {
|
|
1557
1587
|
clearTimeout(timeoutId);
|
|
1558
1588
|
}
|
|
1589
|
+
if (forceKillTimer) {
|
|
1590
|
+
clearTimeout(forceKillTimer);
|
|
1591
|
+
}
|
|
1559
1592
|
handler();
|
|
1560
1593
|
};
|
|
1561
1594
|
child.stdout?.setEncoding("utf8");
|
|
@@ -1570,6 +1603,10 @@ async function runCommand(command, options = {}) {
|
|
|
1570
1603
|
finish(() => reject(error));
|
|
1571
1604
|
});
|
|
1572
1605
|
child.once("close", (code) => {
|
|
1606
|
+
if (forceKillTimer) {
|
|
1607
|
+
clearTimeout(forceKillTimer);
|
|
1608
|
+
forceKillTimer = void 0;
|
|
1609
|
+
}
|
|
1573
1610
|
finish(() => {
|
|
1574
1611
|
if (code === 0) {
|
|
1575
1612
|
resolve3({
|
|
@@ -1605,6 +1642,7 @@ async function runCommand(command, options = {}) {
|
|
|
1605
1642
|
error.stderr = stderr;
|
|
1606
1643
|
reject(error);
|
|
1607
1644
|
});
|
|
1645
|
+
forceKillTimer = scheduleForceKill(child);
|
|
1608
1646
|
}, options.timeoutMs);
|
|
1609
1647
|
}
|
|
1610
1648
|
});
|
|
@@ -2715,6 +2753,9 @@ async function collectRecursive(absDir, root, out) {
|
|
|
2715
2753
|
}
|
|
2716
2754
|
|
|
2717
2755
|
// src/env/environmentInspector.ts
|
|
2756
|
+
var import_node_fs = require("fs");
|
|
2757
|
+
var import_node_os = require("os");
|
|
2758
|
+
var import_node_path = require("path");
|
|
2718
2759
|
var import_devtools_protocol4 = require("@serviceme/devtools-protocol");
|
|
2719
2760
|
var DEFAULT_TOOL_CHECK_TIMEOUT_MS = 5e3;
|
|
2720
2761
|
var TOOL_CHECK_TIMEOUT_MS = {
|
|
@@ -2762,11 +2803,19 @@ function posixLoginShellArgs(platform3, envShell, command) {
|
|
|
2762
2803
|
}
|
|
2763
2804
|
var EnvironmentInspector = class {
|
|
2764
2805
|
constructor(options = {}) {
|
|
2806
|
+
/**
|
|
2807
|
+
* Per-check-cycle result cache. `checkEnvironment()` clears it before
|
|
2808
|
+
* probing so a fresh cycle never returns stale results, while concurrent
|
|
2809
|
+
* or repeated `checkTool()` calls within the same cycle share one probe
|
|
2810
|
+
* (deduplicating expensive login-shell fallbacks).
|
|
2811
|
+
*/
|
|
2812
|
+
this.toolCheckCache = /* @__PURE__ */ new Map();
|
|
2765
2813
|
this.runCommandFn = options.runCommand ?? runCommand;
|
|
2766
2814
|
this.platform = options.platform ?? process.platform;
|
|
2767
2815
|
this.shell = options.shell ?? process.env.SHELL;
|
|
2768
2816
|
}
|
|
2769
2817
|
async checkEnvironment() {
|
|
2818
|
+
this.toolCheckCache.clear();
|
|
2770
2819
|
const results = await Promise.all(
|
|
2771
2820
|
import_devtools_protocol4.KNOWN_ENVIRONMENT_TOOLS.map(async (tool) => [tool, await this.checkTool(tool)])
|
|
2772
2821
|
);
|
|
@@ -2776,6 +2825,15 @@ var EnvironmentInspector = class {
|
|
|
2776
2825
|
if (!/^[a-zA-Z0-9-]+$/.test(toolName)) {
|
|
2777
2826
|
throw (0, import_devtools_protocol4.createServicemeError)("invalid_params", "Invalid tool name.");
|
|
2778
2827
|
}
|
|
2828
|
+
const cached = this.toolCheckCache.get(toolName);
|
|
2829
|
+
if (cached) {
|
|
2830
|
+
return cached;
|
|
2831
|
+
}
|
|
2832
|
+
const check = this.performToolCheck(toolName);
|
|
2833
|
+
this.toolCheckCache.set(toolName, check);
|
|
2834
|
+
return check;
|
|
2835
|
+
}
|
|
2836
|
+
async performToolCheck(toolName) {
|
|
2779
2837
|
try {
|
|
2780
2838
|
if (toolName === "nvm") {
|
|
2781
2839
|
return await this.checkNvm();
|
|
@@ -2887,6 +2945,12 @@ var EnvironmentInspector = class {
|
|
|
2887
2945
|
}
|
|
2888
2946
|
}
|
|
2889
2947
|
try {
|
|
2948
|
+
if (!this.resolveNvmShPath()) {
|
|
2949
|
+
return {
|
|
2950
|
+
installed: false,
|
|
2951
|
+
error: "Not installed"
|
|
2952
|
+
};
|
|
2953
|
+
}
|
|
2890
2954
|
const nvmArgs = posixLoginShellArgs(this.platform, this.shell, "nvm --version");
|
|
2891
2955
|
const result = await this.runCommandFn(nvmArgs.command, {
|
|
2892
2956
|
args: nvmArgs.args,
|
|
@@ -2904,6 +2968,28 @@ var EnvironmentInspector = class {
|
|
|
2904
2968
|
};
|
|
2905
2969
|
}
|
|
2906
2970
|
}
|
|
2971
|
+
/**
|
|
2972
|
+
* Resolve `nvm.sh` from `$NVM_DIR` and the known install roots without
|
|
2973
|
+
* spawning a shell. Returns undefined when nvm is not installed in any
|
|
2974
|
+
* well-known location, letting callers skip a login-shell probe.
|
|
2975
|
+
*/
|
|
2976
|
+
resolveNvmShPath() {
|
|
2977
|
+
const candidates = [];
|
|
2978
|
+
const nvmDir = process.env.NVM_DIR?.trim();
|
|
2979
|
+
if (nvmDir && nvmDir.length > 0) {
|
|
2980
|
+
candidates.push(nvmDir);
|
|
2981
|
+
}
|
|
2982
|
+
for (const dir of NVM_FALLBACK_DIRS) {
|
|
2983
|
+
candidates.push(dir.replace(/^\$HOME/, (0, import_node_os.homedir)()));
|
|
2984
|
+
}
|
|
2985
|
+
for (const candidate of candidates) {
|
|
2986
|
+
const scriptPath = (0, import_node_path.join)(candidate, "nvm.sh");
|
|
2987
|
+
if ((0, import_node_fs.existsSync)(scriptPath)) {
|
|
2988
|
+
return scriptPath;
|
|
2989
|
+
}
|
|
2990
|
+
}
|
|
2991
|
+
return void 0;
|
|
2992
|
+
}
|
|
2907
2993
|
async checkNuget() {
|
|
2908
2994
|
const dotnetPath = await this.getToolPath("dotnet");
|
|
2909
2995
|
if (!dotnetPath) {
|
|
@@ -3611,9 +3697,9 @@ var path11 = __toESM(require("path"));
|
|
|
3611
3697
|
var import_devtools_protocol7 = require("@serviceme/devtools-protocol");
|
|
3612
3698
|
|
|
3613
3699
|
// src/utils/fileUtils.ts
|
|
3614
|
-
var
|
|
3700
|
+
var import_node_fs2 = require("fs");
|
|
3615
3701
|
var import_promises3 = require("fs/promises");
|
|
3616
|
-
var
|
|
3702
|
+
var import_node_path2 = require("path");
|
|
3617
3703
|
var import_yauzl = __toESM(require("yauzl"));
|
|
3618
3704
|
var unzipFile = (zipPath, dest) => {
|
|
3619
3705
|
return new Promise((resolve3, reject) => {
|
|
@@ -3623,18 +3709,18 @@ var unzipFile = (zipPath, dest) => {
|
|
|
3623
3709
|
zipfile.readEntry();
|
|
3624
3710
|
zipfile.on("entry", (entry) => {
|
|
3625
3711
|
if (/\/$/.test(entry.fileName)) {
|
|
3626
|
-
void (0, import_promises3.mkdir)((0,
|
|
3712
|
+
void (0, import_promises3.mkdir)((0, import_node_path2.join)(dest, entry.fileName), { recursive: true }).then(() => {
|
|
3627
3713
|
zipfile.readEntry();
|
|
3628
3714
|
}).catch(reject);
|
|
3629
3715
|
} else {
|
|
3630
|
-
const outputPath = (0,
|
|
3631
|
-
void (0, import_promises3.mkdir)((0,
|
|
3716
|
+
const outputPath = (0, import_node_path2.join)(dest, entry.fileName);
|
|
3717
|
+
void (0, import_promises3.mkdir)((0, import_node_path2.dirname)(outputPath), { recursive: true }).then(() => {
|
|
3632
3718
|
zipfile.openReadStream(
|
|
3633
3719
|
entry,
|
|
3634
3720
|
(streamError, readStream) => {
|
|
3635
3721
|
if (streamError) return reject(streamError);
|
|
3636
3722
|
if (!readStream) return reject(new Error("Failed to open zip entry stream."));
|
|
3637
|
-
const writeStream = (0,
|
|
3723
|
+
const writeStream = (0, import_node_fs2.createWriteStream)(outputPath);
|
|
3638
3724
|
readStream.on("error", reject);
|
|
3639
3725
|
writeStream.on("error", reject);
|
|
3640
3726
|
writeStream.on("close", () => {
|
|
@@ -3676,7 +3762,7 @@ var mergeEntry = async (sourcePath, destPath, overwrite) => {
|
|
|
3676
3762
|
await (0, import_promises3.mkdir)(destPath, { recursive: true });
|
|
3677
3763
|
const children = await (0, import_promises3.readdir)(sourcePath);
|
|
3678
3764
|
for (const child of children) {
|
|
3679
|
-
await mergeEntry((0,
|
|
3765
|
+
await mergeEntry((0, import_node_path2.join)(sourcePath, child), (0, import_node_path2.join)(destPath, child), overwrite);
|
|
3680
3766
|
}
|
|
3681
3767
|
await (0, import_promises3.rm)(sourcePath, { recursive: true, force: true });
|
|
3682
3768
|
return;
|
|
@@ -3699,11 +3785,11 @@ var moveFiles = async (sourceDir, destDir, overwrite = false) => {
|
|
|
3699
3785
|
await (0, import_promises3.mkdir)(destDir, { recursive: true });
|
|
3700
3786
|
const files = await (0, import_promises3.readdir)(sourceDir);
|
|
3701
3787
|
for (const file of files) {
|
|
3702
|
-
const sourceFile = (0,
|
|
3703
|
-
const destFile = (0,
|
|
3788
|
+
const sourceFile = (0, import_node_path2.join)(sourceDir, file);
|
|
3789
|
+
const destFile = (0, import_node_path2.join)(destDir, file);
|
|
3704
3790
|
if (!overwrite) {
|
|
3705
3791
|
try {
|
|
3706
|
-
await (0, import_promises3.access)(destFile,
|
|
3792
|
+
await (0, import_promises3.access)(destFile, import_node_fs2.constants.F_OK);
|
|
3707
3793
|
await (0, import_promises3.rm)(sourceFile, { recursive: true, force: true });
|
|
3708
3794
|
continue;
|
|
3709
3795
|
} catch {
|