moidevx 1.0.0

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