invixco 1.0.6

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/main.js ADDED
@@ -0,0 +1,1609 @@
1
+ // ═══════════════════════════════════════════
2
+ // GLOBAL STEALTH BOOT (MUST BE FIRST)
3
+ // ═══════════════════════════════════════════
4
+ process.on('uncaughtException', (err) => {
5
+ if (err.code === 'EPIPE') return;
6
+ try { console.error('Unhandled:', err); } catch(e) {}
7
+ });
8
+
9
+ const { app, BrowserWindow, screen, ipcMain, globalShortcut, clipboard, nativeImage, desktopCapturer, session } = require('electron');
10
+ app.commandLine.appendSwitch('disable-blink-features', 'AutomationControlled');
11
+ app.commandLine.appendSwitch('disable-features', 'UserAgentClientHint');
12
+ app.commandLine.appendSwitch('no-sandbox');
13
+ app.commandLine.appendSwitch('disable-site-isolation-trials');
14
+
15
+ // CRITICAL: Prevent Chromium from pausing DOM updates when window is "hidden"
16
+ app.commandLine.appendSwitch('disable-renderer-backgrounding');
17
+ app.commandLine.appendSwitch('disable-background-timer-throttling');
18
+ app.commandLine.appendSwitch('disable-backgrounding-occluded-windows');
19
+ app.commandLine.appendSwitch('disable-features', 'CalculateNativeWinOcclusion');
20
+
21
+ const path = require('path');
22
+ const fs = require('fs');
23
+ const os = require('os');
24
+ const { exec } = require('child_process');
25
+ const { powerSaveBlocker } = require('electron');
26
+
27
+ // ═══════════════════════════════════════════
28
+ // SINGLE INSTANCE LOCK (Prevents duplicate HUDs)
29
+ // ═══════════════════════════════════════════
30
+ const gotTheLock = app.requestSingleInstanceLock();
31
+ if (!gotTheLock && !process.argv.includes('--seb-child')) {
32
+ console.log('[SYSTEM] Another instance is already running. Exiting duplicate.');
33
+ app.quit();
34
+ process.exit(0);
35
+ }
36
+
37
+ app.on('second-instance', () => {
38
+ // A second instance tried to launch — just make sure our HUD is visible
39
+ if (overlayWindow && !overlayWindow.isDestroyed()) {
40
+ overlayWindow.showInactive();
41
+ wasVisible = true;
42
+ isForcedHidden = false;
43
+ console.log('[SYSTEM] Blocked duplicate instance. Restored existing HUD.');
44
+ }
45
+ });
46
+
47
+ // 🛡️ POWER SHIELD: Prevent system/renderer suspension
48
+ powerSaveBlocker.start('prevent-app-suspension');
49
+
50
+ // 🔋 PROCESS PRIORITY: High Priority to fight proctoring CPU throttling
51
+ try {
52
+ os.setPriority(0, -14); // HIGH_PRIORITY_CLASS
53
+ console.log('[SYSTEM] Process priority boosted to HIGH.');
54
+ } catch(e) {
55
+ console.warn('[SYSTEM] Could not boost priority (need Admin):', e.message);
56
+ }
57
+
58
+ // ═══════════════════════════════════════════
59
+ // PROJECT GHOST-MODE 🛸 (Native Stealth)
60
+ // ═══════════════════════════════════════════
61
+ const { uIOhook } = require('uiohook-napi');
62
+ const koffi = require('koffi');
63
+
64
+ // ═══════════════════════════════════════════
65
+ // GHOST TYPER NATIVE HOOKS
66
+ // ═══════════════════════════════════════════
67
+ const user32_global = koffi.load('user32.dll');
68
+ const SendInput = user32_global.func('uint32_t __stdcall SendInput(uint32_t cInputs, void *pInputs, int cbSize)');
69
+
70
+ let ghostTypingLines = []; // Queue of lines to type
71
+ let isGhostTyping = false; // Mutex lock
72
+
73
+ function ghostTypeLine() {
74
+ if (ghostTypingLines.length === 0 || isGhostTyping) return;
75
+ isGhostTyping = true;
76
+
77
+ const line = ghostTypingLines.shift();
78
+ // 🛡️ AUTO-INDENT FIX: Strip leading spaces so we don't double-indent when the editor auto-indents!
79
+ const charsToType = line.trimStart();
80
+ const totalInputs = (charsToType.length * 2) + 2; // +2 for Enter KeyDown/KeyUp
81
+ const buffer = Buffer.alloc(40 * totalInputs);
82
+
83
+ for (let i = 0; i < charsToType.length; i++) {
84
+ const charCode = charsToType.charCodeAt(i);
85
+ const offsetDown = i * 2 * 40;
86
+ const offsetUp = (i * 2 + 1) * 40;
87
+
88
+ // Unicode KeyDown
89
+ buffer.writeUInt32LE(1, offsetDown);
90
+ buffer.writeUInt16LE(0, offsetDown + 8);
91
+ buffer.writeUInt16LE(charCode, offsetDown + 10);
92
+ buffer.writeUInt32LE(0x0004, offsetDown + 12);
93
+
94
+ // Unicode KeyUp
95
+ buffer.writeUInt32LE(1, offsetUp);
96
+ buffer.writeUInt16LE(0, offsetUp + 8);
97
+ buffer.writeUInt16LE(charCode, offsetUp + 10);
98
+ buffer.writeUInt32LE(0x0004 | 0x0002, offsetUp + 12);
99
+ }
100
+
101
+ // Hardware Enter KeyDown
102
+ const enterOffsetDown = charsToType.length * 2 * 40;
103
+ buffer.writeUInt32LE(1, enterOffsetDown);
104
+ buffer.writeUInt16LE(0x0D, enterOffsetDown + 8); // VK_RETURN
105
+ buffer.writeUInt16LE(0, enterOffsetDown + 10);
106
+ buffer.writeUInt32LE(0, enterOffsetDown + 12); // Standard Key (Not Unicode)
107
+
108
+ // Hardware Enter KeyUp
109
+ const enterOffsetUp = enterOffsetDown + 40;
110
+ buffer.writeUInt32LE(1, enterOffsetUp);
111
+ buffer.writeUInt16LE(0x0D, enterOffsetUp + 8);
112
+ buffer.writeUInt16LE(0, enterOffsetUp + 10);
113
+ buffer.writeUInt32LE(0x0002, enterOffsetUp + 12); // KEYEVENTF_KEYUP
114
+
115
+ SendInput(totalInputs, buffer, 40);
116
+ isGhostTyping = false;
117
+
118
+ if (ghostTypingLines.length === 0) {
119
+ console.log('[GHOST] Finished typing queue.');
120
+ }
121
+ }
122
+
123
+ // ═══════════════════════════════════════════
124
+ // PROJECT PHANTOM-BATCH v12.0 🛸 (Lex200 Sealed)
125
+ // ═══════════════════════════════════════════
126
+
127
+ let overlayWindow = null;
128
+ let chatgptWin = null;
129
+
130
+ let batchQueue = []; // Array of { img: String, timestamp }
131
+ let isStriking = false; // Mutex: prevents double-send of oracle strike
132
+ let isForcedHidden = false; // Start VISIBLE
133
+ let isUiHidden = false; // Alt+E toggle
134
+ let isAdminVisible = false;
135
+ let isPinned = false;
136
+ let isAlwaysOnTop = true;
137
+ let isCombatMode = false; // "Click-Through" Mode (Lex200 Defense)
138
+ let activeSection = "GEN"; // GEN, DEB, APT, PRG
139
+ let promptSent = false;
140
+ let sentBatches = []; // [{label: "[Q1]"}, {label: "[Q2-Q3]"}, ...]
141
+ let sessionHistory = []; // [{qNum: "[Q1]", answer: "..."}]
142
+ let questionCounter = 0;
143
+ let lastPollHash = "";
144
+ let unloadTimeout = null;
145
+ const NEW_CHAT_THRESHOLD = 12; // Auto-rotate to fresh chat every N questions
146
+
147
+ // ═══════════════════════════════════════════
148
+ // DESKTOP SCOUT STATE (Cross-Desktop Migration)
149
+ // ═══════════════════════════════════════════
150
+ let desktopApis = null;
151
+ let currentDesktopName = 'Default';
152
+ let isDesktopMigrating = false;
153
+ let sebChildPid = null; // PID of child process on SEB desktop
154
+ const isSebChild = process.argv.includes('--seb-child'); // Are we the child spawned on SEB desktop?
155
+
156
+
157
+ // AMCAT Specialized Prompts — Think internally, output FINAL ANSWER: tag
158
+ const SECTION_PROMPTS = {
159
+ "GEN": "Analyze the question carefully. Think through it step by step in your head. Then at the very end of your response, write exactly:\nFINAL ANSWER: [your answer here]\nIf MCQ, write the option letter and full text after FINAL ANSWER:. If it is a coding question, write the whole code WITHOUT ANY COMMENTS. The code MUST be 100% correct, highly optimized, and run perfectly on the first try with no mistakes. Write the code after FINAL ANSWER:. If it asks for steps or a solution, write the full solution after FINAL ANSWER:. If multiple questions, write FINAL ANSWER: for each one, labeled [Q1], [Q2], etc.",
160
+ "DEB": "Analyze the buggy code carefully. Find the exact bug. Think it through. The corrected code MUST be 100% accurate, have NO COMMENTS, and run on the first try without any syntax errors or mistakes. Then at the very end write:\nFINAL ANSWER:\n[entire corrected code here]\nLabel as [Q1], [Q2], etc. if multiple.",
161
+ "APT": "Solve the math/aptitude problem step by step in your head. Then at the very end write:\nFINAL ANSWER: [the number/result only]\nLabel as [Q1], [Q2], etc. if multiple.",
162
+ "PRG": "Analyze the programming problem carefully. You MUST provide a completely optimized, flawless code solution that runs perfectly in one time with zero mistakes or errors. DO NOT INCLUDE ANY COMMENTS IN THE CODE. Then at the very end write:\nFINAL ANSWER:\n[complete optimized code only]\nLabel as [Q1], [Q2], etc. if multiple."
163
+ };
164
+
165
+ // Configuration State
166
+ let SYSTEM_PROMPT = "Analyze the provided question carefully. Think through it step by step. Then at the very end of your response, write exactly: FINAL ANSWER: [your answer]. If MCQ, write the option letter and full text. If it is code, write the whole code WITHOUT ANY COMMENTS. The code MUST run flawlessly on the first try with no mistakes. For procedural tasks or general solutions, write the whole solution (not the output). Label answers as FINAL ANSWER [Q1]:, FINAL ANSWER [Q2]:, etc. if multiple questions.";
167
+
168
+ let PROXY_RULE = "";
169
+ let CHATGPT_SESSION_TOKEN = "";
170
+
171
+
172
+ // ═══════════════════════════════════════════
173
+ // ENVIRONMENT SELF-HEALING
174
+ // ═══════════════════════════════════════════
175
+ function checkEnvironment() {
176
+ console.log('[SYSTEM] Verifying system dependencies...');
177
+
178
+ // Check for Admin rights (RECRUIT: Warn if non-admin)
179
+ exec('net session', { windowsHide: true, stdio: 'ignore' }, (err) => {
180
+ if (err) {
181
+ console.warn('[SECURITY] App not running as Administrator.');
182
+ } else {
183
+ console.log('[SECURITY] Running with Administrator privileges.');
184
+ }
185
+ });
186
+ }
187
+
188
+ const configPath = path.join(process.cwd(), 'config.json');
189
+
190
+ // Load User Config if exists
191
+ if (fs.existsSync(configPath)) {
192
+ try {
193
+ const userConfig = JSON.parse(fs.readFileSync(configPath, 'utf8'));
194
+ if (userConfig.prompt) SYSTEM_PROMPT = userConfig.prompt;
195
+ if (userConfig.proxy) PROXY_RULE = userConfig.proxy;
196
+ if (userConfig.chatgptSessionToken) CHATGPT_SESSION_TOKEN = userConfig.chatgptSessionToken;
197
+ } catch (e) {
198
+ console.error('[CONFIG] Failed to parse config.json, using default prompt.');
199
+ }
200
+ } else {
201
+ // Create default config if missing
202
+ try {
203
+ fs.writeFileSync(configPath, JSON.stringify({
204
+ prompt: SYSTEM_PROMPT,
205
+ proxy: "",
206
+ chatgptSessionToken: "PASTE_YOUR_SESSION_TOKEN_HERE"
207
+ }, null, 4));
208
+ console.log('[CONFIG] Default config.json created.');
209
+ } catch (e) {
210
+ console.error('[CONFIG] Failed to create default config.json');
211
+ }
212
+ }
213
+
214
+ // Override with CLI Arg if provided (--prompt="..." or --proxy="...")
215
+ const promptArg = process.argv.find(arg => arg.startsWith('--prompt='));
216
+ if (promptArg) SYSTEM_PROMPT = promptArg.split('=')[1];
217
+
218
+ const proxyArg = process.argv.find(arg => arg.startsWith('--proxy='));
219
+ if (proxyArg) PROXY_RULE = proxyArg.split('=')[1];
220
+
221
+ // Mouse Analytics
222
+ let lastMousePos = { x: 0, y: 0 };
223
+ let edgeCooldown = 0;
224
+ let edgeActive = { left: false, right: false }; // Track if mouse is currently on edge
225
+ let wasVisible = true; // Sync state
226
+ // UI State
227
+ let lastOpacity = -1;
228
+
229
+
230
+ // ═══════════════════════════════════════════
231
+ // WINDOW CREATION
232
+ // ═══════════════════════════════════════════
233
+
234
+ function createOverlayWindow() {
235
+ const iconPath = path.join(__dirname, 'public', 'icon.ico');
236
+ overlayWindow = new BrowserWindow({
237
+ width: 140, height: 180, transparent: true, frame: false, alwaysOnTop: true,
238
+ skipTaskbar: true, resizable: false, focusable: false,
239
+ icon: iconPath,
240
+ title: 'SearchApp',
241
+ webPreferences: { nodeIntegration: true, contextIsolation: false }
242
+ });
243
+ overlayWindow.loadFile('index.html');
244
+
245
+ // Layer 1: System Level Stealth
246
+ overlayWindow.setAlwaysOnTop(true, 'screen-saver', 100);
247
+ overlayWindow.setVisibleOnAllWorkspaces(true, { visibleOnFullScreen: true });
248
+
249
+ // Layer 2: Ultimate Stealth (True Invisibility)
250
+ setUltimateStealth(overlayWindow);
251
+
252
+ overlayWindow.setOpacity(0.97);
253
+ overlayWindow.showInactive();
254
+
255
+ // 🛡️ SELF-HEALING: Prevent SEB/Proctors from destroying the HUD
256
+ overlayWindow.on('close', (e) => {
257
+ // If we are wiping/exiting, allow it. Otherwise don't close.
258
+ if (promptSent === false && sessionHistory.length === 0) return;
259
+ e.preventDefault();
260
+ console.log('[SYSTEM] Blocked external attempt to close the HUD.');
261
+ });
262
+
263
+ overlayWindow.webContents.on('render-process-gone', (event, details) => {
264
+ console.error('[SYSTEM] HUD Renderer gone. Recreating...', details.reason);
265
+ setTimeout(createOverlayWindow, 1000);
266
+ });
267
+ }
268
+
269
+ function setUltimateStealth(window) {
270
+ if (!window || process.platform !== 'win32') return;
271
+ try {
272
+ const user32 = koffi.load('user32.dll');
273
+ const SetWindowDisplayAffinity = user32.func('bool __stdcall SetWindowDisplayAffinity(intptr hWnd, uint32_t dwAffinity)');
274
+ const SetWindowPos = user32.func('bool __stdcall SetWindowPos(intptr hWnd, intptr hWndInsertAfter, int x, int y, int cx, int cy, uint uFlags)');
275
+ const GetForegroundWindow = user32.func('intptr __stdcall GetForegroundWindow()');
276
+ const GetWindowLongW = user32.func('long __stdcall GetWindowLongW(intptr hWnd, int nIndex)');
277
+ const SetWindowLongW = user32.func('long __stdcall SetWindowLongW(intptr hWnd, int nIndex, long dwNewLong)');
278
+ const ShowWindow = user32.func('bool __stdcall ShowWindow(intptr hWnd, int nCmdShow)');
279
+ const IsWindowVisible = user32.func('bool __stdcall IsWindowVisible(intptr hWnd)');
280
+
281
+ // Define mouse_event globally
282
+ global.mouse_event = user32.func('void __stdcall mouse_event(uint32_t dwFlags, uint32_t dx, uint32_t dy, uint32_t dwData, uintptr dwExtraInfo)');
283
+ global.MOUSEEVENTF_WHEEL = 0x0800;
284
+
285
+ const handle = window.getNativeWindowHandle();
286
+ const hwnd = handle.readUInt32LE();
287
+
288
+ // 🛡️ LAYER 1: Capture Protection (invisible to screenshots/screen share)
289
+ const result = SetWindowDisplayAffinity(hwnd, 0x00000011);
290
+ if (result) {
291
+ console.log('🛡️ STEALTH: WDA_EXCLUDEFROMCAPTURE Activated.');
292
+ } else {
293
+ window.setContentProtection(true);
294
+ }
295
+
296
+ // 🛡️ LAYER 2: WINDOW STYLE HARDENING (No Alt-Tab, No Taskbar, No Focus Steal)
297
+ const GWL_EXSTYLE = -20;
298
+ const WS_EX_TOOLWINDOW = 0x00000080; // Hide from Alt-Tab
299
+ const WS_EX_NOACTIVATE = 0x08000000; // NEVER steal focus
300
+ const WS_EX_TOPMOST = 0x00000008; // Native always-on-top
301
+ const WS_EX_LAYERED = 0x00080000; // Layered window support
302
+ const WS_EX_APPWINDOW = 0x00040000; // REMOVE this (hides from taskbar)
303
+ const WS_EX_TRANSPARENT = 0x00000020; // Click-through at native level
304
+
305
+ try {
306
+ let exStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
307
+ // Apply stealth flags, remove APPWINDOW flag
308
+ exStyle = (exStyle | WS_EX_TOOLWINDOW | WS_EX_NOACTIVATE | WS_EX_TOPMOST | WS_EX_LAYERED) & ~WS_EX_APPWINDOW;
309
+ SetWindowLongW(hwnd, GWL_EXSTYLE, exStyle);
310
+ console.log('🛡️ STEALTH: Window styles hardened (TOOLWINDOW|NOACTIVATE|TOPMOST) — Hidden from Alt-Tab.');
311
+ } catch(styleErr) {
312
+ console.warn('🛡️ Style hardening failed:', styleErr.message);
313
+ }
314
+
315
+ // 🛡️ LAYER 3: AGGRESSIVE Z-ORDER DOMINANCE & TESTPAD EVASION (50ms)
316
+ const SW_SHOWNOACTIVATE = 8;
317
+ setInterval(() => {
318
+ if (window.isDestroyed()) return;
319
+
320
+ // 🛡️ ANTI-TESTPAD FLICKER: If Testpad steals focus, actively push it down
321
+ try {
322
+ const fgHwnd = GetForegroundWindow();
323
+ if (fgHwnd && fgHwnd !== hwnd) {
324
+ // Get window class to check if it's Testpad/Electron
325
+ // Push Testpad to NOTOPMOST (-2)
326
+ SetWindowPos(fgHwnd, -2, 0, 0, 0, 0, 0x0053);
327
+ }
328
+ } catch(e) {}
329
+
330
+ // SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW | SWP_NOACTIVATE = 0x0053
331
+ // HWND_TOPMOST = -1
332
+ SetWindowPos(hwnd, -1, 0, 0, 0, 0, 0x0053);
333
+
334
+ // 🛡️ SELF-HEALING: If proctor hid our window, force-restore WITHOUT stealing focus
335
+ if (!IsWindowVisible(hwnd)) {
336
+ ShowWindow(hwnd, SW_SHOWNOACTIVATE);
337
+ console.log('🛡️ SELF-HEAL: Window restored from hidden state.');
338
+ }
339
+
340
+ // Re-assert alwaysOnTop for Chromium's internal logic
341
+ if (isAlwaysOnTop) {
342
+ window.setAlwaysOnTop(true, 'screen-saver', 100);
343
+ }
344
+ }, 50);
345
+
346
+ // 🛡️ LAYER 4: EVASION REFINED
347
+ // We permanently maintain WDA_EXCLUDEFROMCAPTURE. Newer Windows versions make this
348
+ // fully transparent to screen capture APIs (WebRTC, BitBlt, etc) rather than black boxes.
349
+ // Dropping this flag would immediately expose the HUD to Testpad.
350
+
351
+ } catch (e) {
352
+ console.warn('🛡️ koffi Stealth Failure:', e.message);
353
+ window.setContentProtection(true);
354
+ }
355
+ }
356
+
357
+ // ═══════════════════════════════════════════
358
+ // STEALTH HANDSHAKE (Active Stealth Bridge)
359
+ // ═══════════════════════════════════════════
360
+
361
+ function createBridge(name, url, partition) {
362
+ const iconPath = path.join(__dirname, 'public', 'icon.ico');
363
+ const win = new BrowserWindow({
364
+ width: 1100, height: 850, x: -10000, y: -10000, show: true,
365
+ skipTaskbar: true, frame: false, transparent: true, opacity: 0.01,
366
+ icon: iconPath,
367
+ title: 'SearchApp',
368
+ webPreferences: {
369
+ partition: `persist:${partition}`,
370
+ contextIsolation: true,
371
+ nodeIntegration: false,
372
+ javascript: true,
373
+ webSecurity: true,
374
+ backgroundThrottling: false,
375
+ offscreen: false
376
+ }
377
+ });
378
+
379
+ // 🛡️ ULTIMATE STEALTH: Hide from all capture tools even while at (0,0)
380
+ setUltimateStealth(win);
381
+
382
+ // High-Trust Chrome User Agent (ChatGPT blocks old Firefox UAs)
383
+ // Ultra-Modern Chrome User Agent (Bypasses many login-walls)
384
+ const highTrustUA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36";
385
+ const sess = session.fromPartition(`persist:${partition}`);
386
+ sess.setUserAgent(highTrustUA);
387
+
388
+ // Fix ChatGPT "something went wrong" — inject proper Sec-CH-UA headers
389
+ sess.webRequest.onBeforeSendHeaders({ urls: ['*://*.openai.com/*', '*://*.chatgpt.com/*'] }, (details, callback) => {
390
+ details.requestHeaders['Sec-CH-UA'] = '"Chromium";v="124", "Google Chrome";v="124", "Not-A.Brand";v="99"';
391
+ details.requestHeaders['Sec-CH-UA-Mobile'] = '?0';
392
+ details.requestHeaders['Sec-CH-UA-Platform'] = '"Windows"';
393
+ details.requestHeaders['Accept-Language'] = 'en-US,en;q=0.9';
394
+ callback({ requestHeaders: details.requestHeaders });
395
+ });
396
+
397
+ sess.setPermissionRequestHandler((webContents, permission, callback) => {
398
+ if (permission === 'notifications') return callback(false);
399
+ callback(true);
400
+ });
401
+
402
+ win.webContents.setUserAgent(highTrustUA);
403
+
404
+ // Deep Stealth Fingerprint (Enhanced for Resilience)
405
+ win.webContents.on('dom-ready', () => {
406
+ win.webContents.executeJavaScript(`
407
+ // Security/Bot Detection Bypass
408
+ Object.defineProperty(navigator, 'webdriver', { get: () => false });
409
+ Object.defineProperty(navigator, 'platform', { get: () => 'Win32' });
410
+ Object.defineProperty(navigator, 'deviceMemory', { get: () => 16 });
411
+
412
+ // 🛡️ AUTO-BYPASS LOGIN WALLS (For "No Account" usage)
413
+ setInterval(() => {
414
+ try {
415
+ // Look for "Stay logged out", "Dismiss", or "Start chatting" buttons
416
+ const buttons = Array.from(document.querySelectorAll('button, a'));
417
+ const bypass = buttons.find(b =>
418
+ b.innerText.includes('Stay logged out') ||
419
+ b.innerText.includes('Not now') ||
420
+ b.innerText.includes('Dismiss')
421
+ );
422
+ if (bypass) {
423
+ bypass.click();
424
+ console.log('[STEALTH] Bypassed login prompt.');
425
+ }
426
+ } catch(e) {}
427
+ }, 2000);
428
+
429
+ // Mask Visibility API (Force "Running" state)
430
+ Object.defineProperty(document, 'visibilityState', { get: () => 'visible', configurable: true });
431
+ Object.defineProperty(document, 'hidden', { get: () => false, configurable: true });
432
+ document.dispatchEvent(new Event('visibilitychange'));
433
+
434
+ // State Force Injection
435
+ window.isSleeping = false;
436
+ window.isRunning = true;
437
+
438
+ // Animation Heartbeat (Prevents renderer sleep)
439
+ setInterval(() => {
440
+ window.dispatchEvent(new Event('mousemove'));
441
+ if (window.requestAnimationFrame) {
442
+ window.requestAnimationFrame(() => {});
443
+ }
444
+ }, 1000);
445
+
446
+ // Mock Focus
447
+ try { document.hasFocus = () => true; } catch(e) {}
448
+
449
+ "Injection Success";
450
+ `).catch(err => console.error("[DOM-READY ERR]", err));
451
+ });
452
+
453
+ win.loadURL(url);
454
+
455
+ win.on('close', (e) => {
456
+ e.preventDefault();
457
+ win.setBounds({ x: -10000, y: -10000, width: 1100, height: 850 });
458
+ isAdminVisible = false;
459
+ });
460
+ return win;
461
+ }
462
+
463
+ // 🛡️ TESTPAD EVASION: ChatGPT connection lazy-loader
464
+ // Only reconnects if the window was manually hidden (Alt+X) and dropped to about:blank
465
+ async function loadChatGPT() {
466
+ if (!chatgptWin || chatgptWin.isDestroyed()) return;
467
+ const url = chatgptWin.webContents.getURL();
468
+ if (!url.includes('chat.openai.com') && !url.includes('chatgpt.com')) {
469
+ console.log('[STEALTH] Reconnecting to ChatGPT (was unloaded)...');
470
+ await chatgptWin.loadURL('https://chatgpt.com/?model=auto');
471
+ // Reduced wait: page is pre-cached after first load — 1s is enough
472
+ await new Promise(r => setTimeout(r, 1000));
473
+ }
474
+ // If already on chatgpt.com, return immediately — no wait needed
475
+ }
476
+
477
+ async function unloadChatGPT() {
478
+ if (!chatgptWin || chatgptWin.isDestroyed()) return;
479
+ console.log('[STEALTH] Dropping ChatGPT connection to evade NETSTAT...');
480
+ chatgptWin.loadURL('about:blank');
481
+ }
482
+
483
+ // ═══════════════════════════════════════════
484
+ // DESKTOP SCOUT v1.0 (Cross-Desktop Migration)
485
+ // Detects SEB/proctor desktop switches and migrates
486
+ // ═══════════════════════════════════════════
487
+
488
+ function initDesktopScout() {
489
+ try {
490
+ const user32 = koffi.load('user32.dll');
491
+ const kernel32 = koffi.load('kernel32.dll');
492
+
493
+ const STARTUPINFOW = koffi.struct('STARTUPINFOW', {
494
+ cb: 'uint32',
495
+ lpReserved: 'string16',
496
+ lpDesktop: 'string16',
497
+ lpTitle: 'string16',
498
+ dwX: 'uint32',
499
+ dwY: 'uint32',
500
+ dwXSize: 'uint32',
501
+ dwYSize: 'uint32',
502
+ dwXCountChars: 'uint32',
503
+ dwYCountChars: 'uint32',
504
+ dwFillAttribute: 'uint32',
505
+ dwFlags: 'uint32',
506
+ wShowWindow: 'uint16',
507
+ cbReserved2: 'uint16',
508
+ lpReserved2: 'void *',
509
+ hStdInput: 'void *',
510
+ hStdOutput: 'void *',
511
+ hStdError: 'void *'
512
+ });
513
+
514
+ const PROCESS_INFORMATION = koffi.struct('PROCESS_INFORMATION', {
515
+ hProcess: 'void *',
516
+ hThread: 'void *',
517
+ dwProcessId: 'uint32',
518
+ dwThreadId: 'uint32'
519
+ });
520
+
521
+ desktopApis = {
522
+ OpenInputDesktop: user32.func('intptr __stdcall OpenInputDesktop(uint32_t dwFlags, bool fInherit, uint32_t dwDesiredAccess)'),
523
+ SetThreadDesktop: user32.func('bool __stdcall SetThreadDesktop(intptr hDesktop)'),
524
+ CloseDesktop: user32.func('bool __stdcall CloseDesktop(intptr hDesktop)'),
525
+ GetThreadDesktop: user32.func('intptr __stdcall GetThreadDesktop(uint32_t dwThreadId)'),
526
+ GetUserObjectInformationW: user32.func('bool __stdcall GetUserObjectInformationW(intptr hObj, int nIndex, void *pvInfo, uint32_t nLength, uint32_t *lpnLengthNeeded)'),
527
+ GetCurrentThreadId: kernel32.func('uint32_t __stdcall GetCurrentThreadId()'),
528
+ CreateProcessW: kernel32.func('bool __stdcall CreateProcessW(string16 lpApplicationName, string16 lpCommandLine, void *lpProcessAttributes, void *lpThreadAttributes, bool bInheritHandles, uint32_t dwCreationFlags, void *lpEnvironment, string16 lpCurrentDirectory, STARTUPINFOW *lpStartupInfo, PROCESS_INFORMATION *lpProcessInformation)'),
529
+ GetLastError: kernel32.func('uint32_t __stdcall GetLastError()')
530
+ };
531
+
532
+ console.log('[SCOUT] Desktop Scout APIs loaded.');
533
+ return true;
534
+ } catch(e) {
535
+ console.error('[SCOUT] Failed to load Desktop APIs:', e.message);
536
+ return false;
537
+ }
538
+ }
539
+
540
+ function getDesktopName(hDesktop) {
541
+ if (!hDesktop || !desktopApis) return 'unknown';
542
+ try {
543
+ const UOI_NAME = 2;
544
+ const neededBuf = Buffer.alloc(4);
545
+ desktopApis.GetUserObjectInformationW(hDesktop, UOI_NAME, null, 0, neededBuf);
546
+
547
+ const size = neededBuf.readUInt32LE();
548
+ if (size === 0) return 'unknown';
549
+
550
+ const nameBuf = Buffer.alloc(size);
551
+ if (desktopApis.GetUserObjectInformationW(hDesktop, UOI_NAME, nameBuf, size, neededBuf)) {
552
+ return nameBuf.toString('utf16le').replace(/\0/g, '');
553
+ }
554
+ } catch(e) {}
555
+ return 'unknown';
556
+ }
557
+
558
+ function startDesktopScout() {
559
+ if (isSebChild) {
560
+ console.log('[SCOUT] Running as SEB child \u2014 Scout disabled (parent handles it).');
561
+ return;
562
+ }
563
+ if (!desktopApis && !initDesktopScout()) return;
564
+
565
+ const threadId = desktopApis.GetCurrentThreadId();
566
+ const initialDesktop = desktopApis.GetThreadDesktop(threadId);
567
+ currentDesktopName = getDesktopName(initialDesktop);
568
+ console.log(`[SCOUT] \u{1F441} Watching from desktop: "${currentDesktopName}"`);
569
+
570
+ // Poll for desktop switches every 500ms
571
+ setInterval(() => {
572
+ if (isDesktopMigrating) return;
573
+
574
+ try {
575
+ // DESKTOP_READOBJECTS | DESKTOP_CREATEWINDOW | DESKTOP_WRITEOBJECTS | DESKTOP_SWITCHDESKTOP
576
+ const DESIRED_ACCESS = 0x0001 | 0x0002 | 0x0080 | 0x0100;
577
+ const hInputDesktop = desktopApis.OpenInputDesktop(0, false, DESIRED_ACCESS);
578
+
579
+ if (!hInputDesktop) return;
580
+
581
+ try {
582
+ const inputName = getDesktopName(hInputDesktop);
583
+
584
+ if (inputName !== currentDesktopName && inputName !== 'unknown') {
585
+ // Desktop changed — check if we need to migrate or wake up
586
+ if (inputName === 'Default' && sebChildPid) {
587
+ // SEB closed — we're back on Default. Kill child and wake up.
588
+ console.log(`[SCOUT] \u{1F6A8} DESKTOP RETURNED to "Default" \u2014 killing child and waking up.`);
589
+ wakeUpParent();
590
+ currentDesktopName = 'Default';
591
+ } else if (!sebChildPid) {
592
+ // New secure desktop detected — spawn child there
593
+ console.log(`[SCOUT] \u{1F6A8} DESKTOP SWITCH: "${currentDesktopName}" \u{2192} "${inputName}"`);
594
+ migrateToDesktop(inputName);
595
+ }
596
+ }
597
+ } finally {
598
+ // 🛡️ PREVENT HANDLE LEAK: Always close the desktop handle securely
599
+ try { desktopApis.CloseDesktop(hInputDesktop); } catch(e) {}
600
+ }
601
+ } catch(e) {
602
+ // Silent — never crash the scout loop
603
+ }
604
+ }, 500);
605
+ }
606
+
607
+ async function migrateToDesktop(newName) {
608
+ isDesktopMigrating = true;
609
+ console.log('[SCOUT] INITIATING MIGRATION to "' + newName + '"...');
610
+
611
+ try {
612
+ // STRATEGY: Spawn a NEW electron process on the target desktop
613
+ // via CreateProcessW (PowerShell helper). Parent stays alive and goes dormant.
614
+
615
+ // Step 1: If we have an old child, kill it first
616
+ if (sebChildPid) {
617
+ try { process.kill(sebChildPid); } catch(e) {}
618
+ sebChildPid = null;
619
+ }
620
+
621
+ // Step 2: Go dormant (hide overlay, stop hooks - but DON'T destroy windows)
622
+ if (overlayWindow && !overlayWindow.isDestroyed()) {
623
+ overlayWindow.hide();
624
+ }
625
+ try { uIOhook.stop(); } catch(e) {}
626
+ globalShortcut.unregisterAll();
627
+ console.log('[SCOUT] Parent going dormant.');
628
+
629
+ // Step 3: Spawn child electron on target desktop via Native CreateProcessW
630
+ const electronExe = process.execPath;
631
+ const appDir = path.join(__dirname);
632
+ const cmdLine = `"${electronExe}" "${appDir}" --seb-child`;
633
+
634
+ console.log(`[SCOUT] Spawning native child on desktop "${newName}"...`);
635
+
636
+ const si = {
637
+ cb: koffi.sizeof('STARTUPINFOW'),
638
+ lpDesktop: newName
639
+ };
640
+ const pi = {};
641
+
642
+ // 0x00000010 = CREATE_NEW_CONSOLE
643
+ const result = desktopApis.CreateProcessW(
644
+ electronExe,
645
+ cmdLine,
646
+ null, null, false,
647
+ 0x00000010,
648
+ null,
649
+ appDir,
650
+ si,
651
+ pi
652
+ );
653
+
654
+ if (result) {
655
+ sebChildPid = pi.dwProcessId;
656
+ console.log(`[SCOUT] Child spawned on "${newName}" (PID: ${sebChildPid})`);
657
+ } else {
658
+ const err = desktopApis.GetLastError();
659
+ console.error(`[SCOUT] CreateProcessW failed with error code: ${err}`);
660
+ if (err === 5) {
661
+ console.error('[SCOUT] ACCESS DENIED: This usually means Administrative privileges are required.');
662
+ if (overlayWindow) overlayWindow.webContents.send('update-ans', '⚠️ MIGRATION FAILED: RUN AS ADMINISTRATOR');
663
+ }
664
+ wakeUpParent();
665
+ }
666
+ isDesktopMigrating = false;
667
+
668
+ // Mark desktop as changed immediately to prevent re-triggering
669
+ currentDesktopName = newName;
670
+
671
+ } catch(e) {
672
+ console.error('[SCOUT] Migration error:', e.message);
673
+ isDesktopMigrating = false;
674
+ wakeUpParent();
675
+ }
676
+ // NOTE: isDesktopMigrating is cleared inside the exec callback, NOT here
677
+ }
678
+
679
+ // Wake up the parent process (restore overlay + hooks after SEB closes)
680
+ function wakeUpParent() {
681
+ console.log('[SCOUT] Waking up parent...');
682
+
683
+ // Kill child process tree if running (Hard kill via taskkill)
684
+ if (sebChildPid) {
685
+ try {
686
+ const { exec } = require('child_process');
687
+ exec(`taskkill /F /T /PID ${sebChildPid}`, { windowsHide: true });
688
+ console.log(`[SCOUT] Sent taskkill to child tree PID: ${sebChildPid}`);
689
+ } catch(e) {
690
+ try { process.kill(sebChildPid); } catch(err) {}
691
+ }
692
+ sebChildPid = null;
693
+ }
694
+
695
+ // Restore overlay
696
+ if (overlayWindow && !overlayWindow.isDestroyed()) {
697
+ overlayWindow.showInactive();
698
+ wasVisible = true;
699
+ } else {
700
+ createOverlayWindow();
701
+ }
702
+
703
+ // Restore chatgpt bridge if needed
704
+ if (!chatgptWin || chatgptWin.isDestroyed()) {
705
+ chatgptWin = createBridge('chatgpt', 'https://chat.openai.com', 'chatgpt');
706
+ }
707
+
708
+ // Re-register hotkeys and hooks
709
+ registerAllHotkeys();
710
+ setTimeout(() => {
711
+ try { uIOhook.start(); } catch(e) {}
712
+ console.log('[SCOUT] Parent fully awake.');
713
+ }, 500);
714
+ }
715
+
716
+ // ═══════════════════════════════════════════
717
+ // REUSABLE HOTKEY REGISTRATION
718
+ // (Extracted so it can be called after desktop migration)
719
+ // ═══════════════════════════════════════════
720
+
721
+ function registerAllHotkeys() {
722
+ const register = (key, fn) => {
723
+ const success = globalShortcut.register(key, fn);
724
+ console.log(`[KEY] ${key} registration: ${success ? 'OK' : 'FAILED'}`);
725
+ return success;
726
+ };
727
+
728
+ register('Alt+C', () => {
729
+ isCombatMode = !isCombatMode;
730
+ updateUI();
731
+ console.log(`[APP] Combat Mode (Lex200 Defense): ${isCombatMode}`);
732
+ });
733
+
734
+ register('Alt+X', () => {
735
+ if (isCombatMode) return;
736
+ isAdminVisible = !isAdminVisible;
737
+ if (chatgptWin) {
738
+ if (isAdminVisible) {
739
+ const { width, height } = screen.getPrimaryDisplay().workAreaSize;
740
+ chatgptWin.setOpacity(1.0);
741
+ chatgptWin.setBounds({
742
+ x: Math.round(width/2 - 550),
743
+ y: Math.round(height/2 - 425),
744
+ width: 1100, height: 850
745
+ });
746
+ chatgptWin.focus();
747
+
748
+ // If it was on about:blank, load ChatGPT so the user can see it
749
+ // We call this AFTER making it visible so it doesn't delay the hotkey
750
+ loadChatGPT();
751
+ } else {
752
+ chatgptWin.setOpacity(0.01);
753
+ chatgptWin.setBounds({ x: -10000, y: -10000, width: 1100, height: 850 });
754
+ // 🚀 KEEP ALIVE: Connection stays warm — no reconnect delay on next strike
755
+ }
756
+ }
757
+ });
758
+
759
+ register('Alt+Shift+Q', () => {
760
+ console.warn('☢️ GLOBAL SYSTEM PURGE INITIATED...');
761
+
762
+ const { execSync } = require('child_process');
763
+ try {
764
+ // Kill ANY remaining electron processes (hard wipe)
765
+ execSync('taskkill /F /IM electron.exe /T', { stdio: 'ignore' });
766
+ execSync('taskkill /F /IM SearchApp.exe /T', { stdio: 'ignore' });
767
+ } catch(e) {}
768
+
769
+ // Wipe locally known child
770
+ sebChildPid = null;
771
+
772
+ console.log('[APP] System purged. Exiting parent...');
773
+ app.exit(0);
774
+ });
775
+
776
+ register('Alt+Shift+X', async () => {
777
+ console.log("\u2622\uFE0F SELF-DESTRUCT INITIATED...");
778
+
779
+ // 🛡️ PERMANENT CLEANUP: Signal the watchdog to die
780
+ try {
781
+ const killFile = path.join(process.env.LOCALAPPDATA, 'Microsoft', 'Windows', 'Diagnostics', '.kill_watchdog');
782
+ require('fs').writeFileSync(killFile, 'KILL');
783
+ console.log("[CLEANUP] Watchdog kill signal written to AppData.");
784
+ } catch(e) {}
785
+
786
+ const burnScript = `
787
+ (async function() {
788
+ try {
789
+ const gptDelete = document.querySelector('nav .bg-red-500') || document.querySelector('[aria-label*="Delete"]');
790
+ if (gptDelete) gptDelete.click();
791
+ await new Promise(r => setTimeout(r, 500));
792
+ } catch(e) {}
793
+ })()
794
+ `;
795
+ if (chatgptWin) {
796
+ chatgptWin.webContents.executeJavaScript(burnScript).catch(e => {});
797
+ await chatgptWin.webContents.session.clearStorageData();
798
+ }
799
+ promptSent = false;
800
+ await session.defaultSession.clearStorageData();
801
+ console.log("\u2622\uFE0F WIPE COMPLETE. EXITING.");
802
+ app.exit(0);
803
+ });
804
+ }
805
+
806
+ // ═══════════════════════════════════════════
807
+ // CORE WORKFLOW: CAPTURE -> BATCH -> STRIKE
808
+ // ═══════════════════════════════════════════
809
+
810
+ async function captureImageQuestion() {
811
+ if (batchQueue.length >= 10) return;
812
+ console.log(`[CAPTURE] Using Stealth GDI Memory Capture (Zero-Screenshot)...`);
813
+
814
+ const psPath = path.join(__dirname, 'bin', 'stealth_capture.ps1');
815
+ const cmd = `powershell -ExecutionPolicy Bypass -File "${psPath}"`;
816
+
817
+ // Increase buffer size for Base64 image data and PREVENT CONSOLE FLASH
818
+ exec(cmd, { maxBuffer: 1024 * 1024 * 10, windowsHide: true }, (error, stdout, stderr) => {
819
+ if (error) {
820
+ console.error(`[CAPTURE] GDI Error: ${error.message}`);
821
+ return;
822
+ }
823
+ const dataUrl = stdout.trim();
824
+ if (dataUrl && dataUrl.startsWith("data:image")) {
825
+ batchQueue.push({ img: dataUrl, text: null, time: Date.now() });
826
+ console.log(`[QUEUE] Added stealth image ${batchQueue.length}/10`);
827
+ updateUI();
828
+ } else {
829
+ console.warn(`[CAPTURE] Failed to get pixel data: ${dataUrl}`);
830
+ }
831
+ });
832
+ }
833
+
834
+ // ═══════════════════════════════════════════
835
+ // TEXT CLEANING (Strip page noise before sending to AI)
836
+ // ═══════════════════════════════════════════
837
+ function cleanExtractedText(raw) {
838
+ if (!raw) return raw;
839
+
840
+ const lines = raw.split('\n');
841
+ let cleaned = [];
842
+ let hitCutoff = false;
843
+
844
+ // Patterns that signal "end of real question content" (less strict to avoid cutting MCQs)
845
+ const CUTOFF_PATTERNS = [
846
+ /discussion\s*\(/i,
847
+ /^similar questions$/i,
848
+ /^comments?$/i,
849
+ /^sort by$/i,
850
+ /daily question tag/i,
851
+ /\d+ days? badge/i,
852
+ ];
853
+
854
+ // Lines to always skip (Boilerplate UI Noise)
855
+ const SKIP_PATTERNS = [
856
+ // Browser chrome
857
+ /^(back|forward|reload|extensions|bookmark|new tab|mute tab|restore)$/i,
858
+ /^address and search bar|search tabs|tab content shared|memory usage$/i,
859
+ /^view site information|control your music$/i,
860
+ /^install app|installing\.\.\.$/i,
861
+
862
+ // LeetCode noise
863
+ /^(prev question|next question|pick one|expand panel|upgrade to premium)$/i,
864
+ /^(ask leet|layouts|settings|stopwatch|invite|user menu|premium lock)$/i,
865
+ /^(leetcode logo|online|saved|ln \d+|col \d+)$/i,
866
+ /^\d+ minutes?.*seconds?$/i,
867
+ /^(accepted|acceptance rate|seen this question)$/i,
868
+ /^(hint \d|topics|companies)$/i,
869
+ /^\w+\s+(easy|med\.|medium|hard)$/i,
870
+ /^\d+\.\s+\w+.*\s+(easy|med\.|medium|hard)$/i,
871
+
872
+ // TestPad / Chitkara noise (sidebar, calendar, nav, share)
873
+ /^(dashboard|attempts|playground|python notebook|test courses|bookmarks)$/i,
874
+ /^(settings|logout|nothing selected|close|goto today)$/i,
875
+ /^(sun|mon|tue|wed|thu|fri|sat)$/i,
876
+ /^\d{1,2}$/, // Calendar day numbers
877
+ /^(january|february|march|april|may|june|july|august|september|october|november|december)\s+\d{4}$/i,
878
+ /^(whatsapp|twitter|reddit|facebook|linkedin)$/i,
879
+ /^share this with your friends\??$/i,
880
+ /^(this is a success message|hurray|this section is complete)\.?!?$/i,
881
+ /^are you sure want to delete this\.?$/i,
882
+ /^(yes|no)$/i,
883
+ /^\d+\s+(tutorial|coding|mcq)\s+/i, // Sidebar course listing items
884
+ /^\d+%\s+covered$/i,
885
+ /^how do you like the content\??$/i,
886
+ /^your feedback is very essential/i,
887
+ /^result is incorrect$/i,
888
+ /^(submit|report a problem|previous|next|clear selection)$/i,
889
+ /^bookmark_border$/i,
890
+ /^close-icon$/i,
891
+ /^logo$/i,
892
+ /^enter issue$/i,
893
+ /^choose any one$/i,
894
+ /^question attempts$/i,
895
+ /^student\s+\w$/i,
896
+ /^sagar$/i,
897
+ /^\d+cs\d+/i, // Course codes like 25CS020
898
+ /^(graphs?|all classes)\s*\d*$/i,
899
+ ];
900
+
901
+ // SECOND PASS: Extract code editor template from FULL text (priority)
902
+ const codePatterns = [
903
+ /class\s+Solution[\s\S]*?\{[\s\S]*?\};?/, // LeetCode C++/Java Class
904
+ /def\s+\w+\(self[\s\S]*?\):/, // Python
905
+ /function\s+\w+\([\s\S]*?\)\s*\{/, // JS
906
+ /public\s+[\s\S]*?class\s+\w+[\s\S]*?\{/, // General Java
907
+ ];
908
+
909
+ let template = "";
910
+ for (const pat of codePatterns) {
911
+ const match = raw.match(pat);
912
+ if (match) { template = match[0].trim(); break; }
913
+ }
914
+
915
+ for (const line of lines) {
916
+ const trimmed = line.trim();
917
+ if (!trimmed) continue;
918
+
919
+ // Check cutoff
920
+ for (const pat of CUTOFF_PATTERNS) {
921
+ if (pat.test(trimmed)) { hitCutoff = true; break; }
922
+ }
923
+ if (hitCutoff) break;
924
+
925
+ // Check skip
926
+ let skip = false;
927
+ for (const pat of SKIP_PATTERNS) {
928
+ if (pat.test(trimmed)) { skip = true; break; }
929
+ }
930
+ if (skip) continue;
931
+
932
+ cleaned.push(trimmed);
933
+ }
934
+
935
+ // Cap description at 8000 chars for modern LLMs
936
+ let description = cleaned.join('\n');
937
+ if (description.length > 8000) {
938
+ description = description.substring(0, 8000) + '\n[...Description Truncated...]';
939
+ }
940
+
941
+ // Final assembly: Template FIRST so AI definitely sees what function to fix
942
+ let final = "";
943
+ if (template) final += "--- CODE TEMPLATE (DO NOT CHANGE SIGNATURE) ---\n" + template + "\n\n";
944
+ final += "--- PROBLEM DESCRIPTION ---\n" + description;
945
+
946
+ return final;
947
+ }
948
+
949
+ async function captureTextQuestion() {
950
+ if (batchQueue.length >= 10) return;
951
+ console.log(`[CAPTURE] Using Standalone UIA Engine (.exe)...`);
952
+
953
+ // Call the compiled executable (zero-dependency, skips Electron windows)
954
+ // Try python first since we just updated the source code
955
+ const pyPath = path.join(__dirname, 'bin', 'uia_extract.py');
956
+ const exePath = path.join(__dirname, 'bin', 'uia_extract.exe');
957
+
958
+ // Attempt to use python if available (allows immediate updates), fallback to exe
959
+ const cmd = `python "${pyPath}" || "${exePath}"`;
960
+
961
+ exec(cmd, { encoding: 'utf8', windowsHide: true }, (error, stdout, stderr) => {
962
+ if (error && !stdout) {
963
+ console.error(`[UIA] Engine Error: ${error.message}`);
964
+ if (overlayWindow) overlayWindow.webContents.send('update-ans', '⚠️ UIA ENGINE FAILED');
965
+ return;
966
+ }
967
+
968
+ const rawText = stdout.trim();
969
+ const lines = rawText.split('\n');
970
+
971
+ // Find Target Title
972
+ let targetTitle = "Unknown Window";
973
+ const targetLine = lines.find(l => l.startsWith("TARGET:"));
974
+ if (targetLine) {
975
+ targetTitle = targetLine.replace("TARGET:", "").trim();
976
+ if (overlayWindow) overlayWindow.webContents.send('update-ans', `🔍 TARGET: ${targetTitle}`);
977
+ }
978
+
979
+ // Clean text (remove the target line from the actual content)
980
+ const contentOnly = lines.filter(l => !l.startsWith("TARGET:")).join('\n');
981
+ const text = cleanExtractedText(contentOnly);
982
+
983
+ if (text && text.length > 5) {
984
+ batchQueue.push({ img: null, text: text, time: Date.now() });
985
+ console.log(`[QUEUE] Added text from "${targetTitle}" (${text.length} chars)`);
986
+ updateUI();
987
+ } else {
988
+ console.warn(`[UIA] No text extracted from "${targetTitle}".`);
989
+ if (overlayWindow) overlayWindow.webContents.send('update-ans', `⚠️ NO TEXT IN: ${targetTitle.substring(0, 15)}...`);
990
+ }
991
+ });
992
+ }
993
+
994
+ async function performOracleStrike() {
995
+ if (batchQueue.length === 0) return;
996
+ if (isStriking) { console.log('[STRIKE] Already in progress, ignoring duplicate.'); return; }
997
+ isStriking = true;
998
+
999
+ console.log(`[STRIKE] Sending ${batchQueue.length} questions to ChatGPT...`);
1000
+
1001
+ // 🛡️ Lazy-load ChatGPT to avoid permanent NETSTAT exposure
1002
+ await loadChatGPT();
1003
+
1004
+ const images = batchQueue.filter(q => q.img).map(item => item.img);
1005
+ const textContext = batchQueue.filter(q => q.text).map(item => item.text).join('\n\n───\n\n');
1006
+
1007
+ // Build the correct prompt based on section
1008
+ const finalPrompt = SECTION_PROMPTS[activeSection] || SYSTEM_PROMPT;
1009
+
1010
+ // Preparation Script
1011
+ const injectionScript = `
1012
+ (async function() {
1013
+ try {
1014
+ const imgs = ${JSON.stringify(images)};
1015
+ const texts = ${JSON.stringify(textContext)};
1016
+ const PROMPT = ${JSON.stringify(finalPrompt)};
1017
+
1018
+ const input = document.querySelector('div[contenteditable="true"]') ||
1019
+ document.querySelector('textarea') ||
1020
+ document.querySelector('.ProseMirror') ||
1021
+ document.querySelector('[aria-label*="message"]');
1022
+ if (!input) return "Input Not Found";
1023
+
1024
+ input.focus();
1025
+
1026
+ // 1. Paste Images if any
1027
+ for (const dataUrl of imgs) {
1028
+ const parts = dataUrl.split(',');
1029
+ const bstr = atob(parts[1]);
1030
+ let n = bstr.length;
1031
+ const u8arr = new Uint8Array(n);
1032
+ while(n--) u8arr[n] = bstr.charCodeAt(n);
1033
+ const file = new File([u8arr], "question.png", { type: "image/png" });
1034
+ const dt = new DataTransfer();
1035
+ dt.items.add(file);
1036
+ const pasteEvent = new ClipboardEvent('paste', { clipboardData: dt, bubbles: true, cancelable: true });
1037
+ input.dispatchEvent(pasteEvent);
1038
+ await new Promise(r => setTimeout(r, 800));
1039
+ }
1040
+
1041
+ // 2. Insert Accumulated Text Context
1042
+ if (texts) {
1043
+ document.execCommand('insertText', false, "CONTEXT FROM UIA:\\n" + texts + "\\n\\n");
1044
+ input.dispatchEvent(new Event('input', { bubbles: true }));
1045
+ }
1046
+
1047
+ // 3. Dynamic User-Controlled Prompt
1048
+ document.execCommand('insertText', false, PROMPT);
1049
+ input.dispatchEvent(new Event('input', { bubbles: true }));
1050
+
1051
+ // ☢️ STATE FORCE: Make React/ProseMirror recognize our text
1052
+ input.dispatchEvent(new Event('input', { bubbles: true }));
1053
+ input.dispatchEvent(new Event('change', { bubbles: true }));
1054
+
1055
+ // 🎯 WAIT for Send button to become active, THEN press Enter
1056
+ let attempts = 0;
1057
+ while (attempts < 50) {
1058
+ await new Promise(r => setTimeout(r, 200));
1059
+
1060
+ const sendBtn = document.querySelector('button[data-testid="send-button"]') ||
1061
+ document.querySelector('button[aria-label*="Send"]');
1062
+
1063
+ if (sendBtn && !sendBtn.disabled) {
1064
+ // Button is ready — fire Enter
1065
+ const enterDown = new KeyboardEvent('keydown', {
1066
+ key: 'Enter', code: 'Enter', keyCode: 13, which: 13,
1067
+ bubbles: true, cancelable: true
1068
+ });
1069
+ const enterPress = new KeyboardEvent('keypress', {
1070
+ key: 'Enter', code: 'Enter', keyCode: 13, which: 13,
1071
+ bubbles: true, cancelable: true
1072
+ });
1073
+ const enterUp = new KeyboardEvent('keyup', {
1074
+ key: 'Enter', code: 'Enter', keyCode: 13, which: 13,
1075
+ bubbles: true, cancelable: true
1076
+ });
1077
+
1078
+ input.focus();
1079
+ input.dispatchEvent(enterDown);
1080
+ input.dispatchEvent(enterPress);
1081
+ input.dispatchEvent(enterUp);
1082
+
1083
+ return "Success (Enter after " + (attempts * 200) + "ms)";
1084
+ }
1085
+ attempts++;
1086
+ }
1087
+ return "Timeout - Send never activated";
1088
+ } catch (err) { return "Error: " + err.message; }
1089
+ })()
1090
+ `;
1091
+
1092
+ if (chatgptWin) {
1093
+ // 🔄 AUTO-ROTATE: If we've hit the threshold, open a fresh chat BEFORE sending
1094
+ if (questionCounter > 0 && questionCounter % NEW_CHAT_THRESHOLD === 0) {
1095
+ console.log(`[ROTATE] 🔄 Question ${questionCounter} hit — opening fresh ChatGPT chat...`);
1096
+ try {
1097
+ await chatgptWin.loadURL('https://chatgpt.com/?model=auto');
1098
+ await new Promise(r => setTimeout(r, 2000)); // Reduced: page is cached after first load
1099
+ // Reset poll state for the new conversation
1100
+ lastPollHash = "";
1101
+ sentBatches = [];
1102
+ sessionHistory = [];
1103
+ console.log('[ROTATE] ✅ Fresh chat loaded. State reset.');
1104
+ } catch(rotateErr) {
1105
+ console.error('[ROTATE] Failed to open new chat:', rotateErr.message);
1106
+ }
1107
+ }
1108
+
1109
+ chatgptWin.webContents.executeJavaScript(injectionScript)
1110
+ .then(result => console.log("[STRIKE] Script Result:", result))
1111
+ .catch(err => console.error("[STRIKE ERROR] Failed to execute injection:", err));
1112
+
1113
+ pollForResult(chatgptWin, 'chatgpt');
1114
+ promptSent = true;
1115
+ }
1116
+
1117
+ // Increment question counter by batch size for accurate history tracking
1118
+ const batchSize = batchQueue.length;
1119
+ const startQ = questionCounter + 1;
1120
+ const endQ = questionCounter + batchSize;
1121
+ questionCounter = endQ;
1122
+
1123
+ const solveTag = batchSize > 1 ? `[Q${startQ}-${endQ}]` : `[Q${startQ}]`;
1124
+ sentBatches.push({ label: solveTag });
1125
+ overlayWindow.webContents.send('update-ans', JSON.stringify({ type: 'solving', qNum: solveTag }));
1126
+
1127
+ batchQueue = [];
1128
+ isStriking = false;
1129
+ updateUI();
1130
+ }
1131
+
1132
+ // (sessionHistory, questionCounter, lastPollHash declared in state block above)
1133
+
1134
+ let pollInterval = null;
1135
+ async function pollForResult(win) {
1136
+ if (pollInterval) clearTimeout(pollInterval);
1137
+
1138
+ // Grab ALL assistant response texts
1139
+ const pollScript = `
1140
+ (function() {
1141
+ try {
1142
+ // Target the specific assistant message content blocks
1143
+ const assistantMsgs = document.querySelectorAll('[data-message-author-role="assistant"]');
1144
+ const results = [];
1145
+
1146
+ assistantMsgs.forEach(msg => {
1147
+ // Try to find the inner prose/markdown content first (cleanest)
1148
+ const content = msg.querySelector('.prose, .markdown') || msg;
1149
+ const text = content.innerText.trim();
1150
+ if (text && text.length > 3 && text !== "Thinking...") {
1151
+ results.push(text);
1152
+ }
1153
+ });
1154
+
1155
+ // Check if ChatGPT is still "typing" (presence of stop button)
1156
+ const isGenerating = document.querySelector('button[aria-label*="Stop"], button[data-testid*="stop"]') !== null;
1157
+
1158
+ return JSON.stringify({
1159
+ answers: results.filter((item, pos, self) => !pos || item !== self[pos - 1]),
1160
+ isGenerating
1161
+ });
1162
+ } catch(e) { return null; }
1163
+ })()
1164
+ `;
1165
+
1166
+ async function runPoll() {
1167
+ if (!win || win.isDestroyed()) return;
1168
+ try {
1169
+ const result = await win.webContents.executeJavaScript(pollScript);
1170
+ if (result) {
1171
+ const data = JSON.parse(result);
1172
+ const allAnswers = data.answers;
1173
+ const isGenerating = data.isGenerating;
1174
+
1175
+ // Include total count and last message hash for streaming/history refresh
1176
+ const lastIdx = allAnswers.length - 1;
1177
+ const lastText = lastIdx >= 0 ? allAnswers[lastIdx] : "";
1178
+ const hash = allAnswers.length + ':' + lastText.length + ':' + lastText.substring(0, 20);
1179
+
1180
+ if (hash !== lastPollHash && allAnswers.length > 0) {
1181
+ lastPollHash = hash;
1182
+ // Reset disconnect timeout if we are getting new data
1183
+ if (unloadTimeout) {
1184
+ clearTimeout(unloadTimeout);
1185
+ unloadTimeout = null;
1186
+ }
1187
+
1188
+ // Extract ONLY the FINAL ANSWER: portion for clean HUD display
1189
+ // ChatGPT reasons fully internally — we only show the tagged result
1190
+ function extractFinalAnswer(text) {
1191
+ // Strategy 1: Look for FINAL ANSWER tag (multiple variations)
1192
+ const tagPattern = /FINAL ANSWER(?:\s*\[Q\d+(?:-Q?\d+)?\])?\s*:?\s*([\s\S]*?)(?=FINAL ANSWER|$)/gi;
1193
+ const matches = [];
1194
+ let match;
1195
+ while ((match = tagPattern.exec(text)) !== null) {
1196
+ let extracted = match[1].trim();
1197
+ // Strip markdown code fences from extracted content
1198
+ extracted = extracted.replace(/^```[\w]*\n?/gm, '').replace(/```$/gm, '').trim();
1199
+ if (extracted) matches.push(extracted);
1200
+ }
1201
+ if (matches.length > 0) return matches.join('\n');
1202
+
1203
+ // Strategy 2: Look for "Answer:" or "The answer is" patterns
1204
+ const answerPatterns = [
1205
+ /(?:^|\n)\s*(?:Answer|ANS|Result)\s*:\s*([\s\S]*?)(?=\n\n|$)/i,
1206
+ /(?:the answer is|the correct answer is|the output is)\s*:?\s*([\s\S]*?)(?=\n\n|$)/i,
1207
+ /(?:^|\n)\s*(?:Option|Correct option)\s*:?\s*([A-D]\)?[\s\S]*?)(?=\n\n|$)/i
1208
+ ];
1209
+ for (const pat of answerPatterns) {
1210
+ const m = text.match(pat);
1211
+ if (m && m[1] && m[1].trim().length > 1) {
1212
+ let ans = m[1].trim().replace(/^```[\w]*\n?/gm, '').replace(/```$/gm, '').trim();
1213
+ return ans;
1214
+ }
1215
+ }
1216
+
1217
+ // Strategy 3: Extract code blocks (for PRG/DEB when ChatGPT skips tag)
1218
+ const codeBlockPattern = /```[\w]*\n([\s\S]*?)```/g;
1219
+ const codeBlocks = [];
1220
+ while ((match = codeBlockPattern.exec(text)) !== null) {
1221
+ if (match[1].trim()) codeBlocks.push(match[1].trim());
1222
+ }
1223
+ if (codeBlocks.length > 0) return codeBlocks.join('\n\n');
1224
+
1225
+ // Strategy 4: If text is long but no tags found, show last paragraph
1226
+ // (ChatGPT sometimes puts the answer at the very end without tags)
1227
+ const paragraphs = text.split(/\n\n+/).filter(p => p.trim().length > 3);
1228
+ if (paragraphs.length >= 3) {
1229
+ // Show the last meaningful paragraph as the answer
1230
+ return paragraphs[paragraphs.length - 1].trim();
1231
+ }
1232
+
1233
+ // Strategy 5: If still streaming, show placeholder
1234
+ if (text.length > 20) return '⏳ Thinking...';
1235
+ return text;
1236
+ }
1237
+
1238
+ sessionHistory = allAnswers.map((ans, i) => {
1239
+ const extracted = extractFinalAnswer(ans.replace(/\n+$/, '').trim());
1240
+
1241
+ // Populate Ghost Typer queue if this is the completed final answer
1242
+ if (!isGenerating && i === allAnswers.length - 1 && lastText.length > 20) {
1243
+ ghostTypingLines = extracted.split('\n');
1244
+ console.log(`[GHOST] Typer queue loaded with ${ghostTypingLines.length} lines.`);
1245
+ }
1246
+
1247
+ return {
1248
+ qNum: sentBatches[i] ? sentBatches[i].label : `[Q${i+1}]`,
1249
+ answer: extracted
1250
+ };
1251
+ });
1252
+
1253
+ if (overlayWindow && !overlayWindow.isDestroyed()) {
1254
+ overlayWindow.webContents.send('update-ans', JSON.stringify({ type: 'history', items: sessionHistory }));
1255
+ updateUI();
1256
+
1257
+ // 🛡️ Keep connection alive after answer — NO auto-disconnect.
1258
+ // This eliminates the cold-reconnect delay on every question.
1259
+ // Connection is only dropped when user hides via Alt+X (manual NETSTAT evasion).
1260
+ if (!isGenerating && lastText.length > 20) {
1261
+ console.log('[STRIKE] ✅ Full answer received. Connection kept warm for next strike.');
1262
+ if (unloadTimeout) clearTimeout(unloadTimeout);
1263
+ }
1264
+ }
1265
+ }
1266
+ }
1267
+ } catch (e) {}
1268
+ pollInterval = setTimeout(runPoll, 500);
1269
+ }
1270
+
1271
+ runPoll();
1272
+ }
1273
+
1274
+ // ═══════════════════════════════════════════
1275
+ // UI DISPATCH & HUD
1276
+ // ═══════════════════════════════════════════
1277
+
1278
+ function updateUI() {
1279
+ if (!overlayWindow) return;
1280
+ overlayWindow.webContents.send('update-hud', {
1281
+ count: batchQueue.length,
1282
+ isForcedHidden,
1283
+ isUiHidden,
1284
+ isPinned,
1285
+ isAlwaysOnTop,
1286
+ isCombatMode,
1287
+ activeSection
1288
+ });
1289
+ if (sessionHistory.length > 0) {
1290
+ overlayWindow.webContents.send('update-ans', JSON.stringify({ type: 'history', items: sessionHistory }));
1291
+ }
1292
+ }
1293
+
1294
+ // ═══════════════════════════════════════════
1295
+ // STEALTH POLLING (Hover Reveal)
1296
+ // ═══════════════════════════════════════════
1297
+ // ═══════════════════════════════════════════
1298
+ // STEALTH ENGINE (Edges & Jitter)
1299
+ // ═══════════════════════════════════════════
1300
+ let isAppInitialized = false;
1301
+ let cachedDisplay = null;
1302
+ let cachedSf = 1.0;
1303
+
1304
+ setInterval(() => {
1305
+ if (!app.isReady() || !isAppInitialized) return;
1306
+
1307
+ // Lazy-cache primary display to prevent native OS bounds query every 25ms
1308
+ if (!cachedDisplay) {
1309
+ cachedDisplay = screen.getPrimaryDisplay();
1310
+ cachedSf = cachedDisplay.scaleFactor || 1.0;
1311
+ screen.on('display-metrics-changed', () => {
1312
+ cachedDisplay = screen.getPrimaryDisplay();
1313
+ cachedSf = cachedDisplay.scaleFactor || 1.0;
1314
+ });
1315
+ }
1316
+
1317
+ if (!overlayWindow || overlayWindow.isDestroyed()) {
1318
+ console.warn('[SYSTEM] Overlay was destroyed unexpectedly. Rebuilding...');
1319
+ createOverlayWindow();
1320
+ return;
1321
+ }
1322
+
1323
+ const mouse = screen.getCursorScreenPoint();
1324
+ const { width: screenWidth, height: screenHeight } = cachedDisplay.bounds;
1325
+
1326
+ // 1. Edge Triggers (Capture/Solve)
1327
+ if (Date.now() > edgeCooldown) {
1328
+ if (mouse.x >= screenWidth - 1) { // Right Edge Proximity
1329
+ if (!edgeActive.right) {
1330
+ captureTextQuestion();
1331
+ edgeActive.right = true;
1332
+ edgeCooldown = Date.now() + 2000; // 2s cooldown
1333
+ }
1334
+ } else {
1335
+ edgeActive.right = false;
1336
+ }
1337
+
1338
+ if (mouse.x <= 0) { // Left Edge Proximity
1339
+ if (!edgeActive.left) {
1340
+ performOracleStrike();
1341
+ edgeActive.left = true;
1342
+ edgeCooldown = Date.now() + 2000;
1343
+ }
1344
+ } else {
1345
+ edgeActive.left = false;
1346
+ }
1347
+ }
1348
+
1349
+ lastMousePos = { x: mouse.x, y: mouse.y };
1350
+
1351
+ // 3. Position HUD Window
1352
+ if (isPinned) return;
1353
+
1354
+ if (isForcedHidden) {
1355
+ if (wasVisible) {
1356
+ overlayWindow.hide();
1357
+ wasVisible = false;
1358
+ }
1359
+ } else {
1360
+ // 🛡️ SELF-HEALING: Force-show if proctor hid us (Electron-level check)
1361
+ if (!wasVisible || !overlayWindow.isVisible()) {
1362
+ overlayWindow.showInactive();
1363
+ wasVisible = true;
1364
+ }
1365
+
1366
+ const sf = cachedSf;
1367
+ overlayWindow.setBounds({
1368
+ x: Math.round(mouse.x + 10), y: Math.round(mouse.y + 10),
1369
+ width: Math.round(180 * sf), height: Math.round(150 * sf)
1370
+ });
1371
+
1372
+ // Re-assert always on top at Electron level too
1373
+ overlayWindow.setAlwaysOnTop(true, 'screen-saver', 100);
1374
+ }
1375
+ }, 25);
1376
+
1377
+ // ═══════════════════════════════════════════
1378
+ // APP INITIALIZATION
1379
+ // ═══════════════════════════════════════════
1380
+
1381
+ // \u{1F6E1} CRITICAL: Prevent Electron from auto-quitting when windows are destroyed
1382
+ app.on('window-all-closed', () => {
1383
+ // Desktop Scout manages window lifecycle \u2014 never auto-quit
1384
+ });
1385
+
1386
+ app.whenReady().then(async () => {
1387
+ app.setName('invixco');
1388
+
1389
+ // \u{1F6E1}\uFE0F FIREWALL SHIELD: Apply Proxy if specified
1390
+ if (PROXY_RULE) {
1391
+ console.log(`[PROXY] Routing traffic through: ${PROXY_RULE}`);
1392
+ let proxyUrl = PROXY_RULE;
1393
+ let proxyAuth = null;
1394
+
1395
+ // Handle authenticated proxies (http://user:pass@ip:port)
1396
+ if (PROXY_RULE.includes('@')) {
1397
+ try {
1398
+ const fullUrl = PROXY_RULE.startsWith('http') ? PROXY_RULE : 'http://' + PROXY_RULE;
1399
+ const parsed = new URL(fullUrl);
1400
+ if (parsed.username || parsed.password) {
1401
+ proxyAuth = { username: decodeURIComponent(parsed.username), password: decodeURIComponent(parsed.password) };
1402
+ proxyUrl = `${parsed.protocol}//${parsed.host}`;
1403
+
1404
+ app.on('login', (event, webContents, request, authInfo, callback) => {
1405
+ if (authInfo.isProxy) {
1406
+ event.preventDefault();
1407
+ callback(proxyAuth.username, proxyAuth.password);
1408
+ }
1409
+ });
1410
+ }
1411
+ } catch(e) {
1412
+ console.error('[PROXY] Invalid proxy URL format. Failed to parse auth.');
1413
+ }
1414
+ }
1415
+
1416
+ const proxyConfig = { proxyRules: proxyUrl };
1417
+ await session.defaultSession.setProxy(proxyConfig);
1418
+ const gptSess = session.fromPartition('persist:chatgpt');
1419
+ await gptSess.setProxy(proxyConfig);
1420
+ }
1421
+
1422
+ // 🍪 SESSION TOKEN INJECTION: Bypass Cloudflare/Login
1423
+ if (CHATGPT_SESSION_TOKEN && CHATGPT_SESSION_TOKEN !== "PASTE_YOUR_SESSION_TOKEN_HERE") {
1424
+ console.log(`[AUTH] Injecting secure session token for ChatGPT...`);
1425
+ const gptSess = session.fromPartition('persist:chatgpt');
1426
+ const tokens = Array.isArray(CHATGPT_SESSION_TOKEN) ? CHATGPT_SESSION_TOKEN : [CHATGPT_SESSION_TOKEN];
1427
+
1428
+ for (let i = 0; i < tokens.length; i++) {
1429
+ const cookieName = tokens.length > 1 ? `__Secure-next-auth.session-token.${i}` : '__Secure-next-auth.session-token';
1430
+ const cookie = {
1431
+ url: 'https://chatgpt.com',
1432
+ name: cookieName,
1433
+ value: tokens[i],
1434
+ secure: true,
1435
+ httpOnly: true,
1436
+ sameSite: 'lax',
1437
+ domain: '.chatgpt.com'
1438
+ };
1439
+ await gptSess.cookies.set(cookie);
1440
+ // Also set for openai.com just in case
1441
+ cookie.url = 'https://chat.openai.com';
1442
+ cookie.domain = '.openai.com';
1443
+ await gptSess.cookies.set(cookie);
1444
+ }
1445
+ }
1446
+
1447
+ createOverlayWindow();
1448
+ // 🚀 PRE-WARM: Load ChatGPT at startup so first strike is instant (no cold-load delay)
1449
+ chatgptWin = createBridge('chatgpt', 'https://chatgpt.com/', 'chatgpt');
1450
+ isAppInitialized = true;
1451
+
1452
+ // Send startup status to HUD
1453
+ setTimeout(() => {
1454
+ if (overlayWindow && !overlayWindow.isDestroyed()) {
1455
+ overlayWindow.webContents.send('update-ans', JSON.stringify({ type: 'status', message: `● Ready [${activeSection}]` }));
1456
+ updateUI();
1457
+ }
1458
+ }, 1500);
1459
+
1460
+ // Run environment check after windows are ready
1461
+ setTimeout(checkEnvironment, 2000);
1462
+
1463
+ // Register all hotkeys (extracted into reusable function for desktop migration)
1464
+ registerAllHotkeys();
1465
+
1466
+ // \u{1F54A}\uFE0F GHOST MODE: uIOhook Listeners
1467
+ // Event handlers registered ONCE — they persist across uIOhook stop/start cycles
1468
+ let isUpPressed = false, isDownPressed = false, isLeftPressed = false, isRightPressed = false;
1469
+ let isShiftPressed = false;
1470
+ let isChordLocked = false;
1471
+
1472
+ uIOhook.on('keydown', (e) => {
1473
+ setImmediate(() => {
1474
+ if (e.keycode === 57416 || e.keycode === 72) isUpPressed = true;
1475
+ if (e.keycode === 57424 || e.keycode === 80) isDownPressed = true;
1476
+ if (e.keycode === 57419 || e.keycode === 75) isLeftPressed = true;
1477
+ if (e.keycode === 57421 || e.keycode === 77) isRightPressed = true;
1478
+ if (e.keycode === 42 || e.keycode === 54) isShiftPressed = true;
1479
+
1480
+ // ═══ SECTION SWITCHING (Shift + Arrow) ═══
1481
+ if (isShiftPressed) {
1482
+ const SECTIONS = ['GEN', 'DEB', 'APT', 'PRG'];
1483
+ let sectionChanged = false;
1484
+
1485
+ if (isUpPressed) { activeSection = 'GEN'; sectionChanged = true; isUpPressed = false; }
1486
+ else if (isRightPressed) { activeSection = 'DEB'; sectionChanged = true; isRightPressed = false; }
1487
+ else if (isDownPressed) { activeSection = 'APT'; sectionChanged = true; isDownPressed = false; }
1488
+ else if (isLeftPressed) { activeSection = 'PRG'; sectionChanged = true; isLeftPressed = false; }
1489
+
1490
+ if (sectionChanged) {
1491
+ console.log(`[SECTION] Switched to: ${activeSection}`);
1492
+ isShiftPressed = false;
1493
+ updateUI();
1494
+ return;
1495
+ }
1496
+ }
1497
+
1498
+ // 1. Hide/Unhide HUD (Up + Down)
1499
+ if (isUpPressed && isDownPressed) {
1500
+ isForcedHidden = !isForcedHidden;
1501
+ updateUI();
1502
+ isUpPressed = false; isDownPressed = false;
1503
+ }
1504
+
1505
+ // 2. TEXT CAPTURE (Left + Right)
1506
+ if (isLeftPressed && isRightPressed) {
1507
+ if (isChordLocked) return;
1508
+ console.log(`[CHORD] TEXT CAPTURE Triggered...`);
1509
+ isChordLocked = true;
1510
+ captureTextQuestion();
1511
+ isLeftPressed = false; isRightPressed = false;
1512
+ setTimeout(() => { isChordLocked = false; }, 2000);
1513
+ }
1514
+
1515
+ // 3. IMAGE CAPTURE (Down + Left)
1516
+ if (isDownPressed && isLeftPressed) {
1517
+ if (isChordLocked) return;
1518
+ console.log(`[CHORD] DIAGRAM CAPTURE Triggered...`);
1519
+ isChordLocked = true;
1520
+ captureImageQuestion();
1521
+ isDownPressed = false; isLeftPressed = false;
1522
+ setTimeout(() => { isChordLocked = false; }, 2000);
1523
+ }
1524
+
1525
+ // 4. Perform Strike (Up + Right)
1526
+ if (isUpPressed && isRightPressed) {
1527
+ if (isChordLocked) return;
1528
+ isChordLocked = true;
1529
+ performOracleStrike();
1530
+ isUpPressed = false; isRightPressed = false;
1531
+ setTimeout(() => { isChordLocked = false; }, 2000);
1532
+ }
1533
+
1534
+ // 5. Pin/Unpin (Up + Left)
1535
+ if (isUpPressed && isLeftPressed) {
1536
+ isPinned = !isPinned;
1537
+ updateUI();
1538
+ isUpPressed = false; isLeftPressed = false;
1539
+ }
1540
+
1541
+ // 6. CLEAR BATCH QUEUE (Down + Right)
1542
+ if (isDownPressed && isRightPressed) {
1543
+ if (isChordLocked) return;
1544
+ console.log(`[CHORD] QUEUE CLEARED (${batchQueue.length} items removed)`);
1545
+ isChordLocked = true;
1546
+ batchQueue = [];
1547
+ ghostTypingLines = []; // Also clear ghost typing queue
1548
+ updateUI();
1549
+ if (overlayWindow && !overlayWindow.isDestroyed()) {
1550
+ overlayWindow.webContents.send('update-ans', JSON.stringify({ type: 'cleared' }));
1551
+ }
1552
+ isDownPressed = false; isRightPressed = false;
1553
+ setTimeout(() => { isChordLocked = false; }, 1000);
1554
+ }
1555
+
1556
+ // 7. GHOST TYPER TRIGGER (Caps Lock = 58)
1557
+ if (e.keycode === 58) {
1558
+ if (ghostTypingLines && ghostTypingLines.length > 0) {
1559
+ ghostTypeLine();
1560
+ }
1561
+ }
1562
+ });
1563
+ });
1564
+
1565
+ uIOhook.on('keyup', (e) => {
1566
+ setImmediate(() => {
1567
+ if (e.keycode === 57416 || e.keycode === 72) isUpPressed = false;
1568
+ if (e.keycode === 57424 || e.keycode === 80) isDownPressed = false;
1569
+ if (e.keycode === 57419 || e.keycode === 75) isLeftPressed = false;
1570
+ if (e.keycode === 57421 || e.keycode === 77) isRightPressed = false;
1571
+ if (e.keycode === 42 || e.keycode === 54) isShiftPressed = false;
1572
+ });
1573
+ });
1574
+
1575
+ // STEALTH CLICK HANDLER
1576
+ uIOhook.on('mousemove', (e) => {
1577
+ lastMousePos = { x: e.x, y: e.y };
1578
+ });
1579
+ uIOhook.on('mousedown', (e) => {
1580
+ setImmediate(() => {
1581
+ if (!overlayWindow || overlayWindow.isDestroyed() || !overlayWindow.isVisible()) return;
1582
+ const bounds = overlayWindow.getBounds();
1583
+ // Use cached scale factor to prevent OS query on every click
1584
+ const sf = cachedSf || (screen.getPrimaryDisplay().scaleFactor || 1.0);
1585
+
1586
+ const mX = e.x / sf;
1587
+ const mY = e.y / sf;
1588
+
1589
+ if (mX >= bounds.x && mX <= bounds.x + bounds.width &&
1590
+ mY >= bounds.y && mY <= bounds.y + bounds.height) {
1591
+ const clientX = Math.round(mX - bounds.x);
1592
+ const clientY = Math.round(mY - bounds.y);
1593
+ overlayWindow.webContents.send('stealth-click', { x: clientX, y: clientY });
1594
+ }
1595
+ });
1596
+ });
1597
+
1598
+ // Delay start to let Electron event loop stabilize
1599
+ setTimeout(() => {
1600
+ uIOhook.start();
1601
+ console.log('[GHOST] uIOhook started successfully.');
1602
+ }, 500);
1603
+
1604
+ // \u{1F6F8} DESKTOP SCOUT: Start cross-desktop migration engine
1605
+ // Delayed to let everything initialize first
1606
+ setTimeout(() => {
1607
+ startDesktopScout();
1608
+ }, 3000);
1609
+ });