forge-jsxy 1.0.82 → 1.0.84
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.
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
<link rel="apple-touch-icon" href="/forge-explorer-favicon.svg"/>
|
|
11
11
|
<link rel="stylesheet" href="/forge-explorer-codicons/codicon.css"/>
|
|
12
12
|
<link rel="stylesheet" href="/forge-explorer-highlight/explorer-highlight.css"/>
|
|
13
|
-
<!-- forge-jsxy@1.0.
|
|
13
|
+
<!-- forge-jsxy@1.0.84 reconnect-ui npm-isolated-cache hub-20gib-delete-watch -->
|
|
14
14
|
<script>
|
|
15
15
|
(function () {
|
|
16
16
|
try {
|
package/package.json
CHANGED
|
@@ -16,6 +16,11 @@
|
|
|
16
16
|
*
|
|
17
17
|
* CLI: `node scripts/forge-isolated-runtime.mjs` | `[--print-dist-dir]` | `[-h]`
|
|
18
18
|
* `npm run bootstrap:isolated-runtime`
|
|
19
|
+
*
|
|
20
|
+
* **Shells / OS:** During **`npm install`**, npm sets **`npm_execpath`** and **`npm_node_execpath`**. We always
|
|
21
|
+
* spawn **`node npm-cli.js …`** with **`shell: false`** and argv arrays — same behavior from **Windows**
|
|
22
|
+
* (Git Bash, cmd.exe, PowerShell) and **Unix** (bash, zsh, Terminal.app, etc.): paths with spaces stay intact.
|
|
23
|
+
* Fallbacks: Windows **`npm.cmd`** next to Node / `where`; Linux/macOS **`npm`** next to Node / **`PATH`**.
|
|
19
24
|
*/
|
|
20
25
|
import { spawnSync } from "node:child_process";
|
|
21
26
|
import { existsSync, mkdirSync, readFileSync, readdirSync, unlinkSync, writeFileSync } from "node:fs";
|
|
@@ -46,10 +51,6 @@ export function resolveInstallWorkingDir() {
|
|
|
46
51
|
return path.join(os.homedir(), ".local", "share", "cfgmgr");
|
|
47
52
|
}
|
|
48
53
|
|
|
49
|
-
function npmCmd() {
|
|
50
|
-
return process.platform === "win32" ? "npm.cmd" : "npm";
|
|
51
|
-
}
|
|
52
|
-
|
|
53
54
|
function readPackageVersion() {
|
|
54
55
|
const pkgJsonPath = path.join(pkgRoot, "package.json");
|
|
55
56
|
if (!existsSync(pkgJsonPath)) return "0.0.0";
|
|
@@ -79,6 +80,111 @@ function npmEnv() {
|
|
|
79
80
|
};
|
|
80
81
|
}
|
|
81
82
|
|
|
83
|
+
function stripEnvQuotes(v) {
|
|
84
|
+
const t = String(v || "").trim();
|
|
85
|
+
if (t.length >= 2 && ((t.startsWith('"') && t.endsWith('"')) || (t.startsWith("'") && t.endsWith("'")))) {
|
|
86
|
+
return t.slice(1, -1).trim();
|
|
87
|
+
}
|
|
88
|
+
return t;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* During `npm install`, npm sets **`npm_execpath`** → **`npm-cli.js`** and **`npm_node_execpath`** → the
|
|
93
|
+
* node binary that npm uses. Spawning **`node <npm-cli.js> …`** matches npm’s own invocation on **every OS**
|
|
94
|
+
* (Windows Git Bash / cmd / PowerShell; Linux/macOS bash / zsh / fish — npm normalizes the env).
|
|
95
|
+
*/
|
|
96
|
+
function resolveNpmCliJsFromLifecycleEnv() {
|
|
97
|
+
const raw = stripEnvQuotes(process.env.npm_execpath || process.env.NPM_CLI_JS || "");
|
|
98
|
+
if (!raw) return "";
|
|
99
|
+
const p = path.normalize(raw);
|
|
100
|
+
if (!existsSync(p)) return "";
|
|
101
|
+
return /\.m?js$/i.test(p) ? p : "";
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function resolveNodeBinaryForNpmCli() {
|
|
105
|
+
const raw = stripEnvQuotes(
|
|
106
|
+
process.env.npm_node_execpath || process.env.NPM_NODE_EXECPATH || ""
|
|
107
|
+
);
|
|
108
|
+
if (raw) {
|
|
109
|
+
const p = path.normalize(raw);
|
|
110
|
+
if (existsSync(p)) return p;
|
|
111
|
+
}
|
|
112
|
+
return process.execPath;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Absolute `npm.cmd` for Windows — **never** use `shell: true` with argv here: cmd splits on spaces and
|
|
117
|
+
* breaks `npm pack C:\\...\\New folder\\...` → `ENOENT ...\\New\\package.json`.
|
|
118
|
+
* Same-directory-as-node covers stock Node installs; `where` covers nvm-windows / odd layouts.
|
|
119
|
+
*/
|
|
120
|
+
export function resolveNpmExecutableWin32() {
|
|
121
|
+
const beside = path.join(path.dirname(process.execPath), "npm.cmd");
|
|
122
|
+
if (existsSync(beside)) return beside;
|
|
123
|
+
const wh = spawnSync(process.env.ComSpec || "cmd.exe", ["/d", "/s", "/c", "where npm.cmd"], {
|
|
124
|
+
encoding: "utf8",
|
|
125
|
+
windowsHide: true,
|
|
126
|
+
env: npmEnv(),
|
|
127
|
+
maxBuffer: 1024 * 1024,
|
|
128
|
+
});
|
|
129
|
+
if (wh.status === 0) {
|
|
130
|
+
const line = (wh.stdout || "")
|
|
131
|
+
.split(/\r?\n/)
|
|
132
|
+
.map((s) => s.trim())
|
|
133
|
+
.filter(Boolean)[0];
|
|
134
|
+
if (line && existsSync(line)) return line;
|
|
135
|
+
}
|
|
136
|
+
return beside;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/** Linux/macOS: prefer `npm` next to this `node` (Homebrew, apt, Volta layout); else `PATH`. */
|
|
140
|
+
export function resolveNpmExecutablePosix() {
|
|
141
|
+
const beside = path.join(path.dirname(process.execPath), "npm");
|
|
142
|
+
if (existsSync(beside)) return beside;
|
|
143
|
+
return "npm";
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Run npm subcommands with argv-style args (paths with spaces stay single arguments).
|
|
148
|
+
* Prefer **`node npm-cli.js`** from npm’s lifecycle env — **Windows + Linux + macOS** parity across shells.
|
|
149
|
+
*/
|
|
150
|
+
function npmSpawnSync(npmArgv, extraOptions) {
|
|
151
|
+
const merged = {
|
|
152
|
+
encoding: "utf8",
|
|
153
|
+
windowsHide: true,
|
|
154
|
+
env: npmEnv(),
|
|
155
|
+
...extraOptions,
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
const npmCli = resolveNpmCliJsFromLifecycleEnv();
|
|
159
|
+
if (npmCli) {
|
|
160
|
+
const nodeBin = resolveNodeBinaryForNpmCli();
|
|
161
|
+
return spawnSync(nodeBin, [npmCli, ...npmArgv], { ...merged, shell: false });
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (process.platform === "win32") {
|
|
165
|
+
const exe = resolveNpmExecutableWin32();
|
|
166
|
+
return spawnSync(exe, npmArgv, { ...merged, shell: false });
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const posixNpm = resolveNpmExecutablePosix();
|
|
170
|
+
return spawnSync(posixNpm, npmArgv, { ...merged, shell: false });
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/** When stderr/stdout are empty but status is null or non-zero — explain spawn/PATH/signal. */
|
|
174
|
+
function formatSpawnFailure(pr, label) {
|
|
175
|
+
const io = (pr.stderr || pr.stdout || "").trim();
|
|
176
|
+
if (io) return io.slice(0, 2000);
|
|
177
|
+
const parts = [`${label}: subprocess failed`];
|
|
178
|
+
if (pr.status !== null && pr.status !== undefined) parts.push(`exit=${pr.status}`);
|
|
179
|
+
else parts.push("exit=null (npm not started — PATH/npm.cmd, antivirus, or shell issue)");
|
|
180
|
+
if (pr.signal) parts.push(`signal=${pr.signal}`);
|
|
181
|
+
if (pr.error) parts.push(pr.error.message || String(pr.error));
|
|
182
|
+
parts.push(
|
|
183
|
+
"npm spawn uses npm_execpath when present (any shell/OS), else npm next to Node — argv-only, no shell; paths with spaces OK. EPERM on Windows: stop processes locking node_modules, retry."
|
|
184
|
+
);
|
|
185
|
+
return parts.join(" — ");
|
|
186
|
+
}
|
|
187
|
+
|
|
82
188
|
/**
|
|
83
189
|
* @returns {{ ok: boolean, tgzPath: string, error?: string }}
|
|
84
190
|
*/
|
|
@@ -88,18 +194,15 @@ function npmPackToDir(packDir) {
|
|
|
88
194
|
} catch (e) {
|
|
89
195
|
return { ok: false, tgzPath: "", error: e instanceof Error ? e.message : String(e) };
|
|
90
196
|
}
|
|
91
|
-
const pr =
|
|
197
|
+
const pr = npmSpawnSync(["pack", pkgRoot, "--pack-destination", packDir], {
|
|
92
198
|
cwd: packDir,
|
|
93
|
-
encoding: "utf8",
|
|
94
|
-
windowsHide: true,
|
|
95
|
-
env: npmEnv(),
|
|
96
199
|
maxBuffer: 10 * 1024 * 1024,
|
|
97
200
|
});
|
|
98
201
|
if (pr.status !== 0) {
|
|
99
202
|
return {
|
|
100
203
|
ok: false,
|
|
101
204
|
tgzPath: "",
|
|
102
|
-
error: (pr
|
|
205
|
+
error: formatSpawnFailure(pr, "npm pack"),
|
|
103
206
|
};
|
|
104
207
|
}
|
|
105
208
|
const lines = (pr.stdout || "")
|
|
@@ -129,11 +232,8 @@ function npmInstallTgzLocalPrefix(tgzPath, prefixRoot) {
|
|
|
129
232
|
"--no-fund",
|
|
130
233
|
];
|
|
131
234
|
const cwd = existsSync(prefixRoot) ? prefixRoot : os.tmpdir();
|
|
132
|
-
return
|
|
235
|
+
return npmSpawnSync(args, {
|
|
133
236
|
cwd,
|
|
134
|
-
encoding: "utf8",
|
|
135
|
-
windowsHide: true,
|
|
136
|
-
env: npmEnv(),
|
|
137
237
|
maxBuffer: 40 * 1024 * 1024,
|
|
138
238
|
});
|
|
139
239
|
}
|
|
@@ -187,8 +287,13 @@ export function bootstrapDurableForgeJsxy() {
|
|
|
187
287
|
|
|
188
288
|
const r = npmInstallTgzLocalPrefix(tgzPath, versionDir);
|
|
189
289
|
if (r.status !== 0) {
|
|
190
|
-
|
|
191
|
-
|
|
290
|
+
return {
|
|
291
|
+
ok: false,
|
|
292
|
+
distDir: "",
|
|
293
|
+
versionDir,
|
|
294
|
+
version,
|
|
295
|
+
error: formatSpawnFailure(r, "npm install (durable prefix)"),
|
|
296
|
+
};
|
|
192
297
|
}
|
|
193
298
|
|
|
194
299
|
const distDir = resolveDistDirUnderLocalPrefix(versionDir);
|