@aexol/spectral 0.9.158 → 0.9.159
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.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/extensions/desktop-screenshot/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/extensions/desktop-screenshot/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAQH,OAAO,KAAK,EAEX,YAAY,EAEZ,MAAM,iCAAiC,CAAC;AA8dzC,wBAA8B,0BAA0B,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAoFzF"}
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
* extension automatically analyzes with a vision model.
|
|
14
14
|
*/
|
|
15
15
|
import { execFile } from "node:child_process";
|
|
16
|
+
import crossSpawn from "cross-spawn";
|
|
16
17
|
import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
17
18
|
import { tmpdir } from "node:os";
|
|
18
19
|
import { join } from "node:path";
|
|
@@ -246,6 +247,35 @@ function linuxWindowScreenshot(windowId, options) {
|
|
|
246
247
|
// ===========================================================================
|
|
247
248
|
// Windows (PowerShell)
|
|
248
249
|
// ===========================================================================
|
|
250
|
+
/**
|
|
251
|
+
* Run a PowerShell script file and return its stdout as a string.
|
|
252
|
+
*
|
|
253
|
+
* Uses `cross-spawn` instead of Node's `execFile` because, on Windows,
|
|
254
|
+
* `execFile` does not resolve commands through PATHEXT and requires a fully
|
|
255
|
+
* populated PATH. Inside Electron/desktop sandboxes the PATH is often trimmed,
|
|
256
|
+
* which leads to `spawn powershell.exe ENOENT`. `cross-spawn` resolves the
|
|
257
|
+
* executable via PATHEXT/PATH like a shell would.
|
|
258
|
+
*
|
|
259
|
+
* `-Sta` is passed so the single-threaded apartment required by
|
|
260
|
+
* System.Windows.Forms / CopyFromScreen is initialized even in sessions that
|
|
261
|
+
* default to MTA (avoids COM failures).
|
|
262
|
+
*/
|
|
263
|
+
function runPowerShell(psPath) {
|
|
264
|
+
return new Promise((resolve, reject) => {
|
|
265
|
+
const child = crossSpawn("powershell.exe", ["-NoProfile", "-Sta", "-ExecutionPolicy", "Bypass", "-File", psPath], { timeout: 15000, windowsHide: true });
|
|
266
|
+
let stdout = "";
|
|
267
|
+
let stderr = "";
|
|
268
|
+
child.stdout?.on("data", (chunk) => { stdout += chunk.toString(); });
|
|
269
|
+
child.stderr?.on("data", (chunk) => { stderr += chunk.toString(); });
|
|
270
|
+
child.on("error", reject);
|
|
271
|
+
child.on("close", (code) => {
|
|
272
|
+
if (code === 0)
|
|
273
|
+
return resolve(stdout);
|
|
274
|
+
const tail = stderr.trim() || `exited with code ${code}`;
|
|
275
|
+
reject(new Error(`powershell.exe ${tail}`));
|
|
276
|
+
});
|
|
277
|
+
});
|
|
278
|
+
}
|
|
249
279
|
function listWin32Windows() {
|
|
250
280
|
const psLines = [
|
|
251
281
|
'Add-Type @"',
|
|
@@ -284,19 +314,15 @@ function listWin32Windows() {
|
|
|
284
314
|
const psScript = psLines.join("\r\n");
|
|
285
315
|
const psPath = join(tmpDir(), `${randomUUID()}.ps1`);
|
|
286
316
|
writeFileSync(psPath, psScript, "utf-8");
|
|
287
|
-
return
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
windows.push({ id, owner, title: titleParts.join("\t") });
|
|
297
|
-
}
|
|
298
|
-
resolve(windows);
|
|
299
|
-
});
|
|
317
|
+
return runPowerShell(psPath).then((stdout) => {
|
|
318
|
+
const windows = [];
|
|
319
|
+
for (const line of stdout.trim().split("\n").filter(Boolean)) {
|
|
320
|
+
const [id, owner, ...titleParts] = line.split("\t");
|
|
321
|
+
if (!id || !owner)
|
|
322
|
+
continue;
|
|
323
|
+
windows.push({ id, owner, title: titleParts.join("\t") });
|
|
324
|
+
}
|
|
325
|
+
return windows;
|
|
300
326
|
});
|
|
301
327
|
}
|
|
302
328
|
function win32FullScreenshot(options) {
|
|
@@ -321,25 +347,17 @@ function win32FullScreenshot(options) {
|
|
|
321
347
|
const psScript = psLines.join("\r\n");
|
|
322
348
|
const psPath = join(tmpDir(), `${randomUUID()}.ps1`);
|
|
323
349
|
writeFileSync(psPath, psScript, "utf-8");
|
|
324
|
-
return
|
|
325
|
-
execFile("powershell.exe", ["-NoProfile", "-ExecutionPolicy", "Bypass", "-File", psPath], { timeout: 15000 }, (err) => {
|
|
326
|
-
if (err)
|
|
327
|
-
return reject(new Error(`Screenshot failed: ${err.message}`));
|
|
328
|
-
try {
|
|
329
|
-
resolve(readFileSync(outPath));
|
|
330
|
-
}
|
|
331
|
-
catch (e) {
|
|
332
|
-
reject(e);
|
|
333
|
-
}
|
|
334
|
-
});
|
|
335
|
-
});
|
|
350
|
+
return runPowerShell(psPath).then(() => readFileSync(outPath), (err) => { throw new Error(`Screenshot failed: ${err.message}`); });
|
|
336
351
|
}
|
|
337
352
|
function win32WindowScreenshot(hwnd, options) {
|
|
338
353
|
const format = options.format ?? "png";
|
|
339
354
|
const formatUpper = format.toUpperCase();
|
|
340
355
|
const imageFormat = (formatUpper === "JPG" || formatUpper === "JPEG") ? "Jpeg" : "Png";
|
|
341
|
-
//
|
|
342
|
-
|
|
356
|
+
// Normalize hwnd to hex regardless of input format: Number() parses both
|
|
357
|
+
// decimal (65882) and hex ("0x10132"), then toString(16) yields the hex
|
|
358
|
+
// digits to feed into [IntPtr]::new(0x...). Without this, a decimal hwnd
|
|
359
|
+
// was inserted verbatim producing 0x65882 (wrong pointer).
|
|
360
|
+
const hwndHex = Number(hwnd).toString(16);
|
|
343
361
|
const outPath = join(tmpDir(), `${randomUUID()}.${format}`);
|
|
344
362
|
const psLines = [
|
|
345
363
|
"Add-Type -AssemblyName System.Drawing",
|
|
@@ -376,18 +394,7 @@ function win32WindowScreenshot(hwnd, options) {
|
|
|
376
394
|
const psScript = psLines.join("\r\n");
|
|
377
395
|
const psPath = join(tmpDir(), `${randomUUID()}.ps1`);
|
|
378
396
|
writeFileSync(psPath, psScript, "utf-8");
|
|
379
|
-
return
|
|
380
|
-
execFile("powershell.exe", ["-NoProfile", "-ExecutionPolicy", "Bypass", "-File", psPath], { timeout: 15000 }, (err) => {
|
|
381
|
-
if (err)
|
|
382
|
-
return reject(new Error(`Window screenshot failed: ${err.message}`));
|
|
383
|
-
try {
|
|
384
|
-
resolve(readFileSync(outPath));
|
|
385
|
-
}
|
|
386
|
-
catch (e) {
|
|
387
|
-
reject(e);
|
|
388
|
-
}
|
|
389
|
-
});
|
|
390
|
-
});
|
|
397
|
+
return runPowerShell(psPath).then(() => readFileSync(outPath), (err) => { throw new Error(`Window screenshot failed: ${err.message}`); });
|
|
391
398
|
}
|
|
392
399
|
// ===========================================================================
|
|
393
400
|
// Unified API
|