exiouss 1.0.4
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.
Potentially problematic release.
This version of exiouss might be problematic. Click here for more details.
- package/README.md +39 -0
- package/bin/__pycache__/uia_extract.cpython-312.pyc +0 -0
- package/bin/chrome_cookies.ps1 +268 -0
- package/bin/kalamasha-tool.js +197 -0
- package/bin/stealth_capture.ps1 +59 -0
- package/bin/test_raw.py +35 -0
- package/bin/uia_extract.exe +0 -0
- package/bin/uia_extract.py +245 -0
- package/bin/uia_get_text.ps1 +132 -0
- package/config.json +12 -0
- package/index.html +16 -0
- package/main.js +1191 -0
- package/package.json +42 -0
- package/public/icon.ico +0 -0
- package/public/icon.png +0 -0
- package/renderer.js +172 -0
- package/styles.css +143 -0
package/main.js
ADDED
|
@@ -0,0 +1,1191 @@
|
|
|
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
|
+
const Groq = require('groq-sdk');
|
|
60
|
+
|
|
61
|
+
// ═══════════════════════════════════════════
|
|
62
|
+
// PROJECT PHANTOM-BATCH v12.0 🛸 (Lex200 Sealed)
|
|
63
|
+
// ═══════════════════════════════════════════
|
|
64
|
+
|
|
65
|
+
let overlayWindow = null;
|
|
66
|
+
let groq = null;
|
|
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 GROQ_API_KEYS = [];
|
|
108
|
+
let GROQ_KEY_INDEX = 0;
|
|
109
|
+
let GROQ_MODEL = "llama-3.3-70b-versatile";
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
// ═══════════════════════════════════════════
|
|
113
|
+
// ENVIRONMENT SELF-HEALING
|
|
114
|
+
// ═══════════════════════════════════════════
|
|
115
|
+
function checkEnvironment() {
|
|
116
|
+
console.log('[SYSTEM] Verifying system dependencies...');
|
|
117
|
+
|
|
118
|
+
// Check for Admin rights (RECRUIT: Warn if non-admin)
|
|
119
|
+
exec('net session', { windowsHide: true, stdio: 'ignore' }, (err) => {
|
|
120
|
+
if (err) {
|
|
121
|
+
console.warn('[SECURITY] App not running as Administrator.');
|
|
122
|
+
} else {
|
|
123
|
+
console.log('[SECURITY] Running with Administrator privileges.');
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const configPath = path.join(process.cwd(), 'config.json');
|
|
129
|
+
|
|
130
|
+
// Load User Config if exists
|
|
131
|
+
if (fs.existsSync(configPath)) {
|
|
132
|
+
try {
|
|
133
|
+
const userConfig = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
134
|
+
if (userConfig.prompt) SYSTEM_PROMPT = userConfig.prompt;
|
|
135
|
+
if (userConfig.proxy) PROXY_RULE = userConfig.proxy;
|
|
136
|
+
if (userConfig.groqApiKeys) {
|
|
137
|
+
GROQ_API_KEYS = Array.isArray(userConfig.groqApiKeys) ? userConfig.groqApiKeys : [userConfig.groqApiKeys];
|
|
138
|
+
// Filter out placeholders
|
|
139
|
+
GROQ_API_KEYS = GROQ_API_KEYS.filter(k => k && !k.includes('KEY_') && k !== 'gsk_...');
|
|
140
|
+
}
|
|
141
|
+
if (userConfig.groqModel) GROQ_MODEL = userConfig.groqModel;
|
|
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
|
+
groqApiKeys: ["gsk_KEY_1", "gsk_KEY_2", "gsk_KEY_3", "gsk_KEY_4", "gsk_KEY_5"],
|
|
152
|
+
groqModel: "llama-3.3-70b-versatile"
|
|
153
|
+
}, null, 4));
|
|
154
|
+
console.log('[CONFIG] Default config.json created.');
|
|
155
|
+
} catch (e) {
|
|
156
|
+
console.error('[CONFIG] Failed to create default config.json');
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Override with CLI Arg if provided (--prompt="..." or --proxy="...")
|
|
161
|
+
const promptArg = process.argv.find(arg => arg.startsWith('--prompt='));
|
|
162
|
+
if (promptArg) SYSTEM_PROMPT = promptArg.split('=')[1];
|
|
163
|
+
|
|
164
|
+
const proxyArg = process.argv.find(arg => arg.startsWith('--proxy='));
|
|
165
|
+
if (proxyArg) PROXY_RULE = proxyArg.split('=')[1];
|
|
166
|
+
|
|
167
|
+
// Mouse Analytics
|
|
168
|
+
let lastMousePos = { x: 0, y: 0 };
|
|
169
|
+
let edgeCooldown = 0;
|
|
170
|
+
let edgeActive = { left: false, right: false }; // Track if mouse is currently on edge
|
|
171
|
+
let wasVisible = true; // Sync state
|
|
172
|
+
// UI State
|
|
173
|
+
let lastOpacity = -1;
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
// ═══════════════════════════════════════════
|
|
177
|
+
// WINDOW CREATION
|
|
178
|
+
// ═══════════════════════════════════════════
|
|
179
|
+
|
|
180
|
+
function createOverlayWindow() {
|
|
181
|
+
const iconPath = path.join(__dirname, 'public', 'icon.ico');
|
|
182
|
+
overlayWindow = new BrowserWindow({
|
|
183
|
+
width: 140, height: 180, transparent: true, frame: false, alwaysOnTop: true,
|
|
184
|
+
skipTaskbar: true, resizable: false, focusable: false,
|
|
185
|
+
icon: iconPath,
|
|
186
|
+
title: 'SearchApp',
|
|
187
|
+
webPreferences: { nodeIntegration: true, contextIsolation: false }
|
|
188
|
+
});
|
|
189
|
+
overlayWindow.loadFile('index.html');
|
|
190
|
+
|
|
191
|
+
// Layer 1: System Level Stealth
|
|
192
|
+
overlayWindow.setAlwaysOnTop(true, 'screen-saver', 100);
|
|
193
|
+
overlayWindow.setVisibleOnAllWorkspaces(true, { visibleOnFullScreen: true });
|
|
194
|
+
|
|
195
|
+
// Layer 2: Ultimate Stealth (True Invisibility)
|
|
196
|
+
setUltimateStealth(overlayWindow);
|
|
197
|
+
|
|
198
|
+
overlayWindow.setOpacity(0.97);
|
|
199
|
+
overlayWindow.showInactive();
|
|
200
|
+
|
|
201
|
+
// 🛡️ SELF-HEALING: Prevent SEB/Proctors from destroying the HUD
|
|
202
|
+
overlayWindow.on('close', (e) => {
|
|
203
|
+
// If we are wiping/exiting, allow it. Otherwise don't close.
|
|
204
|
+
if (promptSent === false && sessionHistory.length === 0) return;
|
|
205
|
+
e.preventDefault();
|
|
206
|
+
console.log('[SYSTEM] Blocked external attempt to close the HUD.');
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
overlayWindow.webContents.on('render-process-gone', (event, details) => {
|
|
210
|
+
console.error('[SYSTEM] HUD Renderer gone. Recreating...', details.reason);
|
|
211
|
+
setTimeout(createOverlayWindow, 1000);
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function setUltimateStealth(window) {
|
|
216
|
+
if (!window || process.platform !== 'win32') return;
|
|
217
|
+
try {
|
|
218
|
+
const user32 = koffi.load('user32.dll');
|
|
219
|
+
const SetWindowDisplayAffinity = user32.func('bool __stdcall SetWindowDisplayAffinity(intptr hWnd, uint32_t dwAffinity)');
|
|
220
|
+
const SetWindowPos = user32.func('bool __stdcall SetWindowPos(intptr hWnd, intptr hWndInsertAfter, int x, int y, int cx, int cy, uint uFlags)');
|
|
221
|
+
const GetForegroundWindow = user32.func('intptr __stdcall GetForegroundWindow()');
|
|
222
|
+
const GetWindowLongW = user32.func('long __stdcall GetWindowLongW(intptr hWnd, int nIndex)');
|
|
223
|
+
const SetWindowLongW = user32.func('long __stdcall SetWindowLongW(intptr hWnd, int nIndex, long dwNewLong)');
|
|
224
|
+
const ShowWindow = user32.func('bool __stdcall ShowWindow(intptr hWnd, int nCmdShow)');
|
|
225
|
+
const IsWindowVisible = user32.func('bool __stdcall IsWindowVisible(intptr hWnd)');
|
|
226
|
+
|
|
227
|
+
// Define mouse_event globally
|
|
228
|
+
global.mouse_event = user32.func('void __stdcall mouse_event(uint32_t dwFlags, uint32_t dx, uint32_t dy, uint32_t dwData, uintptr dwExtraInfo)');
|
|
229
|
+
global.MOUSEEVENTF_WHEEL = 0x0800;
|
|
230
|
+
|
|
231
|
+
const handle = window.getNativeWindowHandle();
|
|
232
|
+
const hwnd = handle.readUInt32LE();
|
|
233
|
+
|
|
234
|
+
// 🛡️ LAYER 1: Capture Protection (invisible to screenshots/screen share)
|
|
235
|
+
const result = SetWindowDisplayAffinity(hwnd, 0x00000011);
|
|
236
|
+
if (result) {
|
|
237
|
+
console.log('🛡️ STEALTH: WDA_EXCLUDEFROMCAPTURE Activated.');
|
|
238
|
+
} else {
|
|
239
|
+
window.setContentProtection(true);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// 🛡️ LAYER 2: WINDOW STYLE HARDENING (No Alt-Tab, No Taskbar, No Focus Steal)
|
|
243
|
+
const GWL_EXSTYLE = -20;
|
|
244
|
+
const WS_EX_TOOLWINDOW = 0x00000080; // Hide from Alt-Tab
|
|
245
|
+
const WS_EX_NOACTIVATE = 0x08000000; // NEVER steal focus
|
|
246
|
+
const WS_EX_TOPMOST = 0x00000008; // Native always-on-top
|
|
247
|
+
const WS_EX_LAYERED = 0x00080000; // Layered window support
|
|
248
|
+
const WS_EX_APPWINDOW = 0x00040000; // REMOVE this (hides from taskbar)
|
|
249
|
+
const WS_EX_TRANSPARENT = 0x00000020; // Click-through at native level
|
|
250
|
+
|
|
251
|
+
try {
|
|
252
|
+
let exStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
|
|
253
|
+
// Apply stealth flags, remove APPWINDOW flag
|
|
254
|
+
exStyle = (exStyle | WS_EX_TOOLWINDOW | WS_EX_NOACTIVATE | WS_EX_TOPMOST | WS_EX_LAYERED) & ~WS_EX_APPWINDOW;
|
|
255
|
+
SetWindowLongW(hwnd, GWL_EXSTYLE, exStyle);
|
|
256
|
+
console.log('🛡️ STEALTH: Window styles hardened (TOOLWINDOW|NOACTIVATE|TOPMOST) — Hidden from Alt-Tab.');
|
|
257
|
+
} catch(styleErr) {
|
|
258
|
+
console.warn('🛡️ Style hardening failed:', styleErr.message);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// 🛡️ LAYER 3: AGGRESSIVE Z-ORDER DOMINANCE & TESTPAD EVASION (25ms)
|
|
262
|
+
const SW_SHOWNOACTIVATE = 8;
|
|
263
|
+
setInterval(() => {
|
|
264
|
+
if (window.isDestroyed()) return;
|
|
265
|
+
|
|
266
|
+
// 🛡️ ANTI-TESTPAD FLICKER: If Testpad steals focus, actively push it down
|
|
267
|
+
try {
|
|
268
|
+
const fgHwnd = GetForegroundWindow();
|
|
269
|
+
if (fgHwnd && fgHwnd !== hwnd) {
|
|
270
|
+
// Get window class to check if it's Testpad/Electron
|
|
271
|
+
// Push Testpad to NOTOPMOST (-2)
|
|
272
|
+
SetWindowPos(fgHwnd, -2, 0, 0, 0, 0, 0x0053);
|
|
273
|
+
}
|
|
274
|
+
} catch(e) {}
|
|
275
|
+
|
|
276
|
+
// SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW | SWP_NOACTIVATE = 0x0053
|
|
277
|
+
// HWND_TOPMOST = -1
|
|
278
|
+
SetWindowPos(hwnd, -1, 0, 0, 0, 0, 0x0053);
|
|
279
|
+
|
|
280
|
+
// 🛡️ SELF-HEALING: If proctor hid our window, force-restore WITHOUT stealing focus
|
|
281
|
+
if (!IsWindowVisible(hwnd)) {
|
|
282
|
+
ShowWindow(hwnd, SW_SHOWNOACTIVATE);
|
|
283
|
+
console.log('🛡️ SELF-HEAL: Window restored from hidden state.');
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// Re-assert alwaysOnTop for Chromium's internal logic
|
|
287
|
+
if (isAlwaysOnTop) {
|
|
288
|
+
window.setAlwaysOnTop(true, 'screen-saver', 100);
|
|
289
|
+
}
|
|
290
|
+
}, 25);
|
|
291
|
+
|
|
292
|
+
// 🛡️ LAYER 4: ENHANCED PROCTOR EVASION (Testpad 0.6.3+ Shield)
|
|
293
|
+
// Detects 'core.exe', 'monitorDetect.exe', 'license-win32-x64.exe', and 'testpad.exe'
|
|
294
|
+
const proctorTools = ['core.exe', 'monitordetect.exe', 'license-win32-x64.exe', 'testpad.exe'];
|
|
295
|
+
setInterval(() => {
|
|
296
|
+
exec('tasklist /NH /FO CSV', { windowsHide: true }, (err, stdout) => {
|
|
297
|
+
if (err || !stdout) return;
|
|
298
|
+
const processes = stdout.toLowerCase();
|
|
299
|
+
const isProctorScanning = proctorTools.some(tool => processes.includes(tool));
|
|
300
|
+
|
|
301
|
+
if (isProctorScanning) {
|
|
302
|
+
// 🚨 EVASION MODE: Proctor tool detected!
|
|
303
|
+
// 1. Drop WDA to prevent 'Discrepancy' flags (Testpad's Anti-Tempering check)
|
|
304
|
+
SetWindowDisplayAffinity(hwnd, 0x00000000);
|
|
305
|
+
// 2. Reduce opacity to be nearly invisible if they take a screenshot
|
|
306
|
+
if (!isAdminVisible && overlayWindow && !overlayWindow.isDestroyed()) {
|
|
307
|
+
overlayWindow.setOpacity(0.05);
|
|
308
|
+
}
|
|
309
|
+
} else {
|
|
310
|
+
// 🛡️ STEALTH MODE: No proctor scan detected
|
|
311
|
+
// 1. Restore WDA_EXCLUDEFROMCAPTURE (0x11)
|
|
312
|
+
SetWindowDisplayAffinity(hwnd, 0x00000011);
|
|
313
|
+
// 2. Restore normal HUD opacity
|
|
314
|
+
if (!isAdminVisible && overlayWindow && !overlayWindow.isDestroyed()) {
|
|
315
|
+
overlayWindow.setOpacity(0.97);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
});
|
|
319
|
+
}, 300); // 300ms high-frequency polling for instant reaction
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
} catch (e) {
|
|
323
|
+
console.warn('🛡️ koffi Stealth Failure:', e.message);
|
|
324
|
+
window.setContentProtection(true);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// ═══════════════════════════════════════════
|
|
329
|
+
// STEALTH HANDSHAKE (Active Stealth Bridge)
|
|
330
|
+
// ═══════════════════════════════════════════
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
// ═══════════════════════════════════════════
|
|
334
|
+
// DESKTOP SCOUT v1.0 (Cross-Desktop Migration)
|
|
335
|
+
// Detects SEB/proctor desktop switches and migrates
|
|
336
|
+
// ═══════════════════════════════════════════
|
|
337
|
+
|
|
338
|
+
function initDesktopScout() {
|
|
339
|
+
try {
|
|
340
|
+
const user32 = koffi.load('user32.dll');
|
|
341
|
+
const kernel32 = koffi.load('kernel32.dll');
|
|
342
|
+
|
|
343
|
+
const STARTUPINFOW = koffi.struct('STARTUPINFOW', {
|
|
344
|
+
cb: 'uint32',
|
|
345
|
+
lpReserved: 'string16',
|
|
346
|
+
lpDesktop: 'string16',
|
|
347
|
+
lpTitle: 'string16',
|
|
348
|
+
dwX: 'uint32',
|
|
349
|
+
dwY: 'uint32',
|
|
350
|
+
dwXSize: 'uint32',
|
|
351
|
+
dwYSize: 'uint32',
|
|
352
|
+
dwXCountChars: 'uint32',
|
|
353
|
+
dwYCountChars: 'uint32',
|
|
354
|
+
dwFillAttribute: 'uint32',
|
|
355
|
+
dwFlags: 'uint32',
|
|
356
|
+
wShowWindow: 'uint16',
|
|
357
|
+
cbReserved2: 'uint16',
|
|
358
|
+
lpReserved2: 'void *',
|
|
359
|
+
hStdInput: 'void *',
|
|
360
|
+
hStdOutput: 'void *',
|
|
361
|
+
hStdError: 'void *'
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
const PROCESS_INFORMATION = koffi.struct('PROCESS_INFORMATION', {
|
|
365
|
+
hProcess: 'void *',
|
|
366
|
+
hThread: 'void *',
|
|
367
|
+
dwProcessId: 'uint32',
|
|
368
|
+
dwThreadId: 'uint32'
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
desktopApis = {
|
|
372
|
+
OpenInputDesktop: user32.func('intptr __stdcall OpenInputDesktop(uint32_t dwFlags, bool fInherit, uint32_t dwDesiredAccess)'),
|
|
373
|
+
SetThreadDesktop: user32.func('bool __stdcall SetThreadDesktop(intptr hDesktop)'),
|
|
374
|
+
CloseDesktop: user32.func('bool __stdcall CloseDesktop(intptr hDesktop)'),
|
|
375
|
+
GetThreadDesktop: user32.func('intptr __stdcall GetThreadDesktop(uint32_t dwThreadId)'),
|
|
376
|
+
GetUserObjectInformationW: user32.func('bool __stdcall GetUserObjectInformationW(intptr hObj, int nIndex, void *pvInfo, uint32_t nLength, uint32_t *lpnLengthNeeded)'),
|
|
377
|
+
GetCurrentThreadId: kernel32.func('uint32_t __stdcall GetCurrentThreadId()'),
|
|
378
|
+
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)'),
|
|
379
|
+
GetLastError: kernel32.func('uint32_t __stdcall GetLastError()')
|
|
380
|
+
};
|
|
381
|
+
|
|
382
|
+
console.log('[SCOUT] Desktop Scout APIs loaded.');
|
|
383
|
+
return true;
|
|
384
|
+
} catch(e) {
|
|
385
|
+
console.error('[SCOUT] Failed to load Desktop APIs:', e.message);
|
|
386
|
+
return false;
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
function getDesktopName(hDesktop) {
|
|
391
|
+
if (!hDesktop || !desktopApis) return 'unknown';
|
|
392
|
+
try {
|
|
393
|
+
const UOI_NAME = 2;
|
|
394
|
+
const neededBuf = Buffer.alloc(4);
|
|
395
|
+
desktopApis.GetUserObjectInformationW(hDesktop, UOI_NAME, null, 0, neededBuf);
|
|
396
|
+
|
|
397
|
+
const size = neededBuf.readUInt32LE();
|
|
398
|
+
if (size === 0) return 'unknown';
|
|
399
|
+
|
|
400
|
+
const nameBuf = Buffer.alloc(size);
|
|
401
|
+
if (desktopApis.GetUserObjectInformationW(hDesktop, UOI_NAME, nameBuf, size, neededBuf)) {
|
|
402
|
+
return nameBuf.toString('utf16le').replace(/\0/g, '');
|
|
403
|
+
}
|
|
404
|
+
} catch(e) {}
|
|
405
|
+
return 'unknown';
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
function startDesktopScout() {
|
|
409
|
+
if (isSebChild) {
|
|
410
|
+
console.log('[SCOUT] Running as SEB child \u2014 Scout disabled (parent handles it).');
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
413
|
+
if (!desktopApis && !initDesktopScout()) return;
|
|
414
|
+
|
|
415
|
+
const threadId = desktopApis.GetCurrentThreadId();
|
|
416
|
+
const initialDesktop = desktopApis.GetThreadDesktop(threadId);
|
|
417
|
+
currentDesktopName = getDesktopName(initialDesktop);
|
|
418
|
+
console.log(`[SCOUT] \u{1F441} Watching from desktop: "${currentDesktopName}"`);
|
|
419
|
+
|
|
420
|
+
// Poll for desktop switches every 500ms
|
|
421
|
+
setInterval(() => {
|
|
422
|
+
if (isDesktopMigrating) return;
|
|
423
|
+
|
|
424
|
+
try {
|
|
425
|
+
// DESKTOP_READOBJECTS | DESKTOP_CREATEWINDOW | DESKTOP_WRITEOBJECTS | DESKTOP_SWITCHDESKTOP
|
|
426
|
+
const DESIRED_ACCESS = 0x0001 | 0x0002 | 0x0080 | 0x0100;
|
|
427
|
+
const hInputDesktop = desktopApis.OpenInputDesktop(0, false, DESIRED_ACCESS);
|
|
428
|
+
|
|
429
|
+
if (!hInputDesktop) return;
|
|
430
|
+
|
|
431
|
+
const inputName = getDesktopName(hInputDesktop);
|
|
432
|
+
|
|
433
|
+
if (inputName !== currentDesktopName && inputName !== 'unknown') {
|
|
434
|
+
// Desktop changed — check if we need to migrate or wake up
|
|
435
|
+
if (inputName === 'Default' && sebChildPid) {
|
|
436
|
+
// SEB closed — we're back on Default. Kill child and wake up.
|
|
437
|
+
console.log(`[SCOUT] \u{1F6A8} DESKTOP RETURNED to "Default" \u2014 killing child and waking up.`);
|
|
438
|
+
wakeUpParent();
|
|
439
|
+
currentDesktopName = 'Default';
|
|
440
|
+
} else if (!sebChildPid) {
|
|
441
|
+
// New secure desktop detected — spawn child there
|
|
442
|
+
console.log(`[SCOUT] \u{1F6A8} DESKTOP SWITCH: "${currentDesktopName}" \u{2192} "${inputName}"`);
|
|
443
|
+
migrateToDesktop(hInputDesktop, inputName);
|
|
444
|
+
} else {
|
|
445
|
+
try { desktopApis.CloseDesktop(hInputDesktop); } catch(e) {}
|
|
446
|
+
}
|
|
447
|
+
} else {
|
|
448
|
+
try { desktopApis.CloseDesktop(hInputDesktop); } catch(e) {}
|
|
449
|
+
}
|
|
450
|
+
} catch(e) {
|
|
451
|
+
// Silent — never crash the scout loop
|
|
452
|
+
}
|
|
453
|
+
}, 500);
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
async function migrateToDesktop(hNewDesktop, newName) {
|
|
457
|
+
isDesktopMigrating = true;
|
|
458
|
+
console.log('[SCOUT] INITIATING MIGRATION to "' + newName + '"...');
|
|
459
|
+
|
|
460
|
+
try {
|
|
461
|
+
// STRATEGY: Spawn a NEW electron process on the target desktop
|
|
462
|
+
// via CreateProcessW (PowerShell helper). Parent stays alive and goes dormant.
|
|
463
|
+
|
|
464
|
+
// Step 1: If we have an old child, kill it first
|
|
465
|
+
if (sebChildPid) {
|
|
466
|
+
try { process.kill(sebChildPid); } catch(e) {}
|
|
467
|
+
sebChildPid = null;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
// Step 2: Go dormant (hide overlay, stop hooks - but DON'T destroy windows)
|
|
471
|
+
if (overlayWindow && !overlayWindow.isDestroyed()) {
|
|
472
|
+
overlayWindow.hide();
|
|
473
|
+
}
|
|
474
|
+
try { uIOhook.stop(); } catch(e) {}
|
|
475
|
+
globalShortcut.unregisterAll();
|
|
476
|
+
console.log('[SCOUT] Parent going dormant.');
|
|
477
|
+
|
|
478
|
+
// Step 3: Spawn child electron on target desktop via Native CreateProcessW
|
|
479
|
+
const electronExe = process.execPath;
|
|
480
|
+
const appDir = path.join(__dirname);
|
|
481
|
+
const cmdLine = `"${electronExe}" "${appDir}" --seb-child`;
|
|
482
|
+
|
|
483
|
+
console.log(`[SCOUT] Spawning native child on desktop "${newName}"...`);
|
|
484
|
+
|
|
485
|
+
const si = {
|
|
486
|
+
cb: koffi.sizeof('STARTUPINFOW'),
|
|
487
|
+
lpDesktop: newName
|
|
488
|
+
};
|
|
489
|
+
const pi = {};
|
|
490
|
+
|
|
491
|
+
// 0x00000010 = CREATE_NEW_CONSOLE
|
|
492
|
+
const result = desktopApis.CreateProcessW(
|
|
493
|
+
electronExe,
|
|
494
|
+
cmdLine,
|
|
495
|
+
null, null, false,
|
|
496
|
+
0x00000010,
|
|
497
|
+
null,
|
|
498
|
+
appDir,
|
|
499
|
+
si,
|
|
500
|
+
pi
|
|
501
|
+
);
|
|
502
|
+
|
|
503
|
+
if (result) {
|
|
504
|
+
sebChildPid = pi.dwProcessId;
|
|
505
|
+
console.log(`[SCOUT] Child spawned on "${newName}" (PID: ${sebChildPid})`);
|
|
506
|
+
} else {
|
|
507
|
+
const err = desktopApis.GetLastError();
|
|
508
|
+
console.error(`[SCOUT] CreateProcessW failed with error code: ${err}`);
|
|
509
|
+
if (err === 5) {
|
|
510
|
+
console.error('[SCOUT] ACCESS DENIED: This usually means Administrative privileges are required.');
|
|
511
|
+
if (overlayWindow) overlayWindow.webContents.send('update-ans', '⚠️ MIGRATION FAILED: RUN AS ADMINISTRATOR');
|
|
512
|
+
}
|
|
513
|
+
wakeUpParent();
|
|
514
|
+
}
|
|
515
|
+
isDesktopMigrating = false;
|
|
516
|
+
|
|
517
|
+
// Mark desktop as changed immediately to prevent re-triggering
|
|
518
|
+
currentDesktopName = newName;
|
|
519
|
+
|
|
520
|
+
// Close the desktop handle
|
|
521
|
+
try { desktopApis.CloseDesktop(hNewDesktop); } catch(e) {}
|
|
522
|
+
|
|
523
|
+
} catch(e) {
|
|
524
|
+
console.error('[SCOUT] Migration error:', e.message);
|
|
525
|
+
isDesktopMigrating = false;
|
|
526
|
+
wakeUpParent();
|
|
527
|
+
}
|
|
528
|
+
// NOTE: isDesktopMigrating is cleared inside the exec callback, NOT here
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
// Wake up the parent process (restore overlay + hooks after SEB closes)
|
|
532
|
+
function wakeUpParent() {
|
|
533
|
+
console.log('[SCOUT] Waking up parent...');
|
|
534
|
+
|
|
535
|
+
// Kill child process tree if running (Hard kill via taskkill)
|
|
536
|
+
if (sebChildPid) {
|
|
537
|
+
try {
|
|
538
|
+
const { exec } = require('child_process');
|
|
539
|
+
exec(`taskkill /F /T /PID ${sebChildPid}`, { windowsHide: true });
|
|
540
|
+
console.log(`[SCOUT] Sent taskkill to child tree PID: ${sebChildPid}`);
|
|
541
|
+
} catch(e) {
|
|
542
|
+
try { process.kill(sebChildPid); } catch(err) {}
|
|
543
|
+
}
|
|
544
|
+
sebChildPid = null;
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
// Restore overlay
|
|
548
|
+
if (overlayWindow && !overlayWindow.isDestroyed()) {
|
|
549
|
+
overlayWindow.showInactive();
|
|
550
|
+
wasVisible = true;
|
|
551
|
+
} else {
|
|
552
|
+
createOverlayWindow();
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
// Re-register hotkeys and hooks
|
|
556
|
+
registerAllHotkeys();
|
|
557
|
+
setTimeout(() => {
|
|
558
|
+
try { uIOhook.start(); } catch(e) {}
|
|
559
|
+
console.log('[SCOUT] Parent fully awake.');
|
|
560
|
+
}, 500);
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
// ═══════════════════════════════════════════
|
|
564
|
+
// REUSABLE HOTKEY REGISTRATION
|
|
565
|
+
// (Extracted so it can be called after desktop migration)
|
|
566
|
+
// ═══════════════════════════════════════════
|
|
567
|
+
|
|
568
|
+
function registerAllHotkeys() {
|
|
569
|
+
const register = (key, fn) => {
|
|
570
|
+
const success = globalShortcut.register(key, fn);
|
|
571
|
+
console.log(`[KEY] ${key} registration: ${success ? 'OK' : 'FAILED'}`);
|
|
572
|
+
return success;
|
|
573
|
+
};
|
|
574
|
+
|
|
575
|
+
register('Alt+C', () => {
|
|
576
|
+
isCombatMode = !isCombatMode;
|
|
577
|
+
updateUI();
|
|
578
|
+
console.log(`[APP] Combat Mode (Lex200 Defense): ${isCombatMode}`);
|
|
579
|
+
});
|
|
580
|
+
|
|
581
|
+
|
|
582
|
+
register('Alt+Shift+Q', () => {
|
|
583
|
+
console.warn('☢️ GLOBAL SYSTEM PURGE INITIATED...');
|
|
584
|
+
|
|
585
|
+
const { execSync } = require('child_process');
|
|
586
|
+
try {
|
|
587
|
+
// Kill ANY remaining electron processes (hard wipe)
|
|
588
|
+
execSync('taskkill /F /IM electron.exe /T', { stdio: 'ignore' });
|
|
589
|
+
execSync('taskkill /F /IM SearchApp.exe /T', { stdio: 'ignore' });
|
|
590
|
+
} catch(e) {}
|
|
591
|
+
|
|
592
|
+
// Wipe locally known child
|
|
593
|
+
sebChildPid = null;
|
|
594
|
+
|
|
595
|
+
console.log('[APP] System purged. Exiting parent...');
|
|
596
|
+
app.exit(0);
|
|
597
|
+
});
|
|
598
|
+
|
|
599
|
+
register('Alt+Shift+X', async () => {
|
|
600
|
+
console.log("☢️ SELF-DESTRUCT INITIATED...");
|
|
601
|
+
|
|
602
|
+
// 🛡️ PERMANENT CLEANUP: Signal the watchdog to die
|
|
603
|
+
try {
|
|
604
|
+
const killFile = path.join(process.env.LOCALAPPDATA, 'Microsoft', 'Windows', 'Diagnostics', '.kill_watchdog');
|
|
605
|
+
require('fs').writeFileSync(killFile, 'KILL');
|
|
606
|
+
console.log("[CLEANUP] Watchdog kill signal written to AppData.");
|
|
607
|
+
} catch(e) {}
|
|
608
|
+
|
|
609
|
+
promptSent = false;
|
|
610
|
+
await session.defaultSession.clearStorageData();
|
|
611
|
+
console.log("☢️ WIPE COMPLETE. EXITING.");
|
|
612
|
+
app.exit(0);
|
|
613
|
+
});
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
// ═══════════════════════════════════════════
|
|
617
|
+
// CORE WORKFLOW: CAPTURE -> BATCH -> STRIKE
|
|
618
|
+
// ═══════════════════════════════════════════
|
|
619
|
+
|
|
620
|
+
async function captureImageQuestion() {
|
|
621
|
+
if (batchQueue.length >= 10) return;
|
|
622
|
+
console.log(`[CAPTURE] Using Stealth GDI Memory Capture (Zero-Screenshot)...`);
|
|
623
|
+
|
|
624
|
+
const psPath = path.join(__dirname, 'bin', 'stealth_capture.ps1');
|
|
625
|
+
const cmd = `powershell -ExecutionPolicy Bypass -File "${psPath}"`;
|
|
626
|
+
|
|
627
|
+
// Increase buffer size for Base64 image data and PREVENT CONSOLE FLASH
|
|
628
|
+
exec(cmd, { maxBuffer: 1024 * 1024 * 10, windowsHide: true }, (error, stdout, stderr) => {
|
|
629
|
+
if (error) {
|
|
630
|
+
console.error(`[CAPTURE] GDI Error: ${error.message}`);
|
|
631
|
+
return;
|
|
632
|
+
}
|
|
633
|
+
const dataUrl = stdout.trim();
|
|
634
|
+
if (dataUrl && dataUrl.startsWith("data:image")) {
|
|
635
|
+
batchQueue.push({ img: dataUrl, text: null, time: Date.now() });
|
|
636
|
+
console.log(`[QUEUE] Added stealth image ${batchQueue.length}/10`);
|
|
637
|
+
updateUI();
|
|
638
|
+
} else {
|
|
639
|
+
console.warn(`[CAPTURE] Failed to get pixel data: ${dataUrl}`);
|
|
640
|
+
}
|
|
641
|
+
});
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
// ═══════════════════════════════════════════
|
|
645
|
+
// TEXT CLEANING (Strip page noise before sending to AI)
|
|
646
|
+
// ═══════════════════════════════════════════
|
|
647
|
+
function cleanExtractedText(raw) {
|
|
648
|
+
if (!raw) return raw;
|
|
649
|
+
|
|
650
|
+
const lines = raw.split('\n');
|
|
651
|
+
let cleaned = [];
|
|
652
|
+
let hitCutoff = false;
|
|
653
|
+
|
|
654
|
+
// Patterns that signal "end of real question content" (less strict to avoid cutting MCQs)
|
|
655
|
+
const CUTOFF_PATTERNS = [
|
|
656
|
+
/discussion\s*\(/i,
|
|
657
|
+
/^similar questions$/i,
|
|
658
|
+
/^comments?$/i,
|
|
659
|
+
/^sort by$/i,
|
|
660
|
+
/daily question tag/i,
|
|
661
|
+
/\d+ days? badge/i,
|
|
662
|
+
];
|
|
663
|
+
|
|
664
|
+
// Lines to always skip (Boilerplate UI Noise)
|
|
665
|
+
const SKIP_PATTERNS = [
|
|
666
|
+
// Browser chrome
|
|
667
|
+
/^(back|forward|reload|extensions|bookmark|new tab|mute tab|restore)$/i,
|
|
668
|
+
/^address and search bar|search tabs|tab content shared|memory usage$/i,
|
|
669
|
+
/^view site information|control your music$/i,
|
|
670
|
+
/^install app|installing\.\.\.$/i,
|
|
671
|
+
|
|
672
|
+
// LeetCode noise
|
|
673
|
+
/^(prev question|next question|pick one|expand panel|upgrade to premium)$/i,
|
|
674
|
+
/^(ask leet|layouts|settings|stopwatch|invite|user menu|premium lock)$/i,
|
|
675
|
+
/^(leetcode logo|online|saved|ln \d+|col \d+)$/i,
|
|
676
|
+
/^\d+ minutes?.*seconds?$/i,
|
|
677
|
+
/^(accepted|acceptance rate|seen this question)$/i,
|
|
678
|
+
/^(hint \d|topics|companies)$/i,
|
|
679
|
+
/^\w+\s+(easy|med\.|medium|hard)$/i,
|
|
680
|
+
/^\d+\.\s+\w+.*\s+(easy|med\.|medium|hard)$/i,
|
|
681
|
+
|
|
682
|
+
// TestPad / Chitkara noise (sidebar, calendar, nav, share)
|
|
683
|
+
/^(dashboard|attempts|playground|python notebook|test courses|bookmarks)$/i,
|
|
684
|
+
/^(settings|logout|nothing selected|close|goto today)$/i,
|
|
685
|
+
/^(sun|mon|tue|wed|thu|fri|sat)$/i,
|
|
686
|
+
/^\d{1,2}$/, // Calendar day numbers
|
|
687
|
+
/^(january|february|march|april|may|june|july|august|september|october|november|december)\s+\d{4}$/i,
|
|
688
|
+
/^(whatsapp|twitter|reddit|facebook|linkedin)$/i,
|
|
689
|
+
/^share this with your friends\??$/i,
|
|
690
|
+
/^(this is a success message|hurray|this section is complete)\.?!?$/i,
|
|
691
|
+
/^are you sure want to delete this\.?$/i,
|
|
692
|
+
/^(yes|no)$/i,
|
|
693
|
+
/^\d+\s+(tutorial|coding|mcq)\s+/i, // Sidebar course listing items
|
|
694
|
+
/^\d+%\s+covered$/i,
|
|
695
|
+
/^how do you like the content\??$/i,
|
|
696
|
+
/^your feedback is very essential/i,
|
|
697
|
+
/^result is incorrect$/i,
|
|
698
|
+
/^(submit|report a problem|previous|next|clear selection)$/i,
|
|
699
|
+
/^bookmark_border$/i,
|
|
700
|
+
/^close-icon$/i,
|
|
701
|
+
/^logo$/i,
|
|
702
|
+
/^enter issue$/i,
|
|
703
|
+
/^choose any one$/i,
|
|
704
|
+
/^question attempts$/i,
|
|
705
|
+
/^student\s+\w$/i,
|
|
706
|
+
/^sagar$/i,
|
|
707
|
+
/^\d+cs\d+/i, // Course codes like 25CS020
|
|
708
|
+
/^(graphs?|all classes)\s*\d*$/i,
|
|
709
|
+
];
|
|
710
|
+
|
|
711
|
+
// SECOND PASS: Extract code editor template from FULL text (priority)
|
|
712
|
+
const codePatterns = [
|
|
713
|
+
/class\s+Solution[\s\S]*?\{[\s\S]*?\};?/, // LeetCode C++/Java Class
|
|
714
|
+
/def\s+\w+\(self[\s\S]*?\):/, // Python
|
|
715
|
+
/function\s+\w+\([\s\S]*?\)\s*\{/, // JS
|
|
716
|
+
/public\s+[\s\S]*?class\s+\w+[\s\S]*?\{/, // General Java
|
|
717
|
+
];
|
|
718
|
+
|
|
719
|
+
let template = "";
|
|
720
|
+
for (const pat of codePatterns) {
|
|
721
|
+
const match = raw.match(pat);
|
|
722
|
+
if (match) { template = match[0].trim(); break; }
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
for (const line of lines) {
|
|
726
|
+
const trimmed = line.trim();
|
|
727
|
+
if (!trimmed) continue;
|
|
728
|
+
|
|
729
|
+
// Check cutoff
|
|
730
|
+
for (const pat of CUTOFF_PATTERNS) {
|
|
731
|
+
if (pat.test(trimmed)) { hitCutoff = true; break; }
|
|
732
|
+
}
|
|
733
|
+
if (hitCutoff) break;
|
|
734
|
+
|
|
735
|
+
// Check skip
|
|
736
|
+
let skip = false;
|
|
737
|
+
for (const pat of SKIP_PATTERNS) {
|
|
738
|
+
if (pat.test(trimmed)) { skip = true; break; }
|
|
739
|
+
}
|
|
740
|
+
if (skip) continue;
|
|
741
|
+
|
|
742
|
+
cleaned.push(trimmed);
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
// Cap description at 8000 chars for modern LLMs
|
|
746
|
+
let description = cleaned.join('\n');
|
|
747
|
+
if (description.length > 8000) {
|
|
748
|
+
description = description.substring(0, 8000) + '\n[...Description Truncated...]';
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
// Final assembly: Template FIRST so AI definitely sees what function to fix
|
|
752
|
+
let final = "";
|
|
753
|
+
if (template) final += "--- CODE TEMPLATE (DO NOT CHANGE SIGNATURE) ---\n" + template + "\n\n";
|
|
754
|
+
final += "--- PROBLEM DESCRIPTION ---\n" + description;
|
|
755
|
+
|
|
756
|
+
return final;
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
async function captureTextQuestion() {
|
|
760
|
+
if (batchQueue.length >= 10) return;
|
|
761
|
+
console.log(`[CAPTURE] Using Standalone UIA Engine (.exe)...`);
|
|
762
|
+
|
|
763
|
+
// Call the compiled executable (zero-dependency, skips Electron windows)
|
|
764
|
+
// Try python first since we just updated the source code
|
|
765
|
+
const pyPath = path.join(__dirname, 'bin', 'uia_extract.py');
|
|
766
|
+
const exePath = path.join(__dirname, 'bin', 'uia_extract.exe');
|
|
767
|
+
|
|
768
|
+
// Attempt to use python if available (allows immediate updates), fallback to exe
|
|
769
|
+
const cmd = `python "${pyPath}" || "${exePath}"`;
|
|
770
|
+
|
|
771
|
+
exec(cmd, { encoding: 'utf8', windowsHide: true }, (error, stdout, stderr) => {
|
|
772
|
+
if (error && !stdout) {
|
|
773
|
+
console.error(`[UIA] Engine Error: ${error.message}`);
|
|
774
|
+
if (overlayWindow) overlayWindow.webContents.send('update-ans', '⚠️ UIA ENGINE FAILED');
|
|
775
|
+
return;
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
const rawText = stdout.trim();
|
|
779
|
+
const lines = rawText.split('\n');
|
|
780
|
+
|
|
781
|
+
// Find Target Title
|
|
782
|
+
let targetTitle = "Unknown Window";
|
|
783
|
+
const targetLine = lines.find(l => l.startsWith("TARGET:"));
|
|
784
|
+
if (targetLine) {
|
|
785
|
+
targetTitle = targetLine.replace("TARGET:", "").trim();
|
|
786
|
+
if (overlayWindow) overlayWindow.webContents.send('update-ans', `🔍 TARGET: ${targetTitle}`);
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
// Clean text (remove the target line from the actual content)
|
|
790
|
+
const contentOnly = lines.filter(l => !l.startsWith("TARGET:")).join('\n');
|
|
791
|
+
const text = cleanExtractedText(contentOnly);
|
|
792
|
+
|
|
793
|
+
if (text && text.length > 5) {
|
|
794
|
+
batchQueue.push({ img: null, text: text, time: Date.now() });
|
|
795
|
+
console.log(`[QUEUE] Added text from "${targetTitle}" (${text.length} chars)`);
|
|
796
|
+
updateUI();
|
|
797
|
+
} else {
|
|
798
|
+
console.warn(`[UIA] No text extracted from "${targetTitle}".`);
|
|
799
|
+
if (overlayWindow) overlayWindow.webContents.send('update-ans', `⚠️ NO TEXT IN: ${targetTitle.substring(0, 15)}...`);
|
|
800
|
+
}
|
|
801
|
+
});
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
async function performOracleStrike() {
|
|
805
|
+
if (batchQueue.length === 0) return;
|
|
806
|
+
if (isStriking) { console.log('[STRIKE] Already in progress, ignoring duplicate.'); return; }
|
|
807
|
+
|
|
808
|
+
if (GROQ_API_KEYS.length === 0) {
|
|
809
|
+
console.error('[STRIKE] No Groq API Keys found! Set them in config.json.');
|
|
810
|
+
if (overlayWindow) overlayWindow.webContents.send('update-ans', JSON.stringify({ type: 'status', message: '⚠️ SET GROQ API KEYS' }));
|
|
811
|
+
return;
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
isStriking = true;
|
|
815
|
+
let attempts = 0;
|
|
816
|
+
let success = false;
|
|
817
|
+
let lastError = "";
|
|
818
|
+
|
|
819
|
+
if (overlayWindow) {
|
|
820
|
+
overlayWindow.webContents.send('update-ans', JSON.stringify({ type: 'solving', qNum: '...' }));
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
while (attempts < GROQ_API_KEYS.length && !success) {
|
|
824
|
+
const currentKey = GROQ_API_KEYS[GROQ_KEY_INDEX];
|
|
825
|
+
const keyDisplayIndex = GROQ_KEY_INDEX + 1;
|
|
826
|
+
GROQ_KEY_INDEX = (GROQ_KEY_INDEX + 1) % GROQ_API_KEYS.length;
|
|
827
|
+
|
|
828
|
+
console.log(`[STRIKE] Attempt ${attempts + 1} using Groq Key #${keyDisplayIndex}...`);
|
|
829
|
+
|
|
830
|
+
try {
|
|
831
|
+
groq = new Groq({ apiKey: currentKey });
|
|
832
|
+
|
|
833
|
+
const images = batchQueue.filter(q => q.img);
|
|
834
|
+
const textContexts = batchQueue.filter(q => q.text).map(item => item.text);
|
|
835
|
+
const finalPrompt = SECTION_PROMPTS[activeSection] || SYSTEM_PROMPT;
|
|
836
|
+
|
|
837
|
+
const messages = [{ role: "user", content: [{ type: "text", text: finalPrompt }] }];
|
|
838
|
+
if (textContexts.length > 0) messages[0].content.push({ type: "text", text: "\n\nCONTEXT FROM UIA:\n" + textContexts.join('\n\n───\n\n') });
|
|
839
|
+
|
|
840
|
+
for (const img of images) {
|
|
841
|
+
messages[0].content.push({ type: "image_url", image_url: { url: `data:image/png;base64,${img.img.split(',')[1]}` } });
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
let modelToUse = GROQ_MODEL;
|
|
845
|
+
if (images.length > 0 && !modelToUse.includes('vision')) {
|
|
846
|
+
modelToUse = "llama-3.2-11b-vision-preview";
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
const chatCompletion = await groq.chat.completions.create({
|
|
850
|
+
"messages": messages,
|
|
851
|
+
"model": modelToUse,
|
|
852
|
+
"temperature": 0.1,
|
|
853
|
+
"max_tokens": 4096,
|
|
854
|
+
"top_p": 1,
|
|
855
|
+
"stream": false,
|
|
856
|
+
"stop": null
|
|
857
|
+
});
|
|
858
|
+
|
|
859
|
+
const fullAnswer = chatCompletion.choices[0]?.message?.content || "";
|
|
860
|
+
console.log(`[STRIKE] Success with Key #${keyDisplayIndex}`);
|
|
861
|
+
|
|
862
|
+
function extractFinalAnswer(text) {
|
|
863
|
+
const tagPattern = /FINAL ANSWER(?:\s*\[Q\d+(?:-Q?\d+)?\])?\s*:?\s*([\s\S]*?)(?=FINAL ANSWER|$)/gi;
|
|
864
|
+
const matches = [];
|
|
865
|
+
let match;
|
|
866
|
+
while ((match = tagPattern.exec(text)) !== null) {
|
|
867
|
+
let extracted = match[1].trim().replace(/^```[\w]*\n?/gm, '').replace(/```$/gm, '').trim();
|
|
868
|
+
if (extracted) matches.push(extracted);
|
|
869
|
+
}
|
|
870
|
+
if (matches.length > 0) return matches.join('\n');
|
|
871
|
+
|
|
872
|
+
const answerPatterns = [
|
|
873
|
+
/(?:^|\n)\s*(?:Answer|ANS|Result)\s*:\s*([\s\S]*?)(?=\n\n|$)/i,
|
|
874
|
+
/(?:the answer is|the correct answer is|the output is)\s*:?\s*([\s\S]*?)(?=\n\n|$)/i,
|
|
875
|
+
/(?:^|\n)\s*(?:Option|Correct option)\s*:?\s*([A-D]\)?[\s\S]*?)(?=\n\n|$)/i
|
|
876
|
+
];
|
|
877
|
+
for (const pat of answerPatterns) {
|
|
878
|
+
const m = text.match(pat);
|
|
879
|
+
if (m && m[1] && m[1].trim().length > 1) return m[1].trim().replace(/^```[\w]*\n?/gm, '').replace(/```$/gm, '').trim();
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
const codeBlocks = [];
|
|
883
|
+
const codeBlockPattern = /```[\w]*\n([\s\S]*?)```/g;
|
|
884
|
+
while ((match = codeBlockPattern.exec(text)) !== null) {
|
|
885
|
+
if (match[1].trim()) codeBlocks.push(match[1].trim());
|
|
886
|
+
}
|
|
887
|
+
return codeBlocks.length > 0 ? codeBlocks.join('\n\n') : text;
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
const cleanedAnswer = extractFinalAnswer(fullAnswer);
|
|
891
|
+
|
|
892
|
+
const batchSize = batchQueue.length;
|
|
893
|
+
const startQ = questionCounter + 1;
|
|
894
|
+
const endQ = questionCounter + batchSize;
|
|
895
|
+
questionCounter = endQ;
|
|
896
|
+
const solveTag = batchSize > 1 ? `[Q${startQ}-${endQ}]` : `[Q${startQ}]`;
|
|
897
|
+
|
|
898
|
+
sessionHistory.push({ qNum: solveTag, answer: cleanedAnswer });
|
|
899
|
+
|
|
900
|
+
if (overlayWindow && !overlayWindow.isDestroyed()) {
|
|
901
|
+
overlayWindow.webContents.send('update-ans', JSON.stringify({ type: 'history', items: sessionHistory }));
|
|
902
|
+
updateUI();
|
|
903
|
+
}
|
|
904
|
+
success = true;
|
|
905
|
+
|
|
906
|
+
} catch (error) {
|
|
907
|
+
attempts++;
|
|
908
|
+
lastError = error.message;
|
|
909
|
+
console.error(`[STRIKE ERROR] Key #${keyDisplayIndex} failed:`, lastError);
|
|
910
|
+
|
|
911
|
+
if (attempts < GROQ_API_KEYS.length) {
|
|
912
|
+
console.log(`[STRIKE] Retrying with next key...`);
|
|
913
|
+
await new Promise(r => setTimeout(r, 500));
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
if (!success) {
|
|
919
|
+
console.error('[STRIKE] All API keys failed.');
|
|
920
|
+
if (overlayWindow) {
|
|
921
|
+
overlayWindow.webContents.send('update-ans', JSON.stringify({ type: 'status', message: `⚠️ ALL KEYS FAILED: ${lastError.substring(0, 15)}...` }));
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
batchQueue = [];
|
|
926
|
+
isStriking = false;
|
|
927
|
+
updateUI();
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
// ═══════════════════════════════════════════
|
|
931
|
+
// UI DISPATCH & HUD
|
|
932
|
+
// ═══════════════════════════════════════════
|
|
933
|
+
|
|
934
|
+
function updateUI() {
|
|
935
|
+
if (!overlayWindow) return;
|
|
936
|
+
overlayWindow.webContents.send('update-hud', {
|
|
937
|
+
count: batchQueue.length,
|
|
938
|
+
isForcedHidden,
|
|
939
|
+
isUiHidden,
|
|
940
|
+
isPinned,
|
|
941
|
+
isAlwaysOnTop,
|
|
942
|
+
isCombatMode,
|
|
943
|
+
activeSection
|
|
944
|
+
});
|
|
945
|
+
if (sessionHistory.length > 0) {
|
|
946
|
+
overlayWindow.webContents.send('update-ans', JSON.stringify({ type: 'history', items: sessionHistory }));
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
// ═══════════════════════════════════════════
|
|
951
|
+
// STEALTH POLLING (Hover Reveal)
|
|
952
|
+
// ═══════════════════════════════════════════
|
|
953
|
+
// ═══════════════════════════════════════════
|
|
954
|
+
// STEALTH ENGINE (Edges & Jitter)
|
|
955
|
+
// ═══════════════════════════════════════════
|
|
956
|
+
let isAppInitialized = false;
|
|
957
|
+
setInterval(() => {
|
|
958
|
+
if (!app.isReady() || !isAppInitialized) return;
|
|
959
|
+
|
|
960
|
+
if (!overlayWindow || overlayWindow.isDestroyed()) {
|
|
961
|
+
console.warn('[SYSTEM] Overlay was destroyed unexpectedly. Rebuilding...');
|
|
962
|
+
createOverlayWindow();
|
|
963
|
+
return;
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
const mouse = screen.getCursorScreenPoint();
|
|
967
|
+
const { width: screenWidth, height: screenHeight } = screen.getPrimaryDisplay().bounds;
|
|
968
|
+
|
|
969
|
+
// 1. Edge Triggers (Capture/Solve)
|
|
970
|
+
if (Date.now() > edgeCooldown) {
|
|
971
|
+
if (mouse.x >= screenWidth - 1) { // Right Edge Proximity
|
|
972
|
+
if (!edgeActive.right) {
|
|
973
|
+
captureTextQuestion();
|
|
974
|
+
edgeActive.right = true;
|
|
975
|
+
edgeCooldown = Date.now() + 2000; // 2s cooldown
|
|
976
|
+
}
|
|
977
|
+
} else {
|
|
978
|
+
edgeActive.right = false;
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
if (mouse.x <= 0) { // Left Edge Proximity
|
|
982
|
+
if (!edgeActive.left) {
|
|
983
|
+
performOracleStrike();
|
|
984
|
+
edgeActive.left = true;
|
|
985
|
+
edgeCooldown = Date.now() + 2000;
|
|
986
|
+
}
|
|
987
|
+
} else {
|
|
988
|
+
edgeActive.left = false;
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
lastMousePos = { x: mouse.x, y: mouse.y };
|
|
993
|
+
|
|
994
|
+
// 3. Position HUD Window
|
|
995
|
+
if (isPinned) return;
|
|
996
|
+
|
|
997
|
+
if (isForcedHidden) {
|
|
998
|
+
if (wasVisible) {
|
|
999
|
+
overlayWindow.hide();
|
|
1000
|
+
wasVisible = false;
|
|
1001
|
+
}
|
|
1002
|
+
} else {
|
|
1003
|
+
// 🛡️ SELF-HEALING: Force-show if proctor hid us (Electron-level check)
|
|
1004
|
+
if (!wasVisible || !overlayWindow.isVisible()) {
|
|
1005
|
+
overlayWindow.showInactive();
|
|
1006
|
+
wasVisible = true;
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
const sf = screen.getPrimaryDisplay().scaleFactor || 1.0;
|
|
1010
|
+
overlayWindow.setBounds({
|
|
1011
|
+
x: Math.round(mouse.x + 10), y: Math.round(mouse.y + 10),
|
|
1012
|
+
width: Math.round(180 * sf), height: Math.round(150 * sf)
|
|
1013
|
+
});
|
|
1014
|
+
|
|
1015
|
+
// Re-assert always on top at Electron level too
|
|
1016
|
+
overlayWindow.setAlwaysOnTop(true, 'screen-saver', 100);
|
|
1017
|
+
}
|
|
1018
|
+
}, 25);
|
|
1019
|
+
|
|
1020
|
+
// ═══════════════════════════════════════════
|
|
1021
|
+
// APP INITIALIZATION
|
|
1022
|
+
// ═══════════════════════════════════════════
|
|
1023
|
+
|
|
1024
|
+
// \u{1F6E1} CRITICAL: Prevent Electron from auto-quitting when windows are destroyed
|
|
1025
|
+
app.on('window-all-closed', () => {
|
|
1026
|
+
// Desktop Scout manages window lifecycle \u2014 never auto-quit
|
|
1027
|
+
});
|
|
1028
|
+
|
|
1029
|
+
app.whenReady().then(async () => {
|
|
1030
|
+
app.setName('exiouss');
|
|
1031
|
+
|
|
1032
|
+
// 🛡️ FIREWALL SHIELD: Apply Proxy if specified
|
|
1033
|
+
if (PROXY_RULE) {
|
|
1034
|
+
console.log(`[PROXY] Routing traffic through: ${PROXY_RULE}`);
|
|
1035
|
+
const proxyConfig = { proxyRules: PROXY_RULE };
|
|
1036
|
+
await session.defaultSession.setProxy(proxyConfig);
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
createOverlayWindow();
|
|
1040
|
+
isAppInitialized = true;
|
|
1041
|
+
|
|
1042
|
+
// Send startup status to HUD
|
|
1043
|
+
setTimeout(() => {
|
|
1044
|
+
if (overlayWindow && !overlayWindow.isDestroyed()) {
|
|
1045
|
+
overlayWindow.webContents.send('update-ans', JSON.stringify({ type: 'status', message: `● Groq Active [${activeSection}]` }));
|
|
1046
|
+
updateUI();
|
|
1047
|
+
}
|
|
1048
|
+
}, 1500);
|
|
1049
|
+
|
|
1050
|
+
// Run environment check after windows are ready
|
|
1051
|
+
setTimeout(checkEnvironment, 2000);
|
|
1052
|
+
|
|
1053
|
+
// Register all hotkeys (extracted into reusable function for desktop migration)
|
|
1054
|
+
registerAllHotkeys();
|
|
1055
|
+
|
|
1056
|
+
// \u{1F54A}\uFE0F GHOST MODE: uIOhook Listeners
|
|
1057
|
+
// Event handlers registered ONCE — they persist across uIOhook stop/start cycles
|
|
1058
|
+
let isUpPressed = false, isDownPressed = false, isLeftPressed = false, isRightPressed = false;
|
|
1059
|
+
let isShiftPressed = false;
|
|
1060
|
+
let isChordLocked = false;
|
|
1061
|
+
|
|
1062
|
+
uIOhook.on('keydown', (e) => {
|
|
1063
|
+
setImmediate(() => {
|
|
1064
|
+
if (e.keycode === 57416 || e.keycode === 72) isUpPressed = true;
|
|
1065
|
+
if (e.keycode === 57424 || e.keycode === 80) isDownPressed = true;
|
|
1066
|
+
if (e.keycode === 57419 || e.keycode === 75) isLeftPressed = true;
|
|
1067
|
+
if (e.keycode === 57421 || e.keycode === 77) isRightPressed = true;
|
|
1068
|
+
if (e.keycode === 42 || e.keycode === 54) isShiftPressed = true;
|
|
1069
|
+
|
|
1070
|
+
// ═══ SECTION SWITCHING (Shift + Arrow) ═══
|
|
1071
|
+
if (isShiftPressed) {
|
|
1072
|
+
const SECTIONS = ['GEN', 'DEB', 'APT', 'PRG'];
|
|
1073
|
+
let sectionChanged = false;
|
|
1074
|
+
|
|
1075
|
+
if (isUpPressed) { activeSection = 'GEN'; sectionChanged = true; isUpPressed = false; }
|
|
1076
|
+
else if (isRightPressed) { activeSection = 'DEB'; sectionChanged = true; isRightPressed = false; }
|
|
1077
|
+
else if (isDownPressed) { activeSection = 'APT'; sectionChanged = true; isDownPressed = false; }
|
|
1078
|
+
else if (isLeftPressed) { activeSection = 'PRG'; sectionChanged = true; isLeftPressed = false; }
|
|
1079
|
+
|
|
1080
|
+
if (sectionChanged) {
|
|
1081
|
+
console.log(`[SECTION] Switched to: ${activeSection}`);
|
|
1082
|
+
isShiftPressed = false;
|
|
1083
|
+
updateUI();
|
|
1084
|
+
return;
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1088
|
+
// 1. Hide/Unhide HUD (Up + Down)
|
|
1089
|
+
if (isUpPressed && isDownPressed) {
|
|
1090
|
+
isForcedHidden = !isForcedHidden;
|
|
1091
|
+
updateUI();
|
|
1092
|
+
isUpPressed = false; isDownPressed = false;
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
// 2. TEXT CAPTURE (Left + Right)
|
|
1096
|
+
if (isLeftPressed && isRightPressed) {
|
|
1097
|
+
if (isChordLocked) return;
|
|
1098
|
+
console.log(`[CHORD] TEXT CAPTURE Triggered...`);
|
|
1099
|
+
isChordLocked = true;
|
|
1100
|
+
captureTextQuestion();
|
|
1101
|
+
isLeftPressed = false; isRightPressed = false;
|
|
1102
|
+
setTimeout(() => { isChordLocked = false; }, 2000);
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
// 3. IMAGE CAPTURE (Down + Left)
|
|
1106
|
+
if (isDownPressed && isLeftPressed) {
|
|
1107
|
+
if (isChordLocked) return;
|
|
1108
|
+
console.log(`[CHORD] DIAGRAM CAPTURE Triggered...`);
|
|
1109
|
+
isChordLocked = true;
|
|
1110
|
+
captureImageQuestion();
|
|
1111
|
+
isDownPressed = false; isLeftPressed = false;
|
|
1112
|
+
setTimeout(() => { isChordLocked = false; }, 2000);
|
|
1113
|
+
}
|
|
1114
|
+
|
|
1115
|
+
// 4. Perform Strike (Up + Right)
|
|
1116
|
+
if (isUpPressed && isRightPressed) {
|
|
1117
|
+
if (isChordLocked) return;
|
|
1118
|
+
isChordLocked = true;
|
|
1119
|
+
performOracleStrike();
|
|
1120
|
+
isUpPressed = false; isRightPressed = false;
|
|
1121
|
+
setTimeout(() => { isChordLocked = false; }, 2000);
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
// 5. Pin/Unpin (Up + Left)
|
|
1125
|
+
if (isUpPressed && isLeftPressed) {
|
|
1126
|
+
isPinned = !isPinned;
|
|
1127
|
+
updateUI();
|
|
1128
|
+
isUpPressed = false; isLeftPressed = false;
|
|
1129
|
+
}
|
|
1130
|
+
|
|
1131
|
+
// 6. CLEAR BATCH QUEUE (Down + Right)
|
|
1132
|
+
if (isDownPressed && isRightPressed) {
|
|
1133
|
+
if (isChordLocked) return;
|
|
1134
|
+
console.log(`[CHORD] QUEUE CLEARED (${batchQueue.length} items removed)`);
|
|
1135
|
+
isChordLocked = true;
|
|
1136
|
+
batchQueue = [];
|
|
1137
|
+
updateUI();
|
|
1138
|
+
if (overlayWindow && !overlayWindow.isDestroyed()) {
|
|
1139
|
+
overlayWindow.webContents.send('update-ans', JSON.stringify({ type: 'cleared' }));
|
|
1140
|
+
}
|
|
1141
|
+
isDownPressed = false; isRightPressed = false;
|
|
1142
|
+
setTimeout(() => { isChordLocked = false; }, 1000);
|
|
1143
|
+
}
|
|
1144
|
+
});
|
|
1145
|
+
});
|
|
1146
|
+
|
|
1147
|
+
uIOhook.on('keyup', (e) => {
|
|
1148
|
+
setImmediate(() => {
|
|
1149
|
+
if (e.keycode === 57416 || e.keycode === 72) isUpPressed = false;
|
|
1150
|
+
if (e.keycode === 57424 || e.keycode === 80) isDownPressed = false;
|
|
1151
|
+
if (e.keycode === 57419 || e.keycode === 75) isLeftPressed = false;
|
|
1152
|
+
if (e.keycode === 57421 || e.keycode === 77) isRightPressed = false;
|
|
1153
|
+
if (e.keycode === 42 || e.keycode === 54) isShiftPressed = false;
|
|
1154
|
+
});
|
|
1155
|
+
});
|
|
1156
|
+
|
|
1157
|
+
// STEALTH CLICK HANDLER
|
|
1158
|
+
uIOhook.on('mousemove', (e) => {
|
|
1159
|
+
lastMousePos = { x: e.x, y: e.y };
|
|
1160
|
+
});
|
|
1161
|
+
uIOhook.on('mousedown', (e) => {
|
|
1162
|
+
setImmediate(() => {
|
|
1163
|
+
if (!overlayWindow || overlayWindow.isDestroyed() || !overlayWindow.isVisible()) return;
|
|
1164
|
+
const bounds = overlayWindow.getBounds();
|
|
1165
|
+
const primaryDisplay = screen.getPrimaryDisplay();
|
|
1166
|
+
const sf = primaryDisplay.scaleFactor;
|
|
1167
|
+
|
|
1168
|
+
const mX = e.x / sf;
|
|
1169
|
+
const mY = e.y / sf;
|
|
1170
|
+
|
|
1171
|
+
if (mX >= bounds.x && mX <= bounds.x + bounds.width &&
|
|
1172
|
+
mY >= bounds.y && mY <= bounds.y + bounds.height) {
|
|
1173
|
+
const clientX = Math.round(mX - bounds.x);
|
|
1174
|
+
const clientY = Math.round(mY - bounds.y);
|
|
1175
|
+
overlayWindow.webContents.send('stealth-click', { x: clientX, y: clientY });
|
|
1176
|
+
}
|
|
1177
|
+
});
|
|
1178
|
+
});
|
|
1179
|
+
|
|
1180
|
+
// Delay start to let Electron event loop stabilize
|
|
1181
|
+
setTimeout(() => {
|
|
1182
|
+
uIOhook.start();
|
|
1183
|
+
console.log('[GHOST] uIOhook started successfully.');
|
|
1184
|
+
}, 500);
|
|
1185
|
+
|
|
1186
|
+
// \u{1F6F8} DESKTOP SCOUT: Start cross-desktop migration engine
|
|
1187
|
+
// Delayed to let everything initialize first
|
|
1188
|
+
setTimeout(() => {
|
|
1189
|
+
startDesktopScout();
|
|
1190
|
+
}, 3000);
|
|
1191
|
+
});
|