mindweave 2.4.1 → 2.4.2
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/dist/tools/screenshot.js
CHANGED
|
@@ -43,17 +43,6 @@ import { join } from "node:path";
|
|
|
43
43
|
import { describeImage, isRejection } from "../memory/images.js";
|
|
44
44
|
import { formatBytes } from "./webFetch.js";
|
|
45
45
|
import { captureWindow, listWindows } from "./screenshotWin.js";
|
|
46
|
-
/**
|
|
47
|
-
* How long to wait for a NAMED window to appear before giving up.
|
|
48
|
-
*
|
|
49
|
-
* Sized for the gap between launching a GUI app and its window being drawn, which on a
|
|
50
|
-
* cold browser start is a second or two. Long enough to cover that, short enough that a
|
|
51
|
-
* genuinely absent window is reported quickly rather than hanging the turn.
|
|
52
|
-
*/
|
|
53
|
-
const WINDOW_WAIT_MS = 5000;
|
|
54
|
-
/** How often to re-list while waiting. Each list is a PowerShell round trip, so this is
|
|
55
|
-
* a compromise between noticing quickly and not spawning a process ten times a second. */
|
|
56
|
-
const WINDOW_POLL_MS = 400;
|
|
57
46
|
/** How many titles to name when a match fails, so the model can retry precisely. */
|
|
58
47
|
const MAX_LISTED = 12;
|
|
59
48
|
/**
|
|
@@ -155,7 +144,9 @@ export const screenshot = {
|
|
|
155
144
|
"actually came up and renders correctly — a running process is not proof of that — " +
|
|
156
145
|
"or to see a layout, a chart, or an error dialog for yourself. " +
|
|
157
146
|
"Pass `window` with part of the window's title; leave it out to capture the window " +
|
|
158
|
-
"the user is currently focused on. " +
|
|
147
|
+
"the user is currently focused on. For an app you just launched, or one with a custom " +
|
|
148
|
+
"title bar that shows a blank OS title (common for desktop apps), omit `window` to grab " +
|
|
149
|
+
"the focused window rather than guessing its title. " +
|
|
159
150
|
"It photographs whatever that window is showing, so call it when looking will " +
|
|
160
151
|
"genuinely tell you something, not as a routine check. " +
|
|
161
152
|
"Windows only, one window at a time — the whole screen is never captured, and " +
|
|
@@ -188,35 +179,27 @@ export const screenshot = {
|
|
|
188
179
|
let windows;
|
|
189
180
|
let pick;
|
|
190
181
|
try {
|
|
191
|
-
//
|
|
192
|
-
// and
|
|
193
|
-
//
|
|
194
|
-
//
|
|
195
|
-
//
|
|
196
|
-
//
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
// Only when a query was given. With no query the target is whatever has focus,
|
|
200
|
-
// which is true immediately and cannot be waited into existence.
|
|
201
|
-
const deadline = Date.now() + (query ? WINDOW_WAIT_MS : 0);
|
|
202
|
-
for (;;) {
|
|
203
|
-
windows = await listWindows(ctx.abortSignal);
|
|
204
|
-
pick = pickWindow(query, windows);
|
|
205
|
-
if (pick.kind !== "none" || Date.now() >= deadline)
|
|
206
|
-
break;
|
|
207
|
-
await new Promise((resolve) => setTimeout(resolve, WINDOW_POLL_MS));
|
|
208
|
-
}
|
|
182
|
+
// Listed ONCE, not waited on. A blocking wait for a named window punishes every
|
|
183
|
+
// wrong name and every custom-title-bar app with the same multi-second stall, and
|
|
184
|
+
// it does not actually solve the case it was built for: a just-launched app whose
|
|
185
|
+
// title has not populated yet is not waited into existence either. The window is
|
|
186
|
+
// there or it is not; if it is still coming up, the model is told to try again,
|
|
187
|
+
// which is cheaper and does not freeze the turn.
|
|
188
|
+
windows = await listWindows(ctx.abortSignal);
|
|
189
|
+
pick = pickWindow(query, windows);
|
|
209
190
|
}
|
|
210
191
|
catch (error) {
|
|
211
192
|
return fail(`Could not list open windows: ${message(error)}`);
|
|
212
193
|
}
|
|
213
194
|
if (pick.kind === "none") {
|
|
214
195
|
return fail(query
|
|
215
|
-
? `No open window's title contains "${query}"
|
|
216
|
-
`
|
|
217
|
-
`
|
|
218
|
-
`
|
|
219
|
-
`
|
|
196
|
+
? `No open window's title contains "${query}". ${listTitles(pick.candidates)}\n` +
|
|
197
|
+
`Three things to try, in order: if you just launched the app, its window may need a ` +
|
|
198
|
+
`moment — call again. If it has a custom title bar (many desktop apps, and Tauri or ` +
|
|
199
|
+
`Electron with window decorations off, show a blank OS title), omit \`window\` to ` +
|
|
200
|
+
`capture whichever window is focused. Or name one of the windows listed above. ` +
|
|
201
|
+
`Do NOT capture a different named window as a stand-in: a picture of something else ` +
|
|
202
|
+
`cannot tell you anything about "${query}".`
|
|
220
203
|
: `There is no window to capture. ${listTitles(pick.candidates)}`);
|
|
221
204
|
}
|
|
222
205
|
if (pick.kind === "ambiguous") {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"screenshot.js","sourceRoot":"","sources":["../../src/tools/screenshot.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC3C,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACxC,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACjE,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,WAAW,EAAmB,MAAM,oBAAoB,CAAC;AAEjF
|
|
1
|
+
{"version":3,"file":"screenshot.js","sourceRoot":"","sources":["../../src/tools/screenshot.ts"],"names":[],"mappings":"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"}
|
|
@@ -28,6 +28,13 @@
|
|
|
28
28
|
* caller-supplied DC), so a blank result falls back to copying that rectangle off
|
|
29
29
|
* the screen. That fallback captures whatever is physically on top, which is why
|
|
30
30
|
* the tool asks for approval BEFORE any of this runs.
|
|
31
|
+
*
|
|
32
|
+
* Enumeration is the standard "would this window appear in Alt-Tab" test rather than
|
|
33
|
+
* "does it have a title": DWM-cloaked windows (invisible UWP and host windows that still
|
|
34
|
+
* report visible) and tool windows are skipped, and a window with an EMPTY title is kept
|
|
35
|
+
* and labelled by its process. An empty title is the normal state of an app with a custom
|
|
36
|
+
* title bar (Tauri, Electron with decorations off), and dropping those made a window the
|
|
37
|
+
* user was plainly looking at impossible to capture at all.
|
|
31
38
|
*/
|
|
32
39
|
import { spawn } from "node:child_process";
|
|
33
40
|
import { mkdtemp, writeFile } from "node:fs/promises";
|
|
@@ -58,12 +65,43 @@ public static class MwCapture {
|
|
|
58
65
|
[DllImport("user32.dll")] static extern bool SetProcessDPIAware();
|
|
59
66
|
[DllImport("user32.dll")] static extern bool GetWindowRect(IntPtr h, out RECT r);
|
|
60
67
|
[DllImport("user32.dll")] public static extern IntPtr GetForegroundWindow();
|
|
68
|
+
[DllImport("user32.dll")] static extern uint GetWindowThreadProcessId(IntPtr h, out uint pid);
|
|
69
|
+
[DllImport("user32.dll")] static extern int GetWindowLong(IntPtr h, int index);
|
|
61
70
|
[DllImport("dwmapi.dll")] static extern int DwmGetWindowAttribute(IntPtr h, int attr, out RECT r, int size);
|
|
71
|
+
[DllImport("dwmapi.dll", EntryPoint = "DwmGetWindowAttribute")] static extern int DwmGetIntAttribute(IntPtr h, int attr, out int v, int size);
|
|
62
72
|
|
|
63
73
|
[StructLayout(LayoutKind.Sequential)] public struct RECT { public int Left, Top, Right, Bottom; }
|
|
64
74
|
|
|
65
75
|
public static void Dpi() { SetProcessDPIAware(); }
|
|
66
76
|
|
|
77
|
+
// A DWM-cloaked window passes IsWindowVisible but is not actually on screen — the
|
|
78
|
+
// invisible UWP and host windows that would otherwise flood the list. Any failure to
|
|
79
|
+
// read the attribute is treated as not-cloaked, so a window is never dropped on error.
|
|
80
|
+
static bool Cloaked(IntPtr h) {
|
|
81
|
+
int v;
|
|
82
|
+
return DwmGetIntAttribute(h, 14 /* DWMWA_CLOAKED */, out v, sizeof(int)) == 0 && v != 0;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// The Shell's own "is this an Alt-Tab window" test: a tool window is a palette or
|
|
86
|
+
// tray surface and is never what "the app" means, unless it also asks for the taskbar.
|
|
87
|
+
static bool AltTabWorthy(IntPtr h) {
|
|
88
|
+
int ex = GetWindowLong(h, -20 /* GWL_EXSTYLE */);
|
|
89
|
+
bool tool = (ex & 0x00000080) != 0; // WS_EX_TOOLWINDOW
|
|
90
|
+
bool app = (ex & 0x00040000) != 0; // WS_EX_APPWINDOW
|
|
91
|
+
return !tool || app;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// The window's process name, for a window that has no title of its own. Wrapped
|
|
95
|
+
// because the process can exit between the enum and the lookup.
|
|
96
|
+
static string ProcName(IntPtr h) {
|
|
97
|
+
try {
|
|
98
|
+
uint pid;
|
|
99
|
+
GetWindowThreadProcessId(h, out pid);
|
|
100
|
+
if (pid == 0) return "";
|
|
101
|
+
using (var p = System.Diagnostics.Process.GetProcessById((int)pid)) return p.ProcessName;
|
|
102
|
+
} catch { return ""; }
|
|
103
|
+
}
|
|
104
|
+
|
|
67
105
|
// DWMWA_EXTENDED_FRAME_BOUNDS. GetWindowRect includes an invisible border on
|
|
68
106
|
// Windows 10+, so it is the fallback rather than the first choice.
|
|
69
107
|
static bool Bounds(IntPtr h, out RECT r) {
|
|
@@ -77,16 +115,27 @@ public static class MwCapture {
|
|
|
77
115
|
IntPtr fg = GetForegroundWindow();
|
|
78
116
|
EnumWindows(delegate(IntPtr h, IntPtr l) {
|
|
79
117
|
if (!IsWindowVisible(h) || IsIconic(h)) return true;
|
|
80
|
-
|
|
81
|
-
if (len == 0) return true;
|
|
82
|
-
var sb = new StringBuilder(len + 1);
|
|
83
|
-
GetWindowText(h, sb, sb.Capacity);
|
|
84
|
-
string title = sb.ToString().Trim();
|
|
85
|
-
if (title.Length == 0) return true;
|
|
118
|
+
if (Cloaked(h) || !AltTabWorthy(h)) return true;
|
|
86
119
|
RECT r;
|
|
87
120
|
if (!Bounds(h, out r)) return true;
|
|
88
121
|
// Tool windows and tray hosts are real but never what anyone means.
|
|
89
122
|
if (r.Right - r.Left < 120 || r.Bottom - r.Top < 120) return true;
|
|
123
|
+
int len = GetWindowTextLength(h);
|
|
124
|
+
string title = "";
|
|
125
|
+
if (len > 0) {
|
|
126
|
+
var sb = new StringBuilder(len + 1);
|
|
127
|
+
GetWindowText(h, sb, sb.Capacity);
|
|
128
|
+
title = sb.ToString().Trim();
|
|
129
|
+
}
|
|
130
|
+
// An empty title is NOT a reason to drop the window. A custom title bar
|
|
131
|
+
// (Tauri or Electron with decorations off) leaves the OS title blank, as does
|
|
132
|
+
// an app whose web content has not set document.title yet — and dropping it
|
|
133
|
+
// makes a window the user is plainly looking at impossible to capture, by name
|
|
134
|
+
// OR as the foreground. Label it by its process so it stays nameable.
|
|
135
|
+
if (title.Length == 0) {
|
|
136
|
+
string pn = ProcName(h);
|
|
137
|
+
title = pn.Length > 0 ? pn : "(untitled window)";
|
|
138
|
+
}
|
|
90
139
|
// The leading marker is how the caller knows which window the user is
|
|
91
140
|
// actually looking at, so it can name it when asking permission.
|
|
92
141
|
found.Add((h == fg ? "*" : "-") + h.ToInt64().ToString() + "\t" + title);
|
|
@@ -212,7 +261,11 @@ export function parseWindowList(stdout) {
|
|
|
212
261
|
}
|
|
213
262
|
return windows;
|
|
214
263
|
}
|
|
215
|
-
/**
|
|
264
|
+
/**
|
|
265
|
+
* Every visible, non-minimised, reasonably sized top-level window a user could Alt-Tab
|
|
266
|
+
* to — DWM-cloaked ghosts and tool/palette windows excluded, and a window with no OS
|
|
267
|
+
* title (a custom title bar) kept and labelled by its process rather than dropped.
|
|
268
|
+
*/
|
|
216
269
|
export async function listWindows(signal) {
|
|
217
270
|
return parseWindowList(await runScript(["-Mode", "list"], signal));
|
|
218
271
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"screenshotWin.js","sourceRoot":"","sources":["../../src/tools/screenshotWin.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"screenshotWin.js","sourceRoot":"","sources":["../../src/tools/screenshotWin.ts"],"names":[],"mappings":"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"}
|