@apmantza/greedysearch-pi 1.8.10 → 1.9.1

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/bin/cdp.mjs CHANGED
@@ -365,10 +365,23 @@ async function captureMainContext(cdp, sid) {
365
365
  // Always disable Runtime after capturing
366
366
  await cdp.send("Runtime.disable", {}, sid).catch(() => {});
367
367
 
368
- // Find the main world context
369
- const main = contexts.find(
368
+ // Get the root frame ID so we can prefer its context when multiple
369
+ // isDefault contexts exist (e.g. Gemini embeds _/bscframe as a child
370
+ // frame whose context fires first and would otherwise be picked instead).
371
+ let rootFrameId = null;
372
+ try {
373
+ const ft = await cdp.send("Page.getFrameTree", {}, sid);
374
+ rootFrameId = ft?.frameTree?.frame?.id ?? null;
375
+ } catch {}
376
+
377
+ const defaults = contexts.filter(
370
378
  (ctx) => ctx.auxData?.isDefault && ctx.auxData?.type === "default",
371
379
  );
380
+ // Prefer the context whose frameId matches the root frame
381
+ const main =
382
+ (rootFrameId && defaults.find((ctx) => ctx.auxData?.frameId === rootFrameId)) ||
383
+ defaults[0] ||
384
+ null;
372
385
  return main?.id ?? null;
373
386
  }
374
387
 
@@ -106,6 +106,69 @@ function httpGet(url, timeoutMs = 1000) {
106
106
  });
107
107
  }
108
108
 
109
+ async function minimizeViaCDP(port) {
110
+ try {
111
+ const version = await httpGet(`http://localhost:${port}/json/version`).then(
112
+ (r) => JSON.parse(r.body),
113
+ );
114
+ const targets = await httpGet(`http://localhost:${port}/json/list`).then(
115
+ (r) => JSON.parse(r.body),
116
+ );
117
+ const targetId = targets.find((t) => t.type === "page")?.id;
118
+ if (!targetId) return;
119
+
120
+ // Validate browser WebSocket URL to prevent SSRF (SonarCloud javasecurity:S5335)
121
+ const wsUrlStr = version.webSocketDebuggerUrl;
122
+ if (typeof wsUrlStr !== "string") return;
123
+ const wsUrl = new URL(wsUrlStr);
124
+ if (wsUrl.hostname !== "localhost" && wsUrl.hostname !== "127.0.0.1")
125
+ return;
126
+ if (!/^ws:\/\/localhost:\d+/.test(`ws://${wsUrl.host}`)) return;
127
+ const wsPath = wsUrl.pathname;
128
+ const ws = new WebSocket(`ws://localhost:${port}${wsPath}`);
129
+ await new Promise((resolve) => {
130
+ ws.onopen = () =>
131
+ ws.send(
132
+ JSON.stringify({
133
+ id: 1,
134
+ method: "Browser.getWindowForTarget",
135
+ params: { targetId },
136
+ }),
137
+ );
138
+ ws.onmessage = (ev) => {
139
+ const msg = JSON.parse(ev.data);
140
+ if (msg.id === 1 && msg.result?.windowId) {
141
+ ws.send(
142
+ JSON.stringify({
143
+ id: 2,
144
+ method: "Browser.setWindowBounds",
145
+ params: {
146
+ windowId: msg.result.windowId,
147
+ bounds: { windowState: "minimized" },
148
+ },
149
+ }),
150
+ );
151
+ } else if (msg.id === 2) {
152
+ ws.close();
153
+ resolve();
154
+ }
155
+ };
156
+ ws.onerror = () => {
157
+ ws.close();
158
+ resolve();
159
+ };
160
+ setTimeout(() => {
161
+ try {
162
+ ws.close();
163
+ } catch {}
164
+ resolve();
165
+ }, 5000);
166
+ });
167
+ } catch {
168
+ // best-effort — Chrome is still usable if minimize fails
169
+ }
170
+ }
171
+
109
172
  async function waitForPort(timeoutMs = 15000) {
110
173
  const deadline = Date.now() + timeoutMs;
111
174
  while (Date.now() < deadline) {
@@ -226,6 +289,8 @@ async function main() {
226
289
  process.exit(1);
227
290
  }
228
291
 
292
+ await minimizeViaCDP(PORT);
293
+
229
294
  console.log("Visible Chrome ready on port 9222.");
230
295
  console.log("Keep this terminal open to keep Chrome alive.");
231
296
  }